# ================================================ # Urban Lifeline - PostgreSQL 数据库镜像 # 支持初始化脚本和自定义配置 # ================================================ FROM postgres:16-alpine # 设置环境变量 ENV LANG=C.UTF-8 \ TZ=Asia/Shanghai \ PGCLIENTENCODING=UTF8 # 安装时区数据(contrib 扩展已包含在官方 postgres 镜像中) RUN apk add --no-cache tzdata \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone # 创建初始化目录 RUN mkdir -p /docker-entrypoint-initdb.d /opt/sql # 复制初始化脚本和 SQL 文件 COPY init/sql/ /opt/sql/ COPY init/bin.sh /opt/bin.sh # 创建 Docker 初始化入口脚本 RUN cat > /docker-entrypoint-initdb.d/01-init-database.sh <<'EOF' #!/bin/bash set -e echo "==========================================" echo "Urban Lifeline - PostgreSQL 数据库初始化" echo "==========================================" # 设置环境变量 export PGCLIENTENCODING=UTF8 # 检查数据库是否已初始化(通过检查初始化状态表) check_initialized() { # 先检查数据库是否存在 if ! psql -U "$POSTGRES_USER" -d "postgres" -tAc "SELECT 1 FROM pg_database WHERE datname = '$POSTGRES_DB'" | grep -q 1; then return 1 # 数据库不存在,需要初始化 fi # 检查初始化状态表是否存在且标记为成功 if psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -tAc "SELECT 1 FROM _db_init_status WHERE script_name = '01-init-database.sh' AND status = 'success'" 2>/dev/null | grep -q 1; then return 0 # 已初始化 fi return 1 # 未初始化 } # 检查是否已经初始化 if check_initialized; then echo "==========================================" echo "✅ 数据库已初始化,跳过初始化步骤" echo "==========================================" exit 0 fi echo "首次启动,开始初始化数据库..." cd /opt/sql # 执行 initAll.sql(包含创建数据库、表结构和初始数据) echo "执行数据库初始化脚本..." psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "postgres" -f initAll.sql if [ $? -ne 0 ]; then echo "==========================================" echo "❌ 数据库初始化失败!" echo "==========================================" exit 1 fi # 创建初始化状态表并标记完成 echo "标记初始化状态..." psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL -- 创建初始化状态表 CREATE TABLE IF NOT EXISTS _db_init_status ( id SERIAL PRIMARY KEY, script_name VARCHAR(255) NOT NULL UNIQUE, executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, status VARCHAR(50) DEFAULT 'init' ); -- 标记初始化完成 INSERT INTO _db_init_status (script_name, status) VALUES ('01-init-database.sh', 'success') ON CONFLICT (script_name) DO UPDATE SET status = 'success', executed_at = CURRENT_TIMESTAMP; EOSQL echo "==========================================" echo "✅ 数据库初始化完成!" echo "==========================================" EOF # 设置执行权限 RUN chmod +x /docker-entrypoint-initdb.d/01-init-database.sh \ && chmod +x /opt/bin.sh # 暴露端口 EXPOSE 5432 # 健康检查 HEALTHCHECK --interval=10s --timeout=5s --retries=5 --start-period=60s \ CMD pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-urban_lifeline} || exit 1