Skip to content

Commit fb83f4c

Browse files
Only recreate task definition in infrastructure on critical chances
- Also update deployment pipeline to reset parameter store variable from config
1 parent 08ce90f commit fb83f4c

File tree

8 files changed

+45
-57
lines changed

8 files changed

+45
-57
lines changed

.github/workflows/deploy-application.yml

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ on:
4141
description: The git commit SHA to deploy.
4242
required: true
4343
type: string
44+
app_version:
45+
description: The git ref to deploy (branch, tag, or commit SHA).
46+
required: false
47+
type: string
4448

4549
permissions: {}
4650

@@ -52,11 +56,8 @@ env:
5256
&& 'arn:aws:iam::820242920762:role/GithubDeployMavisAndInfrastructure'
5357
|| 'arn:aws:iam::393416225559:role/GithubDeployMavisAndInfrastructure' }}
5458
aws_account_id: ${{ inputs.environment == 'production' && '820242920762' || '393416225559' }}
55-
web_codedeploy_application: mavis-${{ inputs.environment }}
56-
web_codedeploy_group: blue-green-group-${{ inputs.environment }}
5759
cluster_name: mavis-${{ inputs.environment }}
58-
good_job_service: mavis-${{ inputs.environment }}-good-job
59-
web_service: mavis-${{ inputs.environment }}-web
60+
app_version: ${{ inputs.app_version == '' && 'unknown' || inputs.app_version }}
6061

6162
jobs:
6263
prepare-deployment:
@@ -77,6 +78,13 @@ jobs:
7778
with:
7879
role-to-assume: ${{ env.aws-role }}
7980
aws-region: eu-west-2
81+
- name: Setup python
82+
uses: actions/setup-python@v4
83+
with:
84+
python-version: 3.12.3
85+
cache: pip
86+
- name: Install Python dependencies
87+
run: python3 -m pip install -r script/requirements.txt
8088
- name: Get image digest
8189
id: get-image-digest
8290
run: |
@@ -92,33 +100,39 @@ jobs:
92100
parsed_env_vars=$(yq -r '.environments.${{ inputs.environment }} | to_entries | .[] | .key + "=" + .value' config/container_variables.yml)
93101
echo "parsed_env_vars=$parsed_env_vars" >> $GITHUB_OUTPUT
94102
- name: Populate web task definition
95-
if: inputs.server_types == 'web' || inputs.server_types == 'all'
103+
if: ${{ inputs.server_types == 'web' || inputs.server_types == 'all' }}
96104
id: create-web-task-definition
97105
uses: aws-actions/amazon-ecs-render-task-definition@v1
98106
with:
99107
task-definition-family: "mavis-web-task-definition-${{ inputs.environment }}"
100108
container-name: "application"
101109
image: "${{ env.aws_account_id }}.dkr.ecr.eu-west-2.amazonaws.com/mavis/webapp@${{ steps.get-image-digest.outputs.digest }}"
102110
environment-variables: ${{ steps.parse-environment-variables.outputs.parsed_env_vars }}
103-
secrets: | # We can define secrets here too if we want
104-
RAILS_MASTER_KEY=/copilot/mavis/secrets/STAGING_RAILS_MASTER_KEY
105111
- name: Populate good-job task definition
106-
if: inputs.server_types == 'good-job' || inputs.server_types == 'all'
112+
if: ${{ inputs.server_types == 'good-job' || inputs.server_types == 'all' }}
107113
id: create-good-job-task-definition
108114
uses: aws-actions/amazon-ecs-render-task-definition@v1
109115
with:
110116
task-definition-family: "mavis-good-job-task-definition-${{ inputs.environment }}"
111117
container-name: "application"
112118
image: "${{ env.aws_account_id }}.dkr.ecr.eu-west-2.amazonaws.com/mavis/webapp@${{ steps.get-image-digest.outputs.digest }}"
113119
environment-variables: ${{ steps.parse-environment-variables.outputs.parsed_env_vars }}
120+
- name: Populate SSM parameters for web service
121+
if: ${{ inputs.server_types == 'web' || inputs.server_types == 'all' }}
122+
run: |
123+
python3 script/populate_ssm_parameters.py ${{ inputs.environment }} web --app-version ${{ env.app_version }}
124+
- name: Populate SSM parameters for good-job service
125+
if: ${{ inputs.server_types == 'good-job' || inputs.server_types == 'all' }}
126+
run: |
127+
python3 script/populate_ssm_parameters.py ${{ inputs.environment }} good-job --app-version ${{ env.app_version }}
114128
- name: Upload artifact for web task definition
115-
if: inputs.server_types == 'web' || inputs.server_types == 'all'
129+
if: ${{ inputs.server_types == 'web' || inputs.server_types == 'all' }}
116130
uses: actions/upload-artifact@v4
117131
with:
118132
name: ${{ inputs.environment }}-web-task-definition
119133
path: ${{ steps.create-web-task-definition.outputs.task-definition }}
120134
- name: Upload artifact for good-job task definition
121-
if: inputs.server_types == 'good-job' || inputs.server_types == 'all'
135+
if: ${{ inputs.server_types == 'good-job' || inputs.server_types == 'all' }}
122136
uses: actions/upload-artifact@v4
123137
with:
124138
name: ${{ inputs.environment }}-good-job-task-definition
@@ -134,7 +148,7 @@ jobs:
134148
deploy-web:
135149
name: Deploy web service
136150
runs-on: ubuntu-latest
137-
if: inputs.server_types == 'web' || inputs.server_types == 'all'
151+
if: ${{ inputs.server_types == 'web' || inputs.server_types == 'all' }}
138152
needs: [ prepare-deployment, approve-deployments ]
139153
permissions:
140154
id-token: write
@@ -166,9 +180,9 @@ jobs:
166180
task-definition: ${{ needs.prepare-deployment.outputs.web-task-definition-path }}
167181
codedeploy-appspec: appspec.yaml
168182
cluster: ${{ env.cluster_name }}
169-
service: ${{ env.web_service }}
170-
codedeploy-application: ${{ env.web_codedeploy_application }}
171-
codedeploy-deployment-group: ${{ env.web_codedeploy_group }}
183+
service: mavis-${{ inputs.environment }}-web
184+
codedeploy-application: mavis-${{ inputs.environment }}
185+
codedeploy-deployment-group: blue-green-group-${{ inputs.environment }}
172186
- name: Wait for deployment to complete
173187
run: |
174188
echo "Waiting for CodeDeploy deployment ${{ steps.deploy-web-service.outputs.codedeploy-deployment-id }} to complete..."
@@ -178,7 +192,7 @@ jobs:
178192
deploy-good-job:
179193
name: Deploy good-job service
180194
runs-on: ubuntu-latest
181-
if: inputs.server_types == 'good-job' || inputs.server_types == 'all'
195+
if: ${{ inputs.server_types == 'good-job' || inputs.server_types == 'all' }}
182196
needs: [ prepare-deployment, approve-deployments ]
183197
permissions:
184198
id-token: write
@@ -198,6 +212,6 @@ jobs:
198212
with:
199213
task-definition: ${{ needs.prepare-deployment.outputs.good-job-task-definition-path }}
200214
cluster: ${{ env.cluster_name }}
201-
service: ${{ env.good_job_service }}
215+
service: mavis-${{ inputs.environment }}-good-job
202216
force-new-deployment: true
203217
wait-for-service-stability: true

