django - 'django_1 | 运行 docker-compose up 后没有要连接的端口 [s]
问题描述
我是 docker 新手,已经编写了一个容器化的 django 应用程序和 react 应用程序。当我去跑步时,docker-compose up
我得到一个奇怪的、持续存在的错误,即 django 没有要连接的端口。从 react 和 python 端运行服务器都可以。
错误信息
COPY ./react_app/package.json .
RUN apk add --no-cache --virtual .gyp \
python \
make \
g++ \
&& npm install \
&& apk del .gyp
COPY ./react_app .
ARG API_SERVER
ENV REACT_APP_API_SERVER=${API_SERVER}
RUN REACT_APP_API_SERVER=${API_SERVER} \
npm run build
WORKDIR /usr/src/app
RUN npm install -g serve
COPY --from=builder /usr/src/app/build ./build
Django Python backend Dockerfile
WORKDIR /usr/src/app
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
FROM python:3.7.9-slim-stretch
RUN apt-get update && apt-get install -y --no-install-recommends netcat && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install --no-cache /wheels/*
WORKDIR /usr/src/app
COPY ./entrypoint.sh /usr/src/app/entrypoint.sh
COPY ./django_app .
RUN chmod +x /usr/src/app/entrypoint.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
and the nginx dockerfile
FROM nginx:1.19.0-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
WORKDIR /usr/src/app
Django Python 后端 Dockerfile
WORKDIR /usr/src/app
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
FROM python:3.7.9-slim-stretch
RUN apt-get update && apt-get install -y --no-install-recommends netcat && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install --no-cache /wheels/*
WORKDIR /usr/src/app
COPY ./entrypoint.sh /usr/src/app/entrypoint.sh
COPY ./django_app .
RUN chmod +x /usr/src/app/entrypoint.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
和 nginx dockerfile
FROM nginx:1.19.10-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
WORKDIR /usr/src/app
我的 entrypoint.sh
#!/bin/sh
if [ "$DATABASE" = "postgres" ]
then
echo "Waiting for postgres..."
while ! nc -z $DB_HOST $DB_PORT; do
sleep 0.1
done
echo "PostgreSQL started"
fi
python manage.py collectstatic --noinput
python manage.py migrate --noinput
echo "from django.contrib.auth.models import User;
User.objects.filter(email='$DJANGO_ADMIN_EMAIL').delete();
User.objects.create_superuser('$DJANGO_ADMIN_USER', '$DJANGO_ADMIN_EMAIL', '$DJANGO_ADMIN_PASSWORD')" | python manage.py shell
exec "$@"
Docker-compose.yml
version: "3.7"
services:
django:
build:
context: ./backend
dockerfile: Dockerfile
volumes:
- django_static_volume:/usr/src/app/static
expose:
- 8000
env_file:
- ./backend/.env
command: gunicorn candle.wsgi:application --bind 0.0.0.0:8000
depends_on:
- db
db:
image: postgres:12.0-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- ./postgres/.env
react:
build:
context: ./frontend
dockerfile: Dockerfile
args:
- API_SERVER=${ENV_API_SERVER}
volumes:
- react_static_volume:/usr/src/app/build/static
expose:
- 3000
env_file:
- .env
command: serve -s build -l 3000
depends_on:
- django
nginx:
restart: always
build: ./nginx
volumes:
- django_static_volume:/usr/src/app/django_files/static
- react_static_volume:/usr/src/app/react_files/static
ports:
- 80:80
depends_on:
- react
volumes:
postgres_data:
django_static_volume:
react_static_volume:
Nginx 配置
upstream django_backend {
server django:8000;
}
upstream react_frontend {
server react:3000;
}
server {
listen 80;
###########
# URL ROUTING #
###########
location /admin {
proxy_pass http://django_backend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /api {
proxy_pass http://django_backend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
###########
# STATIC FOLDER ROUTING #
###########
location /static/admin/ {
alias /usr/src/app/django_files/static/admin/;
}
location /static/rest_framework/ {
alias /usr/src/app/django_files/static/rest_framework/;
}
location /static/ {
alias /usr/src/app/react_files/static/;
}
location /media/ {
alias /usr/src/app/media/;
}
###########
# URL ROUTING #
###########
location / {
proxy_pass http://react_frontend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
我找不到与此相关的任何内容,而且我也是 Docker 的新手。
解决方案
这是一个 netcat 错误。具体来说,当您在运行时提供主机名而不是端口时会发生这种情况nc
。
例子:
# nc -z 8.8.8.8
no port[s] to connect to
然后,您的入口点脚本看到 netcat 因错误退出,并重新运行它直到它成功,它永远不会成功。
调试过程
我怀疑这是一个 netcat 问题,因为入口点脚本打印“Waiting for postgres ...”而不是“PostgreSQL 已启动”。但是,我无法让 netcat 产生“无端口”错误。
所以我运行了一个基本映像的副本,并手动安装了 netcat。
docker run -it python:3.7.9-slim-stretch bash
# in container
apt-get update
apt-get install netcat
我仍然无法让 netcat 产生错误。于是我下载了netcat的源码:
# still in container
apt-get source netcat
然后,带着一份netcat 的源代码,我找到了这段代码:
if (argv[optind] == NULL)
bail ("no port[s] to connect to");
翻译:如果刚刚完成主机值解析的参数解析代码用完了参数,则发出“no port[s] to connect to”错误。
我们可以通过在容器中运行 nc 来检查这一点:
root@cc139fd40237:/source/netcat-1.10# nc -z localhost
no port[s] to connect to
有趣的是,Ubuntu 有不同版本的 netcat,带有不同的错误消息。
$ nc -z localhost
nc: missing port number
...这就是为什么我无法在容器外重现 netcat 错误的原因!
强大的 shell 脚本
在这一行中,未设置 DB_HOST 或 DB_PORT:
while ! nc -z $DB_HOST $DB_PORT; do
除了解决问题之外,这是使您的脚本更健壮的好机会。如果你添加set -u
到你的 shell 脚本的顶部,你会得到一个非常有用的错误消息:
Waiting for postgres...
entrypoint.sh: 7: DB_PORT: parameter not set
您还可以使用shellcheck 工具- 在您的脚本中,它建议您引用参数:
In entrypoint.sh line 6:
while ! nc -z $DB_HOST $DB_PORT; do
^------^ SC2086: Double quote to prevent globbing and word splitting.
^------^ SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
while ! nc -z "$DB_HOST" "$DB_PORT"; do
这也是一个绝妙的主意。
推荐阅读
- c# - GraphQL HotChocolate 添加 PaginationAmountType 将我的 int 转换为 PaginationAmmount
- dynamics-crm - 在 Common Data Service 中跨多个 Dynamics 实体进行筛选
- c++ - cin 在我的提示符中忽略空格的问题
- newrelic - 我们可以在 Newrelic 中获得每个应用程序的应用程序正常运行时间吗
- r - 如何避免选择两个选项时(其中之一),以避免获得积极的积分?
- php - 如何隐藏在 ajax post 方法中调用的 php 文件?
- java - 我从包含“%20”和 Java Net URL 的 URL 字符串中收到 Http 400 错误
- scala - 从 spark 数据框中获取元素并将其传递给函数
- javascript - 如何使用 Javascript 将两个音频 .wav 文件合并/合并为一个文件
- python - 为什么 .tif 不是在 AdobeRGB 颜色配置文件中导出,但 .jpg 是