Docker Compose环境下Phoenix服务无法连接PostgreSQL求助
问题描述
我配置了如下docker-compose.yml文件:
version: "3.8" services: plataforma-pescarte: build: /home/dev/pescarte container_name: plataforma-pescarte ports: - 8080:8080 depends_on: postgresql: condition: service_healthy env_file: - /home/dev/pescarte/.env networks: - pescarte-network postgresql: image: postgres container_name: postgresql environment: - POSTGRES_USER=peapescarte - POSTGRES_DB=peapescarte - POSTGRES_PASSWORD=<redacted> ports: - 5432:5432 healthcheck: test: ["CMD-SHELL", "pg_isready -U peapescarte -h postgresql -d peapescarte"] interval: 5s timeout: 2s retries: 1 networks: - pescarte-network networks: pescarte-network:
plataforma-pescarte的Dockerfile:
ARG ELIXIR_VERSION=1.14.2 ARG OTP_VERSION=25.1.2.1 ARG DEBIAN_VERSION=buster-20230109-slim ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}" FROM ${BUILDER_IMAGE} as builder RUN apt-get update -y && apt-get install -y build-essential curl \ && curl -fsSL https://deb.nodesource.com/setup_17.x | bash - \ && apt-get install -y nodejs WORKDIR /app RUN mix local.hex --force && \ mix local.rebar --force ENV MIX_ENV="prod" COPY mix.exs mix.lock ./ RUN mix deps.get --only $MIX_ENV RUN mkdir config # to be re-compiled. COPY config/config.exs config/${MIX_ENV}.exs config/ RUN mix deps.compile COPY priv priv COPY lib lib COPY assets assets # compile assets RUN npm i --prefix ./assets RUN mix assets.deploy # Compile the release RUN mix compile # Changes to config/runtime.exs don't require recompiling the code COPY config/runtime.exs config/ COPY rel rel RUN mix release FROM ${RUNNER_IMAGE} RUN apt-get update -y \ && apt-get install -y iputils-ping libstdc++6 openssl libncurses5 locales postgresql-client # Set the locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 WORKDIR /pescarte RUN chown nobody /pescarte # set runner ENV ENV MIX_ENV="prod" # Only copy the final release from the build stage COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/pescarte ./ USER nobody CMD ["bin/server"]
.env文件内容:
SECRET_KEY_BASE="lDNl9lE0FnTNYArm0Cc7+Z18ocSn8WA2mO36cDxQC+4Ihiuzvs69Lqj9b5QYnYon" DATABASE_URL="ecto://peapescarte:<redacted>@postgresql:5432/peapescarte" SSL_KEY_PATH=/etc/ssl/private/ssl-cert-snakeoil.key SSL_CERT_PATH=/etc/ssl/certs/ssl-cert-snakeoil.pem ECTO_IPV6=true UENF_SERVER=true MIX_ENV=prod PORT=8080
config/runtime.exs配置:
database_url = System.get_env("DATABASE_URL") || raise "DATABASE_URL not available" if System.get_env("ECTO_IPV6") do config :pescarte, Pescarte.Repo, socket_options: [:inet6] end config :pescarte, Pescarte.Repo, # fly.io don't need ssl: false, url: database_url, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
构建成功,但执行docker compose up时,plataforma-pescarte服务出现如下错误:
postgresql | PostgreSQL init process complete; ready for start up. postgresql | postgresql | 2023-06-23 16:12:06.631 UTC [1] LOG: starting PostgreSQL 15.2 (Debian 15.2-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit postgresql | 2023-06-23 16:12:06.632 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 postgresql | 2023-06-23 16:12:06.632 UTC [1] LOG: listening on IPv6 address "::", port 5432 postgresql | 2023-06-23 16:12:06.640 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" postgresql | 2023-06-23 16:12:06.652 UTC [64] LOG: database system was shut down at 2023-06-23 16:12:06 UTC postgresql | 2023-06-23 16:12:06.662 UTC [1] LOG: database system is ready to accept connections plataforma-pescarte | 16:12:11.588 [error] Postgrex.Protocol (#PID<0.137.0>) failed to connect: ** (DBConnection.ConnectionError) tcp connect (postgresql:5432): non-existing domain - :nxdomain
但进入plataforma-pescarte容器执行ping postgresql或pg_isready -U peapescarte -d peapescarte -h postgresql命令时,能正常解析域名并连接PostgreSQL数据库。请问哪里配置出错了?
解决方案
问题出在IPv6配置冲突上:
.env中设置了ECTO_IPV6=true,导致config/runtime.exs给Repo添加了socket_options: [:inet6],强制Ecto使用IPv6连接数据库。- 虽然PostgreSQL日志显示监听了IPv6地址,但Docker默认自定义网络是禁用IPv6的,这就导致Ecto尝试用IPv6解析
postgresql域名时失败,抛出:nxdomain错误。 - 进入容器后用
ping或pg_isready能成功,是因为这些工具默认优先使用IPv4,自动 fallback 到了可用的IPv4地址。
修复方案:
- 临时快速修复:将
.env里的ECTO_IPV6=true改为ECTO_IPV6=false,让Ecto使用IPv4连接,问题即可解决。 - 永久方案(若确实需要IPv6):在
docker-compose.yml的自定义网络中启用IPv6支持,示例配置:
networks: pescarte-network: enable_ipv6: true ipam: config: - subnet: fd00::/80
同时需要确保Docker daemon本身已启用IPv6支持(修改/etc/docker/daemon.json后重启Docker服务)。
内容的提问来源于stack exchange,提问作者Zoey
相关产品推荐
相关产品推荐

