在Github Actions中运行集成测试: 连接Postgres存在问题。

4

我有一些整合测试,为了能够成功运行,需要通过docker-compose配置启动一个运行中的Postgres数据库,并且我的Go应用程序从main.go 运行。以下是我的docker-compose文件:

version: "3.9"
services:

  postgres:
    image: postgres:12.5
    user: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: my-db
    ports:
      - "5432:5432"
    volumes:
      - data:/var/lib/postgresql/data
      - ./initdb:/docker-entrypoint-initdb.d
networks:
  default:
    driver: bridge

volumes:
  data:
    driver: local

我的Github Actions如下:

jobs:
  unit:
    name: Test
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:12.5
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: password
          POSTGRES_DB: my-db
        ports:
          - 5432:5432
    env:
      GOMODCACHE: "${{ github.workspace }}/.go/mod/cache"
      TEST_RACE: true 
   steps:
     - name: Initiate Database
       run: psql -f initdb/init.sql postgresql://postgres:password@localhost:5432/my-db

     - name: Set up Cloud SDK
       uses: google-github-actions/setup-gcloud@v0

     - name: Authenticate with GCP
       id: auth
       uses: "google-github-actions/auth@v0"
       with: credentials_json: ${{ secrets.GCP_ACTIONS_SECRET }}

     - name: Configure Docker
       run: |
         gcloud auth configure-docker "europe- docker.pkg.dev,gcr.io,eu.gcr.io"

     - name: Set up Docker BuildX
       uses: docker/setup-buildx-action@v1

     - name: Start App
       run: |
         VERSION=latest make images
         docker run -d -p 3000:3000 -e      POSTGRES_DB_URL='//postgres:password@localhost:5432/my-db?sslmode=disable' --name='app' image/app

     - name: Tests
       env:
        POSTGRES_DB_URL: //postgres:password@localhost:5432/my-db?sslmode=disable
      GOMODCACHE: ${{ github.workspace }}/.go/pkg/mod
       run: | 
         make test-integration
         docker stop app

在本地使用 docker-compose up命令并从main.go运行应用程序时,我的测试可以正常运行。然而,在Github actions中我遇到了以下错误:

failed to connect to `host=/tmp user=nonroot database=`: dial error (dial unix /tmp/.s.PGSQL.5432: connect: no such file or directory

我缺少什么?谢谢


不太确定这与问题有任何关系:https://github.com/jackc/pgx/issues/596 - panza
请查看以下网址以了解有关 Postgres 连接问题的信息:https://dev59.com/deo6XIcBkEYKwwoYOR4q - kozmo
谢谢,这更具体地针对brew,并没有提到Github actions。我试了很多个,并应用了-h localhost,但是缺少Github actions部分,我没有找到解决方案。 - panza
如果你的应用程序在 GitHub 上运行在 Docker 容器中,那么 'localhost' 是容器内部的本地地址。但是 psql 并不在容器内运行。你可以将 psql 作为一个 Docker 容器来运行,并让这两个容器使用相同的 Docker 网络。现在你应该能够使用 psql 容器的名称作为 DB_URL 中的主机名了。 - Eelco
嘿 @panza,你能否请看一下我的答案?我已经添加了你可能需要解决问题的所有内容。 - mrkachariker
显示剩余2条评论
2个回答

4
你所缺少的是在Github Actions服务器中设置实际的Postgres客户端(这就是为什么找不到psql工具)。
将其设置为一个步骤。
请参考此链接进行操作。
     - name: Install PostgreSQL client
        run: |
          apt-get update
          apt-get install --yes postgresql-client

除此之外,如果你通过docker-compose来运行所有内容,你需要等待postgres启动并运行(健康且接受连接)。

请考虑以下docker-compose:

version: '3.1'

services:
  api:
    build: .
    depends_on:
      - db
    ports:
      - 8080:8080
    environment:
      - RUN_UP_MIGRATION=true
      - PSQL_CONN_STRING=postgres://gotstock_user:123@host.docker.internal:5432/gotstockapi?sslmode=disable
    command: ./entry
    
  db:
    image: postgres:9.5-alpine
    restart: always
    environment:
      - POSTGRES_USER=root
      - POSTGRES_PASSWORD=password
    ports:
      - "5432:5432"
    volumes:
      - ./db:/docker-entrypoint-initdb.d/

有几件事情需要注意。首先,在apienvironment部分,我们将PSQL_CONN_STRING=postgres://gotstock_user:123@host.docker.internal:5432/gotstockapi?sslmode=disable作为环境变量传递到数据库的连接字符串。请注意主机名是host.docker.internal

除此之外,在api部分我们还有command: ./entry。在entry文件中包含以下#!/bin/ash脚本:

#!/bin/ash
NOT_READY=1
while [ $NOT_READY -gt 0 ] # <- loop that waits till postgres is ready to accept connections
do 
    pg_isready --dbname=gotstockapi --host=host.docker.internal --port=5432 --username=gotstock_user
    NOT_READY=$?
    sleep 1
done;
./gotstock-api # <- actually executes the build of the api
sleep 10
go test -v ./it # <- executes the integration-tests

最后,为了让psql客户端在上面的脚本中工作,API的docker文件如下所示:


# syntax=docker/dockerfile:1

FROM golang:1.19-alpine3.15

RUN apk add build-base

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .

RUN apk add postgresql-client

RUN go build -o gotstock-api

EXPOSE 8080

注意 RUN apk add postgresql-client 这一行代码,它安装了客户端。

祝你愉快!=)


