1. 为什么选择PostgreSQL与Docker组合
在当今云原生时代,Docker已经成为应用部署的标准工具之一。作为一名长期使用PostgreSQL的开发者,我发现将PostgreSQL部署在Docker容器中,能够带来诸多便利。PostgreSQL作为功能最强大的开源关系型数据库,与Docker的轻量级容器化技术相结合,可以快速搭建开发、测试和生产环境。
PostgreSQL 16是目前最新的稳定版本,相比MySQL,它在以下场景表现尤为出色:
- 复杂查询和数据分析:PostgreSQL的查询优化器更为先进
- JSON数据处理:内置的JSONB类型提供了完整的JSON支持
- 地理空间数据:通过PostGIS扩展支持专业的地理信息系统
- 自定义数据类型:允许开发者创建自己的数据类型和运算符
提示:虽然PostgreSQL功能强大,但对于简单的Web应用,MySQL可能仍然是更轻量级的选择。选择数据库时应该根据实际业务需求来决定。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与项目初始化
2.1 Docker环境检查与安装
在开始之前,我们需要确保系统已经安装了Docker和Docker Compose。我推荐使用以下命令检查版本:
bash复制docker --version
docker-compose --version
如果系统尚未安装Docker Compose,可以使用以下命令安装(以Ubuntu/Debian为例):
bash复制sudo apt update
sudo apt install docker-compose-plugin -y
注意:较新的Docker版本已经将docker-compose集成到docker命令中,作为插件形式提供。建议使用
docker compose而不是旧的docker-compose命令。
2.2 镜像拉取与验证
我们将使用官方PostgreSQL 16镜像和pgAdmin 4镜像:
bash复制docker pull postgres:16
docker pull dpage/pgadmin4
验证镜像是否下载成功:
bash复制docker images | grep -E "postgres|pgadmin"
3. 项目目录结构与配置
3.1 创建项目目录
合理的目录结构是项目可维护性的基础。我建议按照以下方式组织项目:
bash复制mkdir -p ~/docker/postgres-project
cd ~/docker/postgres-project
mkdir -p postgres/{data,init}
mkdir -p pgadmin
chmod -R 777 pgadmin
目录结构说明:
code复制~/docker/postgres-project/
├── docker-compose.yml
├── postgres/
│ ├── data/ # 数据库数据文件(持久化存储)
│ └── init/ # 初始化SQL脚本
└── pgadmin/ # pgAdmin配置文件
3.2 初始化脚本编写
初始化脚本可以在容器首次启动时自动创建表结构和测试数据。这是一个非常实用的功能,特别是在开发环境中。
创建初始化脚本:
bash复制vim postgres/init/01-init.sql
以下是一个功能更完善的初始化脚本示例:
sql复制-- 启用常用扩展
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- 创建产品表
CREATE TABLE IF NOT EXISTS products (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
description TEXT,
price DECIMAL(10,2) CHECK (price > 0),
stock INTEGER DEFAULT 0 CHECK (stock >= 0),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 创建用户表(带密码加密)
CREATE TABLE IF NOT EXISTS users (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
is_admin BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP WITH TIME ZONE
);
-- 创建订单表
CREATE TABLE IF NOT EXISTS orders (
id SERIAL PRIMARY KEY,
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
product_id INTEGER REFERENCES products(id) ON DELETE SET NULL,
quantity INTEGER NOT NULL CHECK (quantity > 0),
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'completed', 'cancelled')),
total_price DECIMAL(10,2),
order_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 创建索引
CREATE INDEX idx_products_name ON products(name);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_status ON orders(status);
-- 插入测试数据
INSERT INTO products (name, description, price, stock) VALUES
('智能手机', '最新款智能手机', 2999.00, 100),
('笔记本电脑', '高性能笔记本电脑', 5999.00, 50),
('无线耳机', '降噪无线耳机', 299.00, 200)
ON CONFLICT (name) DO NOTHING;
-- 触发器示例:更新时自动设置updated_at字段
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_products_timestamp
BEFORE UPDATE ON products
FOR EACH ROW EXECUTE FUNCTION update_timestamp();
CREATE TRIGGER update_orders_timestamp
BEFORE UPDATE ON orders
FOR EACH ROW EXECUTE FUNCTION update_timestamp();
这个脚本不仅创建了基本表结构,还包含了数据验证、触发器、索引等高级功能,更适合真实项目场景。
4. Docker Compose配置详解
4.1 完整的docker-compose.yml
以下是经过优化的docker-compose.yml配置:
yaml复制version: '3.8'
services:
postgres:
image: postgres:16
container_name: postgres16
restart: unless-stopped
ports:
- "5432:5432"
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD:-123456}
POSTGRES_DB: myapp
TZ: Asia/Shanghai
POSTGRES_INITDB_ARGS: --encoding=UTF-8 --lc-collate=C --lc-ctype=C
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./postgres/data:/var/lib/postgresql/data
- ./postgres/init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d myapp"]
interval: 5s
timeout: 5s
retries: 5
networks:
- postgres-network
pgadmin:
image: dpage/pgadmin4
container_name: pgadmin
restart: un
