Docker构建阶段如何定义IP/主机名?解决数据库连接失败
容器构建时数据库连接失败的解决方案
背景
我有一个通过BIN文件和.properties配置文件安装的应用,配置文件包含数据库位置(主机名/IP)、应用访问URL等配置,安装命令为:
bash ./app.bin -s conf.properties
安装过程中,BIN文件会连接指定数据库创建库和用户,但此步骤失败,报错信息:
Create database: failure unable to create database, reason: Connection to 127.0.0.1:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. org.postgresql.util.PSQLException: Connection to 127.0.0.1:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
目标
实现无需传入变量/环境变量即可运行容器,同时支持自定义主机名等环境变量。
问题
构建阶段(docker build)中主机名或IP似乎不存在,导致数据库连接错误。如何解决?是否需要将BIN文件安装放到运行阶段(docker run)?这可行吗?
当前Dockerfile
FROM redhat/ubi9:9.0.0 AS RHEL9 LABEL name="Desinger" RUN mkdir -p /usr/local/designer # Update system packages RUN yum -y update #Install bzip2 RUN yum install bzip2 -y #Install PostgreSQL RUN dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm RUN dnf install -y postgresql14-server RUN systemctl enable postgresql-14 #Copy OO files COPY files/installer-designer.bin /usr/local/designer COPY files/designer.properties /usr/local/designer RUN chmod +x /usr/local/designer/installer-designer.bin #Copy other filers COPY files/ls /usr/bin/ls COPY files/sudo /usr/bin/sudo COPY files/hostname /usr/bin/hostname COPY files/nano /usr/bin/nano #Environment variables ENV ADMIN=admin ENV PASS=?Password_123 #Expose ports EXPOSE 8445 EXPOSE 443 EXPOSE 5432 # Replace placeholders in configuration file with environment variables RUN sed -i 's/${ADMIN}/'"$ADMIN"'/' /usr/local/designer/designer.properties RUN sed -i 's/${PASS}/'"$PASS"'/' /usr/local/designer/designer.properties # Install Designer RUN bash /usr/local/designer/installer-designer.bin -s /usr/local/designer/designer.properties
已尝试无效方案
echo $(head -1 /etc/hosts | cut -f1) $HOST_NAME >> /etc/hosts- 设置
ENV HOSTNAME="foo"并执行RUN echo "foo" > /etc/hostname
解决方案
核心问题分析
Docker构建阶段(docker build)中,每个RUN命令都在独立临时容器中执行,PostgreSQL服务在构建阶段不会持续运行。你虽然安装并启用了postgresql-14,但systemctl enable仅设置开机自启,构建阶段并未启动服务,所以安装BIN文件时连接127.0.0.1:5432必然失败。
方案1:将安装步骤移至运行阶段(推荐)
把BIN文件的安装放到容器启动时执行,此时PostgreSQL服务已启动,能正常连接。具体修改如下:
- 移除Dockerfile中的
RUN bash /usr/local/designer/installer-designer.bin ...命令 - 创建启动脚本
startup.sh,内容如下:
#!/bin/bash # 初始化并启动PostgreSQL postgresql-14-setup initdb systemctl start postgresql-14 # 等待PostgreSQL就绪(可选但建议) until pg_isready -h 127.0.0.1 -p 5432; do echo "等待PostgreSQL启动..." sleep 2 done # 仅首次启动时执行应用安装 if [ ! -d "/usr/local/designer/installed" ]; then bash /usr/local/designer/installer-designer.bin -s /usr/local/designer/designer.properties mkdir /usr/local/designer/installed fi # 启动应用服务(请替换为实际的应用启动命令) systemctl start designer-service # 保持容器运行 tail -f /dev/null
- 将启动脚本复制到容器并设置权限:
COPY files/startup.sh /usr/local/designer/ RUN chmod +x /usr/local/designer/startup.sh
- 将Dockerfile最后一行改为启动脚本:
CMD ["/usr/local/designer/startup.sh"]
方案2:多阶段构建(适用于安装无需运行时依赖的场景)
如果应用安装仅需数据库连接完成初始化,后续运行不需要容器内的PostgreSQL,可采用多阶段构建:
- 第一阶段:安装PostgreSQL并启动,执行BIN安装,导出已安装的应用文件
- 第二阶段:从基础镜像复制导出的应用文件,配置启动命令
此方案需确认应用安装后可脱离构建阶段环境运行,灵活性不如方案1。
自定义环境变量支持
在启动脚本中,可根据环境变量动态修改designer.properties,示例:
# 在startup.sh中添加以下内容 if [ ! -z "$DB_HOST" ]; then sed -i 's/db.host=.*/db.host='"$DB_HOST"'/' /usr/local/designer/designer.properties fi
运行容器时可通过-e DB_HOST=xxx自定义数据库地址,默认仍使用127.0.0.1。
内容的提问来源于stack exchange,提问作者Zeta
相关产品推荐
相关产品推荐

