chore(): Publishing a blog post about deploying Traefik and Pi-hole on

the Pi Swarm cluster
This commit is contained in:
Elia el Lazkani 2022-08-25 21:02:06 +02:00
parent 526b27b280
commit 4a1580f113
2 changed files with 444 additions and 0 deletions

View file

@ -2812,6 +2812,223 @@ clusters on low resource devices extremly easy. It comes with the added bonus of
having built-in /service discovery/ and /networking/. Give it a try, you might
be pleasently surprised like I was.
*** DONE Deploying Traefik and Pihole on the /Swarm/ home cluster :docker:linux:arm:ansible:traefik:pihole:swarm:raspberry_pi:
:PROPERTIES:
:EXPORT_HUGO_LASTMOD: 2022-08-25
:EXPORT_DATE: 2022-08-25
:EXPORT_FILE_NAME: deploying-traefik-and-pihole-on-the-swarm-home-cluster
:CUSTOM_ID: deploying-traefik-and-pihole-on-the-swarm-home-cluster
:END:
In the [[#raspberry-pi-container-orchestration-and-swarm-right-at-home][previous post]], 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.
#+hugo: more
**** 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.
#+BEGIN_EXPORT html
<div class="admonition warning">
<p class="admonition-title">warning</p>
#+END_EXPORT
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.
#+BEGIN_EXPORT html
</div>
#+END_EXPORT
***** Network Configuration
We started with /Ansible/ and we shall continue with /Ansible/. We begin with
creating the network.
#+begin_src yaml
---
- name: Create a Traefik Ingress network
community.docker.docker_network:
name: traefik-ingress
driver: overlay
scope: swarm
#+end_src
***** Ingress
Once the network is in place, we can go ahead and deploy /Traefik/.
#+BEGIN_EXPORT html
<div class="admonition warning">
<p class="admonition-title">warning</p>
#+END_EXPORT
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.
#+BEGIN_EXPORT html
</div>
#+END_EXPORT
#+begin_src 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
#+end_src
#+BEGIN_EXPORT html
<div class="admonition note">
<p class="admonition-title">Note</p>
#+END_EXPORT
Even though these are /Ansible/ tasks, /Swarm/ stack manifests are not much
different as I'm using mostly the raw format.
#+BEGIN_EXPORT html
</div>
#+END_EXPORT
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.
#+begin_src 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
#+end_src
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.
#+begin_src 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
#+end_src
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 !
** K3s :@k3s:
*** DONE Building k3s on a Pi :arm:kubernetes:
:PROPERTIES:

View file

@ -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 !