<span class="hljs-attribute">EMAIL</span>[email protected] <span class="hljs-attribute">DOMAIN</span>=example.com envsubst < traefik.toml.kv.sample > traefik.toml</pre></div><div id="39d0"><pre><span class="hljs-comment"># forward consul to localhost</span>
<span class="hljs-variable"> </span>kubectl -n consul port-forward consul-<span class="hljs-number">0</span> <span class="hljs-number">8500</span>:<span class="hljs-number">8500</span> &</pre></div><div id="8d2c"><pre><span class="hljs-comment"># magic time</span>
$ traefik storeconfig --consul --consul.<span class="hljs-attribute">endpoint</span>=localhost:8500 --file.<span class="hljs-attribute">filename</span>=./traefik.toml
<span class="hljs-built_in">..</span>.
Writing<span class="hljs-built_in"> config </span><span class="hljs-keyword">to</span> KV</pre></div><p id="77d1">If properly imported, check the values in Consul K/V store</p><figure id="7361"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*z27gviv45MWFjI3iLHeURw.png"><figcaption>K/V store after import</figcaption></figure><p id="14f8">After above importing steps, a manual change for the value of key traefik/consul/endpoint is needed. As shown in below screenshot, to ‘<a href="https://consul.consul.svc.cluster.local:8443">https://consul.consul.svc.cluster.local:8443</a>’, which is the URL to the consul service.</p><figure id="9c0b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*PgVe1D9RAMM1FRT-D1edWQ.png"><figcaption>manually modify this valule</figcaption></figure><p id="e185">If there are existing Let’sEncrypt certificates in a file acme.json, simply un-comment the line</p><div id="a877"><pre><span class="hljs-meta">#storageFile = <span class="hljs-string">"./acme.json"</span></span></pre></div><p id="9996">from file traefik.toml and do the import. It will also get imported into Consul.</p><p id="bdda">Then delete the key traefik/acme/account/lock, to a
Options
llow the Traefik Ingress pods get the lock.</p><h2 id="d658">Deploy Traefik Ingress Controller cluster</h2><p id="b428">Create TLS secret for traefik cluster. It’s used to access Consul.</p><div id="9f18"><pre>cd ca kubectl -n kube-system create secret generic traefik-consul
<span class="hljs-meta prompt_">></span> <span class="language-javascript"> --<span class="hljs-keyword">from</span>-file=ca.<span class="hljs-property">pem</span> </span>
<span class="hljs-meta prompt_">></span> <span class="language-javascript"> --<span class="hljs-keyword">from</span>-file=traefik.<span class="hljs-property">pem</span> </span>
<span class="hljs-meta prompt_">></span> <span class="language-javascript"> --<span class="hljs-keyword">from</span>-file=traefik-key.<span class="hljs-property">pem</span></span>
secret/traefik-consul created</pre></div><p id="531d">Create traefik dashboard secret.</p><div id="ef15"><pre>kubectl -n kube-<span class="hljs-keyword">system</span> create secret <span class="hljs-keyword">generic</span> kubesecret --<span class="hljs-keyword">from</span>-file auth</pre></div><p id="4e65">File ‘auth’ is created from this command. The username/password will be used to access the traefik dashboard</p><div id="ced9"><pre> htpasswd -c ./auth <span class="hljs-tag"><username></span>
New password:
Re-<span class="hljs-keyword">type</span> new password:
Adding password for <span class="hljs-keyword">user</span> <span class="hljs-title">testaaa</span></pre></div><p id="3693">Now deploy it.</p><p id="47e7">The example traefik_kv.yaml will deploy to master nodes. If this is not desired, adjust the “nodeAffinity” part.</p><div id="d7cd"><pre>DOMAIN=example.com envsubst < traefik_kv.yaml | <span class="hljs-type">kubectl</span> <span class="hljs-built_in">apply</span> -f -</pre></div><p id="ff41">There are 3 pods for traefik-ingress-controller.</p><div id="e19a"><pre> kubectl <span class="hljs-operator">-</span>n kube<span class="hljs-operator">-</span><span class="hljs-keyword">system</span> <span class="hljs-keyword">get</span> pod <span class="hljs-operator">-</span>o wide
traefik<span class="hljs-operator">-</span>ingress<span class="hljs-operator">-</span>controller<span class="hljs-number">-5</span>dlbz <span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">1</span> <span class="hljs-keyword">Running</span> <span class="hljs-number">0</span> <span class="hljs-number">5</span>m21s <span class="hljs-number">10.0</span><span class="hljs-number">.142</span><span class="hljs-number">.69</span> master3
traefik<span class="hljs-operator">-</span>ingress<span class="hljs-operator">-</span>controller<span class="hljs-number">-9</span>nxqt <span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">1</span> <span class="hljs-keyword">Running</span> <span class="hljs-number">0</span> <span class="hljs-number">6</span>m34s <span class="hljs-number">10.0</span><span class="hljs-number">.123</span><span class="hljs-number">.196</span> master2
traefik<span class="hljs-operator">-</span>ingress<span class="hljs-operator">-</span>controller<span class="hljs-operator">-</span>xzkzd <span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">1</span> <span class="hljs-keyword">Running</span> <span class="hljs-number">0</span> <span class="hljs-number">5</span>m34s <span class="hljs-number">10.0</span><span class="hljs-number">.255</span><span class="hljs-number">.14</span> master1 </pre></div><p id="6368">Add labels to the nodes which has Ingress Controller deployed, as I will use the label to handle the cluster reboot sequence. Refer to my article “How to reboot highly available Kubernetes Cluster” (<a href="https://readmedium.com/how-to-reboot-highly-available-kubernetes-cluster-5a9df4daecf">link</a>).</p><div id="6933"><pre><span class="hljs-comment"># for all nodes that has Ingress Controller</span>
kubectl label nodes master1 <span class="hljs-keyword">node</span><span class="hljs-title">-role</span>.kubernetes.io/<span class="hljs-attr">ingress-controller=</span></pre></div><div id="8e0d"><pre> kubectl get nodes
NAME STATUS ROLES AGE <span class="hljs-keyword">VERSION</span>
master1 Ready ingress-controller,<span class="hljs-keyword">master</span> <span class="hljs-title">49d</span> v1.<span class="hljs-number">14.1</span>
master2 Ready ingress-controller,<span class="hljs-keyword">master</span> <span class="hljs-title">49d</span> v1.<span class="hljs-number">14.1</span>
master3 Ready ingress-controller,<span class="hljs-keyword">master</span> <span class="hljs-title">49d</span> v1.<span class="hljs-number">14.1</span>
worker1 Ready <span class="hljs-tag"><none></span> <span class="hljs-number">49</span>d v1.<span class="hljs-number">14.1</span>
worker2 Ready <span class="hljs-tag"><none></span> <span class="hljs-number">48</span>d v1.<span class="hljs-number">14.1</span>
worker3 Ready <span class="hljs-tag"><none></span> <span class="hljs-number">48</span>d v1.<span class="hljs-number">14.1</span></pre></div><h2 id="52ea">Add Haproxy rules</h2><p id="a016">When the traefik cluster is ready, add haproxy rules to both primary and backup haproxy hosts. Basically, forward port 80 and 443.</p>
<figure id="7fc6">
<div>
<div>
<iframe class="gist-iframe" src="/gist/liejuntao001/651490c9033b0980a9ff778fa117d372.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><p id="6ac9">As the DNS for the domain point to the haproxy, now the traefik dashboard h<a href="https://traefik.example.com/">ttps://traefik.k8s.example.com/</a> is accessible, with the username/password created above.</p><h2 id="c67b">Export acme from consul</h2><p id="a690">I’d like to check/backup the Let’sEncrypt certificates that the Traefik cluster has got for the services. I couldn’t find clear instructions and below is my steps after some tries.</p><div id="17e1"><pre><span class="hljs-comment"># Connect to consul</span>
<span class="hljs-attribute">kubectl</span> -n consul port-forward consul-<span class="hljs-number">0</span> <span class="hljs-number">8500</span>:<span class="hljs-number">8500</span> &</pre></div><div id="c76b"><pre><span class="hljs-comment"># Keep the consul connection open</span>
<span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>; <span class="hljs-keyword">do</span> consul members && <span class="hljs-built_in">sleep</span> 10; <span class="hljs-keyword">done</span></pre></div><div id="a4e2"><pre><span class="hljs-comment"># retrieve compressed acme object</span>
consul kv <span class="hljs-built_in">get</span> traefik/acme/account/object > acme.gz</pre></div><div id="92ee"><pre><span class="hljs-meta"># gunzip</span>
cat acme.gz <span class="hljs-string">| gunzip > acme.json</span></pre></div><div id="65c0"><pre># <span class="hljs-keyword">Format</span>
cat acme.json | jq <span class="hljs-string">'.'</span> > acme.json.formatted</pre></div><h2 id="a69e">Backup/Restore consul</h2><p id="d12f">I hit a case that I want to change the Persistent volumes for the consul cluster. So I need destroy the consul cluster and recreate it. Obviously I don’t want to lose the existing KV values. I found it is pretty easy with the consul snapshot backup/restore.</p><ol><li>Create a snapshot as backup</li><li>Destroy the consul statefulsets and pvc</li><li>Re-create with new consul configs</li><li>Restore from snapshot</li></ol><div id="80be"><pre><span class="hljs-meta"># backup</span>
consul snapshot <span class="hljs-keyword">save</span> backup.snap</pre></div><div id="85c8"><pre># <span class="hljs-built_in">restore</span>
consul snapshot <span class="hljs-built_in">restore</span> backup.snap</pre></div><p id="30b3">Thanks for reading.</p></article></body>
Traefik cluster as Ingress Controller for Kubernetes
Traefik cluster as Ingress Controller for Kubernetes
Introduction
Ingress Controller is the portal to the services running on Kubernetes cluster. To get a highly available cluster, there should be multiple Ingress Controllers working together as a cluster.
Traefik is one of the Ingress Controllers. I use it for its dynamic configuration and automatic LetsEncrypt certificates. There are many instructions to deploy a single Traefik Ingress Controller but not so much details for a Traefik cluster as Ingress Controller. The official document is quite brief, so I’d like to share my experience in this article.
A working HA Kubernetes cluster has at least 3 master nodes and some workers. I have shared my experience here. By adding Traefik cluster, the architecture of the cluster is like below diagram.
Here I deploy Ingress Controllers on the master nodes, which I think is suitable for a low traffic cluster. More instances could be deployed to worker nodes, if the cluster need serve high traffic.
Architecture
Updated 1/9/2020
Traefik uses Consul Cluster as storage back end. To make it secure/stable, I shared my recent experience about running Consul in Kubernetes for production in this article.
As Consul need persistent volume, adjust storageClassName in consul/consul_statefulset.yml properly.
If the cluster has less than 3 worker nodes, remove the “podAntiAffinity” from consul/consul_statefulset.yml. However to get highly available Consul cluster, it’s better to have 3 or 5 replicas running on different nodes.
# forward consul to localhost$ kubectl -n consul port-forward consul-08500:8500 &
# magic time
$ traefik storeconfig --consul --consul.endpoint=localhost:8500 --file.filename=./traefik.toml
...
Writing config to KV
If properly imported, check the values in Consul K/V store
K/V store after import
After above importing steps, a manual change for the value of key traefik/consul/endpoint is needed. As shown in below screenshot, to ‘https://consul.consul.svc.cluster.local:8443’, which is the URL to the consul service.
manually modify this valule
If there are existing Let’sEncrypt certificates in a file acme.json, simply un-comment the line
#storageFile = "./acme.json"
from file traefik.toml and do the import. It will also get imported into Consul.
Then delete the key traefik/acme/account/lock, to allow the Traefik Ingress pods get the lock.
Deploy Traefik Ingress Controller cluster
Create TLS secret for traefik cluster. It’s used to access Consul.
$ cd ca
$ kubectl -n kube-system create secret generic traefik-consul \
> --from-file=ca.pem \> --from-file=traefik.pem \> --from-file=traefik-key.pem
secret/traefik-consul created
Add labels to the nodes which has Ingress Controller deployed, as I will use the label to handle the cluster reboot sequence. Refer to my article “How to reboot highly available Kubernetes Cluster” (link).
# for all nodes that has Ingress Controller
$ kubectl label nodes master1 node-role.kubernetes.io/ingress-controller=
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready ingress-controller,master49d v1.14.1
master2 Ready ingress-controller,master49d v1.14.1
master3 Ready ingress-controller,master49d v1.14.1
worker1 Ready <none>49d v1.14.1
worker2 Ready <none>48d v1.14.1
worker3 Ready <none>48d v1.14.1
Add Haproxy rules
When the traefik cluster is ready, add haproxy rules to both primary and backup haproxy hosts. Basically, forward port 80 and 443.
As the DNS for the domain point to the haproxy, now the traefik dashboard https://traefik.k8s.example.com/ is accessible, with the username/password created above.
Export acme from consul
I’d like to check/backup the Let’sEncrypt certificates that the Traefik cluster has got for the services. I couldn’t find clear instructions and below is my steps after some tries.
# Connect to consulkubectl -n consul port-forward consul-08500:8500 &
# Keep the consul connection openwhiletrue; do consul members && sleep 10; done
# retrieve compressed acme object
consul kv get traefik/acme/account/object > acme.gz
# gunzip
cat acme.gz | gunzip > acme.json
# Format
cat acme.json | jq '.' > acme.json.formatted
Backup/Restore consul
I hit a case that I want to change the Persistent volumes for the consul cluster. So I need destroy the consul cluster and recreate it. Obviously I don’t want to lose the existing KV values. I found it is pretty easy with the consul snapshot backup/restore.