From 0d3533ac67879a4b246a007ad7be8e782819cb55 Mon Sep 17 00:00:00 2001 From: David Wilkie Date: Tue, 22 Aug 2023 21:32:17 +0700 Subject: [PATCH] Upgrade media-proxy infrastructure (#297) --- .github/workflows/media_proxy.yml | 75 +++++++------ .tool-versions | 2 +- components/media_proxy/Dockerfile | 20 ++-- infrastructure/core/.terraform.lock.hcl | 29 ++--- infrastructure/core/codebuild.tf | 102 ++++++++++++++++++ .../modules/container_instances/main.tf | 11 +- .../modules/container_instances/variables.tf | 9 ++ 7 files changed, 191 insertions(+), 57 deletions(-) create mode 100644 infrastructure/core/codebuild.tf diff --git a/.github/workflows/media_proxy.yml b/.github/workflows/media_proxy.yml index 2d7351f9b..539a7b065 100644 --- a/.github/workflows/media_proxy.yml +++ b/.github/workflows/media_proxy.yml @@ -1,6 +1,11 @@ name: Media Proxy on: push +env: + IMAGE_TAG: ${{ github.sha }} + ECR_REGISTRY: public.ecr.aws/somleng + GHCR_REGISTRY: ghcr.io/somleng + jobs: build: name: Build @@ -9,8 +14,6 @@ jobs: matrix: ${{ steps.set-deployment-matrix.outputs.matrix }} matrixLength: ${{ steps.set-deployment-matrix.outputs.matrixLength }} - # Render task definition doesn't support working directory - # https://github.com/aws-actions/amazon-ecs-render-task-definition/issues/68#issuecomment-881407765 steps: - name: Set Deployment Matrix id: set-deployment-matrix @@ -36,38 +39,30 @@ jobs: EOF ) matrix=$(echo $matrixSource | jq --arg branchName "$branchName" 'map(. | select((.branch==$branchName)) )') - echo ::set-output name=matrix::{\"include\":$(echo $matrix)}\" - echo ::set-output name=matrixLength::$(echo $matrix | jq length) + echo "matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT + echo "matrixLength=$(echo $matrix | jq length)" >> $GITHUB_OUTPUT - deploy: - name: Deploy + build-packages: + name: Build Packages runs-on: ubuntu-latest - needs: - - build - if: needs.build.outputs.matrixLength > 0 + defaults: run: working-directory: components/media_proxy - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: ap-southeast-1 - ECR_PUBLIC_REGISTRY: public.ecr.aws - ECR_REPOSITORY: public.ecr.aws/somleng/media-proxy - GHCR_REPOSITORY: ghcr.io/somleng/media-proxy - IMAGE_TAG: ${{ github.sha }} + needs: + - build strategy: - matrix: ${{fromJson(needs.build.outputs.matrix)}} + matrix: ${{fromJSON(needs.build.outputs.matrix)}} + fail-fast: false steps: - name: Checkout uses: actions/checkout@v3 - name: Configure AWS credentials - id: aws-login uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -80,7 +75,7 @@ jobs: - name: Login to AWS Public ECR uses: docker/login-action@v2 with: - registry: ${{ env.ECR_PUBLIC_REGISTRY }} + registry: public.ecr.aws env: AWS_REGION: us-east-1 @@ -91,9 +86,6 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -102,25 +94,48 @@ jobs: with: context: components/media_proxy push: true - platforms: linux/amd64 cache-from: type=gha,scope=${{ matrix.identifier }} cache-to: type=gha,mode=max,scope=${{ matrix.identifier }} tags: | - ${{ env.ECR_REPOSITORY }}:${{ matrix.image_tag }} - ${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} - ${{ env.GHCR_REPOSITORY }}:${{ matrix.image_tag }} + ${{ env.ECR_REGISTRY }}/media-proxy:${{ matrix.image_tag }} + ${{ env.ECR_REGISTRY }}/media-proxy:${{ env.IMAGE_TAG }} + ${{ env.GHCR_REGISTRY }}/media-proxy:${{ matrix.image_tag }} + + deploy: + name: Deploy + runs-on: ubuntu-latest + if: needs.build.outputs.matrixLength > 0 + + needs: + - build + - build-packages + + strategy: + matrix: ${{fromJson(needs.build.outputs.matrix)}} + + steps: + - name: Configure AWS credentials + id: aws-login + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + role-skip-session-tagging: true + role-duration-seconds: 3600 + aws-region: ap-southeast-1 - name: Get current task definition run: | aws ecs describe-task-definition --task-definition "${{ matrix.identifier }}" --query 'taskDefinition' > task-definition.json - - name: Prepare task definition + - name: Inject new image into task definition id: render-task-def uses: aws-actions/amazon-ecs-render-task-definition@v1 with: - task-definition: components/media_proxy/task-definition.json + task-definition: task-definition.json container-name: media_proxy - image: ${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} + image: ${{ env.ECR_REGISTRY }}/media-proxy:${{ env.IMAGE_TAG }} - name: Deploy uses: aws-actions/amazon-ecs-deploy-task-definition@v1 diff --git a/.tool-versions b/.tool-versions index 5e16f9bf6..0743ddecd 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -terraform 1.2.8 +terraform 1.5.5 diff --git a/components/media_proxy/Dockerfile b/components/media_proxy/Dockerfile index 922ea68b8..3b981a9d2 100644 --- a/components/media_proxy/Dockerfile +++ b/components/media_proxy/Dockerfile @@ -1,21 +1,21 @@ -FROM debian:bullseye-slim +FROM public.ecr.aws/debian/debian:bookworm-slim USER root ENV DEBIAN_FRONTEND noninteractive -ARG REL=10.5 -ARG DIST=bullseye +ARG REL=latest +ARG DIST=bookworm WORKDIR /tmp -RUN apt-get -y update -qq && apt-get -y install ca-certificates wget -RUN wget https://dfx.at/rtpengine/latest/pool/main/r/rtpengine-dfx-repo-keyring/rtpengine-dfx-repo-keyring_1.0_all.deb -RUN dpkg -i rtpengine-dfx-repo-keyring_1.0_all.deb -RUN echo "deb [signed-by=/usr/share/keyrings/dfx.at-rtpengine-archive-keyring.gpg] https://dfx.at/rtpengine/$REL $DIST main" | tee /etc/apt/sources.list.d/dfx.at-rtpengine.list -RUN apt-get -y update -qq && apt-get -y install rtpengine netcat jq curl -RUN apt-get purge -y --auto-remove wget -RUN rm -rf /var/lib/apt/lists/* +RUN apt-get -y update -qq && apt-get -y install ca-certificates wget \ + && wget https://dfx.at/rtpengine/latest/pool/main/r/rtpengine-dfx-repo-keyring/rtpengine-dfx-repo-keyring_1.0_all.deb \ + && dpkg -i rtpengine-dfx-repo-keyring_1.0_all.deb \ + && echo "deb [signed-by=/usr/share/keyrings/dfx.at-rtpengine-archive-keyring.gpg] https://dfx.at/rtpengine/$REL $DIST main" | tee /etc/apt/sources.list.d/dfx.at-rtpengine.list \ + && apt-get -y update -qq && apt-get -y install rtpengine netcat-traditional jq curl \ + && apt-get purge -y --auto-remove wget \ + && rm -rf /var/lib/apt/lists/* COPY docker-entrypoint.sh /docker-entrypoint.sh diff --git a/infrastructure/core/.terraform.lock.hcl b/infrastructure/core/.terraform.lock.hcl index 914c55dd8..ce1f4fe70 100644 --- a/infrastructure/core/.terraform.lock.hcl +++ b/infrastructure/core/.terraform.lock.hcl @@ -2,20 +2,23 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { - version = "4.19.0" + version = "5.13.1" hashes = [ - "h1:Q1pATpL2UxF68UEvZ95Ocsf4HzdMuzuWu8SjV/8WR40=", - "zh:22820bfa0065f583298015367f8dc015dffa5b19b76dbd78ecf5da8d7d599573", - "zh:31a5c5fade4bd30dbc2b15f448cebb9ed527793c607e8687d3b2101bcf2c4471", - "zh:37c9e469e51aa835a5542510561397541de08b62fc15292588382932624fcf88", - "zh:398bfe1ba7428ef03293c6618067ddd8c0aaae8bbe764177ae951259228af724", - "zh:4610f5a93ef956103d719ae73872a52ecd6cb321452c26a879896348bc27eed9", - "zh:4a0d570dc5f01f41538b4eb70086a00dfb25c5d00fd27c950ac209d3609486f6", - "zh:4fb65ce84801f82a3beb4e2cb72c5d52ca04d4717ed3890b206da346f02d5def", + "h1:spYQK/G02YRkTfSCnmzLTIIygC+dVQ1axbGgElzhw5w=", + "zh:0d107e410ecfbd5d2fb5ff9793f88e2ce03ae5b3bda4e3b772b5d146cdd859d8", + "zh:1080cf6a402939ec4ad393380f2ab2dfdc0e175903e08ed796aa22eb95868847", + "zh:300420d642c3ada48cfe633444eafa7bcd410cd6a8503de2384f14ac54dc3ce3", + "zh:4e0121014a8d6ef0b1ab4634877545737bb54e951340f1b67ffea8cd22b2d252", + "zh:59b401bbf95dc8c6bea58085ff286543380f176271251193eac09cb7fcf619b7", + "zh:5dfaf51e979131710ce8e1572e6012564e68c7c842e3d9caaaeb0fe6af15c351", + "zh:84bb75dafca056d7c3783be5185187fdd3294f902e9d72f7655f2efb5e066650", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9bb3919bd6d94fb22025540f0c1db5eceec8927bd71b8fbdcd295609c999065f", - "zh:ce2623a13f74677cdb948607e456ce00407c57333b8310d5c9d053fc3defbc78", - "zh:e0d57e8784e6ccfa96fdd07ae1ddcc947be242bc11e7a5dd16b520b4204e0d09", - "zh:f988b7c37e95a5b3a493a6b9dcc5ed270136f97d5c0effa84a51940f71626c12", + "zh:aa4e2b9f699d497041679bc05ca34ac21a5184298eb1813f35455b1883977910", + "zh:b51a4f08d84b071128df68a95cfa5114301a50bf8ab8e655dcf7e384e5bc6458", + "zh:bce284ac6ebb65053d9b703048e3157bf4175782ea9dbaec9f64dc2b6fcefb0c", + "zh:c748f78b79b354794098b06b18a02aefdb49be144dff8876c9204083980f7de0", + "zh:ee69d9aef5ca532392cdc26499096f3fa6e55f8622387f78194ebfaadb796aef", + "zh:ef561bee58e4976474bc056649095737fa3b2bcb74602032415d770bfc620c1f", + "zh:f696d8416c57c31f144d432779ba34764560a95937db3bb3dd2892a791a6d5a7", ] } diff --git a/infrastructure/core/codebuild.tf b/infrastructure/core/codebuild.tf new file mode 100644 index 000000000..cc36d2c40 --- /dev/null +++ b/infrastructure/core/codebuild.tf @@ -0,0 +1,102 @@ +locals { + codebuild_identifier = "somleng-switch" +} + +data "aws_iam_policy_document" "codebuild_assume_role" { + statement { + effect = "Allow" + + principals { + type = "Service" + identifiers = ["codebuild.amazonaws.com"] + } + + actions = ["sts:AssumeRole"] + } +} + +resource "aws_iam_role" "codebuild" { + name = "codebuild-${local.codebuild_identifier}" + assume_role_policy = data.aws_iam_policy_document.codebuild_assume_role.json +} + +data "aws_iam_policy_document" "codebuild" { + statement { + effect = "Allow" + + resources = [ + "arn:aws:logs:*:*:log-group:/aws/codebuild/${local.codebuild_identifier}*", + "arn:aws:logs:*:*:log-group:/aws/codebuild/${local.codebuild_identifier}*:*" + ] + + actions = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ] + } +} + +resource "aws_iam_role_policy" "codebuild" { + role = aws_iam_role.codebuild.name + policy = data.aws_iam_policy_document.codebuild.json +} + +resource "aws_iam_role_policy_attachment" "codebuild_ecr_public" { + role = aws_iam_role.codebuild.name + policy_arn = "arn:aws:iam::aws:policy/AmazonElasticContainerRegistryPublicPowerUser" +} + +resource "aws_codebuild_project" "amd64" { + name = "${local.codebuild_identifier}-amd64" + + service_role = aws_iam_role.codebuild.arn + + artifacts { + type = "NO_ARTIFACTS" + } + + cache { + type = "LOCAL" + modes = ["LOCAL_DOCKER_LAYER_CACHE", "LOCAL_SOURCE_CACHE"] + } + + environment { + compute_type = "BUILD_GENERAL1_SMALL" + image = "aws/codebuild/amazonlinux2-x86_64-standard:5.0" + type = "LINUX_CONTAINER" + privileged_mode = true + } + + source { + type = "GITHUB" + location = "https://github.com/somleng/somleng-switch.git" + } +} + +resource "aws_codebuild_project" "arm64" { + name = "${local.codebuild_identifier}-arm64" + + service_role = aws_iam_role.codebuild.arn + + artifacts { + type = "NO_ARTIFACTS" + } + + cache { + type = "LOCAL" + modes = ["LOCAL_DOCKER_LAYER_CACHE", "LOCAL_SOURCE_CACHE"] + } + + environment { + compute_type = "BUILD_GENERAL1_SMALL" + image = "aws/codebuild/amazonlinux2-aarch64-standard:3.0" + type = "ARM_CONTAINER" + privileged_mode = true + } + + source { + type = "GITHUB" + location = "https://github.com/somleng/somleng-switch.git" + } +} diff --git a/infrastructure/modules/container_instances/main.tf b/infrastructure/modules/container_instances/main.tf index fdb875286..813b32d3c 100644 --- a/infrastructure/modules/container_instances/main.tf +++ b/infrastructure/modules/container_instances/main.tf @@ -1,6 +1,11 @@ # https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html -data "aws_ssm_parameter" "this_ami" { - name = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended" +# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/retrieve-ecs-optimized_AMI.html +data "aws_ssm_parameter" "amd64_ami" { + name = "/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended" +} + +data "aws_ssm_parameter" "arm64_ami" { + name = "/aws/service/ecs/optimized-ami/amazon-linux-2023/arm64/recommended" } data "aws_ec2_instance_type" "this" { @@ -66,7 +71,7 @@ resource "aws_iam_role_policy_attachment" "ssm" { # Launch Template resource "aws_launch_template" "this" { name_prefix = var.app_identifier - image_id = jsondecode(data.aws_ssm_parameter.this_ami.value).image_id + image_id = jsondecode((var.architecture == "arm64" ? data.aws_ssm_parameter.arm64_ami : data.aws_ssm_parameter.amd64_ami).value).image_id instance_type = data.aws_ec2_instance_type.this.instance_type iam_instance_profile { diff --git a/infrastructure/modules/container_instances/variables.tf b/infrastructure/modules/container_instances/variables.tf index 04bb9edda..9fe2fc53d 100644 --- a/infrastructure/modules/container_instances/variables.tf +++ b/infrastructure/modules/container_instances/variables.tf @@ -2,6 +2,15 @@ variable "instance_type" { default = "t3.small" } +variable "architecture" { + default = "amd64" + + validation { + condition = contains(["amd64", "arm64"], var.architecture) + error_message = "Valid values for var: architecture are (amd64, arm64)." + } +} + variable "app_identifier" {} variable "vpc" {} variable "instance_subnets" {}