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

时间:2020-02-27 04:26:05

标签: kubernetes kubernetes-helm kubectl

helm upgrade ... --force时,我得到以下错误

Error: UPGRADE FAILED: failed to replace object: Service "api" is invalid: spec.clusterIP: Invalid value: "": field is immutable

这就是我的服务文件的样子:(未在任何地方传递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

头盔版本: 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图表]

1 个答案:

答案 0 :(得分:10)

我已经对Helm进行了一些测试,并且在尝试将服务类型从NodePort/ClusterIP更改为LoadBalancer时遇到了同样的问题。

这是我转载您的问题的方式:

Kubernetes 1.15.3(GKE) 头盔 3.1.1

用于测试的头盔图:stable/nginx-ingress

我如何复制:

  1. 获取并解压缩文件:
helm fetch stable/nginx-ingress  
tar xzvf nginx-ingress-1.33.0.tgz  
  1. type: LoadBalancer文件中将服务类型从type: NodePort修改为values.yaml(第271行):
sed -i '271s/LoadBalancer/NodePort/' values.yaml
  1. 安装图表:
helm install nginx-ingress ./
  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
  1. 现在将LoadBalancer中的服务类型再次修改为values.yaml
sed -i '271s/NodePort/LoadBalancer/' values.yaml
  1. 最后,尝试使用--force标志升级图表:
helm upgrade nginx-ingress ./ --force

然后:

Error: UPGRADE FAILED: failed to replace object: Service "nginx-ingress-controller" is invalid: spec.clusterIP: Invalid value: "": field is immutable

说明

到处逛逛,我在HELM source code:

中发现了这个问题
// if --force is applied, attempt to replace the existing resource with the new object.
    if force {
        obj, err = helper.Replace(target.Namespace, target.Name, true, target.Object)
        if err != nil {
            return errors.Wrap(err, "failed to replace object")
        }
        c.Log("Replaced %q with kind %s for kind %s\n", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind)
    } else {
        // send patch to server
        obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil)
        if err != nil {
            return errors.Wrapf(err, "cannot patch %q with kind %s", target.Name, kind)
        }
    }

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

否则,Helm将使用kubectl patch api请求进行升级。

让我们检查一下是否有意义:

使用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

创建服务:

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

现在让我们尝试使用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

这显示了错误:

The Service "test-svc" is invalid: spec.clusterIP: Invalid value: "": field is immutable

现在,让我们使用kubectl patch将NodePort更改为LoadBalancer,模拟舵升级命令 --force标志:

Here是kubectl补丁文档,如果想了解使用方法。

kubectl patch svc test-svc -p '{"spec":{"type":"LoadBalancer"}}'

然后您会看到: service/test-svc patched

解决方法

您应该在不使用helm upgrade的情况下使用--force,它将起作用。

例如,如果您确实需要使用--force来重新创建一些资源,例如pod来获取最新的configMap更新,那么我建议您在Helm升级之前首先手动更改服务规格。 / p>

如果您尝试更改服务类型,则可以导出服务yaml,更改类型并再次应用(因为仅当我尝试从第一个应用相同的模板时,我才遇到这种现象。时间):

kubectl get svc test-svc -o yaml | sed 's/NodePort/LoadBalancer/g' | kubectl replace --force -f -

输出:

service "test-svc" deleted
service/test-svc replaced

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

希望对您有所帮助!