假设我已经拉出了官方的mysql:5.6.21 image。
我已经通过创建多个docker容器部署了此映像。
这些容器已经运行了一段时间,直到MySQL 5.6.22发布。mysql:5.6的官方映像已随新版本更新,但我的容器仍运行5.6.21。
如何将映像中的更改(即升级MySQL发行版)传播到所有现有容器?这样做的正确Docker方法是什么?
假设我已经拉出了官方的mysql:5.6.21 image。
我已经通过创建多个docker容器部署了此映像。
这些容器已经运行了一段时间,直到MySQL 5.6.22发布。mysql:5.6的官方映像已随新版本更新,但我的容器仍运行5.6.21。
如何将映像中的更改(即升级MySQL发行版)传播到所有现有容器?这样做的正确Docker方法是什么?
Answers:
在评估答案并研究了主题之后,我想总结一下。
Docker升级容器的方式似乎如下:
应用程序容器不应存储应用程序数据。这样,您可以随时通过执行以下操作将应用容器替换为其较新的版本:
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升级将不起作用)。
我要感谢提供答案的每个人,以便我们能看到所有不同的方法。
docker rename my-mysql-container trash-container
在创建新的之前怎么样?
我不喜欢将卷安装为主机目录的链接,所以我想出了一种使用完全由Docker管理的容器升级Docker容器的模式。使用创建新的docker容器--volumes-from <container>
将为具有更新的映像的新容器提供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容器的位置;因此,如果升级失败,则可以通过再次旋转原始Docker容器轻松地恢复到以前的工作方式。
./postgres-data/:/var/lib/postgres/data
./postgres-data/
只是为了提供一个更通用(不是特定于mysql)的答案...
与服务映像注册表同步(https://docs.docker.com/compose/compose-file/#image):
docker-compose pull
如果docker-compose文件或映像已更改,请重新创建容器:
docker-compose up -d
容器映像管理是使用docker-compose的原因之一(请参阅https://docs.docker.com/compose/reference/up/)
如果已有用于服务的容器,并且在创建容器后更改了服务的配置或映像,则docker-compose up通过停止并重新创建容器(保留已安装的卷)来获取更改。为防止Compose获取更改,请使用--no-recreate标志。
docker-compose还可以通过安装的外部“卷”(请参阅https://docs.docker.com/compose/compose-file/#volumes)或数据容器来涵盖数据管理方面。
这使得潜在的向后兼容性和数据迁移问题没有得到解决,但是这些是“应用性”问题,而不是特定于Docker的问题,必须根据发行说明和测试进行检查...
我想补充一点,如果您想自动执行此过程(使用@Yaroslav所述的相同设置来下载,停止和重新启动新容器),则可以使用WatchTower。一个程序,可在更改容器时自动更新您的容器https://github.com/v2tec/watchtower
考虑以下答案:
app_schema
app_db
root123
这被认为是不好的做法,因为如果丢失容器,则会丢失数据。尽管这是一个不好的做法,但是这是一种可行的方法:
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变得更加容易。松开容器不会丢失任何数据。您可以使用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映像,重新创建并使用新映像启动容器。
docker-compose
,这行得通吗?stackoverflow.com/a/31485685/65313
volumes_from
现在不推荐使用key(甚至在compose文件的版本3中已将其删除),以使用新的volumes
key。
docker pull image_uri:tag && docker restart container_running_that_image
为我工作。不需要docker-compose pull && docker-compose up -d
。
与上述类似的答案
docker images | awk '{print $1}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull
这是docker-compose
构建自定义时使用的外观Dockerfile
。
docker build -t imagename:version .
这会将您的新版本存储在本地。docker-compose down
docker-compose.yml
文件以反映您在步骤1中设置的新图像名称。docker-compose up -d
。它将在本地查找该图像并使用升级后的图像。-编辑-
我上面的步骤比他们需要的更为冗长。我通过将build: .
参数包含到docker-compose文件中来优化了我的工作流程。步骤如下所示:
docker-compose build
docker-compose up -d
当时我没有意识到,但是docker-compose足够聪明,只需使用一个命令即可将容器更新为新映像,而不必先将其关闭。
docker-compose up -d
而不必先停止所有操作。
您需要重建所有映像并重新启动所有容器,或者以某种方式更新软件并重新启动数据库。没有升级途径,而是您自己设计。
docker restart
命令,但是我不确定它将获取图像更改。容器中的数据又如何处理?
取自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
对于我自己的图像,这也是我一直在努力的事情。我有一个从中创建Docker映像的服务器环境。更新服务器时,我希望所有基于Docker映像运行容器的用户能够升级到最新服务器。
理想情况下,我希望生成一个新版本的Docker映像,并基于该映像的先前版本将所有容器自动地“更新”到新映像。但是这种机制似乎并不存在。
因此,到目前为止,我能想到的下一个最佳设计是提供一种使容器自身更新的方法,类似于桌面应用程序检查更新然后自我升级的方式。就我而言,这可能意味着要编写一个脚本,该脚本涉及到来自知名标签的Git拉取。
图像/容器实际上并没有更改,但是该容器的“内部”更改了。您可以想象使用apt-get,yum或任何适合您的环境的方法进行相同的操作。与此同时,我将更新注册表中的myserver:latest映像,以便所有新容器都将基于最新映像。
我想听听是否有任何现有技术可以解决这种情况。
更新资料
这主要是查询容器不更新,因为构建映像是一种方法
我遇到了同样的问题,所以我创建了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
您可以创建和别名并将其用作常规命令行,例如
alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'
apt update; apt upgrade
,图像将会增长。)