Kategorien: | HowTos |
---|---|
Tags: | kubectl Kubernetes Open Source |
Wer mit Kubernetes arbeitet, der kommt nicht umhin sich auch mit kubectl
zu beschäftigen. Es ist das standard Command-Line-Interface zur Arbeit mit einem Kubernetes Cluster.
Dieser Blogpost soll dazu dienen, den initialen Start mit kubectl zu vereinfachen und den ein oder anderen Hinweis aufzuzeigen. Er orientiert sich dabei an Aufgaben und Problemstellungen, mit denen der reguläre Benutzer eines Clusters konfrontiert wird.
Zuerst wird eine sogenannte KUBECONFIG
Konfigurationsdatei benötigt. Diese beinhaltet alle Parameter, die für eine oder mehrere Verbindung(en) zu Kubernetes benötigt werden.
Standardmäßig prüft kubectl
, ob sich unter ~/.kube/config
eine Konfigurationsdatei findet. Um alternative Konfigurationsdateien zu nutzen, gibt es zwei Optionen diese zu definieren:
--kubeconfig=<filepath>
oder aber alsKUBECONFIG=<filepath>
Für eine Verbindung wird mindestens der Name des Clusters und der Benutzer innerhalb des Clusters benötigt. Diese Informationen werden in einem so genannten Context zusammengefasst. Optional kann an dieser Stelle der Namespace angegeben werden, der verwendet wird, sofern dieser beim Aufruf nicht angegeben wird.
Hier ein Beispiel:
contexts: - context: cluster: my-k8s-cluster namespace: default user: system-admin name: default/my-k8s-cluster/system:admin
Der gezeigte Context alleine reicht allerdings noch nicht aus, um Kontakt zu unserem Cluster aufzunehmen. Es fehlen Detailinformationen für cluster
und user
.
Ein user
-Eintrag könnte wie folgt aussehen:
users: - user: token: eaBQIVe1jFDpsuD3NwsS6c2Qx7+eGDlat6BF2qlsgtY name: system-admin
Nun fehlen noch Detailinformationen zu unserem cluster
:
clusters: - cluster: server: https://my-k8s-cluster.example.com:8443 name: my-k8s-cluster
Je nach Authentifikationsmethode des user
s und Konfiguration des cluster
s können sich die benötigten Konfigurationseinstellungen unterscheiden.
Werden alle Teile zusammengesetzt, ergibt sich der folgende Aufbau:
apiVersion: v1 kind: Config current-context: default/my-k8s-cluster/system:admin clusters: - cluster: server: https://my-k8s-cluster.example.com:8443 name: my-k8s-cluster users: - user: token: eaBQIVe1jFDpsuD3NwsS6c2Qx7+eGDlat6BF2qlsgtY name: system-admin contexts: - context: cluster: my-k8s-cluster namespace: default user: system-admin name: default/my-k8s-cluster/system:admin
Neben den bereits gezeigten Abschnitten definieren wir den ausgewählten Context.
Auch wenn der Name des Contexts frei gewählt werden kann, empfehlen sich eindeutige Bezeichnungen: default/my-k8s-cluster/system:admin
Dieser beinhaltet alle wichtigen Details zur Verbindung und ist damit eindeutig identifizierbar.
Zusätzliche Einträge wie cluster
, user
und context
können ebenfalls definiert werden.
Somit ist es möglich, verschiedene Konstellationen in der Konfiguration zu hinterlegen, zwischen denen gewechselt werden kann.
Die konfigurierten context
s können wir uns mit dem folgenden Befehl anzeigen lassen.
$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * default/my-k8s-cluster/system:admin my-k8s-cluster system-admin default
Der ausgewählte context
wird durch einen *
gekennzeichnet. Sofern mehrere contexts
definiert wurden, können diese mit kubectl config use-context <context>
gewechselt werden.
kubectl
bietet neben der Anzeige und Auswahl der contexts
auch die Möglichkeit die ausgewählte KUBECONFIG via Command-Line zu editieren.
Wie dies genau funktioniert, beschreibt die Hilfeausgabe:
$ kubectl config --help Modify kubeconfig files using subcommands like "kubectl config set current-context my-context" The loading order follows these rules: 1. If the --kubeconfig flag is set, then only that file is loaded. The flag may only be set once and no merging takes place. 2. If $KUBECONFIG environment variable is set, then it is used as a list of paths (normal path delimiting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list. 3. Otherwise, ${HOME}/.kube/config is used and no merging takes place. Available Commands: current-context Displays the current-context delete-cluster Delete the specified cluster from the kubeconfig delete-context Delete the specified context from the kubeconfig get-clusters Display clusters defined in the kubeconfig get-contexts Describe one or many contexts rename-context Renames a context from the kubeconfig file. set Sets an individual value in a kubeconfig file set-cluster Sets a cluster entry in kubeconfig set-context Sets a context entry in kubeconfig set-credentials Sets a user entry in kubeconfig unset Unsets an individual value in a kubeconfig file use-context Sets the current-context in a kubeconfig file view Display merged kubeconfig settings or a specified kubeconfig file Usage: kubectl config SUBCOMMAND [options] Use "kubectl <command> --help" for more information about a given command. Use "kubectl options" for a list of global command-line options (applies to all commands).
Das wohl meistgenutzte Feature von kubectl
ist die Anzeige von Objekten innerhalb des Clusters und deren Status. Hierzu stehen gleich mehrere Methoden bereit, je nachdem welche Informationen wir uns anzeigen lassen wollen. Unter anderem:
get
: Auflisten und Anzeigen von Objektendescribe
: Beschreibung von Objekten und deren Statuslogs
: Anzeige der Logs eines Containersexplain
: Anzeigen des Aufbaus von OjektenMittels der get
Methoden kann sich der User alle Objekte innerhalb des Clusters anzeigen lassen, auf die er Zugriff hat.
Hierzu muss mindestens ein Objekttyp angegeben werden, der angezeigt werden soll. Alternativ kann man sich mit all
auch mehrere Objekttypen anzeigen lassen.
An dieser Stelle sollte angemerkt werden, dass all
nicht all bedeutet. Es werden lediglich die gängigsten Objekte angezeigt.
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deployment-6dd86d77d-5hldn 1/1 Running 0 47s nginx-deployment-6dd86d77d-jr7hk 1/1 Running 0 47s
$ kubectl get all NAME READY STATUS RESTARTS AGE pod/nginx-deployment-6dd86d77d-5hldn 1/1 Running 0 100s pod/nginx-deployment-6dd86d77d-jr7hk 1/1 Running 0 100s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx-deployment 2/2 2 2 100s NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-6dd86d77d 2 2 2 100s
Die ausgabe des all
Befehls kann in unserem konkreten Fall auch dadurch erreicht werden, dass mehrere Objekttypen gleichzeitig abgefragt werden.
Um alle Instanzen der Objekttypen pod
, deployment
und replicaset
anzuzeigen, können wir auch folgenden Befehl verwenden:
$ kubectl get pods,deployments,replicasets NAME READY STATUS RESTARTS AGE pod/nginx-deployment-6dd86d77d-5hldn 1/1 Running 0 4m35s pod/nginx-deployment-6dd86d77d-jr7hk 1/1 Running 0 4m35s NAME READY UP-TO-DATE AVAILABLE AGE deployment.extensions/nginx-deployment 2/2 2 2 4m35s NAME DESIRED CURRENT READY AGE replicaset.extensions/nginx-deployment-6dd86d77d 2 2 2 4m35s
Sobald die Antwort des Servers mehrere Objekttypen beinhaltet, werden die einzelnen Objektnamen mit ihrem Typ gepräfixt.
Soll nur der Status eines spezifischen Objekts ausgegeben werden, so geschieht dies durch Angabe des Objektnamens nach dem Objekttyp:
$ kubectl get pod nginx-deployment-6dd86d77d-5hldn NAME READY STATUS RESTARTS AGE nginx-deployment-6dd86d77d-5hldn 1/1 Running 0 19m
Alternativ kann auch die Syntax <typ>/<name>
verwendet werden.
Zum Beispiel: kubectl get pod/nginx-deployment-6dd86d77d-5hldn
Welche Informationen bei der Anzeige ausgegeben werden, hängt sowohl vom Ojekttyp selber, als auch vom Ausgabeformat ab. Neben dem Standardausgabeformat stehen unter anderem die folgenden Formate zur Verfügung:
wide
: Darstellung zusätzlicher Informationenyaml
: Ausgabe des gesamten Objekts im YAML formatjson
: Ausgabe des gesamten Objekts im JSON formatjsonpath
: Ausgabe definierter BereicheEine vollständige Liste der Ausgabeformate kann der Ausgabe von kubectl get --help
entnommen werden.
Schauen wir uns beispielsweise die Ausgabe der laufenden Pods mithilfe des Ausgabeformats wide
an, dann werden neben den bereits bekannten Informationen zusätzliche Laufzeitinformationen angezeigt. Hierzu zählen unter anderem die IP-Adresse des Pods, sowie der Node auf dem der Pod ausgeführt wird.
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-6dd86d77d-5hldn 1/1 Running 0 112m 10.233.65.109 node-05.example.com <none> <none> nginx-deployment-6dd86d77d-jr7hk 1/1 Running 0 112m 10.233.79.238 node-04.example.com <none> <none>
Die Formate yaml
sowie json
unterscheiden sich – abgesehen vom Format selbst – nicht in ihrem Inhalt. Beide liefern das ausgewählte Objekt und all seine Eigenschaften zurück.
Neben den manuell definierten Eigenschaften liefern die beiden Ausgabeformate zudem sehr detailierte Informationen über den Status des Objekts.
$ kubectl get pod nginx-deployment-6dd86d77d-5hldn -o yaml apiVersion: v1 kind: Pod metadata: creationTimestamp: "2019-08-26T12:18:51Z" generateName: nginx-deployment-6dd86d77d- labels: app: nginx pod-template-hash: 6dd86d77d name: nginx-deployment-6dd86d77d-5hldn namespace: test ownerReferences: - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet name: nginx-deployment-6dd86d77d uid: aa4125fe-c7fb-11e9-aa70-96000014cd55 resourceVersion: "70713161" selfLink: /api/v1/namespaces/test/pods/nginx-deployment-6dd86d77d-5hldn uid: aa452873-c7fb-11e9-aa70-96000014cd55 spec: containers: - image: nginx:1.7.9 imagePullPolicy: IfNotPresent name: nginx ports: - containerPort: 80 protocol: TCP resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: default-token-q2h6q readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: node-05.example.com priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: default-token-q2h6q secret: defaultMode: 420 secretName: default-token-q2h6q status: conditions: - lastProbeTime: null lastTransitionTime: "2019-08-26T12:18:51Z" status: "True" type: PodScheduled containerStatuses: - containerID: docker://52dfe6498a96a92ec118dbf18705237792c703be33a86498c53676b1028343b7 image: nginx:1.7.9 imageID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451 lastState: {} name: nginx ready: true restartCount: 0 state: running: startedAt: "2019-08-26T12:18:53Z" hostIP: 10.66.0.5 phase: Running podIP: 10.233.65.109 qosClass: BestEffort startTime: "2019-08-26T12:18:51Z"
Das Ausgabeformat jsonpath
ist immer dann hilfreich, wenn Abschnitte der Ausgabe weiterverarbeitet werden sollen. Ein Beispiel stellt das Dekodieren eines base64 kodierten secrets
dar.
Values innerhalb von secrets
werden base64 kodiert gespeichert, was bedeutet, dass wir die Kodierung zunächst durch den Aufruf von base64 -d
rückgängig machen müssen. Dank jsonpath
können wir das in einem Aufruf bewerkstelligen.
Angenommen, wir wollen den Wert des Keys password als Plaintext darstellen und unser secret ist wie folgt aufgebaut. Dies können wir dann mithilfe des Befehls kubectl get secret mysecret -o jsonpath='{.data.password}' | base64 -d
bewerkstelligen.
apiVersion: v1 data: password: c3VwZXJzZWN1cmUxMjM= kind: Secret metadata: creationTimestamp: "2019-08-26T14:38:05Z" name: mysecret namespace: test resourceVersion: "70750555" selfLink: /api/v1/namespaces/test/secrets/mysecret uid: 1d4a2224-c80f-11e9-8df3-96000014cd46 type: Opaque
$ kubectl get secret mysecret -o jsonpath='{.data.password}' | base64 -d supersecure123
Auch ist es möglich, sich ausschließlich Objekte mit einem bestimmten Label anzeigen zu lassen. Hierzu bietet kubectl
für den get
Befehl die entsprechende Filteroption. Wollen wir uns beispielsweise alle deployments, replicasets und pods mit dem Label app=nginx anzeigen, so können wir dies mit dem folgenden Befehl bewerkstelligen:
kubectl get deployments,replicasets,pods -l app=nginx NAME READY UP-TO-DATE AVAILABLE AGE deployment.extensions/nginx-deployment 2/2 2 2 7d6h NAME DESIRED CURRENT READY AGE replicaset.extensions/nginx-deployment-6dd86d77d 2 2 2 7d6h NAME READY STATUS RESTARTS AGE pod/nginx-deployment-6dd86d77d-5hldn 1/1 Running 0 7d6h pod/nginx-deployment-6dd86d77d-jr7hk 1/1 Running 0 7d6h
Welches Label ein Objekt besitzt, kann übrigens durch den zusätzlichen get
-Parameter --show-labels
angezeigt werden.
Neben der einfachen Auflistung der Objekte ist es oftmals hilfreich, sich Objekte beschreiben zu lassen. Hierzu steht der Befehl describe
zur Verfügung.
Die Ausgabe des describe
-Befehls gibt eine relativ ausführliche Darstellung des Aufbaus und des Zustands des Objektes aus. Die describe
-Ausgabe eines Pods gibt beispielsweise Aufschluss über:
Vor allem die Events eines Objekts sind oft ein wertvolles Mittel, um eventuellen Fehlern auf die Schliche zu kommen. Als Beispiel sei die Analyse der Fehlermeldung „ImagePullBackOff“ genannt. Oftmals bieten die Events einen Anhaltspunkt wo bei der Fehlanalyse anzusetzten ist.
$ kubectl describe pod nginx-deployment-6dd86d77d-9fm6w Name: nginx-deployment-6dd86d77d-9fm6w Namespace: test Priority: 0 PriorityClassName: <none> Node: node-05.example.com/10.66.0.5 Start Time: Mon, 02 Sep 2019 20:44:29 +0200 Labels: app=nginx pod-template-hash=6dd86d77d Annotations: <none> Status: Running IP: 10.233.65.100 Controlled By: ReplicaSet/nginx-deployment-6dd86d77d Containers: nginx: Container ID: docker://7a3e3b51987da42a421d6f965824bfe2ba5d553a9f1d2e93758207c34cd4e31b Image: nginx:1.7.9 Image ID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451 Port: 80/TCP Host Port: 0/TCP State: Running Started: Mon, 02 Sep 2019 20:44:31 +0200 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-q2h6q (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-q2h6q: Type: Secret (a volume populated by a Secret) SecretName: default-token-q2h6q Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 19s default-scheduler Successfully assigned test/nginx-deployment-6dd86d77d-9fm6w to node-05.example.com Normal Pulled 18s kubelet, node-05.example.com Container image "nginx:1.7.9" already present on machine Normal Created 18s kubelet, node-05.example.com Created container nginx Normal Started 17s kubelet, node-05.example.com Started container nginx
Wird die Ausgabe eines Containers benötigt, so steht der Befehl logs
zur Verfügung. Sollte sich ein Pod im Status „CrashLoopBackOff“ befinden, gibt die Anzeige der Logs des ensprechenden Containers meist Aufschluss über die Ursache des Problems.
Bei der Verwendung des logs
-Befehls müssen wir explizit zwischen Pods und Containern unterscheiden. Da ein Pod mehrere Container beinhalten kann reicht es, dass einer der Container nicht richtig funktioniert, um den Pod in einen fehlerhaften Zustand zu bringen.
Sollen die Logs eines Pods mit ausschließlich einem Container angezeigt werden, so gestaltet sich die Ausgabe der Logs recht einfach:
$ kubectl logs nginx-deployment-6dd86d77d-9fm6w
Beinhaltet der zu analysierende Pod mehrere Container wird Kubernetes auf die gleiche Anfrage mit einem Fehler antworten.
Dabei ist Kubernetes allerdings so freundlich und liefert die entsprechende Lösung gleich mit.
Beinhaltet ein Pod mehrere Container, so muss neben dem Pod-Namen ebenfalls der Container-Name angegeben werden:
$ kubectl logs nginx-deployment-6dd86d77d-9fm6w -c nginx
Oftmals muss die Ausgabe des logs
-Befehls allerdings nicht für die akute Fehlerbehebung herangezogen werden, sondern wird bei der Fehleranalyse vergangener Ereignisse benötigt.
Hierzu steht das zusätzliche Flag --previous
zur Verfügung. Dabei werden nicht die aktuellen Logs des Containers angezeigt, sondern die der vorangegangenen Instanz des Containers / Pods.
Wer (wie ich) nicht immer den exakten Namen eines Parameters oder dessen Platzierung innerhalb der Objektstruktur im Kopf hat, kann sich mit Hilfe des explain
-Befehls selbst helfen und sich den korrekten Aufbau eines Kubernetes-Objekts in der genutzten API-Version anzeigen zu lassen.
Er gibt neben dem Aufbau von Objekten auch eine kurze Beschreibung zu allen Parametern aus.
Wollen wir uns beispielsweise den Aufbau der Pod-Spezifiation anschauen, so könnnen wir dies mithilfe des folgenden Befehls bewerkstelligen:
$ kubectl explain pod KIND: Pod VERSION: v1 DESCRIPTION: Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts. FIELDS: apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds metadata <Object> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata spec <Object> Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status status <Object> Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
Wer eine rekursive Auflistung aller möglichen Parameter erhalten möchte erlangt diese mithilfe des folgenden Befehls:
kubectl explain --recursive pod.spec KIND: Pod VERSION: v1 RESOURCE: spec <Object> DESCRIPTION: Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status PodSpec is a description of a pod. FIELDS: activeDeadlineSeconds <integer> .. Output Skipped ... automountServiceAccountToken <boolean> containers <[]Object> args <[]string> command <[]string> env <[]Object> name <string> value <string> valueFrom <Object> configMapKeyRef <Object> key <string> name <string> optional <boolean> fieldRef <Object> apiVersion <string> fieldPath <string> resourceFieldRef <Object> containerName <string> divisor <string> resource <string> secretKeyRef <Object> key <string> name <string> optional <boolean> .. Output Skipped .. name <string> ports <[]Object> .. Output Skipped ... volumes <[]Object> awsElasticBlockStore <Object> fsType <string> partition <integer> readOnly <boolean> volumeID <string> .. output Skipped .. vsphereVolume <Object> fsType <string> storagePolicyID <string> storagePolicyName <string> volumePath <string>
Die Ausgabe des explain
-Befehls kann so eine Recherche innerhalb der Kubernetes-Dokumentation überflüssig machen. Das spart nicht nur Zeit, sondern oftmals auch Nerven.
Wer regelmäßig mit der Konsole arbeitet, lernt das autocompletion-Feature zu lieben.
Oftmals ist die Syntax eines Befehles nicht 100 prozentig klar, oder es müssen Argumente vervollständigt werden, deren Namen man sich einfach nicht merken kann oder will. Viele Command-Line-Tools bringen deshalb so genannte completion-files mit und kubectl
ist hier keine Ausnahme.
Wer die autocompletion-Funktionalität von kubectl
verwenden will, muss dazu den Befehl kubectl completion ...
bemühen. Der completion
-Befehl gibt die entsprechenden completion-scripts sowohl für bash als auch für zsh aus. Wer die Autovervollständigung ad-hoc nutzten möchte, der kann sich mithilfe der folgenden Befehle behelfen:
bash: source <(kubectl completion bash)
zsh: source <(kubectl completion zsh)
Wer auch nach Beenden des Terminals in den Genuss der Auto-Completion kommen möchte, speichert sich die Ausgabe der Befehle kubectl completion bash/zsh
innerhalb einer Datei ab und lädt diese wie gewohnt innerhalb seiner .bashrc
oder .zshrc
.
Zum Anlegen, Ändern oder Löschen von Objekten stehen via kubectl
unterschiedliche Methoden zur Verfügung. Alle haben gemeinsam, dass sie das zu kontrollierende Objekt anhand ihres Namens und Namespaces (bei namespacesbehafteten Objekten) identifizieren.
Um ein neues Objekt im Cluster anzulegen, können sowohl die Befehle create
als auch apply
verwendet werden. Dabei setzt create
voraus, dass das Zielobjekt noch nicht existiert. Das folgende Beispiel zeigt die Erzeugung eines Deplyoments
, welcher den Webserver Nginx als einzigen Pod beinhaltet:
$ kubectl create deployment nginx --image=nginx deployment.apps/nginx created
Versuchen wir nun das gleiche Deployment erneut anzulegen, erhalten wir eine Fehlermeldung, weil ein Deployment
mit den namen nginx
bereits exisiert.
kubectl create deployment nginx --image=nginx Error from server (AlreadyExists): deployments.apps "nginx" already exists
Der create
Befehl stellt somit eine konkrete Aktion dar und beschreibt nicht – wie andere Befehle – den Zielzustand.
Des Weiteren wurde die Definition des Objekts nicht lokal gespeichert, sondern lediglich dem Cluster mitgeteilt. Um das Objekt, in unserem Fall das Nginx Deployment
, auch in anderen Cluster bereitzustellen, muss nun der gleiche Befehl gegen den neuen Cluster ausgeführt werden.
Oftmals ist es eine bessere Idee, Objekte nicht ad-hoc zu erstellen, sondern den Zwischenweg über eine YAML Datei zu gehen, welche die Definition des Selbigen beinhaltet.
kubectl create
kann hierbei Hilfestellung leisten.
Der Parameter --output yaml
erstellt nicht nur das Objekt, er generiert auch die Definition des Objekts im YAML Format und gibt diese auf der Konsole aus.
Soll die generierte Definition vor dem Einspielen in den Cluster bearbeitet werden, so kann zwischenzeitlich der Parameter --dry-run
genutzt werden.
Beispiel:
$ kubectl create deployment nginx --image=nginx --output=yaml --dry-run apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: nginx name: nginx spec: replicas: 1 selector: matchLabels: app: nginx strategy: {} template: metadata: creationTimestamp: null labels: app: nginx spec: containers: - image: nginx name: nginx resources: {} status: {}
Die Ausgabe des oben stehenden Befehls kann nun als Datei abgelegt und beispielsweise durch Git unter Versionskontrolle gestellt werden.
Wer die resultierende Definition via create
gegen den Cluster anwenden will, der kann dies mit dem Befehl kubectl create -f nginx-deployment.yaml
bewerkstelligen.
Eine Hilfestellung bietet create
oft dann, wenn die Alternative zu fehleranfällig wäre. Als Beispiel sei hier die Erstellung eines secrets
genannt, dass sowohl ein Serverzertifikat als auch den dazugehörigen Schlüssel beinhalten soll. Secrets enthalten base64 encodete Werte, weshalb eine manuelle Erstellung mehrere Schritte beinhalten würde.
Mit dem Befehl kubectl create secret tls certificate-pair --cert=certificate.pem --key=key.pem -o yaml --dry-run
hingegen ist das gewünschte Secret in einem Befehl erstellt.
kubectl create secret tls certificate-pair --cert=certificate.pem --key=key.pem -o yaml --dry-run apiVersion: v1 data: tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ2ekNDQXRPZ0F3SUJBZ0lVY3NtYWR5R29jRlEvZkVrRVRRM25kTjFxZVhrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZUXhDekFKQmdOVkJBWVRBa1JGTVF3d0NnWURWUVFJREFOT1VsY3hHVEFYQmdOVkJBY01FRTF2Wlc1agphR1Z1WjJ4aFpHSmhZMmd4RURBT0JnTlZCQW9NQjBWNFlXMXdiR1V4R1RBWEJnTlZCQU1NRUhSbGMzUXVaWGhoCmJYQnNaUzVqYjIweEh6QWRCZ2txaGtpRzl3MEJDUUVXRUhSbGMzUkFaWGhoYlhCc1pTNWpiMjB3SGhjTk1Ua3cKT1RJMk1UUXpNVEUyV2hjTk1qQXdPVEkxTVRRek1URTJXakNCaERFTE1Ba0dBMVVFQmhNQ1JFVXhEREFLQmdOVgpCQWdNQTA1U1Z6RVpNQmNHQTFVRUJ3d1FUVzlsYm1Ob1pXNW5iR0ZrWW1GamFERVFNQTRHQTFVRUNnd0hSWGhoCmJYQnNaVEVaTUJjR0ExVUVBd3dRZEdWemRDNWxlR0Z0Y0d4bExtTnZiVEVmTUIwR0NTcUdTSWIzRFFFSkFSWVEKZEdWemRFQmxlR0Z0Y0d4bExtTnZiVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQgpBTWtnSmtyd1U5UFhmRGhETW15cDlpblBFdmNiVkI5WUIvb3B6bHF3VzRybkkvbTJnbzFVeXFxZ3FLeDlEZWpWCnI0K3ZPcEtZcUcvTDJVZDlpS1o2bHdHUUZmWnNkaTJKVGRGdjVpSzVyejZPQVhwWTE1THYrTjN4TDRkMU5yN1gKT09DcVIwSmlFKzN0Q0tWN1l0Y1N4RUdsNWJlcStpOEJxK0w0bG1mQTZzS09vdjYwcWhpWi8wOUVUN3JoaXdCMApyYk80b2J4L0t5azZzbVhETW1SY2EvVVBXWk82L3hKSmhQeG9kY1dHOGJJcVE4SGtRM1NOaFpyWjdlekFMMmJoCjcxQSt2WFJOcXFJaHorOTdBRWZaSmozeGJZcm5vSVEwajZITkFZaHI1YzJSWmJ4WHVKL2J5QkUvL0U0Z1NPRmwKUU1EeitrS08rWlE1N25odkVXQWRFK01DQXdFQUFhTlRNRkV3SFFZRFZSME9CQllFRkZLK1JSNVBPVjVReENDOAp1UFM1a3lkMU9vcC9NQjhHQTFVZEl3UVlNQmFBRkZLK1JSNVBPVjVReENDOHVQUzVreWQxT29wL01BOEdBMVVkCkV3RUIvd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSzdGbWFGYWRXei9hdkxxSmI1LzAxZ0UKNUxpNDVuSE5LbjZLa0lGZUdWT2RFS1F2ZWg5eWhyclRGaEJNUDk1aU43UEFVT2R6NVNMNC9tQ0V1QkRKd3dLKwpyc0N3OFJSS0hLaXYvcVdRU29BTDBkdU1LcXVIYU0rRTdINHFHOFVONDk2Q2YrQ3djU0paTjVSNGdROU1JTXp6CmFEL1dhek1qVHlJcFMwMFFaSTd5elBCYlFUMnRnbERLcjRRY0ROblFPNVNiVE5STDgraVR0QnBoZTRWWERjQ24KUTJpRkhweWVtZURvQ0l2YXBUU1k2VUxKM3JxNysrdmhRZmJIYmJtejJ4WHFCSUY5ZUV3RVFhM2NSd2hBeENlZQorMjJEVGoxaXdmeFpNWmRuSnR6UVM5QVRHeTQzSWh4dmJDQ2pxbTNCODBUblBTZGRrcFRDOVFKcEhPdkphTjg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktrd2dnU2xBZ0VBQW9JQkFRREpJQ1pLOEZQVDEzdzQKUXpKc3FmWXB6eEwzRzFRZldBZjZLYzVhc0Z1SzV5UDV0b0tOVk1xcW9LaXNmUTNvMWErUHJ6cVNtS2h2eTlsSApmWWltZXBjQmtCWDJiSFl0aVUzUmIrWWl1YTgramdGNldOZVM3L2pkOFMrSGRUYSsxempncWtkQ1loUHQ3UWlsCmUyTFhFc1JCcGVXM3F2b3ZBYXZpK0pabndPckNqcUwrdEtvWW1mOVBSRSs2NFlzQWRLMnp1S0c4ZnlzcE9ySmwKd3pKa1hHdjFEMW1UdXY4U1NZVDhhSFhGaHZHeUtrUEI1RU4wallXYTJlM3N3QzltNGU5UVByMTBUYXFpSWMvdgpld0JIMlNZOThXMks1NkNFTkkraHpRR0lhK1hOa1dXOFY3aWYyOGdSUC94T0lFamhaVURBOC9wQ2p2bVVPZTU0CmJ4RmdIUlBqQWdNQkFBRUNnZ0VCQUxFV1JhRW1DaWswU29PZlp2NldoOUE0SzVLMzFWSGp5T0pUZlFZTTBnMXoKaHhHUHlWTjNuUnF2YXRTMUoxSWpFL21IYUNNN2x0TVl3YTlZc01Fa24yRVk1TDJjc2xGVjI5YlVsK1ZyYVFuRApMem55ajUwby9nOHRGWlJIZUhTQU8reFZBWGxKc2hLRDZtRUtTdlRqNlRtRVFNZC9HOW5YdHVpWnlKU0NJREk4CnBSSzJpQk9sRStPbHRScER3VnNDUDFtY0w2SjA2L0lWRjBnbjFyM3Q2S1o3NmIyMGlkSktPTjVpVmVLTDAxaUUKMWxmQmtKMXluUWgzR1dlSURDSXJyM2RoZ29qRVgvNjcxakJqRHVmcnBHUFpxNW02NXJLSTg4aENVNnVvMERPLwoyU0dqVG02VFNiRytPMUxPUmIzZXl0aFlMUXR2UVRuZHQ0Z3BIWTNoVklFQ2dZRUE2LzhMbEI0NTVwV1pkYTd6CmVKbTI1VWNxUXdjcUlmUzROZGlQWG5VTmxkWEdYVG5xdU1ST2JXd1JjbWtBUTh4aUxsaDJzYVNvQmNMN1ZYWWEKaTZyV081WXhSNjM3QktERjlOWTBxOHhoUDJlTVJ2ZUV2QkUzZkFFRjhvdCsrNUo0M05kbEI5M3lxOWIyUUs3TgpzRnhoVloyRDd3blM1bXRWekNWL3lHa2NNMGtDZ1lFQTJpeHZTeGxmUHpIZXM1THZpK1RseFhZTldsbFJiRVFvCko1amlEM2JDSG5oSENHQVJWU1V1NVVVTVd3b0pUQmxydldoNFczcWhzeDFoQkxmeDVQNVlOdVBBTDhhQlVQMUwKdUl2NlJtRUVFdXVPZ0MwMmhyRXIwNCtBYWIrbHM3SVpPUkZCMWd6M3FSdEUwQVo5UVF6YlJ4Q3ZUUnovS3lXaApjSHhRbk44RUljc0NnWUJPV0p5Q2JzcHdGNGdidnBvTGxwUldaNXJMSjh5Lyt4dFFuUFZ6dVU1cVNNOFMwaEJ2CmlKUTAxV1N4WTlSM3JabUdvMDI4U2RxU0Z4b1RWQ01aN1B3MFNmZFFRWjBNKzBiY3NtUklDSkRjV01jRUpGWUgKalh1ckNqZnNQbzFJZldic2dnR0RiQmFOSDg4ZXlDbDIvQ1JBSlF2UXhxVWlZODNXK1RnRDA0bE9LUUtCZ1FEVQpJMWlrQVN1bjJ1bmNXZ2NxVTR0SGtSNHl0NTZBVTFWb0N6UGtMV2xiRDBDaVdDY0NUNEZsMU5uS3U5dUdiMEZmCmpuRlpJY2lRelFSRS9rYnFqcFZmNmR3NW1CNnRqVjFQT0d4R2VwYm5mcnUwemtHeWZodExQc0Z5RWJNaEl3OTcKZWRnMk5hMnFkS1ZZVUxjQnhXcUJreXVoSTR6SmUzR2FXb1pYd2xIV09RS0JnUURXdjJmd2JTeVc0dkNEYm5rNgpxd1ZWaVVOV1drOHNYR1dDV3d5RXVxalRiYUlHMjVtbTNuWjRCRVJyUTB2Vmx2VWNsMmZwUVkweWxDdkRObTgxCk5jL243SUw0SnN3dU5XeThUWW1lZ0cxWThtcEUxTHo5UVVhWE1tRmpqZGc5TExwWElLM2xWSUVzYUtFRVNnM0sKN0hmUHpaV1h3dkZJUGlLTWRPaldmZ0xoS0E9PQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg== kind: Secret metadata: creationTimestamp: null name: certificate-pair type: kubernetes.io/tls
Da nicht alle Objekttypen oder Parameter als Argumente an create
übergeben werden können, muss teilweise der Weg über eine Manifestdatei gegangen werden.
Neben create
können neue Objekte auch mithilfe des apply
-Befehls erstellt werden. Hierbei unterscheidet sich apply
jedoch leicht im Handling.
apply
spielt seine Stärken im Umgang mit YAML-Manifesten aus. Nehmen wir die in create
dargestellte Deployment
-Definition und nehmen an, dass diese als nginx-deployment.yaml
vorliegt. Dann können wir diese mit Hilfe des folgenden Befehls im Cluster einspielen:
kubectl apply -f nginx-deployment.yaml deployment.apps/nginx created
Im Gegensatz zu create
verhält sich apply
bei erneuter Ausführung des Befehls unterschiedlich.
kubectl apply -f nginx-deployment.yaml deployment.apps/nginx unchanged
Denn durch apply
wird keine Aktion sondern ein Zielzustand definiert, welche vom Cluster berücksichtigt wird. In unserem Beispiel also die Existenz eines Deployment
-Objekts namens nginx unter Verwendung des Image nginx und einem Replika.
Wollen wir die Anzahl der Replikas nun Beispielsweise auf 2 anheben, so genügt es, die Datei entsprechend zu aktualisieren und erneut den apply
-Befehl auszuführen.
kubectl apply -f nginx-deployment.yaml deployment.apps/nginx configured
Das definierte Ziel, unser Objekt, wird dabei immer anhand der apiVersion, Kind, name und namespace identifiziert.
Viele Eigenschafen eines Objekts können auf diese Weise geändert werden. Es gibt jedoch s.g. immutable Eigenschaften oder Felder, die nach der Erstellung des Objekts nicht mehr angepasst werden können. apply
liefert dann eine entsprechende Fehlermeldung.
Weil keine Aktion, sondern ein Zielzustand definiert wird, eignet sich apply
für mehrere Anwendungsfälle. Ferner ist es dazu geeignet, in Scripts oder Pipelines verwendet zu werden.
Um Eigenschaften eines Objekts anzupassen, steht zusätzlich der Befehl patch
zur Verfügung. Dieser enthält die Information, welches Objekt geändert werden soll und wie. Wollen wir z.B. die Anzahl der Replikas auf drei erhöhen, können wir dies mit dem folgenden patch
-Befehl bewerkstelligen:
kubectl patch deployment nginx -p '{"spec": {"replicas": 3}}' deployment.extensions/nginx patched
patch
bietet sich vor allem dann an, wenn Objekte den eigenen Vorstellungen nach geändert werden sollen, aber automatisiert erstellt werden. Zum Beispiel node
Objekte.
Neben den generischen Methoden wie apply
oder patch
stellt kubectl
eine Reihe von spezifischen Befehlen bereit. Anhand dieser Befehle können beispielsweise Deployments oder StatefulSets skaliert werden, auf einen früheren Stand eines Deployments zurückgewechselt werden, oder aber der Status eines sogenannten rollouts
überprüft werden.
Nachfolgend werden ein paar der gängigen Befehle und deren Verwendung grob skizziert:
label
, annotate
: Hinzufügen, ändern oder löschen von labels und annotations.kubectl label deployment nginx comment=awebserver
scale
: Anpassen der Anzahl der replica
-Eigenschaft.rollout
(history, pause, restart, undo
): Steuerung von rollouts
. Z.B. Rollback auf eine frühere Version eines Deployments.expose
: Erstellung ein Service zu einem gegebenen Objekt.Früher oder später kommt der Moment, in dem die angelegten Objekte auch wieder gelöscht werden sollen.
Hier kommt der Befehl delete
zum Einsatz.
Wie auch bei create
kann delete
das Zielobjekt auf unterschiedliche Weise identifizieren. Entweder durch Angabe der Typs und des Namens oder aber indirekt über den Parameter -f
und eine entsprechende Objektdefinition. Wollen wir unser Nginx Deployment
löschen geschieht dies z.B. mit Hilfe des Befehls:
kubectl delete -f nginx-deployment.yaml deployment.apps "nginx" deleted
Alternativ hätten wir das Deployment
auch via kubectl delete deployment nginx
löschen können.
Auch wenn keine manuellen Änderungen an Dateien oder Prozessen innerhalb eines Containers vorgenommen weden sollen, kann es manchmal durchaus hilfreich sein, in einen Container hineinzusehen. Besonders bei der Entwicklung bietet der Blick in einen Container oftmals schnelleren Einblick in die Situation als andere Lösungen.
Nehmen wir an, wir wollen unseren Nginx-Web-Service debuggen und prüfen, ob dieser auf bestimmte Requests reagiert, so kann der exec
Befehl helfen.
kubectl exec
führt den angegebenen Befehl innerhalb des Containers aus. Auch eine interaktive Shell innerhalb des Containers kann mit exec
gestartet werden, sofern vorhanden.
Wollen wir beispielsweise sicherstellen, dass der Inhalt einer Datei innerhalb des Containers mit unseren Erwartungen übereinstimmt, dann können wir uns diese Datei mittels cat
anzeigen lassen:
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-65f88748fd-lt2z5 1/1 Running 0 4m35s nginx-65f88748fd-mmwl5 1/1 Running 0 4m35s $ kubectl exec nginx-65f88748fd-lt2z5 cat /etc/nginx/nginx.conf user nginx; worker_processes 1; ... http { include /etc/nginx/mime.types; ... include /etc/nginx/conf.d/*.conf; }
Möchten wir eine interaktive Shell im Container starten, dann müssen wir neben dem Befehl selbst weitere Parameter angeben. Dabei handelt es sich um --stdin
und --tty
. Andernfalls wird die Shell zwar gestartet, sie beendet sich allerdings direkt wieder falls wir keine Argumente übergeben haben.
Dies ist bereits aus der Verwendung von docker exec
bekannt. Das dort verwendete Kürzel -it
kann auch bei kubectl exec
verwendet werden. Ein vollständiges Beispiel sieht dann wie folgt aus:
kubectl exec -it nginx-65f88748fd-lt2z5 -- bash root@nginx-65f88748fd-lt2z5:/#
Der auszuführende Befehl muss natürlich innerhalb des Containers vorhanden sein. Da die benutzten Images meist auf minimale Größe ausgelegt sind, ist die Auswahl der Tools innerhalb des Containers oft stark begrenzt. Aus Security-Sicht ist dies eine gute Sache.
Sofern der Zielpod mehrere Container beherbergt, oder gar Init-Container verwendet, kann mittels -c
der ensprechende Containername angegeben werden.
Manchmal müssen Services analysiert werden, die nicht direkt der Außenwelt präsentiert werden, oder aber vorgelagerte Proxies und Loadbalancer bei einer Fehleranalyse ausgeschlossen werden sollen.
Hierzu ist es notwenig, dass direkt auf den entsprechenden Service zugegriffen werden kann. Auch wenn dies normalerweise nicht der Fall ist.
Um direkten Zugriff zu ermöglichen stellt kubectl
den Befehl port-forward
bereit. Dieser dient dazu, einen lokalen Port auf den Port eines Objekts innerhalb des Cluster weiterzuleiten. Als Ziel können unter Anderem Services
, Pods
auch auch ganze Deployments
dienen.
Dabei wird das Ziel in der Form <typ-short>/ angegebenen. Als weiterer Parameter muss eine Kombination aus lokalem Port und Remoteport angegeben werden.
Wollen wir nun direkt auf einen unserer Nginx Pods zugreifen sieht die entsprechende Syntax wie folgt aus:
$ kubectl port-forward pod/nginx-65f88748fd-lt2z5 8080:80 Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80
Dabei gibt 8080 den lokal zu öffnenden Port, 80 den den Zielport. Ein Aufruf von http://localhost:8080 zeigt ob der Port-Forward funktioniert hat und wie erwartet unser Nginx antwortet:
$ curl http://localhost:8080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> ... <p><em>Thank you for using nginx.</em></p> </body> </html>
kubectl port-forward
bestätigt dabei den Request mit dem Output Handling connection for 8080
. Sollte es kubectl
aus irgendeinem Grund nicht möglich sein den Request weiterzuleiten, so wird eine entsprechende Fehlermledung ausgegeben.
Alternativ kann der lokale Port auch weggelassen werden, dann versucht kubectl
lokal den gleichen Port zu öffnen, auf den weitergeleitet werden soll. Je nach Port-Range benötigt man dazu allerdings lokale Root-Berechtigungen. Wer einen zufälligen, lokalen Port öffnen möchte kann dies anhand der Syntax :<target-port>
bewerkstelligen.
Wollen wir die Weiterleitung auf eine dedizierte IP-Adresse binden, dann kann dies mit Hilfe des Parameters --address
geschehen. Diese nimmt im Zweifelsfall auch mehrere IP-Adressen als Argument auf.
Anhand des diff
Befehls ist es möglich, die Abweichungen des IST mit dem SOLL Zustand anzuzeigen.
Hierzu nimmt der diff
Befehl den Parameter -f
auf. Das folgende Beispiel zeigt die diff
Ausgabe nach Aktualisieren unseres Nginx Deployment
YAML und vor dem apply
:
k diff -f nginx-deployment.yaml diff -u -N /tmp/LIVE-265469814/apps.v1.Deployment.test.nginx /tmp/MERGED-783806045/apps.v1.Deployment.test.nginx --- /tmp/LIVE-265469814/apps.v1.Deployment.test.nginx 2019-09-30 13:17:41.525469492 +0200 +++ /tmp/MERGED-783806045/apps.v1.Deployment.test.nginx 2019-09-30 13:17:41.541469584 +0200 @@ -6,7 +6,7 @@ kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app":"nginx","version":"v1"},"name":"nginx","namespace":"test"},"spec":{"replicas":2,"selector":{"matchLabels":{"app":"nginx"}},"strategy":{},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx","name":"nginx","resources":{}}]}}},"status":{}} creationTimestamp: "2019-09-26T16:04:43Z" - generation: 1 + generation: 2 labels: app: nginx comment: awebserver @@ -18,7 +18,7 @@ uid: 5a712cb7-e077-11e9-82d3-96000014cd46 spec: progressDeadlineSeconds: 600 - replicas: 2 + replicas: 5 revisionHistoryLimit: 10 selector: matchLabels: exit status 1
Wer Daten in oder aus einem laufenden Container kopieren möchte, dem steht mit kubectl cp
ein Befehl zur Hand, der genau diese Aufgabe erfüllt. Voraussetzung ist allerdings ein installiertes tar
innerhalb des Containers.
Wollen wir Beispielsweise die nginx.conf
aus unserem Nginx Container kopieren, dann würde der entsprechende Befehl wie folgt aussehen:
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-65f88748fd-lt2z5 1/1 Running 0 3d20h nginx-65f88748fd-mmwl5 1/1 Running 0 3d20h $ kubectl cp nginx-65f88748fd-lt2z5:/etc/nginx/nginx.conf nginx-65f88748fd-lt2z5_nginx.conf tar: Removing leading `/' from member names
Falls innerhalb des Zielpods mehrere Container betrieben werden, so muss mithilfe des Parameter -c <container-name>
der Zielcontainer angegeben werden.
Manchmal könnte bestimmte Aktionen erst durchgeführt werden, nachdem andere erfolgreich abgeschlossen wurden. Oder man möchte einfach nur informiert werden sobald eine spezifische Aktion abgeschlossen wurde. Dies kann mit Hilfe des Befehls wait
vollbracht werden.
wait
nimmt ein Set an Argumenten auf, die sowohl das Zielobjekt als auch den Zielzustand beschreiben.
Wollen wir beispielsweise darauf warten, dass sich einer unserer Pods im Zustand Ready
befindet, so sieht der Befehl wie folgt aus:
$ kubectl wait --for=condition=Ready pod/nginx-65f88748fd-lt2z5 pod/nginx-65f88748fd-lt2z5 condition met
Soll auf das endgültige Löschen eines Pods gewartet werden, so kann als Argument --for
der Wert delete
angegeben werden.
Dies ist insofern nützlich, als dass bei einem delete
nicht der Löschvorgang selber durchgeführt wird, sondern das enstprechende Objekt nur als zu löschen makiert wird.
kubectl wait --for=delete pod/nginx-65f88748fd-49qv2 --timeout=120s pod/nginx-65f88748fd-49qv2 condition met
Falls Sie Unterstützung beim Einsatz von Kubernetes benötigen, steht Ihnen unser Open Source Support Center zur Verfügung – Falls gewünscht auch 24 Stunden am Tag, an 365 Tagen im Jahr.
Wir freuen uns auf Ihre Kontaktaufnahme.
Kategorien: | HowTos |
---|---|
Tags: | kubectl Kubernetes Open Source |
über den Autor
Technischer Leiter
zur Person
Adrian ist seit 2013 Mitarbeiter der credativ GmbH. Als technischer Leiter des Cloud Infrastructure Teams beschäftigt er sich hauptsächlich mit der Planung, Realisierung und Betreuung verteilter Infrastrukturen wie zum Beispiel Kubernetes und Ceph sowie mit der Erarbeitung von Deployment-Strategien. Zuvor war er Teil des Datenbank-Teams bei credativ und war dort unter anderem mit dem Aufbau und der Verwaltung von hochverfügbaren Datenbank-Systemen betreut. Seit 2015 beteiligt er sich aktiv am Debian-Projekt.