Kubernetes, wie die Bereitstellung zum Aktualisieren des Images durchgeführt wird

129

Ich habe eine Bereitstellung mit einem einzelnen Pod, mit meinem benutzerdefinierten Docker-Image wie:

containers:
  - name: mycontainer
    image: myimage:latest

Während der Entwicklung möchte ich die neueste Version veröffentlichen und die Bereitstellung aktualisieren. Ich kann nicht finden, wie das geht, ohne Tag / Version explizit zu definieren und es für jeden Build zu erhöhen

kubectl set image deployment/my-deployment mycontainer=myimage:1.9.1
oben
quelle

Antworten:

151

Sie können Ihren Pod mit einer Nachfrist konfigurieren (z. B. 30 Sekunden oder mehr, abhängig von der Startzeit des Containers und der Bildgröße) und festlegen "imagePullPolicy: "Always". Und verwenden kubectl delete pod pod_name. Ein neuer Container wird erstellt und das neueste Bild automatisch heruntergeladen. Anschließend wird der alte Container beendet.

Beispiel:

spec:
  terminationGracePeriodSeconds: 30
  containers:
  - name: my_container
    image: my_image:latest
    imagePullPolicy: "Always"

Ich verwende derzeit Jenkins für automatisierte Builds und Image-Tagging und es sieht ungefähr so ​​aus:

kubectl --user="kube-user" --server="https://kubemaster.example.com"  --token=$ACCESS_TOKEN set image deployment/my-deployment mycontainer=myimage:"$BUILD_NUMBER-$SHORT_GIT_COMMIT"

Ein weiterer Trick besteht darin, zunächst auszuführen:

kubectl set image deployment/my-deployment mycontainer=myimage:latest

und dann:

kubectl set image deployment/my-deployment mycontainer=myimage

Es wird tatsächlich das fortlaufende Update auslösen, aber stellen Sie sicher, dass Sie auch imagePullPolicy: "Always"festgelegt haben.

Aktualisieren:

Ein weiterer Trick, den ich gefunden habe, bei dem Sie den Bildnamen nicht ändern müssen, besteht darin, den Wert eines Feldes zu ändern, das ein fortlaufendes Update auslöst, wie z terminationGracePeriodSeconds. Sie können tun dies mit kubectl edit deployment your_deploymentoder kubectl apply -f your_deployment.yamloder einen Patch wie folgt aus:

kubectl patch deployment your_deployment -p \
  '{"spec":{"template":{"spec":{"terminationGracePeriodSeconds":31}}}}'

Stellen Sie einfach sicher, dass Sie immer den Zahlenwert ändern.

Camil
quelle
1
Eigentlich ist es dein Trick ist nicht schlecht, wenn man mein Bild betrachtet: lastet und myimage sind im Grunde dasselbe, danke!
oben
1
Dieser Trick scheint eher ein Fehler zu sein, nicht sicher, warum wir ihn zweimal angeben müssen.
Speedplane
2
Wenn Sie möchten, dass eine Kubernetes-Bereitstellung einen neuen Pod mit demselben Image startet (und dieser Trick funktioniert nur mit dem "neuesten" Tag), müssen Sie ihn ohne Tag angeben. Wenn Sie das nächste Mal das "neueste" Tag hinzufügen, wird das Update ausgelöst. Die Reihenfolge könnte umgekehrt werden, es spielt keine Rolle. Sie verwenden niemals das "neueste" Tag in der Produktion, aber für Entwicklungszwecke können Sie manchmal davon profitieren.
Camil
2
Es funktioniert nur für die neuesten. Zumindest im Docker-Hub wird standardmäßig das "neueste" Tag angenommen, wenn kein Bild markiert wird. Funktioniert aber auch ohne. Dieses Beispiel ist in einer Produktionsumgebung nicht erwünscht, und es gibt nicht viele Anwendungsfälle, in denen Sie auch in der Entwicklung davon profitieren können. Es gibt bessere Methoden, um ein Image mithilfe eines CI / CD-Tools automatisch zu aktualisieren.
Camil
11
Jedes Mal, wenn Sie das Tag ändern und den kubectl set imageBefehl ausführen, führen kubernetes ein fortlaufendes Update durch. Angenommen, Sie haben "repo / myimage: latest" bereitgestellt. In der Zwischenzeit wurde Ihr Bild geändert und mit dem Tag "v0.2" in das Repo verschoben. Sie können ein Update durchführen, indem Sie ausführen. kubectl set image deployment/my-deployment mycontainer=myimage:v0.2Dieses Image hat auch das "neueste" Tag.
Camil
73

UPDATE 2019-06-24

Basierend auf dem @ Jodiug-Kommentar können Sie den folgenden Befehl verwenden, wenn Sie eine 1.15Version haben :

kubectl rollout restart deployment/demo

Lesen Sie mehr zu diesem Thema:

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


