我目前正在尝试对我的 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 运行它时,它失败了!