So aktualisieren Sie Ihre Docker-Container automatisch, wenn Basis-Images aktualisiert werden

205

Angenommen, ich habe einen trivialen Container, der auf dem basiert ubuntu:latest. Jetzt gibt es ein Sicherheitsupdate, ubuntu:latestdas im Docker-Repo aktualisiert wird.

  1. Woher weiß ich, dass mein lokales Image und seine Container hinterher laufen?

  2. Gibt es eine bewährte Methode zum automatischen Aktualisieren lokaler Images und Container, um den Docker-Repo-Updates zu folgen, was Ihnen in der Praxis die gleichen Vorteile bietet, wenn unbeaufsichtigte Upgrades auf einem herkömmlichen Ubuntu-Computer ausgeführt werden

hbogert
quelle
11
Ich suche seit Beginn von Docker nach einer Antwort darauf. Es ist sogar etwas komplizierter. Wenn ich Apache (zum Beispiel) installiere und dieser aktualisiert wird, ändert sich das Basis-Image nicht, da ich es anschließend installiert habe. Ich hätte immer noch gerne automatische Updates für Apache. Ich habe tatsächlich im IRC danach gefragt und als Antwort "Follow Upstream und Neuerstellung bei Updates" erhalten ...
Mathias
8
Ich bin froh, dass ich nicht der einzige bin, der sich wundert. Es scheint, dass Entwicklung und Reproduzierbarkeit für die Docker-Entwickler wichtiger sind als sinnvolle Aktualisierungsmechanismen, die wir seit Jahren haben.
Hbogert
Das Problem ist, Docker ist nur die Technologie für die Container. Ich denke, es braucht einige Zeit, bis sich ein Ökosystem darum entwickelt. Es gibt andere Probleme, die Docker nicht wie die Protokollierung angeht.
Mathias
3
Vielen Dank an alle, die geantwortet haben. Es tut mir leid, dass ich das Kopfgeld nicht teilen konnte. Obwohl es keine endgültige Lösung für mein Problem gab, gab es gute Beiträge von Ihnen allen.
Mathias
1
Für @Mathias verfügt die gerade hinzugefügte Lösung über ein Skript, das nach Sicherheitsupdates für Pakete sucht, die nach dem Pull im Container installiert sind. Es gibt auch ein separates Skript zum Überprüfen des Basisimages.
Fmstrat

Antworten:

8

Eine Möglichkeit, dies zu tun, besteht darin, dies über Ihre CI / CD-Systeme zu steuern. Sobald Ihr übergeordnetes Bild erstellt ist, können Sie Ihre Git-Repos mit diesem übergeordneten Bild nach Bildern durchsuchen. Wenn gefunden, senden Sie eine Pull-Anfrage, um auf neue Versionen des Bildes zuzugreifen. Wenn alle Tests erfolgreich sind, wird die Pull-Anforderung zusammengeführt und Sie erhalten ein neues untergeordnetes Image basierend auf dem aktualisierten übergeordneten Element. Ein Beispiel für ein Tool, das diesen Ansatz verwendet, finden Sie hier: https://engineering.salesforce.com/open-sourcing-dockerfile-image-update-6400121c1a75 .

Wenn Sie Ihr übergeordnetes Bild nicht kontrollieren, wie dies der Fall wäre, wenn Sie vom offiziellen ubuntuBild abhängig sind , können Sie ein Tool schreiben, das Änderungen am übergeordneten Bild-Tag oder der Prüfsumme erkennt (nicht dasselbe, Tags sind veränderbar) und Kinderbildaufrufe entsprechend aufrufen.

Ma3oxuct
quelle
Wow, das ist ein großer Hammer, der sagte: Seit ich diese Frage gestellt habe, habe ich auch festgestellt, dass der Build-Server der richtige Ort ist, um dieses Problem anzugehen. Ich bin froh, einige Werkzeuge zu sehen. Wenn Sie Ihren Ansatz in allgemeinen Konzepten (und nicht in Ihrem genauen Tool / Ihrer Implementierung) erläutern und in die Antwort aufnehmen, werde ich ihn wahrscheinlich akzeptieren.
Hbogert
Danke @hbogert Ich habe das Obige bearbeitet und auch eine Idee hinzugefügt, was zu tun ist, wenn Sie mit öffentlichen Bildern zu tun haben
Ma3oxuct
123

Wir verwenden ein Skript, das prüft, ob ein laufender Container mit dem neuesten Image gestartet wird. Wir verwenden auch Upstart-Init-Skripte zum Starten des Docker-Images.

#!/usr/bin/env bash
set -e
BASE_IMAGE="registry"
REGISTRY="registry.hub.docker.com"
IMAGE="$REGISTRY/$BASE_IMAGE"
CID=$(docker ps | grep $IMAGE | awk '{print $1}')
docker pull $IMAGE

for im in $CID
do
    LATEST=`docker inspect --format "{{.Id}}" $IMAGE`
    RUNNING=`docker inspect --format "{{.Image}}" $im`
    NAME=`docker inspect --format '{{.Name}}' $im | sed "s/\///g"`
    echo "Latest:" $LATEST
    echo "Running:" $RUNNING
    if [ "$RUNNING" != "$LATEST" ];then
        echo "upgrading $NAME"
        stop docker-$NAME
        docker rm -f $NAME
        start docker-$NAME
    else
        echo "$NAME up to date"
    fi
done

Und init sieht aus wie

