Skip to main content
The Exchange platform uses automated CI/CD with GitHub Actions to build, push, and deploy Docker images to production. This guide covers the production deployment strategy and best practices.

Deployment architecture

The production deployment follows a GitOps workflow:
  1. Code push to main branch triggers the CI/CD pipeline
  2. Docker images are built for all services
  3. Images are pushed to Docker Hub with commit SHA tags
  4. Deployment manifests are updated in a separate ops repository
  5. Kubernetes/Docker pulls and deploys the new images

GitHub Actions workflow

The production deployment is automated using GitHub Actions:
1

Trigger on push to main

The workflow runs on every push to the main branch:
.github/workflows/production.yml
name: Continuous Deployment (Production)

on:
  push:
    branches: ["main"]
2

Docker login

Authenticate to Docker Hub using repository secrets:
- name: Docker login
  uses: docker/login-action@v2
  with:
    username: ${{ secrets.DOCKER_USERNAME }}
    password: ${{ secrets.DOCKER_PASSWORD }}
3

Build and push images

Each service is built and pushed with the commit SHA as the tag:
- name: Build and push exchange-router images
  uses: docker/build-push-action@v4
  with:
    context: .
    file: docker/Dockerfile.router
    push: true
    tags: jogeshwar01/exchange-router:${{ github.sha }}
This is repeated for all four services:
  • exchange-router
  • exchange-ws-stream
  • exchange-db-processor
  • exchange-engine
4

Update deployment manifests

The workflow automatically updates the ops repository:
- name: Clone exchange-ops repo, update image tags, and push tags
  env:
    PAT: ${{ secrets.PAT }}
  run: |
    git clone https://github.com/jogeshwar01/exchange-ops.git
    cd exchange-ops

    sed -i 's|image: jogeshwar01/exchange-router:.*|image: jogeshwar01/exchange-router:${{ github.sha }}|' backend/deployment.yml
    sed -i 's|image: jogeshwar01/exchange-ws-stream:.*|image: jogeshwar01/exchange-ws-stream:${{ github.sha }}|' websocket/deployment.yml
    sed -i 's|image: jogeshwar01/exchange-db-processor:.*|image: jogeshwar01/exchange-db-processor:${{ github.sha }}|' db-processor/deployment.yml
    sed -i 's|image: jogeshwar01/exchange-engine:.*|image: jogeshwar01/exchange-engine:${{ github.sha }}|' engine/deployment.yml

    git config user.name "GitHub Actions Bot"
    git config user.email "[email protected]"
    git add .
    git commit -m "deploy: update exchange image tags to ${{ github.sha }}"
    git push https://${PAT}@github.com/jogeshwar01/exchange-ops.git main

Required GitHub secrets

Configure the following secrets in your GitHub repository settings:
1

DOCKER_USERNAME

Your Docker Hub username for pushing images.
# Example
jogeshwar01
2

DOCKER_PASSWORD

Your Docker Hub password or access token.
Use a Docker Hub access token instead of your password for better security.
3

PAT (Personal Access Token)

GitHub Personal Access Token with repo scope to update the ops repository.Generate at: https://github.com/settings/tokensRequired scopes:
  • repo - Full control of private repositories

Setting up GitHub secrets

  1. Go to your repository on GitHub
  2. Navigate to SettingsSecrets and variablesActions
  3. Click New repository secret
  4. Add each secret with its corresponding value

Production server setup

1

Connect to your server

SSH into your production server:
ssh -i key.pem ubuntu@<server-ip>
2

Install Docker

Install Docker and Docker Compose:
# Add Docker's official GPG key
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
3

Configure Docker permissions

Add your user to the docker group:
sudo usermod -aG docker $USER
newgrp docker
docker ps  # Verify it works
4

Clone the ops repository

git clone https://github.com/jogeshwar01/exchange-ops.git
cd exchange-ops
5

Configure environment

Create and configure the .env file:
cp .env.example .env
nano .env  # Edit with production values
Use strong passwords and secure credentials in production!
6

Start services

docker compose up -d

Production environment variables

Critical production configurations:

Database configuration

POSTGRES_HOST=exchange-postgres
POSTGRES_DB=exchange-db
POSTGRES_USER=<strong-username>
POSTGRES_PASSWORD=<strong-password>
POSTGRES_PORT=5432
PG__POOL_MAX_SIZE=16

Redis configuration

REDIS_URL=redis://exchange-redis:6379

Service endpoints

SERVER_ADDR=0.0.0.0:8080
WS_STREAM_URL=0.0.0.0:4000
See the Configuration guide for detailed environment variable documentation.

Performance tuning

PostgreSQL optimization

Increase max connections for high load:
db:
  command: -c 'max_connections=800'
  shm_size: 1gb

Memory limits

Adjust based on your server capacity:
deploy:
  resources:
    limits:
      memory: 5G

Connection pooling

Configure optimal pool size:
PG__POOL_MAX_SIZE=16  # Adjust based on load

Redis persistence

Configure Redis snapshot frequency:
redis:
  command: redis-server --save 20 1 --loglevel warning
This saves to disk if at least 1 key changed in 20 seconds.

Monitoring and health checks

Check service status

# View running containers
docker ps

# Check specific service logs
docker logs -f exchange-router

Resource monitoring

# Container resource usage
docker stats

# System resources
top
htop

Database health

# Check PostgreSQL
docker exec -it exchange-postgres psql -U root -d exchange-db -c "SELECT COUNT(*) FROM trades;"

# Check Redis
docker exec -it exchange-redis redis-cli ping

Rollback strategy

If a deployment fails, rollback to a previous version:
1

Identify the previous commit SHA

git log --oneline
2

Update deployment manifests

cd exchange-ops
sed -i 's|image: jogeshwar01/exchange-router:.*|image: jogeshwar01/exchange-router:<previous-sha>|' backend/deployment.yml
# Repeat for other services
3

Commit and push

git add .
git commit -m "rollback: revert to <previous-sha>"
git push
4

Pull and restart services

docker compose pull
docker compose up -d

Security best practices

Always follow these security practices in production:
  • Use strong passwords for database and Redis
  • Store secrets in GitHub Secrets, never in code
  • Use TLS/SSL for all external connections
  • Enable firewall rules to restrict access
  • Regularly update dependencies and Docker images
  • Implement rate limiting on API endpoints
  • Enable audit logging for all transactions
  • Use read replicas for database scalability

Backup strategy

Database backups

# Automated daily backup
docker exec exchange-postgres pg_dump -U root exchange-db > backup-$(date +%Y%m%d).sql

Redis backups

Redis automatically saves to:
docker/redis-data/dump.rdb
Copy this file regularly to backup storage.

Scaling considerations

Horizontal scaling

For high-traffic deployments:
  • Run multiple instances of router behind a load balancer
  • Use a dedicated Redis cluster
  • Implement database read replicas
  • Use separate servers for each service

Vertical scaling

Increase resources per service:
deploy:
  resources:
    limits:
      memory: 10G
      cpus: '4'

Next steps

Build docs developers (and LLMs) love