Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'django_1 | no port[s] to connect to' after running docker-compose up

Tags:

docker

django

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

enter image description here 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.

like image 515
Andrew Bregman Avatar asked Aug 26 '21 23:08

Andrew Bregman


People also ask

Does Docker use port 8080?

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 .

What is ports in Docker compose?

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.

What is the significance of 80 8080 when used in the Docker run?

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.


Video Answer


1 Answers

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.

Debugging process

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!

Robust shell scripts

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.

like image 159
Nick ODell Avatar answered Oct 27 '22 00:10

Nick ODell