Kubernetes Nginx Ingress Controller – So gelingt Dein einfacher Start!

This entry is part 4 of 5 in the series Kubernetes - so startest Du durch!

Kubernetes LogoMit den ersten Schritten mit Kubernetes weißt Du bereits, wie Du Anwendungen in Deinem Kubernetes Cluster startest. Nun exponieren wir Deine Anwendung online. Wie das Ganze funktioniert und wie Du mit einem Kubernetes Nginx Ingress Controller am besten selbst direkt loslegen kannst, erläutere ich Dir im Folgenden an einem Beispiel.

Um in einem Kubernetes Cluster Anwendungen von außen erreichbar zu machen, kann man einen Service vom Typ Loadbalancer verwenden. In der NETWAYS Cloud starten wir hier im Hintergrund ein Openstack Octavia LB mit öffentlicher IP und leiten den eingehenden Traffic an die Pods weiter (Bingo). Somit benötigen wir für jede Anwendung einen eigenen Loadbalancer mit öffentlicher IP. Um in einem Fall wie diesem etwas ressourcen- und somit kosteneffizienter arbeiten zu können, hat man vor Langem named-based virtual hosts und server name indication (sni) erfunden. Der altbekannte NGINX-Webserver unterstützt beides und als Kubernetes Ingress Controller kann dieser, mit nur einer öffentlichen IP-Adresse, all unsere http/s-Anwendungen schnell und einfach erreichbar machen.

Die Installation und die Aktualisierung des Ningx Ingress Controllers ist dank eines Helm Charts sehr vereinfacht. Mit K8s Ingress Objekten konfiguriert man die Zuordnung von vHosts, URI-Pfaden und TLS-Zertifikaten zu K8s Services und somit zu unseren Anwendungen. Damit die Buzzwords Dir nicht den Blick aufs Wesentliche verhindern, hier ein kleiner Überblick, wie die HTTP-Anfragen an unsere Anwendungen weitergeleitet werden:

 

Installation Kubernetes Nginx Ingress Controller

Helm Logo

Zur einfachen Installation des Kubernetes Nginx Ingress Controllers solltest Du Helm verwenden. Helm bezeichnet sich selbst als Paketmanager für Kubernetes-Anwendungen. Neben der Installation bietet Helm auch einfache Updates seiner Anwendungen. Wie auch bei kubectl brauchst Du nur die K8s-Config, um direkt loszulegen:

$ helm install my-ingress stable/nginx-ingress

 

 

Mit diesem Befehl startet Helm alle nötigen Komponenten im default Namespace und gibt diesen das Label my-ingress. Für den Nginx Ingress Controller wird ein deployment, ein replicaset und ein pod erstellt. Alle http/s-Anfragen müssen an diesen pod weitergeleitet werden, damit dieser anhand von vHosts und URI-Pfaden die Anfragen sortieren kann. Dafür wurde ein service vom Typ loadbalancer erstellt, welcher auf eine öffentliche IP lauscht und den ankommenden Traffic auf den Ports 443 und 80 an unseren pod weiterleitet. Ein ähnliches Konstrukt wird auch für das default-backend angelegt, auf welche ich hier aber nicht näher eingehe. Damit Du den Überblick nicht verlierst, kannst Du Dir alle beteiligten Komponenten mit kubectl anzeigen lassen:

$ kubectl get all -l release=my-ingress  #mit default-backend

$ kubectl get all -l release=my-ingress -l component=controller #ohne default-backend

NAME                                                             READY    STATUS      RESTARTS
pod/my-ingress-nginx-ingress-controller-5b649cbcd8-6hgz6         1/1      Running     0       

NAME                                                             READY    UP-TO-DATE  AVAILABLE
deployment.apps/my-ingress-nginx-ingress-controller              1/1      1           1        

NAME                                                             DESIRED  CURRENT     READY
replicaset.apps/my-ingress-nginx-ingress-controller-5b649cbcd8   1        1           1    

NAME                                              TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)
service/my-ingress-nginx-ingress-controller       LoadBalancer   10.254.252.54    185.233.188.56   80:32110/TCP,443:31428/TCP

 

Beispielanwendungen: Apache und Nginx

Als nächstes starten wir zwei einfache Beispielanwendungen. Im Beispiel verwende ich Apache und Nginx. Ziel ist es, beide Anwendungen unter eigenen name-based virtual hosts verfügbar zu machen: nginx.nws.netways.de und apache.nws.netways.de. Damit die beiden Deployments innerhalb des K8s Clusters erreichbar sind, müssen wir diese noch jeweils mit einem Service verbinden.

K8s Deployments

Nginx Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Apache Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache-deployment
  labels:
    app: apache
spec:
  replicas: 3
  selector:
    matchLabels:
      app: apache
  template:
    metadata:
      labels:
        app: apache
    spec:
      containers:
      - name: apache
        image: httpd:2.4
        ports:
        - containerPort: 80

K8s Service

Nginx Service

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    app: nginx
Apache Service

apiVersion: v1
kind: Service
metadata:
  name: apache-svc
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    app: apache

 

Virtual Hosts ohne TLS

Um nun die Anfragen vom Nginx Controller zu unseren Anwendungen weiterzureichen, müssen wir ein passendes Kubernetes Ingress Objekt ausrollen. Im spec Bereich des Ingress Objekts können wir unterschiedliche Pfade und virtuell Hosts definieren. Im Beispiel sehen wir vHosts für nginx.nws.netways.de und apache.nws.netways.de. Für jeden der beiden vHosts ist im Bereich backend natürlich der entsprechende service eingetragen.

