1
0
Fork 0
mirror of https://github.com/imjasonh/terraform-playground synced 2026-07-21 06:48:08 +00:00

Merge pull request #6 from imjasonh/copilot/sub-pr-3-another-one

This commit is contained in:
Jason Hall 2025-11-28 09:36:22 -06:00 committed by GitHub
commit c20be36cd2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 71 deletions

View file

@ -1,60 +1,61 @@
#cloud-config #cloud-config
# This cloud-init configuration defines a systemd service to run the Docker container # This cloud-init configuration defines systemd services to run Docker containers
# on Container-Optimized OS (COS). # on Container-Optimized OS (COS).
write_files: write_files:
- path: /etc/systemd/system/${container_name}.service %{ for name, container in containers ~}
- path: /etc/systemd/system/${name}.service
permissions: 0644 permissions: 0644
owner: root owner: root
content: | content: |
[Unit] [Unit]
Description=Containerized application: ${container_name} Description=Containerized application: ${name}
# Wait for the Docker socket to be ready # Wait for the Docker socket to be ready
Wants=docker.socket Wants=docker.socket
After=docker.service After=docker.service
[Service] [Service]
# Crucial for persistence: ensure the service restarts on exit. # Crucial for persistence: ensure the service restarts on exit.
Restart=${restart_policy} Restart=${container.restart_policy}
RestartSec=5s RestartSec=5s
# Stop and remove any pre-existing container with the same name. # Stop and remove any pre-existing container with the same name.
ExecStartPre=/usr/bin/docker stop ${container_name} || true ExecStartPre=/usr/bin/docker stop ${name} || true
ExecStartPre=/usr/bin/docker rm ${container_name} || true ExecStartPre=/usr/bin/docker rm ${name} || true
# Pull the latest version of the image before starting. # Pull the image before starting.
ExecStartPre=/usr/bin/docker pull ${container_image} ExecStartPre=/usr/bin/docker pull ${container.image}
# The main execution command: docker run. # The main execution command: docker run.
# We use 'docker run --rm' to ensure clean removal after failure/stop.
ExecStart=/usr/bin/docker run \ ExecStart=/usr/bin/docker run \
--name ${container_name} \ --name ${name} \
%{ for key, value in container_env ~} %{ for e in container.env ~}
-e ${key}="${value}" \ -e ${e.name}="${e.value}" \
%{ endfor ~} %{ endfor ~}
${container_image} \ ${container.image} \
%{ if container_command != "" ~} %{ if container.command != "" ~}
"${container_command}" \ "${container.command}" \
%{ endif ~} %{ endif ~}
%{ if length(container_args) > 0 ~} %{ for arg in container.args ~}
%{ for arg in container_args ~} # Escape single quotes: end quoted string, add escaped quote, resume quoted string
# Escape single quotes in arguments by ending the quoted string, inserting an escaped quote, and resuming the quoted string.
# This pattern: replace(arg, "'", "'\\''") is standard for safely passing single quotes in shell.
'${replace(arg, "'", "'\\''")}' \ '${replace(arg, "'", "'\\''")}' \
%{ endfor ~} %{ endfor ~}
%{ endif ~}
# ExecStop is called when the service is stopped manually. # ExecStop is called when the service is stopped manually.
ExecStop=/usr/bin/docker stop ${container_name} ExecStop=/usr/bin/docker stop ${name}
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
runcmd: %{ endfor ~}
# Reload the systemd configuration to recognize the new service file.
- systemctl daemon-reload runcmd:
# Enable the service to start automatically on subsequent boots. # Reload the systemd configuration to recognize the new service files.
- systemctl enable ${container_name}.service - systemctl daemon-reload
# Start the service immediately. %{ for name, container in containers ~}
- systemctl start ${container_name}.service # Enable and start ${name} service.
- systemctl enable ${name}.service
- systemctl start ${name}.service
%{ endfor ~}

View file

@ -7,12 +7,7 @@ data "google_compute_image" "source_image" {
# Render the cloud-init YAML template using dynamic module inputs # Render the cloud-init YAML template using dynamic module inputs
locals { locals {
rendered_cloud_init = templatefile("${path.module}/cloud-init.yaml.tftpl", { rendered_cloud_init = templatefile("${path.module}/cloud-init.yaml.tftpl", {
container_name = var.container_name, containers = var.containers,
container_image = var.container_image,
restart_policy = var.restart_policy,
container_env = var.container_env,
container_command = var.container_command,
container_args = var.container_args,
}) })
} }

View file

@ -15,44 +15,28 @@ variable "machine_type" {
default = "e2-medium" default = "e2-medium"
} }
variable "container_image" { variable "containers" {
description = "The container image to run, must be referenced by digest (e.g., 'gcr.io/my-project/my-app@sha256:abc123...')." description = "A map of containers to run on the VM. Each key is the container name, and the value specifies the container configuration."
type = string type = map(object({
image = string
command = optional(string, "")
args = optional(list(string), [])
env = optional(list(object({
name = string
value = string
})), [])
restart_policy = optional(string, "always")
}))
validation { validation {
condition = can(regex("^.+@sha256:[a-f0-9]{64}$", var.container_image)) condition = length(var.containers) > 0
error_message = "The container_image must be referenced by digest (e.g., 'gcr.io/my-project/my-app@sha256:<64 hex chars>')." error_message = "At least one container must be specified."
} }
}
variable "container_name" { validation {
description = "The name to assign to the running Docker container." condition = alltrue([for name, c in var.containers : can(regex("^.+@sha256:[a-f0-9]{64}$", c.image))])
type = string error_message = "All container images must be referenced by digest (e.g., 'gcr.io/my-project/my-app@sha256:<64 hex chars>')."
default = "gce-container-app" }
}
variable "restart_policy" {
description = "The systemd/Docker restart policy (e.g., 'always', 'on-failure', 'no')."
type = string
default = "always"
}
variable "container_env" {
description = "A map of environment variables to set in the container."
type = map(string)
default = {}
}
variable "container_command" {
description = "The optional command to override the ENTRYPOINT (e.g., '/bin/bash')."
type = string
default = ""
}
variable "container_args" {
description = "Optional arguments to pass to the container command."
type = list(string)
default = []
} }
variable "service_account_email" { variable "service_account_email" {