如果基础映像已更新,如何自动更新您的Docker容器


205

假设我有一个基于的琐碎容器ubuntu:latest。现在有一个安全更新,并ubuntu:latest在docker repo中进行了更新。

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

  2. 是否有一些最佳实践来自动更新本地映像和容器以跟随docker repo更新,实际上,这会给您带来与在常规ubuntu机器上运行无人值守升级一样的好处。


11
自docker诞生以来,我一直在寻找答案。它甚至更加复杂。如果我安装了apache(例如)并且已更新,则基本映像不会更改,因为之后安装了它。我仍然希望自动更新Apache。我实际上在IRC中问过这个问题,得到了“跟进上游并根据更新进行重建”作为答案……
Mathias 2014年

8
很高兴我不是唯一的想知道的人。对于docker开发人员来说,开发和重现性似乎比我们多年来已有的明智的更新机制更为重要。
hbogert

问题是,泊坞窗只是用于容器的技术。我认为生态系统需要一段时间才能发展。Docker无法解决日志记录等其他问题。
Mathias

3
感谢所有回答。对不起,我无法分割赏金。即使没有最终解决方案来解决我的问题,也有大家的积极参与。
Mathias 2014年

1
对于@Mathias,我刚刚添加的解决方案具有一个脚本,该脚本将检查容器后拉中安装的软件包的安全更新。它还具有用于检查基本映像的单独脚本。
Fmstrat

Answers:


8

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

如果您不控制父映像(例如,如果您依赖于官方ubuntu映像),则可以编写一些工具来检测父映像标签或校验和(不是同一件事,标签是可变的)中的更改,并且相应地调用子图像构建。


哇,这是个很大的锤子:自从我问这个问题的时候起,我就已经意识到构建服务器是解决这个问题的地方。我很高兴看到一些工具。如果您以通用概念(而不是确切的工具/实现)解释您的方法,并将其包含在答案中,我可能会接受。
hbogert

谢谢@hbogert,我对上面的内容进行了编辑,还提供了一个有关如何处理公共图像的想法
Ma3oxuct

123

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

初始化看起来像

docker run -t -i --name $NAME $im /bin/bash

1
非常感谢您的宝贵贡献。这似乎是更新基本映像的好方法。剩下的问题是,如何更新由dockerfile中的发行版安装的应用程序(如apache)?还是只使用只需要应用程序代码的现成基础映像(例如网站)?
Mathias

我们使用打包程序和人偶来配置映像。我们的图像在创建后即可投入生产
bsuttor 2014年

@Mathias,请参阅我的编辑答案,我有一个微型工具docker-run,用于更新所有正在运行的容器中的linux(当前为debian / ubuntu)软件包。
iTech 2014年

3
如果图像与容器名称相同(例如redis),LATEST=`docker inspect --format "{{.Id}}" $IMAGE`则将获取容器信息。添加--type image以解决此问题。
Patrick Fisher

1
感谢您的帖子。我对其进行了修改,将整个内容包装在一个循环中以从docker获取图像: for IMAGE in $(docker ps --format {{.Image}} -q | sort -u)
Armand

25

一种“码头工人方式”将是使用码头工人枢纽 自动构建。重建上游容器时,“ 存储库链接”功能将重建您的容器,并且Webhooks功能将向您发送通知。

似乎webhooks仅限于HTTP POST调用。您需要设置一个服务来捕获它们,或者使用POST之一通过电子邮件发送服务。

我没有研究过,但是新的Docker通用控制平面可能具有检测更新的容器并重新部署的功能。


我必须为AMQP服务构建一个Webhook
goliatone

可悲的是,上游触发器不再可用:github.com/docker/hub-feedback/issues/1717
Julien Chastang

22

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

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

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


1
守望台虽然使用docker套接字。从安全性的角度来看,这可以释放对主机的根访问权限。
JoeG

1
另外,Watchtower似乎无法从Docker Hub之外的私有存储库更新映像。对于使用Azure的我们来说真是个遗憾。
托马斯·艾德

