Skip to main content

App Deployment with Hashicorp Nomad from Gitlab Part Deux

Shen Zhen, China

Run a Docker Image with Gitlab Artifacts

I now want to run an ingress container for an existing web service. So far the NGINX ingress is configured to proxy-pass a couple of web frontend containers and direct traffic into that Docker cluster:

default.conf:

server {
listen 80;
listen [::]:80;

server_name wiki.instar.com;

return 301 https://$server_name$request_uri;
}


server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl;
ssl_certificate /opt/letsencrypt/live/wiki.instar.com/fullchain.pem;
ssl_certificate_key /opt/letsencrypt/live/wiki.instar.com/privkey.pem;
# include ssl/self-signed.conf;
include ssl/ssl-params.conf;
include /etc/nginx/conf.d/header.conf;

server_name wiki.instar.com;

location / {
rewrite ^/(.*)$ /en/$1 permanent;
}

location /de/ {
proxy_pass http://wiki_de:9999/;
}

location /en/ {
proxy_pass http://wiki_en:8888/;
}

location /fr/ {
proxy_pass http://wiki_fr:7777/;
}

location ~ /dl/.* {
root /opt/wiki_downloads/;
add_before_body /dl/theme/header.html;
add_after_body /dl/theme/footer.html;
autoindex on;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
}


error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

I was using a docker network to lock-down access to those containers - except traffic that was using the ingress. Which also allowed me to use the Docker DNS service to point NGINX to those front ends: proxy_pass http://wiki_de:9999/.

With Nomad I guess I now have to run those containers on the host network instead and proxy_pass from localhost instead. This is not an issue, though. As I can bind those ports to localhost and/or use the firewall to block all direct traffic.

I can spin up each of those containers using Nomad. Unlike before I am not using a dynamic port, but instead make it static for now (I am planing to add Consul to the mix later to handle the service discovery - but let's keep it simple'ish for now):

job "wiki_de" {
datacenters = ["instaryun"]

group "wiki_de" {
count = 1

network {
mode = "host"
port "http" {
static = "9999"
}
}

task "container" {
driver = "docker"

config {
image = "mygitlab.mydomain.com:12345/wiki/wiki_de_mdx"
ports = ["http"]

auth {
username = "mynomaduserongitlab"
password = "acomplicatedpassword"
}
}
}
}
}

Configuration Artifacts

So there are three of those services and the last one is a file server - a download area. I can create this inside the Ingress job specification using the Artifact Stanza. This also takes care of the NGINX configuration files that I source control on Gitlab:

locals {
ports = [
{
port_label = "http"
port = 80
},
{
port_label = "https"
port = 443
}
]
}

job "wiki_ingress" {
datacenters = ["instaryun"]

group "nginx" {
count = 1

network {
mode = "host"
dynamic "port" {
for_each = local.ports
labels = [port.value.port_label]

content {
to = port.value.port
}
}
}

service {
name = "nginx"
}

volume "letsencrypt" {
type = "host"
read_only = true
source = "letsencrypt"
}

task "ingress_container" {
driver = "docker"

volume_mount {
volume = "letsencrypt"
destination = "/opt/letsencrypt" #in the container
read_only = false
}

config {
network_mode = "host"
image = "nginx:1.23.0-alpine"
ports = ["http","https"]
volumes = [
"local/nginx/configuration/conf.d:/etc/nginx/conf.d",
"local/nginx/configuration/ssl:/etc/nginx/ssl",
"local/nginx/configuration/nginx.conf:/etc/nginx/nginx.conf",
"local/wiki_downloads:/opt/wiki_downloads",
]
}

artifact {
source = "git::git@my.gitlab.address.com/group/wiki_ingress.git"
destination = "local/nginx"
options {
sshkey = "${base64encode(file(pathexpand("/etc/nomad.d/.ssh/id_rsa")))}"
depth = 1
}
}

artifact {
source = "git::git@my.gitlab.address.com/group/wiki_downloads.git"
destination = "local/wiki_downloads"
options {
sshkey = "${base64encode(file(pathexpand("/etc/nomad.d/.ssh/id_rsa")))}"
depth = 1
}
}
}
}
}

Adding Volumes

You should first create the volume path before nomad is starting, then add the following configs in your client.hcl file [Plugin Stanza | Host Volume Stanza]:

nano /etc/nomad.d/client.hcl


client {
enabled = true
servers = ["myhost:port"]
host_volume "letsencrypt" {
path = "/etc/letsencrypt"
read_only = true
}
}

# Docker Configuration
plugin "docker" {
volumes {
enabled = true
}
}

And then in the job specifications, inside the Group Stanza define the volume:

volume "letsencrypt" {
type = "host"
read_only = true
source = "letsencrypt"
}

and then finally add following in the Task Stanza use the defined volume:

volume_mount {
volume = "letsencrypt"
destination = "/opt/letsencrypt" #<-- in the container
read_only = false
}

That is a bit complicated for a simple volume mount....