在Github actions中运行集成测试时遇到了与PostgreSQL连接的问题。

huangapple go评论124阅读模式
英文:

Running integration tests in Github actions: issues with connecting with postgres

问题

我有一些集成测试,为了成功运行,需要一个正在运行的postgres数据库,通过docker-compose进行设置,并且我的go应用程序从main.go运行。这是我的docker-compose文件:

  1. version: "3.9"
  2. services:
  3. postgres:
  4. image: postgres:12.5
  5. user: postgres
  6. environment:
  7. POSTGRES_USER: postgres
  8. POSTGRES_PASSWORD: password
  9. POSTGRES_DB: my-db
  10. ports:
  11. - "5432:5432"
  12. volumes:
  13. - data:/var/lib/postgresql/data
  14. - ./initdb:/docker-entrypoint-initdb.d
  15. networks:
  16. default:
  17. driver: bridge
  18. volumes:
  19. data:
  20. driver: local

我的Github Actions配置如下:

  1. jobs:
  2. unit:
  3. name: Test
  4. runs-on: ubuntu-latest
  5. services:
  6. postgres:
  7. image: postgres:12.5
  8. env:
  9. POSTGRES_USER: postgres
  10. POSTGRES_PASSWORD: password
  11. POSTGRES_DB: my-db
  12. ports:
  13. - 5432:5432
  14. env:
  15. GOMODCACHE: "${{ github.workspace }}/.go/mod/cache"
  16. TEST_RACE: true
  17. steps:
  18. - name: Initiate Database
  19. run: psql -f initdb/init.sql postgresql://postgres:password@localhost:5432/my-db
  20. - name: Set up Cloud SDK
  21. uses: google-github-actions/setup-gcloud@v0
  22. - name: Authenticate with GCP
  23. id: auth
  24. uses: "google-github-actions/auth@v0"
  25. with:
  26. credentials_json: ${{ secrets.GCP_ACTIONS_SECRET }}
  27. - name: Configure Docker
  28. run: |
  29. gcloud auth configure-docker "europe-docker.pkg.dev,gcr.io,eu.gcr.io"
  30. - name: Set up Docker BuildX
  31. uses: docker/setup-buildx-action@v1
  32. - name: Start App
  33. run: |
  34. VERSION=latest make images
  35. docker run -d -p 3000:3000 -e POSTGRES_DB_URL='//postgres:password@localhost:5432/my-db?sslmode=disable' --name='app' image/app
  36. - name: Tests
  37. env:
  38. POSTGRES_DB_URL: //postgres:password@localhost:5432/my-db?sslmode=disable
  39. GOMODCACHE: ${{ github.workspace }}/.go/pkg/mod
  40. run: |
  41. make test-integration
  42. docker stop app

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

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

我漏掉了什么?谢谢。

英文:

I have some integration tests that, in order to succesfully run, require a running postgres database, setup via docker-compose, and my go app running from main.go. Here is my docker-compose:

  1. version: "3.9"
  2. services:
  3. postgres:
  4. image: postgres:12.5
  5. user: postgres
  6. environment:
  7. POSTGRES_USER: postgres
  8. POSTGRES_PASSWORD: password
  9. POSTGRES_DB: my-db
  10. ports:
  11. - "5432:5432"
  12. volumes:
  13. - data:/var/lib/postgresql/data
  14. - ./initdb:/docker-entrypoint-initdb.d
  15. networks:
  16. default:
  17. driver: bridge
  18. volumes:
  19. data:
  20. driver: local