Die öffentliche IP findet man im service des Nginx Ingress Controllers und kubectl describe zeigt alle wichtigen Details zum Service (siehe unten). Zum Testen manipulierst Du am besten seine /etc/hosts Datei und trägst dort die IP von LoadBalancer Ingress ein.

K8s Ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: apache.nws.netways.de
    http:
      paths:
        - backend:
            serviceName: apache-svc
            servicePort: 80
  - host: nginx.nws.netways.de
    http:
      paths:
        - backend:
            serviceName: nginx-svc
            servicePort: 80

$ kubectl describe service/my-ingress-nginx-ingress-controller

$ kubectl get service/my-ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[].ip}’

 

Virtual Hosts mit TLS

Natürlich bietet man selten Anwendungen ohne Verschlüsselung öffentlich erreichbar an. Speziell für TLS-Zertifikate hat Kubernetes einen eigenen Typ tls innerhalb des secret Objekts. Alles was man benötigt ist ein TLS-Zertifikat und den dazugehörigen Schlüssel. Mit kubectl kannst Du das Pärchen in Kubernetes speichern:

$ kubectl create secret tls my-secret –key cert.key –cert cert.crt

Das angelegte secret kann dann durch den angegebenen Namen my-secret in spec des Ingress Objekts referenziert werden. Dazu gibst Du im Array hosts innerhalb von tls unser virtual host und das dazugehörige TLS-Zertifikat an. Ein automatischer Redirect von http auf https ist von Anfang an aktiviert.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  tls:
    - hosts:
      - apache.nws.netways.de
      - nginx.nws.netways.de
      secretName: my-secret
  rules:
  - host: apache.nws.netways.de
    http:
      paths:
        - backend:
            serviceName: apache-svc
            servicePort: 80
  - host: nginx.nws.netways.de
    http:
      paths:
        - backend:
            serviceName: nginx-svc
            servicePort: 80

Fazit

Mit dem Nginx Ingress Controller ist es eine Leichtigkeit, Deine webbasierten Anwendungen öffentlich erreichbar zu machen. Die angebotenen Features und Konfigurationsmöglichkeiten sollten die Anforderungen aller Anwendungen abdecken und sind im offiziellen User Guide zu finden. Neben der eigenen Anwendung benötigst Du nur ein Helm Chart und ein K8s Ingress-Objekt. Kubernetes schafft es auch hier, mit nur wenigen abstrakten Objekten wie deployment und ingress viele komplexe Ebenen und Technologien zu verstecken. Mit einer NETWAYS Managed Kubernetes Lösung kannst Du die Vorteile dieser Abstraktion voll ausnutzen und Dich auf die eigene Anwendung konzentrieren. Na also: Leg los!

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Erste Schritte mit Kubernetes

This entry is part 3 of 5 in the series Kubernetes - so startest Du durch!

Du hast ein brand neues Kubernetes Cluster und willst jetzt loslegen? Aber egal, ob bei Dir ein lokales minikube läuft oder ob Du ein Managed Kubernetes mit allen Schikanen hast, die ersten Kubernetes-Objekte im super einfachem YAML-Format lassen fast jeden erstmal die Stirn runzeln. Was sind eigentlich deployments, services und Co? Und wozu die ganzen Labels? Versuchen wir Licht ins Dunkle zu bekommen.

Die wichtigsten Kubernetes-Objekte

Hierarchie von Deployment Replicaset und PodZum Verwalten und Steuern eins Kubernetes Clusters verwendet man Kubernetes-API-Objekte, in welchen man den gewünschten Zustand des Clusters beschreibt. Diese werden im einfachen YAML-Format mit Hilfe von kubectl an das Cluster gesendet. Neben einer API-Version, Metadaten und der Objektart gibt es meistens noch den Abschnitt spec. In diesem beschreibt man den gewünschten Zustand seiner Anwendung. spec kann für jedes Objekt unterschiedlich definiert sein und ist in vielen Fällen verschachtelt. Zum Beispiel enthält ein Objekt deployment Attribute für ein Objekt replicaSet, welches wiederum im eigenen spec Abschnitt Attribute für ein pod Objekt hat. Aber bevor es zu kompliziert wird, erstmal eine kurze Erklärung dieser drei wichtigen Objekte:

deployment

Ein deployment beschreibt einen gewünschten Zustand einer Anwendung und versucht, beständig diesen herzustellen. Mit deployments lassen sich Anwendungen starten, skalieren, aktualisieren, zurückrollen und löschen. In der Regel verwendet man deployment Objekte, um Anwendungen zu verwalten.

replicaSet

Ein replicaSet gewährleistet die Verfügbarkeit einer definierten Anzahl identischer Pods. Gegebenenfalls werden neue Pods gestartet und auch gestoppt. replicaSet verwendet man im Normalfall nur indirekt durch ein deployment.

pod

Ein pod definiert eine Gruppe von Containern (oftmals nur einer), die sich einen gemeinsamen Namespace auf einen Host teilen. Durch die gemeinsamen Namespaces (z.B. gemeinsames Dateisystem oder Netzwerk) ist eine einfache Kommunikation der Container erleichtert. Ein Pod ist immer durch eine eindeutige IP im Cluster erreichbar. Im Normalfall verwendet man Pods nur indirekt durch ein deployment.

Mit diesen drei Objekten können wir unser erstes MariaDB Deployment starten und eine erste Verbindung damit herstellen.

Das erste K8s-Deployment

