# 创建 PostgreSQL 服务容器

您可以创建 PostgreSQL 服务容器用于您的工作流程。 本指南举例说明如何为容器中运行或直接在运行器机器上运行的作业创建 PostgreSQL 服务。

## 简介

本指南演示了使用 Docker Hub `postgres` 映像配置服务容器的工作流示例。 工作流程运行一个脚本，以连接到 PostgreSQL 服务，创建一个表，然后用数据填充该表。 为了测试工作流程是否创建并填充 PostgreSQL 表，脚本会将表中的数据打印到控制台。

> \[!NOTE]
> 如果工作流使用 Docker 容器操作、作业容器或服务容器，则必须使用 Linux 运行器：
>
> * 如果您要使用 GitHub 托管的运行器，则必须使用 Ubuntu 运行器。
> * 如果您要使用自托管运行器，则必须使用 Linux 机器作为运行器，并且必须安装 Docker。

## 先决条件

您应该熟悉服务容器如何与 GitHub Actions 协同作用，以及直接在运行器上或在容器中运行任务之间的网络差异。 有关详细信息，请参阅“[与 Docker 服务容器通信](/zh/actions/using-containerized-services/about-service-containers)”。

了解 YAML、GitHub Actions 的语法及 PostgreSQL 的基本知识会很有帮助。 有关详细信息，请参阅：

