快速上手:使用 Docker Compose 运行 PostgreSQL – wiki基地


快速上手:使用 Docker Compose 轻松运行 PostgreSQL

在现代软件开发中,数据库是几乎所有应用程序不可或缺的核心组件。作为开源关系型数据库领域的佼佼者,PostgreSQL 以其强大的功能、稳定性和可靠性赢得了广泛的认可。然而,传统的数据库安装和配置过程往往繁琐且容易遇到各种依赖问题。这时,容器化技术,尤其是 Docker,就显得尤为重要。

Docker 提供了轻量级、可移植且自给自足的环境,使得应用程序及其所有依赖项可以打包在一起,并在任何地方一致地运行。而对于需要管理多个容器协同工作的复杂应用(比如一个 Web 应用、一个数据库和一个缓存服务),Docker Compose 应运而生。它允许你使用一个 YAML 文件来定义和管理多容器 Docker 应用,极大地简化了应用的部署和管理流程。

本文将带你快速上手,学习如何使用 Docker Compose 来运行 PostgreSQL 数据库,并详细讲解其核心配置和最佳实践,让你轻松告别繁琐的数据库安装,专注于应用的开发。

为什么选择使用 Docker Compose 运行 PostgreSQL?

在使用 Docker Compose 运行 PostgreSQL 之前,让我们先理解这种方式带来的显著优势:

  1. 环境隔离与一致性: Docker Compose 为 PostgreSQL 创建了一个独立的环境。这意味着它不会干扰你主机上的其他软件或数据库安装,也不会受到它们的影响。无论在开发、测试还是生产环境,只要 Docker 和 Docker Compose 环境就绪,PostgreSQL 就能以完全相同的方式运行,消除了“在我的机器上可以跑”的问题。
  2. 简化安装与配置: 你不再需要手动下载安装包、配置环境变量、初始化数据库。只需编写一个简单的 YAML 文件,运行一个命令,Docker Compose 就会自动完成镜像的下载、容器的创建和配置。
  3. 易于管理: 使用一个文件管理数据库服务(启动、停止、重启、删除),比手动管理进程或服务要高效得多。
  4. 数据持久化: Docker Compose 提供了强大的卷(Volumes)管理机制,可以确保你的数据库数据在容器停止、删除甚至更新后依然安全地保留。
  5. 依赖管理与组网: 如果你的应用(如后端服务)需要连接到数据库,Docker Compose 可以轻松地将它们放在同一个网络中,并允许服务之间通过服务名称互相发现和通信,无需复杂的网络配置。
  6. 版本控制: 数据库配置以 docker-compose.yml 文件的形式存在,可以像代码一样被版本控制起来,方便团队协作和回溯。

前提条件

在开始之前,请确保你的系统上已经安装了 Docker 和 Docker Compose。

  • 安装 Docker: 访问 Docker 官方网站,下载并安装适用于你操作系统的 Docker Desktop (macOS, Windows) 或 Docker Engine (Linux)。
  • 安装 Docker Compose: 在 Docker Desktop 中,Docker Compose 通常是内置的。对于 Linux 用户,可能需要单独安装。请参考 Docker Compose 官方安装指南。较新版本的 Docker Compose 是作为一个 Docker CLI 插件提供的,使用 docker compose 命令(无 -)。旧版本则使用 docker-compose 命令(有 -)。本文将主要使用较新的 docker compose 命令格式。

你可以通过运行以下命令来验证 Docker 和 Docker Compose 是否已正确安装:

bash
docker --version
docker compose version

如果命令输出了版本信息,说明你已经准备就绪。

核心:docker-compose.yml 文件

Docker Compose 的魔力集中在一个名为 docker-compose.yml 的文本文件中。这个文件使用 YAML 格式编写,用于定义你的服务、网络和卷等。

创建一个新的目录来存放你的项目文件,并在该目录中创建一个 docker-compose.yml 文件。

bash
mkdir my-postgres-app
cd my-postgres-app
touch docker-compose.yml

现在,打开 docker-compose.yml 文件,我们将逐步构建一个用于运行 PostgreSQL 的配置。

