Introduction
When the Docker container came, it made building web applications easier for developers in both development and deployment. Before, I used Docker for development, but now I have decided to learn how to use it for deployment.
When you search the Internet, you may encounter many complex terms for newbies, such as CI/CD, K8s, and docker swarm. In this post, I'll focus on a basic understanding of the deployment workflow and then, deploy a simple Go web app on my Linode VPS.
In my opinion, the basic workflow behind Docker deployment can be divided into 4 steps:
- Build an image from your application code.
- Push the image you built in the previous step to the Docker service ( docker hub, Amazon ECR, ...).
- Write a file (regularly .yml) that defines each needed service.
- Run a file in step 3 to pull images, setup and run each service on your VPS.
Sample Golang web app
For saving time, I'll use the existing repo, at the beginning I decided to use my old Rails app. But after going around on the Internet, and seeing the exciting repo that was written in Go, I'll use it for demo deployment.
Here's my Git repo for this demo: https://github.com/hungle00/hacker-live
You can see a Dockerfile to build an image for this app in this repo.
Dockerfile for hacker-live
Use docker-compose
I will use Treafik for the proxy server, which will act as the middle-man between the outside web and your VPS. The advantage of Treafik compared to other proxy servers is that it can automatically detect our running containers.
Here's the docker-compose.yml
file that defines 2 services: Treafik proxy and our Go app.
version: '3'
services:
reverse-proxy:
# The official v3 Traefik docker image
image: traefik:v3.3
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
# The HTTP port
- "80:80"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
hacker-live:
image: jamesjoyce/hacker-live
container_name: hacker-live
labels:
- "traefik.http.routers.hacker-live.rule=Host(`Your IP/domain`)"
You just ssh to your server, copy docker-compose.yml
file and then run:
docker-compose up -d
This approach is not practical because every time you change code, you must rebuild this image, then ssh to the server, and edit the docker-compose file to redefine the services.
In reality, we need the tool for the automatic setup of these steps. In the next part, I'll introduce Kamal for deployment.
Use Kamal
Kamal is the tool developed by the Rails team for deploying and managing your web app in production with Docker.
Simply speaking, Kamal is mostly a bunch of scripts to automate Docker deploys. When you run kamal init
, it will generate some files that need for deployment, the most important file is config/deploy.yml
.
For example, below is the config/deploy.yml
file I use
# Name of your application. Used to uniquely configure containers.
service: hacker-live
# Name of the container image.
image: jamesjoyce/hacker-live
# Deploy to these servers.
servers:
web:
- 192.168.0.1 # change this with your IP
# job:
# hosts:
# - 192.168.0.1
# cmd: bin/jobs
proxy:
ssl: true
host: app.example.com
# Proxy connects to your container on port 80 by default.
# app_port: 3000
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
# server: registry.digitalocean.com / ghcr.io / ...
username: jamesjoyce
# Always use an access token rather than real password (pulled from .kamal/secrets).
password:
- KAMAL_REGISTRY_PASSWORD
# Configure builder setup.
builder:
arch: amd64
# Pass in additional build args needed for your Dockerfile.
# args:
# RUBY_VERSION: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
As you can see, I didn't define service for Treakfik. This is because Kamal automatically uses their Kamal proxy for the proxy server.
After config, then you run:
kamal deploy
# or kamal setup
It will SSH into each server, prepare it with any necessary dependencies, and build and push the latest images to the docker registry.
You can read more about Kamal at the official docs. There are many concepts that I didn't introduce in this post, for example: manage accessories (db/redis/search), manage logging, ...
Whatβs next
In this post, I just introduce how to deploy a very basic web app on VPS using Docker. In reality, you may need more to deploy and manage your web app in production, for example:
- Some services like database, job workers, Redis, ...
- Monitoring your server (memory usage, CPU, disk, etc.) ...
- Setup CI/CD
Top comments (0)