如果更新基本映像,如何自动更新docker容器

hbo*_*ert 187 automatic-updates docker

假设我有一个基于的简单容器ubuntu:latest.现在有一个安全更新,并ubuntu:latest在docker repo中更新.

  1. 我怎么知道我的本地图像及其容器在后面运行?

  2. 是否有一些最佳实践可以自动更新本地映像和容器以遵循docker repo更新,这在实践中会为您提供在传统ubuntu机器上运行无人值守升级的相同细节

bsu*_*tor 115

我们使用一个脚本来检查正在运行的容器是否以最新映像启动.我们还使用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
Run Code Online (Sandbox Code Playgroud)

而init看起来像

docker run -t -i --name $NAME $im /bin/bash
Run Code Online (Sandbox Code Playgroud)

  • 如果图像与容器具有相同的名称(例如`redis`),`LATEST = \`docker inspect --format"{{.Id}}"$ IMAGE \``将获取容器信息.添加`--type image`来解决这个问题. (3认同)
  • 非常感谢您做出的宝贵贡献。这似乎是更新基础映像的好方法。剩下的问题是,如何更新 dockerfile 中的发行版安装的应用程序(如 apache)?或者您只使用现成的基础映像,只需要您的应用程序代码(如网站)? (2认同)

CAB*_*CAB 22

"docker方式"将是使用docker hub 自动构建.该库链接功能时,上游容器重建将重建你的容器,和网络挂接功能会送你一个通知.

看起来webhook仅限于HTTP POST调用.您需要设置一个服务来捕获它们,或者使用POST之一来发送电子邮件服务.

我没有调查过,但新的Docker Universal Control Plane可能具有检测更新容器和重新部署的功能.

  • 遗憾的是,上游触发器不再可用:https://github.com/docker/hub-feedback/issues/1717。 (2认同)

jjl*_*lin 19

您可以使用Watchtower监视容器实例化的映像的更新,并使用更新的映像自动提取更新并重新启动容器.但是,当基于它的上游图像发生更改时,这并不能解决重建自定义图像的问题.您可以将其视为一个由两部分组成的问题:(1)知道上游图像何时更新,以及(2)进行实际图像重建.(1)可以很容易地解决,但(2)很大程度上取决于你的本地构建环境/实践,因此为此创建一个通用的解决方案可能要困难得多.

如果您能够使用Docker Hub的自动构建,则可以使用存储库链接功能相对干净地解决整个问题,该功能允许您在更新链接存储库(可能是上游存储库)时自动触发重建.您还可以配置webhook以在发生自动构建时通知您.如果您需要电子邮件或短信通知,可以将webhook连接到IFTTT Maker.我发现IFTTT用户界面有点令人困惑,但您可以将Docker webhook配置为使用/ key/发布到https://maker.ifttt.com/trigger/docker_xyz_image_built/your_key.

如果您需要在本地构建,您至少可以通过在Docker Hub中创建与您感兴趣的回购链接相关联的虚拟仓库来解决在更新上游映像时获取通知的问题.虚拟仓库的唯一目的是在重建时触发webhook(这意味着其中一个链接的repos已更新).如果您能够接收此webhook,您甚至可以使用它来触发您的重建.

  • 不过,Watchtower 使用的是 docker 套接字。从安全角度来看,这会放弃对主机的 root 访问权限。 (2认同)
  • 值得一提的是,watch望塔被其维护者抛弃,并且DockerHub中的映像与github中的映像甚至都不是最新的。 (2认同)

iTe*_*ech 9

我有同样的问题,并认为它可以通过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
Run Code Online (Sandbox Code Playgroud)

助手脚本

安装

#!/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"]
Run Code Online (Sandbox Code Playgroud)

开始

#!/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
Run Code Online (Sandbox Code Playgroud)

编辑

我开发了一个小工具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的所有正在运行的容器

  • 这里描述的解决方案实际上并没有修复容器中可能存在的许多漏洞。如果您更新正在运行的程序正在使用的软件包,那么它并不会真正改变该正在运行的程序的任何内容。必须重新启动才能获取新安装的包/文件。因此,您可能看起来没有任何安全问题,但实际上仍然存在。 (2认同)

sea*_*mcl 7

如果没有运行docker pull你就不会知道你的容器落后了.然后,您需要重建重构您的图像.

docker pull image:tag
docker-compose -f docker-compose.yml -f production.yml up -d --build
Run Code Online (Sandbox Code Playgroud)

这些命令可以与完成升级所需的任何其他内容一起放入脚本中,尽管适当的容器不需要任何额外的东西.