Als erste einfache Anwendung starten wir eine nicht replizierte MariaDB als deployment. Bevor wir aber einen genauen Blick auf die Definition werfen, sende doch das Objekt mit kubectl apply an Dein Cluster:

Speichere einfach die mariadb.yaml auf Deinem Rechner und sende diese mit apply an Dein Cluster:

$ kubectl apply -f mariadb.yaml deployment.apps/mariadb-deploy created

Du hast noch kein kubectl? Erfahre, wie man kubctl installiert (klick) und speichere deine kubeconfig in ~/.kube/config

 

Für Änderungen an Deinem deployment kannst Du die Yaml-Datei einfach anpassen und mit dem gleichen Befehl an Dein Cluster senden. Willst Du Dein deployment wieder löschen, ersetzt Du das apply einfach durch ein delete.

mariadb.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb-deploy
  labels:
    app: mariadb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      containers:
        - name: mariadb
          image: mariadb
          ports:
            - containerPort: 3306
              name: db-port
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "123456"
Erklärung:

Bei einem genaueren Blick finden wir im Beispiel Parameter für alle drei Kubernetes-Objekte.

Zeile 1-6: Wir definieren API-Version, kind, Name und ein frei wählbares Label für unser deployment Objekt.

Zeile 8-11: Sind Teil des replicaset (RS). Hier wird neben der Anzahl der replicas auch matchLabels definiert und es werden pods mit dem Label mariadb in das RS mit aufgenommen.

Zeile 13-25: Definieren Deinen Pod. Neben einem Label werden Parameter für den MariaDB Container übergeben. Wir verwenden das offizielle MariaDB Image, definieren den Port 3306 und setzen über eine Environment-Variable das root-Passwort für die Datenbank.

Besserer Überblick mit describe und get

Mit describe und get kannst Du Dir einen schnellen Überblick verschaffen und alle nötigen Details Deiner Anwendungen bekommen. Ein einfaches kubectl describe deployment/mariadb-deploy liefert alle Details zum MariaDB Deployment aus dem Beispiel.
get all hingegen listet alle Objekte auf, aber die Ausgabe kann auch schon mit wenigen Anwendungen im Cluster schnell unübersichtlich werden. Deshalb gibt es verschiedene Möglichkeiten zum Filtern der Ausgabe, z.B. anhand des Labels app. Mit folgenden Beispielen hast Du die Ausgabe aber schnell im Griff.

Beispiel für get mit verschiedenen Filtern

$ kubectl get pods
$ kubectl get deployment
$ kubectl get replicaset -l app=mariadb -o json
$ kubectl get po –field-selector=status.phase=Running

Die Komponenten Deiner MariaDB kannst Du am schnellsten mit dem Label Filter anzeigen:

kubectl get all -l app=mariadb


NAME READY STATUS RESTARTS AGE
pod/mariadb-deploy-64bfc599f7-j9twt 1/1 Running 0 64s

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/mariadb-deploy 1/1 1 1 64s

NAME DESIRED CURRENT READY AGE
replicaset.apps/mariadb-deploy-64bfc599f7 1 1 1 64s

Nachdem Du jetzt weißt, wie Du den aktuellen und gewünschten Zustand Deiner Anwendung überprüfst, werfen wir nun einen genaueren Blick auf Pods und Container.

Mit Pods interagieren

Ohne weitere Konfiguration sind Anwendungen nur innerhalb des Kubernetes-Clusters erreichbar. Zudem will man selten eine Datenbank über eine öffentliche IP erreichbar machen. kubectl bietet deswegen mit proxy und port-forward zwei Möglichkeiten, um Zugriffe auf interne Pods und Services zu gewährleisten. Für MariaDB benutzen wir port-forward und senden sämtlichen Traffic der lokal auf Port 3306 ankommt durch kubectl an unseren MariaDB Pod. Du kannst übrigens direkt den Namen des deployments verwenden. Die Namen von pod und replicaSet führen aber zum selben Ergebnis. Mit telnet oder einem MySQL Client prüfst Du am schnellsten, ob die Verbindung funktioniert:

kubectl port-forward deployment.apps/mariadb-deploy 3306:3306

mysql -h 127.0.0.1 -P 3306 -u root -p123456

telnet 127.0.0.1 3306

Weitere Möglichkeiten, um mit seinem Container zu interagieren, bietet kubectl mit log und exec. Ersteres zeigt Dir natürlich stdout Deines Pods. exec hingegen wird wohl meistens zum Starten einer interaktiven Shell genutzt. Ähnlich wie bei docker benötigt man die Parameter interactive und tty (-ti), um eine funktionsfähige Bash zu erhalten:

$ kubectl exec -it mariadb-deploy-64bfc599f7-j9twt — /bin/bash

Mit diesen wenigen Befehlen kannst Du Deine im K8s-Cluster abgeschirmten Pods erreichen und debuggen. Anwendungen, die nur innerhalb des Clusters erreichbar sind, machen natürlich nicht immer Sinn. Damit auch andere darauf zugreifen können, benötigst du einen Kubernetes service mit öffentlicher IP. Hinter einem service steckt aber noch viel mehr.

Verbinde deine Pods mit einem service

