GitHub Actions
Setting up GitHub Actions
The GitHub workflow file is triggered on every manual trigger, push to the develop branch, or tags starting with v. It builds the new container image upon the trigger and updates the task definition in the ECS cluster. This ensures that the latest image is deployed to the ECS cluster.
name: Deploy Care
on:
  workflow_dispatch:
  push:
    tags:
      - 'v*'
    branches:
      - develop
    paths-ignore:
      - "docs/**"
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
env:
  IMAGE_NAME: care
  AWS_DEFAULT_REGION: ap-south-1
  AWS_DEFAULT_OUTPUT: json
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS Access Key ID for authentication
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # AWS Secret Access Key for authentication
  ECS_SERVICE_BACKEND: "care-backend" # ECS service name for the backend
  ECS_SERVICE_CELERY: "care-celery" # ECS service name for Celery
  ECS_CLUSTER: "example_cluster" # Name of the ECS cluster
  ECS_TASK_DEFINITION_BACKEND: "./aws/backend.json" # Path to the backend task definition
  ECS_TASK_DEFINITION_CELERY: "./aws/celery.json" # Path to the Celery task definition
  CONTAINER_NAME_BACKEND: "care-backend" # Container name for the backend
  CONTAINER_NAME_WORKER: "care-celery-worker" # Container name for the Celery worker
  CONTAINER_NAME_CRON: "care-celery-beat" # Container name for the Celery beat
jobs:
  build:
    name: Build & Push to container registries
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Generate docker tags
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: |
            ghcr.io/${{ github.repository }}
            ${{ secrets.DOCKER_HUB_USERNAME }}/${{ github.event.repository.name }}
          tags: |
            type=raw,value=production-latest,enable=${{ startsWith(github.event.ref, 'refs/tags/v') }}
            type=raw,value=production-latest-${{ github.run_number }}-{{date 'YYYYMMDD'}}-{{sha}},enable=${{ startsWith(github.event.ref, 'refs/tags/v') }}
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/develop' }}
            type=raw,value=latest-${{ github.run_number }},enable=${{ github.ref == 'refs/heads/develop' }}
            type=semver,pattern={{version}}
          flavor: latest=false
      - name: Setup QEMU
        uses: docker/setup-qemu-action@v3
      - name: Setup Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_HUB_USERNAME }} # DockerHub username
          password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} # DockerHub access token
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }} # GitHub token for authentication
      - name: Cache Docker layers
        uses: actions/cache@v4
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-build-${{ hashFiles('Pipfile.lock', 'docker/prod.Dockerfile') }}
          restore-keys: |
            ${{ runner.os }}-buildx-build-
      - name: Build and push image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: docker/prod.Dockerfile
          push: true
          provenance: false
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          build-args: |
            APP_VERSION=${{ github.sha }}
            ADDITIONAL_PLUGS=${{ secrets.ADDITIONAL_PLUGS }} # Additional plugins
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
      - name: Move cache
        run: |
          rm -rf /tmp/.buildx-cache
          mv /tmp/.buildx-cache-new /tmp/.buildx-cache
  deploy:
    name: Deploy to ECS
    runs-on: ubuntu-latest
    environment:
      name: Deployment-ecs
      url: https://careapi.example.com
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS Access Key ID for authentication
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # AWS Secret Access Key for authentication
          aws-region: ${{ env.AWS_DEFAULT_REGION }}
      - name: IMAGE Tagging
        env:
          ECR_REGISTRY: ghcr.io/${{ github.repository }}
          IMAGE_TAG: latest-${{ github.run_number }}
        run: echo "IMAGE_VALUE=`echo ghcr.io/${{ github.repository }}:$IMAGE_TAG`" >> $GITHUB_ENV
      - name: Fill Celery Cron definition
        id: task-def-celery-cron
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ env.ECS_TASK_DEFINITION_CELERY }}
          container-name: ${{ env.CONTAINER_NAME_CRON }}
          image: ${{ env.IMAGE_VALUE }}
      - name: Fill Celery Worker definition
        id: task-def-celery-worker
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ steps.task-def-celery-cron.outputs.task-definition }}
          container-name: ${{ env.CONTAINER_NAME_WORKER }}
          image: ${{ env.IMAGE_VALUE }}
      - name: Deploy Backend Celery
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-celery-worker.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE_CELERY }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true
      - name: Fill Backend API definition
        id: task-def-api
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ env.ECS_TASK_DEFINITION_BACKEND }}
          container-name: ${{ env.CONTAINER_NAME_BACKEND }}
          image: ${{ env.IMAGE_VALUE }}
      - name: Deploy Backend API
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.task-def-api.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE_BACKEND }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true
Secrets and Variables Used
Secrets
AWS_ACCESS_KEY_ID: AWS Access Key ID for authenticationAWS_SECRET_ACCESS_KEY: AWS Secret Access Key for authenticationDOCKER_HUB_USERNAME: DockerHub usernameDOCKER_HUB_ACCESS_TOKEN: DockerHub access tokenGITHUB_TOKEN: GitHub token for authenticationADDITIONAL_PLUGS: Additional plugins specified in JSON format to include in the build
Variables
IMAGE_NAME: Name of the image to be builtAWS_DEFAULT_REGION: AWS regionAWS_DEFAULT_OUTPUT: AWS output formatECS_SERVICE_BACKEND: ECS service name for the backend (care-backend)ECS_SERVICE_CELERY: ECS service name for the Celery service (care-celery)ECS_CLUSTER: ECS cluster name (care-cluster)ECS_TASK_DEFINITION_BACKEND: Path to the backend task definition (./aws/backend.json)ECS_TASK_DEFINITION_CELERY: Path to the Celery task definition (./aws/celery.json)CONTAINER_NAME_BACKEND: Container name for the backend (care-backend)CONTAINER_NAME_WORKER: Container name for the Celery worker (care-worker)CONTAINER_NAME_CRON: Container name for the Celery cron (care-cron)IMAGE_TAG: Tag for the built imageIMAGE_VALUE: Value of the built image