Ошибка: UPGRADE FAILED: не удалось заменить объект: Служба "api" недействительна: spe c .clusterIP: Неверное значение: "": поле является неизменным - PullRequest
1 голос
/ 27 февраля 2020

При выполнении 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 Ответ

1 голос
/ 05 марта 2020

Я провел несколько тестов с 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  
Изменить тип службы с type: LoadBalancer на type: NodePort в файле values.yaml (строка 271):
sed -i '271s/LoadBalancer/NodePort/' values.yaml
Установить схему:
helm install nginx-ingress ./
Проверьте тип услуги, должно быть 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
Теперь измените тип сервиса снова на LoadBalancer в values.yaml:
sed -i '271s/NodePort/LoadBalancer/' values.yaml
Наконец, попробуйте обновить диаграмму, используя флаг --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

Объяснение

Копаться вокруг I нашел это в исходном коде HELM :

// 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-запрос для обновления.

Давайте проверим, имеет ли это смысл:

Po C с использованием kubectl

  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, имитируя команду обновления helm без --force flag:

Здесь - документация патча kubectl если хочешь увидеть хо w для использования.

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

Тогда вы увидите: service/test-svc patched

Обходной путь

Вам следует использовать helm upgrade без --force, это будет работа.

Если вам действительно нужно использовать --force для воссоздания некоторых ресурсов, например, таких как pods, для получения последнего обновления configMap, тогда я предлагаю вам сначала вручную изменить спецификации сервиса перед обновлением Helm.

Если вы пытаетесь изменить тип сервиса, вы можете сделать это, экспортируя сервис 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 и не будете делать никаких изменений в сервисе, он будет работать и будет воссоздавать ваши стручки и другие ресурсы.

Я надеюсь, что это поможет вам!

...