and my Github Actions are as follows:

  1. jobs:
  2. unit:
  3. name: Test
  4. runs-on: ubuntu-latest
  5. services:
  6. postgres:
  7. image: postgres:12.5
  8. env:
  9. POSTGRES_USER: postgres
  10. POSTGRES_PASSWORD: password
  11. POSTGRES_DB: my-db
  12. ports:
  13. - 5432:5432
  14. env:
  15. GOMODCACHE: "${{ github.workspace }}/.go/mod/cache"
  16. TEST_RACE: true
  17. steps:
  18. - name: Initiate Database
  19. run: psql -f initdb/init.sql postgresql://postgres:password@localhost:5432/my-db
  20. - name: Set up Cloud SDK
  21. uses: google-github-actions/setup-gcloud@v0
  22. - name: Authenticate with GCP
  23. id: auth
  24. uses: "google-github-actions/auth@v0"
  25. with: credentials_json: ${{ secrets.GCP_ACTIONS_SECRET }}
  26. - name: Configure Docker
  27. run: |
  28. gcloud auth configure-docker "europe- docker.pkg.dev,gcr.io,eu.gcr.io"
  29. - name: Set up Docker BuildX
  30. uses: docker/setup-buildx-action@v1
  31. - name: Start App
  32. run: |
  33. VERSION=latest make images
  34. docker run -d -p 3000:3000 -e POSTGRES_DB_URL='//postgres:password@localhost:5432/my-db?sslmode=disable' --name='app' image/app
  35. - name: Tests
  36. env:
  37. POSTGRES_DB_URL: //postgres:password@localhost:5432/my-db?sslmode=disable
  38. GOMODCACHE: ${{ github.workspace }}/.go/pkg/mod
  39. run: |
  40. make test-integration
  41. docker stop app

My tests run just fine locally firing off the docker-compose with docker-compose up and running the app from main.go. However, in Github actions I am getting the following error:

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

What am I missing? Thanks

答案1

得分: 4

你所缺少的是在 Github Actions 服务器上设置实际的 Postgres 客户端(这就是为什么找不到 psql 工具)。

按照以下步骤进行设置(参考链接:https://remarkablemark.org/blog/2021/03/14/setup-postgresql-in-github-actions/):

  1. - name: 安装 PostgreSQL 客户端
  2. run: |
  3. apt-get update
  4. apt-get install --yes postgresql-client

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

考虑以下 docker-compose 配置:

  1. version: '3.1'
  2. services:
  3. api:
  4. build: .
  5. depends_on:
  6. - db
  7. ports:
  8. - 8080:8080
  9. environment:
  10. - RUN_UP_MIGRATION=true
  11. - PSQL_CONN_STRING=postgres://gotstock_user:123@host.docker.internal:5432/gotstockapi?sslmode=disable
  12. command: ./entry
  13. db:
  14. image: postgres:9.5-alpine
  15. restart: always
  16. environment:
  17. - POSTGRES_USER=root
  18. - POSTGRES_PASSWORD=password
  19. ports:
  20. - "5432:5432"
  21. volumes:
  22. - ./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: ./entryentry 文件包含以下 #!/bin/ash 脚本:

  1. #!/bin/ash
  2. NOT_READY=1
  3. while [ $NOT_READY -gt 0 ] # <- 循环等待直到 Postgres 准备好接受连接
  4. do
  5. pg_isready --dbname=gotstockapi --host=host.docker.internal --port=5432 --username=gotstock_user
  6. NOT_READY=$?
  7. sleep 1
  8. done;
  9. ./gotstock-api # <- 实际执行构建 api
  10. sleep 10
  11. go test -v ./it # <- 执行集成测试

最后,为了使上述脚本中的 psql 客户端正常工作,api 的 Dockerfile 如下所示:

  1. # syntax=docker/dockerfile:1
  2. FROM golang:1.19-alpine3.15
  3. RUN apk add build-base
  4. WORKDIR /app
  5. COPY go.mod go.sum ./
  6. RUN go mod download && go mod verify
  7. COPY . .
  8. RUN apk add postgresql-client
  9. RUN go build -o gotstock-api
  10. EXPOSE 8080

注意 RUN apk add postgresql-client,它安装了客户端。

祝你愉快编码!=)

英文:

What you are missing is setting up the actual Postgres Client inside the Github Actions server (that is why there is no psql tool to be found).

Set it up as a step.

  1. - name: Install PostgreSQL client
  2. run: |
  3. apt-get update
  4. apt-get install --yes postgresql-client

Apart from that, if you run everything through docker-compose you will need to wait for postgres to be up and running (healthy & accepting connections).

