Nachdem die Versuche, Nomad zusammen mit dem Consul Service Mesh dazu zu benutzen, gänzlich unabhängige Cluster miteinander zu integrieren, an (nicht) globalen Service Tokens gescheitert waren, kam ja dann Nebula zur Hilfe.
Damit ist ein Nomad-Cluster, der sich über mehrere unabhängige Umgebungen erstreckt, schnell aufgebaut.
Nebula startet man am besten per systemd:
[Unit]
Description=Nebula overlay networking tool
Wants=basic.target network-online.target nss-lookup.target time-sync.target
After=basic.target network.target network-online.target
Before=sshd.service
[Service]
Type=notify
NotifyAccess=main
SyslogIdentifier=nebula
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/nebula -config /etc/nebula/config.yaml
Restart=always
[Install]
WantedBy=multi-user.target
Für die Nomad-Server müssen nur wenige Ports im Overlay-Netzwerk erlaubt werden:
# http
- port: 4646
proto: tcp
host: any
# rpc
- port: 4647
proto: tcp
host: any
# serf
- port: 4648
proto: tcp
host: any
- port: 4648
proto: udp
host: any
Für die Nomad-Clients werden nur rpc und der gesamte Portrange, den Nomad für Allocations nutzt, freigegeben:
inbound:
- port: 20000-32000
proto: any
host: any
- port: 4647
proto: tcp
host: any
In der Nomad Clientkonfiguration sollte man dann die verschiedenen Netzwerkinterfaces konfigurieren bzw. bekannt machen (so wie es auch in der Dokumentation beschrieben wird):
[...]
client {
enabled = true
# node_pool = "static-clients"
cni_path = "/opt/cni/bin"
cni_config_dir = "/opt/cni/config"
server_join {
retry_join = [ "10.21.20.12", "10.21.20.13", "10.21.20.14" ]
retry_max = 5
retry_interval = "15s"
}
host_network "overlay" {
interface = "nebula1"
}
host_network "internal" {
interface = "ens3"
}
}
An der Serverkonfiguration muß nichts geändert werden. Nur die Clients müssen die anliegenden Netze kennen.
Diese Netzdefinitionen können dann in der group- und service-Definition in Nomad Job-Files verwendet werden:
job "memcached-prod1" {
datacenters = ["prod1"]
group "group-memcached-prod1" {
network {
port "memcached" {
host_network = "overlay"
}
}
task "task-memcached-prod1" {
driver = "exec"
config {
command = "/usr/local/bin/memcached"
args = [
"-l",
"${NOMAD_IP_memcached}",
"-p",
"${NOMAD_PORT_memcached}"
]
}
service {
tags = [ "${node.datacenter}" ]
name = "memcached-prod1"
port = "memcached"
provider = "nomad"
address_mode = "auto"
check {
type = "tcp"
port = "memcached"
interval = "10s"
timeout = "2s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = "false"
}
}
}
}
}
}
Der Job fährt z. B. einen memcached im vorher definierten "overlay" Netzwerk hoch und vergibt eine zufällige Portnummer aus dem Nomad Portrange:
root@triton-nomad1:~/nomad-jobs# nomad service info memcached-prod1
Job ID Address Tags Node ID Alloc ID
memcached-prod1 10.21.20.11:25417 [prod1] cbe5e990 6329fce9
Damit wird es natürlich sehr einfach - wie in diesem Fall - mehrere memcached-Instanzen in verschiedenen Umgebungen über einen memcached-proxy mit Daten zu befüllen (bzw. zum Zwecke der Ausfallsicherheit aus diesen zu lesen):
job "memcached-proxy" {
datacenters = ["*"]
group "group-memcachedp" {
network {
port "memcachedp" {}
}
task "task-memcachedp" {
driver = "exec"
config {
command = "/usr/local/bin/memcached"
args = [
"-l",
"${NOMAD_IP_memcachedp}",
"-p",
"${NOMAD_PORT_memcachedp}",
"-o",
"proxy_config=routelib,proxy_arg=local/config.lua",
]
}
template {
data = <<EOH
pools{
set_all = {
{ backends = {
{{- range nomadService "memcached-prod1" }}
"{{ .Address }}:{{ .Port }}"{{- end}}
}
},
{ backends = {
{{- range nomadService "memcached-prod4" }}
"{{ .Address }}:{{ .Port }}"{{- end}}
}
},
}
}
routes{
cmap = {
get = route_failover{
children = "set_all",
stats = true,
miss = true,
shuffle = true,
failover_count = 2
},
},
default = route_allsync{
children = "set_all",
},
}
EOH
destination = "local/config.lua"
}
service {
name = "memcached-proxy"
port = "memcachedp"
provider ="nomad"
check {
type = "tcp"
port = "memcachedp"
interval = "10s"
timeout = "2s"
check_restart {
limit = 3
grace = "90s"
ignore_warnings = "false"
}
}
}
}
}
}
Wenn man jetzt Daten beim memcached-proxy
root@triton-nomad1:~/nomad-jobs# nomad service info memcached-proxy
Job ID Address Tags Node ID Alloc ID
memcached-proxy 192.168.0.200:26290 [] cbe5e990 d41b143c
einwirft (s. a. memcached-Dokumentation):
root@nomad-client-0:~# telnet 192.168.0.200 26290
Trying 192.168.0.200...
Connected to 192.168.0.200.
Escape character is '^]'.
set quickstart/data 0 0 6
Hello!
STORED
get quickstart/data
VALUE quickstart/data 0 6
Hello!
END
quit
Dann kann man sie auch aus den beiden memcached-Instanzen wieder auslesen:
root@nomad-client-0:~# telnet 10.21.20.11 25417
Trying 10.21.20.11...
Connected to 10.21.20.11.
Escape character is '^]'.
get quickstart/data
VALUE quickstart/data 0 6
Hello!
END
quit
Connection closed by foreign host.
root@nomad-client-0:~# telnet 10.21.20.10 28132
Trying 10.21.20.10...
Connected to 10.21.20.10.
Escape character is '^]'.
get quickstart/data
VALUE quickstart/data 0 6
Hello!
END
quit
Connection closed by foreign host.
Die Daten werden nicht repliziert! Man sollte also immer eine memcached-Instanz mehr haben als man Ausfälle hat!
Interessant auch: Wenn man keine host_network
Definition im Job-File verwendet, wird offenbar "automagisch" das "normale" Netzwerkinteface der Client-Instanz verwendet.