Docker + Traefik
Create a microservice architecture and handle routing
Docker is a container management tool and Traefik is a reverse proxy for managing the routing between containers. With both tools, you can create a microservice architecture.
This quick tutorial will focus on developing with Docker and Traefik. Thus, it won’t go over Docker swarm mode very much (which is for running Docker on multiple machines).
I’ll be using this repo for the tutorial: https://github.com/efossas/CRUD. It’s for creating a CRUD application. It’s super simple to set up. Run the commands below and set up DNS to route crud.docker.localhost & traefik.docker.localhost to localhost (127.0.0.1). The easy way to do that is to edit /etc/hosts
git clone https://github.com/efossas/CRUD
docker-compose up -d
Btw, it helps to have a strong understanding of how Unix shells work to really understand Docker.
What This Tutorial Covers
- Docker basics
- Building a Docker image
- Docker terminology
- Using Docker Compose
- Using Traefik with Docker
What You Need For This Tutorial
Docker is a set of tools for managing containers. A container is essentially a sandboxed user level operating system with a single running process.
Run the following command and you will be put inside a container with the Alpine operating system. It’s running process is the ASH unix shell, so you can run typical commands like ls, cd, pwd, etc. To exit the container, run exit.
docker run -it alpine
Btw, there are many linux based operating system Docker containers, like Ubuntu and Centos, but Alpine is very common as it has the smallest size.
The following are basic Docker commands everyone should know:
- docker run -itd — name NAME IMAGE
- docker exec -it NAME COMMAND
- docker ps -aq
- docker restart NAME
- docker stop NAME
- docker start NAME
- docker rm NAME
Building A Docker Image
A Docker image is like a template. When you run an image, it becomes a container. To build a Docker image, we first create a Dockerfile with instructions. The following is a simple Dockerfile definition:
Now to actually build the file, we run the following command:
# without the -f flag, Docker assumes the file is called 'Dockerfile'
# the . at the end just means to look for the file in current directory docker build --no-cache -f Dockerfile -t efossas/crud:latest .
The no-cache flag requires some explaining. For each instruction in the Dockerfile, Docker creates a new commit, like the way git does a commit. When you rebuild an image, Docker will use the results of previously run instructions instead of running them again. Using the no-cache ensures that all instructions are run again.
The following are some commands for viewing, removing, pulling, and pushing images:
- docker image ls
- docker rmi IMAGE
- docker pull IMAGE
- docker push IMAGE
For the push command to work, you must have a registry set up. You can run your own using the official registry image https://hub.docker.com/_/registry/. You can also use DockerHub to host your images. Finally, there are many other SaaS providers that offer registry services, like GitLab.
Finally, Docker assumes you’re using DockerHub as your registry. To use a different one, you must run the following command:
docker login URI
- Image — A template for a container.
- Container — A sandboxed user level operating system with a single running process.
- Service — A container along with additional information needed to interact with it, including networking, persistent storage, and additional configuration .
- Stack — A collections of services grouped together. They can be orchestrated and scaled together.
- Swarm (not discussed in this tutorial) — “Swarm” mode is for running services across multiple machines. It’s mainly for production so you can scale your compute and storage resources.
Compose is a tool that allows you to declare Docker stacks. A Docker stack is a group of related services.
It’s best explained by just showing you a complete docker-compose.yml file with comments explaining what everything does.
Now to start your microservice application, you run the following command:
# without the -f flag, Docker assumes the file is called 'docker-compose.yml'
# the -d flag is for detached mode, in that Docker will run as a background process docker-compose -f docker-compose.yml up -d
Finally, some extra configuration can be put in a hidden .env file.
Traefik is a reverse proxy. It’s useful for routing connections to different services based on different domains and paths. For example, you can have http://DOMAIN/first/pathroute to one container & http://DOMAIN/second/pathroute to another container. Traefik also has load balancers built in, though I don’t use them in this tutorial as it’s focused on development more than production.
There are 3 important things to understand about Traefik.
- Entry Point is a port that Traefik accepts connections to. Entry points are defined in traefik.toml. Then, each service must declare which entry point(s) it wants to accept connections from.
- Front End is a rule for routing connections. Each service must declare rule(s) for matching connections it wants to accept, such as Host: for matching incoming connections by host name.
- Back End is a load balancer for distributing incoming connections that match a front end rule to multiple containers running the same service. Services do not have to declare a back end. When not declared, a default back-end is created with the name backend-SERVICE-PROJECT-SEGMENT. You really only need to define back-ends if you plan on load balancing among multiple containers.
A list of configuration and rules can be found here: https://docs.traefik.io/configuration/backends/docker/#on-containers
So, after spinning up our Docker stack, our application networking looks like the image below:
Here is the traefik.toml configuration.
Btw, feel free to tell Traefik it should support yml files for configuration here: https://github.com/containous/traefik/issues/2999
Well, that’s zero to hundred in about as short as I could make it for Docker and Traefik.