Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Docker Image CI/CD

on:
push:
branches:
- "main"
workflow_dispatch:

jobs:
backend:
runs-on: ubuntu-latest

steps:
- name: Check repository
uses: actions/checkout@v4

- name: Get date for tagging
id: date
run: echo "date=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push the Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/server/Dockerfile
push: true
tags: |
${{ vars.DOCKERHUB_USERNAME }}/wajo-prod-server:latest
${{ vars.DOCKERHUB_USERNAME }}/wajo-prod-server:${{ env.date }}

frontend:
runs-on: ubuntu-latest

steps:
- name: Check repository
uses: actions/checkout@v4

- name: Get date for tagging
id: date
run: echo "date=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV

# Login
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

# Client Docker image
- name: Build and push the client Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/client/Dockerfile
push: true
tags: |
${{ vars.DOCKERHUB_USERNAME }}/wajo-prod-client:latest
${{ vars.DOCKERHUB_USERNAME }}/wajo-prod-client:${{ env.date }}
4 changes: 2 additions & 2 deletions .github/workflows/template-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ jobs:
uses: actions/checkout@v4
with:
# submodules: true
token: ${{ secrets.TEMPLATE_SYNC_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: actions-template-sync
uses: AndreasAugustin/actions-template-sync@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
source_gh_token: ${{ secrets.GITHUB_TOKEN }}
source_repo_path: codersforcauses/django-nextjs-template
upstream_branch: main
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,10 @@ If you modify anything in the `docker` folder, you need to add the `--build` fla
### Changing env vars

Edit the `.env` file in the respective directory (client or server).

### Production mode

Use code below to start **Production** mode after modify the `.env` to `PRODUCTION`
```bash
docker compose -f docker-compose.prod.yml up -d --build
```
62 changes: 62 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
services:
db:
image: postgres:16.4
restart: unless-stopped
volumes:
- ${LOCAL_WORKSPACE_FOLDER:-.}/data/db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 3s
timeout: 3s
retries: 5
env_file: ./server/.env
ports:
- 5432:5432
server:
image: ${DOCKERHUB_USERNAME}/wajo-prod-server:latest
container_name: wajo_server
restart: unless-stopped
env_file: ./.env.server
entrypoint: /entrypoint.sh
volumes:
- ./opt/gunicorn-logs/:/var/log/gunicorn/
- ./opt/django-logs/:/var/log/django/
- ./opt/static_files/:/app/static_files
- ./opt/media/:/app/mediafiles/media
depends_on:
- db
client:
image: ${DOCKERHUB_USERNAME}/wajo-prod-client:latest
container_name: wajo-client
restart: unless-stopped
env_file: ./.env.client
ports:
- 3000:3000
depends_on:
- server

nginx:
image: nginx
container_name: wajo_nginx
restart: unless-stopped
ports:
- 80:3000
- 443:3000
- 3000:3000
- 8000:8000
volumes:
- ./custom.conf:/etc/nginx/conf.d/default.conf
- ./opt/static_files:/opt/static_files
- ./opt/media:/opt/media
- ./opt/nginx-logs/:/var/log/nginx/
depends_on:
- client
- server

watchtower:
image: containrrr/watchtower
container_name: wajo_watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 30
21 changes: 8 additions & 13 deletions docker/client/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
FROM node:20-slim as development-stage
FROM node:20-slim as client-prod

# SET WORKING DIRECTORY
WORKDIR /app

# Copy runtime script & make it executable
COPY /docker/client/entrypoint.sh /entrypoint.sh

COPY ./client/package.json ./client/package-lock.json ./

# Install ALL Dependencies
RUN npm install
# Make the script executable
RUN chmod +x /entrypoint.sh

# Copy Application code into a directory called `app`
COPY ./client /app
COPY ./client ./

# ========================================
# ---- Executed at Container Runtime ----
# ========================================
# Install dependencies without dev dependencies
RUN npm install --production

# CMD commands get executed at container runtime!
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
RUN npm run build

# TODO: Production
EXPOSE 3000
7 changes: 7 additions & 0 deletions docker/client/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,11 @@ if [ "${APP_ENV^^}" = "DEVELOPMENT" ]; then
echo "======= Starting inbuilt nextjs webserver ==================================================================="
npm run dev
exit
fi

if [[ "${APP_ENV^^}" = "PRODUCTION" ]]; then
# npm install --production
echo " "
echo "======= Starting nextjs webserver ==================================================================="
npm run start
fi
21 changes: 21 additions & 0 deletions docker/nginx/custom.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
server {
listen 8000;
server_name localhost;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
client_max_body_size 5M;

location / {
proxy_pass http://server:8081;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location /static/ {
alias /opt/static_files/;
}

location /media/ {
alias /opt/media/;
}
}
9 changes: 3 additions & 6 deletions docker/server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ WORKDIR /app

COPY ./docker/server/entrypoint.sh /entrypoint.sh

COPY ./server/pyproject.toml ./server/poetry.lock ./

RUN poetry install

COPY ./server ./

RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
RUN poetry install --without dev

RUN chmod +x /entrypoint.sh
8 changes: 6 additions & 2 deletions docker/server/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ fi
# Run Django/Gunicorn
# ===================
if [ "${APP_ENV^^}" = "PRODUCTION" ]; then
# Create file to hold django logs
printf "\n" && echo "Creating file to hold django logs"
echo "Running: mkdir -p /var/log/django && touch /var/log/django/django.log"
mkdir -p /var/log/django && touch /var/log/django/django.log

# Run Gunicorn / Django
printf "\n" && echo " Running Gunicorn / Django"
echo "Running: gunicorn api.wsgi -b 0.0.0.0:8000 --workers=6 --keep-alive 20 --log-file=- --log-level debug --access-logfile=/var/log/accesslogs/gunicorn --capture-output --timeout 50"
gunicorn api.wsgi -b 0.0.0.0:8000 --workers=6 --keep-alive 20 --log-file=- --log-level debug --access-logfile=/var/log/accesslogs/gunicorn --capture-output --timeout 50
echo "Running: gunicorn api.wsgi -b 0.0.0.0:8081 --workers=3 --keep-alive 20 --log-level info --access-logfile=/var/log/gunicorn/access.log --error-logfile=/var/log/gunicorn/error.log --capture-output --timeout 50"
gunicorn api.wsgi -b 0.0.0.0:8081 --workers=3 --keep-alive 20 --log-level info --access-logfile=/var/log/gunicorn/access.log --error-logfile=/var/log/gunicorn/error.log --capture-output --timeout 50
fi
2 changes: 2 additions & 0 deletions rundev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
(cd server && ./dev.sh) & (cd client && npm run dev )
2 changes: 1 addition & 1 deletion server/api/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@

from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings")

application = get_asgi_application()
4 changes: 2 additions & 2 deletions server/api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@
STATIC_URL = "/static/"

# STATIC_ROOT is where the static files get copied to when "collectstatic" is run.
STATIC_ROOT = "static_files"
STATIC_ROOT = os.path.join(PROJECT_ROOT, "static_files")

# This is where to _find_ static files when 'collectstatic' is run.
# These files are then copied to the STATIC_ROOT location.
STATICFILES_DIRS = ("static",)
STATICFILES_DIRS = (os.path.join(PROJECT_ROOT, "static"),)

# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
Expand Down
2 changes: 1 addition & 1 deletion server/api/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings")

application = get_wsgi_application()