GitHub Actions for ECS Containers
This runbook describes a new process for running CI pipelines to build and deploy containerized applications in AWS. Instead of using AWS CodePipeline we now use GitHub Actions. One other major change is that we now only build 1 image which we promote thru the different environments.
Shared Repository
The first requirement is to create a repository for the container images in the Shared Services AWS account. The process for this is described in the Create A Shared ECR Repository Runbook
Task definitions
The deployment phase of the pipelines rely on task definitions to ensure that the correct tagged version is pulled. Previously when each image was built for each environment the :latest tag was sufficient. Now we need to pull the shared image based on the tag so task definitions need altering to <env>-latest.
For the NACS Server we can see this in the task defination terraform in ecs_task_defination.tf in the following snippet.
}
],
"image": "${var.ecr_repository_mojo_nac_radius.repository_url}:${var.env}-latest",
"logConfiguration": {
"logDriver": "awslogs",
Development pipeline
An example pipeline can be seen in network-access-control-server GitHub repo.
There are a number of secrets/varibles that need setting up in the repository settings, as there are required by the development pipeline.
| Name | Type | Where to find value |
|---|---|---|
| DOCKERHUB_USERNAME | Variable | Parameter Store /moj-network-access-control/docker/username |
| DOCKERHUB_PASSWORD | Secret | Parameter Store /moj-network-access-control/docker/password |
| AWS_ROLE_TO_ASSUME | Secret | IAM Role GitHubWorkflow arn |
| AWS_ROLE_TO_ASSUME_DEV | Secret | Paramter Store /github/shared-services/admin/development/assume_role |
| TOKEN_APP_ID | Secret | Secrets Manager github_app/staff-technology-services-github/app_id |
| TOKEN_APP_PRIVATE_KEY | Secret | Secrets Manager github_app/staff-technology-services-github/private_key |
On every push to main, a number of jobs are run as part of this pipeline, the basic order being.
- Run Integration tests.
- Build and Push the radius server to the shared ECR repo
- Tag the build with a development latest tag
- Tag the build with the commit ID
- Repeat the build and tagging steps for the nginx container
- Deploy the updated containers by updating the ECS service
The steps above rely on a number of reusable work flows in the staff-device-shared-services-actions repo.
Build. Builds the image, tags it latest by default, pushes it to the ECR
Tag. This is additive in that it adds tags and does not replace them. An existing tag is passed and then it is possible to specify an additional tag.
Deploy. This basically runs the “aws ecs update-service” command to ensure that the correct build is running.
Integration tests are kept in the projects own repo as there are likely to be different for each application and a shared workflow is not appropiate for this.
Release pipeline
Triggered by pushing a release-* tag (or manually for rollback). The pipeline promotes an already-built image by retagging it as pre-production-latest, then deploys it to the pre-production ECS services. See this example.
This pipeline runs through the following steps.
- Resolves the image tag to ensure the correct image is upgraded. Normally if run on creation of a release-* tag it will resolve to the git commit id. Alternatively if running manually it is possible to supply the image tag that we wish to use. In a typical rollback situation this would be the commit id of the last known good build.
- Retags PreProd. Based on the tag from the 1st step, this will add the preproduction-latest tag to the image.
- Deploy to pre-production. Runs the update service in the pre-production environmnent.
- Approval gate: After the pre-production deployment completes, the pipeline pauses and requires manual approval before continuing to production.
- After approval, the production-latest tag is added to the image.
- Finally we deploy to production, running update service in the production environment.