docker run -t -i --name $NAME $im /bin/bash
bsuttor
quelle
1
Vielen Dank für diesen wertvollen Beitrag. Dies scheint eine gute Möglichkeit zu sein, das Basis-Image zu aktualisieren. Die verbleibende Frage ist, wie Sie eine Anwendung (wie Apache) aktualisieren, die von der Distribution in der Docker-Datei installiert wurde. Oder verwenden Sie nur vorgefertigte Basis-Images, die nur Ihren Anwendungscode benötigen (wie eine Website)?
Mathias
Wir verwenden Packer und Puppe, um unsere Bilder zu konfigurieren. Unsere Bilder sind bereit, nach ihrer Erstellung in Produktion zu gehen
bsuttor
@ Mathias, siehe meine bearbeitete Antwort. Ich habe ein kleines Tool, das vom Docker ausgeführt wird und mit dem ich Linux-Pakete (derzeit Debian / Ubuntu) in allen laufenden Containern aktualisiere.
iTech
3
Wenn ein Bild den gleichen Namen wie ein Container hat (z. B. redis), LATEST=`docker inspect --format "{{.Id}}" $IMAGE`werden die Containerinformationen abgerufen. Fügen Sie hinzu --type image, um dies zu beheben.
Patrick Fisher
1
Danke für deinen Beitrag. Ich habe es modifiziert, um das Ganze in eine Schleife zu wickeln, um Bilder vom Docker zu erhalten: for IMAGE in $(docker ps --format {{.Image}} -q | sort -u)
Armand
25

Ein "Docker-Weg" wäre die Verwendung automatisierter Docker-Hub- Builds . Die Funktion " Repository-Links" erstellt Ihren Container neu, wenn ein Upstream-Container neu erstellt wird, und die Funktion " Webhooks " sendet Ihnen eine Benachrichtigung.

Es sieht so aus, als wären die Webhooks auf HTTP-POST-Aufrufe beschränkt. Sie müssten einen Dienst einrichten, um sie abzufangen, oder einen der POSTs verwenden, um E-Mail-Dienste zu senden.

Ich habe mich nicht damit befasst, aber die neue Docker Universal Control Plane verfügt möglicherweise über eine Funktion zum Erkennen aktualisierter Container und zum erneuten Bereitstellen.

TAXI
quelle
Ich musste einen Webhook für den AMQP-Dienst
erstellen
Upstream-Trigger sind leider nicht mehr verfügbar: github.com/docker/hub-feedback/issues/1717 .
Julien Chastang
22

Sie können den Wachtturm verwenden , um nach Aktualisierungen des Images zu suchen, aus dem ein Container instanziiert wird, und das Update automatisch abzurufen und den Container mithilfe des aktualisierten Images neu zu starten. Dies löst jedoch nicht das Problem der Neuerstellung eigener benutzerdefinierter Images, wenn das zugrunde liegende Upstream-Image geändert wird. Sie können dies als zweiteiliges Problem betrachten: (1) Wissen, wann ein Upstream-Image aktualisiert wurde, und (2) Ausführen der eigentlichen Image-Neuerstellung. (1) kann ziemlich einfach gelöst werden, aber (2) hängt stark von Ihrer lokalen Build-Umgebung / -Praxis ab, sodass es wahrscheinlich viel schwieriger ist, eine allgemeine Lösung dafür zu erstellen.

Wenn Sie die automatisierten Builds von Docker Hub verwenden können, kann das gesamte Problem mithilfe der Repository-Verknüpfungsfunktion relativ sauber gelöst werden. Mit dieser Funktion können Sie automatisch eine Neuerstellung auslösen, wenn ein verknüpftes Repository (wahrscheinlich ein Upstream-Repository) aktualisiert wird. Sie können auch einen Webhook konfigurieren , um Sie zu benachrichtigen, wenn ein automatisierter Build erfolgt. Wenn Sie eine E-Mail- oder SMS-Benachrichtigung wünschen, können Sie den Webhook mit IFTTT Maker verbinden . Ich fand die IFTTT-Benutzeroberfläche etwas verwirrend, aber Sie würden den Docker-Webhook so konfigurieren, dass er unter https://maker.ifttt.com/trigger/docker_xyz_image_built / with / key / veröffentlicht wird your_key.

Wenn Sie lokal erstellen müssen, können Sie zumindest das Problem des Erhaltens von Benachrichtigungen beim Aktualisieren eines Upstream-Images lösen, indem Sie in Docker Hub ein Dummy-Repo erstellen, das mit Ihren Repos verknüpft ist. Der einzige Zweck des Dummy-Repos besteht darin, einen Webhook auszulösen, wenn er neu erstellt wird (was bedeutet, dass eines seiner verknüpften Repos aktualisiert wurde). Wenn Sie diesen Webhook erhalten können, können Sie damit sogar einen Neuaufbau auf Ihrer Seite auslösen.

jjlin
quelle
1
Der Wachtturm verwendet jedoch die Docker-Buchse. Aus Sicherheitsgründen wird der Root-Zugriff auf den Host-Computer vergeben.
JoeG
1
Außerdem scheint Watchtower nicht in der Lage zu sein, Bilder aus anderen privaten Repositorys als Docker Hub zu aktualisieren. Ein Mist für uns, die Azure verwenden.
Thomas Eyde
1
Sie können private Register mit REPO_USERund REPO_PASSUmgebungsvariablen verwenden. Werfen Sie einen Blick auf readme.md vom Wachtturm für weitere Informationen: github.com/v2tec/watchtower#usage
Alejandro Nortes
2
Ein Wort der Warnung: Der Wachturm wird von seinem Betreuer aufgegeben, und das Bild in DockerHub ist nicht einmal mit dem in Github auf dem neuesten Stand.
XanderStrike
Das Wachtturm-Repo scheint auf Containrrr / Wachturm migriert worden zu sein . Und es gibt einige Probleme mit verknüpften automatisierten Builds auf Dockerhub, wie diese Antwort auf eine ähnliche Frage zeigt .
Chrki
10

