如何在映像更改后升级docker容器

时间:2014-11-04 11:48:23

标签: docker

我们说我已撤下官方mysql:5.6.21 image

我已经通过创建多个docker容器来部署此映像。

这些容器已运行一段时间,直到MySQL 5.6.22发布。 mysql的官方形象:5.6使用新版本更新,但我的容器仍然运行5.6.21。

如何将图像中的更改(即升级MySQL发行版)传播到我现有的所有容器? Docker的正确方法是什么?

14 个答案:

答案 0 :(得分:494)

在评估答案并研究主题后,我想总结一下。

Docker升级容器的方式似乎如下:

应用程序容器不应存储应用程序数据。这样,您可以通过执行以下操作来随时替换app容器及其较新版本:

docker pull mysql
docker stop my-mysql-container
docker rm my-mysql-container
docker run --name=my-mysql-container --restart=always \
  -e MYSQL_ROOT_PASSWORD=mypwd -v /my/data/dir:/var/lib/mysql -d mysql

您可以将数据存储在主机(作为卷装入的目录中)或特殊仅数据容器中。阅读更多相关信息

在容器内升级应用程序(例如,使用yum / apt-get升级)被视为反模式。应用程序容器应该是不可变的,这将保证可重现的行为。一些官方应用程序映像(特别是mysql:5.6)甚至没有设计为自我更新(apt-get upgrade赢得了工作)。

我要感谢所有给出答案的人,所以我们可以看到所有不同的方法。

答案 1 :(得分:74)

我不想将卷作为主机目录的链接加载,因此我提出了一种模式,用于使用完全由docker管理的容器升级docker容器。使用--volumes-from <container>创建新的docker容器将为新容器提供已更新的映像,共享docker托管卷的所有权。

docker pull mysql
docker create --volumes-from my_mysql_container [...] --name my_mysql_container_tmp mysql

如果尚未立即删除原始my_mysql_container,则如果升级后的容器没有正确的数据,或者未通过完整性测试,则可以恢复到已知的工作容器。

此时,我通常会为容器运行任何备份脚本,以便在出现问题时为自己提供安全网

docker stop my_mysql_container
docker start my_mysql_container_tmp

现在您有机会确保您希望新容器中的数据存在并进行健全性检查。

docker rm my_mysql_container
docker rename my_mysql_container_tmp my_mysql_container

只要任何容器正在使用它们,docker卷就会一直存在,因此您可以安全地删除原始容器。删除原始容器后,新容器可以采用原始容器的名称,以使一切尽可能美观。

使用此模式升级docker容器有两个主要优点。首先,它允许将卷直接传输到升级的容器,从而无需将卷安装到主机目录。其次,你永远不会处于一个没有工作的码头集装箱的位置;因此,如果升级失败,您可以通过再次旋转原始docker容器轻松恢复之前的工作方式。

答案 2 :(得分:23)

我想补充一点,如果您想自动执行此过程(使用@Yaroslav所描述的相同设置下载,停止并重新启动新容器),您可以使用WatchTower。一个程序,可在更改容器时自动更新容器https://github.com/v2tec/watchtower

答案 3 :(得分:19)

考虑这个答案:

  • 数据库名称为app_schema
  • 容器名称为app_db
  • root密码为root123

如何在容器内存储应用程序数据时更新MySQL

这被认为是一种不好的做法,因为如果丢失容器,您将丢失数据。虽然这是一种不好的做法,但这是一种可行的方法:

1)将数据库转储作为SQL:

docker exec app_db sh -c 'exec mysqldump app_schema -uroot -proot123' > database_dump.sql

2)更新图片:

docker pull mysql:5.6

3)更新容器:

docker rm -f app_db
docker run --name app_db --restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=root123 \
-d mysql:5.6

4)恢复数据库转储:

docker exec app_db sh -c 'exec mysql -uroot -proot123' < database_dump.sql

如何使用外部卷

更新MySQL容器

使用外部卷是一种更好的数据管理方式,更容易更新MySQL。丢失容器不会丢失任何数据。您可以使用docker-compose来帮助在单个主机中管理多容器Docker应用程序:

1)创建docker-compose.yml文件以管理您的应用程序:

version: '2'
services:
  app_db:
    image: mysql:5.6
    restart: unless-stopped
    volumes_from: app_db_data
  app_db_data:
    volumes: /my/data/dir:/var/lib/mysql

2)更新MySQL(来自与docker-compose.yml文件相同的文件夹):

docker-compose pull
docker-compose up -d

注意:上面的最后一个命令将更新MySQL映像,使用新映像重新创建并启动容器。

答案 4 :(得分:18)

