mirror of
https://github.com/imjasonh/terraform-playground
synced 2026-07-07 23:35:16 +00:00
Merge pull request #3 from imjasonh/imjasonh-patch-1
This commit is contained in:
commit
436b5adcd0
4 changed files with 239 additions and 0 deletions
71
container-vm/cloud-init.yaml.tftpl
Normal file
71
container-vm/cloud-init.yaml.tftpl
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#cloud-config
|
||||
# This cloud-init configuration defines systemd services to run Docker containers
|
||||
# on Container-Optimized OS (COS) with full observability support.
|
||||
|
||||
write_files:
|
||||
%{ for name, container in containers ~}
|
||||
- path: /etc/systemd/system/${name}.service
|
||||
permissions: 0644
|
||||
owner: root
|
||||
content: |
|
||||
[Unit]
|
||||
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=${container.restart_policy}
|
||||
RestartSec=5s
|
||||
|
||||
# Stop and remove any pre-existing container with the same name.
|
||||
ExecStartPre=/usr/bin/docker stop ${name} || true
|
||||
ExecStartPre=/usr/bin/docker rm ${name} || true
|
||||
|
||||
# Pull the image before starting.
|
||||
ExecStartPre=/usr/bin/docker pull ${container.image}
|
||||
|
||||
# The main execution command: docker run.
|
||||
# When logging is enabled, use the gcplogs driver to send container logs to Cloud Logging.
|
||||
ExecStart=/usr/bin/docker run \
|
||||
--name ${name} \
|
||||
%{ if enable_logging ~}
|
||||
--log-driver=gcplogs \
|
||||
--log-opt gcp-project=${project_id} \
|
||||
--log-opt gcp-log-cmd=true \
|
||||
--log-opt gcp-meta-zone=true \
|
||||
--log-opt gcp-meta-name=true \
|
||||
--log-opt labels=container_name \
|
||||
--label container_name=${name} \
|
||||
%{ endif ~}
|
||||
%{ 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 ~}
|
||||
|
||||
|
||||
# ExecStop is called when the service is stopped manually.
|
||||
ExecStop=/usr/bin/docker stop ${name}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
%{ 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 ~}
|
||||
|
||||
64
container-vm/main.tf
Normal file
64
container-vm/main.tf
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# Fetch the latest source image based on the input variables (defaulting to COS)
|
||||
data "google_compute_image" "source_image" {
|
||||
family = var.source_image_family
|
||||
project = var.source_image_project
|
||||
}
|
||||
|
||||
# Render the cloud-init YAML template using dynamic module inputs
|
||||
locals {
|
||||
rendered_cloud_init = templatefile("${path.module}/cloud-init.yaml.tftpl", {
|
||||
containers = var.containers,
|
||||
enable_logging = var.enable_logging,
|
||||
project_id = var.project_id,
|
||||
})
|
||||
}
|
||||
|
||||
# The Instance Template resource itself
|
||||
resource "google_compute_instance_template" "container_vm_template" {
|
||||
project = var.project_id
|
||||
name_prefix = "systemd-container-tmpl-"
|
||||
description = "Runs a container using Docker, managed by a systemd unit via cloud-init."
|
||||
machine_type = var.machine_type
|
||||
region = var.region
|
||||
labels = var.labels
|
||||
|
||||
# Disk configuration using the fetched OS image
|
||||
disk {
|
||||
source_image = data.google_compute_image.source_image.self_link
|
||||
auto_delete = true
|
||||
boot = true
|
||||
}
|
||||
|
||||
# Network configuration (private VM - no external IP)
|
||||
network_interface {
|
||||
network = var.network
|
||||
subnetwork = var.subnetwork
|
||||
}
|
||||
|
||||
# Service Account configuration (needed for Google Cloud API access, including image pulls)
|
||||
service_account {
|
||||
email = var.service_account_email
|
||||
scopes = ["cloud-platform"]
|
||||
}
|
||||
|
||||
# Metadata for cloud-init and observability
|
||||
metadata = {
|
||||
user-data = local.rendered_cloud_init
|
||||
google-logging-enabled = tostring(var.enable_logging)
|
||||
google-monitoring-enabled = tostring(var.enable_monitoring)
|
||||
cos-metrics-enabled = tostring(var.enable_cos_metrics)
|
||||
}
|
||||
|
||||
scheduling {
|
||||
automatic_restart = true
|
||||
on_host_maintenance = "MIGRATE"
|
||||
}
|
||||
|
||||
# Enable shielded VM features for security
|
||||
shielded_instance_config {
|
||||
enable_secure_boot = true
|
||||
enable_vtpm = true
|
||||
enable_integrity_monitoring = true
|
||||
}
|
||||
}
|
||||
|
||||
10
container-vm/outputs.tf
Normal file
10
container-vm/outputs.tf
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
output "instance_template_self_link" {
|
||||
description = "The self-link of the created instance template. Use this to deploy VMs or MIGs."
|
||||
value = google_compute_instance_template.container_vm_template.self_link
|
||||
}
|
||||
|
||||
output "instance_template_name" {
|
||||
description = "The name of the created instance template."
|
||||
value = google_compute_instance_template.container_vm_template.name
|
||||
}
|
||||
|
||||
94
container-vm/variables.tf
Normal file
94
container-vm/variables.tf
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
variable "project_id" {
|
||||
description = "The GCP project ID."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "The region where the compute template is created."
|
||||
type = string
|
||||
default = "us-central1"
|
||||
}
|
||||
|
||||
variable "machine_type" {
|
||||
description = "The machine type for the VM instance template."
|
||||
type = string
|
||||
default = "e2-medium"
|
||||
}
|
||||
|
||||
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 = length(var.containers) > 0
|
||||
error_message = "At least one container must be specified."
|
||||
}
|
||||
|
||||
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" {
|
||||
description = "The email of the service account to use for the VM. Must be created outside this module."
|
||||
type = string
|
||||
}
|
||||
|
||||
# Defaulting to COS, which has Docker/containerd pre-installed.
|
||||
variable "source_image_family" {
|
||||
description = "The OS image family to use. COS is recommended."
|
||||
type = string
|
||||
default = "cos-stable"
|
||||
}
|
||||
|
||||
variable "source_image_project" {
|
||||
description = "The project hosting the source image."
|
||||
type = string
|
||||
default = "cos-cloud"
|
||||
}
|
||||
|
||||
variable "network" {
|
||||
description = "The VPC network to attach the VM to (e.g., 'projects/PROJECT/global/networks/NETWORK' or 'NETWORK')."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "subnetwork" {
|
||||
description = "The subnetwork to attach the VM to (e.g., 'projects/PROJECT/regions/REGION/subnetworks/SUBNET' or 'SUBNET')."
|
||||
type = string
|
||||
}
|
||||
|
||||
# Observability variables
|
||||
variable "enable_logging" {
|
||||
description = "Enable Cloud Logging for the VM and containers. When true, container logs are sent to Cloud Logging using the gcplogs driver."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_monitoring" {
|
||||
description = "Enable Cloud Monitoring for the VM. When true, VM metrics are collected and sent to Cloud Monitoring."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_cos_metrics" {
|
||||
description = "Enable Container-Optimized OS metrics collection for additional container and system metrics."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
description = "Labels to apply to the instance template for organization and filtering in Cloud Monitoring and Logging."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue