I am new to docker, and have written a containerized django app, and react app. When I go to run docker-compose up
I get a weird, perpetuating error that django has no port(s) to connect to. Running the server from the react and python side both work.
Error message
Frontend dockerfile:
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 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.10-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
WORKDIR /usr/src/app
My 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 Config
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;
}
}
I can't find anything related to this, and I also am new to Docker.
Docker also finds ports you expose with --expose 8080 (assuming you want to expose port 8080). Docker maps all of these ports to a host port within a given epehmeral port range . You can find the configuration for these ports (usually 32768 to 61000) in /proc/sys/net/ipv4/ip_local_port_range .
This property defines the ports that Docker Compose exposes from the container. These ports will be accessible by other services connected to the same network but won't be published on the host machine.
8080:80 refers that in the container you are using port 80 and you are forwarding that port to host machine's 8080 port. So you are running Jenkins on port 80 inside your container wherever in scenario 2 you are running Jenkins on port 8080 inside the container and exposing it over the same port on host machine.
This is a netcat error. Specifically, it occurs when you provide a hostname but not a port while running nc
.
Example:
# nc -z 8.8.8.8
no port[s] to connect to
Then, your entrypoint script sees that netcat exited with an error, and re-runs it until it succeeds, which it never will.
I suspected that this was a netcat problem because the entrypoint script prints "Waiting for postgres..." but not "PostgreSQL started." However, I couldn't get netcat to produce the "no port" error.
So I ran a copy of the base image, and manually installed netcat.
docker run -it python:3.7.9-slim-stretch bash
# in container
apt-get update
apt-get install netcat
I still couldn't get netcat to produce the error. So I downloaded the source code of netcat:
# still in container
apt-get source netcat
Then, armed with a copy of the source code of netcat, I found this code:
if (argv[optind] == NULL)
bail ("no port[s] to connect to");
Translation: If the argument parsing code, which has just finished parsing the host value, runs out of arguments, then emit the "no port[s] to connect to" error.
We can check this by running nc inside the container:
root@cc139fd40237:/source/netcat-1.10# nc -z localhost
no port[s] to connect to
Interestingly, Ubuntu has a different version of netcat, with a different error message.
$ nc -z localhost
nc: missing port number
...so that was why I couldn't reproduce the netcat error outside the container!
In this line, either DB_HOST or DB_PORT is unset:
while ! nc -z $DB_HOST $DB_PORT; do
Besides just fixing the problem, this is a good opportunity to make your script more robust. If you add set -u
to the top of your shell script, you would've gotten a vastly more helpful error message instead:
Waiting for postgres...
entrypoint.sh: 7: DB_PORT: parameter not set
You can also use the shellcheck tool - on your script, it recommends that you quote arguments:
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
which is also an excellent idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With