Environment: Ubuntu 23.10
Docker Version:   26.1.2
Docker Compose Ver: 2.27
1. Dockerfile for Nextjs front end placed parallel to package.json file 
FROM node:20.12.2-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"] 
1.a. .env
NEXT_PUBLIC_BASE_URL=http://192.168.x.x:8000
 
2. Dockerfile for Python backend placed above src folder 
FROM python:3.11.4-alpine3.18
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /usr/src/app
COPY ./src/requirements/requirements_dev.txt /usr/src/app
COPY ./src/requirements/base.txt /usr/src/app
RUN pip install --upgrade pip && \
    apk update && \
    apk add postgresql-dev gcc python3-dev musl-dev jpeg-dev zlib-dev curl && \
    pip install -r requirements_dev.txt
COPY ./src/.env /usr/src/app
RUN mkdir /usr/src/app/logs
COPY ./entrypoint.sh /usr/src/app
RUN sed -i 's/\r$//g' ./entrypoint.sh
RUN chmod 777 ./entrypoint.sh
COPY ./src /usr/src/app/
RUN chmod 777 ./es_index.py
ENTRYPOINT ["./entrypoint.sh"]
2.a. entrypoint.sh
#!/bin/sh
export POSTGRES_HOST="db"
if [ $DATABASE = "postgres" ]
then
    echo "Waiting for postgres to load..."
    while ! nc -z $POSTGRES_HOST $POSTGRES_PORT; do
        sleep 0.1
    done
    echo "postgres ready to run"
    python manage.py makemigrations
    python manage.py migrate --no-input
fi
python manage.py createsuperuser --noinput --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL 
python es_index.py
exec "$@"
2.b. vi .env
# secret key
SECRET_KEY=ac6cd19772005f224cefb220060037bf15f35a6e3e1826a1095a26fc
# database stuffs
DATABASE=postgres
DB_ENGINE=django.db.backends.postgresql
POSTGRES_DB=courses
POSTGRES_USER=postgres
POSTGRES_PASSWORD=xxxxx
POSTGRES_PORT=5432
POSTGRES_HOST=db
# superuser setup
DJANGO_SUPERUSER_USERNAME=admin
DJANGO_SUPERUSER_PASSWORD=admin
DJANGO_SUPERUSER_EMAIL=admin@gmail.com
# smtp setup
EMAIL_HOST_USER=courses@xxxxxx.org
EMAIL_HOST_PASSWORD=titygjzkngqtzoek
# celery stuffs
#CELERY_BROKER_URL=amqp://guest:guest@localhost:15672/
#CELERY_RESULT_BACKEND=db+postgresql://postgres:admin@localhost:5432/celery_tasks
# Adjust for dockerizatin 
CELERY_BROKER_URL=amqp://myuser:mypassword@rabbitmq:5672
CELERY_RESULT_BACKEND=db+postgresql://postgres:admin@db:5432/celery_tasks
ADMIN_USER=xxxxxx@xxxxxx.org
# elastic
#ES_HOST=localhost
ES_HOST=elasticsearch
ES_NUMBER_OF_SHARDS=1
ES_NUMBER_OF_REPLICAS=0
ES_USE_SSL=False
ES_PORT=9200
ES_INDEX=seepalaya
3. Dockerfile for Celery 
FROM python:3.11.4-alpine3.18
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /usr/src/app
COPY ./src/requirements/requirements_dev.txt /usr/src/app
COPY ./src/requirements/base.txt /usr/src/app
RUN pip install --upgrade pip && \
    apk update && \
    apk add postgresql-dev gcc python3-dev musl-dev jpeg-dev zlib-dev && \
    pip install -r requirements_dev.txt
COPY ./src/.env /usr/src/app
RUN mkdir /usr/src/app/logs
COPY ./src /usr/src/app/
3.a .env
similar to above 
 
