假设我有一个基于ubuntu:latest
. 现在有一个安全更新,并ubuntu:latest
在 docker repo 中更新。
我怎么知道我的本地映像及其容器在后面运行?
是否有一些自动更新本地图像和容器以遵循 docker repo 更新的最佳实践,这实际上会给你在传统的 ubuntu 机器上运行无人值守升级的相同好处
假设我有一个基于ubuntu:latest
. 现在有一个安全更新,并ubuntu:latest
在 docker repo 中更新。
我怎么知道我的本地映像及其容器在后面运行?
是否有一些自动更新本地图像和容器以遵循 docker repo 更新的最佳实践,这实际上会给你在传统的 ubuntu 机器上运行无人值守升级的相同好处
我们使用一个脚本来检查正在运行的容器是否以最新的图像启动。我们还使用 upstart 初始化脚本来启动 docker 镜像。
#!/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
和 init 看起来像
docker run -t -i --name $NAME $im /bin/bash
一种“码头方式”是使用docker hub 自动构建。Repository Links功能将在上游容器重建时重建您的容器,Webhooks功能将向您发送通知。
看起来 webhook 仅限于 HTTP POST 调用。您需要设置一个服务来捕获它们,或者可能使用其中一个 POST 来发送电子邮件服务。
我还没有研究过,但新的Docker 通用控制平面可能具有检测更新容器和重新部署的功能。
您可以使用Watchtower来监视实例化容器的镜像的更新,并自动拉取更新并使用更新的镜像重新启动容器。但是,这并不能解决在其所基于的上游映像发生更改时重建您自己的自定义映像的问题。您可以将此视为一个由两部分组成的问题:(1) 了解上游映像何时更新,以及 (2) 进行实际的映像重建。(1) 可以很容易地解决,但 (2) 在很大程度上取决于您当地的构建环境/实践,因此为此创建通用解决方案可能要困难得多。
如果您能够使用 Docker Hub 的自动构建,则可以使用存储库链接功能相对干净地解决整个问题,这使您可以在链接存储库(可能是上游存储库)更新时自动触发重建。您还可以配置webhook以在发生自动构建时通知您。如果您需要电子邮件或短信通知,您可以将 webhook 连接到IFTTT Maker。我发现 IFTTT 用户界面有点令人困惑,但您可以将 Docker webhook 配置为发布到https://maker.ifttt.com/trigger/`docker_xyz_image_built`/with/key/`your_key`。
如果您需要在本地构建,您至少可以通过在 Docker Hub 中创建一个链接到您感兴趣的存储库的虚拟存储库来解决更新上游映像时获取通知的问题。虚拟存储库的唯一目的是在重建时触发 webhook(这意味着其链接的存储库之一已更新)。如果您能够收到此 webhook,您甚至可以使用它来触发您这边的重建。
一种方法是通过您的 CI/CD 系统来驱动它。构建父映像后,请使用该父映像扫描您的 git 存储库以查找图像。如果找到,然后您将发送拉取请求以碰撞到图像的新版本。如果所有测试都通过,拉取请求将被合并,并且您将拥有一个基于更新父级的新子图像。可以在此处找到采用这种方法的工具示例:https ://engineering.salesforce.com/open-sourcing-dockerfile-image-update-6400121c1a75 。
如果你不控制你的父图像,如果你依赖于官方ubuntu
图像,你可以编写一些工具来检测父图像标签或校验和的变化(不是一回事,标签是可变的)和相应地调用子图像构建。
我有同样的问题,并认为它可以通过unattended-upgrade
每天调用一个 cron 作业来解决。
我的目的是将其作为一种自动且快速的解决方案,以确保生产容器的安全和更新,因为我可能需要一些时间来更新我的映像并使用最新的安全更新部署一个新的 docker 映像。
也可以使用Github 钩子自动化图像构建和部署
我创建了一个基本的docker 镜像,它每天自动检查和安装安全更新(可以直接运行docker run itech/docker-unattended-upgrade
)。
我还遇到了另一种不同的方法来检查容器是否需要更新。
我的完整实现:
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
帮助脚本
安装
#!/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"]
开始
#!/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
编辑
我开发了一个小工具docker-run,它作为 docker 容器运行,可用于更新所有或选定的运行容器中的包,也可用于运行任意命令。
可以使用以下命令轻松测试:
docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec
默认情况下,它将date
在所有正在运行的容器中执行命令并显示结果。如果你通过update
而不是exec
它将在所有正在运行的容器中apt-get update
执行apt-get upgrade -y
如果不运行docker pull,您将不会知道您的容器落后了。然后你需要重建或重组你的形象。
docker pull image:tag
docker-compose -f docker-compose.yml -f production.yml up -d --build
这些命令可以与完成升级所需的任何其他内容一起放入脚本中,尽管适当的容器不需要任何额外内容。
这是自动更新 docker 容器的最简单方法
通过以下方式完成工作$ crontab -e
:
0 * * * * sh ~/.docker/cron.sh
~/.docker
使用文件创建目录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
这里有很多答案,但没有一个适合我的需要。我想要对提问者的 #1 问题的实际答案。我如何知道 hub.docker.com 上的图像何时更新?
以下脚本可以每天运行。首次运行时,它会从 HUB 注册表中获取标签的基线和更新日期,并将它们保存在本地。从那时起,每次运行它都会检查注册表中的新标签和更新日期。由于每次存在新图像时都会更改,因此它会告诉我们基础图像是否已更改。这是脚本:
#!/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;
您将需要更改DATAPATH
顶部的变量,并在末尾更改电子邮件通知命令以满足您的需要。对我来说,我将它通过 SSH 连接到我的 SMTP 所在的另一个网络上的服务器。但是您也可以轻松使用该mail
命令。
现在,您还想检查容器本身内的更新包。这实际上可能比在容器工作后进行“拉动”更有效。这是实现这一目标的脚本:
#!/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
更新:使用 Dependabot - https://dependabot.com/docker/
BLUF:找到合适的插入点来监控容器的变化是一个挑战。如果 DockerHub 能解决这个问题,那就太好了。(已经提到了存储库链接,但在 DockerHub 上设置它们时请注意 - “只要在 Docker Hub 上更新基础映像,就在此存储库中触发构建。仅适用于非官方映像。”)
在尝试自己解决这个问题时,我看到了一些关于 webhook 的建议,所以我想详细说明我使用过的几个解决方案。
使用 microbadger.com 跟踪容器中的更改并使用它的通知 webhook 功能来触发操作。我使用 zapier.com 进行了设置(但您可以使用任何可自定义的 webhook 服务)在我的 github 存储库中创建一个使用 Alpine 作为基础映像的新问题。
跟踪 git 提交到上游容器的 RSS 提要。前任。https://github.com/gliderlabs/docker-alpine/commits/rootfs/library-3.8/x86_64。我使用 zapier.com 来监控这个提要,并在提交任何内容时触发 Travis-CI 中容器的自动构建。这有点极端,但您可以更改触发器以执行其他操作,例如在 git 存储库中打开问题以进行手动干预。
Docker 镜像的依赖管理是一个真正的问题。我是构建工具MicroBadger的团队的一员,通过监视容器映像和检查元数据来帮助解决这个问题。它的一个功能是让您设置一个通知 webhook,当您感兴趣的图像(例如基础图像)发生更改时,该通知 webhook 会被调用。
另一种方法可能是假设您的基本映像很快就落后了(这很可能发生),并定期(例如每周)强制构建您的应用程序的另一个映像,然后如果它发生了变化则重新部署它。
据我所知,像官方 Debian 或 Java 这样的流行基础镜像会更新它们的标签以适应安全修复,所以标签不是一成不变的(如果你想要更强有力的保证,你需要使用参考 [image:@digest ],在更新的 Docker 版本中可用)。因此,如果您要使用 构建映像 docker build --pull
,那么您的应用程序应该获得您所引用的最新和最好的基本映像标记。
由于可变标签可能会令人困惑,因此最好每次执行此操作时都增加应用程序的版本号,这样至少在您这边事情会更干净。
因此,我不确定先前答案之一中建议的脚本是否可以完成这项工作,因为它不会重建您的应用程序映像 - 它只是更新基本映像标记,然后重新启动容器,但新容器仍然引用旧的基础图像哈希。
我不提倡在容器(或任何其他进程,除非真的有必要)中运行 cron 类型的作业,因为这违背了每个容器只运行一个进程的口头禅(关于为什么这更好,有各种争论,所以我我不打算在这里讨论)。
我不会讨论您是否想要在生产中进行无人值守更新的整个问题(我认为不是)。我只是将其留在这里以供参考,以防有人发现它有用。使用终端中的以下命令将所有 docker 映像更新到最新版本:
# docker images | awk '(NR>1) && ($2!~/none/) {print $1":"$2}' | xargs -L1 docker pull
以我的回答为前提:
方法
此外,可以升级基础镜像/可以定期构建具有全新基础镜像的容器,因为维护者认为有必要
优点
以上答案也是正确的
有两种方法
- 使用网络挂钩
- 每特定分钟运行脚本以获取最新的 docker 图像
我只是分享脚本可能对你有帮助!您可以将它与 cronjob 一起使用,我在 OSX 上成功尝试过
#!/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
这是我的 docker-compose 文件
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
你试过这个吗:https ://github.com/v2tec/watchtower 。它是一个在 docker 容器中运行的简单工具,用于监视其他容器,如果它们的基本映像发生更改,它将拉取并重新部署。
一个简单而伟大的解决方案是牧羊人