1
0
Fork 0
mirror of https://github.com/imjasonh/terraform-playground synced 2026-07-08 07:44:57 +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
# 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).
write_files:
- path: /etc/systemd/system/${container_name}.service
%{ for name, container in containers ~}
- path: /etc/systemd/system/${name}.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Containerized application: ${container_name}
Description=Containerized application: ${name}
# Wait for the Docker socket to be ready
Wants=docker.socket
After=docker.service
[Service]
# Crucial for persistence: ensure the service restarts on exit.
Restart=${restart_policy}
Restart=${container.restart_policy}
RestartSec=5s
# Stop and remove any pre-existing container with the same name.
ExecStartPre=/usr/bin/docker stop ${container_name} || true
ExecStartPre=/usr/bin/docker rm ${container_name} || true
ExecStartPre=/usr/bin/docker stop ${name} || true
ExecStartPre=/usr/bin/docker rm ${name} || true
# Pull the latest version of the image before starting.
ExecStartPre=/usr/bin/docker pull ${container_image}
# Pull the image before starting.
ExecStartPre=/usr/bin/docker pull ${container.image}
# The main execution command: docker run.
# We use 'docker run --rm' to ensure clean removal after failure/stop.
ExecStart=/usr/bin/docker run \
--name ${container_name} \
%{ for key, value in container_env ~}
-e ${key}="${value}" \
%{ endfor ~}
${container_image} \
%{ if container_command != "" ~}
"${container_command}" \
%{ endif ~}
%{ if length(container_args) > 0 ~}
%{ for arg in container_args ~}
# 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.
--name ${name} \
%{ for e in container.env ~}
-e ${e.name}="${e.value}" \
%{ endfor ~}
${container.image} \
%{ if container.command != "" ~}
"${container.command}" \
%{ endif ~}
%{ for arg in container.args ~}
# Escape single quotes: end quoted string, add escaped quote, resume quoted string
'${replace(arg, "'", "'\\''")}' \
%{ endfor ~}
%{ endif ~}
%{ endfor ~}
# ExecStop is called when the service is stopped manually.
ExecStop=/usr/bin/docker stop ${container_name}
ExecStop=/usr/bin/docker stop ${name}
[Install]
WantedBy=multi-user.target
runcmd:
# Reload the systemd configuration to recognize the new service file.
- systemctl daemon-reload
# Enable the service to start automatically on subsequent boots.
- systemctl enable ${container_name}.service
# Start the service immediately.
- systemctl start ${container_name}.service
%{ endfor ~}
runcmd:
# Reload the systemd configuration to recognize the new service files.
- systemctl daemon-reload
%{ for name, container in containers ~}
# 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
locals {
rendered_cloud_init = templatefile("${path.module}/cloud-init.yaml.tftpl", {
container_name = var.container_name,
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,
containers = var.containers,
})
}

View file

@ -15,44 +15,28 @@ variable "machine_type" {
default = "e2-medium"
}
variable "container_image" {
description = "The container image to run, must be referenced by digest (e.g., 'gcr.io/my-project/my-app@sha256:abc123...')."
type = string
variable "containers" {
description = "A map of containers to run on the VM. Each key is the container name, and the value specifies the container configuration."
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 {
condition = can(regex("^.+@sha256:[a-f0-9]{64}$", var.container_image))
error_message = "The container_image must be referenced by digest (e.g., 'gcr.io/my-project/my-app@sha256:<64 hex chars>')."
condition = length(var.containers) > 0
error_message = "At least one container must be specified."
}
}
variable "container_name" {
description = "The name to assign to the running Docker container."
type = string
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 = []
validation {
condition = alltrue([for name, c in var.containers : can(regex("^.+@sha256:[a-f0-9]{64}$", c.image))])
error_message = "All container images must be referenced by digest (e.g., 'gcr.io/my-project/my-app@sha256:<64 hex chars>')."
}
}
variable "service_account_email" {