.github/workflows/deploy-infrastructure.yml

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,6 @@ jobs:
4848
with:
4949
role-to-assume: ${{ env.aws_role }}
5050
aws-region: eu-west-2
51-
- name: Set image tag
52-
run: |
53-
IMAGE_TAG="${{ inputs.image_tag || github.sha }}"
54-
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
55-
- name: Login to ECR
56-
id: login-ecr
57-
uses: aws-actions/amazon-ecr-login@v2
58-
- name: Pull Docker image
59-
run: |
60-
set -e
61-
DOCKER_IMAGE="${{ steps.login-ecr.outputs.registry }}/mavis/webapp:${IMAGE_TAG}"
62-
docker pull "$DOCKER_IMAGE"
63-
echo "DOCKER_IMAGE=$DOCKER_IMAGE" >> $GITHUB_ENV
64-
- name: Extract image digest
65-
run: |
66-
set -e
67-
DOCKER_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$DOCKER_IMAGE")
68-
DIGEST="${DOCKER_DIGEST#*@}"
69-
echo "DIGEST=$DIGEST" >> $GITHUB_ENV
7051
- name: Install terraform
7152
uses: hashicorp/setup-terraform@v3
7253
with:
@@ -78,7 +59,7 @@ jobs:
7859
run: |
7960
set -e
8061
terraform init -backend-config="env/${{ inputs.environment }}-backend.hcl" -upgrade
81-
terraform plan -var="image_digest=$DIGEST" -var="app_version=${{ env.git_ref_to_deploy }}" \
62+
terraform plan \
8263
-var-file="env/${{ inputs.environment }}.tfvars" \
8364
-out ${{ runner.temp }}/tfplan | tee ${{ runner.temp }}/tf_stdout
8465
TF_EXIT_CODE=${PIPESTATUS[0]}

