This commit is contained in:
Daniel Berteaud 2024-01-22 21:47:02 +01:00
parent e9096a7679
commit f73b6358ce
10 changed files with 126 additions and 70 deletions

View File

@ -1,3 +1,3 @@
Kind = "service-defaults" Kind = "service-defaults"
Name = "[[ .unifi.instance ]][[ .consul.suffix ]]" Name = "[[ .instance ]][[ .consul.suffix ]]"
Protocol = "http" Protocol = "http"

View File

@ -1,8 +1,8 @@
Kind = "service-intentions" Kind = "service-intentions"
Name = "[[ .unifi.instance ]][[ .consul.suffix ]]" Name = "[[ .instance ]][[ .consul.suffix ]]"
Sources = [ Sources = [
{ {
Name = "[[ (merge .unifi.controller .traefik).instance ]]" Name = "[[ (merge .unifi.controller .).traefik.instance ]]"
Permissions = [ Permissions = [
{ {
Action = "allow" Action = "allow"

View File

@ -1,4 +1,4 @@
FROM danielberteaud/alpine:24.1-7 FROM danielberteaud/alpine:24.1-8
MAINTAINER Daniel Berteaud <dbd@ehtrace.com> MAINTAINER Daniel Berteaud <dbd@ehtrace.com>
ENV UBNT_UPDATE_API="https://fw-update.ubnt.com/api/firmware-latest?filter=eq~~product~~unifi-firmware&filter=eq~~channel~~release" \ ENV UBNT_UPDATE_API="https://fw-update.ubnt.com/api/firmware-latest?filter=eq~~product~~unifi-firmware&filter=eq~~channel~~release" \

View File

@ -1,4 +1,4 @@
FROM danielberteaud/java:17.24.1-3 AS builder FROM danielberteaud/java:17.24.1-4 AS builder
ARG UNIFI_VERSION=8.0.26 ARG UNIFI_VERSION=8.0.26
@ -12,7 +12,7 @@ RUN set -euxo pipefail &&\
rm -f UniFi/bin/mongod &&\ rm -f UniFi/bin/mongod &&\
chown -R root:root UniFi chown -R root:root UniFi
FROM danielberteaud/java:17.24.1-3 FROM danielberteaud/java:17.24.1-4
MAINTAINER Daniel Berteaud <dbd@ehtrace.com> MAINTAINER Daniel Berteaud <dbd@ehtrace.com>
ENV JAVA_OPTS="-Djava.awt.headless=true -Dlogback.configurationFile=/opt/unifi/logback.xml --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED" \ ENV JAVA_OPTS="-Djava.awt.headless=true -Dlogback.configurationFile=/opt/unifi/logback.xml --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED" \

View File

@ -19,6 +19,7 @@ job "unifi" {
sidecar_service { sidecar_service {
} }
sidecar_task { sidecar_task {
resources { resources {
cpu = 50 cpu = 50
memory = 64 memory = 64
@ -138,6 +139,7 @@ job "unifi" {
task "nginx" { task "nginx" {
driver = "docker" driver = "docker"
user = 8306 user = 8306
@ -147,8 +149,17 @@ job "unifi" {
} }
config { config {
image = "nginxinc/nginx-unprivileged:alpine" image = "nginxinc/nginx-unprivileged:alpine"
volumes = ["local/nginx.conf:/etc/nginx/conf.d/default.conf"] volumes = ["local/nginx.conf:/etc/nginx/conf.d/default.conf"]
readonly_rootfs = true
mount {
type = "tmpfs"
target = "/tmp"
tmpfs_options {
size = 1000000
}
}
} }
template { template {
@ -207,6 +218,7 @@ _EOF
destination = "local/nginx.conf" destination = "local/nginx.conf"
} }
resources { resources {
cpu = 10 cpu = 10
memory = 15 memory = 15
@ -216,36 +228,60 @@ _EOF
task "controller" { task "controller" {
leader = true leader = true
driver = "docker" driver = "docker"
config { config {
image = "danielberteaud/unifi:8.0.26-2" image = "danielberteaud/unifi:8.0.26-3"
volumes = [ volumes = [
"local/init-system.properties.sh:/entrypoint.d/10-init-system.properties.sh" "local/init-system.properties.sh:/entrypoint.d/10-init-system.properties.sh"
] ]
readonly_rootfs = true
mount { mount {
type = "tmpfs" type = "tmpfs"
target = "/opt/unifi/run" target = "/opt/unifi/run"
tmpfs_options {
size = 1000000
}
}
mount {
type = "tmpfs"
target = "/tmp"
tmpfs_options {
size = 1000000
}
} }
} }
vault { vault {
policies = ["unifi"] policies = ["unifi"]
env = false env = false
disable_file = true disable_file = true
} }
env { env {
LANG = "fr_FR.utf8"
TZ = "Europe/Paris"
} }
# Use a template block instead of env {} so we can fetch values from vault
template {
data = <<_EOT
LANG=fr_FR.utf8
TZ=Europe/Paris
_EOT
destination = "secrets/.env"
perms = 400
env = true
}
template { template {
data = <<_EOF data = <<_EOF
unifi.http.port=8080 unifi.http.port=8080
@ -308,6 +344,7 @@ _EOF
destination = "/data" destination = "/data"
} }
resources { resources {
cpu = 200 cpu = 200
memory = 1024 memory = 1024
@ -317,6 +354,7 @@ _EOF
} }
task "mongo" { task "mongo" {
driver = "docker" driver = "docker"
lifecycle { lifecycle {
@ -325,12 +363,18 @@ _EOF
} }
config { config {
image = "danielberteaud/mongo:5.0.24.1-1" image = "danielberteaud/mongo:5.0.24.1-1"
command = "mongod" command = "mongod"
args = [ readonly_rootfs = true
"--config", args = ["--config", "/local/mongod.conf"]
"/local/mongod.conf" mount {
] type = "tmpfs"
target = "/tmp"
tmpfs_options {
size = 1000000
}
}
} }
template { template {
@ -357,6 +401,7 @@ _EOF
destination = "/data/db" destination = "/data/db"
} }
resources { resources {
cpu = 100 cpu = 100
memory = 256 memory = 256
@ -366,4 +411,3 @@ _EOF
} }
} }
} }

View File

@ -1,3 +1,5 @@
# Access the vault KV (v2) store
path "kv/data/service/unifi" { path "kv/data/service/unifi" {
capabilities = ["read"] capabilities = ["read"]
} }

View File

@ -1 +1 @@
[[ template "common/mv_conf.sh.tpl" dict "ctx" . "services" (dict "unifi" .unifi.instance) ]] [[ template "common/mv_conf.sh.tpl" dict "ctx" . "services" (dict "unifi" .instance) ]]

View File

@ -1,10 +1,10 @@
job [[ .unifi.instance | toJSON ]] { job "[[ .instance ]]" {
[[- template "common/job_start" . ]] [[- template "common/job_start" . ]]
group "unifi" { group "unifi" {
[[- $c := merge .unifi.controller . ]] [[- $c := merge .unifi.controller .unifi . ]]
network { network {
mode = "bridge" mode = "bridge"
@ -14,7 +14,7 @@ job [[ .unifi.instance | toJSON ]] {
} }
service { service {
name = "[[ .unifi.instance ]][[ .consul.suffix ]]" name = "[[ .instance ]][[ .consul.suffix ]]"
port = 8888 port = 8888
[[ template "common/connect" $c ]] [[ template "common/connect" $c ]]
@ -35,41 +35,41 @@ job [[ .unifi.instance | toJSON ]] {
"[[ $c.traefik.instance ]].enable=true", "[[ $c.traefik.instance ]].enable=true",
# Note : no Host as inform requests are sent without. But it's binded to the dedicated entrypoint anyway # Note : no Host as inform requests are sent without. But it's binded to the dedicated entrypoint anyway
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-inform[[ .consul.suffix ]].rule=(Path(`/inform`) && Method(`POST`)) || (PathPrefix(`/dl/firmware-cached`) && (Method(`GET`) || Method(`HEAD`)))", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-inform[[ .consul.suffix ]].rule=(Path(`/inform`) && Method(`POST`)) || (PathPrefix(`/dl/firmware-cached`) && (Method(`GET`) || Method(`HEAD`)))",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-inform[[ .consul.suffix ]].entrypoints=[[ join (merge .unifi.inform.traefik .traefik).entrypoints "," ]]", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-inform[[ .consul.suffix ]].entrypoints=[[ join (merge .unifi.inform.traefik .traefik).entrypoints "," ]]",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-inform[[ .consul.suffix ]].middlewares=[[ template "common/traefik_middlewares.tpl" merge .unifi.inform.traefik .traefik ]]", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-inform[[ .consul.suffix ]].middlewares=[[ template "common/traefik_middlewares.tpl" merge .unifi.inform.traefik .traefik ]]",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-controller[[ .consul.suffix ]].rule=Host(` "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-controller[[ .consul.suffix ]].rule=Host(`
[[- (urlParse .unifi.controller.public_url).Hostname -]]`) [[- (urlParse .unifi.controller.public_url).Hostname -]]`)
[[- if ne "" (urlParse .unifi.controller.public_url).Path ]] && PathPrefix(`[[ (urlParse .unifi.controller.public_url).Path ]]`)[[ end ]]", [[- if ne "" (urlParse .unifi.controller.public_url).Path ]] && PathPrefix(`[[ (urlParse .unifi.controller.public_url).Path ]]`)[[ end ]]",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-controller[[ .consul.suffix ]].entrypoints=[[ join (merge .unifi.controller.traefik .traefik).entrypoints "," ]]", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-controller[[ .consul.suffix ]].entrypoints=[[ join (merge .unifi.controller.traefik .traefik).entrypoints "," ]]",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-controller[[ .consul.suffix ]].tls=true", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-controller[[ .consul.suffix ]].tls=true",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-controller[[ .consul.suffix ]].middlewares=[[ template "common/traefik_middlewares.tpl" merge .unifi.controller.traefik .traefik ]]", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-controller[[ .consul.suffix ]].middlewares=[[ template "common/traefik_middlewares.tpl" merge .unifi.controller.traefik .traefik ]]",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-portal[[ .consul.suffix ]].rule=Host(` "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-portal[[ .consul.suffix ]].rule=Host(`
[[- (urlParse .unifi.guest_portal.public_url).Hostname -]] [[- (urlParse .unifi.guest_portal.public_url).Hostname -]]
`) && PathPrefix(`/guest`)", `) && PathPrefix(`/guest`)",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-portal[[ .consul.suffix ]].entrypoints=[[ join (merge .unifi.guest_portal.traefik .traefik).entrypoints "," ]]", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-portal[[ .consul.suffix ]].entrypoints=[[ join (merge .unifi.guest_portal.traefik .traefik).entrypoints "," ]]",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-portal[[ .consul.suffix ]].tls=true", "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-portal[[ .consul.suffix ]].tls=true",
"[[ $c.traefik.instance ]].http.routers.[[ .unifi.instance ]]-portal[[ .consul.suffix ]].middlewares=[[ template "common/traefik_middlewares.tpl" merge .unifi.guest_portal.traefik .traefik ]]" "[[ $c.traefik.instance ]].http.routers.[[ .instance ]]-portal[[ .consul.suffix ]].middlewares=[[ template "common/traefik_middlewares.tpl" merge .unifi.guest_portal.traefik .traefik ]]"
] ]
} }
service { service {
name = "[[ .unifi.instance ]]-stun[[ .consul.suffix ]]" name = "[[ .instance ]]-stun[[ .consul.suffix ]]"
port = "stun" port = "stun"
tags = [ tags = [
"[[ $c.traefik.instance ]].enable=true", "[[ $c.traefik.instance ]].enable=true",
"[[ $c.traefik.instance ]].udp.routers.[[ .unifi.instance ]]-stun[[ .consul.suffix ]].entrypoints=[[ join .unifi.stun.traefik.entrypoints "," ]]", "[[ $c.traefik.instance ]].udp.routers.[[ .instance ]]-stun[[ .consul.suffix ]].entrypoints=[[ join .unifi.stun.traefik.entrypoints "," ]]",
"[[ $c.traefik.instance ]].consulcatalog.connect=false" "[[ $c.traefik.instance ]].consulcatalog.connect=false"
] ]
} }
[[- if not .unifi.controller.mongo.is_external ]] [[- if not $c.mongo.is_external ]]
service { service {
name = "[[ .unifi.instance ]]-mongo[[ .consul.suffix ]]" name = "[[ .instance ]]-mongo[[ .consul.suffix ]]"
port = 27017 port = 27017
check { check {
@ -91,13 +91,16 @@ job [[ .unifi.instance | toJSON ]] {
[[- end ]] [[- end ]]
[[ template "common/volumes" .unifi.controller.volumes ]] [[ template "common/volumes" $c ]]
[[ template "common/task.wait_for" $c ]] [[ template "common/task.wait_for" $c ]]
task "nginx" { task "nginx" {
driver = [[ .nomad.driver | toJSON ]]
user = 8306 [[- $c := merge .unifi.nginx .unifi . ]]
driver = "[[ .nomad.driver ]]"
user = 8306
lifecycle { lifecycle {
hook = "poststart" hook = "poststart"
@ -105,8 +108,10 @@ job [[ .unifi.instance | toJSON ]] {
} }
config { config {
image = [[ .unifi.nginx.image | toJSON ]] image = "[[ .unifi.nginx.image ]]"
volumes = ["local/nginx.conf:/etc/nginx/conf.d/default.conf"] volumes = ["local/nginx.conf:/etc/nginx/conf.d/default.conf"]
readonly_rootfs = true
[[ template "common/tmpfs" dict "size" "1000000" "target" "/tmp" ]]
} }
template { template {
@ -116,33 +121,34 @@ _EOF
destination = "local/nginx.conf" destination = "local/nginx.conf"
} }
[[ template "common/resources" .unifi.nginx.resources ]] [[ template "common/resources" $c ]]
} }
task "controller" { task "controller" {
[[ $c := merge .unifi.controller .unifi . ]]
leader = true leader = true
driver = [[ .nomad.driver | toJSON ]] driver = "[[ $c.nomad.driver ]]"
config { config {
image = [[ .unifi.controller.image | toJSON ]] image = "[[ $c.image ]]"
volumes = [ volumes = [
"local/init-system.properties.sh:/entrypoint.d/10-init-system.properties.sh" "local/init-system.properties.sh:/entrypoint.d/10-init-system.properties.sh"
] ]
[[ template "common/tmpfs" "/opt/unifi/run" ]] readonly_rootfs = true
[[ template "common/tmpfs" dict "size" "1000000" "target" "/opt/unifi/run" ]]
[[ template "common/tmpfs" dict "size" "1000000" "target" "/tmp" ]]
} }
vault { [[ template "common/vault.policies" $c ]]
policies = ["[[ .unifi.instance ]][[ .consul.suffix ]]"]
env = false
disable_file = true
}
env { env {
[[ template "common/proxy_env" . ]] [[ template "common/proxy_env" . ]]
[[ template "common/env" $c.env ]]
} }
[[ template "common/file_env" $c ]]
template { template {
data =<<_EOF data =<<_EOF
[[ template "unifi/controller/system.properties.tpl" . ]] [[ template "unifi/controller/system.properties.tpl" . ]]
@ -163,14 +169,17 @@ _EOF
destination = "/data" destination = "/data"
} }
[[ template "common/resources" .unifi.controller.resources ]] [[ template "common/resources" $c ]]
} }
[[- if not .unifi.controller.mongo.is_external ]] [[- if not .unifi.controller.mongo.is_external ]]
task "mongo" { task "mongo" {
driver = [[ .nomad.driver | toJSON ]]
[[- $c := merge .unifi.mongo .unifi . ]]
driver = "[[ $c.nomad.driver ]]"
lifecycle { lifecycle {
hook = "prestart" hook = "prestart"
@ -178,12 +187,11 @@ _EOF
} }
config { config {
image = [[ .unifi.mongo.image | toJSON ]] image = "[[ $c.image ]]"
command = "mongod" command = "mongod"
args = [ readonly_rootfs = true
"--config", args = ["--config", "/local/mongod.conf" ]
"/local/mongod.conf" [[ template "common/tmpfs" dict "size" "1000000" "target" "/tmp" ]]
]
} }
template { template {
@ -198,10 +206,9 @@ _EOF
destination = "/data/db" destination = "/data/db"
} }
[[ template "common/resources" .unifi.mongo.resources ]] [[ template "common/resources" $c ]]
} }
} }
[[- end ]] [[- end ]]
} }

View File

@ -6,9 +6,10 @@
# - A mongodb server (optional, can use an external mongodb) # - A mongodb server (optional, can use an external mongodb)
# - A firmware downloader helper : this is because the Unifi Controller can't use an outbound web proxy # - A firmware downloader helper : this is because the Unifi Controller can't use an outbound web proxy
# The name of the nomad job
instance: unifi
unifi: unifi:
# The name of the nomad job
instance: unifi
# This is for the web management console # This is for the web management console
controller: controller:
@ -17,7 +18,11 @@ unifi:
driver: docker driver: docker
# The image for the controller # The image for the controller
image: '[[ .docker.repo ]]unifi:8.0.26-2' image: '[[ .docker.repo ]]unifi:8.0.26-3'
vault:
policies:
- '[[ .instance ]][[ .consul.suffix ]]'
# Resource allocation for the controller # Resource allocation for the controller
resources: resources:

View File

@ -1,3 +1 @@
path "[[ .vault.prefix ]]kv/data/service/[[ .unifi.instance ]]" { [[- template "common/vault.kv_policy" . ]]
capabilities = ["read"]
}