Skip to content

Commit 3d9fee6

Browse files
authored
Merge pull request #12 from MITLibraries/update-lambda-deploy
Deployment Workflow Updates for Provisioned Concurrency
2 parents eccf2f7 + a081e45 commit 3d9fee6

4 files changed

Lines changed: 204 additions & 1 deletion

File tree

.github/workflows/dev-build.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,67 @@ jobs:
5858
CPU_ARCH: ${{ needs.prep.outputs.cpuarch }}
5959
FUNCTION: "timdex-semantic-builder-dev"
6060
# PREBUILD:
61+
62+
# The following section is specific to this function because this is our first
63+
# Lambda function that requires provisioned capacity to stay warm. As a
64+
# consequence, we need to ensure that the Lambda is "published" and that the
65+
# Lambda alias points at the latest published version. We may eventually move
66+
# this to the shared workflow...
67+
publish:
68+
needs: deploy
69+
name: Publish and Update Alias
70+
env:
71+
AWS_REGION: "us-east-1"
72+
GHA_ROLE: "timdex-semantic-builder-gha-dev"
73+
FUNCTION: "timdex-semantic-builder-dev"
74+
runs-on: ubuntu-latest
75+
steps:
76+
77+
- name: Configure AWS credentials
78+
uses: aws-actions/configure-aws-credentials@v6
79+
with:
80+
aws-region: us-east-1
81+
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCT_DEV }}:role/${{ env.GHA_ROLE }}
82+
83+
- name: Publish New Version
84+
id: version
85+
run: |
86+
echo "Waiting for updated Lambda function to be ready"
87+
aws lambda wait function-updated-v2 --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }}
88+
echo "New updated Lambda is ready."
89+
echo "### Publish New Version of the Lambda" >> $GITHUB_STEP_SUMMARY
90+
VERSION=$(aws lambda publish-version --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --query 'Version' --output text)
91+
echo "lambda_version=$VERSION" >> $GITHUB_OUTPUT
92+
aws lambda wait published-version-active --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --qualifier $VERSION
93+
echo "New published Lambda is ready."
94+
echo "New published Lambda version = $VERSION" >> $GITHUB_STEP_SUMMARY
95+
96+
- name: Update Lambda Alias
97+
id: alias
98+
env:
99+
VERSION: ${{ steps.version.outputs.lambda_version }}
100+
run: |
101+
echo "### Update Lambda Alias" >> $GITHUB_STEP_SUMMARY
102+
ALIAS_VERSION=$(aws lambda update-alias --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --name live --function-version ${{ env.VERSION }} --routing-config '{}' --query 'FunctionVersion' --output text)
103+
echo "Lambda alias linked to function version $ALIAS_VERSION" >> $GITHUB_STEP_SUMMARY
104+
105+
- name: Cleanup Lambda Versions
106+
id: cleanup
107+
run: |
108+
echo "### Cleanup Lambda Versions" >> $GITHUB_STEP_SUMMARY
109+
VERSIONS=$(aws lambda list-versions-by-function --function-name ${{ env.FUNCTION }} --query 'Versions[?Version!=`$LATEST`].Version')
110+
echo "Current versions:"
111+
echo "$VERSIONS"
112+
VERSIONS_TO_DELETE=$(echo "$VERSIONS" | jq -r 'sort_by(tonumber) | .[:-2] | .[]')
113+
echo "Versions to delete:"
114+
echo "$VERSIONS_TO_DELETE"
115+
while read VERSION; do
116+
if [ -n "$VERSION" ]; then
117+
echo "Deleting version: $VERSION"
118+
aws lambda delete-function \
119+
--function-name ${{ env.FUNCTION }} \
120+
--qualifier "$VERSION"
121+
fi
122+
done <<< "$VERSIONS_TO_DELETE"
123+
CURRENT_VERSIONS=$(aws lambda list-versions-by-function --function-name ${{ env.FUNCTION }} --query 'Versions[?Version!=`$LATEST`].Version' --output text)
124+
echo "Current available versions of the Lambda: $CURRENT_VERSIONS" >> $GITHUB_STEP_SUMMARY

