0

I have two docker containers : one frontend and one backend and they both run a different /start script.

The frontend container is restarting again and again relaunching the /start script again and again.

I have checked the logs and there is no error.

I have tried to put stdin_open: true in the docker-compose.yml file and it is the same.

Any suggestions on why it is doing so?

Here is the docker-compose.yml

---
version: '3.7'

services:
  frontend:
    container_name: frontend
    build:
      context: .
      dockerfile: ./compose/production/build/Dockerfile
    restart: always
    command: /start
    stdin_open: true
    ports:
      - 80:80
      - 443:443
    volumes:
      - staticfiles:/app/static
      - mediafiles:/app/media
    depends_on:
      - backend
    networks:
      spa_network:
        ipv4_address: 171.20.128.3

  backend:
    container_name: backend
    build:
      context: .
      dockerfile: ./compose/production/django/Dockerfile
    restart: always
    command: /start
    volumes:
      - staticfiles:/app/static
      - mediafiles:/app/media
      - sqlite:/app/db
    ports:
      - 8000:8000
    env_file:
      - ./env/prod-sample
    networks:
      spa_network:
        ipv4_address: 171.20.128.2

networks:
  spa_network:
    name: spa_network
    ipam:
      config:
        - subnet: 171.20.0.0/16
volumes:
  sqlite:
    name: sqlite
  staticfiles:
    name: staticfiles
  mediafiles:
    name: mediafiles

here is the Dockerfile for frontend:

FROM node:14-alpine as frontend-builder
#WORKDIR /app/frontend
WORKDIR /app/frontend
COPY ./frontend .
ENV PATH ./node_modules/.bin/:$PATH
RUN set -ex; \
  yarn install --frozen-lockfile --production; \
  yarn cache clean; \
  yarn run build
###############################################
FROM nginx:1.19.2-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY ./compose/production/build/nginx.conf /etc/nginx/conf.d
COPY ./compose/production/build/start /start
RUN chmod +x /start
#volume /var/log/nginx pour les logs? 
# copy the frontend build
COPY --from=frontend-builder /app/frontend/build /usr/share/nginx/html/build

And here is the /start script for frontend :

#!/bin/sh
apk update
apk add nano
apk add certbot
mkdir /var/lib/letsencrypt
mkdir /var/lib/letsencrypt/.well-known
chgrp www-data /var/lib/letsencrypt
chmod g+s /var/lib/letsencrypt
mkdir /etc/nginx/snippets
touch /etc/nginx/snippets/letsencrypt.conf
echo "location ^~/.well-known/acme-challenge/ {" >>/etc/nginx/snippets/letsencrypt.conf
echo "  allow all;">> /etc/nginx/snippets/letsencrypt.conf
echo "  root /var/lib/letsencrypt/;">> /etc/nginx/snippets/letsencrypt.conf
echo "  default_type "text/plain";">> /etc/nginx/snippets/letsencrypt.conf
echo "  try_files $uri =404;">> /etc/nginx/snippets/letsencrypt.conf
echo "}">> /etc/nginx/snippets/letsencrypt.conf
#nginx -s reload -c /etc/nginx/nginx.conf
echo "certbot"

And here is the output of the logs of the frontend container :

fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
v3.12.12-40-gdc5d0f0e3f [http://dl-cdn.alpinelinux.org/alpine/v3.12/main]
v3.12.12-30-g96b07a1c68 [http://dl-cdn.alpinelinux.org/alpine/v3.12/community]
OK: 12794 distinct packages available
(1/2) Installing libmagic (5.38-r0)
(2/2) Installing nano (4.9.3-r0)
Executing busybox-1.31.1-r16.trigger
OK: 30 MiB in 44 packages
(1/43) Installing expat (2.2.10-r4)
(2/43) Installing libffi (3.3-r2)
(3/43) Installing gdbm (1.13-r1)
(4/43) Installing readline (8.0.4-r0)
(5/43) Installing sqlite-libs (3.32.1-r1)
(6/43) Installing python3 (3.8.10-r0)
(7/43) Installing py3-ordered-set (4.0.1-r0)
(8/43) Installing py3-appdirs (1.4.4-r1)
(9/43) Installing py3-parsing (2.4.7-r0)
(10/43) Installing py3-six (1.15.0-r0)
(11/43) Installing py3-packaging (20.4-r0)
(12/43) Installing py3-setuptools (47.0.0-r0)
(13/43) Installing py3-cparser (2.20-r0)
(14/43) Installing py3-cffi (1.14.0-r2)
(15/43) Installing py3-idna (2.9-r0)
(16/43) Installing py3-asn1crypto (1.3.0-r0)
(17/43) Installing py3-cryptography (2.9.2-r0)
(18/43) Installing py3-openssl (19.1.0-r0)
(19/43) Installing py3-josepy (1.3.0-r0)
(20/43) Installing py3-pbr (5.4.5-r1)
(21/43) Installing py3-mock (4.0.2-r0)
(22/43) Installing py3-tz (2020.1-r0)
(23/43) Installing py3-pyrfc3339 (1.1-r3)
(24/43) Installing py3-chardet (3.0.4-r4)
(25/43) Installing py3-certifi (2020.4.5.1-r0)
(26/43) Installing py3-urllib3 (1.25.9-r0)
(27/43) Installing py3-requests (2.23.0-r0)
(28/43) Installing py3-requests-toolbelt (0.9.1-r1)
(29/43) Installing py3-acme (1.4.0-r0)
(30/43) Installing py3-configargparse (0.15.2-r0)
(31/43) Installing py3-configobj (5.0.6-r7)
(32/43) Installing py3-distro (1.5.0-r1)
(33/43) Installing py3-distutils-extra (2.44-r0)
(34/43) Installing py3-future (0.18.2-r1)
(35/43) Installing py3-parsedatetime (2.5-r0)
(36/43) Installing py3-zope-interface (5.1.0-r0)
(37/43) Installing py3-zope-proxy (4.3.5-r0)
(38/43) Installing py3-zope-deferredimport (4.3.1-r2)
(39/43) Installing py3-zope-deprecation (4.4.0-r3)
(40/43) Installing py3-zope-event (4.4-r4)
(41/43) Installing py3-zope-hookable (5.0.1-r0)
(42/43) Installing py3-zope-component (4.6.1-r0)
(43/43) Installing certbot (1.4.0-r0)
Executing busybox-1.31.1-r16.trigger
OK: 105 MiB in 87 packages
certbot
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
v3.12.12-40-gdc5d0f0e3f [http://dl-cdn.alpinelinux.org/alpine/v3.12/main]
v3.12.12-30-g96b07a1c68 [http://dl-cdn.alpinelinux.org/alpine/v3.12/community]
OK: 12794 distinct packages available
OK: 105 MiB in 87 packages
OK: 105 MiB in 87 packages
mkdir: can't create directory '/var/lib/letsencrypt': File exists
mkdir: can't create directory '/var/lib/letsencrypt/.well-known': File exists
mkdir: can't create directory '/etc/nginx/snippets': File exists
certbot
...
6
  • 1
    As an aside, probably prefer mkdir -p to avoid getting an error message when the directory already exists. Also, mkdir, like most file and directory utilities, allow you to supply a list of directory arguments. Commented Jun 18, 2022 at 18:34
  • 1
    Your start script simply exits, which causes the image to also exit. This is a common Docker FAQ. Those commands would seem to make more sense in a build-time RUN statement anyway, and let the image's default entry point run the server if that's what you want (i.e. don't override it). Commented Jun 18, 2022 at 18:35
  • I thought the run command could create many unwanted "layers"...am i wrong about that? Commented Jun 19, 2022 at 16:10
  • With traditional Docker, you had to minimize the number of RUN statements, but that's less of a concern now. But you obviously can't have fewer commands than you actually need to deliver the functionality you want, regardless of how exactly you execute them. Commented Jun 19, 2022 at 16:31
  • It seems the certbot command needs the server to be running...so it's not good using RUN in the Dockerfile...do you have a suggestion on how to avoid the script to exit ? also, does my start script prevent entrypoint server script to run? i could also modify entrypoint server script but i dont know how to modify a file in a docker image in a scripted way Commented Jun 19, 2022 at 23:29

1 Answer 1

0

Thanks for the link in a comment to the upstream Dockerfile; this runs

/docker-entrypoint.sh

which allows you to put additional scripts to run at startup in the directory it examines. However, these are run before the nginx daemon is run; see below for how to run something after the service started.

Unless you have strong reasons to avoid rebuilding the image as needed (and perhaps even then) I would instead move the commands from your start script to the Dockerfile to only perform the apk installations and mkdirs etc at build time. The apk commands in particular can be tedious to watch every time the image restarts, and the times the results are not identical to the previous run will be the times when you should rebuild the image anyway.

FROM node:14-alpine as frontend-builder
#WORKDIR /app/frontend
WORKDIR /app/frontend
COPY ./frontend .
ENV PATH ./node_modules/.bin/:$PATH
RUN set -ex; \
  yarn install --frozen-lockfile --production; \
  yarn cache clean; \
  yarn run build
###############################################
FROM nginx:1.19.2-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY ./compose/production/build/nginx.conf /etc/nginx/conf.d
COPY ./compose/production/build/start /start
RUN chmod +x /start && \
    apk update && \
    apk add nano certbot && \
    mkdir -p  /var/lib/letsencrypt/.well-known && \
    chgrp www-data /var/lib/letsencrypt && \
    chmod g+s /var/lib/letsencrypt && \
    mkdir /etc/nginx/snippets && \
    printf '%\n' \
        "location ^~/.well-known/acme-challenge/ {" \
        "  allow all;" \
        "  root /var/lib/letsencrypt/;" \
        "  default_type "text/plain";" \
        "  try_files $uri =404;" \
        "}" > /etc/nginx/snippets/letsencrypt.conf
#volume /var/log/nginx pour les logs? 
# copy the frontend build
COPY --from=frontend-builder /app/frontend/build /usr/share/nginx/html/build

You'll notice that this change didn't add the number of RUN statements, by piggybacking all of them into an existing one. With modern Docker, this is no longer strictly necessary, and especially for debugging, it's easier to just use one RUN statement per command.

I can see nothing here which needs to stay in the start script, so with this change, you would take it out entirely. But if some changes can only work when the service is already running, you'd need to perform those after starting the service. This requires some additional refactoring to run the service in the background, and then probably add a wait at the end.

#!/bin/sh
/docker-entrypoint.sh &
nginx_pid=$!
certbot
wait "$nginx_pid"
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot. The thing is i dont find nginx - g daemon off or any command to start nginx in the default entrypoint files (github.com/nginxinc/docker-nginx/blob/master/stable/alpine/… and stackoverflow.com/a/64205695/19271630 )
github.com/nginxinc/docker-nginx/blob/master/… runs all the files in the directory you link to, but those are run before the exec of nginx or nginx-debug. Probably run the linked script with the startup hooks instead of the bare daemon; I have updated the answer to suggest this.
I suppose you could also run a script in the configuration directory to wait in the background for the server to come up, and then run certbot; but this doesn't seem simpler at all.
i ve found this pentacent.medium.com/… ... i will try tomorrow