这样不行,因为应用程序在 Docker 中运行,它仍然无法访问数据库。 - Dennis van de Hoef - Xiotin
他所做的第一步是:步骤: - 名称:初始化数据库 运行:psql -f initdb/init.sql postgresql://postgres:password@localhost:5432/my-db 。因此,我认为他可能需要安装客户端才能使其工作(如果确实存在该问题,因为从问题中并不十分清楚)。 - mrkachariker

4

我认为这段代码存在不止一个问题。

问题一: 在你的代码中,我没有看到你运行docker-compose up,因此我会假设Postgres没有运行。

问题二: 在这行代码中:docker run -d -p 3000:3000 -e POSTGRES_DB_URL='//postgres:password@localhost:5432/my-app?sslmode=disable' --name='app' image/app

你将Postgres的主机指向了localhost,在你的本地机器上这个是有效的。但是,由于你使用docker run,你没有在本地机器上运行它,而是在Docker容器中运行它。在容器内部,localhost指向的是容器内部。

两个问题的可能解决方案

由于你已经在使用docker-compose,我建议你也将测试Web服务器添加到其中。

将你的docker-compose文件更改为:

version: "3.9"
services:

  webapp:
    build: image/app
    environment:
      POSTGRES_DB_URL='//postgres:password@postgres:5432/my-app?sslmode=disable'
    ports:
      - "3000:3000"
    depends_on:
      - "postgres"

  postgres:
    image: postgres:12.5
    user: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: my-app
    ports:
      - "5432:5432"
    volumes:
      - data:/var/lib/postgresql/data
      - ./initdb:/docker-entrypoint-initdb.d
networks:
  default:
    driver: bridge

volumes:
  data:
    driver: local

如果您现在运行docker-compose up,两个服务将可用。它应该可以工作。虽然我不是一个github-actions专家,所以可能会错过一些东西。至少这样,您可以以与CI相同的方式本地运行测试,这是我始终认为的一个大优点。

谢谢,我已经将服务添加到那里,并更新了命名。我确实在services部分启动了Postgres。 - panza
我能够使用docker-compose在本地启动我的数据库并创建模式,然后独立运行Web应用程序。在Github actions中,应用程序正确启动,同时也启动了Postgres并创建了所有表格。问题出在连接它上面。 - panza
你现在是如何连接它的?因为 Docker 运行命令由于已解释的原因无法工作。 - Dennis van de Hoef - Xiotin
我正在我的测试中创建一个新的连接和存储库,指向与我的Github操作中使用的相同数据库字符串。您的解决方案将如何工作?我可以在本地看到,因为我的docker-compose up将同时启动服务和数据库,但是我如何在我的Github操作中利用它?我的services部分是否只需具有docker-compose文件的新版本?谢谢。 - panza
你的问题在于,只要使用docker run,数据库字符串就无法工作。因为你处于一个隔离的容器中,而localhost在容器内部。通过我的建议解决方案,你可以使用docker compose,在连接字符串中使用compose网络中容器的名称,而不是localhost。 - Dennis van de Hoef - Xiotin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接