.github/workflows/prod-deploy.yml

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,67 @@ jobs:
5454
ECR_PROD: "timdex-semantic-builder-prod"
5555
CPU_ARCH: ${{ needs.prep.outputs.cpuarch }}
5656
FUNCTION: "timdex-semantic-builder-prod"
57-
57+
58+
# The following section is specific to this function because this is our first
59+
# Lambda function that requires provisioned capacity to stay warm. As a
60+
# consequence, we need to ensure that the Lambda is "published" and that the
61+
# Lambda alias points at the latest published version. We may eventually move
62+
# this to the shared workflow...
63+
publish:
64+
needs: deploy
65+
name: Publish and Update Alias
66+
env:
67+
AWS_REGION: "us-east-1"
68+
GHA_ROLE: "timdex-semantic-builder-gha-prod"
69+
FUNCTION: "timdex-semantic-builder-prod"
70+
runs-on: ubuntu-latest
71+
steps:
72+
73+
- name: Configure AWS credentials
74+
uses: aws-actions/configure-aws-credentials@v6
75+
with:
76+
aws-region: us-east-1
77+
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCT_PROD }}:role/${{ env.GHA_ROLE }}
78+
79+
- name: Publish New Version
80+
id: version
81+
run: |
82+
echo "Waiting for updated Lambda function to be ready"
83+
aws lambda wait function-updated-v2 --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }}
84+
echo "New updated Lambda is ready."
85+
echo "### Publish New Version of the Lambda" >> $GITHUB_STEP_SUMMARY
86+
VERSION=$(aws lambda publish-version --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --query 'Version' --output text)
87+
echo "lambda_version=$VERSION" >> $GITHUB_OUTPUT
88+
aws lambda wait published-version-active --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --qualifier $VERSION
89+
echo "New published Lambda is ready."
90+
echo "New published Lambda version = $VERSION" >> $GITHUB_STEP_SUMMARY
91+
92+
- name: Update Lambda Alias
93+
env:
94+
VERSION: ${{ steps.version.outputs.lambda_version }}
95+
id: alias
96+
run: |
97+
echo "### Update Lambda Alias" >> $GITHUB_STEP_SUMMARY
98+
ALIAS_VERSION=$(aws lambda update-alias --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --name live --function-version ${{ env.VERSION }} --routing-config '{}' --query 'FunctionVersion' --output text)
99+
echo "Lambda alias linked to function version $ALIAS_VERSION" >> $GITHUB_STEP_SUMMARY
100+
101+
- name: Cleanup Lambda Versions
102+
id: cleanup
103+
run: |
104+
echo "### Cleanup Lambda Versions" >> $GITHUB_STEP_SUMMARY
105+
VERSIONS=$(aws lambda list-versions-by-function --function-name ${{ env.FUNCTION }} --query 'Versions[?Version!=`$LATEST`].Version')
106+
echo "Current versions:"
107+
echo "$VERSIONS"
108+
VERSIONS_TO_DELETE=$(echo "$VERSIONS" | jq -r 'sort_by(tonumber) | .[:-2] | .[]')
109+
echo "Versions to delete:"
110+
echo "$VERSIONS_TO_DELETE"
111+
while read VERSION; do
112+
if [ -n "$VERSION" ]; then
113+
echo "Deleting version: $VERSION"
114+
aws lambda delete-function \
115+
--function-name ${{ env.FUNCTION }} \
116+
--qualifier "$VERSION"
117+
fi
118+
done <<< "$VERSIONS_TO_DELETE"
119+
CURRENT_VERSIONS=$(aws lambda list-versions-by-function --function-name ${{ env.FUNCTION }} --query 'Versions[?Version!=`$LATEST`].Version' --output text)
120+
echo "Current available versions of the Lambda: $CURRENT_VERSIONS" >> $GITHUB_STEP_SUMMARY