Ein service bindet eine feste interne IP-Adresse (ClusterIP) an eine Menge von Pods, welche durch Labels identifiziert werden. Im Vergleich zu einem service sind pods sehr kurzlebig. Sobald wir im Beispiel ein Upgrade der MariaDB anstoßen, verwirft unser deployment den vorhanden Pod und startet einen neuen. Da jeder Pod seine eigenen IP-Adresse hat, ändert sich auch die IP-Adresse, unter welcher deine MariaDB erreichbar ist. Dank der Labels findet der service den neuen Pod und der Traffic wird richtig weitergeleitet.
Ein service gewährleistet somit durch die ClusterIP die interne Erreichbarkeit deiner deployments. Zusätzlich kann ein service auch den Typ Loadbalancer haben. Dadurch wird eine öffentliche IP gebunden und sämtlicher Traffic an die ClusterIP weitergegeben. Im folgenden Beispiel siehst siehst Du einen service für deine MariaDB.

Neben API-Version, kind und metadata gibt es wieder den Abschnitt spec. Protocol, port und targetPort definieren, welcher Traffic weitergereicht wird. Im selector wird anhand der Labels festgelegt, welche Pods bedient werden sollen. Mit der optionalen Zeile type: LoadBalancer wird neben einer internen ClusterIP auch eine öffentliche IP gebunden.
apiVersion: v1
kind: Service
metadata:
  name: mariadb-service
spec:
  ports:
  - port: 3306
    targetPort: 3306
    protocol: TCP
    name: mariadb
  selector:
    app: mariadb
  type: LoadBalancer

Im Beispiel ist für einen Pod genau ein Container definiert und unser selector im Server greift auch nur für einen Pod. Was passiert aber, wenn replicas in der Deployment erhöht wird? Zuerst werden natürlich mehrere Pods gestartet und somit auch mehrere MariaDB-Container. Der selector im MariaDB Service findet diese natürlich anhand des Labels und die Verbindungen werden im round-robin Verfahren an die Pods weitergeleitet. Technisch funktioniert dies im Beispiel auch ohne Probleme, solang MariaDB selbst aber nicht als replizierendes Cluster installiert ist, macht dies aber wenig Sinn.

Was kommt als nächstes?

Mit den hier gezeigten Beispielen kann man seine ersten Anwendungen ausrollen und debuggen. Aber Du ahnst bereits, dass wir nur etwas am Lack von Kubernetes gekratzt haben und es stellen sich natürlich noch viele Fragen! Was passiert mit meinen Daten in MariaDB und wie kann ich die kurzlebigen Pods mit einem persistentem Volume verbinden? Brauche ich für jede Anwendung eine eigene öffentliche IP? Wie komme ich an Metriken und Logs meines Clusters und meiner Anwendungen? Diese und weitere Fragen werden wir natürlich in den folgenden Blogposts beantworten. Also dann, bis nächste Woche!

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

So startest Du Dein Managed Kubernetes bei NWS

This entry is part 2 of 5 in the series Kubernetes - so startest Du durch!

 

 

Dich interessiert, wie Du ein Managed Kubernetes bei NWS startest? Hier erfährst Du, wie du loslegen kannst! Zuerst benötigst Du einen Account für unsere NETWAYS Web Services Plattform. Nach der Registrierung kannst Du unsere Open Source-Apps wie RocketChat und GitLab starten und auch Zugänge zu Openstack und Kubernetes anlegen.

 

tl;dr – sehen statt lesen 

Christian zeigt Dir unser Managed Kubernetes übrigens im aufgezeichneten Webinar. Bilder sagen mehr als Tausend Worte 🤐

 

Du entscheidest Dich natürlich für einen Kubernetes-Zugang und kommst nach wenigen Klicks zur Ansicht zum Verwalten und Starten deiner Kubernetes Cluster.

 

Starte Dein Kubernetes Cluster

Das schwierigste beim Starten Deines Clusters ist wohl die Wahl des Namens. Das können wir Dir leider nicht abnehmen. Wie wäre es mit foobar? Aber bevor virtuelle Maschinen im Hintergrund starten, musst Du Dich jetzt noch für eine Control Plane entscheiden und die Anzahl deiner Worker Nodes festlegen.

Control Plane

Als Control Plane werden alle nötigen Dienste und Ressourcen zur Verwaltung und Steuerung deines Kubernetes Clusters bezeichnet. Diese Dienste können auf einem oder auf drei Master Nodes (VMs) gestartet werden. Letzteres hat den Vorteil, dass in einem Fehlerfall oder bei einem Update die Kubernetes-Dienste und -API trotzdem verfügbar sind. Zudem muss je nach Größe des geplanten Clusters ein Flavor für diese Master Nodes gewählt werden. Bitte beachte, dass Du die Anzahl der Master Nodes und den Flavor später nicht mehr ändern kannst.

Worker Nodes

Auf den Worker Nodes werden Deine Anwendungen gestartet, welche durch die Control Plane verwaltet und betrieben werden. Für eine hochverfügbare Anwendung benötigst Du davon mindestens zwei. Wie auch bei den Master Nodes musst Du ein Flavor auswählen. Aufgrund der auf Ressourcen basierenden Abrechnung fallen zum Beispiel für 16GB Ram immer die selben Kosten an, egal ob diese auf zwei oder vier VMs verteilt werden. Die Anzahl der Worker Nodes kannst Du jederzeit im NWS Webinterface an Deinen aktuellen Bedarf anpassen.

Das Starten des Clusters kann je nach Anzahl der Master- und Worker Nodes fünf bis 15 Minuten dauern. Es ist also genug Zeit für einen Kaffee. Im Hintergrund werden VMs, Floating IPs, Loadbalancer, Security Groups und vieles mehr Stück für Stück gestartet, konfiguriert und geprüft, bis Dein Kubernetes einsatzfähig ist. Und jetzt?

 

