Auto-Deploy Docker Applications
Tags: containers
Published: 2023-01-06 01:23:53

---
title: Auto-Deploy Docker Applications
published: true
date: 2020-05-09 14:20:34 UTC
tags: Containers
canonical_url: https://brandonrozek.com/blog/autodeploydockerapps/
---

This post will combine that last three posts on [Packer](/blog/snapshotswithpacker/), [Terraform](/blog/autodeployterraform/), and their [configuration](/blog/sharedpackerterraformconfig/) to show an entire example of how to deploy a docker-compose application. We will specifically look at deploying a game called [`minetest`](https://www.minetest.net/) on DigitalOcean, but these principles can be adjusted to deploy your application as well. The entire setup is [documented on Github](https://github.com/Brandon-Rozek/minetest-deploy).

## Shared Config

We’re going to use a shared configuration between Packer and Terraform. The template goes like this:

```
base_system_image = "ubuntu-20-04-x64"
region = "nyc3"
size = "512mb"
domain = "brandonrozek.com" # Replace
subdomain = "minetest"

# Secrets
do_token = "DO-TOKEN-HERE" # Replace
key_name = "SSH-NAME-ON-DO-HERE" # Replace

```

We’ll also need to define the types of these variables in `variables.hcl`

```
variable "do_token" {
  type = string
}

variable "base_system_image" {
  type = string
}

variable "domain" {
  type = string
}

variable "key_name" {
  type = string
}

variable "subdomain" {
  type = string
}

variable "region" {
  type = string
}

variable "size" {
  type = string
}

```

## Packer

Create a packer directory and setup some symbolic links to the share configuration

```
mkdir packer && cd packer
ln -s ../config variables.auto.pkrvars.hcl
ln -s ../variables.hcl variables.pkr.hcl

```

Now let’s create a script named `setup.sh` that will run on top of our base image. This will install Docker and setup the firewall to allow SSH and Minetest traffic through.

```
#!/bin/bash
apt update
apt upgrade -y

apt install -y docker.io docker-compose
systemctl enable docker-compose
systemctl start docker-compose

ufw allow OpenSSH
# Add any firewall rules you need
# for your application here
ufw allow 30000/udp
ufw --force enable

```

The image that we’ll use for Minetest comes from [linuxserverio](https://fleet.linuxserver.io/image?name=linuxserver/minetest). To configure docker-compose we’ll need a file named `docker-compose.yml`. Its contents will be highly similar to what is listed on their [Github](https://github.com/linuxserver/docker-minetest/blob/466cde1f2fd38278fe69d33ea3b2f42df50e6b16/README.md).

```
version: "2.1"
services:
  minetest:
    image: linuxserver/minetest
    container_name: minetest
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=US/Eastern
    volumes:
      - /volumes/minetest/config/.minetest:/config/.minetest
    ports:
      - 30000:30000/udp
    restart: unless-stopped

```

We’ll need to create a `systemd` script called `docker-compose.service` for systemd to [enable docker-compose on startup](https://brandonrozek.com/blog/composesystemd/).

```
[Unit]
Description=Docker Compose Application Service
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/root
ExecStart=/usr/bin/docker-compose up -d
ExecStop=/usr/bin/docker-compose down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target

```

Finally we’ll need to write a packer configuration file `do.pkr.hcl` to create our snapshot.

```
source "digitalocean" "web" {
  api_token = var.do_token
  image = var.base_system_image
  region = var.region
  size = var.size
  ssh_username = "root"
  snapshot_name = "packer-docker"
}

build {
  sources = [
    "source.digitalocean.web",
  ]

  provisioner "file" {
    source = "docker-compose.yml"
    destination = "/root/docker-compose.yml"
  }
  
  provisioner "file" {
    source = "docker-compose.service"
    destination = "/etc/systemd/system/docker-compose.service"
  }
  
  provisioner "shell" {
    scripts = ["setup.sh"]
  }
}

```

To build our image we need to run `packer build .` in the directory with all these files.

## Terraform

Like before, we need to tell terraform where to look for its configuration

```
mkdir terraform && cd terraform
ln -s ../config terraform.tfvars
ln -s ../variables.hcl variables.tf

```

To deploy, we only need to create one additional file that will tell digital ocean to create a droplet and assign a subdomain to that droplet.

```
provider "digitalocean" {
    token = var.do_token
}

data "digitalocean_ssh_key" laptop {
    name = var.key_name
}

data "digitalocean_droplet_snapshot" "packer_snapshot" {
    name = "packer-docker"
    most_recent = true
}

# Create a droplet
resource "digitalocean_droplet" "web" {
    name = "tf-1"
    image = data.digitalocean_droplet_snapshot.packer_snapshot.id
    region = var.region
    size = var.size
    ssh_keys = [data.digitalocean_ssh_key.laptop.id]
    backups = false
}

# Attach a subdomain
resource "digitalocean_record" "www" {
  domain = var.domain
  type = "A"
  name = var.subdomain
  value = digitalocean_droplet.web.ipv4_address
}

output "ip" {
    value = digitalocean_droplet.web.ipv4_address
}

output "domain" {
    value = "${digitalocean_record.www.name}.${digitalocean_record.www.domain}"
}

```

To deploy run

```
terraform apply

```

To later take down the minetest server, run

```
terraform destroy

```

## Conclusion

This method can be easily configured to run whichever docker services you’d like. All you have to do is edit the `packer/docker.compose.yml` file and `packer/setup.sh` to setup the firewall rules.