the Pi Swarm cluster
7.1 KiB
+++ title = "Deploying Traefik and Pihole on the Swarm home cluster" author = ["Elia el Lazkani"] date = 2022-08-25 lastmod = 2022-08-25 tags = ["docker", "linux", "arm", "ansible", "traefik", "pihole", "swarm", "raspberry-pi"] categories = ["container"] draft = false +++
In the [previous post]({{< relref "raspberry-pi-container-orchestration-and-swarm-right-at-home" >}}), we setup a Swarm cluster. That's fine and dandy but that cluster, as far as we're concerned, is useless. Let's change that.
Traefik
I've talked and played with Traefik previously on this blog and here we go
again, with another orchestration technology. As always, we need an ingress to
our cluster. Traefik makes a great ingress that's easily configurable with labels
.
Let's not forget, we're working with Swarm this time around. Swarm stacks
look very similar to docker-compose
manifests.
But, before we do that, there is a small piece of information that we need to be aware of. For Traefik to be able to route traffic to our services, both Traefik and the service need to be on the same network. Let's make this a bit more predictable and manage that network ourselves.
warning
Only leader
and manager
nodes will allow interaction with the Swarm
cluster. The worker
nodes will not give you any useful information about the
cluster.
Network Configuration
We started with Ansible and we shall continue with Ansible. We begin with creating the network.
---
- name: Create a Traefik Ingress network
community.docker.docker_network:
name: traefik-ingress
driver: overlay
scope: swarm
Ingress
Once the network is in place, we can go ahead and deploy Traefik.
warning
This setup is not meant to be deploy in a production setting. SSL certificates require extra configuration steps that might come in a future post.
---
- name: Deploy Traefik Stack
community.docker.docker_stack:
state: present
name: Traefik
compose:
- version: '3'
services:
traefik:
image: traefik:latest
restart: unless-stopped
command:
- --entrypoints.web.address=:80
- --providers.docker=true
- --providers.docker.swarmMode=true
- --accesslog
- --log.level=INFO
- --api
- --api.insecure=true
ports:
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- traefik-ingress
deploy:
replicas: 1
resources:
limits:
cpus: '1'
memory: 80M
reservations:
cpus: '0.5'
memory: 40M
placement:
constraints:
- node.role == manager
labels:
- traefik.protocol=http
- traefik.docker.network=traefik-ingress
- traefik.http.routers.traefik-api.rule=Host(`traefik.our-domain.com`)
- traefik.http.routers.traefik-api.service=api@internal
- traefik.http.services.taefik-api.loadbalancer.server.port=8080
networks:
traefik-ingress:
external: true
Note
Even though these are Ansible tasks, Swarm stack manifests are not much different as I'm using mostly the raw format.
Let's talk a bit about what we did.
--providers.docker=true
and--providers.docker.swarmMode=true
- We configure Traefik to enable both docker and swarm mode providers.
--api
and--api-insecure=true
- We enable the API which offers the UI and we allow it to run insecure.
The rest, I believe, have been explained in the previous blog post.
If everything went well, and we configured our DNS properly, we should be
welcomed by a Traefik dashboard on traefik.our-domain.com
.
Pi-hole
Now I know most people install the Pi-hole straight on the Pi. Well, I'm not most people and I'd like to deploy it in a container. I feel it's easier all around than installing it on the system, you'll see.
---
- name: Deploy PiHole Stack
community.docker.docker_stack:
state: present
name: PiHole
compose:
- version: '3'
services:
pihole:
image: pihole/pihole:latest
restart: unless-stopped
ports:
- "53:53"
- "53:53/udp"
cap_add:
- NET_ADMIN
environment:
TZ: "Europe/Vienna"
VIRTUAL_HOST: pihole.our-domain.com
VIRTUAL_PORT: 80
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/"]
interval: 30s
timeout: 20s
retries: 3
volumes:
- /opt/pihole/data/pihole-config:/etc/pihole
- /opt/pihole/data/pihole-dnsmasq.d:/etc/dnsmasq.d
networks:
- traefik-ingress
deploy:
replicas: 1
placement:
constraints:
- node.role == worker
labels:
- traefik.docker.network=traefik-ingress
- traefik.http.routers.pihole-http.entrypoints=web
- traefik.http.routers.pihole-http.rule=Host(`pihole.our-domain.com`)
- traefik.http.routers.pihole-http.service=pihole-http
- traefik.http.services.pihole-http.loadbalancer.server.port=80
- traefik.http.routers.pihole-http.middlewares=pihole-main
- traefik.http.middlewares.pihole-main.chain.middlewares=frame-deny,browser-xss-filter
- traefik.http.middlewares.frame-deny.headers.framedeny=true
- traefik.http.middlewares.browser-xss-filter.headers.browserxssfilter=true
networks:
traefik-ingress:
external: true
We make sure to expose port 53
for DNS on all nodes, and configure the
proper labels
to our service so that Traefik can pick it up.
Once deployed and your DNS is pointing properly then pihole.our-domain.com
is waiting for you. This also shows us that the networking between nodes works
properly. Let's test it out.
$ nslookup duckduckgo.com pihole.our-domain.com
Server: pihole.our-domain.com
Address: 192.168.1.100#53
Non-authoritative answer:
Name: duckduckgo.com
Address: 52.142.124.215
Alright, seems that our Pi-hole works.
Conclusion
On these small Raspberry Pis, the cluster seems to be working very well. The Pi-hole has been running without any issues for a few days running my internal DNS. There's a few improvements that can be done to this setup, mainly the deployment of an SSL cert. That may come in the future, time permitting. Stay safe, until the next one !