Consider the following docker-compose:

  1. version: &#39;3.1&#39;
  2. services:
  3. api:
  4. build: .
  5. depends_on:
  6. - db
  7. ports:
  8. - 8080:8080
  9. environment:
  10. - RUN_UP_MIGRATION=true
  11. - PSQL_CONN_STRING=postgres://gotstock_user:123@host.docker.internal:5432/gotstockapi?sslmode=disable
  12. command: ./entry
  13. db:
  14. image: postgres:9.5-alpine
  15. restart: always
  16. environment:
  17. - POSTGRES_USER=root
  18. - POSTGRES_PASSWORD=password
  19. ports:
  20. - &quot;5432:5432&quot;
  21. volumes:
  22. - ./db:/docker-entrypoint-initdb.d/

There are a couple of things you need to notice. First of all, in the environment section of the api we have PSQL_CONN_STRING=postgres://gotstock_user:123@host.docker.internal:5432/gotstockapi?sslmode=disable which is the connection string to the db being passed as an env variable. Notice the host is host.docker.internal.

Besides that we have command: ./entry in the api section. The entry file contains the following #!/bin/ash script:

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

And finally, in order for the psql client to work in the above script, the docker file of the api is looking like this:

  1. # syntax=docker/dockerfile:1
  2. FROM golang:1.19-alpine3.15
  3. RUN apk add build-base
  4. WORKDIR /app
  5. COPY go.mod go.sum ./
  6. RUN go mod download &amp;&amp; go mod verify
  7. COPY . .
  8. RUN apk add postgresql-client
  9. RUN go build -o gotstock-api
  10. EXPOSE 8080

Notice RUN apk add postgresql-client which installs the client.

Happy hacking! =)

答案2

得分: 3

我认为这段代码有多个问题。

问题一:
在你的代码中,我没有看到你运行 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 文件更改为:

  1. version: "3.9"
  2. services:
  3. webapp:
  4. build: image/app
  5. environment:
  6. POSTGRES_DB_URL='//postgres:password@postgres:5432/my-app?sslmode=disable'
  7. ports:
  8. - "3000:3000"
  9. depends_on:
  10. - "postgres"
  11. postgres:
  12. image: postgres:12.5
  13. user: postgres
  14. environment:
  15. POSTGRES_USER: postgres
  16. POSTGRES_PASSWORD: password
  17. POSTGRES_DB: my-app
  18. ports:
  19. - "5432:5432"
  20. volumes:
  21. - data:/var/lib/postgresql/data
  22. - ./initdb:/docker-entrypoint-initdb.d
  23. networks:
  24. default:
  25. driver: bridge
  26. volumes:
  27. data:
  28. driver: local

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

英文:

I think this code has more than one problem.

Problem one:
In your code I don't see you run docker-compose up, therefore I would assume that Postgres is not running.

Problem two:
is in this line: docker run -d -p 3000:3000 -e POSTGRES_DB_URL=&#39;//postgres:password@localhost:5432/my-app?sslmode=disable&#39; --name=&#39;app&#39; image/app

You point the host of Postgres to localhost, which on your local machine works. As there localhost is your local comuter. Though, as you use docker run you are not running this on your local machine, but in a docker container. There localhost is pointing to inside the conmtainer.

Posible solution for both

As you are already using docker-compose I suggest you to also add your test web server there.

Change your docker-compose file to:

  1. version: &quot;3.9&quot;
  2. services:
  3. webapp:
  4. build: image/app
  5. environment:
  6. POSTGRES_DB_URL=&#39;//postgres:password@postgres:5432/my-app?sslmode=disable&#39;
  7. ports:
  8. - &quot;3000:3000&quot;
  9. depends_on:
  10. - &quot;postgres&quot;
  11. postgres:
  12. image: postgres:12.5
  13. user: postgres
  14. environment:
  15. POSTGRES_USER: postgres
  16. POSTGRES_PASSWORD: password
  17. POSTGRES_DB: my-app
  18. ports:
  19. - &quot;5432:5432&quot;
  20. volumes:
  21. - data:/var/lib/postgresql/data
  22. - ./initdb:/docker-entrypoint-initdb.d
  23. networks:
  24. default:
  25. driver: bridge
  26. volumes:
  27. data:
  28. driver: local

If you now run docker-compose up, both services will be available. And it should work. Though I am not a github-actions expert, so I might have missed something. At least like this, you can run your tests locally the same way as in CI, something that I always see as a big plus.

huangapple
  • 本文由 发表于 2022年11月1日 05:45:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/74269416.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定