1. 基本的 PostgreSQL 服务配置

最简单的情况,我们只需要指定要使用的 PostgreSQL 镜像和一些必要的环境变量。

“`yaml
version: ‘3.8’ # 指定 Docker Compose 文件格式版本

services:
db: # 定义一个名为 ‘db’ 的服务,你可以起任何名字,比如 ‘postgres’
image: postgres:15 # 指定使用的 PostgreSQL 镜像,这里使用官方的 15 版本
restart: always # 设置容器退出时总是重启,保证服务高可用
environment: # 设置环境变量,用于配置 PostgreSQL
POSTGRES_PASSWORD: your_strong_password # !! 重要:设置 PostgreSQL 超级用户的密码
# POSTGRES_USER: myuser # 可选:设置超级用户的用户名,默认是 ‘postgres’
# POSTGRES_DB: mydatabase # 可选:设置默认创建的数据库名称,默认是和用户名一样

# ports: # 可选:将容器内部的 PostgreSQL 端口映射到主机上
#   - "5432:5432" # 格式是 主机端口:容器端口

# volumes: # 数据持久化配置,非常重要!后面会详细讲解
#   - db_data:/var/lib/postgresql/data # 将容器内数据目录映射到具名卷 'db_data'

volumes: # 如果使用了具名卷,需要在这里定义

db_data: # 定义一个名为 ‘db_data’ 的具名卷

“`

解释:

  • version: '3.8': 指定 Docker Compose 文件的版本。不同版本支持不同的特性。3.8 是一个比较常用的版本。
  • services:: 在这里定义你的所有服务(容器)。每个服务都有一个名称(例如 db)。
  • db:: 这是我们给 PostgreSQL 服务起的名字。在 Docker Compose 网络中,其他服务可以通过这个名字来访问 PostgreSQL。
  • image: postgres:15: 指定构建此服务所使用的 Docker 镜像。postgres 是官方 PostgreSQL 镜像的名称,:15 指定了使用 15 版本。你也可以使用 latest,但推荐使用特定版本以确保环境稳定。
  • restart: always: 设置容器的重启策略。always 表示无论容器如何退出(正常停止、错误退出等),Docker 都会尝试重启它。这有助于提高服务的可用性。
  • environment:: 用于设置传递给容器的环境变量。这是配置 PostgreSQL 的主要方式。
    • POSTGRES_PASSWORD: 这是最重要且必须设置的环境变量! 它指定了 PostgreSQL 超级用户(默认为 postgres)的密码。请务必将其替换为一个强密码! 不要使用示例中的 your_strong_password
    • POSTGRES_USER (可选): 指定超级用户的用户名。如果未设置,默认为 postgres
    • POSTGRES_DB (可选): 指定在容器启动时自动创建的数据库名称。如果未设置,默认数据库的名称将与 POSTGRES_USER 相同。
  • ports: (可选): 用于将容器内部的端口映射到主机上。PostgreSQL 默认监听 5432 端口。将 5432:5432 映射出来后,你就可以直接从主机上使用数据库客户端(如 psql 或 pgAdmin)连接到这个数据库。注意:在生产环境中,通常不建议将数据库端口直接暴露到公网,而是在 Docker Compose 网络内部供其他应用容器访问。
  • volumes: (重要): 用于数据持久化。这是确保数据库数据不会随着容器的删除而丢失的关键配置。在上面的基本配置中,我们注释掉了这一行,后面会详细讲解如何正确配置。
  • volumes: (在服务定义之外): 用于定义具名卷(Named Volumes)。如果服务中使用了具名卷,需要在文件的顶层 volumes 部分进行定义。

2. 运行你的 PostgreSQL 服务

保存 docker-compose.yml 文件。现在,在包含这个文件的目录下,打开终端,运行以下命令来启动你的 PostgreSQL 服务:

bash
docker compose up -d

解释:

  • docker compose: 调用 Docker Compose CLI 工具。
  • up: 构建、(如果需要)创建、启动和连接服务。
  • -d: 以“分离”(detached)模式运行,这意味着容器将在后台运行,不会阻塞你的终端。

