假设我有一个基于ubuntu:latest的普通容器。现在有一个安全更新和ubuntu:latest更新在docker repo。
我如何知道我的本地映像及其容器运行落后? 是否有一些最佳实践来自动更新本地映像和容器来跟踪docker回购更新,这在实践中会给你同样的好处,让无人值守的升级运行在传统的ubuntu机器上
假设我有一个基于ubuntu:latest的普通容器。现在有一个安全更新和ubuntu:latest更新在docker repo。
我如何知道我的本地映像及其容器运行落后? 是否有一些最佳实践来自动更新本地映像和容器来跟踪docker回购更新,这在实践中会给你同样的好处,让无人值守的升级运行在传统的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
其他回答
我不打算讨论您是否希望在生产中进行无人值守的更新(我认为不需要)。我只是把这个留在这里作为参考,以防有人觉得有用。在终端中使用以下命令将所有docker映像更新到最新版本:
# docker images | awk '(NR>1) && ($2!~/none/) {print $1":"$2}' | xargs -L1 docker pull
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映像的依赖管理是一个真正的问题。我所在的团队开发了一个名为MicroBadger的工具,通过监视容器图像和检查元数据来帮助解决这个问题。它的功能之一是让你设置一个通知网络钩子,当你感兴趣的图像(例如基本图像)发生变化时,它会被调用。
我们使用一个脚本来检查正在运行的容器是否以最新映像启动。我们还使用upstart init脚本来启动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方式”是使用docker hub自动构建。当上游容器被重建时,Repository Links特性将重建你的容器,Webhooks特性将向你发送通知。
看起来webhooks仅限于HTTP POST调用。您需要设置一个服务来捕获它们,或者可能使用其中一个POST发送电子邮件服务。
我还没有深入研究,但是新的Docker通用控制平面可能有一个检测更新容器和重新部署的功能。