parent
526b27b280
commit
4a1580f113
@ -0,0 +1,227 @@ |
||||
+++ |
||||
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. |
||||
|
||||
<!--more--> |
||||
|
||||
|
||||
## Traefik {#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. |
||||
|
||||
<div class="admonition warning"> |
||||
<p class="admonition-title">warning</p> |
||||
|
||||
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. |
||||
|
||||
</div> |
||||
|
||||
|
||||
### Network Configuration {#network-configuration} |
||||
|
||||
We started with _Ansible_ and we shall continue with _Ansible_. We begin with |
||||
creating the network. |
||||
|
||||
```yaml |
||||
--- |
||||
- name: Create a Traefik Ingress network |
||||
community.docker.docker_network: |
||||
name: traefik-ingress |
||||
driver: overlay |
||||
scope: swarm |
||||
``` |
||||
|
||||
|
||||
### Ingress {#ingress} |
||||
|
||||
Once the network is in place, we can go ahead and deploy _Traefik_. |
||||
|
||||
<div class="admonition warning"> |
||||
<p class="admonition-title">warning</p> |
||||
|
||||
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. |
||||
|
||||
</div> |
||||
|
||||
```yaml |
||||
--- |
||||
- 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 |
||||
``` |
||||
|
||||
<div class="admonition note"> |
||||
<p class="admonition-title">Note</p> |
||||
|
||||
Even though these are _Ansible_ tasks, _Swarm_ stack manifests are not much |
||||
different as I'm using mostly the raw format. |
||||
|
||||
</div> |
||||
|
||||
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 {#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. |
||||
|
||||
```yaml |
||||
--- |
||||
- 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. |
||||
|
||||
```shell |
||||
$ 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 {#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 ! |
Loading…
Reference in new issue