1
您可以使用REPO_USERREPO_PASS环境变量来使用私有注册表。请看来自守望台的readme.md以获取更多信息:github.com/v2tec/watchtower#usage
Alejandro Nortes

2
值得一提的是,watch望塔被其维护者所抛弃,DockerHub中的映像甚至与github中的映像都不是最新的。
XanderStrike

守望台仓库似乎已迁移到containrrr / watchtower。正如在类似问题上的答案所指出的那样,在Dockerhub上链接自动构建存在一些问题。
chrki

10

我遇到了同样的问题,并认为可以通过unattended-upgrade每天进行一次cron作业来解决。

我的目的是将其作为一种自动且快速的解决方案,以确保生产容器的安全和更新,因为这可能需要我花费一些时间来更新映像并部署具有最新安全更新的新docker映像。

也可以使用Github挂钩自动执行映像构建和部署

我创建了一个基本的docker映像,该映像每天都会自动检查并安装安全更新(可以通过直接运行docker run itech/docker-unattended-upgrade)。

我还遇到了另一种不同的方法来检查容器是否需要更新。

我完整的实现:

Docker文件

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环境中进行类比。我的目的是解决此docker方法(如果存在),在容器中具有一个额外的进程将超过docker imo的目的。它确实解决了上游更新映像与您(用户)实际在当前容器中伪装之间的延迟问题。尽管无人值守的升级也可能需要1天的时间,所以.. github引用也不令人满意,因为更新机制现在严重依赖于主机OS。
hbogert 2014年

如果它们紧密相关并且不会造成可伸缩性瓶颈,那么“ docker方式”不会阻止您在同一容器上运行其他进程。这个特定的用例是何时可以使容器具有另一个正在运行的进程的很好的例子。(例如,参见gitlab的图像,因为它在同一容器上运行多个强制性进程)。
iTech

我不会称与图像的主要功能紧密相关的更新机制。此解决方案就像为常规计算机上的每个应用程序提供其自己的更新机制,而不是将负担放在包管理器上。尽管这是一个解决方案,但它不能回答我的问题,即自动更新本地图像,然后应重新运行容器。随着容器本身的更新,我们再次引入了很多我们不知道的状态,这与docker方式背道而驰(再次恕我直言)。
hbogert 2014年

1
您可能需要比Docker更高级的功能,例如Kubernetes对于大型基础架构部署很有用,但是Google仍在大力开发它。目前,您可以使用Ansible之类的置备工具以相当简单的方式自动执行此操作。
iTech

您所引用的“不同方法”可能就是我想要的。您自己的贡献似乎是“胖容器”的可行替代方案。我一定会进一步研究两者,谢谢您的回答。
Mathias

7

如果不运行docker pull,您将不知道自己的容器在后面。然后,您需要重建重新构图

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

可以将命令以及完成升级所需的所有其他命令放在脚本中,尽管适当的容器不需要任何其他内容。


1:好的,但是然后我必须查看我所有的本地图像,获取它们的基本图像,然后将其拉出。然后重建其基础图像已更改的图像。然后停止图像已更改的容器,并使用“ docker run”和所需的参数重新创建容器。这似乎过于手工。但是,如果这是现状,那么我会接受答案。
hbogert 2014年

请等待,然后接受。也许那里有东西。我已经使用docker 6个月了,但是一直没有跟上最新的发展。
seanmcl 2014年

在某种程度上,Docker能够在内部比较映像以执行其“缓存”功能。也许您可以找到一种利用THAT的方法。换句话说,请检查基础映像(一直返回到基础)是否已更改,然后触发重建过程。不幸的是,在这种情况下,缓存将无济于事:由于基础映像已更改,因此将重建整个映像。
汤姆·帕金

5

Docker映像的依赖管理是一个实际问题。我是一个团队的成员,该团队构建了一个工具MicroBadger,以通过监视容器图像和检查元数据来提供帮助。它的功能之一是让您设置一个通知Webhook,当您感兴趣的图像(例如,基本图像)发生更改时,该通知Webhook将被调用。


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;

您将需要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

