postgresql - 如何在维护数据的同时升级 docker 容器中的 postgres? 10.3 到最新的 10.x 或 12.x

标签 postgresql macos docker ubuntu

我的生产和本地主机中有一个 10.3 postgres docker 容器。
在以前的 question ,我必须恢复在 10.5 中存档的转储。感谢我使用纯格式的答案。但这是一个临时解决方案。
我想知道是否有一种简单的方法可以在本地主机和生产环境中为我的 docker 容器升级我的 postgres 版本。
在 localhost 中,我有许多用于开发和探索目的的数据库和模式。
在生产中,数据要少得多,但数据当然要重要得多。
我喜欢在不危及数据和架构的情况下升级到新版本的 postgres。
在 localhost 中,我的主机操作系统是 macOS 10.15 catalina。在生产中,主机操作系统是 ubuntu headless server edition 18.04
生产环境和本地主机都使用相同的 Dockerfile 配置

FROM postgres:10.3

COPY ./maintenance /usr/local/bin/maintenance
RUN chmod +x /usr/local/bin/maintenance/*
RUN mv /usr/local/bin/maintenance/* /usr/local/bin \
    && rmdir /usr/local/bin/maintenance

我确实找到了这个 https://github.com/docker-library/postgres/issues/37#issuecomment-431317584但我对这个评论所暗示的内容没有概念上的理解。
我还发现了这个库 https://github.com/bwbroersma/docker-postgres-upgrade
不确定这两种方法如何相同或不同
希望在这里得到对 Docker 和 Postgres 都有经验的人寻求建议。
我试过的
这是我的原创local.yml对于 docker 。本地因为用于本地开发环境。
version: "3.7"

volumes:
  postgres_data_local: {}
  postgres_backup_local: {}

services:
  django:
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: eno-a3-django_local_django
    depends_on:
      - postgres
      - mailhog
      - redis
    volumes:
      - .:/app
    env_file:
      - ./.envs/.local/.django
      - ./.envs/.local/.postgres
    ports:
      - "8000:8000"
    command: /start

  postgres:
    build: ./compose/production/postgres/
    image: eno-a3-django_production_postgres
    volumes:
      - postgres_data_local:/var/lib/postgresql/data
      - postgres_backup_local:/backups
    env_file:
      - ./.envs/.local/.postgres
    ports:
      - "5432:5432"

  mailhog:
    image: mailhog/mailhog:v1.0.0
    ports:
      - "8025:8025"

  redis:
    build: ./compose/production/redis/
    container_name: redis
    restart: always
然后我想我会创建一个新的 docker 容器。
所以我改成了这个
version: "3.7"

volumes:
  postgres_data_local: {}
  postgres_backup_local: {}

services:
  django:
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: eno-a3-django_local_django
    depends_on:
      - postgres
      - mailhog
      - redis
      - postgres_new
    volumes:
      - .:/app
    env_file:
      - ./.envs/.local/.django
      - ./.envs/.local/.postgres
    ports:
      - "8000:8000"
    command: /start

  postgres:
    build: ./compose/production/postgres/
    image: eno-a3-django_production_postgres
    volumes:
      - postgres_data_local:/var/lib/postgresql/data
      - postgres_backup_local:/backups
    env_file:
      - ./.envs/.local/.postgres
    ports:
      - "5432:5432"

  postgres_new:
    build: ./compose/production/postgres_new/
    image: eno-a3-django_production_postgres_new
    volumes:
      - postgres_data_local:/var/lib/postgresql/data
      - postgres_backup_local:/backups
    env_file:
      - ./.envs/.local/.postgres_new
    ports:
      - "15432:5432"

  mailhog:
    image: mailhog/mailhog:v1.0.0
    ports:
      - "8025:8025"

  redis:
    build: ./compose/production/redis/
    container_name: redis
    restart: always
请注意我如何为 postgres_new 使用相同的卷。容器。postgres_new 的 Dockerfile是
FROM postgres:10.13

COPY ./maintenance /usr/local/bin/maintenance
RUN chmod +x /usr/local/bin/maintenance/*
RUN mv /usr/local/bin/maintenance/* /usr/local/bin \
    && rmdir /usr/local/bin/maintenance
当我运行 docker build 并使用端口 15432 登录时,我可以看到我的旧数据库架构等。
看起来两个容器可以通过相同的卷共享相同的数据。
然后我使用 10.5 存档文件恢复到这个 Docker 容器,它成功了。
我用来恢复的命令在我的主机操作系统中是这样的
docker cp ~/path/to/10.5.dump eno-a3-django_postgres_new_1:/backups
docker exec eno-a3-django_postgres_new_1 pg_restore -U debug -d 1013-replicatelive /backups/10.5.dump
因为我认为两个容器都在与同一个卷通信,但是当我通过 5432 连接到旧的 postgres 容器时,我注意到我通过新的 postgres 容器 10.13 创建的新数据库不存在。
它似乎有效。我可以简单地销毁旧容器而不会意外破坏现有数据吗?
然而..
当我通过端口 5432 因此通过旧的 postgres 容器更改数据库中的某些数据库值(我认为在新的 postgres 容器中很常见)时,在新的 postgres 容器的相应数据库中看不到更改。
在我注释掉 local.yml 中的旧 postgres 容器之后
然后,我只 docker up 新的 postgres 容器并使其使用主机端口 5432。我现在可以看到新模式(通过主机端口 15432 恢复)以及公共(public)数据库模式中的更改。所以我猜这个方法有效。
但为什么它会起作用?是因为卷被重用了吗?

最佳答案

免责声明:我不是 Postgres 专家,请考虑这个答案来自一般 Docker 背景
容器和卷(以及相关的图像)是 Docker 中的独立实体。你 can share one volume between many containers ,但由于这几乎等于共享文件系统 - 您应该避免让两个不同的应用程序同时访问一组文件。您还可以在不影响您的卷或图像的情况下删除容器(有修剪所有内容的选项 - 有 plenty information on SO about how to do that )
为什么有效
我假设 postgres 从 /var/lib/postgresql/data 加载数据库列表在启动时,因此您对新数据库的更改可能不会立即传播到其他容器,但在重新启动后最终可见。
看来您的示例最终运行良好,因为您将备份恢复到不同的数据库中,因此没有发生损坏。对我来说,这似乎是一个意外。
备份-恢复
从我在您指向的 github 链接中可以看到 - 两者都对 /var/lib/postgresql/data 使用单独的卷(正是为了避免并发修改)但共享一个卷进行备份。然后他们会将旧数据库转储到共享卷并将其通过管道传输到新数据库。
自定义 pg_upgrade 镜像
在这里您可以构建具有源版本和目标版本的容器并运行较新的 pg_upgrade as per official guide - 这应该执行升级并将二进制数据库文件写入您选择的位置。然后,您可以将此数据卷挂载到新的 postgres 容器上。
就地升级(次要版本)
由于pg_upgrade文档声称次要版本不需要它,可以安全地假设它们之间没有文件布局更改。然后你可能甚至不需要启动另一个容器 - 只需升级你的 docker-compose 中的 postgres 镜像。并继续使用旧卷。这将为您节省一些麻烦。话虽如此 - 这可能是您需要进行大量测试的最后选择。

关于postgresql - 如何在维护数据的同时升级 docker 容器中的 postgres? 10.3 到最新的 10.x 或 12.x,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62790302/

相关文章:

docker - 无法安装到Kubernetes中的NFS Pod

java - "Powershell"- 使用 OpenJDK 启动 Docker 容器时出错 :Windowsservercore

ruby-on-rails - 使用 ActiveRecord 更新 Postgres JSON 字段

python psycopg2 插入 postgresql 帮助

macos - textmate 不保存提交信息

python - 在 mac 上使用 readline 安装 ipython

python - GeoDjango touches 功能很慢

Django fixture 失败,显示 "DatabaseError: value too long for type character varying(50)"

macos - 如何使用 gcc 在 Mac OS X 中从多个 .o 构建 dylib

django - 在 Windows 上为 django 构建 docker 镜像时出现 gcc 错误