In this post we will setup a Docker Image for Traefik Proxy on the ARM Architecture, specifically on the Raspberry Pi, which we will deploy to our Raspberry Pi Docker Swarm.
Then we will build and push our image to a registry, then setup traefik and also setup a web application that sits behind our Traefik Proxy.
What is Traefik
Traefik is a modern load balancer and reverse proxy built for micro services.
Dockerfile
We will be running Traefik on Alpine 3.8:
FROM rbekker87/armhf-alpine:3.8
ENV TRAEFIK_VERSION 1.7.0-rc3
ENV ARCH arm
ADD https://github.com/containous/traefik/releases/download/v${TRAEFIK_VERSION}/traefik_linux-${ARCH} /traefik
RUN apk add --no-cache ca-certificates \
&& chmod +x /traefik \
&& rm -rf /var/cache/apk/*
EXPOSE 80 8080 443
ENTRYPOINT ["/traefik"]
Build and Push
Build and Push your image to your registry of choice:
$ docker build -t your-user/repo:tag .
$ docker push your-user/repo:tag
If you do not want to push to a registry, I have a public image available at https://hub.docker.com/r/rbekker87/armhf-traefik/, the image itself is rbekker87/armhf-traefik:1.7.0-rc3
Deploy Traefik to the Swarm
From our traefik-compose.yml
, you will notice that I have set that our network is external, so the network should exist prior to deploying the stack.
Let's create the overlay network:
$ docker network create --driver overlay appnet
Below, the traefik-compose.yml
:
version: "3.4"
services:
traefik:
image: rbekker87/armhf-traefik:1.7.0-rc3
command:
- "--api"
- "--docker"
- "--docker.swarmmode"
- "--docker.domain=mydomain.co.za"
- "--docker.watch"
- "--logLevel=DEBUG"
- "--web"
networks:
- appnet
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- 80:80
- 8080:8080
deploy:
mode: global
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
networks:
appnet:
external: true
Deploy the stack:
$ docker stack deploy -c traefik-compose.yml proxy
List the stacks:
$ docker stack ls
NAME SERVICES
proxy 1
Check if the services in your stack is running. Since our deploy mode was global, there will be a replica running on each node, and in my swarm I've got 3 nodes:
$ docker stack services proxy
ID NAME MODE REPLICAS IMAGE PORTS
16x31j7o0f0r proxy_traefik global 3/3 rbekker87/armhf-traefik:1.7.0-rc3 *:80->80/tcp,*:8080->8080/tcp
Deploy a Web Service hooked up to Traefik
Pre-Requirement:
To register subdomains on the fly, set you DNS for your domain to the following:
mydomain.co.za
A
x.x.x.x
*.mydomain.co.za
A
x.x.x.x
Next, we will deploy we app that will be associated to our Traefik service domain, so we will inform Traefik that our web app fqdn and port that will be registered with the proxy.
Our app-compose.yml
file for our webapp:
version: "3.4"
services:
whoami:
image: rbekker87/golang-whoami:alpine-amrhf
networks:
- appnet
deploy:
replicas: 3
labels:
- "traefik.backend=whoami"
- "traefik.port=80"
- "traefik.frontend.rule=Host:whoami.mydomain.co.za"
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
placement:
constraints: [node.role == worker]
healthcheck:
test: nc -vz 127.0.0.1 80 || exit 1
interval: 60s
timeout: 3s
retries: 3
networks:
appnet:
external: true
In the above compose, you will notice that our traefik backend is set to our service name, our port is the port that the proxy will forward requests to the containers port, since the proxy and the whoami container is in the same network, they will be able to communicate with each other. Then we also have our frontend rule which will be the endpoint we will reach our application on.
Deploy the stack:
$ docker stack deploy -c whoami.yml web
Creating service web_whoami
List the tasks running in our web stack:
$ docker stack services web
ID NAME MODE REPLICAS IMAGE PORTS
31ylfcfb7uyw web_whoami replicated 3/3 rbekker87/golang-whoami:alpine-amrhf
Once all the replicas is running, move along to test the application
Testing our Application:
I have 3 replicas each running on their own container, so each container will respond with its own hostname:
$ docker service ps web_whoami
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ivn8fgfosvgd web_whoami.1 rbekker87/golang-whoami:alpine-amrhf rpi-01 Running Running 26 minutes ago
rze6u6z56aop web_whoami.2 rbekker87/golang-whoami:alpine-amrhf rpi-02 Running Running 26 minutes ago
6fjua869r498 web_whoami.3 rbekker87/golang-whoami:alpine-amrhf rpi-04 Running Running 23 minutes ago
Making our 1st GET request:
$ $ curl http://whoami.pistack.co.za/
Hostname: 43f5f0a6682f
IP: 127.0.0.1
IP: 10.0.0.138
IP: 10.0.0.218
IP: 172.18.0.4
GET / HTTP/1.1
Host: whoami.pistack.co.za
User-Agent: curl/7.38.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 165.73.96.95, 10.255.0.2
X-Forwarded-Host: whoami.pistack.co.za
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 31b37f9714d3
X-Real-Ip: 10.255.0.2
Our 2nd GET Request:
$ curl http://whoami.pistack.co.za/
Hostname: d1c17a476414
IP: 127.0.0.1
IP: 10.0.0.138
IP: 10.0.0.71
IP: 172.19.0.5
GET / HTTP/1.1
Host: whoami.pistack.co.za
User-Agent: curl/7.38.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 165.73.96.95, 10.255.0.2
X-Forwarded-Host: whoami.pistack.co.za
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 02b0ff6eab73
X-Real-Ip: 10.255.0.2
And our 3rd GET Request:
$ curl http://whoami.pistack.co.za/
Hostname: 17c817a1813b
IP: 172.18.0.6
IP: 127.0.0.1
IP: 10.0.0.138
IP: 10.0.0.73
GET / HTTP/1.1
Host: whoami.pistack.co.za
User-Agent: curl/7.38.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 165.73.96.95, 10.255.0.2
X-Forwarded-Host: whoami.pistack.co.za
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 31b37f9714d3
X-Real-Ip: 10.255.0.2
Hope this was useful.