Docker部署Supabase时安装Apache AGE扩展失败求助
基于supabase/postgres:15.8.1.020构建了包含Apache AGE的自定义镜像,使用dbmate执行迁移添加AGE扩展时,报错extension 'age' is not available。但进入容器后能看到/usr/share/postgresql/15/extension/下存在AGE相关文件,尝试将age加入shared_preload_libraries也未解决。
相关配置文件
Dockerfile
FROM supabase/postgres:15.8.1.020 AS builder # Add proxy configuration RUN echo 'Acquire::http::Pipeline-Depth 0;' > /etc/apt/apt.conf.d/99fixbadproxy && \ echo 'Acquire::http::No-Cache true;' >> /etc/apt/apt.conf.d/99fixbadproxy && \ echo 'Acquire::BrokenProxy true;' >> /etc/apt/apt.conf.d/99fixbadproxy # Add PostgreSQL repository RUN apt-get update && apt-get install -y curl ca-certificates gnupg lsb-release RUN curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql-keyring.gpg RUN echo "deb [signed-by=/usr/share/keyrings/postgresql-keyring.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list # Install build dependencies RUN apt-get update RUN apt-get install -y --no-install-recommends --no-install-suggests \ bison \ build-essential \ flex \ git \ postgresql-server-dev-15 # Clone and build Apache AGE RUN git clone https://github.com/apache/age.git /age WORKDIR /age RUN git checkout release/PG15/1.5.0 RUN make install # Final stage - clean image with just the extension files FROM supabase/postgres:15.8.1.020 # Copy only the compiled extension files COPY --from=0 /usr/lib/postgresql/15/lib/age.so /usr/lib/postgresql/15/lib/ COPY --from=0 /usr/share/postgresql/15/extension/age* /usr/share/postgresql/15/extension/
docker-compose.yml
db: container_name: supabase-db image: localhost:5000/supabase-with-age restart: unless-stopped volumes: - ./volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z # Must be superuser to create event trigger - ./volumes/db/webhooks.sql:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql:Z # Must be superuser to alter reserved role - ./volumes/db/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:Z # Initialize the database settings with JWT_SECRET and JWT_EXP - ./volumes/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:Z # PGDATA directory is persisted between restarts - ./volumes/db/data:/var/lib/postgresql/data:Z # Changes required for internal supabase data such as _analytics - ./volumes/db/_supabase.sql:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql:Z # Changes required for Analytics support - ./volumes/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:Z # Changes required for Pooler support - ./volumes/db/pooler.sql:/docker-entrypoint-initdb.d/migrations/99-pooler.sql:Z # Use named volume to persist pgsodium decryption key between restarts - db-config:/etc/postgresql-custom healthcheck: test: [ "CMD", "pg_isready", "-U", "postgres", "-h", "localhost" ] interval: 5s timeout: 5s retries: 10 depends_on: vector: condition: service_healthy environment: POSTGRES_HOST: /var/run/postgresql PGPORT: ${POSTGRES_PORT} POSTGRES_PORT: ${POSTGRES_PORT} PGPASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} PGDATABASE: ${POSTGRES_DB} POSTGRES_DB: ${POSTGRES_DB} JWT_SECRET: ${JWT_SECRET} JWT_EXP: ${JWT_EXPIRY} command: [ "postgres", "-c", "config_file=/etc/postgresql/postgresql.conf", "-c", "log_min_messages=fatal" # prevents Realtime polling queries from appearing in logs ] dbmate: image: amacneil/dbmate command: --wait up # auto apply migrations restart: on-failure:3 # Limit restart attempts volumes: - ./db/migrations:/db/migrations:Z environment: DATABASE_URL: "postgres://postgres:postgres@db:5432/postgres?sslmode=disable" DBMATE_SCHEMA_MIGRATIONS_TABLE: "schema_migrations" # Explicitly name tracking table DBMATE_NO_DUMP_SCHEMA: "true" # Skip schema dumping for performance depends_on: db: condition: service_healthy # Requires the healthcheck defined above logging: driver: "json-file" options: max-size: "10m" max-file: "3"
排查与解决办法
1. 确认PostgreSQL扩展搜索路径
Supabase的PostgreSQL可能自定义了extension_directory,导致默认路径下的AGE文件不被识别。进入容器执行SQL命令确认:
SHOW extension_directory;
如果输出不是/usr/share/postgresql/15/extension,需要在docker-compose的db服务command中添加指定路径的参数:
command: [ "postgres", "-c", "config_file=/etc/postgresql/postgresql.conf", "-c", "log_min_messages=fatal", "-c", "extension_directory=/usr/share/postgresql/15/extension" ]
2. 修复AGE编译兼容性
Supabase的PostgreSQL镜像带有定制化补丁,直接用官方PG开发包编译的AGE可能存在兼容性问题。修改Dockerfile的依赖安装步骤,移除官方PG开发包,确保使用与镜像匹配的编译环境:
# 替换原PG开发包安装命令 RUN apt-get install -y --no-install-recommends --no-install-suggests \ bison \ build-essential \ flex \ git # 无需安装postgresql-server-dev-15,直接使用Supabase镜像内置的PostgreSQL开发文件
3. 修正AGE文件权限
AGE的.so文件和扩展脚本需要PostgreSQL进程有权限读取。在Dockerfile中添加权限修正步骤:
COPY --from=0 /usr/lib/postgresql/15/lib/age.so /usr/lib/postgresql/15/lib/ COPY --from=0 /usr/share/postgresql/15/extension/age* /usr/share/postgresql/15/extension/ # 修正文件权限 RUN chown postgres:postgres /usr/lib/postgresql/15/lib/age.so \ && chmod 644 /usr/lib/postgresql/15/lib/age.so \ && chown -R postgres:postgres /usr/share/postgresql/15/extension/age* \ && chmod -R 644 /usr/share/postgresql/15/extension/age*
4. 正确配置预加载库
确保age被正确加入shared_preload_libraries,并重启PostgreSQL生效。在docker-compose的db服务command中添加:
command: [ "postgres", "-c", "config_file=/etc/postgresql/postgresql.conf", "-c", "log_min_messages=fatal", "-c", "shared_preload_libraries=age" ]
如果原本已有其他预加载库,用逗号分隔,例如shared_preload_libraries=pg_stat_statements,age。
5. 调整初始化顺序
dbmate的迁移可能在AGE完全加载前执行,可通过两种方式解决:
- 将创建AGE扩展的语句放入Supabase初始化目录(
/docker-entrypoint-initdb.d/)的脚本中,优先执行 - 修改dbmate的command,增加等待时间:
command: sh -c "sleep 10 && dbmate --wait up"
6. 手动验证扩展可用性
进入容器,用psql连接数据库手动执行创建命令,查看详细错误信息:
CREATE EXTENSION age;
如果报错,错误信息会直接指向问题根源(如文件缺失、权限不足等)。
内容的提问来源于stack exchange,提问作者Niall