Verschaffe Dir einen Überblick im NWS Webinterface

Nachdem dein Cluster gestartet ist, gibt Dir das NWS Webinterface einen guten ersten Überblick. Dort findest Du wichtige Informationen und andere Möglichkeiten, um Dein Cluster zu steuern:

 

Zustand und Worker Nodes

Den Status Deiner Master- und Worker Nodes sowie die Erreichbarkeit der API kannst Du jederzeit im NWS Webinterface überprüfen. Solltest Du mehr Ressourcen benötigen, kannst Du die Anzahl Deiner Worker Nodes mit einigen wenigen Klicks anpassen und im Problemfall auch einen harten Neustart einzelner VMs durchführen.

Kubernetes Dashboard

Für einen einfacheren Einstieg haben wir bereits das Kubernetes Dashboard für Dich ausgerollt und vorbereitet. Ein einfacher Einblick gelingt in drei kleinen Schritten.

 

Object Store

Mit dem Start des Clusters bekommst Du auch einen Zugang zu unserem Object Store. Dieser basiert auf Ceph und ist mit der S3- und Swift-API kompatibel. Deine Daten werden über unsere ISO-27001 zertifizierten Rechenzentren repliziert und bleiben in Deutschland.

Cluster Update

Um Kubernetes Cluster-Updates für Dich so einfach wie möglich zu gestalten, werden diese von uns gründlich getestet. Aber damit Du die Kontrolle behältst, entscheidest Du per Knopfdruck, wann die Updates eingespielt werden. Neben den Kubernetes-Diensten wird auch das Betriebssystem der VMs aktualisiert. Im Falle einer hochverfügbaren Control Plane werden die Komponenten Stück für Stück aktualisiert, so dass kein Serviceausfall entsteht. Auch auf Deinen Worker Nodes werden die Anwendungen verschoben, so dass nach und nach einzelne VMs aktualisiert und neu gestartet werden können.

 

kubeconfig

Als kubeconfig bezeichnet man eine Datei, die alle Informationen enthält, um über das Kommando kubectl auf die Kubernetes-API zuzugreifen. Technisch enthält diese YAML-Datei den HTTP-Endpunkt der API, einen Benutzernamen und ein TLS-Client-Zertifikat mit CA. Im Webinterface kannst Du die Datei natürlich herunterladen und gleich unter $HOME/.kube/config speichern. Somit kannst Du ohne weitere Parameter Dein Cluster mit kubectl erkunden. Wie Du dies am schnellsten für Dein Betriebssystem installierst, erfährst du am besten aus der offiziellen Dokumentation.

 

Starte mit kubectl auf der Kommandozeile

Beim täglichen Arbeiten mit Kubernetes benötigst Du unser Webinterface leider nicht sehr oft. Die meiste Zeit wirst du auf der Kommandozeile verbringen. kubectl ist hier das zentrale Tool, um Deine Anwendungen im Cluster zu steuern. Zunächst solltest Du ein paar einfache Kommandos ausführen, um mit Deinem Cluster vertraut zu werden:

 

kubectl get nodes

Zeigt eine Liste deiner Nodes mit Status und Version.

kubectl describe node <Name>

Neben Labels, Pods und Metriken bekommst Du viele detaillierte Information zu Deinen Nodes.

 

kubectl explain <Ressourcentyp>

Mit explain kannst Du Dir schnell weitere Informationen zu einzelnen Ressourcentypen holen.

kubectl get all

Zeigt Dir eine Übersicht aller laufenden Ressourcen im default Namespace. Mit –all-namespaces siehst Du nicht nur Deine Anwendungen, sondern auch die Ressourcen des Kubernetes Clusters selbst.

 

Mit der kubeconfig und kubectl hast Du nun alles an der Hand, um zu starten. Mit was? Mit Teil 3 unserer Serie und deinen ersten Schritten in Kubernetes. Dort erfährst Du mehr über deployments, pods und services und wie Du Deine erste Anwendung ausrollst.

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Storage Wars – Using Ceph since Firefly | OSDC 2019

This entry is part 4 of 6 in the series OSDC 2019 | Recap

 

Achim Ledermüller ist Lead Senior Systems Engineer bei NETWAYS und kennt sich aus in Sachen Storage. 2019 hat er seinen Talk “Storage Wars – Using Ceph since Firefly” auf der Open Source Data Center Conference (OSDC) in Berlin gehalten. Wer den Talk verpasst hat, bekommt nun die Möglichkeit, Achims Vortrag noch einmal zu sehen und zu lesen (siehe weiter unten).

Die OSDC wird 2020 erstmalig unter neuem Namen stackconf veranstaltet. Mit den Veränderungen in der modernen IT hat sich in den vergangenen Jahren zunehmend auch der Fokus der Konferenz verlagert: Von einem hauptsächlich auf statische Infrastrukturen zielenden Ansatz zu einem breiteren Spektrum, das agile Methoden, Continuous Integration, Container-, Hybrid- und Cloud-Lösungen umfasst. Dieser Entwicklung soll mit der Namensänderung der Konferenz Rechnung getragen und das Themenfeld für weitere Innovationen geöffnet werden.

Aufgrund der Bedenken rund am das Coronavirus (COVID-19) wurde die Entscheidung getroffen, die stackconf 2020 als Online-Konferenz stattfinden zu lassen. Das Online-Event findet nun vom 16. bis 18. Juni 2020 statt. Live dabei sein lohnt sich! Jetzt Ticket sichern unter: stackconf.eu/ticket/


