Deployment Guide
This guide covers the deployment process for the Rhea Agripad backend on a production server.
Deployment Overview
The Rhea Agripad backend is deployed using Docker containers on DigitalOcean. The deployment process is automated using GitHub Actions.
GitHub Actions Deployment Pipeline
When code is pushed to the main branch, a GitHub Actions workflow builds a Docker image, tags it with a hash value, and pushes it to the DigitalOcean container registry.
GitHub Action Secrets
The following secrets are used in the GitHub Actions workflow:
CREATE_CONTAINER_IMAGE
: Set to 'true' to enable image creation, 'false' to disableDIGITALOCEAN_TOKEN
: Access token for DigitalOceanSSH_PRIVATE_KEY
: Private key for connecting to the dropletENV
: Environment to deploy the infrastructureAGE_PRIVATE_KEY
: Key used to decrypt the Terraform state file
Disabling Container Image Creation
To disable container image creation when pushing to the main branch, set the CREATE_CONTAINER_IMAGE
secret to 'false'.
Docker Image creation
To create the image, you need to push to the Agripad Backend
repository (https://github.com/Rhea-Africa/agripad-multitenant-backend). If you have enabled image creation, the image will be built and pushed to the DigitalOcean container registry.
Before creating new images, its good to delete the old images after backing up them locally to avoid high space usage.
Updating the image tag
- Go to Digital ocean
- Go to Container Registry
- Identify you images for either backend or frontend
- Copy the result image tag and update the
docker-compose.yml
file in this repository https://github.com/Rhea-Africa/agripad-backend-cloud
Actual Deployment
To deploy the application, you need to push to the agripad-backend-cloud
repository (https://github.com/Rhea-Africa/agripad-backend-cloud) main
branch
Docker Compose Deployment
The application is deployed using Docker Compose on the DigitalOcean droplet.
Updating the Application
To update the application to a new version:
- Update the image tag in the docker-compose.yml file with the new hash value
- Push the changes to the main branch
Example docker-compose.yml update:
# Current version
app1:
image: prod-rhea-container-registry/app1:f2ef4211cf5e3b068484f7dfb5d770fa6ee8f04b
env_file:
- .env.app1
ports:
- "8000:80"
networks:
- container-network
# Updated version
app1:
image: prod-rhea-container-registry/app1:8484f7dfb5d770fa6ee8f04bf2ef4211cf5e3b06
env_file:
- .env.app1
ports:
- "8000:80"
networks:
- container-network
Important: Always check if services are running after deployment!
Managing Services on the Droplet
Checking Service Status
To check if services are running:
docker ps -a
Starting Services
To start all services:
docker-compose up
To start a specific service:
docker-compose up <service_name>
Stopping Services
To stop all services:
docker-compose down
To stop a specific service:
docker-compose down <service_name>
Troubleshooting Failed Services
If a service fails to start:
-
Check if the service is running:
docker ps -a
-
Try to start the service manually to see error messages:
docker-compose up <service-name>
-
Check container logs:
docker logs <container-name>
EMQX Configuration
Creating Swap Memory for EMQX
EMQX may require additional memory. Create a swap file:
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
To make the swap permanent:
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Restart EMQX after configuring swap:
sudo systemctl restart emqx
Creating Tenants in Production
To create tenants in the production environment:
# Create Main Tenant
docker exec -it <container_id> sh -c "python manage.py create_tenant --domain-domain=main.api.rhea-agripad.xyz --schema=main --name=Main"
# Create Rhea Tenant
docker exec -it <container_id> sh -c "python manage.py create_tenant --domain-domain=rhea.api.rhea-agripad.xyz --schema=rhea --name=Rhea"
# Create Kilimo Tenant
docker exec -it <container_id> sh -c "python manage.py create_tenant --domain-domain=kilimo.api.rhea-agripad.xyz --schema=kilimo --name=Kilimo --no-input"
Replace <container_id>
with the actual container ID of your Django application.