错误:升级失败:无法替换对象:服务“api”无效:spec.clusterIP:无效值:“”:字段不可变

Sai*_*tty 5 kubernetes kubectl kubernetes-helm

这样做时,helm upgrade ... --force我收到以下错误

Error: UPGRADE FAILED: failed to replace object: Service "api" is invalid: spec.clusterIP: Invalid value: "": field is immutable
Run Code Online (Sandbox Code Playgroud)

这就是我的服务文件的样子:(不在任何地方传递 clusterIP)

apiVersion: v1
kind: Service
metadata:
  name: {{ .Chart.Name }}
  namespace: {{ .Release.Namespace }}
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
    service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
  labels:
    app: {{ .Chart.Name }}-service
    kubernetes.io/name: {{ .Chart.Name | quote }}
    dns: route53
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
    release: "{{ .Release.Name }}"
spec:
  selector:
    app: {{ .Chart.Name }}
  type: LoadBalancer
  ports:
  - port: 443
    name: https
    targetPort: http-port
    protocol: TCP
Run Code Online (Sandbox Code Playgroud)

头盔版本:3.0.1

Kubectl版本:1.13.1 [也尝试过1.17.1 ]

服务器1.14

注意:以前我使用的是旧版本(服务器、kubectl、helm),当时我没有遇到这种问题。我可以在 GitHub 中看到很多与此相关的类似问题,但无法为我找到任何可行的解决方案。

几个类似的问题:

https://github.com/kubernetes/kubernetes/issues/25241

https://github.com/helm/charts/pull/13646 [Nginx 图表]

Mr.*_*ler 14

我做了一些测试,用头盔,得到了试图从改变服务类型时,同样的问题NodePort/ClusterIPLoadBalancer

这是我重现您的问题的方式:

Kubernetes 1.15.3 (GKE) Helm 3.1.1

用于测试的 Helm 图表:stable/nginx-ingress

我是如何复制的:

  1. 获取并解压文件:
helm fetch stable/nginx-ingress  
tar xzvf nginx-ingress-1.33.0.tgz  
Run Code Online (Sandbox Code Playgroud)
  1. 修改文件中的服务类型从type: LoadBalancer到(第 271 行):type: NodePortvalues.yaml
sed -i '271s/LoadBalancer/NodePort/' values.yaml
Run Code Online (Sandbox Code Playgroud)
  1. 安装图表:
helm install nginx-ingress ./
Run Code Online (Sandbox Code Playgroud)
  1. 检查服务类型,必须是NodePort
kubectl get svc -l app=nginx-ingress,component=controller

NAME                       TYPE       CLUSTER-IP   EXTERNAL-IP   PORT(S)                      AGE
nginx-ingress-controller   NodePort   10.0.3.137   <none>        80:30117/TCP,443:30003/TCP   1m
Run Code Online (Sandbox Code Playgroud)
  1. 现在再次将服务类型修改LoadBalancervalues.yaml
sed -i '271s/NodePort/LoadBalancer/' values.yaml
Run Code Online (Sandbox Code Playgroud)
  1. 最后,尝试使用--force标志升级图表:
helm upgrade nginx-ingress ./ --force
Run Code Online (Sandbox Code Playgroud)

进而:

Error: UPGRADE FAILED: failed to replace object: Service "nginx-ingress-controller" is invalid: spec.clusterIP: Invalid value: "": field is immutable
Run Code Online (Sandbox Code Playgroud)

解释

我在 HELM源代码中发现了这一点

helm fetch stable/nginx-ingress  
tar xzvf nginx-ingress-1.33.0.tgz  
Run Code Online (Sandbox Code Playgroud)

分析上面的代码 Helm 将使用类似于kubectl replaceapi 请求(而不是kubectl replace --force我们所期望的)...当 helm--force标志被设置时。

如果没有,则 Helm 将使用kubectl patchapi 请求进行升级。

让我们检查它是否有意义:

使用 kubectl 的 PoC

  1. 创建一个简单的服务NodePort
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
 labels:
   app: test-svc
 name: test-svc
spec:
 selector:
   app: test-app
 ports:
 - port: 80
   protocol: TCP
   targetPort: 80
 type: NodePort
EOF
Run Code Online (Sandbox Code Playgroud)

使服务被创建:

kubectl get svc -l app=test-svc

NAME       TYPE       CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
test-svc   NodePort   10.0.7.37    <none>        80:31523/TCP   25
Run Code Online (Sandbox Code Playgroud)

现在让我们尝试使用kubectl replace将服务升级到LoadBalancer,例如helm upgrade --force

kubectl replace -f - <<EOF
apiVersion: v1
kind: Service
metadata:
 labels:
   app: test-svc
 name: test-svc
spec:
 selector:
   app: test-app
 ports:
 - port: 80
   protocol: TCP
   targetPort: 80
 type: LoadBalancer
EOF
Run Code Online (Sandbox Code Playgroud)

这显示了错误:

The Service "test-svc" is invalid: spec.clusterIP: Invalid value: "": field is immutable
Run Code Online (Sandbox Code Playgroud)

现在,让我们使用kubectl patch将 NodePort 更改为 LoadBalancer,模拟没有 --force标志的 helm upgrade 命令:

这里是kubectl补丁文档,想看怎么用。

kubectl patch svc test-svc -p '{"spec":{"type":"LoadBalancer"}}'
Run Code Online (Sandbox Code Playgroud)

然后你看到: service/test-svc patched

解决方法

你应该使用helm upgradewithout --force,它会起作用。

如果你真的需要使用--force重新创建一些资源,比如 pods 来获取最新configMap更新,那么我建议你在 Helm 升级之前先手动更改服务规范。

如果您尝试更改服务类型,您可以导出服务yaml,更改类型并再次应用它(因为我只有在第一次尝试应用相同模板时才遇到这种行为):

kubectl get svc test-svc -o yaml | sed 's/NodePort/LoadBalancer/g' | kubectl replace --force -f -
Run Code Online (Sandbox Code Playgroud)

输出:

service "test-svc" deleted
service/test-svc replaced
Run Code Online (Sandbox Code Playgroud)

现在,如果您尝试使用helm upgrade --force该服务并且没有任何更改要做,它将起作用并重新创建您的 pod 和其他资源。

我希望对你有帮助!