如何在Arm64v8/Apple Silicon上复用x86 PostgreSQL数据?
问题
我们项目基于postgres:12.13-alpine(x86架构)构建每日更新的开发库PostgreSQL Docker镜像,该镜像包含大型数据库。我现在用搭载Apple Silicon的新Mac,通过Docker Desktop+Rosetta运行x86镜像时性能极差。
我写了Dockerfile尝试直接把数据目录复制到arm64v8/postgres:12镜像里,数据库能启动、表结构也完整,但数据显示乱码。有没有不用完整备份恢复就能迁移数据的方法?CI构建x86镜像已经花了好几个小时,不想再花同样时间构建arm64镜像,而且目前只有我一个人用arm64。
以下是我编写的Dockerfile:
ARG BASE=image-registry.apps.os-test.acme.inet/acme-dev/devdb ARG TAG=2023-11-27_amd64 ARG ORIGINAL="${BASE}:${TAG}" # Create a temporary container from the existing amd64 image to extract the data FROM --platform=linux/amd64 ${ORIGINAL} as amd64image # Use the arm64/arm64v8 version of the PostgreSQL image as the base image FROM arm64v8/postgres:12 ARG PG_POSTGRES_PWD=UShouldKnowBetter ENV POSTGRES_DB postgres ENV POSTGRES_USER postgres ENV POSTGRES_PASSWORD ${PG_POSTGRES_PWD} ENV PGDATA /pgdata # Create a directory to copy data from the amd64 image RUN mkdir -p /docker-entrypoint-initdb.d /pgdata # Copy the data from the amd64 image to the arm64 image COPY --from=amd64image /docker-entrypoint-initdb.d /docker-entrypoint-initdb.d COPY --from=amd64image /var/lib/postgresql /var/lib/postgresql COPY --from=amd64image /pgdata /pgdata #RUN echo "de_DE.utf8" >> /etc/locale.gen && locale-gen && grep -vwE "(lc_messages|lc_monetary|lc_numeric|lc_time)" /pgdata/postgresql.conf > /pgdata/postgresql.conf.new && \ # cp /pgdata/postgresql.conf.new /pgdata/postgresql.conf && chown -R postgres:postgres /pgdata && chmod 0750 -R /pgdata RUN echo "de_DE.utf8 UTF-8" >> /etc/locale.gen && locale-gen && chown -R postgres:postgres /pgdata && chmod 0750 -R /pgdata HEALTHCHECK --interval=10s --timeout=30s --start-period=5s --retries=3 \ CMD pg_isready -U postgres -d postgres
解决思路与方案
一、先搞定乱码问题
直接复制数据目录出乱码,核心是x86的alpine镜像和arm64的debian系镜像locale配置、字符集环境不匹配,PostgreSQL数据目录依赖底层系统locale。按下面步骤修复:
对齐locale与字符集配置
- 原x86镜像用alpine(musl-libc),arm64镜像用debian(glibc),locale生成逻辑不一样,得确保arm64镜像的locale和原镜像完全一致(比如你用的
de_DE.utf8)。修改Dockerfile的locale部分:RUN apt-get update && apt-get install -y locales && \ echo "de_DE.UTF-8 UTF-8" > /etc/locale.conf && \ echo "de_DE.UTF-8 UTF-8" >> /etc/locale.gen && \ locale-gen de_DE.UTF-8 && \ update-locale LANG=de_DE.UTF-8 LC_ALL=de_DE.UTF-8 ENV LANG de_DE.UTF-8 ENV LC_ALL de_DE.UTF-8 - 同时从原x86镜像导出
postgresql.conf,覆盖arm64镜像/pgdata下的配置,确保字符集参数一致,比如:client_encoding = 'UTF8' default_text_search_config = 'pg_catalog.german'
- 原x86镜像用alpine(musl-libc),arm64镜像用debian(glibc),locale生成逻辑不一样,得确保arm64镜像的locale和原镜像完全一致(比如你用的
修正数据目录权限
- 原x86镜像中postgres用户的UID/GID可能和arm64镜像不同,arm64镜像里postgres默认UID是999,所以要改权限:
RUN chown -R 999:999 /pgdata && chmod 0700 /pgdata
- 原x86镜像中postgres用户的UID/GID可能和arm64镜像不同,arm64镜像里postgres默认UID是999,所以要改权限:
二、无需全量备份的迁移方案
如果直接复制数据目录还是不稳定,试试下面几种轻量方法,比重新构建镜像快得多:
方法1:用pg_dumpall导出逻辑备份,快速导入
虽然是备份,但针对开发库做优化,比CI构建快:
- 启动原x86镜像(哪怕慢,只用来导出):
docker run --rm --platform linux/amd64 ${ORIGINAL} pg_dumpall -U postgres > devdb_dump.sql - 在arm64的Dockerfile里把dump文件复制到初始化目录,启动时自动导入:
COPY devdb_dump.sql /docker-entrypoint-initdb.d/
方法2:多阶段构建+pg_dump导出指定库
如果数据库太大,pg_dumpall太慢,只导出常用业务库:
FROM --platform=linux/amd64 ${ORIGINAL} as dump RUN pg_dump -U postgres -d your_dev_db > /dump.sql FROM arm64v8/postgres:12 COPY --from=dump /dump.sql /docker-entrypoint-initdb.d/ # 其他环境变量、权限配置同上
方法3:pg_basebackup物理备份(超大型库首选)
物理备份比逻辑备份快,可直接在arm64镜像恢复:
- 启动x86镜像容器,确保开启wal日志,执行备份:
docker exec -it x86_devdb_container pg_basebackup -D /tmp/backup -U postgres -Fp -Xs -P - 把备份目录复制到arm64镜像的
/pgdata,修改postgresql.conf中的wal相关参数,启动即可。
三、临时优化:提升Rosetta运行x86镜像的性能
如果暂时不想迁移,试试这些设置提升性能:
- 在Docker Desktop设置里开启"Use the new Virtualization framework"(Apple Silicon专属)
- 给x86镜像分配更多CPU和内存(比如8核16G)
- 关闭Docker Desktop的"Resource saver"模式
内容的提问来源于stack exchange,提问作者Dominik Dorn
相关产品推荐
相关产品推荐

