Skip to content

Continuous Deployment

Continuous Deployment is deploying changes to Production without human intervention.

flowchart LR
    DS2[DEPLOY TO TEST] DS2DP2@-.-> DP2[DEPLOY TO PROD]

    DS2DP2@{ animation: fast }

    style DS2 fill:#43F8B6,color:#fff,stroke:none
    style DP2 fill:#43F8B6,color:#fff,stroke:none

In GitHub Actions, continuous deployment can be implemented as multiple deployment jobs chained up via proper usage of needs.

Code Example

Deploying to services in multiple environments

Services in this context can refer to either ECS Fargate Services or AWS Lambda Functions.

flowchart LR
    build@{ label: "Build Image" }
    subgraph CI["Shared Account"]
        ecr@{ label: "ECR" }
    end
    build X@-.-> |Job 1| ecr

    subgraph PROD[AWS — Prod Account]
        ecs_prod@{ label: "Service" }
    end

    subgraph TEST[AWS — Test Account]
        ecs_test@{ label: "Service" }
    end

    ecr Y@-.-> |Job 2| ecs_test
    ecr Z@-.-> |Job 3| ecs_prod

    X@{ animation: fast }
    Y@{ animation: fast }
    Z@{ animation: fast }

    style CI fill:none,stroke:#1a5fe0
    style TEST fill:#fff8f0,stroke:#FF9900
    style PROD fill:#fff0f0,stroke:#cc0000
.github/workflows/cd.yml
name: Continuous Deployment

on:
  push:
    branches: [master]
  workflow_dispatch:

jobs:
  build_push_image_to_shared:
    name: Build image and publish to ECR
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: "Service A"
        uses: BYM-IKT/github-actions/build-and-push-image-to-ecr@master
        with:
          aws-account-id:      "<<AWS_ACCOUNT_ID_TEST>>"        
          ecr-name:            <<ECR_REPOSITORY_NAME>>
          docker-context-path: <<DOCKER_CONTEXT_PATH>>

  deploy_images_to_ecs_service_test:
    needs: [build_push_image_to_shared]
    name: "Deploy to TEST"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-ecs.yml@v0
    with:
      environment:              testing
      aws-account-id-target:    "<<AWS_ACCOUNT_ID_TEST>>"
      ecr-name:                 <<ECR_REPOSITORY_NAME>>
      image-tag-target:         latest
      image-tag-new:            test
      ecs-cluster-name:         <<ECS_CLUSTER_NAME_TEST>>
      ecs-service-name:         <<ECS_SERVICE_NAME_TEST>>

  deploy_images_to_ecs_service_prod:
    needs: [deploy_images_to_ecs_service_test]
    name: "Deploy to PROD"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-ecs.yml@v0
    with:
      environment:              production
      aws-account-id-target:    "<<AWS_ACCOUNT_ID_PROD>>"
      ecr-name:                 <<ECR_REPOSITORY_NAME>>
      image-tag-target:         test
      image-tag-new:            prod
      ecs-cluster-name:         <<ECS_CLUSTER_NAME_PROD>>
      ecs-service-name:         <<ECS_SERVICE_NAME_PROD>>
.github/workflows/cd.yml
name: Continuous Deployment

on:
  push:
    branches: [master]
  workflow_dispatch:

jobs:
  build_push_image_to_shared:
    name: Build image and publish to ECR
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: "Service A"
        uses: BYM-IKT/github-actions/build-and-push-image-to-ecr@master
        with:
          aws-account-id:      "<<AWS_ACCOUNT_ID_TEST>>"        
          ecr-name:            <<ECR_REPOSITORY_NAME>>
          docker-context-path: <<DOCKER_CONTEXT_PATH>>

  deploy_image_to_lambda_function_test:
    needs: [build_push_image_to_shared]
    name: "Deploy to TEST"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-lambda.yml@v0
    with:
      environment:              testing 
      aws-account-id-target:    <<AWS_ACCOUNT_ID_TEST>>
      ecr-name:                 <<ECR_REPOSITORY_NAME>>
      image-tag-target:         latest
      image-tag-new:            test
      lambda-name:              <<LAMBDA_FUNCTION_NAME_TEST>>

  deploy_image_to_lambda_function_prod:
    needs: [deploy_image_to_lambda_function_test]
    name: "Deploy to PROD"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-lambda.yml@v0
    with:
      environment:              production 
      aws-account-id-target:    <<AWS_ACCOUNT_ID_PROD>>
      ecr-name:                 <<ECR_REPOSITORY_NAME>>
      image-tag-target:         test
      image-tag-new:            prod
      lambda-name:              <<LAMBDA_FUNCTION_NAME_PROD>>

Including automatic tests

Sometimes, you might want to run tests on the TEST environment, before proceeding with the deployment to PROD:

flowchart LR
    DS2[DEPLOY TO TEST] DS2E@-.-> DE[Run tests against TEST] DS2DP2@-.-> DP2[DEPLOY TO PROD]

    DS2DP2@{ animation: fast }
    DS2E@{ animation: fast }

    style DS2 fill:#43F8B6,color:#fff,stroke:none
    style DP2 fill:#43F8B6,color:#fff,stroke:none

In GitHub Actions, you can achieve this by adding an intermediate job as follows:

.github/workflows/cd.yml
name: Continuous Deployment

on:
  push:
    branches: [master]
  workflow_dispatch:

jobs:
  build_push_image_to_shared:
    name: Build image and publish to ECR
      ...

  deploy_images_to_ecs_service_test:
    needs: [build_push_image_to_shared]
    name: "Deploy to TEST"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-ecs.yml@v0
      ...

  e2e_tests:
    needs: [deploy_images_to_ecs_service_test]
    name: "Run E2E tests"
    steps:
      ...

  deploy_images_to_ecs_service_prod:
    needs: [e2e_tests]
    name: "Deploy to PROD"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-ecs.yml@v0
      ...