4. Dockerfile for Postgres
FROM postgres:15.7-alpine3.18
ENV PG_MAX_WAL_SENDERS 8
ENV PG_WAL_KEEP_SEGMENTS 8
#Set timezone
ENV TZ=Asia/Kathmandu
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Copy the custom initialization script to the Docker image
COPY create_celery.sh /docker-entrypoint-initdb.d/
COPY *.sql /tmp/
COPY populate_ep.sh /docker-entrypoint-initdb.d/
# Grant execution permissions to the script
RUN chmod +x /docker-entrypoint-initdb.d/create_celery.sh
RUN chmod +x /docker-entrypoint-initdb.d/populate_ep.sh
 
4a. create_celery.sh 
#!/bin/bash
set -e
# Create additional databases
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
    CREATE DATABASE celery_tasks;
EOSQL
4b. populate_ep.sh 
#!/bin/bash
set -e
# Function to check if the database exists
db_exists() {
    psql -U "$POSTGRES_USER" -tc "SELECT 1 FROM pg_database WHERE datname = 'pustakalaya'" | grep -q 1
}
# Create the database if it does not exist
if ! db_exists; then
    psql -U "$POSTGRES_USER" -c "CREATE DATABASE pustakalaya"
fi
# Create the user and grant privileges
psql -U "$POSTGRES_USER" <<-EOSQL
    DO \$\$
    BEGIN
        IF NOT EXISTS (SELECT FROM pg_catalog.pg_user WHERE usename = 'pustakalaya_user') THEN
            CREATE USER pustakalaya_user WITH PASSWORD 'pustakalaya123';
        END IF;
    END
    \$\$;
    GRANT ALL PRIVILEGES ON DATABASE pustakalaya TO pustakalaya_user;
EOSQL
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname=pustakalaya < /tmp/pustakalaya.sql
4.c. .env
POSTGRES_DB=courses
POSTGRES_USER=postgres
POSTGRES_PASSWORD=xxxxx                 
 
5. docker-compose.yml 
version: "3.8"
services:
  db:
    build:
      context: seepalaya-new-database 
      dockerfile: Dockerfile.postgres
    container_name: seepalaya-db 
    env_file:
      - ./seepalaya-new-database/.env 
    volumes:
      - ./db/:/var/lib/postgresql/
    networks:
      - seepalaya-new 
    restart: always
  seepalaya-backend:
    build:
      context: seepalaya-new-backend 
      dockerfile: Dockerfile
    container_name: seepalaya-backend 
    command: "python manage.py runserver 0.0.0.0:8000"
    ports:
      - 8000:8000
    env_file:
      - ./seepalaya-new-backend/src/.env 
    environment:
      - CELERY_BROKER_URL=amqp://myuser:mypassword@rabbitmq:5672
    depends_on:
      - db
    networks:
      - seepalaya-new 
    restart: always
  rabbitmq:
    image: rabbitmq:3-management
    ports:
      - "5672:5672"
    environment:
      - RABBITMQ_DEFAULT_USER=myuser
      - RABBITMQ_DEFAULT_PASS=mypassword
    networks:
      - seepalaya-new 
    restart: always
 seepalaya-celery:
    build:
      context: seepalaya-new-celery 
      dockerfile: Dockerfile
    container_name: seepalaya-celery 
    command: celery -A config worker -l info 
    environment:
      - CELERY_BROKER_URL=amqp://myuser:mypassword@rabbitmq:5672 
    depends_on:
      - rabbitmq
      - seepalaya-backend 
    networks:
      - seepalaya-new 
    restart: always
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
    environment:
      - discovery.type=single-node
    ports:
      - "9200:9200"
    networks:
      - seepalaya-new
    restart: always
  
  seepalaya-front:
    build:
      context: seepalaya_new
      dockerfile: Dockerfile     
    container_name: seepalaya-front
    env_file:
      - ./seepalaya_new/.env
    ports:
      - "3000:3000"
    networks:
      - seepalaya-new
    restart: always
networks:
  seepalaya-new:
    driver: bridge