homelab-nomad/service.nomad

283 lines
6.7 KiB
HCL

# Vars
# name = string*
# image = string*
# service_port = int
# ingress = bool
# sticky_disk = bool
# args = json(list[str])
# resources = dict(cpu = int, mem = int)
# env = json(dict(str: any))
# ingress_middlewares = json(list(str))
# templates = json(list(dict(
# data = str,
# dest = str,
# change_mode = str,
# change_signal = str,
# left_delimiter = str,
# right_delimiter = str,
# mount = bool
# )))
# host_volumes = json(list(dict(
# name = str,
# dest = str,
# read_only = bool,
# )))
# healthcheck = "/"
# upstreams = json(list(dict(
# destination_name = str,
# local_bind_port = int
# )))
# mysql = bool
# redis = bool
# vault = bool
# mysql_bootstrap = json(dict(
# vault_key = str
# db_name = str
# db_name_key = str
# db_user = str
# db_user_key = str
# db_pass = str
# db_pass_key = str
# ))
job "[[.name]]" {
region = "global"
datacenters = ["dc1"]
type = "service"
group "[[.name]]" {
[[ with .count ]]count = [[ . ]][[ end ]]
network {
mode = "bridge"
[[ if not (empty .service_port) -]]
port "main" {
[[ if default false .ingress -]]
host_network = "loopback"
[[ end -]]
to = [[ .service_port ]]
}
[[ end -]]
}
[[ if default false .sticky_disk ]]
ephemeral_disk {
migrate = true
sticky = true
}
[[ end ]]
[[ with .host_volumes -]]
[[ range $v := . | parseJSON -]]
volume "[[ $v.name ]]" {
type = "host"
read_only = [[ $v.read_only ]]
source = "[[ $v.name ]]"
}
[[ end ]]
[[ end -]]
[[ if not (empty .service_port) ]]
service {
name = "[[.name | replace "_" "-"]]"
port = "main"
[[ if default false .ingress ]]
connect {
sidecar_service {
proxy {
local_service_port = [[ .service_port ]]
[[ if default false .mysql -]]
upstreams {
destination_name = "mysql-server"
local_bind_port = 4040
}
[[ end -]]
[[ if default false .redis -]]
upstreams {
destination_name = "redis"
local_bind_port = 6379
}
[[ end -]]
[[ with .upstreams -]]
[[range $u := . | parseJSON -]]
upstreams {
destination_name = "[[ $u.destination_name ]]"
local_bind_port = [[ $u.local_bind_port ]]
}
[[ end ]]
[[ end -]]
}
}
sidecar_task {
resources {
cpu = 50
memory = 20
memory_max = 50
}
}
}
[[ end ]]
[[ if not (eq .healthcheck "") -]]
check {
type = "http"
path = "[[ or .healthcheck "/" ]]"
port = "main"
interval = "10s"
timeout = "10s"
}
[[ end -]]
tags = [
[[ if default false .ingress -]]
"traefik.enable=true",
"traefik.http.routers.[[.name]].entryPoints=websecure",
[[ if not (empty .ingress_rule) -]]
"traefik.http.routers.[[.name]].rule=[[.ingress_rule]]",
[[ end -]]
[[ with .ingress_middlewares -]][[ range $m := . | parseJSON -]]
"traefik.http.routers.[[$.name]].middlewares=[[ $m ]]",
[[ end -]][[ end -]]
[[ end -]]
]
}
[[ end -]]
task "[[.name]]" {
driver = "docker"
config {
image = "[[.image]]"
[[ with .service_port -]]
ports = ["main"]
[[ end -]]
[[ with .args -]]
args = [[ . ]]
[[ end -]]
[[ with .templates -]]
[[ range $t := . | parseJSON -]]
[[ if and (default true $t.mount) (not (default false $t.env)) -]]
mount {
type = "bind"
target = "[[ $t.dest ]]"
source = "[[ default "local/" $t.dest_prefix ]][[ $t.dest ]]"
}
[[ end -]]
[[ end ]]
[[ end -]]
}
[[ if default false .vault -]]
vault {
policies = [
"access-tables",
"nomad-task",
]
}
[[ end -]]
[[ with .env -]]
env = {
[[ range $k, $v := . | parseJSON -]]
"[[$k]]" = "[[$v]]"
[[ end -]]
}
[[ end -]]
[[ with .host_volumes -]]
[[ range $v := . | parseJSON -]]
volume_mount {
volume = "[[ $v.name ]]"
destination = "[[ $v.dest ]]"
read_only = [[ $v.read_only ]]
}
[[ end ]]
[[ end -]]
[[ with .templates -]]
[[ range $t := . | parseJSON -]]
template {
data = <<EOF
[[ $t.data ]]
EOF
destination = "[[ default "local/" $t.dest_prefix ]][[ $t.dest ]]"
[[ with $t.left_delimiter ]]left_delimiter = "[[ . ]]"[[ end -]]
[[ with $t.right_delimiter ]]right_delimiter = "[[ . ]]"[[ end -]]
[[ with $t.change_mode ]]change_mode = "[[ . ]]"[[ end -]]
[[ with $t.change_signal ]]change_signal = "[[ . ]]"[[ end -]]
[[ with $t.env ]]env = [[ . ]][[ end ]]
}
[[ end -]]
[[ end -]]
[[ with .resources -]]
resources {
cpu = [[ .cpu ]]
memory = [[ .memory ]]
}
[[ end -]]
}
[[ with .mysql_bootstrap ]][[ with . | parseJSON ]]
task "[[$.name]]-bootstrap" {
driver = "docker"
lifecycle {
hook = "prestart"
sidecar = false
}
config {
image = "mariadb:10"
args = [
"/bin/bash",
"-c",
"/usr/bin/mysql --defaults-extra-file=${NOMAD_SECRETS_DIR}/my.cnf < ${NOMAD_SECRETS_DIR}/bootstrap.sql",
]
}
vault {
policies = [
"access-tables",
"nomad-task",
]
}
template {
data = <<EOF
[client]
host={{ env "NOMAD_UPSTREAM_IP_mysql_server" }}
port={{ env "NOMAD_UPSTREAM_PORT_mysql_server" }}
user=root
{{ with secret "kv/data/mysql" -}}
password={{ .Data.data.root_password }}
{{ end -}}
EOF
destination = "${NOMAD_SECRETS_DIR}/my.cnf"
}
template {
data = <<EOF
{{ with secret "[[.vault_key]]" -}}
CREATE DATABASE IF NOT EXISTS `{{ .Data.data.[[ default "db_name" .db_name_key ]] }}`
CHARACTER SET = 'utf8mb4'
COLLATE = 'utf8mb4_unicode_ci';
CREATE USER IF NOT EXISTS '{{ .Data.data.[[ default "db_user" .db_user_key ]] }}'@'%'
IDENTIFIED BY '{{ .Data.data.[[ default "db_pass" .db_pass_key ]] }}';
GRANT ALL ON `{{ .Data.data.[[ default "db_name" .db_name_key ]] }}`.* to '{{ .Data.data.[[ default "db_user" .db_user_key ]] }}'@'%';
{{ end -}}
{{ end -}}
EOF
destination = "${NOMAD_SECRETS_DIR}/bootstrap.sql"
}
resources {
cpu = 50
memory = 50
}
}
[[ end -]][[ end -]]
}
}