Kubernetes Cluster mit Rancher RKE - Containerized
In unserem ersten Blogpost zu dem Thema Rancher Kubernetes Engine hatten wir bereits - wie immer :) - zahlreiche Verbesserungsideen.
Einige von diesen Ideen haben wir umgesetzt und wollen Euch hier zeigen, welche Ergebnisse wir erzielt haben.
Die erste Version
Zur Erinnerung: Es geht um die automatische Provisionierung eines Kubernetes-Clusters mit der Rancher Kubernetes Engine (RKE), Terraform und (natürlich!) Docker CE.
In der ersten Version haben wir die benötigten Ressourcen per Terraform in der Digital Ocean Cloud angelegt, mit einem Script die Config-Datei für RKE erstellt, und danach die Installation von RKE gestartet.
Dazu waren aber immer noch einige Vorbereitungen oder Zwischenschritte nötig, die wir aber mit Tool-Container eleganter abbilden wollten. Z.B waren das
- Installation von Terraform auf dem lokalen Rechner
- Installation von RKE zum Erzeugen des Kubernetes-Clusters
- Installation von kubectl, um sich den entstandenen Kubernetes-Cluster anzuschauen
- Manuelles erstellen und übertragen des SSH-Keys zum Zugriff auf die Digital Ocean Droplets
- Erzeuge der Cluster-Konfiguration per Python-Script
Der neue Ansatz
Die verschiedenen Werkzeuge wollten wir lieber in Tool-Docker-Container bereitstellen. So bleibt das lokale System von einer umfangreichen Tool-Installation verschont, die zahlreichen anderen Vorteile von Container möchte ich diesmal nicht wieder aufzählen :)
Dazu brauchen wir einfach je Tool einen Container:
- Terraform
- RKE
- kubectl
Die ersten beiden bauen wir selbst, für kubectl hatten wir der Einfachheit halber auf einen fertigen Container zurückgegriffen.
Terraform kann ja ein bisschen mehr als nur ein paar Droplets erzeugen. Für uns sollte Terraform daher auch
- den generierten SSH-Key für Digital Ocean bereitstellen
- mit Hilfe von Templates direkt die fertige Konfigurationsdatei (
cluster.yml
) für RKE erstellen, denn dort müssen ja primär die IP-Adressen der Droplets sowie der Pfad zum SSH-Key eingetragen werden.
Die Umsetzung
Container bauen
Zur Vereinfachung haben wir ein Makefile hinterlegt, so dass die Images einfach gebaut werden können:
make build
baut also das Terraform-Image aus dem zugehörigen Dockerfile, make build-rke
macht das gleiche für RKE.
Hier exemplarisch mal die Version für RKE:
FROM alpine:3.7
# Maintainer
LABEL maintainer="maintainers@bee42.com"
# Environment variables
ARG RKE_VERSION="v0.1.2"
# RKE-Installation
RUN apk --no-cache add wget ca-certificates git bash openssh-client && \
wget -O /usr/local/bin/rke https://github.com/rancher/rke/releases/download/${RKE_VERSION}/rke_linux-amd64 && \
chmod +x /usr/local/bin/rke && \
apk del --purge wget && \
rm -rf /var/cache/apk/*
ENV RKE_USER=rke \
RKE_UID=1000 \
RKE_GID=1000 \
RKE_HOME=/rke
RUN addgroup -S $RKE_USER -g ${RKE_GID} \
&& adduser -S \
-g $RKE_USER \
-h $RKE_HOME \
-u ${RKE_UID} \
$RKE_USER
USER $RKE_USER
WORKDIR $RKE_HOME
Wir Ihr seht, braucht Ihr für eine andere RKE-Version nur die Versionsnummer anzupassen und neu zu bauen. Getestet haben wir das ganze mit der zur Zeit aktuellen Version v0.1.2
.
Das allmächtige Terraform…
Was vielleicht nicht alle wissen: Terraform besitzt einen spannenden Templating-Provider. Mit dessen Hilfe gelingt auch die Erzeugung der cluster.yml-Datei.
Als Besonderheit haben wir noch eingebaut, dass die Anzahl der ControlePlanes und Worker konfigurierbar ist.
variables.tf:
variable "worker_count" {
description="Describes the amount of worker for the clusters"
default=2
}
Für die Worker gibt es zunächst ein eigenes Template, in das die IP-Adressen eingebaut werden
template/worker.tpl
- address: ${worker_address}
internal_address: ""
role:
- worker
hostname_override: ""
user: root
docker_socket: /var/run/docker.sock
ssh_key: ""
ssh_key_path: ""
So werden jetzt die IP-Adressen injiziert:
template.tf
data "template_file" "worker" {
template = "${file("${path.module}/template/worker.tpl")}"
count= "${var.worker_count}"
vars {
worker_address = "${element(digitalocean_droplet.worker.*.ipv4_address,count.index)}"
}
}
Damit ist der Teil für die Worker fertig, diesen könnte man jetzt einfach ausgeben. Oder - und das machen wir im Folgenden - als Eingabe für ein weiteres Template verwenden:
template/cluster.tpl
nodes:
${controlplane}
${worker}
services:
etcd:
image: quay.io/coreos/etcd:latest
extra_args: {}
#…
template.tf
data "template_file" "cluster" {
template = "${file("${path.module}/template/cluster.tpl")}"
vars {
controlplane = "${join("\n",data.template_file.controlplane.*.rendered)}"
worker = "${join("\n",data.template_file.worker.*.rendered)}"
ssh_key_path ="${var.ssh_cluster_private_key}"
}
}
So kann also in einem Arbeitsgang nicht nur die eigentliche Infrastruktur durch Terraform erstellt werden, sondern auch gleich die fertige cluster.yml
mit beliebig vielen ControlPlanes und Workern generiert werden!
SSH-Key und die Datei cluster.yml
werden danach extrahiert und dem RKE-Container übergeben.
Das Ergebnis
Mit wenigen Befehlen und viel Technologie lässt sich so ein Kubernetes-Cluster einfach provisionieren.
Nachdem die Images gebaut sind, müssen sie nur noch gestartet werden, und schon ist der K8s-Cluster verfügbar.
Hier unser kleines Script dazu, dass den Digital Ocean-Token als Parameter benötigt:
start.sh
docker run -it --rm -v tf:/tf --env DO_TOKEN=$1 bee42/terraform apply
docker run -it --rm -v tf:/tf --env DO_TOKEN=$1 bee42/terraform output cluster_template > cluster.yml
docker run -it --rm -v tf:/tf --env DO_TOKEN=$1 bee42/terraform output ssh_private_key > private_key
docker run -it --rm -v $(pwd):/rke -v $(pwd) /private_key:/tf/.ssh/cluster_ed25519 bee42/rke rke up --config cluster.yml
docker run -v $(pwd)/.kube_config_cluster.yml:/root/.kube/config ceroic/kubectl kubectl get nodes
Fazit
Im Unterschied zur ersten Lösung haben wir jetzt wieder einige weitere Ziele erreicht: Die Containerisierung, das Entfallen einiger Zwischenschritte und nebenbei auch ein etwas tieferer Einstieg in die Terraform-Templating-Engine!
Wenn Ihr Euch das genauer ansehen wollt: Auf Github steht alles bereit!