Skip to content

backend deployment by Karan0005 #15

backend deployment by Karan0005

backend deployment by Karan0005 #15

name: backend_pipeline
run-name: backend deployment by ${{ github.actor }}
on:
push:
branches:
- develop
- uat
- main
paths:
- 'apps/backend/**'
- 'libs/shared/**'
jobs:
build:
name: Build Backend
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3.3.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set Environment Variables
run: |
case $GITHUB_REF in
refs/heads/develop)
echo "PORT_BACKEND=8000" >> $GITHUB_ENV
echo "DOCKER_TAG=develop" >> $GITHUB_ENV
;;
refs/heads/uat)
echo "PORT_BACKEND=8000" >> $GITHUB_ENV
echo "DOCKER_TAG=uat" >> $GITHUB_ENV
;;
refs/heads/main)
echo "PORT_BACKEND=8000" >> $GITHUB_ENV
echo "DOCKER_TAG=prod" >> $GITHUB_ENV
;;
esac
- name: Backup existing image if exists
run: |
IMAGE_EXISTS=$(docker manifest inspect ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }} > /dev/null 2>&1 && echo "YES" || echo "NO")
if [ "$IMAGE_EXISTS" = "YES" ]; then
echo "Backup existing image..."
docker pull ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }}
docker tag ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }} ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }}_backup
docker push ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }}_backup
else
echo "No existing image to backup."
fi
- name: Build and Push Backend Docker Image
uses: docker/build-push-action@v6
with:
context: .
file: devops/backend/Dockerfile
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }}
build-args: |
PORT_BACKEND=${{ env.PORT_BACKEND }}
deploy:
name: Deploy Backend
runs-on: ubuntu-latest
needs: build
steps:
- name: Set Environment Variables
run: |
case $GITHUB_REF in
refs/heads/develop)
echo "APP_ENV=DEV" >> $GITHUB_ENV
echo "REDIS_HOST=redis" >> $GITHUB_ENV
echo "REDIS_PORT=6379" >> $GITHUB_ENV
echo "MIN_REDIS_VERSION=7.0.0" >> $GITHUB_ENV
echo "PORT_BACKEND=8000" >> $GITHUB_ENV
echo "PORT_FRONTEND=80" >> $GITHUB_ENV
echo "DOCKER_TAG=develop" >> $GITHUB_ENV
echo "ROUTE_PREFIX=api" >> $GITHUB_ENV
echo "KEY_VAULT_URI=${{ secrets.DEV_KEY_VAULT_URI }}" >> $GITHUB_ENV
echo "TENANT_ID=${{ secrets.DEV_TENANT_ID }}" >> $GITHUB_ENV
echo "CLIENT_ID=${{ secrets.DEV_CLIENT_ID }}" >> $GITHUB_ENV
echo "CLIENT_SECRET=${{ secrets.DEV_CLIENT_SECRET }}" >> $GITHUB_ENV
echo "SERVER_HOST=${{ secrets.DEV_SERVER_HOST }}" >> $GITHUB_ENV
echo "SERVER_PASS_PHRASE=${{ secrets.DEV_SERVER_PASS_PHRASE }}" >> $GITHUB_ENV
echo "SERVER_PRIVATE_SSH_KEY<<EOF" >> $GITHUB_ENV
echo "${{ secrets.DEV_SERVER_PRIVATE_SSH_KEY }}" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
echo "SERVER_USER=${{ secrets.DEV_SERVER_USER }}" >> $GITHUB_ENV
;;
refs/heads/uat)
echo "APP_ENV=UAT" >> $GITHUB_ENV
echo "REDIS_HOST=redis" >> $GITHUB_ENV
echo "REDIS_PORT=6379" >> $GITHUB_ENV
echo "MIN_REDIS_VERSION=7.0.0" >> $GITHUB_ENV
echo "PORT_BACKEND=8000" >> $GITHUB_ENV
echo "PORT_FRONTEND=80" >> $GITHUB_ENV
echo "DOCKER_TAG=uat" >> $GITHUB_ENV
echo "ROUTE_PREFIX=api" >> $GITHUB_ENV
echo "KEY_VAULT_URI=${{ secrets.UAT_KEY_VAULT_URI }}" >> $GITHUB_ENV
echo "TENANT_ID=${{ secrets.UAT_TENANT_ID }}" >> $GITHUB_ENV
echo "CLIENT_ID=${{ secrets.UAT_CLIENT_ID }}" >> $GITHUB_ENV
echo "CLIENT_SECRET=${{ secrets.UAT_CLIENT_SECRET }}" >> $GITHUB_ENV
echo "SERVER_HOST=${{ secrets.UAT_SERVER_HOST }}" >> $GITHUB_ENV
echo "SERVER_PASS_PHRASE=${{ secrets.UAT_SERVER_PASS_PHRASE }}" >> $GITHUB_ENV
echo "SERVER_PRIVATE_SSH_KEY<<EOF" >> $GITHUB_ENV
echo "${{ secrets.UAT_SERVER_PRIVATE_SSH_KEY }}" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
echo "SERVER_USER=${{ secrets.UAT_SERVER_USER }}" >> $GITHUB_ENV
;;
refs/heads/main)
echo "APP_ENV=PROD" >> $GITHUB_ENV
echo "REDIS_HOST=redis" >> $GITHUB_ENV
echo "REDIS_PORT=6379" >> $GITHUB_ENV
echo "MIN_REDIS_VERSION=7.0.0" >> $GITHUB_ENV
echo "PORT_BACKEND=8000" >> $GITHUB_ENV
echo "PORT_FRONTEND=80" >> $GITHUB_ENV
echo "DOCKER_TAG=prod" >> $GITHUB_ENV
echo "ROUTE_PREFIX=api" >> $GITHUB_ENV
echo "KEY_VAULT_URI=${{ secrets.PROD_KEY_VAULT_URI }}" >> $GITHUB_ENV
echo "TENANT_ID=${{ secrets.PROD_TENANT_ID }}" >> $GITHUB_ENV
echo "CLIENT_ID=${{ secrets.PROD_CLIENT_ID }}" >> $GITHUB_ENV
echo "CLIENT_SECRET=${{ secrets.PROD_CLIENT_SECRET }}" >> $GITHUB_ENV
echo "SERVER_HOST=${{ secrets.PROD_SERVER_HOST }}" >> $GITHUB_ENV
echo "SERVER_PASS_PHRASE=${{ secrets.PROD_SERVER_PASS_PHRASE }}" >> $GITHUB_ENV
echo "SERVER_PRIVATE_SSH_KEY<<EOF" >> $GITHUB_ENV
echo "${{ secrets.PROD_SERVER_PRIVATE_SSH_KEY }}" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
echo "SERVER_USER=${{ secrets.PROD_SERVER_USER }}" >> $GITHUB_ENV
;;
esac
- name: Deploy to Digital Ocean Droplet via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ env.SERVER_HOST }}
username: ${{ env.SERVER_USER }}
key: ${{ env.SERVER_PRIVATE_SSH_KEY }}
passphrase: ${{ env.SERVER_PASS_PHRASE }}
script: |
# Ensure Docker is installed
if ! command -v docker &> /dev/null; then
echo "Docker not found, installing..."
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
else
echo "Docker is already installed."
fi
# Function to create Docker volume if it does not exist
create_volume_if_not_exists() {
local VOLUME_NAME=$1
if [[ $(docker volume ls -q -f name=^${VOLUME_NAME}$) ]]; then
echo "Volume '${VOLUME_NAME}' already exists. Skipping creation."
else
echo "Creating volume '${VOLUME_NAME}'..."
docker volume create "${VOLUME_NAME}" || {
echo "Error: Failed to create volume '${VOLUME_NAME}'."; exit 1;
}
fi
}
# Function to create Docker network if it does not exist
create_network_if_not_exists() {
local NETWORK_NAME=$1
docker network inspect ${NETWORK_NAME} >/dev/null 2>&1 || {
echo "Creating Docker network '${NETWORK_NAME}'..."
docker network create ${NETWORK_NAME} || {
echo "Error: Failed to create network '${NETWORK_NAME}'."; exit 1;
}
}
}
# Function to set up Redis container if not running
setup_redis() {
if [ ! "$(docker ps -q -f name=redis)" ]; then
echo "Setting up Redis container..."
docker run -d --name redis --network backend_network --restart always \
-p ${{ env.REDIS_PORT }}:${{ env.REDIS_PORT }} \
-v redis_data:/app/redis-data redis:7 || {
echo "Error: Failed to start Redis container."; exit 1;
}
echo "Redis container started."
else
echo "Redis container already running."
fi
}
# Function to deploy backend container
deploy_backend() {
echo "Pulling latest backend image..."
docker pull ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }} || {
echo "Error: Failed to pull backend image."; exit 1;
}
if [ "$(docker ps -q -f name=backend)" ]; then
echo "Stopping and removing old backend container..."
docker stop backend && docker rm backend || {
echo "Error: Failed to stop/remove backend container."; exit 1;
}
fi
echo "Starting new backend container..."
docker run -d --restart always --name backend --network backend_network \
-p ${{ env.PORT_BACKEND }}:${{ env.PORT_BACKEND }} \
-e APP_ENV=${{ env.APP_ENV }} \
-e PORT_BACKEND=${{ env.PORT_BACKEND }} \
-e PORT_FRONTEND=${{ env.PORT_FRONTEND }} \
-e ROUTE_PREFIX=${{ env.ROUTE_PREFIX }} \
-e KEY_VAULT_URI=${{ env.KEY_VAULT_URI }} \
-e TENANT_ID=${{ env.TENANT_ID }} \
-e CLIENT_ID=${{ env.CLIENT_ID }} \
-e CLIENT_SECRET=${{ env.CLIENT_SECRET }} \
-e REDIS_HOST=${{ env.REDIS_HOST }} \
-e REDIS_PORT=${{ env.REDIS_PORT }} \
-e MIN_REDIS_VERSION=${{ env.MIN_REDIS_VERSION }} \
-v /var/run/docker.sock:/var/run/docker.sock \
-v source_code_volume:/app/source-code \
${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }} || {
echo "Error: Failed to start new backend container."; exit 1;
}
echo "Backend container started successfully."
}
# Function to roll back to backup backend container
rollback_backend() {
echo "Rolling back to backup backend container..."
docker pull ${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }}_backup || {
echo "Error: Failed to pull backup backend image."; exit 1;
}
# Stop and remove failed container (if it exists)
docker stop backend || true
docker rm backend || true
docker run -d --restart always --name backend --network backend_network \
-p ${{ env.PORT_BACKEND }}:${{ env.PORT_BACKEND }} \
-e APP_ENV=${{ env.APP_ENV }} \
-e PORT_BACKEND=${{ env.PORT_BACKEND }} \
-e PORT_FRONTEND=${{ env.PORT_FRONTEND }} \
-e ROUTE_PREFIX=${{ env.ROUTE_PREFIX }} \
-e KEY_VAULT_URI=${{ env.KEY_VAULT_URI }} \
-e TENANT_ID=${{ env.TENANT_ID }} \
-e CLIENT_ID=${{ env.CLIENT_ID }} \
-e CLIENT_SECRET=${{ env.CLIENT_SECRET }} \
-e REDIS_HOST=${{ env.REDIS_HOST }} \
-e REDIS_PORT=${{ env.REDIS_PORT }} \
-e MIN_REDIS_VERSION=${{ env.MIN_REDIS_VERSION }} \
-v /var/run/docker.sock:/var/run/docker.sock \
-v source_code_volume:/app/source-code \
${{ secrets.DOCKER_USERNAME }}/backend:${{ env.DOCKER_TAG }}_backup || {
echo "Error: Failed to roll back to backup backend container."; exit 1;
}
echo "Rolled back to backup backend container."
}
# Create necessary volumes
create_volume_if_not_exists "source_code_volume"
create_volume_if_not_exists "redis_data"
# Create necessary network
create_network_if_not_exists "backend_network"
# Set up Redis container
setup_redis
# Deploy backend container
deploy_backend || rollback_backend
# Remove old backend images (dangling images)
docker images --filter "dangling=true" --format "{{.ID}}" | xargs -r docker rmi || true