My Docker

My Docker

Ok, here goes another attempt (here is the previous one ⏳) of automation of my Docker server. In the previous article I failed, but now it looks much more promising and this article is being updated and expanded as I progress with this project 📈. However, the original reason for the ability to easily migrate my Docker server to more powerful instance is gone, as my kids are not interested to play on my Minecraft server 😭. Never mind, at least it is opportunity to learn something new.

The New Beginning 🌅

This time my semi-automated deployment consists of three main components:

  1. Terraform
  2. Ansible
  3. My Docker files

Terraform

I’m using pretty much the same Terraform plan as in the [previous](/terraform-handson/ article and my goal stays the same, provision the infrastructure as much as possible using Terraform. So here goes the current terraform.tf:

### Variables

variable "scaleway_access_key" {}
variable "scaleway_secret_key" {}

variable "swtype" {
  default = "DEV1-M"
}
variable "hostname" {
  default = "docker-sw1"
}
variable "env" {
  default = "test"
}

variable "cloudflare_email" {}
variable "cloudflare_token" {}
variable "base_domain" {}

### Scaleway

provider "scaleway" {
  access_key = var.scaleway_access_key
  secret_key = var.scaleway_secret_key
  zone = "fr-par-1"
  region = "fr-par"
  organization_id = "zyx"
}

resource "scaleway_instance_ip" "public_ip" {}

resource "scaleway_instance_server" "docker" {
  name = format("%s-%s.%s", var.hostname, var.env, var.base_domain)
  type  = var.swtype
  image = "docker"

  tags = [ var.env, "linux", "docker" ]

  # attach the public_ip to instance
  ip_id = scaleway_instance_ip.public_ip.id
}

### Cloudflare

provider "cloudflare" {
  version = "~> 2.0"
  email = var.cloudflare_email
  api_key = var.cloudflare_token
}

resource "cloudflare_record" "vaulttec" {
  zone_id = "xyz"
  name    = format("%s-%s", var.hostname, var.env)
  value   = scaleway_instance_ip.public_ip.address
  type    = "A"
  proxied = false
}

The terraform.tfvars contains basic variables:

scaleway_access_key = "xyz"
scaleway_secret_key = "xyz"

cloudflare_email = "lubos@klokner.sk"
cloudflare_token = "xyz"

base_domain = "vault-tec.sk"

And finally the output.tf:

# Outputs

output "ssh_to_instance" {
  value = [ format("ssh root@%s-%s.%s", var.hostname, var.env, var.base_domain)]
}

If I remember correctly, the only difference is, that I decided to add a variable env which represent the deployment type. TEST or PROD and it generates a subdomain when registering FQDN in the domain at Cloudflare.

To conclude this section, running tf init, tf plan and tf apply (I have created an alias for terraform command) should:

  1. create a Docker instance at ScaleWay with defined resources assigned (swtype)
  2. register a DNS record at Cloudflare under base_domain as combination of variables: hostname and env

Easy…

Docker

Moving to my custom Docker files that I host locally on my MBP 👨🏻‍💻 from where I run all this. There are two at this moment:

  1. ./traefik Here is corresponding docker-compose.yml:
    version: '3.7'
    services:
      traefik:
     image: traefik:v1.7
     container_name: traefik
     restart: always
     command: |
         --web \
         --docker \
         --docker.watch \
         --docker.exposedbydefault=false
     ports:
         - 80:80
         - 443:443
         - 8080:8080
     volumes:
         - ./traefik.toml:/traefik.toml
         - ./acme.json:/acme.json
         - /var/run/docker.sock:/var/run/docker.sock
     networks:
         - traefik
    networks:
      traefik:
     name: traefik
    

and Traefik configuration file. As I’m extremely lazy, I’m still running older version 1.7 as you can see in the docker-compose.yml file.

traefik.toml:

debug = false

logLevel = "DEBUG"
defaultEntryPoints = ["https","http"]

[entryPoints]
    [entryPoints.http]
    address = ":80"
        [entryPoints.http.redirect]
            entryPoint = "https"
    [entryPoints.https]
        address = ":443"
    [entryPoints.https.tls]
        minVersion = "VersionTLS12"
        cipherSuites = [
            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
            "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
            "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
        ]

[retry]

[acme]
    email = "lubos@klokner.sk"
    storage = "acme.json"
    entryPoint = "https"
    onHostRule = true
    [acme.httpChallenge]
        entryPoint = "http"

[web]
    address = ":8080"
    [web.auth.basic]
    users = ["admin:xyz]%

Nothing special here, it just redirect every page published on Docker using traefik labels to https, ask the Let’s Encrypt for the Cert (if needed) and sends traffic to the particular Docker container. Admin Dashboard is publised on port 8080, without any encryption 🤦🏻‍♂️ (please don’t tell anybody).

  1. ./f5-demo-httpd Just generic F5 demo application…

Dockerfile:

FROM f5devcentral/f5-demo-httpd
EXPOSE 80

docker-compose.yaml:

version: '3.7'
services:
    f5-demo-httpd:
        build: .
#        container_name:
#        ports:
#            - ${PORT:-80}:80
        restart: always
        labels:
            traefik.enable: true
            traefik.frontend.rule: Host:demo.f5demo.app
            traefik.docker.network: traefik
        networks:
            - traefik
networks:
    traefik:
        external:
            name: traefik

The rest of Docker configuration files is hosted on Github, so the description is available below in the Ansible section.

Ansible

… work in progress.