From a2c121249478c3894dbbea14cbfeb845c5e18719 Mon Sep 17 00:00:00 2001 From: Alexander Shestakov Date: Sat, 31 May 2025 15:39:39 +0300 Subject: [PATCH 1/2] update the dockerfile to reduce the total image size and increase security by only adding needed files --- Dockerfile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7912cc3..b18c04f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,31 @@ -FROM node:lts-alpine +FROM node:lts-alpine AS builder WORKDIR /app COPY package*.json . +COPY pnpm-lock.yaml . RUN npm install COPY . . +# Generate the Prisma client and types RUN npx prisma generate RUN npm run build +FROM node:lts-alpine AS runner + +WORKDIR /app + +# Copy package.json and node_modules (includes @prisma/client) +COPY --from=builder /app/package*.json ./ +COPY --from=builder /app/pnpm-lock.yaml ./ +COPY --from=builder /app/node_modules ./node_modules + +# Copy built app files (dist folder) +COPY --from=builder /app/dist ./dist + EXPOSE 8393 CMD ["npm", "run", "start:prod"] \ No newline at end of file From 74ae5639d77d251160c130fa1dc7e5bdb8436c5e Mon Sep 17 00:00:00 2001 From: Alexander Shestakov Date: Sat, 31 May 2025 17:18:06 +0300 Subject: [PATCH 2/2] created a better terraform config for deploying to azure --- terraform/.terraform.lock.hcl | 33 +++++++------ terraform/main.tf | 90 ++++++++++++++++++++++++++--------- terraform/outputs.tf | 3 ++ terraform/variables.tf | 49 ++++++++++++------- 4 files changed, 117 insertions(+), 58 deletions(-) create mode 100644 terraform/outputs.tf diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl index f888acb..5764964 100644 --- a/terraform/.terraform.lock.hcl +++ b/terraform/.terraform.lock.hcl @@ -1,23 +1,22 @@ # This file is maintained automatically by "terraform init". # Manual edits may be lost in future updates. -provider "registry.terraform.io/kreuzwerker/docker" { - version = "3.5.0" - constraints = "~> 3.0" +provider "registry.terraform.io/hashicorp/azurerm" { + version = "4.31.0" + constraints = "~> 4.31.0" hashes = [ - "h1:TYbKlCFkOOI9hh63nbWT6yvd/0PfBONtMO4jkGvu8Us=", - "zh:01fa6b2f9c44fc0f286f27941d3866adb749e34235f25b9d731b4f45f9c8a601", - "zh:0f945042448360b3f44662db4dceb7287236a950cf936bc973735acc7cded206", - "zh:44f1e6b5b451d072e84dffe61dbf2c3fbbb4a9f8e98f921a99025ac19c6adbb6", - "zh:5724f8af7c2bbd0f019114421dd46e7c8983ec7ea9444a03fc3a770510b47f03", - "zh:790d0b9bc941d1953a739da5426b6a5efa4db97a9c4bb30c52019536abc40661", - "zh:7b89c7cf131a33604a9b8c3fd7a94b28446beba633bbf52e6e37ea3fef643421", - "zh:7e59eb91e253a3f04b40e1e0b45b027fed0e69fed78cd996788a23d92f02137d", - "zh:9caf1c13d1c6ed6a3b7aa11a61b56623b6bd30a6a1e396558c3dbe82370f34f5", - "zh:ba5b46ae242953fbec32f9f93dc5a81fd2e6962df68f17c670c0533040c74b42", - "zh:cae081982d5931ad265223c09824f2b3cd58a1fe307ccc701188d688ad217e6e", - "zh:cda2545056b6028d84505b18aaf20e7c769f6665fe27e16d2c52e35d23840689", - "zh:e41f2b9901202cb2cf7929005340ffc498ab1ca813005e364af4016a85634b5e", - "zh:e84272077a0287bc68523134292d9b12af54e200e413a89ae37f5788c063de5d", + "h1:RqdLXhIjmbRFuzcDtSrU6R1B7vU1xBl0Q8eGQe2pgpo=", + "zh:1ccb29d38aa385b854edde35f217f9db05dd1f9cb68ae9dfe718f73b26210641", + "zh:2022bbeaa035ddadff71c588d8fc4af04bd038d0195b148163ad5c8a8b464751", + "zh:2f87226d25388de7b55ef7ed3f731d50ec2f5a84cf8d5bd4c8f8ef5c111ba342", + "zh:363ef0cc9584b2f882fd7fa66d1d2358aca5d7e83738f602c7a3bb9b0fafbc08", + "zh:40e10684ecffe2ece53a5f24e6fe4e408c96a9a634715ce42b88aaa9887d02be", + "zh:52572a6ce316eb2528964cf948fe2959480d5d38d617e2535090eb58ad84cbc8", + "zh:54f1cf050dfc0af6bcbc8003e357d0b0cb0d66d8e8aaa07388b7668109453994", + "zh:5ce0b2b82ac8c7a6d00c9b2cbbda18ccddd496eb7247f2f6f2ce64be2c840ad9", + "zh:66b21cce52d213714f9522f659ddf2aed889153e8796ac7570a75b38af5677dc", + "zh:c83d495c79126cf578a6532fcfee0c9b54e790b4cb3169ef4a255396c66145bb", + "zh:cdb918c0892bb12d29d126f2e72c2af0cad2cbc4766b96dba108f7606f60ae06", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } diff --git a/terraform/main.tf b/terraform/main.tf index d98b46d..c2d600d 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -1,39 +1,83 @@ terraform { required_providers { - docker = { - source = "kreuzwerker/docker" - version = "~> 3.0" + azurerm = { + source = "hashicorp/azurerm" + version = "~> 4.31.0" } } } -provider "docker" {} +provider "azurerm" { + features {} + subscription_id = var.subscription_id +} -resource "docker_image" "app_image" { - name = var.image_name - keep_locally = true +resource "azurerm_resource_group" "rg" { + name = "${var.app_name}-rg" + location = var.location } -resource "docker_container" "app_container" { - name = var.container_name - image = docker_image.app_image.image_id - restart = "unless-stopped" +resource "azurerm_log_analytics_workspace" "log" { + name = "${var.app_name}-log" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + retention_in_days = 30 +} - dynamic "ports" { - for_each = var.ports - content { - internal = ports.value.internal - external = ports.value.external - } +resource "azurerm_container_app_environment" "env" { + name = "${var.app_name}-env" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + log_analytics_workspace_id = azurerm_log_analytics_workspace.log.id +} + +resource "azurerm_container_app" "app" { + name = "${var.app_name}-app" + resource_group_name = azurerm_resource_group.rg.name + container_app_environment_id = azurerm_container_app_environment.env.id + revision_mode = "Single" + + registry { + server = "ghcr.io" + username = var.registry_username + password_secret_name = "ghcr-pat" } - env = var.env_vars + secret { + name = "ghcr-pat" + value = var.registry_password_secret + } + + template { + container { + name = var.container_name + image = var.image_name + cpu = 1.0 + memory = "2.0Gi" + + dynamic "env" { + for_each = var.env_vars + content { + name = env.value["name"] + value = env.value["value"] + } + } + + # Override the PORT environment variable to ensure the app listens on port 80 + env { + name = "PORT" + value = "80" + } + } + } - dynamic "volumes" { - for_each = var.volumes - content { - host_path = volumes.value.host_path - container_path = volumes.value.container_path + ingress { + allow_insecure_connections = false + external_enabled = true + target_port = 80 + traffic_weight { + percentage = 100 + latest_revision = true } } } diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000..9d73cde --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,3 @@ +output "azurerm_container_app_url" { + value = azurerm_container_app.app.latest_revision_fqdn +} diff --git a/terraform/variables.tf b/terraform/variables.tf index f6f63ed..88725cd 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -1,33 +1,46 @@ -variable "image_name" { - description = "Docker image name with tag" +variable "subscription_id" { + description = "Azure subscription ID" + type = string +} + +variable "app_name" { + description = "Name of the application" + type = string +} + +variable "location" { + description = "Azure region for the resources" + type = string + default = "Italy North" +} + +variable "registry_username" { + description = "Username for the container registry" type = string } +variable "registry_password_secret" { + description = "Secret for the container registry password" + type = string + sensitive = true +} + variable "container_name" { - description = "Docker container name" + description = "Server's docker container name" type = string + default = "server" } -variable "ports" { - description = "List of ports to expose" - type = list(object({ - internal = number - external = number - })) - default = [] +variable "image_name" { + description = "Docker image name with tag" + type = string } variable "env_vars" { description = "Environment variables" - type = list(string) - default = [] -} - -variable "volumes" { - description = "Volumes to mount" type = list(object({ - host_path = string - container_path = string + name = string + value = string })) default = [] }