Skip to content

Commit c56a91d

Browse files
CCM-14149 Container Lambda Support (#94)
* CCM-14149: Container Lambda Support * CCM-14149: Container Lambda Support * CCM-14149: Container Lambda Support * CCM-14149: Container Lambda Support * CCM-14149: Container Lambda Support * CCM-14149: Container Lambda Support
1 parent f8e24b0 commit c56a91d

10 files changed

Lines changed: 213 additions & 18 deletions

File tree

docs/package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
terraform 1.9.2
1+
terraform 1.10.1

infrastructure/terraform/components/examplecomponent/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ No requirements.
1616
| <a name="input_force_lambda_code_deploy"></a> [force\_lambda\_code\_deploy](#input\_force\_lambda\_code\_deploy) | If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development | `bool` | `false` | no |
1717
| <a name="input_group"></a> [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes |
1818
| <a name="input_log_retention_in_days"></a> [log\_retention\_in\_days](#input\_log\_retention\_in\_days) | The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite | `number` | `0` | no |
19+
| <a name="input_parent_acct_environment"></a> [parent\_acct\_environment](#input\_parent\_acct\_environment) | Name of the environment responsible for the acct resources used, affects things like DNS zone. Useful for named dev environments | `string` | `"main"` | no |
1920
| <a name="input_project"></a> [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes |
2021
| <a name="input_region"></a> [region](#input\_region) | The AWS Region | `string` | n/a | yes |
2122
## Modules
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# module "example_image_lambda" {
2+
# source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.32/terraform-lambda.zip"
3+
4+
# project = var.project
5+
# environment = var.environment
6+
# component = var.component
7+
# aws_account_id = var.aws_account_id
8+
# region = var.region
9+
# group = var.group
10+
11+
# function_name = "example-image-lambda"
12+
# description = "Example image lambda function"
13+
14+
# kms_key_arn = var.kms_key_arn
15+
16+
# package_type = "Image"
17+
# image_uri = "${var.aws_account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.project}-${var.parent_acct_environment}-acct@${data.aws_ecr_image.example_image_lambda.image_digest}"
18+
# image_repository_names = ["${var.project}-${var.parent_acct_environment}-acct"]
19+
20+
# memory = 128
21+
# timeout = 3
22+
23+
24+
# send_to_firehose = var.send_to_firehose
25+
# log_destination_arn = var.log_destination_arn
26+
# log_retention_in_days = var.log_retention_in_days
27+
# log_subscription_role_arn = var.log_subscription_role_arn
28+
# }
29+
30+
# data "aws_ecr_image" "example_image_lambda" {
31+
# registry_id = var.aws_account_id
32+
# repository_name = "${var.project}-${var.parent_acct_environment}-acct"
33+
# image_tag = "${var.project}-${var.environment}-${var.component}-example-image-lambda-latest"
34+
# }

infrastructure/terraform/components/examplecomponent/module_lambda_example_lambda.tf renamed to infrastructure/terraform/components/examplecomponent/module_lambda_example_zip_lambda.tf

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# module "example_lambda" {
1+
# module "example_zip_lambda" {
22
# source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda?ref=v2.0.10"
33

4-
# function_name = "example-lambda"
5-
# description = "An example lambda function"
4+
# function_name = "example-zip-lambda"
5+
# description = "An example zip lambda function"
66

77
# aws_account_id = var.aws_account_id
88
# component = var.component
@@ -15,12 +15,12 @@
1515
# kms_key_arn = module.kms.key_arn ## Requires shared kms module
1616

1717
# iam_policy_document = {
18-
# body = data.aws_iam_policy_document.example_lambda.json
18+
# body = data.aws_iam_policy_document.example_zip_lambda.json
1919
# }
2020

2121
# function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"]
2222
# function_code_base_path = local.aws_lambda_functions_dir_path
23-
# function_code_dir = "example-lambda/dist"
23+
# function_code_dir = "example-zip-lambda/dist"
2424
# function_include_common = true
2525
# handler_function_name = "handler"
2626
# runtime = "nodejs22.x"
@@ -35,7 +35,7 @@
3535
# }
3636
# }
3737

38-
# data "aws_iam_policy_document" "example_lambda" {
38+
# data "aws_iam_policy_document" "example_zip_lambda" {
3939
# statement {
4040
# sid = "KMSPermissions"
4141
# effect = "Allow"

infrastructure/terraform/components/examplecomponent/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,9 @@ variable "force_lambda_code_deploy" {
6262
description = "If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development"
6363
default = false
6464
}
65+
66+
variable "parent_acct_environment" {
67+
type = string
68+
description = "Name of the environment responsible for the acct resources used, affects things like DNS zone. Useful for named dev environments"
69+
default = "main"
70+
}

lambdas/example-lambda/build.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
rm -rf dist
6+
7+
npx esbuild \
8+
--bundle \
9+
--minify \
10+
--sourcemap \
11+
--target=es2020 \
12+
--platform=node \
13+
--loader:.node=file \
14+
--entry-names=[name] \
15+
--outdir=dist \
16+
src/index.ts ## Update this to include your lambda's entry point
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ARG BASE_IMAGE
2+
3+
FROM ${BASE_IMAGE}
4+
5+
# Copy the built output from the build context (docker.sh should have run build.sh already)
6+
COPY dist/ ${LAMBDA_TASK_ROOT}/
7+
8+
CMD [ "index.handler" ]

lambdas/example-lambda/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"name": "nhs-notify-repository-template-example-lambda",
1515
"private": true,
1616
"scripts": {
17-
"lambda-build": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --loader:.node=file --entry-names=[name] --outdir=dist src/index.ts",
17+
"//": "For a standard zip based Lambda use './build.sh', For a Container based lambda use '../../scripts/lambda-container-build/docker.sh --base-image <base-image>'",
18+
"lambda-build": "./build.sh",
1819
"lint": "eslint .",
1920
"lint:fix": "eslint . --fix",
2021
"test:unit": "jest",
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#!/bin/bash
2+
3+
# Fail fast on errors, unset variables, and pipeline failures.
4+
set -euo pipefail
5+
6+
# Ensure build.sh is executable and build the lambda artifacts before producing the Docker image.
7+
chmod +x ./build.sh
8+
./build.sh
9+
10+
11+
# Parse arguments
12+
BASE_IMAGE=""
13+
while [[ $# -gt 0 ]]; do
14+
case $1 in
15+
--base-image)
16+
BASE_IMAGE="$2"
17+
shift 2
18+
;;
19+
*)
20+
echo "Unknown argument: $1" >&2
21+
exit 1
22+
;;
23+
esac
24+
done
25+
26+
if [[ -z "$BASE_IMAGE" ]]; then
27+
echo "Error: --base-image parameter is required." >&2
28+
exit 1
29+
fi
30+
31+
CSI="${PROJECT}-${ENVIRONMENT}-${COMPONENT}"
32+
ECR_REPO="${ECR_REPO:-nhs-notify-main-acct}"
33+
GHCR_LOGIN_TOKEN="${GITHUB_TOKEN}"
34+
GHCR_LOGIN_USER="${GITHUB_ACTOR}"
35+
LAMBDA_NAME="${LAMBDA_NAME:-$(basename "$PWD")}"
36+
37+
## Set IMAGE_TAG_SUFFIX based on git tag or short SHA for unique lambda image tagging in ECR.
38+
#This ensures that each build produces a uniquely identifiable image, and tagged releases are easily traceable.
39+
echo "Checking if current commit is a tag..."
40+
GIT_TAG="$(git describe --tags --exact-match 2>/dev/null || true)"
41+
if [ -n "$GIT_TAG" ]; then
42+
TAGGED="tag-$GIT_TAG"
43+
echo "On tag: $GIT_TAG, exporting IMAGE_TAG_SUFFIX as tag: $TAGGED"
44+
export IMAGE_TAG_SUFFIX="$TAGGED"
45+
46+
else
47+
SHORT_SHA="sha-$(git rev-parse --short HEAD)"
48+
echo "Not on a tag, exporting IMAGE_TAG_SUFFIX as short SHA: $SHORT_SHA"
49+
export IMAGE_TAG_SUFFIX="$SHORT_SHA"
50+
fi
51+
52+
## Check if we are running in the context of a Terraform apply or plan, and set PUBLISH_LAMBDA_IMAGE accordingly. We only want to push images to ECR on apply, not on plan.
53+
echo "Checking if ACTION is 'apply' to set PUBLISH_LAMBDA_IMAGE..."
54+
if [ "$ACTION" = "apply" ]; then
55+
echo "Setting PUBLISH_LAMBDA_IMAGE to true for apply action"
56+
export PUBLISH_LAMBDA_IMAGE="true"
57+
else
58+
echo "Not setting PUBLISH_LAMBDA_IMAGE for action ($ACTION)"
59+
fi
60+
61+
# Ensure required AWS/ECR configuration is present.
62+
echo "BASE_IMAGE: ${BASE_IMAGE:-<unset>}"
63+
echo "AWS_ACCOUNT_ID: ${AWS_ACCOUNT_ID:-<unset>}"
64+
echo "AWS_REGION: ${AWS_REGION:-<unset>}"
65+
echo "COMPONENT: ${COMPONENT:-<unset>}"
66+
echo "CSI: ${CSI:-<unset>}"
67+
echo "ECR_REPO: ${ECR_REPO:-<unset>}"
68+
echo "ENVIRONMENT: ${ENVIRONMENT:-<unset>}"
69+
echo "GHCR_LOGIN_TOKEN: ${GHCR_LOGIN_TOKEN:-<unset>}"
70+
echo "GHCR_LOGIN_USER: ${GHCR_LOGIN_USER:-<unset>}"
71+
echo "IMAGE_TAG_SUFFIX: ${IMAGE_TAG_SUFFIX:-<unset>}"
72+
echo "LAMBDA_NAME: ${LAMBDA_NAME:-<unset>}"
73+
74+
# Authenticate Docker with AWS ECR using an ephemeral login token.
75+
aws ecr get-login-password --region "${AWS_REGION}" | docker login --username AWS --password-stdin "${AWS_ACCOUNT_ID}".dkr.ecr."${AWS_REGION}".amazonaws.com
76+
77+
# Authenticate to GitHub Container Registry for base images.
78+
if [ -n "${GHCR_LOGIN_USER:-}" ] && [ -n "${GHCR_LOGIN_TOKEN:-}" ]; then
79+
echo "Attempting GHCR login as ${GHCR_LOGIN_USER}..."
80+
if echo "${GHCR_LOGIN_TOKEN}" | docker login ghcr.io --username "${GHCR_LOGIN_USER}" --password-stdin; then
81+
echo "GHCR login successful."
82+
else
83+
echo "GHCR login failed!" >&2
84+
fi
85+
fi
86+
87+
# Namespace tag by CSI and lambda name to avoid cross-environment collisions.
88+
IMAGE_TAG="${CSI}-${LAMBDA_NAME}"
89+
90+
# Compose the full ECR image references.
91+
ECR_REPO_URI="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO}"
92+
93+
# Final tag names we will produce
94+
95+
IMAGE_TAG_LATEST="${ECR_REPO_URI}:${IMAGE_TAG}-latest"
96+
IMAGE_TAG_SUFFIXED="${ECR_REPO_URI}:${IMAGE_TAG}-${IMAGE_TAG_SUFFIX}"
97+
98+
echo "Will build and tag images:"
99+
echo " LATEST -> ${IMAGE_TAG_LATEST}"
100+
echo " SUFFIXED -> ${IMAGE_TAG_SUFFIXED}"
101+
102+
# Build and tag the Docker image for the lambda.
103+
# --load makes the built image available to the local docker daemon (single-platform).
104+
docker buildx build \
105+
-f docker/lambda/Dockerfile \
106+
--platform=linux/amd64 \
107+
--provenance=false \
108+
--sbom=false \
109+
--build-arg BASE_IMAGE="${BASE_IMAGE}" \
110+
-t "${IMAGE_TAG_LATEST}" \
111+
-t "${IMAGE_TAG_SUFFIXED}" \
112+
--load \
113+
.
114+
115+
# Push the image tag(s) to ECR on apply only. The Terraform configuration will reference image digest.
116+
if [ "${PUBLISH_LAMBDA_IMAGE:-false}" = "true" ]; then
117+
echo "PUBLISH_LAMBDA_IMAGE is set to true. Pushing Docker images to ECR..."
118+
119+
120+
for TAG in "${IMAGE_TAG_LATEST}" "${IMAGE_TAG_SUFFIXED}"; do
121+
echo "Pushing ${TAG}..."
122+
docker push "${TAG}"
123+
done
124+
125+
echo "Push complete."
126+
else
127+
echo "PUBLISH_LAMBDA_IMAGE is not set to true (likely TF Plan). Skipping Docker push."
128+
exit 0
129+
fi

0 commit comments

Comments
 (0)