1
第一个脚本中的mkdir可能应该是:mkdir -p此外,第一个脚本将VAR1与VAR2进行比较,假定应将OLD与NEW进行比较。如果为true,则表示此脚本不会真正执行OP想要的操作,除非它在安装时首先运行。也就是说,即使结果与以前的运行结果不同,也不能真正确定要安装什么东西……
JoeG

5

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

据我所知,流行的基本映像(例如官方Debian或Java)会更新其标签以解决安全问题,因此标签不是一成不变的(如果您想更强地保证需要使用引用,请使用[image:@digest ],在较新的Docker版本中可用)。因此,如果您要使用 docker build --pull,则您的应用程序应该获取您所引用的最新和最大的基础图像标签。

由于可变标记可能会造成混淆,因此,每次执行此操作时,最好都增加应用程序的版本号,以使至少在您看来更干净。

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

我不主张在容器中运行cron型作业(或其他进程,除非确实需要),因为这违背了每个容器仅运行一个进程的口号(关于为什么这样做更好,存在各种争论,所以我我不打算在这里讨论)。


4

我不会讨论您是否要在生产中进行无人值守更新的整个问题(我认为不是)。如果有人觉得有用,我就在这里留作参考。在终端中使用以下命令将所有docker映像更新为最新版本:

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


1
该命令对于更新所有图像很有用,但不会更改生产中正在运行的任何内容。容器仍然源自旧图像,现在未加标签。

真正。这是本书的# docker system prune -a --volumes -f
又一

4

更新:使用Dependabot- https

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

在尝试自己解决此问题时,我看到了一些有关Webhooks的建议,因此我想详细介绍一下我使用的一些解决方案。

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

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

    • 优点:更接近自动化管道。Travis-CI构建仅检查容器是否存在与提交到基本映像存储库有关的任何问题。如果您的CI服务采取进一步的措施,则取决于您。
    • 缺点:跟踪提交提要并不完美。很多事情都提交到存储库中,不会影响基础映像的构建。不考虑任何与频率/提交次数和任何API节流有关的问题。

3

前提是我的回答:

  1. 容器与标签一起运行。
  2. 我们可以/认为适当,可以将同一标签指向不同的图像UUID。
  3. 对图像所做的更新可以提交到新的图像层

方法

  1. 首先使用安全修补程序更新脚本构建所有容器
  2. 为以下内容建立自动化流程
    • 使用安全补丁程序脚本将现有映像运行到新容器
    • 将更改提交为
      • 现有标签->然后依次重新启动容器
      • 新版本标签->用新标签替换一些容器->验证->将所有容器移至新标签

此外,可以根据需要维护者升级基本映像/可以定期构建带有完整新基本映像的容器

优点

  1. 在创建新的安全修补程序映像时,我们将保留映像的旧版本,因此如有必要,我们可以回滚到先前运行的映像
  2. 我们正在保留docker缓存,因此减少了网络传输(仅更改的层可以在线使用)
  3. 升级到产品之前,可以在升级阶段进行验证
  4. 这可以是一个受控过程,因此只有在必要/被认为重要时,才可以推送安全补丁。

在生产环境中,尽管它们是安全更新,但我怀疑您是否想要无人参与的更新!如果需要进行无人值守的更新,则该过程可以作为cron作业定期(适当时)运行。
Phani 2015年

1
我的前提是安全更新应该来自上游/基础映像。
hbogert 2015年

@hbogert我宁愿说理论与实践之间有细微的区别。当事情付诸实践时,将需要考虑许多外部方面,例如:与实现相关的成本(不仅是美元价值,而且还包括时间)。
Phani 2015年

3

以上答案也是正确的

有两种方法

  1. 使用网络挂钩
  2. 每隔一分钟运行一次脚本,以获取最新的Docker映像

我只是分享脚本,可能会对您有帮助!您可以将其与c​​ronjob一起使用,我已在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

3

这是自动更新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

牧羊人是一个简单而伟大的解决方案


iiuc,这在一般意义上无济于事,因为它与Swarm耦合并且仅在上游重新启动,而我们想对上游更改做出反应,重建等,而不仅仅是重启。
hbogert

这听起来像您应该在CI管道中执行的操作
user672009
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.