From 51931698ea15ab800b27710b1b6b4ff443509080 Mon Sep 17 00:00:00 2001 From: Vasyl Shliakhtychenko Date: Fri, 17 Apr 2026 15:07:55 +0300 Subject: [PATCH] Migrated to lightsail --- Containerfile | 1 - terraform/README.md | 4 +- terraform/aws/.terraform.lock.hcl | 106 ++++++++++++++++++++++++++++++ terraform/aws/README.md | 14 ++-- terraform/aws/apprunner.tf | 86 ------------------------ terraform/aws/ecr.tf | 14 ++++ terraform/aws/lightsail.tf | 47 +++++++++++++ terraform/aws/variables.tf | 56 ++++------------ 8 files changed, 185 insertions(+), 143 deletions(-) create mode 100644 terraform/aws/.terraform.lock.hcl delete mode 100644 terraform/aws/apprunner.tf create mode 100644 terraform/aws/lightsail.tf diff --git a/Containerfile b/Containerfile index a2114d6..a705264 100644 --- a/Containerfile +++ b/Containerfile @@ -63,7 +63,6 @@ ARG APP_DIR ENV NODE_ENV=production -COPY --chown=${UID}:${GID} ./public ./public COPY --chown=${UID}:${GID} ./views ./views COPY --chown=${UID}:${GID} --from=build ${APP_DIR}/dist ./dist diff --git a/terraform/README.md b/terraform/README.md index 98d81fd..fc7cb71 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -133,7 +133,7 @@ The directory structure is organized to support deploying the extension app to d - `README.md`: The main documentation file. - `aws/`: Contains Terraform configuration files for deploying to Amazon Web Services. - `README.md`: Documentation specific to AWS deployment. - - `apprunner.tf`, `ecr.tf`, `image.tf`, `main.tf`, `outputs.tf`, `providers.tf`, `terraform.tf`, `variables.tf`: Various Terraform configuration files for AWS resources. + - `lightsail.tf`, `ecr.tf`, `image.tf`, `main.tf`, `outputs.tf`, `providers.tf`, `terraform.tf`, `variables.tf`: Various Terraform configuration files for AWS resources. - `azure/`: Contains Terraform configuration files for deploying to Microsoft Azure. - `README.md`: Documentation specific to Azure deployment. - `acr.tf`, `image.tf`, `main.tf`, `outputs.tf`, `providers.tf`, `resource_group.tf`, `terraform.tf`, `variables.tf`, `webapp.tf`: Various Terraform configuration files for Azure resources. @@ -156,7 +156,7 @@ The directory structure is organized to support deploying the extension app to d ├── README.md ├── aws │   ├── README.md -│   ├── apprunner.tf +│   ├── lightsail.tf │   ├── ecr.tf │   ├── image.tf │   ├── main.tf diff --git a/terraform/aws/.terraform.lock.hcl b/terraform/aws/.terraform.lock.hcl new file mode 100644 index 0000000..9376bff --- /dev/null +++ b/terraform/aws/.terraform.lock.hcl @@ -0,0 +1,106 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.100.0" + constraints = "~> 5.0" + hashes = [ + "h1:Ijt7pOlB7Tr7maGQIqtsLFbl7pSMIj06TVdkoSBcYOw=", + "zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644", + "zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2", + "zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274", + "zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b", + "zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862", + "zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93", + "zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2", + "zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e", + "zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421", + "zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4", + "zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9", + "zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9", + "zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70", + ] +} + +provider "registry.terraform.io/hashicorp/local" { + version = "2.8.0" + constraints = "~> 2.5" + hashes = [ + "h1:3jWHVwO5QUIS9V1NsK10ZzdpkK2ABuB4G+UIWrVeGp4=", + "zh:05f18164beab4a84753e5fedf463771ee0c6eca8e90346b8766f1e1c186dec1e", + "zh:563a0702e3711e25ba8930120899b681378b50cbb957fd204b37745c7c9b5f40", + "zh:5b56ab2ed70ed92721febb4a070af0837f1084c44825c18e4b95f7efb1d45d26", + "zh:6cbedc09b67a5cdb9501ff1b18a315fa46a38e0530424cab1c7f4b3acc75f489", + "zh:71b3bd50f89fb385a42a436ba2ce2b8e00f9de53535ce956deff1477b0b117dc", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:9d45ac0a00b85cabdd398b859349d17f124c598b6e6bf272f1bb01321ce708a8", + "zh:a453efe8641a8f31fe806b597bf2b34d7b78b971a8e3919061ea89d61fda7b8d", + "zh:ac692bacb8c3dca8b5b37e5383168aca1f87d3cd7b40615efd300defb76494f5", + "zh:bda9e90c8547d90c9c573206985c5675cc1406047605af037a5069942c3c5966", + "zh:c30a1967de040d00f5038086dd53cdbfb78cc05d1dbc75037410f011bf2a20d8", + "zh:c80bbd1c3f56b3c836d80cf93ac0e8809305c2642f0c98b54bf5d05d3b12718c", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.8.1" + constraints = "~> 3.6" + hashes = [ + "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", + "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", + "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", + "zh:229665ddf060aa0ed315597908483eee5b818a17d09b6417a0f52fd9405c4f57", + "zh:2469d2e48f28076254a2a3fc327f184914566d9e40c5780b8d96ebf7205f8bc0", + "zh:37d7eb334d9561f335e748280f5535a384a88675af9a9eac439d4cfd663bcb66", + "zh:741101426a2f2c52dee37122f0f4a2f2d6af6d852cb1db634480a86398fa3511", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:a902473f08ef8df62cfe6116bd6c157070a93f66622384300de235a533e9d4a9", + "zh:b85c511a23e57a2147355932b3b6dce2a11e856b941165793a0c3d7578d94d05", + "zh:c5172226d18eaac95b1daac80172287b69d4ce32750c82ad77fa0768be4ea4b8", + "zh:dab4434dba34aad569b0bc243c2d3f3ff86dd7740def373f2a49816bd2ff819b", + "zh:f49fd62aa8c5525a5c17abd51e27ca5e213881d58882fd42fec4a545b53c9699", + ] +} + +provider "registry.terraform.io/hashicorp/time" { + version = "0.13.1" + constraints = "~> 0.12" + hashes = [ + "h1:ZT5ppCNIModqk3iOkVt5my8b8yBHmDpl663JtXAIRqM=", + "zh:02cb9aab1002f0f2a94a4f85acec8893297dc75915f7404c165983f720a54b74", + "zh:04429b2b31a492d19e5ecf999b116d396dac0b24bba0d0fb19ecaefe193fdb8f", + "zh:26f8e51bb7c275c404ba6028c1b530312066009194db721a8427a7bc5cdbc83a", + "zh:772ff8dbdbef968651ab3ae76d04afd355c32f8a868d03244db3f8496e462690", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:898db5d2b6bd6ca5457dccb52eedbc7c5b1a71e4a4658381bcbb38cedbbda328", + "zh:8de913bf09a3fa7bedc29fec18c47c571d0c7a3d0644322c46f3aa648cf30cd8", + "zh:9402102c86a87bdfe7e501ffbb9c685c32bbcefcfcf897fd7d53df414c36877b", + "zh:b18b9bb1726bb8cfbefc0a29cf3657c82578001f514bcf4c079839b6776c47f0", + "zh:b9d31fdc4faecb909d7c5ce41d2479dd0536862a963df434be4b16e8e4edc94d", + "zh:c951e9f39cca3446c060bd63933ebb89cedde9523904813973fbc3d11863ba75", + "zh:e5b773c0d07e962291be0e9b413c7a22c044b8c7b58c76e8aa91d1659990dfb5", + ] +} + +provider "registry.terraform.io/kreuzwerker/docker" { + version = "3.9.0" + constraints = "~> 3.0" + hashes = [ + "h1:p65AjYSOmmHPjKkIYlEnxSMyrprTHKf1qBzKhCnCtG8=", + "zh:0ead8281830e9b9496651282235d9a139ba1b1b6ff79e395eb8c78658dc446b9", + "zh:0f17d37d8d3872df3fb75c68b5272e0c981343f53b506a9675b4405191edd3ef", + "zh:11d50b37323874427c6d2a08b737d3c7707c8301fdd236c94485cf2828d0b14b", + "zh:32f6f9b847446054e2db3d72886ef2f1d1aa51a6d0dac42340b07dad18e3f28f", + "zh:5ea5c67668b5dcbda560dc6104b788a9bfc974d52f02f7886889b77cc0e5d248", + "zh:5fb19a0b07edc344cd3ddeeb9cfb3d183089deb7a6a94a7b22a583aa1712596b", + "zh:602a7ece444e2a142ec5245abb98e7a1a990a68afae2df63b6c85ec084f0c5d7", + "zh:693dce278524ad8a6d6c9dd7a01bcd63bb85189639198f8d0b044ab0e5099401", + "zh:72e9911568103576c6a78fa38841cfd45eeb88ad22a2c649eb140a377a5b3c26", + "zh:956b62b6857cbb467b50158601f01b1203daa34cbd447dcc7f044c327e878b68", + "zh:9d372bac0d4479868b34485fb4966ba7bb525938f818b6a625f4977004ea83f9", + "zh:e06658a51427f9f53dbdb06263406fc1bc56d1a4fb5e7eb660d7cdfc22f596bd", + "zh:eee38dadf672b946419af25160eae7c03fc2afbb14f39f2f1d2a7404d647e2f7", + ] +} diff --git a/terraform/aws/README.md b/terraform/aws/README.md index f57914d..e5609ef 100644 --- a/terraform/aws/README.md +++ b/terraform/aws/README.md @@ -40,7 +40,6 @@ Now that you’ve set up your AWS environment, continue with the [Terraform depl | Name | Version | |------|---------| | [aws](#provider\_aws) | ~> 5.0 | -| [time](#provider\_time) | ~> 0.12 | ## Modules @@ -57,17 +56,12 @@ Now that you’ve set up your AWS environment, continue with the [Terraform depl | Name | Type | |------|------| -| [aws_apprunner_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apprunner_service) | resource | | [aws_ecr_repository.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | | [aws_ecr_repository_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource | -| [aws_iam_role.access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role.instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy_attachment.apprunner](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [time_sleep.access_iam_role_propagation](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [aws_lightsail_container_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lightsail_container_service) | resource | +| [aws_lightsail_container_service_deployment_version.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lightsail_container_service_deployment_version) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ecr_authorization_token.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecr_authorization_token) | data source | -| [aws_iam_policy_document.app_role_assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.apprunner](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | @@ -82,8 +76,8 @@ Now that you’ve set up your AWS environment, continue with the [Terraform depl | [application\_build\_labels](#input\_application\_build\_labels) | The labels to apply to the application build image | `map(string)` |
{
"org.opencontainers.image.authors": "DocuSign Inc.",
"org.opencontainers.image.description": "This reference implementation models the use case of taking an agreement PDF sent by the Docusign platform using a file archive extension app and storing it locally.",
"org.opencontainers.image.licenses": "MIT",
"org.opencontainers.image.source": "https://github.com/docusign/extension-app-file-archive-reference-implementation-private",
"org.opencontainers.image.title": "File Archive Extension App Reference Implementation",
"org.opencontainers.image.vendor": "DocuSign Inc."
}
| no | | [application\_build\_paths](#input\_application\_build\_paths) | Paths of files relative to the build context, changes to which lead to a rebuild of the image. Supported pattern matches are the same as for the `fileset` Terraform function (https://developer.hashicorp.com/terraform/language/functions/fileset). | `list(string)` |
[
"public/**",
"src/**",
"views/**",
"package.json",
"tsconfig.json",
"Dockerfile",
".dockerignore"
]
| no | | [application\_environment\_mode](#input\_application\_environment\_mode) | The environment mode for the application | `string` | `"production"` | no | -| [application\_instance\_cpu](#input\_application\_instance\_cpu) | The number of CPU units to allocate to the application instance | `string` | `"256"` | no | -| [application\_instance\_memory](#input\_application\_instance\_memory) | The amount of memory to allocate to the application instance | `string` | `"512"` | no | +| [application\_instance\_power](#input\_application\_instance\_power) | The power specification for the Lightsail container service instance | `string` | `"nano"` | no | +| [application\_instance\_scale](#input\_application\_instance\_scale) | The number of Lightsail container service instances to run | `number` | `1` | no | | [application\_jwt\_secret\_key](#input\_application\_jwt\_secret\_key) | The secret key to use for signing JWT tokens. If empty, a random key will be generated. | `string` | `""` | no | | [application\_name](#input\_application\_name) | The name of the application | `string` | `"extension-app-file-archive"` | no | | [application\_oauth\_client\_id](#input\_application\_oauth\_client\_id) | The OAuth client ID for the application. If empty, a random client ID will be generated. | `string` | `""` | no | diff --git a/terraform/aws/apprunner.tf b/terraform/aws/apprunner.tf deleted file mode 100644 index 46fb6c7..0000000 --- a/terraform/aws/apprunner.tf +++ /dev/null @@ -1,86 +0,0 @@ -locals { - iam_role_name_separator = "-" - application_service_protocol = "https" - application_service_url = join("://", [local.application_service_protocol, aws_apprunner_service.this.service_url]) -} - -data "aws_iam_policy_document" "app_role_assume_role_policy" { - statement { - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = ["tasks.apprunner.amazonaws.com"] - } - } -} - -resource "aws_iam_role" "instance" { - name = join(local.iam_role_name_separator, compact([var.application_name, local.region, "instance"])) - assume_role_policy = data.aws_iam_policy_document.app_role_assume_role_policy.json -} - -data "aws_iam_policy_document" "apprunner" { - statement { - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = [ - "build.apprunner.amazonaws.com", - "tasks.apprunner.amazonaws.com", - ] - } - } -} - -resource "aws_iam_role" "access" { - name = join(local.iam_role_name_separator, [var.application_name, local.region, "access"]) - assume_role_policy = data.aws_iam_policy_document.apprunner.json -} - -# workaround for https://github.com/hashicorp/terraform-provider-aws/issues/6566 -resource "time_sleep" "access_iam_role_propagation" { - create_duration = "10s" - - triggers = { - name = aws_iam_role.access.name - } -} - -resource "aws_iam_role_policy_attachment" "apprunner" { - role = time_sleep.access_iam_role_propagation.triggers["name"] - policy_arn = "arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess" -} - -resource "aws_apprunner_service" "this" { - service_name = var.application_name - - source_configuration { - auto_deployments_enabled = false - - authentication_configuration { - access_role_arn = aws_iam_role.access.arn - } - - image_repository { - image_repository_type = "ECR" - image_identifier = module.image.app_image_name - image_configuration { - port = var.application_port - runtime_environment_variables = { - JWT_SECRET_KEY = local.application_jwt_secret_key - OAUTH_CLIENT_ID = local.application_oauth_client_id - OAUTH_CLIENT_SECRET = local.application_oauth_client_secret - AUTHORIZATION_CODE = local.application_authorization_code - } - } - } - } - - instance_configuration { - instance_role_arn = aws_iam_role.instance.arn - cpu = var.application_instance_cpu - memory = var.application_instance_memory - } -} diff --git a/terraform/aws/ecr.tf b/terraform/aws/ecr.tf index 66a749b..e8f1d9c 100644 --- a/terraform/aws/ecr.tf +++ b/terraform/aws/ecr.tf @@ -42,6 +42,20 @@ data "aws_iam_policy_document" "ecr" { ] } } + + statement { + actions = [ + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer", + ] + + principals { + type = "AWS" + identifiers = [ + aws_lightsail_container_service.this.private_registry_access[0].ecr_image_puller_role[0].principal_arn, + ] + } + } } resource "aws_ecr_repository_policy" "this" { diff --git a/terraform/aws/lightsail.tf b/terraform/aws/lightsail.tf new file mode 100644 index 0000000..a0d2fed --- /dev/null +++ b/terraform/aws/lightsail.tf @@ -0,0 +1,47 @@ +locals { + application_service_url = trimsuffix(aws_lightsail_container_service.this.url, "/") +} + +resource "aws_lightsail_container_service" "this" { + name = var.application_name + power = var.application_instance_power + scale = var.application_instance_scale + + private_registry_access { + ecr_image_puller_role { + is_active = true + } + } + + tags = local.tags +} + +resource "aws_lightsail_container_service_deployment_version" "this" { + service_name = aws_lightsail_container_service.this.name + + container { + container_name = var.application_name + image = module.image.app_image_name + + environment = { + JWT_SECRET_KEY = local.application_jwt_secret_key + OAUTH_CLIENT_ID = local.application_oauth_client_id + OAUTH_CLIENT_SECRET = local.application_oauth_client_secret + AUTHORIZATION_CODE = local.application_authorization_code + } + + ports = { + (var.application_port) = "HTTP" + } + } + + public_endpoint { + container_name = var.application_name + container_port = var.application_port + + health_check { + path = "/" + success_codes = "200-499" + } + } +} diff --git a/terraform/aws/variables.tf b/terraform/aws/variables.tf index 7ec5fde..5f155bf 100644 --- a/terraform/aws/variables.tf +++ b/terraform/aws/variables.tf @@ -2,7 +2,7 @@ variable "region" { description = "The AWS region" type = string nullable = true - default = "us-east-1" + default = "us-east-2" } variable "docker_host" { @@ -103,59 +103,27 @@ variable "application_build_labels" { } } -variable "application_instance_cpu" { - description = "The number of CPU units to allocate to the application instance" +variable "application_instance_power" { + description = "The power specification for the Lightsail container service instance" type = string nullable = false - default = "256" + default = "nano" validation { - condition = contains( - [ - "256", - "512", - "1024", - "2048", - "4096", - "0.25 vCPU", - "0.5 vCPU", - "1 vCPU", - "2 vCPU", - "4 vCPU", - ], var.application_instance_cpu) - error_message = "The number of CPU units must be one of '256', '512', '1024', '2048', '4096', '0.25 vCPU', '0.5 vCPU', '1 vCPU', '2 vCPU', or '4 vCPU'" + condition = contains(["nano", "micro", "small", "medium", "large", "xlarge"], var.application_instance_power) + error_message = "The power specification must be one of 'nano', 'micro', 'small', 'medium', 'large', or 'xlarge'" } } -variable "application_instance_memory" { - description = "The amount of memory to allocate to the application instance" - type = string +variable "application_instance_scale" { + description = "The number of Lightsail container service instances to run" + type = number nullable = false - default = "512" + default = 1 validation { - condition = contains( - [ - "512", - "1024", - "2048", - "3072", - "4096", - "6144", - "8192", - "10240", - "12288", - "0.5 GB", - "1 GB", - "2 GB", - "3 GB", - "4 GB", - "6 GB", - "8 GB", - "10 GB", - "12 GB", - ], var.application_instance_memory) - error_message = "The amount of memory must be one of '512', '1024', '2048', '3072', '4096', '6144', '8192', '10240', '12288', '0.5 GB', '1 GB', '2 GB', '3 GB', '4 GB', '6 GB', '8 GB', '10 GB', or '12 GB'" + condition = var.application_instance_scale >= 1 && var.application_instance_scale <= 20 + error_message = "The scale must be between 1 and 20" } }