mongodb/mongodb.nomad.hcl

293 lines
8.4 KiB
HCL

job "[[ .instance ]]" {
[[ template "common/job_start" . ]]
group "mongo" {
[[- $c := merge .mongo . ]]
[[ template "common/group_start" $c ]]
network {
mode = "bridge"
port "mongo" {
[[- if has $c "port" ]]
static = [[ $c.port ]]
[[- end ]]
}
[[- if conv.ToBool $c.prometheus.enabled ]]
port "metrics" {}
[[- end ]]
}
[[ template "common/volumes" $c ]]
# The main service client will use to locate mongo servers
service {
name = "[[ .instance ]][[ .consul.suffix ]]"
port = "mongo"
[[ template "common/service_meta" $c ]]
check {
type = "script"
command = "sh"
args = ["-c", "/local/bin/mongosh --eval 'db.runCommand(\"ping\").ok'"]
interval = "[[ $c.consul.check.interval ]]"
timeout = "[[ $c.consul.check.timeout ]]"
task = "mongod"
}
tags = [
"mongo-${NOMAD_ALLOC_INDEX}"
]
}
# This service is just used by the different nodes to find themself and configure the replica set
service {
name = "[[ .instance ]]-rs[[ .consul.suffix ]]"
port = "mongo"
meta {
[[- range $k, $v := $c.consul.meta ]]
[[ $k ]] = "[[ $v ]]"
[[- end ]]
}
tags = [
"mongo-${NOMAD_ALLOC_INDEX}"
]
}
# This task will init the cluster on first boot
task "mongo-init" {
driver = "docker"
lifecycle {
hook = "poststart"
}
config {
[[ template "common/image" $c ]]
command = "/usr/local/bin/rs_config.sh"
pids_limit = 200
# Mount a few files from the main task
# Just to reduce the verbosity of templates {} sections
volumes = [
"../mongod/secrets/mongo.bundle.pem:/secrets/mongo.bundle.pem:ro",
"../mongod/secrets/mongo.ca.pem:/secrets/mongo.ca.pem:ro",
"../mongod/local/bin/mongosh:/usr/local/bin/mongosh:ro",
"../mongod/local/bin/rs_config.sh:/usr/local/bin/rs_config.sh:ro"
]
[[ template "common/tmpfs" "/tmp" ]]
}
# As the task exits after its done, only reserve little memory
# but allow it to use up to 256MB
resources {
cpu = 20
memory = 20
memory_max = 256
}
}
[[- if conv.ToBool $c.prometheus.enabled ]]
task "exporter" {
[[- $e := merge $c.exporter $c ]]
driver = "[[ $e.nomad.driver ]]"
user = "9216"
config {
[[ template "common/image" $e ]]
args = [
"--mongodb.uri=mongodb://127.0.0.1:${NOMAD_ALLOC_PORT_mongo}/%24external?replicaSet=[[ .mongo.replica_set ]]&authMechanism=MONGODB-X509&tls=true&tlsCertificateKeyFile=%2Fsecrets%2Fmongo.bundle.pem&tlsCAFile=%2Fsecrets%2Fmongo.ca.pem",
"--web.listen-address=:${NOMAD_ALLOC_PORT_metrics}",
"--web.config=/local/web_tls.yml",
"--collect-all"
]
pids_limit = 100
}
lifecycle {
hook = "poststart"
sidecar = true
}
[[ template "common/vault.policies" $e ]]
[[ template "common/artifacts" $e ]]
[[ template "common/metrics_cert" $e ]]
# TLS config for the exporter
template {
data = <<_EOT
[[ template "mongodb/exporter_tls.yml" $e ]]
_EOT
destination = "local/web_tls.yml"
}
# Get a certificate with monitoring capabilities
template {
data = <<_EOT
{{ with pkiCert "[[ $e.vault.pki.path ]]/issue/mongo-monitor"
"common_name=mongo.monitor"
"ttl=168h" }}
{{ .Cert }}
{{ .Key }}
{{ end }}
_EOT
destination = "secrets/mongo.bundle.pem"
uid = 109216
gid = 109216
perms = "0640"
}
# CA cert used to validate remote (mongo servers') certificate. Both root and intermediate
template {
data = <<_EOT
{{ with secret "[[ $e.vault.pki.path ]]/cert/ca_chain" }}{{ .Data.ca_chain }}{{ end }}
_EOT
destination = "secrets/mongo.ca.pem"
}
[[ template "common/resources" $c.exporter ]]
}
[[- end ]]
task "mongod" {
driver = "[[ $c.nomad.driver ]]"
leader = true
# Give mongod some time to shutdown
kill_timeout = "60s"
config {
[[ template "common/image" $c ]]
command = "mongod"
args = ["--config", "/local/mongod.conf"]
pids_limit = 500
volumes = [
"local/bin/mongosh:/usr/local/bin/mongosh:ro"
]
[[ template "common/tmpfs" "/tmp" ]]
}
[[ template "common/vault.policies" $c ]]
[[ template "common/artifacts" $c ]]
template {
data = <<_EOT
[[- if isKind "map" $c.config ]]
[[ merge $c.config (tmpl.Exec "mongodb/mongod.conf" $c | yaml) | toYAML ]]
[[- else if isKind "string" $c.config ]]
[[ merge ($c.config | yaml) (tmpl.Exec "mongodb/mongod.conf" $c | yaml) | toYAML ]]
[[- else ]]
[[ template "mongodb/mongod.conf" $c ]]
[[- end ]]
_EOT
destination = "local/mongod.conf"
}
# This is the certificate used by the mongod process
# Note : we ask for a cert valid for the host IP address, and also for the XXXXX.addr.dc1.consul address
# as it's what is published in the SRV record. The XXXX is the hex representation of the IP.
# Something like {{ range (env "NOMAD_IP_mongo" | split ".") }}{{ printf "%02x" (. | parseInt) }}{{ end }}
# would be cleaner, but can't find how to use it in this context
# Also : each instance will have a slightly differnt ttl so all cert will not expire at the same time
template {
data = <<_EOT
{{- with pkiCert "[[ $c.vault.pki.path ]]/issue/mongod"
(printf "common_name=mongo-%s.[[ .instance ]][[ .consul.suffix ]].service.[[ .consul.domain ]]" (env "NOMAD_ALLOC_INDEX"))
(
printf "alt_names=%02x%02x%02x%02x.addr.dc1.[[ .consul.domain ]]"
(env "NOMAD_HOST_IP_mongo" | regexReplaceAll "^(\\d+)\\..*" "$1" | parseInt)
(env "NOMAD_HOST_IP_mongo" | regexReplaceAll "^\\d+\\.(\\d+)\\..*" "$1" | parseInt)
(env "NOMAD_HOST_IP_mongo" | regexReplaceAll "^\\d+\\.\\d+\\.(\\d+)\\..*" "$1" | parseInt)
(env "NOMAD_HOST_IP_mongo" | regexReplaceAll "^\\d+\\.\\d+\\.\\d+\\.(\\d+)$" "$1" | parseInt)
)
(printf "ip_sans=%s,127.0.0.1" (env "NOMAD_HOST_IP_mongo"))
(printf "ttl=%dh" (env "NOMAD_ALLOC_INDEX" | parseInt | multiply 8 | add 600)) }}
{{ .Cert }}
{{ .Key }}
{{- end }}
_EOT
destination = "secrets/mongo.bundle.pem"
uid = 100999
gid = 100999
perms = "0640"
change_mode = "script"
change_script {
command = "/local/bin/rotate-cert.sh"
# If cert rotation fails, kill the task and restart it
fail_on_error = true
}
}
# CA cert used to validate remote certs
template {
data = <<_EOT
{{- with secret "[[ $c.vault.pki.path ]]/cert/ca_chain" }}
{{ .Data.ca_chain }}
{{- end }}
_EOT
destination = "secrets/mongo.ca.pem"
change_mode = "script"
change_script {
command = "/local/bin/rotate-cert.sh"
# If cert rotation fails, kill the task and restart it
fail_on_error = true
}
}
# A mongosh wrapper which will automatically use the x509 root cert
template {
data = <<_EOT
[[ template "mongodb/mongosh" $c ]]
_EOT
destination = "local/bin/mongosh"
uid = 100000
gid = 100000
perms = "0755"
}
# A script to dynamically reconfigure members' address when mongo instances restart
template {
data = <<_EOT
[[ template "mongodb/rs_config.sh" $c ]]
_EOT
destination = "local/bin/rs_config.sh"
uid = 100000
gid = 100000
perms = "0755"
change_mode = "script"
change_script {
command = "/local/bin/rs_config.sh"
# Will fail when mongod is shuting down. We don't want Nomad to kill the task
fail_on_error = false
}
}
# A script to rotate certificates
template {
data = <<_EOT
[[ template "mongodb/rotate-cert.sh" $c ]]
_EOT
destination = "local/bin/rotate-cert.sh"
uid = 100000
gid = 100000
perms = "0755"
}
# Persistent data
volume_mount {
volume = "mongo"
destination = "/data"
}
[[ template "common/resources" $c ]]
}
}
}