.github/workflows/deploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,4 @@ jobs:
155155
environment: ${{ inputs.environment }}
156156
server_types: ${{ inputs.server_types }}
157157
git_sha_to_deploy: ${{ needs.determine-git-sha.outputs.git-sha }}
158+
app_version: ${{ inputs.git_ref_to_deploy }}

script/populate_ssm_parameters.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ def extract_cloud_variables(config: Dict[str, Any], environment: str, server_typ
3333
return cloud_vars
3434

3535

36-
def update_ssm_parameter(parameter_name: str, values: List[str]) -> None:
36+
def update_ssm_parameter(parameter_name: str, values: List[str], app_version: str) -> None:
3737
"""Update SSM parameter with StringList values."""
3838
try:
3939
ssm = boto3.client('ssm')
40-
40+
values.append(f"app_version={app_version}")
4141
string_list = ','.join(values)
4242

4343
print(f"Updating SSM parameter: {parameter_name}")
@@ -69,6 +69,7 @@ def main():
6969
parser.add_argument('server_type', help='Server type')
7070
parser.add_argument('-c', '--config-file', default='config/container_variables.yml',
7171
help='Container variables file path (default: config/container_variables.yml)')
72+
parser.add_argument('--app-version', default='unknown', help='Application version (default: unknown)')
7273

7374
args = parser.parse_args()
7475

@@ -81,7 +82,7 @@ def main():
8182
cloud_vars = extract_cloud_variables(config, args.environment, args.server_type)
8283

8384
ssm_parameter_path = f"/{args.environment}/envs/{args.server_type}"
84-
update_ssm_parameter(ssm_parameter_path, cloud_vars)
85+
update_ssm_parameter(ssm_parameter_path, cloud_vars, args.app_version)
8586

8687
print(f"Cloud variables updated successfully")
8788

terraform/app/ecs.tf

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ module "web_service" {
3131
}])
3232
cpu = 1024
3333
memory = 2048
34-
docker_image = "${var.account_id}.dkr.ecr.eu-west-2.amazonaws.com/${var.docker_image}@${var.image_digest}"
3534
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
3635
task_role_arn = aws_iam_role.ecs_task_role.arn
3736
log_group_name = aws_cloudwatch_log_group.ecs_log_group.name
@@ -75,7 +74,6 @@ module "good_job_service" {
7574
}])
7675
cpu = 1024
7776
memory = 2048
78-
docker_image = "${var.account_id}.dkr.ecr.eu-west-2.amazonaws.com/${var.docker_image}@${var.image_digest}"
7977
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
8078
task_role_arn = aws_iam_role.ecs_task_role.arn
8179
log_group_name = aws_cloudwatch_log_group.ecs_log_group.name

terraform/app/modules/ecs_service/main.tf

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ resource "aws_ecs_service" "this" {
6969
}
7070
}
7171

72+
resource "terraform_data" "this" {
73+
input = [
74+
var.server_type, var.task_config, var.container_name
75+
]
76+
}
77+
7278
resource "aws_ecs_task_definition" "this" {
7379
family = "mavis-${local.server_type_name}-task-definition-${var.environment}"
7480
requires_compatibilities = ["FARGATE"]
@@ -80,7 +86,7 @@ resource "aws_ecs_task_definition" "this" {
8086
container_definitions = jsonencode([
8187
{
8288
name = var.container_name
83-
image = var.task_config.docker_image
89+
image = "CHANGE_ME"
8490
essential = true
8591
readonlyRootFileSystem = true
8692
portMappings = [
@@ -109,7 +115,8 @@ resource "aws_ecs_task_definition" "this" {
109115
}
110116
])
111117
lifecycle {
112-
ignore_changes = all
118+
ignore_changes = all
119+
replace_triggered_by = [terraform_data.this]
113120
}
114121
}
115122

terraform/app/modules/ecs_service/variables.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ variable "task_config" {
5858
}))
5959
cpu = number
6060
memory = number
61-
docker_image = string
6261
execution_role_arn = string
6362
task_role_arn = string
6463
log_group_name = string

terraform/app/variables.tf

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,19 +104,6 @@ variable "rails_master_key_path" {
104104
nullable = false
105105
}
106106

107-
variable "docker_image" {
108-
type = string
109-
default = "mavis/webapp"
110-
description = "The docker image name for the essential container in the task definition"
111-
nullable = false
112-
}
113-
114-
variable "image_digest" {
115-
type = string
116-
description = "The docker image digest for the essential container in the task definition."
117-
nullable = false
118-
}
119-
120107
locals {
121108
is_production = var.environment == "production"
122109
parameter_store_variables = tomap({ #TODO: Remove this once all variables are sourced from application config

0 commit comments

Comments
 (0)