更改镜像后如何升级Docker容器

比方说,我已经拉到官方的MySQL:5.6.21图像 。

我已经通过创build几个docker容器来部署这个镜像。

这些容器已经运行了一段时间,直到MySQL 5.6.22发布。 mysql:5.6的官方映像获得了新版本的更新,但是我的容器仍然运行5.6.21。

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

在评估答案和研究这个话题之后,我想总结一下。

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

应用程序容器不应存储应用程序数据 这样你可以随时用新版本replace应用程序容器,执行如下所示:

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)甚至没有devise为自我更新(apt-get升级将不起作用)。

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

我不喜欢将卷挂载到主机目录,所以我想出了一个模式来升级docker容器和dockerpipe理的容器。 使用--volumes-from <container>创build一个新的--volumes-from <container>将为新容器赋予更新后的映像共享Dockerpipe理卷的所有权。

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

通过不立即删除原始的my_mysql_container ,如果升级后的容器没有正确的数据,或者没有通过健全性testing,您可以恢复到已知的工作容器。

在这一点上,我通常会运行任何备份脚本来为容器提供一个安全网,以防出现问题

 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集装箱的位置; 所以如果升级失败,可以通过再次旋转原始docker容器,轻松地恢复到之前的工作状态。

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

考虑这个答案:

  • 数据库名称是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容器

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

1)创builddocker-compose.yml文件来pipe理你的应用程序:

 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映像,重新创build并使用新映像启动容器。

与上面类似的答案

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

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

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

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

只是为了提供更一般(不是特定于MySQL)的答案…

  1. 简而言之

与服务映像registry同步( https://docs.docker.com/compose/compose-file/#image ):

 docker-compose pull 

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

 docker-compose up -d 
  1. 背景

容器镜像pipe理是使用docker-compose的原因之一(请参阅https://docs.docker.com/compose/reference/up/

如果存在服务的容器,并且在创build容器后服务的configuration或映像已更改,则docker-compose将通过停止并重新创build容器(保留已装入的卷)来提取更改。 要防止撰写改变,请使用–no-recreate标志。

数据pipe理方面也被docker-compose覆盖,通过挂载的外部“卷”(请参阅https://docs.docker.com/compose/compose-file/#volumes )或数据容器。

这留下了潜在的向后兼容性和数据迁移问题,但这些都是“适用的”问题,而不是特定于Docker,必须根据发行说明和testing进行检查。

你需要重build所有的图像,并重新启动所有的容器,或者不知何故yum更新软件,并重新启动数据库。 没有升级途径,但是你自己devise。

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

理想情况下,我更愿意生成一个新版本的Docker镜像,并将基于该镜像以前版本的所有容器自动更新为新镜像。 但是这个机制似乎并不存在。

所以到目前为止我所能提出的下一个最好的devise是提供一种方法来让容器自行更新 – 类似于桌面应用程序如何检查更新然后自行升级。 在我的情况下,这可能意味着制作一个涉及Git从一个知名标签拉的脚本。

图像/容器实际上并没有改变,但容器的“内部”改变了。 你可以想象用apt-get,yum或者适合你的环境来做同样的事情。 与此同时,我会更新registry中的myserver:latest图像,以便任何新的容器都基于最新的图像。

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

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

它使用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

您可以创build和别名,并将其用作常规命令行,例如

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

确保您正在使用卷来存储容器中与进程状态相关的容器上的所有持久性数据(configuration,日志或应用程序数据)。 更新你的Dockerfile并用你想要的修改重build镜像,然后重新启动这些容器,把卷安装在适当的位置。

以下是在构build自定义Dockerfile时使用Dockerfile docker-composeDockerfile

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