使用容器提供 PostgreSQL RESTful API 服务

大家好,我是你们的老朋友。今天我们来聊一个非常实用的话题:如何用容器技术快速搭建一个 PostgreSQL 数据库,并通过 RESTful API 对外提供服务。你可能会问,为什么要用容器?想象一下,你有一个项目需要数据库,如果直接安装 PostgreSQL 到你的电脑上,那换台机器就得重新配环境,而且不同项目可能需要不同版本的数据库,管理起来非常头疼。容器技术(比如 Docker)就能完美解决这个问题,它把数据库和它的依赖打包成一个轻量级的“箱子”,让你在任何地方都能一键启动。另外,直接操作数据库通常需要写 SQL 语句,不太适合前后端分离的场景。RESTful API 可以让你通过 HTTP 请求(比如 GET /users 获取用户列表)来操作数据,这样前端、移动端甚至其他服务都能方便地访问数据库。今天,我们将用 Docker 运行 PostgreSQL 容器,然后用 Python 的 Flask 框架写一个简单的 RESTful API 服务,最后也用容器来运行这个 API 服务。整个过程通俗易懂,跟着我一步步来,你也能成为容器+数据库的能手!## 准备工作:安装 Docker如果你还没有安装 Docker,请先前往 docker.com 下载并安装。安装完成后,打开终端(Linux/Mac 的 Terminal,Windows 的 PowerShell 或 CMD),运行以下命令验证:bashdocker --version如果看到类似 Docker version 24.0.7 的输出,说明安装成功。## 第一步:启动 PostgreSQL 容器我们先拉取 PostgreSQL 官方镜像,并启动一个容器。这里我们用 postgres:16 版本,设置用户、密码和数据库名。在终端中执行:bashdocker run -d \ --name my-postgres \ -e POSTGRES_USER=myuser \ -e POSTGRES_PASSWORD=mypassword \ -e POSTGRES_DB=mydb \ -p 5432:5432 \ postgres:16解释一下:- -d:后台运行容器。- --name my-postgres:给容器取个名字,方便管理。- -e:设置环境变量,比如数据库用户名、密码和初始数据库名。- -p 5432:5432:将容器的 5432 端口映射到主机的 5432 端口,这样我们就能从主机访问数据库了。等待几秒,容器启动后,我们可以用以下命令检查是否运行成功:bashdocker ps你会看到 my-postgres 容器在运行。现在,PostgreSQL 已经准备好了,接下来我们写 API 服务。## 第二步:编写 RESTful API 服务我们使用 Python 的 Flask 框架,配合 psycopg2 库连接 PostgreSQL。创建一个文件夹,比如 api-service,在里面新建一个文件 app.py。下面是完整的代码示例,包含注释:python# app.pyfrom flask import Flask, request, jsonifyimport psycopg2import osapp = Flask(__name__)# 数据库连接配置,这些环境变量后续可以从容器中传入DB_CONFIG = { 'host': os.getenv('DB_HOST', 'localhost'), # 默认连接本地 'port': os.getenv('DB_PORT', '5432'), 'dbname': os.getenv('DB_NAME', 'mydb'), 'user': os.getenv('DB_USER', 'myuser'), 'password': os.getenv('DB_PASSWORD', 'mypassword')}def get_db_connection(): """建立数据库连接""" conn = psycopg2.connect(**DB_CONFIG) return conn# 初始化数据库表def init_db(): """创建 users 表(如果不存在)""" conn = get_db_connection() cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL ) ''') conn.commit() cursor.close() conn.close()# 启动时初始化表init_db()# RESTful API 端点@app.route('/users', methods=['GET'])def get_users(): """获取所有用户""" conn = get_db_connection() cursor = conn.cursor() cursor.execute('SELECT id, name, email FROM users') users = cursor.fetchall() cursor.close() conn.close() # 将查询结果转为字典列表 result = [{'id': u[0], 'name': u[1], 'email': u[2]} for u in users] return jsonify(result)@app.route('/users', methods=['POST'])def create_user(): """创建新用户""" data = request.get_json() name = data.get('name') email = data.get('email') if not name or not email: return jsonify({'error': 'name and email required'}), 400 conn = get_db_connection() cursor = conn.cursor() try: cursor.execute( 'INSERT INTO users (name, email) VALUES (%s, %s) RETURNING id', (name, email) ) user_id = cursor.fetchone()[0] conn.commit() cursor.close() conn.close() return jsonify({'id': user_id, 'name': name, 'email': email}), 201 except psycopg2.IntegrityError: # 处理邮箱重复的情况 conn.rollback() cursor.close() conn.close() return jsonify({'error': 'Email already exists'}), 409@app.route('/users/<int:user_id>', methods=['GET'])def get_user(user_id): """获取单个用户""" conn = get_db_connection() cursor = conn.cursor() cursor.execute('SELECT id, name, email FROM users WHERE id = %s', (user_id,)) user = cursor.fetchone() cursor.close() conn.close() if user: return jsonify({'id': user[0], 'name': user[1], 'email': user[2]}) else: return jsonify({'error': 'User not found'}), 404if __name__ == '__main__': # 监听所有网络接口,端口5000 app.run(host='0.0.0.0', port=5000, debug=True)这段代码实现了三个 RESTful 端点:- GET /users:获取所有用户。- POST /users:创建新用户(JSON 格式,包括 nameemail)。- GET /users/<id>:获取特定用户。注意,DB_CONFIG 使用了环境变量,这样我们可以在容器化时动态指定数据库连接信息,而不是硬编码。## 第三步:容器化 API 服务为了让 API 服务也能在容器中运行,我们需要创建一个 Dockerfile。在 api-service 文件夹中新建 Dockerfiledockerfile# DockerfileFROM python:3.11-slim# 设置工作目录WORKDIR /app# 复制依赖文件并安装COPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt# 复制应用代码COPY app.py .# 暴露端口EXPOSE 5000# 启动命令CMD ["python", "app.py"]同时,创建 requirements.txt 文件,写入依赖:flaskpsycopg2-binary现在,构建镜像并运行容器:bash# 在 api-service 目录下执行docker build -t my-api-service .# 运行容器,连接 PostgreSQL 容器docker run -d \ --name my-api \ -p 5000:5000 \ -e DB_HOST=my-postgres \ -e DB_PORT=5432 \ -e DB_NAME=mydb \ -e DB_USER=myuser \ -e DB_PASSWORD=mypassword \ --link my-postgres:my-postgres \ my-api-service注意:- --link my-postgres:my-postgres:让 API 容器能通过主机名 my-postgres 访问 PostgreSQL 容器(旧版 Docker 用法,新版可以用自定义网络,但为了简单,这里用 --link)。- 环境变量 DB_HOST=my-postgres 对应 PostgreSQL 容器的名字。## 第四步:测试 RESTful API现在,我们可以用 curl 或 Postman 来测试 API 了。### 创建用户bashcurl -X POST http://localhost:5000/users \ -H "Content-Type: application/json" \ -d '{"name": "张三", "email": "zhangsan@example.com"}'预期返回:json{"id":1, "name":"张三", "email":"zhangsan@example.com"}### 获取所有用户bashcurl http://localhost:5000/users预期返回:json[{"id":1, "name":"张三", "email":"zhangsan@example.com"}]### 获取单个用户bashcurl http://localhost:5000/users/1预期返回同样的用户信息。## 第五步:用 Docker Compose 简化管理手动启动两个容器有点麻烦,而且 --link 也不是最佳实践。我们可以用 Docker Compose 来一键启动所有服务。在项目根目录创建 docker-compose.ymlyamlversion: '3'services: postgres: image: postgres:16 container_name: my-postgres environment: POSTGRES_USER: myuser POSTGRES_PASSWORD: mypassword POSTGRES_DB: mydb ports: - "5432:5432" api: build: ./api-service container_name: my-api ports: - "5000:5000" environment: DB_HOST: postgres # 服务名作为主机名 DB_PORT: 5432 DB_NAME: mydb DB_USER: myuser DB_PASSWORD: mypassword depends_on: - postgres然后只需运行:bashdocker-compose up -d所有服务就都启动了,而且 API 容器会自动等待 PostgreSQL 就绪(虽然 depends_on 只是启动顺序,不保证数据库完全可用,但通常够用)。## 总结今天我们学习了如何用容器技术提供 PostgreSQL RESTful API 服务。整个过程包括:1. 使用 Docker 启动 PostgreSQL 容器。2. 用 Python Flask 编写 RESTful API。3. 将 API 服务也容器化。4. 用 Docker Compose 统一管理。你可能会想,这比直接装数据库复杂啊?但想象一下,你要部署到服务器、或者给同事分享项目时,只需要一个 docker-compose.yml 文件,别人就能一键启动全部服务,不用再装 Python 依赖、配置数据库。这就是容器的魅力——环境一致性、可移植性、易于扩展。而且,这个例子只是一个起点。你可以扩展 API 支持更多操作(如更新、删除),或者换成更强大的框架(如 FastAPI),甚至用容器编排工具(如 Kubernetes)来管理大规模服务。希望这篇文章能帮到你,动手试试吧,你会爱上这种开发方式的!

更多推荐