0

我目前正在尝试对我的 Django API 项目之一进行 dockerize。它使用 postgres 作为数据库。我使用 Docker Cloud 作为 CI,这样我就可以构建、lint 和运行测试。

我从以下 DockerFile 开始

# Start with a python 3.6 image
FROM python:3.6

ENV PYTHONUNBUFFERED 1
ENV POSTGRES_USER postgres 
ENV POSTGRES_PASSWORD xxx 
ENV DB_HOST db 

RUN mkdir /code

ADD . /code/

WORKDIR /code

RUN pip install -r requirements.txt

RUN pylint **/*.py

# First tried running tests from here.

RUN python3 src/manage.py test

但是这个 DockerFile 总是失败,因为 Django 在运行单元测试时无法连接到任何数据库,并且由于没有 postgres 实例在这个 Dockerfile 中运行,所以会失败并出现以下错误

django.db.utils.OperationalError: could not translate host name "db" 
to address: Name or service not known

然后我在 Docker Cloud 中发现了一个名为“Autotest”的东西,它允许您使用 docker-compose.text.yml 文件来描述堆栈,然后在每次构建时运行一些命令。这似乎是我运行测试所需要的,因为它允许我构建我的 Django 映像,引用一个已经存在的 postgres 映像并运行测试。

我删除了

 RUN python3 src/manage.py test

从 DockerFile 并创建以下 docker-compose.test.yml 文件。

 version: '3.2'

 services:
   db:
     image: postgres:9.6.3
     environment:
       - POSTGRES_USER=$POSTGRES_USER
       - POSTGRES_PASSWORD=$POSTGRES_PASSWORD

   sut:
     build: .
     command: python src/manage.py test
     environment:
       - POSTGRES_USER=$POSTGRES_USER
       - POSTGRES_PASSWORD=$POSTGRES_PASSWORD
       - DB_HOST=db
     depends_on:
       - db

然后当我跑

  docker-compose -f docker-compose.test.yml build

  docker-compose -f docker-compose.test.yml run sut

在本地,测试全部运行并全部通过。

然后我将我的更改推送到 Github 并由 Docker 云构建它。构建本身成功,但使用 docker-compose.test.yml 文件的自动测试失败,并出现以下错误:

  django.db.utils.OperationalError: could not connect to server: 
  Connection refused
  Is the server running on host "db" (172.18.0.2) and accepting
  TCP/IP connections on port 5432?

因此,与我的本地计算机相比,似乎 db 服务没有启动或者在 Docker Cloud 上启动太慢?

在谷歌搜索了一下之后,我发现了这个https://docs.docker.com/compose/startup-order/,它说容器并没有真正等待彼此 100% 准备好。然后他们建议编写一个包装脚本来等待 postgres 如果确实需要的话。

我按照他们的指示使用了 wait-for-postgres.sh 脚本。

多汁的部分:

  until psql -h "$host" -U "postgres" -c '\l'; do
    >&2 echo "Postgres is unavailable - sleeping"
    sleep 1
  done

并替换了我的 docker-compose.test.yml 中的命令

 command: python src/manage.py test

 command: ["./wait-for-postgres.sh", "db", "python", "src/manage.py", 
 "test"]

然后我推送到 Github,Docker Cloud 开始构建。构建映像工作,但现在自动测试只是永远等待 postgres(我等了 10 分钟,然后手动关闭了 Docker Cloud 中的构建过程)

我今天有相当多的 Google-d,似乎大多数“Dockerize Django”教程根本没有真正提到单元测试。

我使用 Docker 运行 Django 单元测试是否完全错误?

对我来说似乎很奇怪,它在本地运行得非常好,但是当 Docker Cloud 运行它时,它失败了!

4

1 回答 1

0

我似乎已经通过将文件中的 docker-compose 版本从 3.2 降级到 2.1 并使用 healthcheck 来修复它。

healthcheck 选项在depends_on 子句中给我一个语法错误,因为您必须将一个数组传递给它。不知道为什么 3.2 版不支持此功能

但这是我的新 docker-compose.test.yml

version: '2.1'

services:
  db:
    image: postgres:9.6.3
    environment:
      - POSTGRES_USER=$POSTGRES_USER
      - POSTGRES_PASSWORD=$POSTGRES_PASSWORD
    healthcheck:
      test: ["CMD-SHELL", "psql -h 'localhost' -U 'postgres' -c 
            '\\l'"]
      interval: 30s
      timeout: 30s
      retries: 3

 sut:
   build: .
   command: python3 src/manage.py test
   environment:
     - POSTGRES_USER=$POSTGRES_USER
     - POSTGRES_PASSWORD=$POSTGRES_PASSWORD
     - DB_HOST=db
   depends_on:
   // Does not work in 3.2
     db:
       condition: service_healthy
于 2017-06-25T14:32:09.247 回答