The past two parts were the boring parts. Now this is something where I will try to write in much more detailed because this is amazing. While completely simple, this still blows my mind and I get excited to this day explaining it to people how it works. So lets begin.
Docker: The Power of Containerization
Containerization is a technology that has revolutionized software deployment and management. Docker, although not the pioneer, stands as the preeminent solution in the world of containerization. While alternatives like containerd and Kubernetes exist, Docker’s simplicity and widespread adoption make it a prime choice for developers and system administrators alike.
Imagine you have a piece of code or software running perfectly on your local machine. You’re thrilled to showcase it to others or perhaps deploy it in a production environment. But alas, it refuses to work the same way or, worse, fails to work at all on a different system. The frustrating phrase “but it worked on my computer” echoes in your mind. This is where containerization swoops in as the savior.
Containers are like virtual machines that ride on the back of your operating system files. This unique architecture grants them exceptional lightweight attributes and blazing-fast execution times. Think of them as blank canvases where you can select the base operating system and define precisely which files perform specific functions and where they go. Containerization is like following a recipe – precise instructions yield the exact same output every time. But why stop here with explanations? Let’s roll up our sleeves and get started. I firmly believe that examples are the most effective way to learn.
Setting Up Docker
Let’s begin by SSHing into our remote server. Assuming you already have a Linux-based server up and running, we’ll follow Docker’s official installation guide. Here’s a quick overview:
Step 1: Set up Docker's Apt repository
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update Step 2: Install the Docker packages.
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin Step 3: Verify that the Docker Engine installation is successful by running the hello-world image.
sudo docker run hello-world Congratulations! You’ve successfully installed Docker.
Docker Compose: Simplifying Service Orchestration
But wait, there’s more. Enter Docker Compose, a tool that allows us to bundle all our Dockerfiles and associated parameters into one human-readable YAML file. This simplifies the process of starting and managing multiple services. Let’s get it up and running:
Step 1: Update the package index, and install the latest version of Docker Compose:
sudo apt-get update
sudo apt-get install docker-compose-plugin Step 2: Verify that Docker Compose is installed correctly by checking the version.
docker compose version
# Docker Compose version vN.N.N Traefik: The Reverse Proxy Magic
Docker lays the foundation for our infrastructure, ensuring that we can build and deploy services irrespective of the underlying system. Now, let’s introduce Traefik, a remarkable tool in our arsenal. While Nginx is another excellent option for a reverse proxy, Traefik offers a fresh perspective.
You might be wondering, why do we even need a reverse proxy? Allow me to elucidate.
A reverse proxy acts as an intermediary, receiving incoming requests and directing them to the appropriate service. If you’ve developed web applications, you’re familiar with port numbers like 8080, 3000, or 8000 assigned to your apps. To access them via a browser, you’d enter a URL followed by a colon and the port number. Unless you’re on ports 80 (HTTP) or 443 (HTTPS), this port-centric approach becomes the norm. However, the reverse proxy brings a game-changing solution.
Imagine running a WordPress server on port 80, and you wish to spin up a Vue.js project. The conflict arises because only one application can listen on a port at a time. This is where the reverse proxy shines. It not only eliminates port clashes but also enhances security. Exposing numerous ports to the public poses a security risk, potentially inviting port scan attacks. With a reverse proxy, we ensure that only ports 80 and 443 remain accessible, bolstering security.
You can follow along and fork and edit the repository I have created for this right here on GitHub.
Docker Compose Yaml for Traefik
Now, let’s delve into the docker-compose.yml file for Traefik:
version: "3.8"
services:
traefik:
image: "traefik:latest"
container_name: "traefik"
ports:
- "80:80"
- "443:443"
- "8080:8080" # (optional) expose the dashboard !don't use in production! The labels below will route to 8080 (your dashboard)
volumes:
- "${PWD}/traefik.yml:/etc/traefik/traefik.yml"
- "${PWD}/certs:/etc/traefik/certs"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
labels:
- "traefik.docker.network=traefik-proxy"
- "traefik.enable=true"
# Route Dashboard
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik.service=api@internal"
- "trafeik.http.routers.whoami.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=production"
- "traefik.http.routers.traefik.entrypoints=websecure"
# Authentication middleware
- "traefik.http.routers.traefik.middlewares=auth"
# Use htpasswd to generate Apache specific salted MD5 password
# DO NOT FORGET TO ESCAPE '$' with another '$'!!
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$5j0z4q36$$Zw6i9ObMYnHtpgjIdGdqJ1" # username:password = admin:admin
networks:
- "traefik-proxy"
restart: "unless-stopped"
networks:
traefik-proxy:
external: true Let’s break down the key sections of this docker-compose.yml file and understand the purpose of variables where applicable:
- Version: The
versionkey specifies the version of the Docker Compose file format being used. In your example, it’s set to “3.8,” which indicates compatibility with Compose file format version 3.8. - Services: Under the
servicessection, you define the services or containers you want to run.- traefik: This is the name of the service. It’s associated with the Traefik container.
- image: Specifies the Docker image to be used for this service. In this case,
"traefik:latest"refers to the latest version of the Traefik image available on Docker Hub. - container_name: Defines the name of the container that will be created based on this service. In this case, it’s set to “traefik.”
- ports: Lists the ports to be exposed on the host machine and mapped to the corresponding ports inside the container. In your example, you expose ports 80, 443, and 8080.
- volumes: Mounts directories or files from the host machine into the container. In your case, it includes configuration files and certificates.
- labels: This section is crucial for Traefik’s configuration. It uses labels to specify various settings and rules for Traefik. These labels are where variables are primarily used, defining things like routing rules, enabling authentication middleware, and specifying SSL certificates. Let’s break down a few key labels:
traefik.docker.network: Specifies the Docker network that Traefik should use.traefik.http.routers.traefik.rule: Sets a routing rule for the Traefik dashboard.traefik.http.routers.traefik.service: Specifies the service that Traefik should use for the dashboard.traefik.http.routers.traefik.tls.certresolver: Configures the certificate resolver for SSL/TLS encryption.traefik.http.routers.traefik.middlewares: Defines middleware for authentication.
- Networks: This section specifies Docker networks. In your case, you have a network named “traefik-proxy” defined as an external network. This network is used to connect containers, allowing them to communicate with each other.
- Restart: Determines the container’s restart behavior. In your example, it’s set to “unless-stopped,” meaning the container will restart unless explicitly stopped
Traefik Configuration: traefik.yml
In this traefik.yml file, we configure global settings, logging options, enable the API and dashboard (be cautious in production), define entry points for HTTP and HTTPS, and set up certificate resolvers for securing your services.
Now, let’s explore the traefik.yml file:
global:
checkNewVersion: true
sendAnonymousUsage: false # true by default
# (Optional) Log information
# ---
# log:
# level: ERROR # DEBUG, INFO, WARNING, ERROR, CRITICAL
# format: common # common, json, logfmt
# filePath: /var/log/traefik/traefik.log
# (Optional) Accesslog
# ---
# accesslog:
# format: common # common, json, logfmt
# filePath: /var/log/traefik/access.log
# (Optional) Enable API and Dashboard
# ---
api:
dashboard: true # true by default
insecure: true # Don't do this in production!
# Entry Points configuration
# ---
entryPoints:
web:
address: :80
# (Optional) Redirect to HTTPS
# ---
# http:
# redirections:
# entryPoint:
# to: websecure
# scheme: https
websecure:
address: :443
# Configure your CertificateResolver here...
# ---
certificatesResolvers:
staging:
acme:
email: [email protected]
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
production:
acme:
email: [email protected]
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
# (Optional) Overwrite Default Certificates
#tls:
# stores:
# default:
# defaultCertificate:
# certFile: /etc/traefik/certs/cert.pem
# keyFile: /etc/traefik/certs/cert-key.pem
# (Optional) Disable TLS version 1.0 and 1.1
# options:
# default:
# minVersion: VersionTLS12
providers:
docker:
exposedByDefault: false # Default is true
file:
# watch for dynamic configuration changes
directory: /etc/traefik
watch: true This file contains configuration settings for the Traefik reverse proxy. It complements the docker-compose.yml by providing additional Traefik-specific configurations. Let’s delve into the key sections and understand the use of variables:
- Global Configuration: This section defines global settings for Traefik.
checkNewVersion: A boolean that enables or disables checking for new Traefik versions.sendAnonymousUsage: Another boolean that controls whether anonymous usage data is sent to Traefik maintainers.
- Log Configuration: These settings control how Traefik logs information.
log.level: Defines the log level (e.g., ERROR, INFO, DEBUG).log.format: Specifies the log format (e.g., common, json, logfmt).log.filePath: Sets the file path for Traefik’s log file.
API and Dashboard Configuration: Configures Traefik’s API and dashboard.
api.dashboard: Enables or disables the dashboard.api.insecure: A boolean flag to determine whether the dashboard should be accessible over an insecure connection (not recommended for production).
Entry Points Configuration: Defines entry points for incoming requests.
webandwebsecureare the names of entry points, along with their respective addresses and optional HTTPS redirection.
Certificate Resolvers: Configures certificate resolvers for SSL/TLS encryption.
stagingandproductionare two certificate resolvers with settings such as email, storage location, and CA server.
Providers: Specifies how Traefik should discover and manage routes to different services.
dockerandfileproviders are defined. Thedockerprovider is used to discover services from Docker containers, while thefileprovider watches for dynamic configuration changes in the specified directory.
With these powerful tools in your toolkit, you’re well-equipped to conquer containerization, service orchestration, and reverse proxy magic. Docker, Docker Compose, and Traefik offer a potent trifecta for modern software deployment and management. So, go ahead and unleash their potential to streamline your development and deployment workflows. Happy coding!
Feel free to further customize the content or make any additional changes you may require. If you have any specific requests or questions, please let me know, and I’ll be happy to assist you further.