* [撰写工作流程](/zh/actions/learn-github-actions)
* PostgreSQL 文档中的“[PostgreSQL 教程](https://www.postgresqltutorial.com/)”

## 在容器中运行作业

配置要在容器中运行的作业可简化作业与服务容器之间的网络配置。 同一用户定义的桥接网络上的 Docker 容器互相显示所有端口，因此您无需将任何服务容器端口映射到 Docker 主机。 您可以使用工作流程中配置的标签从作业容器访问服务容器。

你可以将此工作流文件复制到存储库的 `.github/workflows` 目录并根据需要进行修改。

```yaml copy
name: PostgreSQL service example
on: push

jobs:
  # Label of the container job
  container-job:
    # Containers must run in Linux based operating systems
    runs-on: ubuntu-latest
    # Docker Hub image that `container-job` executes in
    container: node:20-bookworm-slim

    # Service containers to run with `container-job`
    services:
      # Label used to access the service container
      postgres:
        # Docker Hub image
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      # Downloads a copy of the code in your repository before running CI tests
      - name: Check out repository code
        uses: actions/checkout@v5

      # Performs a clean installation of all dependencies in the `package.json` file
      # For more information, see https://docs.npmjs.com/cli/ci.html
      - name: Install dependencies
        run: npm ci

      - name: Connect to PostgreSQL
        # Runs a script that creates a PostgreSQL table, populates
        # the table with data, and then retrieves the data.
        run: node client.js
        # Environment variables used by the `client.js` script to create a new PostgreSQL table.
        env:
          # The hostname used to communicate with the PostgreSQL service container
          POSTGRES_HOST: postgres
          # The default PostgreSQL port
          POSTGRES_PORT: 5432
```

### 为容器中的作业配置运行器作业

此工作流配置在 `node:20-bookworm-slim` 容器中运行的作业，并使用 `ubuntu-latest`  GitHub 托管的 运行器作为容器的 Docker 主机。 有关 `node:20-bookworm-slim` 容器的详细信息，请参阅 Docker Hub 上的此[节点映像](https://hub.docker.com/_/node)。

工作流用 `postgres` 标签配置服务容器。 所有服务必须在容器中运行，因此每项服务都需要指定容器 `image`。 此示例使用 `postgres` 容器映像，提供默认的 PostgreSQL 密码，并包括状态检查选项以确保服务正在运行。 有关详细信息，请参阅 Docker Hub 上的 [postgres 映像](https://hub.docker.com/_/postgres)。

```yaml copy
jobs:
  # Label of the container job
  container-job:
    # Containers must run in Linux based operating systems
    runs-on: ubuntu-latest
    # Docker Hub image that `container-job` executes in
    container: node:20-bookworm-slim

    # Service containers to run with `container-job`
    services:
      # Label used to access the service container
      postgres:
        # Docker Hub image
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
```

### 为容器中的作业配置步骤

工作流程执行以下步骤：

1. 检出运行器上的仓库
2. 安装依赖项
3. 运行脚本来创建客户端

```yaml copy
steps:
  # Downloads a copy of the code in your repository before running CI tests
  - name: Check out repository code
    uses: actions/checkout@v5

  # Performs a clean installation of all dependencies in the `package.json` file
  # For more information, see https://docs.npmjs.com/cli/ci.html
  - name: Install dependencies
    run: npm ci

  - name: Connect to PostgreSQL
    # Runs a script that creates a PostgreSQL table, populates
    # the table with data, and then retrieves the data.
    run: node client.js
    # Environment variable used by the `client.js` script to create
    # a new PostgreSQL client.
    env:
      # The hostname used to communicate with the PostgreSQL service container
      POSTGRES_HOST: postgres
      # The default PostgreSQL port
      POSTGRES_PORT: 5432
```

client.js 脚本查找 `POSTGRES_HOST` 和 `POSTGRES_PORT` 环境变量以创建客户端。 工作流将这两个环境变量设置为“连接到 PostgreSQL”步骤的一部分，以使它们可供 client.js 脚本使用。 有关脚本的详细信息，请参阅[测试 PostgreSQL 服务容器](#testing-the-postgresql-service-container)。

PostgreSQL 服务的主机名是你在工作流中配置的标签，在本例中，主机名为 `postgres`。 由于同一用户定义的网桥网络上的 Docker 容器默认打开所有端口，因此您将能够访问默认 PostgreSQL 端口 5432 上的服务容器。

## 直接在运行器机器上运行作业

直接在运行器机器上运行作业时，需要将服务容器上的端口映射到 Docker 主机上的端口。 可以使用 `localhost` 和 Docker 主机端口号从 Docker 主机访问服务容器。

你可以将此工作流文件复制到存储库的 `.github/workflows` 目录并根据需要进行修改。

```yaml copy
name: PostgreSQL Service Example
on: push

jobs:
  # Label of the runner job
  runner-job:
    # You must use a Linux environment when using service containers or container jobs
    runs-on: ubuntu-latest

    # Service containers to run with `runner-job`
    services:
      # Label used to access the service container
      postgres:
        # Docker Hub image
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          # Maps tcp port 5432 on service container to the host
          - 5432:5432

    steps:
      # Downloads a copy of the code in your repository before running CI tests
      - name: Check out repository code
        uses: actions/checkout@v5

      # Performs a clean installation of all dependencies in the `package.json` file
      # For more information, see https://docs.npmjs.com/cli/ci.html
      - name: Install dependencies
        run: npm ci

      - name: Connect to PostgreSQL
        # Runs a script that creates a PostgreSQL table, populates
        # the table with data, and then retrieves the data
        run: node client.js
        # Environment variables used by the `client.js` script to create
        # a new PostgreSQL table.
        env:
          # The hostname used to communicate with the PostgreSQL service container
          POSTGRES_HOST: localhost
          # The default PostgreSQL port
          POSTGRES_PORT: 5432
```

### 为直接在运行器机器上运行的作业配置运行器作业

示例使用 `ubuntu-latest`  GitHub 托管的 运行器作为 Docker 主机。

工作流用 `postgres` 标签配置服务容器。 所有服务必须在容器中运行，因此每项服务都需要指定容器 `image`。 此示例使用 `postgres` 容器映像，提供默认的 PostgreSQL 密码，并包括状态检查选项以确保服务正在运行。 有关详细信息，请参阅 Docker Hub 上的 [postgres 映像](https://hub.docker.com/_/postgres)。

工作流程将 PostgreSQL 服务容器上的端口 5432 映射到 Docker 主机。 有关 `ports` 关键字的详细信息，请参阅 [与 Docker 服务容器通信](/zh/actions/using-containerized-services/about-service-containers#mapping-docker-host-and-service-container-ports)。

```yaml copy
jobs:
  # Label of the runner job
  runner-job:
    # You must use a Linux environment when using service containers or container jobs
    runs-on: ubuntu-latest

    # Service containers to run with `runner-job`
    services:
      # Label used to access the service container
      postgres:
        # Docker Hub image
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          # Maps tcp port 5432 on service container to the host
          - 5432:5432
```

### 为直接在运行器机器上运行的作业配置步骤

工作流程执行以下步骤：

1. 检出运行器上的仓库
2. 安装依赖项
3. 运行脚本来创建客户端

```yaml copy
steps:
  # Downloads a copy of the code in your repository before running CI tests
  - name: Check out repository code
    uses: actions/checkout@v5

  # Performs a clean installation of all dependencies in the `package.json` file
  # For more information, see https://docs.npmjs.com/cli/ci.html
  - name: Install dependencies
    run: npm ci

  - name: Connect to PostgreSQL
    # Runs a script that creates a PostgreSQL table, populates
    # the table with data, and then retrieves the data
    run: node client.js
    # Environment variables used by the `client.js` script to create
    # a new PostgreSQL table.
    env:
      # The hostname used to communicate with the PostgreSQL service container
      POSTGRES_HOST: localhost
      # The default PostgreSQL port
      POSTGRES_PORT: 5432
```

client.js 脚本查找 `POSTGRES_HOST` 和 `POSTGRES_PORT` 环境变量以创建客户端。 工作流将这两个环境变量设置为“连接到 PostgreSQL”步骤的一部分，以使它们可供 client.js 脚本使用。 有关脚本的详细信息，请参阅[测试 PostgreSQL 服务容器](#testing-the-postgresql-service-container)。

主机名为 `localhost` 或 `127.0.0.1`。

## 测试 PostgreSQL 服务容器

您可以使用以下脚本测试工作流程，该脚本将连接到 PostgreSQL 服务，并添加包含某些占位符数据的新表。 然后，脚本将存储在 PostgreSQL 表中的值打印到终端。 你的脚本可以使用任何你喜欢的语言，但此示例使用 Node.js 和 `pg` npm 模块。 有关详细信息，请参阅 [npm pg 模块](https://www.npmjs.com/package/pg)。

可以修改 client.js 以包含工作流所需的任何 PostgreSQL 操作。 在本例中，脚本连接到 PostgreSQL 服务，向 `postgres` 数据库添加一个表，插入一些占位符数据，然后检索数据。

使用以下代码将名为 client.js 的新文件添加到存储库。

```javascript copy
const { Client } = require('pg');

const pgclient = new Client({
    host: process.env.POSTGRES_HOST,
    port: process.env.POSTGRES_PORT,
    user: 'postgres',
    password: 'postgres',
    database: 'postgres'
});

pgclient.connect();

const table = 'CREATE TABLE student(id SERIAL PRIMARY KEY, firstName VARCHAR(40) NOT NULL, lastName VARCHAR(40) NOT NULL, age INT, address VARCHAR(80), email VARCHAR(40))'
const text = 'INSERT INTO student(firstname, lastname, age, address, email) VALUES($1, $2, $3, $4, $5) RETURNING *'
const values = ['Mona the', 'Octocat', 9, '88 Colin P Kelly Jr St, San Francisco, CA 94107, United States', 'octocat@github.com']

pgclient.query(table, (err, res) => {
    if (err) throw err
});

pgclient.query(text, values, (err, res) => {
    if (err) throw err
});

pgclient.query('SELECT * FROM student', (err, res) => {
    if (err) throw err
    console.log(err, res.rows) // Print the data in student table
    pgclient.end()
});
```

该脚本会创建与 PostgreSQL 服务的新连接，并使用 `POSTGRES_HOST` 和 `POSTGRES_PORT` 环境变量来指定 PostgreSQL 服务 IP 地址和端口。 如果未定义 `host` 和 `port`，则默认主机为 `localhost`，默认端口为 5432。

脚本创建一个表，并使用占位符数据填充它。 要测试 `postgres` 数据库是否包含数据，脚本会将表的内容打印到控制台日志。

运行此工作流程时，应会在“连接到 PostgreSQL”步骤中看到以下输出，确认您成功创建了 PostgreSQL 表并添加了数据：

```text
null [ { id: 1,
    firstname: 'Mona the',
    lastname: 'Octocat',
    age: 9,
    address:
     '88 Colin P Kelly Jr St, San Francisco, CA 94107, United States',
    email: 'octocat@github.com' } ]
```