Storage Wars – Using Ceph since Firefly

Wenn es um Storage geht, ist die Erwartungshaltung klar definiert. Storage muss immer verfügbar, skalierbar, redundant, katastrophensicher, schnell und vor allem billig sein. Mit dem Unified Storage Ceph kann man zumindest die meisten Erwartungen ohne Abstriche erfüllen. Durch das Prinzip, wie Ceph Daten zerlegt, speichert und repliziert, ist die Verfügbarkeit, Skalierbarkeit und Redundanz gewährleistet und auch eine katastrophensichere Spiegelung eines Clusters ist ohne Probleme möglich.

Neben den angebotenen Features ist aber auch ein reibungsloser unterbrechungsfreier Betrieb wichtig. Während des fast siebenjährigen Betriebs unseres Clusters änderten sich fast alle Komponenten. Betriebsysteme, Kernel und Init-Systeme wurden ausgewechselt. Alte Netzwerkkarten wurden durch 10GE- und 40GE-Schnittstellen abgelöst und vervierzigfachten ihren Durchsatz. Layer 2 wird wegen Routing on the Host immer unwichtiger, Festplatten sind plötzlich dank moderner SSDs und NVMe nicht mehr das Bottleneck und natürlich gab es auch immer wieder neue Versionen von Ceph selbst. Zwischen all diesen Neuerungen in den letzten Jahren ist natürlich genügend Platz für kleine und große Katastrophen. Umso wichtiger ist es, dass man von Anfang an ein paar grundlegende Dinge richtig macht:

Limitiere IO-intensive Jobs

Im normalen Betrieb laufen verschiedene Aufgaben im Hintergrund, um einen gesunden Zustand des Clusters zu garantieren. Scrubbing Jobs prüfen die Integrität aller gespeicherten Daten einmal pro Woche, Platten- und andere Hardwarefehler veranlassen Ceph, die Anzahl der Replika automatisch wieder herzustellen und auch das Löschen von Snaphosts bringt die Festplatten zum Glühen. Für jedes dieser kleinen Probleme bietet Ceph Konfigurationsmöglichkeiten, um größere Auswirkungen auf Latenzen und Durchsatz der Clients zu verhindern.

Neben dem Datenmanagement durch Ceph selbst wird das Cluster natürlich auch von vielen Clients beansprucht. In unserem Fall wollen virtuelle Maschinen aus OpenStack und OpenNebula an ihre Daten, verschiedenste WebClients wie GitLab, Nextcloud, Glance und andere senden Swift- und S3-Anfragen und ein zentrales NFS-Storage will natürlich auch Tag und Nacht bedient werden. Auch hier kann eine Begrenzung der Requests durch libvirtd, rate-limiting oder andere Mechanismen sinnvoll sein.

Kenne deine Anforderungen

Die Anforderungen der Clients an die Latenz und den Durchsatz des Storage-Systems können sehr unterschiedlich sein. Features wie Replikation und Verfügbarkeit werden mit erhöhten Latenzen erkauft. Große Festplatten mit Spindeln drücken die Kosten, allerdings sind auch nur noch wenige Benutzer und Anwendungen mit wenigen IOPs, höheren Latenzen und dem geringen Durchsatz zufrieden. Was für Archivdaten kein Problem ist, sorgt bei Datenbanken oft für unglückliche Benutzer. Schnellere Festplatten und eine geringe Latenz im Netzwerk verbessern die Situation erheblich, erhöhen aber auch die Kosten. Zudem ändern sich die Bedürfnisse der Clients auch im Laufe der Zeit. Dank Crush kann Ceph den unterschiedlichen Ansprüchen gerecht werden. Ein schneller SSD-Pool kann ohne Probleme parallel zu einem Datengrab auf langsamen großen Spindeln betrieben werden und auch eine Umschichtung der Daten ist jederzeit flexibel möglich.

Plane im Voraus

Neben eines Datenverlusts ist ein volles Cluster wohl eines der schlimmeren Szenarios. Um eine Beschädigung der Daten zu verhindern, werden bei 95% Füllstand keine weiteren Daten mehr angenommen. In den meisten Fällen macht dies den Storage unbenutzbar. Zu diesem Zeitpunkt hat man eigentlich nur zwei Möglichkeiten: Man kann versuchen, nicht mehr benötigte Daten zu entfernen, z.B. in Form von alten, nicht mehr benötigten Snapshots, oder man vergrößert den Cluster rechtzeitig. Hierbei sollte man bedenken, dass die Beschaffung und der Einbau der Hardware schnell mal 7 bis 14 Tage in Anspruch nehmen kann. Genügend Zeit zum Handeln sichert man sich durch verschiedene Thresholds, so dass der Cluster z.B. ab einem Füllstand von 80% warnt.

Ceph kann die klaren Erwartungen an ein modernes Storage-System in den meisten Fällen erfüllen. Die gegebene Flexibilität und die ständige Weiterentwicklung sichert eine einfache Anpassung an neue Anforderungen und ein sich ständig änderndes Umfeld. Somit ist mit etwas Planung, Monitoring und Liebe ❤ ein reibungsloser und stressfreies Betreiben über viele Jahre möglich.

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Out-of-Memory: Marathon 1.6+ und Heap Size

Auch wenn in Sachen Container Orchestrierung Kubernetes klar gegen Marathon und Mesos gewonnen hat bietet das Duo seit Jahren eine zuverlässig Plattform. Durch die stetige Weiterentwicklung und die Umstellung auf Systemd ändert sich leider auch immer wieder die Konfigurationen der Dienste.