第一次运行 docker compose up -d 时,Docker Compose 会:

  1. 查找 docker-compose.yml 文件。
  2. 根据 image: postgres:15 下载 PostgreSQL 镜像(如果本地不存在)。
  3. 创建一个名为 my-postgres-app_db_1 (或类似名称,格式通常是 目录名_服务名_序号) 的容器。
  4. 设置你在 environment 中指定的环境变量。
  5. (如果配置了 ports)在主机上打开指定的端口并将其转发到容器内部。
  6. (如果配置了 volumes)创建或查找指定的卷,并将其挂载到容器内 PostgreSQL 数据目录 (/var/lib/postgresql/data)。
  7. 启动 PostgreSQL 服务。

你可以使用以下命令检查服务是否正在运行:

bash
docker compose ps

输出应该类似于:

NAME COMMAND SERVICE STATUS PORTS
my-postgres-app_db_1 "docker-entrypoint.s…" db running (healthy) 0.0.0.0:5432->5432/tcp # 如果你映射了端口

STATUS 列显示 running,表示容器已成功启动。如果配置了健康检查(后面会讲),可能会显示 running (healthy)

要查看服务的日志,以便进行调试或查看启动过程:

bash
docker compose logs db

要停止服务:

bash
docker compose down

这将停止并删除由 docker compose up 创建的容器和默认网络。注意:docker compose down 默认不会删除卷!这是为了保护你的数据。 如果你想同时删除卷(慎用!会导致数据丢失),可以使用 -v 标志:docker compose down -v

关键:数据持久化 (Volumes)

上面的基本配置有一个严重的问题:如果你停止并删除了容器 (docker compose down),所有存储在数据库中的数据都会丢失,因为数据是存储在容器的可写层中的,而可写层会随着容器的删除而消失。

为了解决这个问题,我们需要使用 Docker 的卷(Volumes)功能将容器内部的数据目录 (/var/lib/postgresql/data 是 PostgreSQL 存储数据文件的默认位置) 映射到 Docker 管理的持久化存储区域。

有两种主要的卷类型:

  1. 具名卷 (Named Volumes): 这是推荐用于数据库数据的方法。具名卷由 Docker 管理,它们在主机文件系统的特定位置存储数据,但具体位置通常不重要,你只需要知道卷的名称。Docker 负责卷的创建、管理和挂载。它们生命周期独立于容器。
  2. 绑定挂载 (Bind Mounts): 允许你将主机文件系统上的一个目录直接挂载到容器内的某个路径。这更常用于将源代码或配置文件挂载到容器中进行开发,或者让容器访问主机上的特定文件或目录。虽然也可以用于数据持久化,但不如具名卷灵活,尤其是在权限管理和跨平台方面。

推荐使用具名卷来持久化 PostgreSQL 数据。

修改你的 docker-compose.yml 文件,添加卷配置:

“`yaml
version: ‘3.8’

services:
db:
image: postgres:15
restart: always
environment:
POSTGRES_PASSWORD: your_strong_password # !! 务必修改为你的强密码
# POSTGRES_USER: myuser
# POSTGRES_DB: mydatabase

ports:
  - "5432:5432" # 暂时保留端口映射方便测试连接

volumes:
  - db_data:/var/lib/postgresql/data # 将具名卷 'db_data' 挂载到容器的 /var/lib/postgresql/data 目录

volumes: # 在 services 之外定义具名卷
db_data: # 定义一个名为 ‘db_data’ 的具名卷
# 可选的配置,例如指定驱动或标签
# driver: local
# driver_opts:
# o: bind
# type: none
# device: /path/on/your/host # 如果想指定主机路径,这实际上变成了 Bind Mount 的高级用法
“`

解释:

  • services -> db 下增加了 volumes: 配置。
    • - db_data:/var/lib/postgresql/data: 这一行表示将名为 db_data 的具名卷挂载到容器内部的 /var/lib/postgresql/data 路径。 Docker 会确保 /var/lib/postgresql/data 目录的内容被存储在 db_data 这个卷中。
  • 在文件的最底部增加了顶级的 volumes: 部分。
    • db_data:: 这是一个简单的定义,告诉 Docker Compose 有一个名为 db_data 的卷需要管理。默认情况下,Docker 会创建一个本地卷。