.github/workflows/stage-build.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,67 @@ jobs:
5858
CPU_ARCH: ${{ needs.prep.outputs.cpuarch }}
5959
FUNCTION: "timdex-semantic-builder-stage"
6060
# PREBUILD:
61+
62+
# The following section is specific to this function because this is our first
63+
# Lambda function that requires provisioned capacity to stay warm. As a
64+
# consequence, we need to ensure that the Lambda is "published" and that the
65+
# Lambda alias points at the latest published version. We may eventually move
66+
# this to the shared workflow...
67+
publish:
68+
needs: deploy
69+
name: Publish and Update Alias
70+
env:
71+
AWS_REGION: "us-east-1"
72+
GHA_ROLE: "timdex-semantic-builder-gha-stage"
73+
FUNCTION: "timdex-semantic-builder-stage"
74+
runs-on: ubuntu-latest
75+
steps:
76+
77+
- name: Configure AWS credentials
78+
uses: aws-actions/configure-aws-credentials@v6
79+
with:
80+
aws-region: us-east-1
81+
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCT_STAGE }}:role/${{ env.GHA_ROLE }}
82+
83+
- name: Publish New Version
84+
id: version
85+
run: |
86+
echo "Waiting for updated Lambda function to be ready"
87+
aws lambda wait function-updated-v2 --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }}
88+
echo "New updated Lambda is ready."
89+
echo "### Publish New Version of the Lambda" >> $GITHUB_STEP_SUMMARY
90+
VERSION=$(aws lambda publish-version --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --query 'Version' --output text)
91+
echo "lambda_version=$VERSION" >> $GITHUB_OUTPUT
92+
aws lambda wait published-version-active --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --qualifier $VERSION
93+
echo "New published Lambda is ready."
94+
echo "New published Lambda version = $VERSION" >> $GITHUB_STEP_SUMMARY
95+
96+
- name: Update Lambda Alias
97+
env:
98+
VERSION: ${{ steps.version.outputs.lambda_version }}
99+
id: alias
100+
run: |
101+
echo "### Update Lambda Alias" >> $GITHUB_STEP_SUMMARY
102+
ALIAS_VERSION=$(aws lambda update-alias --region ${{ env.AWS_REGION }} --function-name ${{ env.FUNCTION }} --name live --function-version ${{ env.VERSION }} --routing-config '{}' --query 'FunctionVersion' --output text)
103+
echo "Lambda alias linked to function version $ALIAS_VERSION" >> $GITHUB_STEP_SUMMARY
104+
105+
- name: Cleanup Lambda Versions
106+
id: cleanup
107+
run: |
108+
echo "### Cleanup Lambda Versions" >> $GITHUB_STEP_SUMMARY
109+
VERSIONS=$(aws lambda list-versions-by-function --function-name ${{ env.FUNCTION }} --query 'Versions[?Version!=`$LATEST`].Version')
110+
echo "Current versions:"
111+
echo "$VERSIONS"
112+
VERSIONS_TO_DELETE=$(echo "$VERSIONS" | jq -r 'sort_by(tonumber) | .[:-2] | .[]')
113+
echo "Versions to delete:"
114+
echo "$VERSIONS_TO_DELETE"
115+
while read VERSION; do
116+
if [ -n "$VERSION" ]; then
117+
echo "Deleting version: $VERSION"
118+
aws lambda delete-function \
119+
--function-name ${{ env.FUNCTION }} \
120+
--qualifier "$VERSION"
121+
fi
122+
done <<< "$VERSIONS_TO_DELETE"
123+
CURRENT_VERSIONS=$(aws lambda list-versions-by-function --function-name ${{ env.FUNCTION }} --query 'Versions[?Version!=`$LATEST`].Version' --output text)
124+
echo "Current available versions of the Lambda: $CURRENT_VERSIONS" >> $GITHUB_STEP_SUMMARY

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,18 @@ Response:
161161
}
162162
```
163163

164+
## Notes on automated deployment in AWS
165+
166+
Due to the need for provisioned concurrency to keep this Lambda warm, it diverges a bit from our standard dev/stage/prod deployment workflows as noted below.
167+
168+
Each of the three GitHub Actions workflows ([dev-build](.github/workflows/dev-build.yml), [stage-build](.github/workflows/stage-build.yml), [prod-deploy](.github/workflows/prod-deploy.yml)) has an additional job to handle the extra deployment steps to ensure that the provisioned concurrency works correctly. This job handles three steps:
169+
170+
1. Publish the latest version of the Lambda function.
171+
1. Update the "live" alias to the function so that it points to the most recent published version of the function.
172+
1. Clean up leftover published versions of the function, leaving the latest and next-most latest published versions in place.
173+
174+
These extra steps are necessary because the infrastructure configures a Lambda alias and associates the provisioned concurrency to that alias.
175+
164176
## Environment Variables
165177

166178
In local development, you can add a `.env` file to manage these. The file is excluded from git and docker builds via

0 commit comments

Comments
 (0)