Ich hatte das gleiche Problem und dachte, es kann einfach durch einen unattended-upgradetäglichen Anruf gelöst werden .

Ich beabsichtige, dies als automatische und schnelle Lösung zu verwenden, um sicherzustellen, dass der Produktionscontainer sicher und aktualisiert ist, da ich einige Zeit benötigen kann, um meine Images zu aktualisieren und ein neues Docker-Image mit den neuesten Sicherheitsupdates bereitzustellen.

Es ist auch möglich, die Image-Erstellung und -Bereitstellung mit Github-Hooks zu automatisieren

Ich habe ein einfaches Docker-Image erstellt , das täglich automatisch Sicherheitsupdates überprüft und installiert (kann direkt von ausgeführt werden docker run itech/docker-unattended-upgrade).

Ich bin auch auf einen anderen Ansatz gestoßen, um zu überprüfen, ob der Container aktualisiert werden muss.

Meine vollständige Implementierung:

Dockerfile

FROM ubuntu:14.04   

RUN apt-get update \
&& apt-get install -y supervisor unattended-upgrades \
&& rm -rf /var/lib/apt/lists/*

COPY install /install
RUN chmod 755 install
RUN /install

COPY start /start
RUN chmod 755 /start

Hilfsskripte

Installieren

#!/bin/bash
set -e

cat > /etc/supervisor/conf.d/cron.conf <<EOF
[program:cron]
priority=20
directory=/tmp
command=/usr/sbin/cron -f
user=root
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
EOF

rm -rf /var/lib/apt/lists/*

ENTRYPOINT ["/start"]

Anfang

#!/bin/bash

set -e

echo "Adding crontab for unattended-upgrade ..."
echo "0 0 * * * root /usr/bin/unattended-upgrade" >> /etc/crontab

# can also use @daily syntax or use /etc/cron.daily

echo "Starting supervisord ..."
exec /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf

Bearbeiten

Ich habe ein kleines Docker- Tool entwickelt , das als Docker-Container ausgeführt wird und zum Aktualisieren von Paketen in allen oder ausgewählten laufenden Containern verwendet werden kann. Es kann auch zum Ausführen beliebiger Befehle verwendet werden.

Kann einfach mit dem folgenden Befehl getestet werden:

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec

Standardmäßig wird der dateBefehl in allen laufenden Containern ausgeführt und die Ergebnisse angezeigt. Wenn Sie updatestattdessen übergeben exec, wird in allen laufenden Containern apt-get updategefolgt von apt-get upgrade -yausgeführt

iTech
quelle
Mein Hinweis auf ein unbeaufsichtigtes Upgrade bestand nur darin, die Analogie in einer Nicht-Docker-Umgebung zu zeigen. Meine Absicht ist es, dies auf Docker-Weise zu lösen (falls vorhanden). Ein zusätzlicher Prozess in einem Container übertrifft den Zweck von Docker imo. Es behebt das Problem der Verzögerung zwischen der Aktualisierung des Images im Upstream und dem tatsächlichen Bereitstellen des Images über Ihren aktuellen Container. Obwohl dies auch bei unbeaufsichtigten Upgrades bis zu 1 Tag dauern kann, ist auch die Github-Referenz nicht zufriedenstellend, da der Update-Mechanismus jetzt stark vom Host-Betriebssystem abhängt.
Hbogert
Der "Docker-Weg" hindert Sie nicht daran, andere Prozesse auf demselben Container auszuführen, wenn diese eng miteinander verbunden sind, und führt nicht zu einem Engpass bei der Skalierbarkeit. Dieser spezielle Anwendungsfall ist ein gutes Beispiel dafür, wann Sie einen Container mit einem anderen laufenden Prozess haben können. (zB siehe Bild für Gitlab, da es mehrere obligatorische Prozesse auf demselben Container ausführt ).
iTech
Ich würde keinen Aktualisierungsmechanismus nennen, der eng mit der Hauptfunktion eines Bildes zusammenhängt. Diese Lösung ist so, als würde jeder Anwendung auf einem herkömmlichen Computer ein eigener Aktualisierungsmechanismus zugewiesen, anstatt einen Paketmanager zu belasten. Obwohl es sich um eine Lösung handelt, beantwortet es nicht meine Frage: Lokale Bilder werden automatisch aktualisiert, und dann sollten Container erneut ausgeführt werden. Mit der Aktualisierung in den Containern selbst führen wir wieder eine Menge Status ein, von dem wir keine Ahnung haben, was gegen den Docker-Weg ist (wieder imho).
Hbogert
1
Möglicherweise benötigen Sie etwas Höheres als Docker, Kubernetesdas für die Bereitstellung großer Infrastrukturen nützlich ist, aber von Google noch stark weiterentwickelt wird. Im Moment können Sie dies mit einem Bereitstellungstool wie Ansible auf relativ einfache Weise automatisieren.
iTech
Ihr zitierter "anderer Ansatz" könnte das sein, wonach ich gesucht habe. Ihr eigener Beitrag scheint eine Alternative für "Fettbehälter" zu sein. Ich werde mich auf jeden Fall etwas näher mit beiden befassen, danke für Ihre Antwort.
Mathias
7

Sie würden nicht wissen, dass Ihr Container im Rückstand ist, ohne Docker Pull auszuführen . Dann müssten Sie Ihr Image neu erstellen oder neu zusammenstellen .

docker pull image:tag
docker-compose -f docker-compose.yml -f production.yml up -d --build

Die Befehle können zusammen mit allem anderen, was zum Abschließen des Upgrades erforderlich ist, in ein Skript eingefügt werden, obwohl für einen geeigneten Container nichts zusätzliches erforderlich wäre.

seanmcl
quelle
1: ok, aber dann müsste ich mir alle meine lokalen Bilder ansehen, ihre Basisbilder holen, diese ziehen. Erstellen Sie dann die Bilder neu, deren Basisbilder sich geändert haben. Stoppen Sie dann Container, deren Image geändert wurde, und erstellen Sie die Container mit 'Docker Run' und den erforderlichen Parametern neu. Dies scheint zu manuell. Aber wenn dies der Status Quo ist, werde ich die Antwort akzeptieren.
Hbogert
Bitte warten Sie, bevor Sie akzeptieren. Vielleicht gibt es da draußen etwas. Ich benutze Docker seit 6 Monaten, bin aber nicht mit den neuesten Entwicklungen Schritt gehalten.
Seanmcl
Intern kann Docker Bilder irgendwie vergleichen, um die Caching-Funktion auszuführen. Vielleicht können Sie einen Weg finden, DAS zu nutzen. Mit anderen Worten, überprüfen Sie, ob sich die zugrunde liegenden Bilder (bis zur Basis) geändert haben, und lösen Sie dann einen Prozess zum Wiederherstellen aus. Leider hilft Ihnen das Caching in diesem Fall nicht weiter: Das gesamte Image wird neu erstellt, da sich das Basis-Image geändert hat.
Thom Parkin
5

Das Abhängigkeitsmanagement für Docker-Images ist ein echtes Problem. Ich bin Teil eines Teams, das mit MicroBadger ein Tool entwickelt hat, das dabei hilft , Container-Images zu überwachen und Metadaten zu überprüfen . Eine der Funktionen besteht darin, dass Sie einen Benachrichtigungs-Webhook einrichten können, der aufgerufen wird, wenn sich ein Bild, an dem Sie interessiert sind (z. B. ein Basisbild), ändert.

Liz Rice
quelle
5

Hier gibt es viele Antworten, aber keine davon entsprach meinen Bedürfnissen. Ich wollte eine tatsächliche Antwort auf die Frage Nr. 1 des Fragestellers. Woher weiß ich, wann ein Bild auf hub.docker.com aktualisiert wird?

Das folgende Skript kann täglich ausgeführt werden. Beim ersten Ausführen werden die Tags und Aktualisierungsdaten aus der HUB-Registrierung abgerufen und lokal gespeichert. Von da an überprüft es bei jeder Ausführung die Registrierung auf neue Tags und Aktualisierungsdaten. Da sich dies jedes Mal ändert, wenn ein neues Bild vorhanden ist, wird angezeigt, ob sich das Basisbild geändert hat. Hier ist das Skript:

#!/bin/bash

DATAPATH='/data/docker/updater/data'

if [ ! -d "${DATAPATH}" ]; then
        mkdir "${DATAPATH}";
fi
IMAGES=$(docker ps --format "{{.Image}}")
for IMAGE in $IMAGES; do
        ORIGIMAGE=${IMAGE}
        if [[ "$IMAGE" != *\/* ]]; then
                IMAGE=library/${IMAGE}
        fi
        IMAGE=${IMAGE%%:*}
        echo "Checking ${IMAGE}"
        PARSED=${IMAGE//\//.}
        if [ ! -f "${DATAPATH}/${PARSED}" ]; then
                # File doesn't exist yet, make baseline
                echo "Setting baseline for ${IMAGE}"
                curl -s "https://registry.hub.docker.com/v2/repositories/${IMAGE}/tags/" > "${DATAPATH}/${PARSED}"
        else
                # File does exist, do a compare
                NEW=$(curl -s "https://registry.hub.docker.com/v2/repositories/${IMAGE}/tags/")
                OLD=$(cat "${DATAPATH}/${PARSED}")
                if [[ "${VAR1}" == "${VAR2}" ]]; then
                        echo "Image ${IMAGE} is up to date";
                else
                        echo ${NEW} > "${DATAPATH}/${PARSED}"
                        echo "Image ${IMAGE} needs to be updated";
                        H=`hostname`
                        ssh -i /data/keys/<KEYFILE> <USER>@<REMOTEHOST>.com "{ echo \"MAIL FROM: root@${H}\"; echo \"RCPT TO: <USER>@<EMAILHOST>.com\"; echo \"DATA\"; echo \"Subject: ${H} - ${IMAGE} needs update\"; echo \"\"; echo -e \"\n${IMAGE} needs update.\n\ndocker pull ${ORIGIMAGE}\"; echo \"\"; echo \".\"; echo \"quit\"; sleep 1; } | telnet <SMTPHOST> 25"
                fi

        fi
done;

Sie möchten die DATAPATHVariable oben und den E-Mail-Benachrichtigungsbefehl am Ende an Ihre Anforderungen anpassen. Für mich habe ich es SSH in einem Server in einem anderen Netzwerk, in dem sich mein SMTP befindet. Sie können den mailBefehl aber auch problemlos verwenden .

Jetzt möchten Sie auch in den Containern selbst nach aktualisierten Paketen suchen. Dies ist wahrscheinlich effektiver als ein "Ziehen", sobald Ihre Container funktionieren. Hier ist das Skript, um das durchzuziehen:

#!/bin/bash


function needsUpdates() {
        RESULT=$(docker exec ${1} bash -c ' \
                if [[ -f /etc/apt/sources.list ]]; then \
                grep security /etc/apt/sources.list > /tmp/security.list; \
                apt-get update > /dev/null; \
                apt-get upgrade -oDir::Etc::Sourcelist=/tmp/security.list -s; \
                fi; \
                ')
        RESULT=$(echo $RESULT)
        GOODRESULT="Reading package lists... Building dependency tree... Reading state information... Calculating upgrade... 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded."
        if [[ "${RESULT}" != "" ]] && [[ "${RESULT}" != "${GOODRESULT}" ]]; then
                return 0
        else
                return 1
        fi
}

function sendEmail() {
        echo "Container ${1} needs security updates";
        H=`hostname`
        ssh -i /data/keys/<KEYFILE> <USRER>@<REMOTEHOST>.com "{ echo \"MAIL FROM: root@${H}\"; echo \"RCPT TO: <USER>@<EMAILHOST>.com\"; echo \"DATA\"; echo \"Subject: ${H} - ${1} container needs security update\"; echo \"\"; echo -e \"\n${1} container needs update.\n\n\"; echo -e \"docker exec ${1} bash -c 'grep security /etc/apt/sources.list > /tmp/security.list; apt-get update > /dev/null; apt-get upgrade -oDir::Etc::Sourcelist=/tmp/security.list -s'\n\n\"; echo \"Remove the -s to run the update\"; echo \"\"; echo \".\"; echo \"quit\"; sleep 1; } | telnet <SMTPHOST> 25"
}

CONTAINERS=$(docker ps --format "{{.Names}}")
for CONTAINER in $CONTAINERS; do
        echo "Checking ${CONTAINER}"
        if needsUpdates $CONTAINER; then
                sendEmail $CONTAINER
        fi
done
Fmstrat
quelle
1
mkdir im ersten Skript sollte wahrscheinlich sein: mkdir -p Außerdem vergleicht das erste Skript VAR1 mit VAR2, vorausgesetzt, es sollte OLD mit NEW vergleichen. Wenn dies jedoch zutrifft, bedeutet dies, dass dieses Skript nicht wirklich das tut, was OP will, es sei denn, es wurde zum Zeitpunkt der Installation zum ersten Mal ausgeführt. Das heißt, es bestimmt nicht wirklich etwas darüber, was installiert ist, nur wenn die Ergebnisse von früheren Läufen abweichen ...
JoeG
5

Ein anderer Ansatz könnte darin bestehen, anzunehmen, dass Ihr Basis-Image ziemlich schnell in Verzug gerät (und das ist sehr wahrscheinlich), und regelmäßig (z. B. jede Woche) einen weiteren Image-Build Ihrer Anwendung zu erzwingen und ihn dann erneut bereitzustellen, wenn er sich geändert hat.

Soweit ich das beurteilen kann, aktualisieren beliebte Basis-Images wie das offizielle Debian oder Java ihre Tags, um Sicherheitsupdates zu berücksichtigen, sodass Tags nicht unveränderlich sind (wenn Sie eine stärkere Garantie dafür wünschen, müssen Sie die Referenz [image: @digest] verwenden ], verfügbar in neueren Docker-Versionen). Wenn Sie also Ihr Image mit erstellen möchten docker build --pull, sollte Ihre Anwendung das neueste und beste der Basis-Image-Tags erhalten, auf die Sie verweisen.

Da veränderbare Tags verwirrend sein können, ist es am besten, die Versionsnummer Ihrer Anwendung jedes Mal zu erhöhen, damit zumindest auf Ihrer Seite die Dinge sauberer werden.

Ich bin mir also nicht sicher, ob das in einer der vorherigen Antworten vorgeschlagene Skript die Aufgabe erfüllt, da es das Image Ihrer Anwendung nicht neu erstellt. Es aktualisiert lediglich das Basis-Image-Tag und startet dann den Container neu, aber der neue Container verweist weiterhin der alte Basisbild-Hash.

Ich würde nicht befürworten, Cron-Jobs in Containern (oder anderen Prozessen, sofern nicht wirklich notwendig) auszuführen, da dies gegen das Mantra verstößt, nur einen Prozess pro Container auszuführen (es gibt verschiedene Argumente, warum dies besser ist, also ich ' Ich werde hier nicht darauf eingehen.

Bogdan
quelle
4

Ich gehe nicht auf die ganze Frage ein, ob Sie unbeaufsichtigte Updates in der Produktion wünschen oder nicht (ich denke nicht). Ich lasse dies hier nur als Referenz, falls jemand es nützlich findet. Aktualisieren Sie alle Docker-Images mit dem folgenden Befehl in Ihrem Terminal auf die neueste Version:

# docker images | awk '(NR>1) && ($2!~/none/) {print $1":"$2}' | xargs -L1 docker pull

Meferdati
quelle
1
Der Befehl ist nützlich, um alle Bilder zu aktualisieren, ändert jedoch nichts, was in der Produktion ausgeführt wird. Die Container stammen noch aus den alten Bildern, die jetzt nicht markiert sind.
Keine
Wahr. Und hier ist noch eine für die Bücher ... Verwenden Sie # docker system prune -a --volumes -f, um alte (baumelnde) Bilder, Bände usw. zu
bereinigen
4

UPDATE: Verwenden Sie Dependabot - https://dependabot.com/docker/

BLUF: Die Herausforderung besteht darin, die richtige Einfügemarke für die Überwachung von Änderungen an einem Container zu finden. Es wäre großartig, wenn DockerHub dies lösen würde. (Repository-Links wurden erwähnt, aber beachten Sie beim Einrichten in DockerHub: " Lösen Sie einen Build in diesem Repository aus, wenn das Basis-Image in Docker Hub aktualisiert wird. Funktioniert nur für nicht offizielle Images." )

Während ich versuchte, dieses Problem selbst zu lösen, sah ich einige Empfehlungen für Webhooks, daher wollte ich einige der von mir verwendeten Lösungen näher erläutern.

  1. Verwenden Sie microbadger.com, um Änderungen in einem Container zu verfolgen, und verwenden Sie die Benachrichtigungs-Webhook-Funktion, um eine Aktion auszulösen. Ich habe dies mit zapier.com eingerichtet (Sie können jedoch jeden anpassbaren Webhook-Dienst verwenden), um ein neues Problem in meinem Github-Repository zu erstellen, das Alpine als Basis-Image verwendet.

    • Vorteile: Sie können die vom Mikrobadger in Github gemeldeten Änderungen überprüfen, bevor Sie Maßnahmen ergreifen.
    • Nachteile: Mit Microbadger können Sie kein bestimmtes Tag verfolgen. Sieht so aus, als würde es nur "Neueste" verfolgen.
  2. Verfolgen Sie den RSS-Feed für Git-Commits in einem Upstream-Container. Ex. https://github.com/gliderlabs/docker-alpine/commits/rootfs/library-3.8/x86_64 . Ich habe zapier.com verwendet, um diesen Feed zu überwachen und einen automatischen Build meines Containers in Travis-CI auszulösen, wenn etwas festgeschrieben wird. Dies ist ein wenig extrem, aber Sie können den Auslöser ändern, um andere Dinge zu tun, z. B. ein Problem in Ihrem Git-Repository für manuelle Eingriffe zu öffnen.

    • Vorteile: Näher an einer automatisierten Pipline. Der Travis-CI-Build prüft nur, ob Ihr Container Probleme mit dem hat, was für das Basis-Image-Repository festgeschrieben wurde. Es liegt an Ihnen, ob Ihr CI-Service weitere Maßnahmen ergreift.
    • Nachteile: Das Verfolgen des Commit-Feeds ist nicht perfekt. Viele Dinge werden in das Repository übernommen, die sich nicht auf die Erstellung des Basisimages auswirken. Berücksichtigt keine Probleme mit der Häufigkeit / Anzahl der Festschreibungen und der API-Drosselung.
2 Stapel
quelle
3

Voraussetzung für meine Antwort:

  1. Container werden mit Tags ausgeführt.
  2. Das gleiche Tag kann auf eine andere Bild-UUID verwiesen werden, wenn wir dies für angemessen halten.
  3. Aktualisierungen, die an einem Bild vorgenommen wurden, können auf eine neue Bildebene übertragen werden

Ansatz

  1. Erstellen Sie zunächst alle Container mit einem Security-Patch-Update-Skript
  2. Erstellen Sie einen automatisierten Prozess für Folgendes
    • Führen Sie ein vorhandenes Image in einem neuen Container mit dem Sicherheitspatch-Skript als Befehl aus
    • Übernehmen Sie Änderungen am Bild als
      • vorhandenes Tag -> gefolgt von einem Neustart der Container nacheinander
      • neues Versions-Tag -> wenige Container durch neues Tag ersetzen -> validieren -> alle Container in neues Tag verschieben

Zusätzlich kann das Basis-Image aktualisiert werden / der Container mit einem komplett neuen Basis-Image kann in regelmäßigen Abständen erstellt werden, wenn der Betreuer dies für erforderlich hält

Vorteile

  1. Wir behalten die alte Version des Images bei, während wir das neue gepatchte Sicherheits-Image erstellen. Daher können wir bei Bedarf ein Rollback zum vorherigen laufenden Image durchführen
  2. Wir behalten den Docker-Cache bei, daher weniger Netzwerkübertragung (nur die geänderte Schicht gelangt auf die Leitung)
  3. Der Upgrade-Prozess kann im Staging überprüft werden, bevor zu prod gewechselt wird
  4. Dies kann ein kontrollierter Prozess sein, daher können die Sicherheitspatches nur dann verschoben werden, wenn dies erforderlich / als wichtig erachtet wird.
Phani
quelle
In einer Produktionsumgebung, obwohl es sich um Sicherheitsupdates handelt, bezweifle ich, dass Sie unbeaufsichtigte Updates wünschen würden! Wenn unbeaufsichtigte Aktualisierungen erforderlich sind, kann der Prozess in regelmäßigen Abständen (je nach Bedarf) als Cron-Job ausgeführt werden.
Phani
1
Ich gehe davon aus, dass Sicherheitsupdates von Upstream- / Basis-Images stammen sollten.
Hbogert
@hbogert Ich würde eher sagen, dass es eine feine Unterscheidung zwischen Theorie und Praxis gibt. Wenn die Dinge in die Praxis umgesetzt werden, müssen viele externe Aspekte berücksichtigt werden, z. B.: Kosten (nicht nur Dollarwert, sondern auch Zeit) im Zusammenhang mit der Implementierung.
Phani
3

Die obigen Antworten sind ebenfalls korrekt

Es gibt zwei Ansätze

  1. Verwenden Sie Webhooks
  2. Führen Sie das Skript für jede bestimmte Minute aus, um Docker-Bilder neu abzurufen

Ich teile nur das Skript, vielleicht wird es für Sie hilfreich sein! Sie können es mit Cronjob verwenden, ich habe es erfolgreich unter OSX versucht

#!/bin/bash
##You can use below commented line for setting cron tab for running cron job and to store its O/P in one .txt file  
#* * * * * /usr/bin/sudo -u admin -i bash -c /Users/Swapnil/Documents/checkimg.sh > /Users/Swapnil/Documents/cron_output.log 2>&1
# Example for the Docker Hub V2 API
# Returns all images and tags associated with a Docker Hub organization account.
# Requires 'jq': https://stedolan.github.io/jq/

# set username, password, and organization
# Filepath where your docker-compose file is present
FILEPATH="/Users/Swapnil/Documents/lamp-alpine"
# Your Docker hub user name
UNAME="ur username"
# Your Docker hub user password
UPASS="ur pwd"
# e.g organisation_name/image_name:image_tag
ORG="ur org name"
IMGNAME="ur img name"
IMGTAG="ur img tag"
# Container name
CONTNAME="ur container name"
# Expected built mins
BUILDMINS="5"
#Generally cronjob frequency
CHECKTIME="5"
NETWORKNAME="${IMGNAME}_private-network"
#After Image pulling, need to bring up all docker services?
DO_DOCKER_COMPOSE_UP=true
# -------
echo "Eecuting Script @ date and time in YmdHMS: $(date +%Y%m%d%H%M%S)"
set -e
PIDFILE=/Users/Swapnil/Documents/$IMGNAME/forever.pid
if [ -f $PIDFILE ]
then
  PID=$(cat $PIDFILE)
  ps -p $PID > /dev/null 2>&1
  if [ $? -eq 0 ]
  then
    echo "Process already running"
    exit 1
  else
    ## Process not found assume not running
    echo $$
    echo $$ > $PIDFILE
    if [ $? -ne 0 ]
    then
      echo "Could not create PID file"
      exit 1
    fi
  fi
else
  echo $$ > $PIDFILE
  if [ $? -ne 0 ]
  then
    echo "Could not create PID file"
    exit 1
  fi
fi

# Check Docker is running or not; If not runing then exit
if docker info|grep Containers ; then
    echo "Docker is running"
else
    echo "Docker is not running"
    rm $PIDFILE
    exit 1
fi

# Check Container is running or not; and set variable
CONT_INFO=$(docker ps -f "name=$CONTNAME" --format "{{.Names}}")
if [ "$CONT_INFO" = "$CONTNAME" ]; then
    echo "Container is running"
    IS_CONTAINER_RUNNING=true
else
    echo "Container is not running"
    IS_CONTAINER_RUNNING=false
fi


# get token
echo "Retrieving token ..."
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${UNAME}'", "password": "'${UPASS}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)

# get list of repositories
echo "Retrieving repository list ..."
REPO_LIST=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/?page_size=100 | jq -r '.results|.[]|.name')

# output images & tags
echo "Images and tags for organization: ${ORG}"
echo
for i in ${REPO_LIST}
do
  echo "${i}:"
  # tags
  IMAGE_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/${i}/tags/?page_size=100 | jq -r '.results|.[]|.name')
  for j in ${IMAGE_TAGS}
  do
    echo "  - ${j}"
  done
  #echo
done

# Check Perticular image is the latest or not
#imm=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/${IMGNAME}/tags/?page_size=100)
echo "-----------------"
echo "Last built date details about Image ${IMGNAME} : ${IMGTAG} for organization: ${ORG}"
IMAGE_UPDATED_DATE=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/${ORG}/${IMGNAME}/tags/?page_size=100 | jq -r '.results|.[]|select(.name | contains("'${IMGTAG}'")).last_updated')
echo "On Docker Hub IMAGE_UPDATED_DATE---$IMAGE_UPDATED_DATE"
echo "-----------------"

IMAGE_CREATED_DATE=$(docker image inspect ${ORG}/${IMGNAME}:${IMGTAG} | jq -r '.[]|.Created')
echo "Locally IMAGE_CREATED_DATE---$IMAGE_CREATED_DATE"

updatedDate=$(date -jf '%Y-%m-%dT%H:%M' "${IMAGE_UPDATED_DATE:0:16}" +%Y%m%d%H%M%S) 
createdDate=$(date -jf '%Y-%m-%dT%H:%M' "${IMAGE_CREATED_DATE:0:16}" +%Y%m%d%H%M%S)
currentDate=$(date +%Y%m%d%H%M%S)

start_date=$(date -jf "%Y%m%d%H%M%S" "$currentDate" "+%s")
end_date=$(date -jf "%Y%m%d%H%M%S" "$updatedDate" "+%s")
updiffMins=$(( ($start_date - $end_date) / (60) ))
if [[ "$updiffMins" -lt $(($CHECKTIME+1)) ]]; then
        if [ ! -d "${FILEPATH}" ]; then
            mkdir "${FILEPATH}";
        fi
        cd "${FILEPATH}"
        pwd
        echo "updatedDate---$updatedDate" > "ScriptOutput_${currentDate}.txt"
        echo "createdDate---$createdDate" >> "ScriptOutput_${currentDate}.txt"
        echo "currentDate---$currentDate" >> "ScriptOutput_${currentDate}.txt"
        echo "Found after regular checking time -> Docker hub's latest updated image is new; Diff ${updiffMins} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Script is checking for latest updates after every ${CHECKTIME} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Fetching all new"
        echo "---------------------------"
        if $IS_CONTAINER_RUNNING ; then
            echo "Container is running"         
        else
            docker-compose down
            echo "Container stopped and removed; Network removed" >> "ScriptOutput_${currentDate}.txt"
        fi
        echo "Image_Created_Date=$currentDate" > ".env"
        echo "ORG=$ORG" >> ".env"
        echo "IMGNAME=$IMGNAME" >> ".env"
        echo "IMGTAG=$IMGTAG" >> ".env"
        echo "CONTNAME=$CONTNAME" >> ".env"
        echo "NETWORKNAME=$NETWORKNAME" >> ".env"
        docker-compose build --no-cache
        echo "Docker Compose built" >> "ScriptOutput_${currentDate}.txt"
        if $DO_DOCKER_COMPOSE_UP ; then
            docker-compose up -d
            echo "Docker services are up now, checked in" >> "ScriptOutput_${currentDate}.txt"  
        else
            echo "Docker services are down, checked in" >> "ScriptOutput_${currentDate}.txt"
        fi
elif [[ "$updatedDate" -gt "$createdDate" ]]; then 
    echo "Updated is latest"
    start_date=$(date -jf "%Y%m%d%H%M%S" "$updatedDate" "+%s")
    end_date=$(date -jf "%Y%m%d%H%M%S" "$createdDate" "+%s")
    diffMins=$(( ($start_date - $end_date) / (60) ))
    if [[ "$BUILDMINS" -lt "$diffMins" ]]; then
        if [ ! -d "${FILEPATH}" ]; then
            mkdir "${FILEPATH}";
        fi
        cd "${FILEPATH}"
        pwd
        echo "updatedDate---$updatedDate" > "ScriptOutput_${currentDate}.txt"
        echo "createdDate---$createdDate" >> "ScriptOutput_${currentDate}.txt"
        echo "currentDate---$currentDate" >> "ScriptOutput_${currentDate}.txt"
        echo "Found after comparing times -> Docker hub's latest updated image is new; Diff ${diffMins} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Actual image built time is less i.e. ${diffMins} mins than MAX expexted BUILD TIME i.e. ${BUILDMINS} mins" >> "ScriptOutput_${currentDate}.txt"
        echo "Fetching all new" >> "ScriptOutput_${currentDate}.txt"
        echo "-----------------------------"
        if $IS_CONTAINER_RUNNING ; then
            echo "Container is running"         
        else
            docker-compose down
            echo "Container stopped and removed; Network removed" >> "ScriptOutput_${currentDate}.txt"
        fi
        echo "Image_Created_Date=$currentDate" > ".env"
        echo "ORG=$ORG" >> ".env"
        echo "IMGNAME=$IMGNAME" >> ".env"
        echo "IMGTAG=$IMGTAG" >> ".env"
        echo "CONTNAME=$CONTNAME" >> ".env"
        echo "NETWORKNAME=$NETWORKNAME" >> ".env"
        docker-compose build --no-cache
        echo "Docker Compose built" >> "ScriptOutput_${currentDate}.txt"
        if $DO_DOCKER_COMPOSE_UP ; then
            docker-compose up -d
            echo "Docker services are up now" >> "ScriptOutput_${currentDate}.txt"  
        else
            echo "Docker services are down" >> "ScriptOutput_${currentDate}.txt"
        fi
    elif [[ "$BUILDMINS" -gt "$diffMins" ]]; then
        echo "Docker hub's latest updated image is NOT new; Diff ${diffMins} mins"
        echo "Docker images not fetched"
    else
        echo "Docker hub's latest updated image is NOT new; Diff ${diffMins} mins"
        echo "Docker images not fetched"
    fi
elif [[ "$createdDate" -gt "$updatedDate" ]]; then 
    echo "Created is latest"
    start_date=$(date -jf "%Y%m%d%H%M%S" "$createdDate" "+%s")
    end_date=$(date -jf "%Y%m%d%H%M%S" "$updatedDate" "+%s")
    echo "Docker hub has older docker image than local; Older than $(( ($start_date - $end_date) / (60) ))mins"
fi
echo 
echo "------------end---------------"
rm $PIDFILE

Hier ist meine Docker-Compose-Datei

version:  "3.2"
services:
  lamp-alpine:
    build:
      context: .
    container_name: "${CONTNAME}"
    image: "${ORG}/${IMGNAME}:${IMGTAG}"
    ports:
      - "127.0.0.1:80:80"
    networks:
      - private-network 

networks:
  private-network:
    driver: bridge
Akshay Shikre
quelle
3

Hier ist die einfachste Möglichkeit, den Docker-Container automatisch zu aktualisieren

Stellen Sie den Job über $ crontab -e:

0 * * * * sh ~/.docker/cron.sh

Verzeichnis ~/.dockermit Datei erstellen cron.sh:

#!/bin/sh
if grep -Fqe "Image is up to date" << EOF
`docker pull ubuntu:latest`
EOF
then
    echo "no update, just do cleaning"
    docker system prune --force
else
    echo "newest exist, recompose!"
    cd /path/to/your/compose/file
    docker-compose down --volumes
    docker-compose up -d
fi
Chetabahana
quelle
0

Haben Sie dies versucht: https://github.com/v2tec/watchtower . Es ist ein einfaches Tool, das im Docker-Container ausgeführt wird und andere Container überwacht. Wenn sich das Basis-Image ändert, wird es abgerufen und erneut bereitgestellt.

linehrr
quelle
-1

Eine einfache und großartige Lösung ist Hirte

user672009
quelle
iiuc, dies hilft nicht im allgemeinen Sinne, da dies an Swarm gekoppelt ist und nur stromaufwärts neu gestartet wird, während wir auf vorgelagerte Änderungen reagieren, neu erstellen usw. und nicht einfach neu starten möchten.
Hbogert
Das klingt nach etwas, das Sie in einer CI-Pipeline tun sollten
user672009