现在,再次运行 docker compose up -d。Docker Compose 会自动创建 db_data 卷(如果不存在),并将其挂载到容器。

你可以通过 docker volume ls 命令查看 Docker 管理的卷列表。

bash
docker volume ls

你会看到一个类似于 my-postgres-app_db_data 的卷(名称通常是 目录名_卷名)。

即使你运行 docker compose down 停止并删除了容器,这个卷及其中的数据仍然保留。下次你运行 docker compose up -d 时,Docker Compose 会使用同一个 db_data 卷创建新的容器,你的数据将得以恢复。只有使用 docker compose down -vdocker volume rm 命令才会删除卷和数据。

访问你的 PostgreSQL 数据库

启动容器后,你可以通过几种方式访问数据库:

1. 使用 psql 连接容器内部

你可以直接进入运行中的 PostgreSQL 容器,使用其内部的 psql 命令行客户端进行操作。

首先,找到容器的名称或 ID(docker compose ps)。然后执行:

bash
docker compose exec db psql -U postgres

解释:

  • docker compose exec db: 在名为 db 的服务容器中执行命令。
  • psql: PostgreSQL 的命令行客户端。
  • -U postgres: 使用 postgres 用户连接。当提示输入密码时,输入你在 docker-compose.yml 中为 POSTGRES_PASSWORD 设置的值。

连接成功后,你就可以像在本地安装的 PostgreSQL 中一样执行 SQL 命令了。

2. 使用主机上的 psql 或 GUI 工具 (如果端口已映射)

如果你在 docker-compose.yml 中配置了 ports: - "5432:5432",你可以直接从主机上使用任何 PostgreSQL 客户端工具连接到 localhost127.0.0.1 的 5432 端口。

  • 使用主机上的 psql: 如果你的主机上也安装了 psql,可以这样连接:

    bash
    psql -h localhost -U postgres -p 5432

    输入密码即可。

  • 使用 GUI 工具 (如 pgAdmin, DBeaver): 打开你喜欢的数据库 GUI 工具,创建新的连接,配置如下:

    • Host/Server Address: localhost127.0.0.1
    • Port: 5432
    • Database: postgres (或你在 POSTGRES_DB 中设置的名称)
    • Username: postgres (或你在 POSTGRES_USER 中设置的名称)
    • Password: 你在 POSTGRES_PASSWORD 中设置的密码

连接成功后,你就可以通过图形界面管理你的数据库了。

进阶配置与最佳实践

为了构建更健壮、更灵活的 Docker Compose 应用,我们需要了解一些进阶配置。

1. 自定义用户和数据库

在上面的示例中,我们使用了默认的 postgres 用户和数据库。在实际应用中,通常需要创建特定的用户和数据库。你可以通过环境变量来实现:

“`yaml
version: ‘3.8’

services:
db:
image: postgres:15
restart: always
environment:
POSTGRES_PASSWORD: your_strong_password # 超级用户密码
POSTGRES_USER: myuser # 指定新的超级用户用户名
POSTGRES_DB: myapp_db # 指定启动时创建的数据库名

ports:
  - "5432:5432"

volumes:
  - db_data:/var/lib/postgresql/data

volumes:
db_data:
“`

使用此配置启动容器后,PostgreSQL 将创建一个名为 myuser 的超级用户,并创建一个名为 myapp_db 的数据库。连接时,你就需要使用 myuser 和对应的密码,连接到 myapp_db 数据库。

2. 连接应用服务到数据库

Docker Compose 的强大之处在于管理多个相互依赖的服务。假设你有一个 Web 应用服务(例如,使用 Node.js, Python, Java 等),它需要连接到 PostgreSQL 数据库。

在同一个 docker-compose.yml 文件中,你可以定义你的应用服务,并将其连接到 db 服务所在的网络。默认情况下,Docker Compose 会为你的所有服务创建一个桥接网络,服务可以通过其服务名称互相访问。