仅提供更通用(而不是特定于mysql)的答案......

  1. 简而言之
  2. 与服务图像注册表(https://docs.docker.com/compose/compose-file/#image)同步:

    docker-compose pull 
    

    如果docker-compose文件或图像已更改,请重新创建容器:

    docker-compose up -d
    
    1. 背景
    2. 容器映像管理是使用docker-compose的原因之一 (见https://docs.docker.com/compose/reference/up/

        

      如果服务存在现有容器,并且在创建容器后更改了服务的配置或映像,则docker-compose会通过停止并重新创建容器(保留已安装的卷)来获取更改。要防止Compose选择更改,请使用--no-recreate标志。

      数据管理方面也由docker-compose通过已安装的外部&#34;卷&#34; (参见https://docs.docker.com/compose/compose-file/#volumes)或数据容器。

      这使得潜在的向后兼容性和数据迁移问题不受影响,但这些问题是“适用的”#34;问题,而不是特定于Docker,必须根据发行说明和测试进行检查......

答案 5 :(得分:13)

上面的类似答案

docker images | awk '{print $1}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull

答案 6 :(得分:11)

以下是构建自定义docker-compose时使用Dockerfile的效果。

  1. 首先构建自定义Dockerfile,附加下一个版本号以区分。例如:docker build -t imagename:version .这将在本地存储您的新版本。
  2. 运行docker-compose down
  3. 修改docker-compose.yml文件以反映您在步骤1中设置的新图像名称。
  4. 运行docker-compose up -d。它将在本地查找图像并使用升级后的图像。
  5. - 编辑 -

    我上面的步骤比他们需要的更冗长。我通过将build: .参数包含到我的docker-compose文件中来优化我的工作流程。这些步骤现在看起来:

    1. 验证我的Dockerfile是我想要的样子。
    2. 在我的docker-compose文件中设置我的图像名称的版本号。
    3. 如果我的图片尚未构建:请运行docker-compose build
    4. 运行docker-compose up -d
    5. 我当时没有意识到,但是docker-compose足够智能,可以使用one命令将我的容器更新为新映像,而不必先将其删除。

答案 7 :(得分:3)

您需要重建所有映像并重新启动所有容器,或者以某种方式yum更新软件并重新启动数据库。没有升级路径,但你自己设计。

答案 8 :(得分:3)

取自http://blog.stefanxo.com/2014/08/update-all-docker-images-at-once/

您可以使用以下命令管道更新所有现有图像:

docker images | awk '/^REPOSITORY|\<none\>/ {next} {print $1}' | xargs -n 1 docker pull

答案 9 :(得分:3)

如果您不想使用Docker Compose,我可以推荐portainer。它具有重新创建功能,可让您在拉动最新图像的同时重新创建容器。

答案 10 :(得分:2)

我遇到了同样的问题所以我创建了docker-run,这是一个非常简单的命令行工具,可以在docker container内运行,以更新其他正在运行的容器中的包。

它使用 docker-py 与正在运行的docker容器进行通信并更新包或运行任意单个命令

示例:

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec

默认情况下,这将在所有正在运行的容器中运行date命令并返回结果,但您可以发出任何命令,例如docker-run exec "uname -a"

更新包(目前仅使用apt-get):

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run update

您可以创建和别名并将其用作常规命令行 e.g。

alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'

答案 11 :(得分:2)

确保使用卷存储在容器中存储的与容器内进程状态相关的所有持久数据(配置,日志或应用程序数据)。更新您的Dockerfile并使用您想要的更改重建映像,并在适当位置安装卷的情况下重新启动容器。

答案 12 :(得分:1)

这也是我为自己的形象而苦苦挣扎的事情。我有一个服务器环境,我可以从中创建一个Docker镜像。当我更新服务器时,我希望所有基于我的Docker镜像运行容器的用户都能够升级到最新的服务器。

理想情况下,我更愿意生成新版本的Docker镜像,并让所有基于该图像的先前版本的容器自动更新到新图像“就位”。但这种机制似乎并不存在。

因此,到目前为止,我能够提出的下一个最好的设计是提供一种让容器更新的方法 - 类似于桌面应用程序检查更新然后自我升级的方式。在我的情况下,这可能意味着制作一个涉及Git拉从一个着名标签的脚本。

图像/容器实际上没有改变,但是该容器的“内部”发生了变化。您可以想象使用apt-get,yum或任何适合您环境的方法。除此之外,我还会在注册表中更新myserver:最新图像,以便任何新容器都基于最新图像。

我有兴趣了解是否有任何现有技术可以解决这种情况。

答案 13 :(得分:1)

即使我要更新的容器是docker-compose组的一部分,我仍然可以使用以下两个命令来更新单个容器:

docker pull image.uri.io:latest
docker restart the-container

提供

docker ps --format 'table{{.Names}}\t{{.Image}}'
NAMES              IMAGE
the-container      image.uri.io:latest

这种方式的优点是您不需要执行docker run并重复执行@Yaroslav's answer中的所有那些创建参数。