假设我已经取消了官方mysql:5.6.21 image。
我通过创建几个 docker 容器部署了这个镜像。
这些容器已经运行了一段时间,直到 MySQL 5.6.22 发布。 mysql:5.6 的官方镜像随着新版本的更新而更新,但我的容器仍然运行 5.6.21。
如何将映像中的更改(即升级 MySQL 发行版)传播到所有现有容器?这样做的正确Docker方式是什么?
在评估了答案并研究了我想总结的主题之后。
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
您可以将数据存储在主机上(在作为卷安装的目录中)或特殊的仅数据容器中。阅读更多关于它的信息
关于卷(Docker 文档)
Tiny Docker Pieces,松散连接(Tom Offermann)
如何处理 Docker 中的持久存储(例如数据库)(堆栈溢出问题)
在容器中升级应用程序(例如使用 yum/apt-get upgrade)被认为是一种反模式。应用程序容器应该是不可变的,这应保证可重现的行为。一些官方应用程序映像(尤其是 mysql:5.6)甚至没有设计为自我更新(apt-get upgrade 不起作用)。
我要感谢所有给出答案的人,所以我们可以看到所有不同的方法。
我不喜欢挂载卷作为指向主机目录的链接,所以我想出了一个模式,用完全由 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 容器的位置;因此,如果升级失败,您可以通过再次启动原始 docker 容器轻松恢复到之前的工作方式。
./postgres-data/:/var/lib/postgres/data
— 即在我的 PostgreSQL 容器中安装了主机目录 ./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
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 镜像,重新创建并使用新镜像启动容器。
docker-compose
,这会起作用吗? stackoverflow.com/a/31485685/65313
volumes_from
键(甚至在 compose 文件的版本 3 中也将其删除),取而代之的是新的 volumes
键。
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
下面是在构建自定义 Dockerfile
时使用 docker-compose
的样子。
首先构建您的自定义 Dockerfile,附加下一个版本号以区分。例如: docker build -t imagename:version 。这将在本地存储您的新版本。运行 docker-compose down 编辑您的 docker-compose.yml 文件以反映您在步骤 1 中设置的新映像名称。运行 docker-compose up -d。它将在本地查找图像并使用您升级的图像。
-编辑-
我上面的步骤比他们需要的更冗长。通过将 build: .
参数包含到我的 docker-compose 文件中,我优化了我的工作流程。现在的步骤如下:
验证我的 Dockerfile 是我想要的样子。在我的 docker-compose 文件中设置我的图像名称的版本号。如果我的图像尚未构建:运行 docker-compose build 运行 docker-compose up -d
当时我没有意识到,但 docker-compose 足够聪明,只需使用一个命令将我的容器更新为新图像,而不必先将其关闭。
docker-compose up -d
而无需先停止一切。
您需要重建所有映像并重新启动所有容器,或者以某种方式 yum 更新软件并重新启动数据库。没有升级路径,只能由您自己设计。
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
确保您将卷用于存储在与容器内进程状态相关的容器上的所有持久数据(配置、日志或应用程序数据)。更新您的 Dockerfile 并使用您想要的更改重建映像,然后重新启动容器并将您的卷安装在适当的位置。
这也是我一直在为自己的图像而苦苦挣扎的事情。我有一个服务器环境,我从中创建一个 Docker 映像。当我更新服务器时,我希望所有基于我的 Docker 映像运行容器的用户都能够升级到最新的服务器。
理想情况下,我更愿意生成新版本的 Docker 映像,并让所有基于该映像先前版本的容器自动更新为“就地”新映像。但这种机制似乎并不存在。
因此,到目前为止,我能够提出的下一个最佳设计是提供一种让容器自行更新的方法——类似于桌面应用程序检查更新然后自行升级的方式。就我而言,这可能意味着制作一个涉及 Git 从知名标签中提取的脚本。
图像/容器实际上并没有改变,但该容器的“内部”发生了变化。您可以想象使用 apt-get、yum 或任何适合您的环境的东西来做同样的事情。除此之外,我还会更新注册表中的 myserver:latest 映像,以便任何新容器都基于最新映像。
我很想知道是否有任何现有技术可以解决这种情况。
更新
这主要是查询容器不要更新,因为构建图像是要完成的方式
我遇到了同样的问题,因此我创建了 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
您可以创建和别名并将其用作常规命令行,例如
alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'
apt update; apt upgrade
,图像会变大。)
从这里尝试了很多东西,但这最终对我有用。如果您在容器上有 AutoRemove: On
,您无法停止和编辑容器,或者正在运行的服务甚至无法暂时停止,您必须:
拉取最新图片 --> docker pull [image:latest]
验证是否拉取了正确的图像,您可以在 Portainer Images 部分看到 UNUSED 标签
使用 Portainer 或 CLI 更新服务并确保使用最新版本的图像,Portainer 将为您提供执行相同操作的选项。
这不仅会使用最新图像更新容器,还会保持服务运行。
docker rename my-mysql-container trash-container
之前怎么样?