“`yaml
version: ‘3.8’

services:
db:
image: postgres:15
restart: always
environment:
POSTGRES_PASSWORD: your_strong_password
POSTGRES_USER: myuser
POSTGRES_DB: myapp_db
volumes:
– db_data:/var/lib/postgresql/data
# 注意:如果你的应用服务和数据库在同一个 Docker Compose 网络中,通常无需将数据库端口映射到主机上。
# 只有当你需要从主机外部(非容器)访问数据库时才需要 ports 映射。
# ports:
# – “5432:5432”

myapp: # 定义你的应用服务
build: ./app # 假设你的应用代码在 ‘./app’ 目录,并且有 Dockerfile
# 或 image: your-app-image # 如果你已经构建了应用镜像
ports:
– “8080:80” # 将应用端口映射到主机
environment: # 配置应用连接数据库所需的环境变量
DATABASE_URL: postgres://myuser:your_strong_password@db:5432/myapp_db # 注意这里的主机名是 ‘db’ (服务名)
# 或者分开设置:
# DB_HOST: db
# DB_PORT: 5432
# DB_USER: myuser
# DB_PASSWORD: your_strong_password
# DB_NAME: myapp_db
depends_on: # 定义服务之间的依赖关系
– db # myapp 依赖于 db 服务

volumes:
db_data:
“`

解释:

  • 新增了一个 myapp 服务。
  • build: ./app (或 image:) 指定如何构建或使用应用镜像。
  • ports: 映射应用服务的端口到主机,以便从浏览器或客户端访问应用。
  • environment: 配置应用连接数据库所需的参数。关键在于数据库主机名不再是 localhost,而是数据库服务在 Docker Compose 网络中的名称 db。Docker Compose 的内部 DNS 会将 db 解析到数据库容器的 IP 地址。
  • depends_on: - db: 告诉 Docker Compose,myapp 服务依赖于 db 服务。Docker Compose 会尝试在启动 myapp 之前先启动 db然而,depends_on 只保证启动顺序,不保证依赖服务已经“准备就绪”(例如,数据库已经完全启动并接受连接)。 这就需要健康检查。

3. 添加健康检查 (Healthcheck)

depends_on 并不能保证数据库已经完全启动并可以接受连接。应用服务可能会启动得更快,导致连接数据库失败。为了解决这个问题,我们可以为数据库服务添加健康检查。Docker Compose 会定期运行一个命令来检查服务的健康状态,并且 depends_on 支持等待依赖服务达到健康状态后再启动。

修改 db 服务的配置,添加 healthcheck:

“`yaml
version: ‘3.8’

services:
db:
image: postgres:15
restart: always
environment:
POSTGRES_PASSWORD: your_strong_password
POSTGRES_USER: myuser
POSTGRES_DB: myapp_db
volumes:
– db_data:/var/lib/postgresql/data
healthcheck: # 添加健康检查配置
test: [“CMD-SHELL”, “pg_isready -U ${POSTGRES_USER:-postgres}”] # 测试命令
interval: 5s # 检查间隔
timeout: 5s # 超时时间
retries: 5 # 重试次数
start_period: 10s # 启动期间的等待时间,在此期间失败不计入 retries
# ports:
# – “5432:5432”

myapp:
build: ./app
ports:
– “8080:80”
environment:
DATABASE_URL: postgres://myuser:your_strong_password@db:5432/myapp_db
depends_on:
db: # 修改 depends_on 语法,指定依赖服务的健康状态
condition: service_healthy # myapp 依赖于 db 服务达到健康状态

volumes:
db_data:
“`