Nun, es gibt eine interessante Diskussion zu diesem Thema im kubernetes GitHub-Projekt. Siehe das Problem: https://github.com/kubernetes/kubernetes/issues/33664

Aus den dort beschriebenen Lösungen würde ich eine von zwei vorschlagen.

Zuerst

1. Bereiten Sie die Bereitstellung vor

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: demo
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
      - name: demo
        image: registry.example.com/apps/demo:master
        imagePullPolicy: Always
        env:
        - name: FOR_GODS_SAKE_PLEASE_REDEPLOY
          value: 'THIS_STRING_IS_REPLACED_DURING_BUILD'

2. Bereitstellen

sed -ie "s/THIS_STRING_IS_REPLACED_DURING_BUILD/$(date)/g" deployment.yml
kubectl apply -f deployment.yml

Zweitens (ein Liner):

kubectl patch deployment web -p \
  "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"`date +'%s'`\"}}}}}"

Natürlich imagePullPolicy: Alwaysist das in beiden Fällen erforderlich.

Przemek Nowak
quelle
Fand einen anderen verwandten Trick. Wenn Sie nur "kubectl rollout restart deploy" ausführen, ohne eine bestimmte Bereitstellungsname anzugeben, werden "alle" ausgeführt.
Lennart Rolland
20
kubectl rollout restart deployment myapp

Dies ist die aktuelle Methode, um ein fortlaufendes Update auszulösen und die alten Replikatsätze für andere Vorgänge zu belassen, die durch kubectl rolloutähnliche Rollbacks bereitgestellt werden .

Martin Peter
quelle
@Prathameshdhanawade Die Patch-Operation hat keinen undoBefehl oder ein Äquivalent.
Martin Peter
7

Ich verwende Gitlab-CI, um das Image zu erstellen und es dann direkt in GCK bereitzustellen. Wenn Sie einen kleinen Trick verwenden, um ein fortlaufendes Update zu erzielen, ohne die tatsächlichen Einstellungen des Containers zu ändern, wird ein Label in das aktuelle Commit-Short-Sha geändert.

Mein Befehl sieht folgendermaßen aus:

kubectl patch deployment my-deployment -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"build\":\"$CI_COMMIT_SHORT_SHA\"}}}}}}"

Hier können Sie einen beliebigen Namen und einen beliebigen Wert für das Label verwenden, solange sich dieser mit jedem Build ändert.

Habe Spaß!

David Faber
quelle
6

Es scheint, dass k8s erwartet, dass wir für jede Bereitstellung ein anderes Image-Tag bereitstellen. Meine Standardstrategie wäre, das CI-System dazu zu bringen, die Docker-Images zu generieren und zu pushen und sie mit der Build-Nummer zu versehen : xpmatteo/foobar:456.

Für die lokale Entwicklung kann es bequem sein, ein Skript oder ein Makefile wie folgt zu verwenden:

# create a unique tag    
VERSION:=$(shell date +%Y%m%d%H%M%S)
TAG=xpmatteo/foobar:$(VERSION)

deploy:
    npm run-script build
    docker build -t $(TAG) . 
    docker push $(TAG)
    sed s%IMAGE_TAG_PLACEHOLDER%$(TAG)% foobar-deployment.yaml | kubectl apply -f - --record

Der sedBefehl ersetzt einen Platzhalter im Bereitstellungsdokument durch das tatsächlich generierte Image-Tag.

xpmatteo
quelle
Bei kubernetes müssen Sie die Bereitstellung nicht mit einem neuen Tag aktualisieren, um die neueste Version eines Images abzurufen. "Neueste" ist das häufigste Beispiel.
Dave White
1

Ich verwende Azure DevOps zum Bereitstellen der Containeranwendungen. Ich kann dieses Problem mithilfe der Build-ID problemlos beheben

Jedes Mal, wenn Builds erstellt und die neue Build-ID generiert werden, verwende ich diese Build-ID als Tag für das Docker-Image

Bildname: buildID

Sobald Ihr Image erfolgreich erstellt wurde (CI), habe ich in der CD-Pipeline in der Bereitstellungs-XML-Datei den Image-Namen als angegeben

imagename: env: buildID

hier evn: buildid ist die Azure Devops-Variable mit dem Wert der Build-ID.

Jetzt muss ich jedes Mal neue Änderungen vornehmen (CI) und bereitstellen (CD).

Bitte kommentieren Sie, wenn Sie eine Build-Definition für CI / CD benötigen.

Noman Sadiq
quelle
Das Manifest ist Teil des Repos. Ich verstehe nicht, was die besten Praktiken dafür sind. Wenn ich das Image in der Pipeline erstelle, sollte ich darauf drängen, das aktualisierte Manifest zu beherrschen? oder sollte ich ein aktualisiertes Manifest für die Artefakte erstellen (und somit wäre das Manifest im Repo nur eine Vorlage ohne das tatsächlich getaggte Bild)?
Pablete