Für einen stabilen Betrieb von Marathon sollte die maximale Heap-Size der Java Virtual Machine (JVM) eine angemessene Größe haben. Zu wenig Memory äußert sich z.B. durch erhöhte Antwortzeiten oder durch die Aktivierung des OOM-Killer. Wo in vergangenen Versionen und Konfigurationen noch die /etc/defaults/marathon zum Setzen der Javaoption verwendet wurde, kann man hier seit Marathon 1.6 vergeblich sein Glück suchen. Aus meiner Sicht ist ein Verzicht auf /etc/defaults/marathon und eine saubere Definition in einer systemd Unit-Datei natürlich zu begrüßen. Die Umgebungsvariablen lassen sich auch dort einfach definieren, aber wie genau muss das für Marathon aussehen?

# systemctl edit marathon.service
[Service]
Environment=JAVA_OPTS=-Xmx2g

Mit systemclt edit kann man eine bestehende Unit-Datei einfach erweitern und der Parameter Environment setzt die Umgebungsvariable.  Alternativ könnte man auch Environmentfile=/etc/defaults/marathon verwenden um das gewohnte Verhalten wieder herzustellen.

Nach dem Speichern braucht es einen Daemon-Reload, damit die neue Unit-Datei eingelesen wird.

# systemctl daemon-reload
# systemctl restart marathon.service

Eigentlich bleibt also alles beim Alten, man muss nur die zusätzlichen Parameter in die JAVA_OPTS setzen und den Service neu starten 😊.

 

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Finde den Weg mit mtr und traceroute

Zum prüfen der Routing Pfade durch das eigene Netzwerk war bisher mtr mein bevorzugtes Tool. Mit  mtr -u 10.10.10.10 werden anstatt icmp udp Pakete/Pings verwendet wodurch man nach und nach alle Pfade durch das eigene Netzwerk findet.

Da sich aber seit Version 3.6 immer wieder das Verhalten des Linux Kernels bezüglich des ECMP Hashing geändert hat, kommt es auf Hosts mit mehreren Pfaden zum ersten Hop/Router immer häufiger vor, dass mtr nur einen Pfad anzeigt (je nach Kernel Version des Hosts). Dies kann sowohl an dem verwendeten Tool als auch an dem sysctl Parameter net.ipv4.fib_multipath_hash_policy liegen. Per default steht dieser auf 0 und bewirkt, dass nur die IP Adressen des Senders und des Empfängers zur Berechnung des Pfades verwendet werden. Setzt man die Hash Policy hingegen auf 1, werden zusätzlich die Ports von Sender und Empfänger mit in die Berechnung aufgenommen.

Da mtr die Ports nicht mit jedem Ping/Paket wechselt, findet man leider wieder nicht die Pfade zum ersten Hop. traceroute hingegen wechselt Sender- und Empfängerport mit jedem Paket wodurch nun alle Pfade gefunden werden. Leider ist traceroute nicht gleich traceroute. Unter Ubuntu findet man dies z.B. in den beiden Paketen inetutils-traceroute und traceroute, in zwei verschiedenen Implementationen mit unterschiedlichem Verhalten. Um unter Ubuntu alle Pfade zu finden sollte man sicherstellen, dass man die Binary aus dem Paket traceroute verwendet.

Kurz zusammengefasst gibt es für nicht angezeigte Pfade also mehrer Ursachen:

  • unterschiedliches ECMP Hashing im Linux Kernel (in Abhängigkeit der Version)
  • nicht explizit aktivierte Multipath Hash Policy
  • Verwendung von mtr oder einer unpassenden traceroute Implementation

Ich für meinen Teil werde bei mtr bleiben und einfach Sender und Empfänger vertauschen, der Router vor dem Empfänger macht ja schon immer alles richtig und berücksichtig auch Layer4.

 

 

 

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Infrastructure as Code mit Terraform und Openstack

This entry is part 1 of 1 in the series Openstack und Terraform Beispiele

Der Drang weg von Hardware zu einer virtuellen oder sogar serverless Infrastruktur ist weiterhin stark. Nicht alle Administratoren oder Entwickler denken sofort an eine Containerplattform wie Kubernetes oder serverless functions sondern verlagern die eigene Infrastruktur in eine Public Cloud. Dadurch bleiben einem lästige Aufgaben in Kalt- und Warmgängen im Rechenzentrum erspart und es bleibt mehr Zeit für anderen Tätigkeiten. Cloud Plattformen wie OpenStack bieten alle nötigen virtuelle Ressourcen die auch in einem Rechenzentrum vorhanden sind, nur dass diese in wenigen Sekunden verfügbar sind. So kann man Komponente wie z.B. Router, Bridges, Interfaces, Server (VMs), Storage (von Block bis Object) und andere schnell und einfach über offene Schnittstellen erstellen und verwalten.

Dies gibt uns Administratoren auch die Möglichkeit unsere Infrastruktur in Textdateien zu beschreiben, zu automatisieren und zu verwalten. Unter dem Buzzword Infrastructure as Code findet man viele Tools die einem hier unterstützen und Terraform ist eines der bekanntesten um z.B. Ressourcen in OpenStack zu verwalten. Mit meinen nächsten Blogposts will ich mit vielen Beispielen zeigen wie man mit Terraform seine virtuelle Ressourcen in der Netways Cloud verwalten kann. Mehr zum Thema Terraform gibt es auch im Talk von Anton Babenko auf der OSDC.

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