解释:

  • db 服务下增加了 healthcheck: 配置。
    • test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]: 这是执行健康检查的命令。pg_isready 是 PostgreSQL 提供的一个小工具,用于检查服务器是否接受连接。-U ${POSTGRES_USER:-postgres} 表示使用 POSTGRES_USER 环境变量指定的用户(如果未设置,则使用默认的 postgres 用户)进行检查。CMD-SHELL 表示在容器的 shell 中执行此命令。
    • interval: 5s: 每隔 5 秒检查一次。
    • timeout: 5s: 如果命令在 5 秒内没有完成,则视为失败。
    • retries: 5: 如果健康检查连续失败 5 次,则容器被标记为 unhealthy。
    • start_period: 10s: 在容器启动后的前 10 秒内,健康检查失败不会导致容器被标记为 unhealthy,这给容器启动和初始化数据库足够的时间。10 秒后,如果健康检查失败,才开始计算重试次数。
  • myapp 服务的 depends_on 中,将 - db 改为更详细的 db: condition: service_healthy。这明确告诉 Docker Compose,只有当 db 服务通过健康检查被标记为 healthy 时,才启动 myapp 服务。

现在,当你运行 docker compose up -d 时,Docker Compose 会等待 db 服务显示为 healthy (可以通过 docker compose psdocker compose logs db 查看状态) 后,才会启动 myapp 服务,从而避免了连接时数据库尚未就绪的问题。

4. 使用 .env 文件管理敏感信息

直接在 docker-compose.yml 中硬编码密码是非常不安全的做法,尤其是在将文件提交到版本控制系统时。更好的方法是使用环境变量,并将这些变量存储在 .env 文件中,然后将 .env 文件排除在版本控制之外(例如,添加到 .gitignore)。

创建一个名为 .env 的文件在与 docker-compose.yml 相同的目录下:

“`ini

.env 文件

POSTGRES_PASSWORD=your_very_secure_password_from_env
POSTGRES_USER=myuser_from_env
POSTGRES_DB=myapp_db_from_env
“`

然后修改 docker-compose.yml,使用 ${VAR_NAME} 语法引用 .env 文件中的变量:

“`yaml
version: ‘3.8’

services:
db:
image: postgres:15
restart: always
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} # 从 .env 文件中读取密码
POSTGRES_USER: ${POSTGRES_USER:-postgres} # 从 .env 中读取用户,如果未设置则使用 postgres
POSTGRES_DB: ${POSTGRES_DB:-postgres} # 从 .env 中读取数据库名,如果未设置则使用 postgres
volumes:
– db_data:/var/lib/postgresql/data
healthcheck:
test: [“CMD-SHELL”, “pg_isready -U ${POSTGRES_USER:-postgres}”]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s

# myapp 服务也同样从 .env 读取配置
# myapp:
# …
# environment:
# DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
# depends_on:
# db:
# condition: service_healthy

volumes:
db_data:
“`

现在,当你运行 docker compose up 时,Docker Compose 会自动读取 .env 文件中的变量,并将它们注入到容器的环境中。.env 文件可以添加到 .gitignore 中,保护你的敏感信息。

注意: 对于生产环境,更安全的敏感信息管理方式是使用 Docker Secrets 或外部密钥管理系统。.env 文件适用于开发和测试环境。

总结

通过本文的学习,你已经掌握了使用 Docker Compose 快速、便捷地运行 PostgreSQL 数据库的方法。我们从最基本的配置开始,逐步深入,了解了数据持久化(卷)、服务间通信、健康检查以及敏感信息管理(.env 文件)等重要概念和实践。

使用 Docker Compose 运行 PostgreSQL 不仅简化了环境搭建过程,更重要的是提供了一致性、隔离性、可移植性的优势,无论你是在开发、测试还是部署应用,都能享受到容器化带来的便利。

现在,你可以尝试:

  • 在你的开发项目中使用 Docker Compose 启动 PostgreSQL。
  • 将你的应用服务添加到 docker-compose.yml 文件中,并配置它连接到数据库。
  • 探索 PostgreSQL 官方镜像的其他配置选项(可以查看 Docker Hub 上的 PostgreSQL 页面 获取详细信息)。
  • 学习如何进行数据库备份和恢复(通常可以通过 docker compose exec 运行 pg_dumppg_restore 命令实现)。

Docker Compose 是构建和管理多容器应用的强大工具。熟练掌握它,将极大地提升你的开发效率和部署可靠性。开始你的容器化数据库之旅吧!

希望这篇详细的文章能够帮助你快速上手使用 Docker Compose 运行 PostgreSQL。祝你编码愉快!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部