Ma3*_*uct 6

其中一种方法是通过CI/CD系统驱动它.构建父图像后,使用该父图像扫描git repos以查找图像.如果找到,您将发送拉动请求以碰撞新版本的图像.如果所有测试都通过,则pull请求将被合并,并且您将根据更新的父级具有新的子图像.可以在此处找到采用此方法的工具示例:https://engineering.salesforce.com/open-sourcing-dockerfile-image-update-6400121c1a75.

如果您不控制父图像,如果您依赖于官方ubuntu图像,则可以编写一些工具来检测父图像标记中的更改并相应地调用子图像构建.


Bog*_*dan 5

另一种方法可能是假设您的基本映像很快落后(这很可能会发生),并定期(例如每周)强制构建应用程序的另一个映像,然后在它发生更改时重新部署它。

据我所知,像官方 Debian 或 Java 这样的流行基础镜像会更新它们的标签以适应安全修复,所以标签不是一成不变的(如果你想要更有力的保证,你需要使用参考 [image:@digest ],在更新的 Docker 版本中可用)。因此,如果您要使用 构建您的映像 docker build --pull,那么您的应用程序应该获得您正在引用的最新和最好的基本映像标记。

由于可变标签可能会令人困惑,因此最好每次执行此操作时都增加应用程序的版本号,这样至少在您这边事情会更清晰。

因此,我不确定在前面的答案之一中建议的脚本是否可以完成这项工作,因为它不会重建您的应用程序的映像 - 它只是更新基本映像标记,然后重新启动容器,但新容器仍然引用旧的基础图像哈希。

我不提倡在容器(或任何其他进程,除非真的有必要)中运行 cron 类型的作业,因为这违背了每个容器只运行一个进程的口头禅(关于为什么这更好,所以我有各种争论)我不打算在这里讨论)。


小智 5

Docker 镜像的依赖管理是一个真正的问题。我是构建工具MicroBadger的团队的一员,通过监视容器映像和检查元数据来帮助解决此问题。它的功能之一是让您设置一个通知 Webhook,当您感兴趣的图像(例如基本图像)发生变化时,该通知 Webhook 会被调用。


Fms*_*rat 5

这里有很多答案,但没有一个适合我的需求。我想要对提问者的 #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;
Run Code Online (Sandbox Code Playgroud)

您将需要更改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
Run Code Online (Sandbox Code Playgroud)


2st*_*cks 5

更新:使用 Dependabot - https://dependabot.com/docker/

BLUF:找到正确的插入点来监视容器的更改是一个挑战。如果 DockerHub 能解决这个问题就太好了。(已经提到了存储库链接,但在 DockerHub 上设置它们时请注意 - “只要在 Docker Hub 上更新基础映像,就触发此存储库中的构建。仅适用于非官方映像。”

在尝试自己解决这个问题时,我看到了一些关于 webhooks 的建议,因此我想详细说明我使用过的几个解决方案。

  1. 使用 microbadger.com 跟踪容器中的更改并使用其通知 Webhook 功能来触发操作。我使用 zapier.com(但您可以使用任何可自定义的 Webhook 服务)进行设置,以在我的 github 存储库中创建一个使用 Alpine 作为基础映像的新问题。

    • 优点:在采取行动之前,您可以在 github 中查看 microbadger 报告的更改。
    • 缺点:Microbadger 不允许您跟踪特定标签。看起来它只跟踪“最新”。
  2. 跟踪 git 提交到上游容器的 RSS 提要。前任。https://github.com/gliderlabs/docker-alpine/commits/rootfs/library-3.8/x86_64。我使用 zapier.com 来监控此 feed,并在发生任何事情时触发 Travis-CI 中容器的自动构建。这有点极端,但您可以更改触发器来执行其他操作,例如在 git 存储库中打开问题以进行手动干预。

    • 优点:更接近自动化管道。Travis-CI 构建只是检查您的容器是否与提交到基础镜像存储库的内容存在问题。您的 CI 服务是否采取任何进一步的行动取决于您。
    • 缺点:跟踪提交源并不完美。很多东西都会提交到存储库中,但不会影响基础映像的构建。不考虑任何频率/提交次数和任何 API 限制的问题。


Che*_*ana 5

这是自动更新docker容器的最简单方法

把工作通过$ crontab -e

0 * * * * sh ~/.docker/cron.sh
Run Code Online (Sandbox Code Playgroud)

~/.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
Run Code Online (Sandbox Code Playgroud)