AJAX mit Ruby on Rails und :remote => true

Mit :remote => true bietet das das Ruby Webframework Rails eine sehr einfache Methode um mit Hilfe von AJAX eine Webseite zu aktualisieren. Dieses kann z.B. einfach zu HTML-Elementen wie Formulare, Buttons, Links und Checkboxen hinzugefügt werden. Dadurch werden z.B. gefüllte Formulare nicht mehr wie gewohnt an den Webserver gesendet, sondern mit AJAX. Man erspart dem Benutzer dadurch einen lästigen ggf. langwierigen Seitenaufbau. Im Gegenzug muss man sich aber selber um eine Aktualisierung der Webseite mit Hilfe von jQuery oder JavaScript kümmern.

Folgender Code in einem View erstellt eine Checkbox welche bei einem Klick mit Hilfe von AJAX einen HTTP Post an die angeben URL sendet:

check_box_tag( 
  "my_checkbox", "i_am_checked", false, 
  data: { 
    remote: true, 
    url: "my_checkbox/click", 
    method: "POST" 
  }
)

Der Request muss in diesem Fall vom my_checkbox Controller angenommen und verarbeitet werden. Um die Ansicht des Benutzers zu ändern schickt man mit den bekannten Rails Methoden Javascript an den Browser zurück. Im my_checkbox_controller.rb erweitert man z.B. die respond_to einfach um ein format.js:

def click
  respond_to do |format|
    format.js {}
  end
end

Der dazugehörigen View (click.js.erb) wird somit an den Browser zurück gesendet und man kann per JavaScript die Webseite aktualisieren:

console.log('I am the response!')
alert('You clicked the checkbox!')

Rails bietet mit :remote=>true somit eine wirklich einfach Methode um AJAX für seine Webseite einzusetzen!

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Get your RadosGW metrics into Ceilometer

With OpenStack it is an ease to provide an object store backed up from your Ceph RadosGW. But getting the usage metrics from Ceph into Ceilometer and Gnocchi is a little bit tricky. At least if you use OpenStack Pike. Following the official Pike documentation we need a RadosGW user with the correct credentials, usage logging enabled and a little bit of Ceilometer configuration:
 

$ radosgw-admin user create --uid ceilometer --display-name "ceilometer" --caps "usage=read;metadata=read;users=read;buckets=read"
# ceilometer.conf
[service_types]
radosgw = object-store
 
[rgw_admin_credentials]
access_key = access
secret_key = secret

 
Additionally we need to add the radosgw.* metrics to your ceilometer polling.yaml. At this point the official documentation lets you down with inconsistent metric names. In Pike, there are no entry points for radosgw.* metrics, only for the old rgw.* metrics. This is described in the bug #1726458. But following the defined entry points into the code, we see that these creates the new radosgw.* metrics. Well, adding the old metric names to your polling.yaml delivers you the new metric names… ¯\_(ツ)_/¯
 

# polling.yaml
- name: radosgw_pollsters
    interval: 1200
    meters:
    -  rgw.containers.objects
    -  rgw.containers.objects.size
    -  rgw.objects
    -  rgw.objects.size
    -  rgw.objects.containers
    -  rgw.usage

To bring it to an end, restarting “ceilometer central” will deliver your RadwosGW metrics to Gnocchi.

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Gnocchi: Metriken und Metadaten

Gnocchi LogoGnocchi kann im Vergleich zu anderen Timeseries Datenbanken auch Metadaten zu einzelnen Ressourcen hinzufügen. Somit kann man Metriken einfach mit Informationen versehen die wiederum für so spannende Dinge wie Accounting und Reporting verwendet werden können. Eine konkrete Metrik, z.B. der aktuelle Speicherverbrauch eines Servers, wird in Gnocchi immer zu einer Ressource (z.B. mein-db-server1) gespeichert. Eine Ressource hat einen Typ, z.B. Server. Der Typ Server gibt die Attribute/Metadaten vor, welche zu meiner Ressource mein-db-server1 gespeichert werden können.
Also nochmal in kurz: Eine Metrik gehört zu einer Ressource. Eine Ressource hat einen Typ. Ein Typ hat Metadaten.
Ein neuer Ressourcetyp, z.B. Server,  mit den Attributen Name und Kundenummer ist mit folgenden HTTP Post an den Endpunkt /v1/resource_type schnell erstellt:

{
  "Name": "Server",
  "attributes": {
    "name": {
    "required": true,
    "type": "string"
  },
  "Kundennummer": {
    "max": 8,
    "min": 8,
    "type": "number",
    "required": true
  }
}

Um nun eine konkrete Ressource mein-db-server1 anzulegen, sendet man unten stehendes Json an den Endpunkt /v1/resource/server:

{
"Kundennummer": "12345678",
"Name": "mein-db-server1"
}

Zu der neuen Ressource kann man beliebige Metriken (z.B. CPU, Memory, Traffic etc.) hinzufügen und natürlich lassen sich auch die Filter der Suche auf die Kundennummer anpassen. Folgender HTTP Post an /v1/search/resource/server findet alle meine Server wieder:

{
  "=": {
    "Kundennummer": "12345678"
  }
}

Gnocchi gibt einem alles an die Hand um die eigenen Metriken mit Metadaten zu versorgen. Damit ist es ein Leichtes seine Reporting und Accounting Tools mit Daten zu befüllen, wie z.B. unser Cost Explorer.

Achim Ledermüller
Achim Ledermüller
Lead Senior Systems Engineer

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.