Treafik woz 'ere
This commit is contained in:
parent
ef40638cd6
commit
618ca06093
57 changed files with 891 additions and 199 deletions
docker
network
service
socket-proxy
volume
products
forgejo/actions-runner
frigate
gitea/actions-runner
github/actions-runner
homeassistant
minio
mitmproxy
pgbackweb
portainer/ui
smokeping
statping
traefik
watchtower
|
@ -7,3 +7,15 @@ variable "labels" {
|
|||
default = {}
|
||||
description = "A map of labels to apply to the service"
|
||||
}
|
||||
|
||||
variable "network_name" {
|
||||
type = string
|
||||
description = "Override the automatically selected name of the network"
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "subnet" {
|
||||
type = string
|
||||
description = "The subnet to use for the network."
|
||||
default = null //"172.16.0.0/16"
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
locals {
|
||||
network_name = var.stack_name
|
||||
// Concat up the network name
|
||||
network_name = var.network_name != null ? "${var.stack_name}-${var.network_name}" : var.stack_name
|
||||
|
||||
// Attach labels
|
||||
labels = merge(var.labels, {
|
||||
"com.docker.stack.namespace" = var.stack_name
|
||||
"ooo.grey.network.stack" = var.stack_name
|
||||
"ooo.grey.network.name" = local.network_name
|
||||
#"ooo.grey.network.created" = timestamp()
|
||||
"ooo.grey.network.subnet" = local.subnet
|
||||
})
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
resource "docker_network" "instance" {
|
||||
name = local.network_name
|
||||
driver = "overlay"
|
||||
name = local.network_name
|
||||
driver = "overlay"
|
||||
attachable = true
|
||||
ipam_driver = "default"
|
||||
ipam_config {
|
||||
aux_address = {}
|
||||
subnet = local.subnet
|
||||
gateway = local.gateway
|
||||
}
|
||||
|
||||
# Attach labels
|
||||
dynamic "labels" {
|
||||
|
@ -10,4 +17,8 @@ resource "docker_network" "instance" {
|
|||
value = labels.value
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = false
|
||||
}
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
output "network" {
|
||||
value = docker_network.instance.id
|
||||
}
|
||||
output "name" {
|
||||
value = docker_network.instance.name
|
||||
}
|
||||
output "id" {
|
||||
value = docker_network.instance.id
|
||||
}
|
14
docker/network/subnet.tf
Normal file
14
docker/network/subnet.tf
Normal file
|
@ -0,0 +1,14 @@
|
|||
resource "random_integer" "upper_mid_byte" {
|
||||
min = 18
|
||||
max = 31
|
||||
}
|
||||
resource "random_integer" "lower_mid_byte" {
|
||||
min = 10
|
||||
max = 254
|
||||
}
|
||||
locals {
|
||||
// Generate a subnet
|
||||
subnet = var.subnet != null ? var.subnet : "172.${random_integer.upper_mid_byte.result}.${random_integer.lower_mid_byte.result}.0/24"
|
||||
// Calculate the gateway from the subnet
|
||||
gateway = cidrhost(local.subnet, 1)
|
||||
}
|
|
@ -5,6 +5,10 @@ terraform {
|
|||
source = "kreuzwerker/docker"
|
||||
version = "~>3.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~>3.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
/*
|
||||
resource "docker_image" "mirror" {
|
||||
count = var.mirror != null ? 1 : 0
|
||||
count = local.enable_mirror ? 1 : 0
|
||||
name = data.docker_registry_image.image.name
|
||||
pull_triggers = [data.docker_registry_image.image.sha256_digest]
|
||||
force_remove = false
|
||||
}
|
||||
resource "docker_tag" "mirror" {
|
||||
count = var.mirror != null ? 1 : 0
|
||||
count = local.enable_mirror ? 1 : 0
|
||||
source_image = docker_image.mirror[0].name
|
||||
target_image = var.mirror
|
||||
}
|
||||
resource "docker_registry_image" "mirror" {
|
||||
count = var.mirror != null ? 1 : 0
|
||||
count = local.enable_mirror ? 1 : 0
|
||||
depends_on = [docker_tag.mirror[0]]
|
||||
name = docker_tag.mirror[0].target_image
|
||||
keep_remotely = true
|
||||
}
|
||||
*/
|
|
@ -19,6 +19,11 @@ variable "restart_policy" {
|
|||
condition = var.restart_policy == "any" || var.restart_policy == "on-failure" || var.restart_policy == "none"
|
||||
}
|
||||
}
|
||||
variable "restart_delay" {
|
||||
type = string
|
||||
default = "0s"
|
||||
description = "The delay before restarting the service."
|
||||
}
|
||||
variable "one_shot" {
|
||||
type = bool
|
||||
default = false
|
||||
|
@ -53,9 +58,12 @@ variable "volumes" {
|
|||
description = "A map of volume names to create and mount. The key is the volume name, and the value is the mount point."
|
||||
}
|
||||
variable "remote_volumes" {
|
||||
type = map(string)
|
||||
type = map(object({
|
||||
id = string
|
||||
driver = string
|
||||
}))
|
||||
default = {}
|
||||
description = "A map of remote volumes to mount into the container."
|
||||
description = "A map of remote volumes to mount into the container. The key is the source, and the value is the target."
|
||||
}
|
||||
variable "mounts" {
|
||||
type = map(string)
|
||||
|
@ -76,8 +84,8 @@ variable "ports" {
|
|||
default = []
|
||||
description = "A map of port mappings to expose on the host. The key is the host port, and the value is the container port."
|
||||
validation {
|
||||
error_message = "Host Ports must be between 1024 and 65535."
|
||||
condition = alltrue([for port in var.ports : port.host >= 1024 && port.host <= 65535])
|
||||
error_message = "Host Ports must be between 1 and 65535."
|
||||
condition = alltrue([for port in var.ports : port.host >= 1 && port.host <= 65535])
|
||||
}
|
||||
validation {
|
||||
error_message = "Container Ports must be between 1 and 65535."
|
||||
|
@ -105,6 +113,11 @@ variable "parallelism" {
|
|||
type = number
|
||||
description = "The number of instances to run."
|
||||
}
|
||||
variable "parallelism_per_node" {
|
||||
default = 0
|
||||
type = number
|
||||
description = "The maximum number of instances to run per node. 0 means no limit."
|
||||
}
|
||||
variable "update_waves" {
|
||||
default = 3
|
||||
type = number
|
||||
|
@ -145,3 +158,31 @@ variable "converge_timeout" {
|
|||
type = string
|
||||
description = "The timeout for the service to converge."
|
||||
}
|
||||
variable "traefik" {
|
||||
default = null
|
||||
type = object({
|
||||
domain = string
|
||||
port = optional(number)
|
||||
})
|
||||
description = "Whether to enable traefik for the service."
|
||||
}
|
||||
variable "limit_cpu" {
|
||||
default = null
|
||||
type = number
|
||||
description = "The CPU limit for the service."
|
||||
}
|
||||
variable "limit_ram_mb" {
|
||||
default = null
|
||||
type = number
|
||||
description = "The RAM limit for the service, measured in megabytes."
|
||||
}
|
||||
variable "reserved_cpu" {
|
||||
default = null
|
||||
type = number
|
||||
description = "The CPU reservation for the service."
|
||||
}
|
||||
variable "reserved_ram_mb" {
|
||||
default = null
|
||||
type = number
|
||||
description = "The RAM reservation for the service, measured in megabytes."
|
||||
}
|
27
docker/service/labels.tf
Normal file
27
docker/service/labels.tf
Normal file
|
@ -0,0 +1,27 @@
|
|||
locals {
|
||||
# Define service labels en-masse
|
||||
labels = merge(var.labels, {
|
||||
"com.docker.stack.namespace" = var.stack_name
|
||||
"com.docker.stack.image" = data.docker_registry_image.image.name
|
||||
"ooo.grey.service.stack" = var.stack_name
|
||||
"ooo.grey.service.name" = var.service_name
|
||||
"ooo.grey.service.image" = data.docker_registry_image.image.name
|
||||
"ooo.grey.service.image.digest" = data.docker_registry_image.image.sha256_digest
|
||||
}, local.traefik_labels)
|
||||
|
||||
# Calculate the traefik labels to use if enabled
|
||||
traefik_labels = merge(
|
||||
(var.traefik == null ? {
|
||||
"traefik.enable" = "false"
|
||||
} : {
|
||||
"traefik.enable" = "true"
|
||||
"traefik.http.routers.${local.service_name}.rule" = "Host(`${var.traefik.domain}`)"
|
||||
"traefik.http.routers.${local.service_name}.entrypoints" = "websecure"
|
||||
"traefik.http.routers.${local.service_name}.tls.certresolver" = "default"
|
||||
}),
|
||||
(try(var.traefik.port, null) == null ? {} : {
|
||||
"traefik.http.services.${local.service_name}.loadbalancer.server.port" = var.traefik.port
|
||||
})
|
||||
)
|
||||
|
||||
}
|
|
@ -5,16 +5,9 @@ locals {
|
|||
substr(var.service_name, 0, 63 - 1 - 20),
|
||||
])
|
||||
|
||||
# Define service labels en-masse
|
||||
labels = merge(var.labels, {
|
||||
"com.docker.stack.namespace" = var.stack_name
|
||||
"com.docker.stack.image" = data.docker_registry_image.image.name
|
||||
"ooo.grey.service.stack" = var.stack_name
|
||||
"ooo.grey.service.name" = var.service_name
|
||||
"ooo.grey.service.image" = data.docker_registry_image.image.name
|
||||
"ooo.grey.service.image.digest" = data.docker_registry_image.image.sha256_digest
|
||||
})
|
||||
enable_mirror = false // var.mirror != null
|
||||
|
||||
# Calculate the docker image to use
|
||||
image = var.mirror != null ? "${docker_registry_image.mirror[0].name}@${docker_registry_image.mirror[0].sha256_digest}" : "${data.docker_registry_image.image.name}@${data.docker_registry_image.image.sha256_digest}"
|
||||
#image = local.enable_mirror ? "${docker_registry_image.mirror[0].name}@${docker_registry_image.mirror[0].sha256_digest}" : "${data.docker_registry_image.image.name}@${data.docker_registry_image.image.sha256_digest}"
|
||||
image = "${data.docker_registry_image.image.name}@${data.docker_registry_image.image.sha256_digest}"
|
||||
}
|
4
docker/service/networks.tf
Normal file
4
docker/service/networks.tf
Normal file
|
@ -0,0 +1,4 @@
|
|||
data "docker_network" "networks" {
|
||||
count = var.networks != null ? length(var.networks) : 0
|
||||
name = var.networks[count.index]
|
||||
}
|
|
@ -17,9 +17,10 @@ resource "docker_service" "instance" {
|
|||
dynamic "mounts" {
|
||||
for_each = var.volumes
|
||||
content {
|
||||
target = mounts.value
|
||||
source = docker_volume.volume[mounts.key].id
|
||||
type = "volume"
|
||||
source = docker_volume.volume[mounts.key].id
|
||||
target = mounts.value
|
||||
type = "volume"
|
||||
read_only = false # Nice assumption bro.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,9 +28,10 @@ resource "docker_service" "instance" {
|
|||
dynamic "mounts" {
|
||||
for_each = var.remote_volumes
|
||||
content {
|
||||
target = mounts.value
|
||||
source = mounts.key
|
||||
type = "volume"
|
||||
source = mounts.value.id
|
||||
target = mounts.key
|
||||
type = "volume"
|
||||
read_only = false # Nice assumption bro.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +39,8 @@ resource "docker_service" "instance" {
|
|||
dynamic "mounts" {
|
||||
for_each = var.mounts
|
||||
content {
|
||||
target = mounts.value
|
||||
source = mounts.key
|
||||
target = mounts.value
|
||||
type = "bind"
|
||||
read_only = false # Nice assumption bro.
|
||||
}
|
||||
|
@ -50,7 +52,7 @@ resource "docker_service" "instance" {
|
|||
content {
|
||||
config_id = module.config[configs.key].id
|
||||
config_name = module.config[configs.key].name
|
||||
file_name = configs.value
|
||||
file_name = configs.key
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,27 +85,41 @@ resource "docker_service" "instance" {
|
|||
|
||||
# Apply the networks
|
||||
dynamic "networks_advanced" {
|
||||
for_each = var.networks
|
||||
for_each = data.docker_network.networks
|
||||
content {
|
||||
name = networks_advanced.value
|
||||
name = networks_advanced.value.id
|
||||
}
|
||||
}
|
||||
|
||||
# Apply restart policy
|
||||
restart_policy {
|
||||
condition = var.one_shot ? "none" : var.restart_policy
|
||||
delay = "0s"
|
||||
delay = var.restart_delay
|
||||
window = "0s"
|
||||
max_attempts = 0
|
||||
}
|
||||
|
||||
# Apply the placement constraints
|
||||
placement {
|
||||
constraints = var.placement_constraints
|
||||
max_replicas = var.parallelism_per_node
|
||||
constraints = var.placement_constraints
|
||||
platforms {
|
||||
architecture = var.processor_architecture
|
||||
os = var.operating_system
|
||||
}
|
||||
}
|
||||
|
||||
# Apply the resource limits and reservations
|
||||
resources {
|
||||
limits {
|
||||
memory_bytes = var.limit_ram_mb != null ? 1024 * 1024 * var.limit_ram_mb : 0
|
||||
nano_cpus = var.limit_cpu != null ? (1000000000 / 100) * var.limit_cpu : 0
|
||||
}
|
||||
reservation {
|
||||
memory_bytes = var.reserved_ram_mb != null ? 1024 * 1024 * var.reserved_ram_mb : 0
|
||||
nano_cpus = var.reserved_cpu != null ? (1000000000 / 100) * var.reserved_cpu : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Global deploy
|
||||
|
|
|
@ -19,7 +19,8 @@ variable "service_name" {
|
|||
description = "The name of the service to create."
|
||||
}
|
||||
variable "placement_constraints" {
|
||||
default = ["node.role == manager"]
|
||||
default = []
|
||||
type = list(string)
|
||||
description = "Docker Swarm placement constraints"
|
||||
}
|
||||
|
||||
|
|
6
docker/socket-proxy/output.tf
Normal file
6
docker/socket-proxy/output.tf
Normal file
|
@ -0,0 +1,6 @@
|
|||
output "docker_service" {
|
||||
value = module.service.docker_service
|
||||
}
|
||||
output "network" {
|
||||
value = module.network.network
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
module "network" {
|
||||
source = "../network"
|
||||
name = "docker-socket-proxy"
|
||||
stack_name = var.stack_name
|
||||
source = "../network"
|
||||
network_name = "docker-socket-proxy"
|
||||
stack_name = var.stack_name
|
||||
}
|
||||
module "service" {
|
||||
source = "../service"
|
||||
image = "${var.docker_socket_proxy_image}:${var.docker_socket_proxy_version}"
|
||||
command = ["/docker-entrypoint.sh", "sockd-username"]
|
||||
stack_name = var.stack_name
|
||||
service_name = var.service_name
|
||||
source = "../service"
|
||||
image = "${var.docker_socket_proxy_image}:${var.docker_socket_proxy_version}"
|
||||
stack_name = var.stack_name
|
||||
service_name = var.service_name
|
||||
placement_constraints = concat(["node.role == manager"], var.placement_constraints)
|
||||
global = true
|
||||
networks = [module.network.network]
|
||||
mounts = { "/var/run/docker.sock" = "/var/run/docker.sock" }
|
||||
environment_variables = {
|
||||
SWARM = 1
|
||||
SERVICES = 1
|
||||
|
@ -17,18 +20,4 @@ module "service" {
|
|||
NODES = 1
|
||||
NETWORKS = 1
|
||||
}
|
||||
placement_constraints = var.placement_constraints
|
||||
global = true
|
||||
networks = [module.network.network.id]
|
||||
mounts = [
|
||||
{
|
||||
target = "/var/run/docker.sock"
|
||||
source = "/var/run/docker.sock"
|
||||
read_only = false
|
||||
type = "bind"
|
||||
}
|
||||
]
|
||||
}
|
||||
output "network" {
|
||||
value = module.network.network
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
output "source" {
|
||||
value = docker_volume.volume.id
|
||||
}
|
||||
output "volume" {
|
||||
value = docker_volume.volume
|
||||
}
|
|
@ -13,9 +13,7 @@ module "forgejo_actions_runner" {
|
|||
forgejo_RUNNER_REGISTRATION_TOKEN = var.forgejo_token
|
||||
CONFIG_FILE = "/config.yaml"
|
||||
}
|
||||
mounts = {
|
||||
"/var/run/docker.sock" = "/var/run/docker.sock"
|
||||
}
|
||||
mounts = { "/var/run/docker.sock" = "/var/run/docker.sock" }
|
||||
configs = {
|
||||
forgejo-config = yamlencode({
|
||||
name_prefix = ["forgejo-config", var.stack_name, var.service_name]
|
||||
|
|
55
products/frigate/frigate.tf
Normal file
55
products/frigate/frigate.tf
Normal file
|
@ -0,0 +1,55 @@
|
|||
data "docker_registry_image" "frigate" {
|
||||
name = "ghcr.io/blakeblackshear/frigate:stable"
|
||||
}
|
||||
|
||||
resource "docker_container" "frigate" {
|
||||
image = "${data.docker_registry_image.frigate.name}@${data.docker_registry_image.frigate.sha256_digest}"
|
||||
name = local.container_name
|
||||
restart = "unless-stopped"
|
||||
privileged = "true"
|
||||
shm_size = var.shm_size_mb
|
||||
network_mode = "bridge"
|
||||
env = [
|
||||
"FRIGATE_RTSP_PASSWORD=${var.frigate_rtsp_password}"
|
||||
]
|
||||
dynamic "devices" {
|
||||
for_each = var.devices
|
||||
content {
|
||||
host_path = devices.value.host_path
|
||||
container_path = devices.value.container_path
|
||||
permissions = devices.value.permissions
|
||||
}
|
||||
}
|
||||
dynamic "volumes" {
|
||||
for_each = var.volumes
|
||||
content {
|
||||
container_path = volumes.value
|
||||
host_path = volumes.key
|
||||
read_only = false
|
||||
}
|
||||
}
|
||||
dynamic "ports" {
|
||||
for_each = var.ports
|
||||
content {
|
||||
internal = ports.value.container
|
||||
external = ports.value.host
|
||||
protocol = ports.value.protocol
|
||||
}
|
||||
}
|
||||
dynamic "networks_advanced" {
|
||||
for_each = var.networks
|
||||
content {
|
||||
name = networks_advanced.value
|
||||
}
|
||||
}
|
||||
dynamic "labels" {
|
||||
for_each = local.labels
|
||||
content {
|
||||
label = labels.key
|
||||
value = labels.value
|
||||
}
|
||||
}
|
||||
lifecycle {
|
||||
create_before_destroy = false
|
||||
}
|
||||
}
|
82
products/frigate/inputs.tf
Normal file
82
products/frigate/inputs.tf
Normal file
|
@ -0,0 +1,82 @@
|
|||
variable "stack_name" {
|
||||
type = string
|
||||
description = "The name of the stack to deploy the service to."
|
||||
}
|
||||
variable "shm_size_mb" {
|
||||
default = 256
|
||||
type = number
|
||||
description = "The size of the shared memory segment in MB"
|
||||
}
|
||||
variable "networks" {
|
||||
type = list(string)
|
||||
default = []
|
||||
description = "A list of network names to attach the service to."
|
||||
}
|
||||
variable "frigate_rtsp_password" {
|
||||
type = string
|
||||
description = "The password to use for the RTSP streams"
|
||||
default = ""
|
||||
}
|
||||
variable "devices" {
|
||||
type = list(object({
|
||||
host_path = string
|
||||
container_path = string
|
||||
permissions = optional(string, "rwm")
|
||||
}))
|
||||
description = "The devices to mount into the container"
|
||||
}
|
||||
variable "volumes" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
description = "A map of volume names to create and mount. The key is the volume name, and the value is the mount point."
|
||||
}
|
||||
|
||||
variable "ports" {
|
||||
type = list(object({
|
||||
host = number
|
||||
container = number
|
||||
protocol = optional(string, "tcp")
|
||||
}))
|
||||
default = [
|
||||
{
|
||||
container = 5000
|
||||
host = 5000
|
||||
protocol = "tcp"
|
||||
},
|
||||
{
|
||||
container = 1935
|
||||
host = 1935
|
||||
protocol = "tcp"
|
||||
},
|
||||
{
|
||||
container = 8554
|
||||
host = 8554
|
||||
protocol = "tcp"
|
||||
},
|
||||
{
|
||||
container = 8555
|
||||
host = 8555
|
||||
protocol = "tcp"
|
||||
},
|
||||
{
|
||||
container = 8555
|
||||
host = 8555
|
||||
protocol = "udp"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
variable "traefik" {
|
||||
default = null
|
||||
type = object({
|
||||
domain = string
|
||||
port = optional(number, 5000)
|
||||
})
|
||||
description = "Whether to enable traefik for the service."
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
description = "A map of labels to apply to the service"
|
||||
}
|
24
products/frigate/labels.tf
Normal file
24
products/frigate/labels.tf
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
locals {
|
||||
container_name = "frigate"
|
||||
# Define service labels en-masse
|
||||
labels = merge({
|
||||
"com.docker.stack.namespace" = var.stack_name
|
||||
"com.docker.stack.image" = data.docker_registry_image.frigate.name
|
||||
"ooo.grey.service.stack" = var.stack_name
|
||||
"ooo.grey.service.name" = local.container_name
|
||||
"ooo.grey.service.image" = data.docker_registry_image.frigate.name
|
||||
"ooo.grey.service.image.digest" = data.docker_registry_image.frigate.sha256_digest
|
||||
}, local.traefik_labels, var.labels)
|
||||
|
||||
# Calculate the traefik labels to use if enabled
|
||||
traefik_labels = var.traefik != null ? {
|
||||
"traefik.enable" = "true"
|
||||
"traefik.http.routers.${local.container_name}.rule" = "Host(`${var.traefik.domain}`)"
|
||||
"traefik.http.routers.${local.container_name}.entrypoints" = "websecure"
|
||||
"traefik.http.routers.${local.container_name}.tls.certresolver" = "default"
|
||||
"traefik.http.services.${local.container_name}.loadbalancer.server.port" = 5000
|
||||
} : {
|
||||
"traefik.enable" = "false"
|
||||
}
|
||||
}
|
3
products/frigate/output.tf
Normal file
3
products/frigate/output.tf
Normal file
|
@ -0,0 +1,3 @@
|
|||
output "endpoint" {
|
||||
value = try("https://${var.traefik.domain}", "unknown")
|
||||
}
|
11
products/frigate/terraform.tf
Normal file
11
products/frigate/terraform.tf
Normal file
|
@ -0,0 +1,11 @@
|
|||
terraform {
|
||||
required_version = "~> 1.6"
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~>3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -12,9 +12,7 @@ module "gitea_actions_runner" {
|
|||
GITEA_RUNNER_REGISTRATION_TOKEN = var.gitea_token
|
||||
CONFIG_FILE = "/config.yaml"
|
||||
}
|
||||
mounts = {
|
||||
"/var/run/docker.sock" = "/var/run/docker.sock"
|
||||
}
|
||||
mounts = { "/var/run/docker.sock" = "/var/run/docker.sock" }
|
||||
configs = {
|
||||
gitea-config = {
|
||||
name_prefix = ["gitea-config", var.stack_name, var.service_name]
|
||||
|
|
|
@ -15,7 +15,5 @@ module "github_actions_runner" {
|
|||
EPHEMERAL = true
|
||||
DISABLE_AUTO_UPDATE = "disable_updates"
|
||||
}
|
||||
mounts = {
|
||||
"/var/run/docker.sock" = "/var/run/docker.sock"
|
||||
}
|
||||
mounts = { "/var/run/docker.sock" = "/var/run/docker.sock" }
|
||||
}
|
13
products/homeassistant/homeassistant.tf
Normal file
13
products/homeassistant/homeassistant.tf
Normal file
|
@ -0,0 +1,13 @@
|
|||
module "homeassistant" {
|
||||
source = "../../docker/service"
|
||||
stack_name = var.stack_name
|
||||
service_name = "homeassistant"
|
||||
image = var.default_image
|
||||
environment_variables = merge({ TZ = "Europe/London" }, var.environment_variables)
|
||||
mounts = var.mounts
|
||||
networks = var.networks
|
||||
placement_constraints = var.placement_constraints
|
||||
ports = [{ host = 8123, container = 8123 }]
|
||||
traefik = var.traefik
|
||||
converge_timeout = "5m"
|
||||
}
|
35
products/homeassistant/inputs.tf
Normal file
35
products/homeassistant/inputs.tf
Normal file
|
@ -0,0 +1,35 @@
|
|||
variable "stack_name" {
|
||||
default = "homeassistant"
|
||||
type = string
|
||||
description = "The name of the stack to create."
|
||||
}
|
||||
|
||||
variable "default_image" {
|
||||
default = "ghcr.io/home-assistant/home-assistant:stable"
|
||||
type = string
|
||||
description = "The image to use for the homeassistant service"
|
||||
}
|
||||
|
||||
variable "environment_variables" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
description = "A map of environment variables to set in the container."
|
||||
}
|
||||
variable "mounts" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
description = "A map of host paths to container paths to mount. The key is the host path, and the value is the container path."
|
||||
}
|
||||
variable "networks" {
|
||||
type = list(string)
|
||||
default = []
|
||||
description = "A list of network names to attach the service to."
|
||||
}
|
||||
variable "placement_constraints" {
|
||||
default = []
|
||||
type = list(string)
|
||||
description = "Docker Swarm placement constraints"
|
||||
}
|
||||
variable "traefik" {
|
||||
|
||||
}
|
3
products/homeassistant/outputs.tf
Normal file
3
products/homeassistant/outputs.tf
Normal file
|
@ -0,0 +1,3 @@
|
|||
output "docker_service" {
|
||||
value = module.homeassistant.docker_service
|
||||
}
|
15
products/homeassistant/terraform.tf
Normal file
15
products/homeassistant/terraform.tf
Normal file
|
@ -0,0 +1,15 @@
|
|||
terraform {
|
||||
required_version = "~> 1.6"
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~>3.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
24
products/minio/inputs.tf
Normal file
24
products/minio/inputs.tf
Normal file
|
@ -0,0 +1,24 @@
|
|||
variable "stack_name" {
|
||||
default = "mitmproxy"
|
||||
type = string
|
||||
description = "The name of the stack to create."
|
||||
}
|
||||
variable "networks" {
|
||||
type = list(string)
|
||||
default = []
|
||||
description = "A list of network names to attach the service to."
|
||||
}
|
||||
|
||||
variable "traefik" {
|
||||
default = null
|
||||
type = object({
|
||||
domain = string
|
||||
port = optional(number)
|
||||
})
|
||||
description = "Whether to enable traefik for the service."
|
||||
}
|
||||
variable "placement_constraints" {
|
||||
default = []
|
||||
type = list(string)
|
||||
description = "Docker Swarm placement constraints"
|
||||
}
|
64
products/minio/minio.tf
Normal file
64
products/minio/minio.tf
Normal file
|
@ -0,0 +1,64 @@
|
|||
resource "random_pet" "minio_admin_user" {
|
||||
length = 2
|
||||
separator = ""
|
||||
}
|
||||
resource "random_password" "minio_admin_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
variable "domain" {
|
||||
type = string
|
||||
description = "The domain to use for the service."
|
||||
}
|
||||
variable "mounts" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
description = "A map of host paths to container paths to mount. The key is the host path, and the value is the container path."
|
||||
}
|
||||
module "minio" {
|
||||
source = "../../docker/service"
|
||||
stack_name = "minio"
|
||||
service_name = "minio"
|
||||
image = "quay.io/minio/minio:latest"
|
||||
command = ["minio", "server", "/data", ]
|
||||
environment_variables = {
|
||||
MINIO_ADDRESS = "0.0.0.0:9000"
|
||||
MINIO_CONSOLE_ADDRESS = "0.0.0.0:9001"
|
||||
MINIO_ROOT_USER = random_pet.minio_admin_user.id
|
||||
MINIO_ROOT_PASSWORD = random_password.minio_admin_password.result
|
||||
MINIO_SERVER_URL = "https://s3.grey.ooo"
|
||||
MINIO_BROWSER_REDIRECT_URL = "https://s3.grey.ooo/ui/"
|
||||
MINIO_BROWSER_REDIRECT = true
|
||||
MINIO_API_ROOT_ACCESS = "on"
|
||||
}
|
||||
mounts = var.mounts
|
||||
networks = concat(["loadbalancer-traefik"], var.networks)
|
||||
placement_constraints = var.placement_constraints
|
||||
labels = {
|
||||
"traefik.enable" = "true"
|
||||
|
||||
// API redirect
|
||||
"traefik.http.routers.minio_api.rule" = "Host(`${var.domain}`) && !PathPrefix(`/ui`)"
|
||||
#"traefik.http.routers.minio_api.service" = "minio_api"
|
||||
"traefik.http.routers.minio_api.entrypoints" = "websecure"
|
||||
"traefik.http.routers.minio_api.tls.certresolver" = "default"
|
||||
"traefik.http.services.minio_api.loadbalancer.server.port" = "9000"
|
||||
|
||||
// UI redirect
|
||||
"traefik.http.routers.minio_ui.rule" = "Host(`${var.domain}`) && PathPrefix(`/ui`)"
|
||||
#"traefik.http.routers.minio_ui.service" = "minio_ui"
|
||||
"traefik.http.routers.minio_ui.entrypoints" = "websecure"
|
||||
"traefik.http.routers.minio_ui.tls.certresolver" = "default"
|
||||
"traefik.http.services.minio_ui.loadbalancer.server.port" = "9001"
|
||||
}
|
||||
}
|
||||
|
||||
output "minio" {
|
||||
value = {
|
||||
endpoint = "https://${var.domain}/ui/"
|
||||
auth = {
|
||||
username = module.minio.docker_service.task_spec[0].container_spec[0].env.MINIO_ROOT_USER
|
||||
password = nonsensitive(module.minio.docker_service.task_spec[0].container_spec[0].env.MINIO_ROOT_PASSWORD)
|
||||
}
|
||||
}
|
||||
}
|
3
products/minio/outputs.tf
Normal file
3
products/minio/outputs.tf
Normal file
|
@ -0,0 +1,3 @@
|
|||
output "docker_service" {
|
||||
value = module.minio.docker_service
|
||||
}
|
15
products/minio/terraform.tf
Normal file
15
products/minio/terraform.tf
Normal file
|
@ -0,0 +1,15 @@
|
|||
terraform {
|
||||
required_version = "~> 1.6"
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~>3.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
25
products/mitmproxy/inputs.tf
Normal file
25
products/mitmproxy/inputs.tf
Normal file
|
@ -0,0 +1,25 @@
|
|||
variable "stack_name" {
|
||||
default = "mitmproxy"
|
||||
type = string
|
||||
description = "The name of the stack to create."
|
||||
}
|
||||
|
||||
variable "networks" {
|
||||
type = list(string)
|
||||
default = []
|
||||
description = "A list of network names to attach the service to."
|
||||
}
|
||||
|
||||
variable "traefik" {
|
||||
default = null
|
||||
type = object({
|
||||
domain = string
|
||||
port = optional(number, 8081)
|
||||
})
|
||||
description = "Whether to enable traefik for the service."
|
||||
}
|
||||
variable "placement_constraints" {
|
||||
default = []
|
||||
type = list(string)
|
||||
description = "Docker Swarm placement constraints"
|
||||
}
|
30
products/mitmproxy/mitmproxy.tf
Normal file
30
products/mitmproxy/mitmproxy.tf
Normal file
|
@ -0,0 +1,30 @@
|
|||
module "mitmproxy" {
|
||||
source = "../../docker/service"
|
||||
stack_name = var.stack_name
|
||||
service_name = "mitmproxy"
|
||||
networks = var.networks
|
||||
image = "ghcr.io/benzine-framework/mitmproxy"
|
||||
command = [
|
||||
"mitmweb",
|
||||
"--web-host", "0.0.0.0",
|
||||
"--web-port", "8081",
|
||||
#"--listen-host", "0.0.0.0",
|
||||
#"--listen-port", "8080",
|
||||
#"--ssl-insecure",
|
||||
]
|
||||
healthcheck = ["CMD-SHELL", " curl -I http://localhost:8081 || exit 1"]
|
||||
placement_constraints = var.placement_constraints
|
||||
traefik = var.traefik
|
||||
ports = [
|
||||
{
|
||||
protocol = "tcp"
|
||||
container = 8080
|
||||
host = 4080
|
||||
},
|
||||
{
|
||||
protocol = "tcp"
|
||||
container = 8081
|
||||
host = 4081
|
||||
}
|
||||
]
|
||||
}
|
3
products/mitmproxy/outputs.tf
Normal file
3
products/mitmproxy/outputs.tf
Normal file
|
@ -0,0 +1,3 @@
|
|||
output "docker_service" {
|
||||
value = module.mitmproxy.docker_service
|
||||
}
|
11
products/mitmproxy/terraform.tf
Normal file
11
products/mitmproxy/terraform.tf
Normal file
|
@ -0,0 +1,11 @@
|
|||
terraform {
|
||||
required_version = "~> 1.6"
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~>3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27,3 +27,7 @@ variable "networks" {
|
|||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
variable "domain" {
|
||||
type = string
|
||||
description = "The domain to use for the service's traefik configuration."
|
||||
}
|
|
@ -17,6 +17,7 @@ module "pgbackweb" {
|
|||
service_name = var.service_name
|
||||
networks = concat([module.network.network], var.networks)
|
||||
placement_constraints = var.placement_constraints
|
||||
traefik = { domain = var.domain }
|
||||
}
|
||||
module "postgres" {
|
||||
source = "../postgres"
|
||||
|
|
|
@ -1,16 +1,33 @@
|
|||
variable "docker" {
|
||||
type = object({
|
||||
name = string
|
||||
stack_name = optional(string)
|
||||
networks = list(object({
|
||||
name = string
|
||||
id = string
|
||||
}))
|
||||
})
|
||||
variable "stack_name" {
|
||||
default = "loadbalancer"
|
||||
type = string
|
||||
description = "The name of the stack to create."
|
||||
}
|
||||
variable "portainer" {
|
||||
variable "traefik" {
|
||||
default = null
|
||||
type = object({
|
||||
version = string
|
||||
logo = optional(string)
|
||||
domain = string
|
||||
port = optional(number, 9000)
|
||||
})
|
||||
description = "Whether to enable traefik for the service."
|
||||
}
|
||||
variable "placement_constraints" {
|
||||
default = []
|
||||
type = list(string)
|
||||
description = "Docker Swarm placement constraints"
|
||||
}
|
||||
|
||||
variable "portainer_version" {
|
||||
default = "sts"
|
||||
type = string
|
||||
description = "The version of the portainer image to use."
|
||||
}
|
||||
variable "portainer_logo" {
|
||||
default = null
|
||||
type = string
|
||||
description = "The URL of the logo to use for the portainer service."
|
||||
}
|
||||
variable "should_mount_local_docker_socket" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
|
@ -4,6 +4,6 @@ output "portainer" {
|
|||
username = "admin" # Sorry, this is hardcoded in the portainer image
|
||||
password = nonsensitive(random_password.password.result)
|
||||
}
|
||||
service_name = docker_service.portainer.name
|
||||
service_name = module.portainer.docker_service.name
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,99 +8,31 @@ resource "htpasswd_password" "hash" {
|
|||
password = random_password.password.result
|
||||
salt = random_password.salt.result
|
||||
}
|
||||
data "docker_registry_image" "portainer_app" {
|
||||
name = "portainer/portainer-ce:${var.portainer.version}"
|
||||
module "vol_portainer" {
|
||||
source = "../../../docker/volume"
|
||||
stack_name = var.stack_name
|
||||
volume_name = "portainer"
|
||||
}
|
||||
resource "docker_volume" "portainer" {
|
||||
name = var.docker.name
|
||||
}
|
||||
resource "docker_service" "portainer" {
|
||||
name = var.docker.name
|
||||
mode {
|
||||
replicated {
|
||||
replicas = 1
|
||||
}
|
||||
}
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "${data.docker_registry_image.portainer_app.name}@${data.docker_registry_image.portainer_app.sha256_digest}"
|
||||
command = [
|
||||
"/portainer",
|
||||
//"--edge-compute",
|
||||
"--logo", coalesce(var.portainer.logo),
|
||||
"--admin-password", htpasswd_password.hash.bcrypt,
|
||||
]
|
||||
#mounts {
|
||||
# target = "/data"
|
||||
# source = "/portainer"
|
||||
# read_only = false
|
||||
# type = "bind"
|
||||
#}
|
||||
mounts {
|
||||
target = "/data"
|
||||
source = docker_volume.portainer.name
|
||||
type = "volume"
|
||||
read_only = false
|
||||
}
|
||||
#mounts {
|
||||
# target = "/var/run/docker.sock"
|
||||
# source = "/var/run/docker.sock"
|
||||
# read_only = false
|
||||
# type = "bind"
|
||||
#}
|
||||
labels {
|
||||
label = "com.docker.stack.namespace"
|
||||
value = var.docker.stack_name
|
||||
}
|
||||
}
|
||||
dynamic "networks_advanced" {
|
||||
for_each = var.docker.networks
|
||||
content {
|
||||
name = networks_advanced.value.id
|
||||
}
|
||||
}
|
||||
restart_policy {
|
||||
condition = "on-failure"
|
||||
delay = "3s"
|
||||
max_attempts = 4
|
||||
window = "10s"
|
||||
}
|
||||
placement {
|
||||
constraints = [
|
||||
"node.role == manager",
|
||||
"node.platform.os == linux",
|
||||
]
|
||||
}
|
||||
}
|
||||
#endpoint_spec {
|
||||
# ports {
|
||||
# target_port = 9000
|
||||
# publish_mode = "ingress"
|
||||
# published_port = 9000
|
||||
# }
|
||||
# ports {
|
||||
# target_port = 8000
|
||||
# publish_mode = "ingress"
|
||||
# published_port = 8000
|
||||
# }
|
||||
#}
|
||||
update_config {
|
||||
# Portainer gets super fuckin' upset if you start a second instance while the first is holding the db lock
|
||||
order = "stop-first"
|
||||
}
|
||||
|
||||
labels {
|
||||
label = "com.docker.stack.namespace"
|
||||
value = var.docker.stack_name
|
||||
}
|
||||
labels {
|
||||
label = "com.docker.stack.image"
|
||||
value = replace(data.docker_registry_image.portainer_app.name, "/:.*/", "")
|
||||
}
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
# MB: This is a hack because terraform keeps detecting a "change" in the placement->platform constraint that doesn't exist.
|
||||
task_spec[0].placement[0].platforms
|
||||
]
|
||||
}
|
||||
module "portainer" {
|
||||
source = "../../../docker/service"
|
||||
stack_name = var.stack_name
|
||||
service_name = "portainer"
|
||||
image = "portainer/portainer-ce:${var.portainer_version}"
|
||||
command = [
|
||||
"/portainer",
|
||||
//"--edge-compute",
|
||||
"--logo", coalesce(var.portainer_logo),
|
||||
"--admin-password", htpasswd_password.hash.bcrypt,
|
||||
]
|
||||
remote_volumes = {
|
||||
"/data" = module.vol_portainer.volume
|
||||
}
|
||||
traefik = var.traefik
|
||||
mounts = var.should_mount_local_docker_socket ? { "/var/run/docker.sock" = "/var/run/docker.sock" } : {}
|
||||
networks = ["loadbalancer-traefik"]
|
||||
start_first = false
|
||||
placement_constraints = concat([
|
||||
"node.role == manager",
|
||||
"node.platform.os == linux",
|
||||
], var.placement_constraints)
|
||||
}
|
||||
|
|
18
products/smokeping/inputs.tf
Normal file
18
products/smokeping/inputs.tf
Normal file
|
@ -0,0 +1,18 @@
|
|||
variable "timezone" {
|
||||
type = string
|
||||
description = "The timezone to use for the service."
|
||||
default = "Europe/London"
|
||||
}
|
||||
variable "traefik" {
|
||||
default = null
|
||||
type = object({
|
||||
domain = string
|
||||
port = optional(number)
|
||||
})
|
||||
description = "Whether to enable traefik for the service."
|
||||
}
|
||||
variable "placement_constraints" {
|
||||
default = []
|
||||
type = list(string)
|
||||
description = "Docker Swarm placement constraints"
|
||||
}
|
3
products/smokeping/outputs.tf
Normal file
3
products/smokeping/outputs.tf
Normal file
|
@ -0,0 +1,3 @@
|
|||
output "docker_service" {
|
||||
value = module.smokeping.docker_service
|
||||
}
|
15
products/smokeping/smokeping.tf
Normal file
15
products/smokeping/smokeping.tf
Normal file
|
@ -0,0 +1,15 @@
|
|||
module "smokeping" {
|
||||
source = "../../docker/service"
|
||||
stack_name = "smokeping"
|
||||
service_name = "smokeping"
|
||||
image = "linuxserver/smokeping:latest"
|
||||
volumes = { "smokeping" = "/data" }
|
||||
environment_variables = {
|
||||
PUID = 1000
|
||||
PGID = 1000
|
||||
TZ = var.timezone
|
||||
}
|
||||
traefik = var.traefik
|
||||
networks = ["loadbalancer-traefik"]
|
||||
placement_constraints = var.placement_constraints
|
||||
}
|
16
products/smokeping/terraform.tf
Normal file
16
products/smokeping/terraform.tf
Normal file
|
@ -0,0 +1,16 @@
|
|||
terraform {
|
||||
required_version = "~> 1.6"
|
||||
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~>3.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,3 +42,11 @@ variable "extra_environment_variables" {
|
|||
default = {}
|
||||
description = "Extra environment variables to pass to the service."
|
||||
}
|
||||
variable "traefik" {
|
||||
default = null
|
||||
type = object({
|
||||
domain = string
|
||||
port = optional(number)
|
||||
})
|
||||
description = "Whether to enable traefik for the service."
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
variable "nginx_hostname" {
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
variable "acme_certificate" {
|
||||
type = object({
|
||||
private_key_pem = string
|
||||
certificate_pem = string
|
||||
issuer_pem = string
|
||||
})
|
||||
default = null
|
||||
}
|
||||
module "nginx_config" {
|
||||
count = var.nginx_hostname != null ? 1 : 0
|
||||
source = "../nginx/site-available"
|
||||
service_name = module.service.service_name
|
||||
hostname = var.nginx_hostname
|
||||
upstream_host = "${module.service.service_name}:8080"
|
||||
config_prefix = module.service.service_name
|
||||
certificate = var.acme_certificate
|
||||
}
|
||||
output "nginx_files" {
|
||||
value = var.nginx_hostname != null ? module.nginx_config[0].files : []
|
||||
}
|
|
@ -7,7 +7,7 @@ output "statping" {
|
|||
port = module.postgres.ports[0]
|
||||
}
|
||||
statping = {
|
||||
instance = var.nginx_hostname != null ? "https://${var.nginx_hostname}" : null
|
||||
instance = try("https://${var.traefik.domain}", "unknown")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ module "service" {
|
|||
image = "${var.statping_image}:${var.statping_version}"
|
||||
stack_name = var.stack_name
|
||||
service_name = "statping"
|
||||
networks = concat([module.network.network, ], var.networks)
|
||||
networks = concat([module.network.network, "loadbalancer-traefik"], var.networks)
|
||||
environment_variables = merge({
|
||||
VIRTUAL_HOST = "localhost"
|
||||
VIRTUAL_PORT = "8080"
|
||||
|
@ -29,4 +29,5 @@ module "service" {
|
|||
}, var.extra_environment_variables)
|
||||
placement_constraints = var.placement_constraints
|
||||
dns_nameservers = var.dns_nameservers
|
||||
traefik = var.traefik
|
||||
}
|
||||
|
|
5
products/traefik/docker-socket-proxy.tf
Normal file
5
products/traefik/docker-socket-proxy.tf
Normal file
|
@ -0,0 +1,5 @@
|
|||
module "docker_socket_proxy" {
|
||||
source = "../../docker/socket-proxy"
|
||||
stack_name = var.stack_name
|
||||
placement_constraints = var.placement_constraints
|
||||
}
|
14
products/traefik/hello.tf
Normal file
14
products/traefik/hello.tf
Normal file
|
@ -0,0 +1,14 @@
|
|||
module "traefik_hello" {
|
||||
count = var.hello_service_domain != null ? 1 : 0
|
||||
source = "../../docker/service"
|
||||
stack_name = var.stack_name
|
||||
service_name = "hello"
|
||||
image = "traefik/whoami"
|
||||
parallelism = 3
|
||||
placement_constraints = var.placement_constraints
|
||||
networks = [module.traefik_network.network, ]
|
||||
traefik = {
|
||||
domain = var.hello_service_domain
|
||||
port = 80
|
||||
}
|
||||
}
|
43
products/traefik/inputs.tf
Normal file
43
products/traefik/inputs.tf
Normal file
|
@ -0,0 +1,43 @@
|
|||
variable "stack_name" {
|
||||
default = "loadbalancer"
|
||||
type = string
|
||||
description = "The name of the stack to create."
|
||||
}
|
||||
|
||||
variable "placement_constraints" {
|
||||
default = []
|
||||
type = list(string)
|
||||
description = "Docker Swarm placement constraints"
|
||||
}
|
||||
variable "acme_use_staging" {
|
||||
type = bool
|
||||
default = false
|
||||
description = "Whether to use the Let's Encrypt staging server."
|
||||
}
|
||||
variable "acme_email" {
|
||||
description = "The email address to use for the ACME certificate."
|
||||
type = string
|
||||
}
|
||||
variable "traefik_service_domain" {
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
variable "hello_service_domain" {
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
variable "log_level" {
|
||||
type = string
|
||||
default = "INFO"
|
||||
description = "The log level to use for traefik."
|
||||
}
|
||||
variable "access_log" {
|
||||
type = bool
|
||||
default = false
|
||||
description = "Whether to enable access logging."
|
||||
}
|
||||
variable "redirect_to_ssl" {
|
||||
type = bool
|
||||
default = true
|
||||
description = "Whether to redirect HTTP to HTTPS."
|
||||
}
|
6
products/traefik/network.tf
Normal file
6
products/traefik/network.tf
Normal file
|
@ -0,0 +1,6 @@
|
|||
module "traefik_network" {
|
||||
source = "../../docker/network"
|
||||
stack_name = var.stack_name
|
||||
network_name = "traefik"
|
||||
subnet = "172.16.0.0/22"
|
||||
}
|
6
products/traefik/outputs.tf
Normal file
6
products/traefik/outputs.tf
Normal file
|
@ -0,0 +1,6 @@
|
|||
output "docker_service" {
|
||||
value = module.traefik.docker_service
|
||||
}
|
||||
output "docker_network" {
|
||||
value = module.traefik_network
|
||||
}
|
13
products/traefik/terraform.tf
Normal file
13
products/traefik/terraform.tf
Normal file
|
@ -0,0 +1,13 @@
|
|||
terraform {
|
||||
required_version = "~> 1.6"
|
||||
required_providers {
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~>3.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.5"
|
||||
}
|
||||
}
|
||||
}
|
69
products/traefik/traefik.tf
Normal file
69
products/traefik/traefik.tf
Normal file
|
@ -0,0 +1,69 @@
|
|||
module "traefik_certs_volume" {
|
||||
source = "../../docker/volume"
|
||||
stack_name = var.stack_name
|
||||
volume_name = "traefik_certs"
|
||||
}
|
||||
module "traefik" {
|
||||
source = "../../docker/service"
|
||||
depends_on = [module.docker_socket_proxy]
|
||||
stack_name = var.stack_name
|
||||
service_name = "traefik"
|
||||
image = "traefik:v3.2"
|
||||
networks = [module.traefik_network.network, module.docker_socket_proxy.network, ]
|
||||
mounts = { "/goliath/letsencrypt" = "/certs" }
|
||||
placement_constraints = var.placement_constraints
|
||||
converge_enable = false // @todo add healthcheck
|
||||
command = [
|
||||
"/usr/local/bin/traefik",
|
||||
"--api.insecure=true",
|
||||
"--api.dashboard=true",
|
||||
"--log.level=${var.log_level}",
|
||||
"--accesslog=${var.access_log ? "true" : "false"}",
|
||||
"--ping=true",
|
||||
|
||||
# Confirm Docker Provider
|
||||
"--providers.docker=true",
|
||||
"--providers.docker.exposedbydefault=false",
|
||||
"--providers.docker.network=${module.traefik_network.name}",
|
||||
"--providers.docker.endpoint=http://${module.docker_socket_proxy.docker_service.name}:2375",
|
||||
|
||||
# Confirm Swarm Provider
|
||||
"--providers.swarm=true",
|
||||
"--providers.swarm.exposedByDefault=false",
|
||||
"--providers.swarm.network=${module.traefik_network.name}",
|
||||
"--providers.swarm.endpoint=http://${module.docker_socket_proxy.docker_service.name}:2375",
|
||||
|
||||
# Configure HTTP and redirect to HTTPS
|
||||
"--entrypoints.web.address=:80",
|
||||
|
||||
# Configure HTTPS
|
||||
"--entrypoints.websecure.address=:443",
|
||||
var.redirect_to_ssl ? "--entrypoints.web.http.redirections.entrypoint.to=websecure" : "",
|
||||
var.redirect_to_ssl ? "--entrypoints.web.http.redirections.entrypoint.scheme=https" : "",
|
||||
|
||||
# Configure the acme provider
|
||||
"--certificatesresolvers.default.acme.tlschallenge=true",
|
||||
var.acme_use_staging ? "--certificatesresolvers.default.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" : "",
|
||||
"--certificatesresolvers.default.acme.email=${var.acme_email}",
|
||||
"--certificatesresolvers.default.acme.storage=/certs/acme.json",
|
||||
]
|
||||
traefik = var.traefik_service_domain != null ? {
|
||||
domain = var.traefik_service_domain
|
||||
port = 8080
|
||||
} : null
|
||||
ports = [
|
||||
{
|
||||
host = 80
|
||||
container = 80
|
||||
},
|
||||
{
|
||||
host = 443
|
||||
container = 443
|
||||
},
|
||||
{
|
||||
host = 8080
|
||||
container = 8080
|
||||
},
|
||||
]
|
||||
|
||||
}
|
3
products/watchtower/outputs.tf
Normal file
3
products/watchtower/outputs.tf
Normal file
|
@ -0,0 +1,3 @@
|
|||
output "docker_service" {
|
||||
value = module.watchtower.docker_service
|
||||
}
|
Loading…
Reference in a new issue