假设我有一个基于ubuntu:latest的普通容器。现在有一个安全更新和ubuntu:latest更新在docker repo。
我如何知道我的本地映像及其容器运行落后? 是否有一些最佳实践来自动更新本地映像和容器来跟踪docker回购更新,这在实践中会给你同样的好处,让无人值守的升级运行在传统的ubuntu机器上
假设我有一个基于ubuntu:latest的普通容器。现在有一个安全更新和ubuntu:latest更新在docker repo。
我如何知道我的本地映像及其容器运行落后? 是否有一些最佳实践来自动更新本地映像和容器来跟踪docker回购更新,这在实践中会给你同样的好处,让无人值守的升级运行在传统的ubuntu机器上
当前回答
One of the ways to do it is to drive this through your CI/CD systems. Once your parent image is built, have something that scans your git repos for images using that parent. If found, you'd then send a pull request to bump to new versions of the image. The pull request, if all tests pass, would be merged and you'd have a new child image based on updated parent. An example of a tool that takes this approach can be found here: https://engineering.salesforce.com/open-sourcing-dockerfile-image-update-6400121c1a75 .
如果你不控制你的父映像,就像你依赖于官方ubuntu映像的情况一样,你可以写一些工具来检测父映像标记或校验和(不是一回事,标记是可变的)的变化,并相应地调用子映像构建。
其他回答
你不会知道你的集装箱在后面没有运行码头拉。然后,您需要重新构建或重组您的映像。
docker pull image:tag
docker-compose -f docker-compose.yml -f production.yml up -d --build
这些命令可以与完成升级所需的任何其他东西一起放在脚本中,尽管一个合适的容器不需要任何额外的东西。
You can use Watchtower to watch for updates to the image a container is instantiated from and automatically pull the update and restart the container using the updated image. However, that doesn't solve the problem of rebuilding your own custom images when there's a change to the upstream image it's based on. You could view this as a two-part problem: (1) knowing when an upstream image has been updated, and (2) doing the actual image rebuild. (1) can be solved fairly easily, but (2) depends a lot on your local build environment/practices, so it's probably much harder to create a generalized solution for that.
If you're able to use Docker Hub's automated builds, the whole problem can be solved relatively cleanly using the repository links feature, which lets you trigger a rebuild automatically when a linked repository (probably an upstream one) is updated. You can also configure a webhook to notify you when an automated build occurs. If you want an email or SMS notification, you could connect the webhook to IFTTT Maker. I found the IFTTT user interface to be kind of confusing, but you would configure the Docker webhook to post to https://maker.ifttt.com/trigger/`docker_xyz_image_built`/with/key/`your_key`.
如果你需要在本地构建,你至少可以通过在Docker Hub中创建一个连接到你感兴趣的repo的虚拟repo来解决上游映像更新时收到通知的问题。虚拟回购的唯一目的是在重新构建时触发一个webhook(这意味着它的一个链接回购被更新)。如果你能收到这个webhook,你甚至可以用它来触发你这边的重建。
One of the ways to do it is to drive this through your CI/CD systems. Once your parent image is built, have something that scans your git repos for images using that parent. If found, you'd then send a pull request to bump to new versions of the image. The pull request, if all tests pass, would be merged and you'd have a new child image based on updated parent. An example of a tool that takes this approach can be found here: https://engineering.salesforce.com/open-sourcing-dockerfile-image-update-6400121c1a75 .
如果你不控制你的父映像,就像你依赖于官方ubuntu映像的情况一样,你可以写一些工具来检测父映像标记或校验和(不是一回事,标记是可变的)的变化,并相应地调用子映像构建。
这里有很多答案,但没有一个符合我的需要。我想知道提问者第一个问题的确切答案。如何知道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所在的另一个网络上的服务器上。但是您也可以轻松地使用邮件命令。
现在,您还需要检查容器本身中是否有更新的包。这实际上可能比在容器工作后“拉”更有效。以下是实现这一目标的脚本:
#!/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
另一种方法是假设您的基本映像很快就会落后(这很可能发生),并定期强制应用程序构建另一个映像(例如每周),如果它发生了更改,则重新部署它。
据我所知,像官方Debian或Java这样的流行基础镜像会更新它们的标记来满足安全修复,所以标记不是不可变的(如果你想要更强的保证,你需要使用参考[image:@digest],在最新的Docker版本中可用)。因此,如果你要用docker build -pull构建你的映像,那么你的应用程序应该得到你引用的base image标签的最新和最好的。
由于可变标记可能令人困惑,所以最好每次都增加应用程序的版本号,这样至少在您的方面,事情会更清楚。
因此,我不确定在前面的答案之一中建议的脚本是否能完成工作,因为它不重新构建应用程序的映像——它只是更新基本映像标记,然后重新启动容器,但新的容器仍然引用旧的基本映像散列。
我不提倡在容器中运行cron类型的作业(或任何其他进程,除非真的有必要),因为这违背了每个容器只运行一个进程的原则(关于为什么这样更好有各种各样的争论,所以我不打算在这里讨论)。