first commit
This commit is contained in:
89
modules/10-services-generic/docker-service/README.md
Normal file
89
modules/10-services-generic/docker-service/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Generic Docker Service Module
|
||||
|
||||
This is a reusable OpenTofu module for deploying Docker containers with configurable options. It serves as the foundation for specific application modules in this homelab project.
|
||||
|
||||
## Features
|
||||
|
||||
- Pull and manage Docker images
|
||||
- Configure container networking, ports, and volumes
|
||||
- Set environment variables and labels
|
||||
- Configure resource limits and constraints
|
||||
- Set up health checks
|
||||
- Support for container logging options
|
||||
|
||||
## Usage
|
||||
|
||||
This module is typically called by application-specific modules rather than used directly, but can be used as follows:
|
||||
|
||||
```hcl
|
||||
module "my_service" {
|
||||
source = "../../10-services-generic/docker-service"
|
||||
|
||||
container_name = "my-service"
|
||||
image = "organization/image"
|
||||
tag = "latest"
|
||||
|
||||
restart_policy = "unless-stopped"
|
||||
network_mode = "bridge"
|
||||
|
||||
// Port mappings
|
||||
ports = [
|
||||
{
|
||||
internal = 8080
|
||||
external = 8080
|
||||
protocol = "tcp"
|
||||
}
|
||||
]
|
||||
|
||||
// Volume mappings
|
||||
volumes = [
|
||||
{
|
||||
host_path = "/path/on/host"
|
||||
container_path = "/path/in/container"
|
||||
read_only = false
|
||||
}
|
||||
]
|
||||
|
||||
// Environment variables
|
||||
env_vars = {
|
||||
VARIABLE_NAME = "value"
|
||||
}
|
||||
|
||||
// Container labels
|
||||
labels = {
|
||||
"com.example.description" = "My service description"
|
||||
}
|
||||
|
||||
// Enable Watchtower updates
|
||||
monitoring = true
|
||||
}
|
||||
```
|
||||
|
||||
## Required Providers
|
||||
|
||||
This module requires the Docker provider to be configured in your root module:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = ">= 3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
See the `variables.tf` file for a complete list of input variables and their descriptions.
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| container_name | Name of the Docker container |
|
||||
| container_id | ID of the Docker container |
|
||||
| image_id | ID of the Docker image |
|
||||
| ip_address | IP address of the container (if applicable) |
|
||||
| container_ports | Published ports of the container |
|
||||
133
modules/10-services-generic/docker-service/main.tf
Normal file
133
modules/10-services-generic/docker-service/main.tf
Normal file
@@ -0,0 +1,133 @@
|
||||
// Generic Docker service module
|
||||
// Creates and manages a Docker container with configurable options
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = ">= 3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
network_mode = var.network_mode
|
||||
container_name = var.container_name
|
||||
image_name = "${var.image}:${var.tag}"
|
||||
|
||||
// Prepare ports configuration
|
||||
ports_config = [
|
||||
for port in var.ports : {
|
||||
internal = port.internal
|
||||
external = port.external
|
||||
protocol = port.protocol
|
||||
}
|
||||
]
|
||||
|
||||
// Prepare volumes configuration
|
||||
volumes_config = [
|
||||
for volume in var.volumes : {
|
||||
host_path = volume.host_path
|
||||
container_path = volume.container_path
|
||||
read_only = volume.read_only
|
||||
}
|
||||
]
|
||||
|
||||
// Define monitoring labels if enabled
|
||||
monitoring_labels = var.monitoring ? {
|
||||
"com.centurylinklabs.watchtower.enable" = "true"
|
||||
} : {}
|
||||
|
||||
// Merge provided labels with monitoring labels
|
||||
merged_labels = merge(var.labels, local.monitoring_labels)
|
||||
}
|
||||
|
||||
// Pull the Docker image
|
||||
resource "docker_image" "service_image" {
|
||||
name = local.image_name
|
||||
keep_locally = var.keep_image_locally
|
||||
pull_triggers = [var.tag]
|
||||
}
|
||||
|
||||
// Create the Docker container
|
||||
resource "docker_container" "service_container" {
|
||||
name = local.container_name
|
||||
image = docker_image.service_image.image_id
|
||||
|
||||
restart = var.restart_policy
|
||||
|
||||
# Set the network mode (bridge, host, etc.)
|
||||
network_mode = local.network_mode
|
||||
|
||||
# Dynamically configure ports based on the provided list
|
||||
dynamic "ports" {
|
||||
for_each = local.ports_config
|
||||
content {
|
||||
internal = ports.value.internal
|
||||
external = ports.value.external
|
||||
protocol = ports.value.protocol
|
||||
}
|
||||
}
|
||||
|
||||
# Dynamically configure networks based on the provided list
|
||||
dynamic "networks_advanced" {
|
||||
for_each = var.networks
|
||||
content {
|
||||
name = networks_advanced.value
|
||||
}
|
||||
}
|
||||
|
||||
# Dynamically configure volumes based on the provided list
|
||||
dynamic "volumes" {
|
||||
for_each = local.volumes_config
|
||||
content {
|
||||
host_path = volumes.value.host_path
|
||||
container_path = volumes.value.container_path
|
||||
read_only = volumes.value.read_only
|
||||
}
|
||||
}
|
||||
|
||||
# Configure environment variables - map to array of strings
|
||||
env = [for k, v in var.env_vars : "${k}=${v}"]
|
||||
|
||||
# Set container labels
|
||||
dynamic "labels" {
|
||||
for_each = local.merged_labels
|
||||
content {
|
||||
label = labels.key
|
||||
value = labels.value
|
||||
}
|
||||
}
|
||||
|
||||
# Add container healthcheck if configured
|
||||
dynamic "healthcheck" {
|
||||
for_each = var.healthcheck != null ? [var.healthcheck] : []
|
||||
content {
|
||||
test = healthcheck.value.test
|
||||
interval = healthcheck.value.interval
|
||||
timeout = healthcheck.value.timeout
|
||||
start_period = healthcheck.value.start_period
|
||||
retries = healthcheck.value.retries
|
||||
}
|
||||
}
|
||||
|
||||
# Set resource limits if specified
|
||||
memory = var.memory_limit
|
||||
memory_swap = var.memory_swap_limit
|
||||
cpu_shares = var.cpu_shares
|
||||
|
||||
# Other container options
|
||||
dns = var.dns
|
||||
dns_search = var.dns_search
|
||||
hostname = var.hostname
|
||||
domainname = var.domainname
|
||||
user = var.user
|
||||
working_dir = var.working_dir
|
||||
command = var.command
|
||||
entrypoint = var.entrypoint
|
||||
privileged = var.privileged
|
||||
|
||||
# Set log options
|
||||
log_driver = var.log_driver
|
||||
log_opts = var.log_opts
|
||||
}
|
||||
24
modules/10-services-generic/docker-service/outputs.tf
Normal file
24
modules/10-services-generic/docker-service/outputs.tf
Normal file
@@ -0,0 +1,24 @@
|
||||
output "container_name" {
|
||||
description = "Name of the Docker container"
|
||||
value = docker_container.service_container.name
|
||||
}
|
||||
|
||||
output "container_id" {
|
||||
description = "ID of the Docker container"
|
||||
value = docker_container.service_container.id
|
||||
}
|
||||
|
||||
output "image_id" {
|
||||
description = "ID of the Docker image"
|
||||
value = docker_image.service_image.id
|
||||
}
|
||||
|
||||
output "ip_address" {
|
||||
description = "IP address of the container (if applicable)"
|
||||
value = docker_container.service_container.network_data != null ? docker_container.service_container.network_data[0].ip_address : null
|
||||
}
|
||||
|
||||
output "container_ports" {
|
||||
description = "Published ports of the container"
|
||||
value = docker_container.service_container.ports
|
||||
}
|
||||
181
modules/10-services-generic/docker-service/variables.tf
Normal file
181
modules/10-services-generic/docker-service/variables.tf
Normal file
@@ -0,0 +1,181 @@
|
||||
variable "container_name" {
|
||||
description = "Name of the Docker container"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "image" {
|
||||
description = "Docker image name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "tag" {
|
||||
description = "Docker image tag"
|
||||
type = string
|
||||
default = "latest"
|
||||
}
|
||||
|
||||
variable "keep_image_locally" {
|
||||
description = "Whether to keep the Docker image locally after pulling"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "restart_policy" {
|
||||
description = "Docker restart policy (no, always, unless-stopped, on-failure)"
|
||||
type = string
|
||||
default = "unless-stopped"
|
||||
}
|
||||
|
||||
variable "network_mode" {
|
||||
description = "Docker network mode (bridge, host, etc.)"
|
||||
type = string
|
||||
default = "bridge"
|
||||
}
|
||||
|
||||
variable "ports" {
|
||||
description = "List of port mappings"
|
||||
type = list(object({
|
||||
internal = number
|
||||
external = number
|
||||
protocol = string
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "networks" {
|
||||
description = "List of networks to connect the container to"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "volumes" {
|
||||
description = "List of volume mappings"
|
||||
type = list(object({
|
||||
host_path = string
|
||||
container_path = string
|
||||
read_only = bool
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "env_vars" {
|
||||
description = "Environment variables for the container"
|
||||
type = map(string)
|
||||
default = {}
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
description = "Docker container labels"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "monitoring" {
|
||||
description = "Enable container monitoring via Watchtower"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "healthcheck" {
|
||||
description = "Container healthcheck configuration"
|
||||
type = object({
|
||||
test = list(string)
|
||||
interval = string
|
||||
timeout = string
|
||||
start_period = string
|
||||
retries = number
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
// Resource limits
|
||||
variable "memory_limit" {
|
||||
description = "Memory limit for the container (in MB)"
|
||||
type = number
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "memory_swap_limit" {
|
||||
description = "Memory swap limit for the container (in MB)"
|
||||
type = number
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "cpu_shares" {
|
||||
description = "CPU shares for the container (relative weight)"
|
||||
type = number
|
||||
default = null
|
||||
}
|
||||
|
||||
// Networking options
|
||||
variable "dns" {
|
||||
description = "DNS servers for the container"
|
||||
type = list(string)
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "dns_search" {
|
||||
description = "DNS search domains for the container"
|
||||
type = list(string)
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "hostname" {
|
||||
description = "Container hostname"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "domainname" {
|
||||
description = "Container domainname"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
// Execution options
|
||||
variable "user" {
|
||||
description = "User to run commands as inside the container"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "working_dir" {
|
||||
description = "Working directory inside the container"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "command" {
|
||||
description = "Command to run when starting the container"
|
||||
type = list(string)
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "entrypoint" {
|
||||
description = "Entrypoint for the container"
|
||||
type = list(string)
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "privileged" {
|
||||
description = "Run container in privileged mode"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
// Logging options
|
||||
variable "log_driver" {
|
||||
description = "Log driver for the container"
|
||||
type = string
|
||||
default = "json-file"
|
||||
}
|
||||
|
||||
variable "log_opts" {
|
||||
description = "Log driver options"
|
||||
type = map(string)
|
||||
default = {
|
||||
max-size = "10m"
|
||||
max-file = "3"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user