From 4a1580f113bcb12bfd010d4835ac154769252df3 Mon Sep 17 00:00:00 2001 From: Elia el Lazkani Date: Thu, 25 Aug 2022 21:02:06 +0200 Subject: [PATCH] chore(): Publishing a blog post about deploying Traefik and Pi-hole on the Pi Swarm cluster --- content-org/blog.org | 217 +++++++++++++++++ ...ik-and-pihole-on-the-swarm-home-cluster.md | 227 ++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 content/posts/deploying-traefik-and-pihole-on-the-swarm-home-cluster.md diff --git a/content-org/blog.org b/content-org/blog.org index f1658f2..1304b2c 100644 --- a/content-org/blog.org +++ b/content-org/blog.org @@ -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 +
+

warning

+#+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 +
+#+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 +
+

warning

+#+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 +
+#+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 +
+

Note

+#+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 +
+#+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: diff --git a/content/posts/deploying-traefik-and-pihole-on-the-swarm-home-cluster.md b/content/posts/deploying-traefik-and-pihole-on-the-swarm-home-cluster.md new file mode 100644 index 0000000..a71ae92 --- /dev/null +++ b/content/posts/deploying-traefik-and-pihole-on-the-swarm-home-cluster.md @@ -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. + + + + +## 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. + +
+

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 {#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_. + +
+

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. + +
+ +```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 +``` + +
+

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 {#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 !