首页 文章

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

提问于
浏览
378

假设我拉了官方mysql:5.6.21 image .

我通过创建几个docker容器来部署此映像 .

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

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

13 回答

  • 441

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

  • 3

    我不喜欢将卷安装为主机目录的链接,因此我提出了一种模式,用于升级具有完全docker托管容器的docker容器 . 使用 --volumes-from <container> 创建新的docker容器将为新容器提供已更新的映像共享docker managed卷的所有权 .

    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容器轻松恢复之前的工作方式 .

  • 3

    在评估答案并研究我想总结的主题之后 .

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

    Application containers should not store application data . 这样,您可以通过执行以下操作随时将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
    

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

    Upgrading applications (eg. with yum/apt-get upgrade) within containers is considered to be an anti-pattern . 应用程序容器应该是不可变的,这应该保证可重现的行为 . 一些官方应用程序映像(特别是mysql:5.6)甚至没有设计为自我更新(apt-get升级不起作用) .

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

  • 13

    取自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
    
  • 19

    考虑这个答案:

    • 数据库名称为 app_schema

    • 容器名称为 app_db

    • root密码是 root123

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

    This is considered a bad practice ,因为如果丢失容器,您将丢失数据 . 虽然这是一个不好的做法,但这是一种可行的方法:

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

  • 1

    这是构建自定义 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足够智能,可以使用one命令将我的容器更新为新映像,而不必先将其删除 .

  • 62

    我有同样的问题,所以我创建了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'

  • 16

    类似的答案如上

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

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

  • 11

    仅仅是为了提供更通用(而不是特定于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会通过停止并重新创建容器(保留已安装的卷)来获取更改 . 要防止Compose选择更改,请使用--no-recreate标志 .

    数据管理方面也由docker-compose通过已安装的外部"volumes"(参见https://docs.docker.com/compose/compose-file/#volumes)或数据容器来实现 .

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

  • 3

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

  • 10

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

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

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

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

    我有兴趣听听是否有任何现有技术可以解决这个问题 .

  • 1

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

相关问题