15 Understand multi-container Pod design patterns

MultiContainerPod MultiContainerPod Communication

15.1 Eigenschaften von Multi-Container Pods in Kubernetes

15.2 Gemeinsame Namespaces in einem Pod

Container in einem Pod teilen sich einige (Linux-)Namespaces, was bedeutet, dass sie bestimmte Systemressourcen gemeinsam nutzen.

15.2.1 Gemeinsame Namespaces

Namespace Typ Beschreibung Mandatorisch/Optional
Netzwerk-Namespace Alle Container in einem Pod teilen sich eine IP-Adresse und Portraum, können über localhost oder Standard-IPC-Kanäle kommunizieren. Mandatorisch
IPC-Namespace Ermöglicht Kommunikation zwischen den Containern eines Pods über gemeinsame Speicherbereiche oder andere IPC-Mechanismen. Mandatorisch
UTS-Namespace Isoliert systemrelevante Informationen, die von uname zurückgegeben werden. Mandatorisch
PID-Namespace Erlaubt es Containern, Prozesse in demselben Pod zu sehen und Signale zu senden. Optional
Mount-Namespace Ermöglicht es Containern, Dateisystem-Mounts zu teilen. Optional

Die gemeinsame Nutzung von Namespaces ermöglicht eine engere Kopplung und Kommunikation zwischen den Containern in einem Pod und kann die Entwicklung und Verwaltung von Anwendungen vereinfachen.

15.3 Nutzung von Multi-Container Pods

15.3.1 Beispiele und Muster

15.3.2 Hinweis

Die Verwendung von Multi-Container Pods in Kubernetes sollte mit Sorgfalt erfolgen, da sie die Komplexität der Anwendungsarchitektur erhöhen können.

15.4 Sidecar Pattern in Kubernetes

Das Sidecar-Muster ist ein Entwurfsmuster, das in Kubernetes verwendet wird, um zusätzliche Funktionalität oder Dienste zu einem Hauptcontainer hinzuzufügen, indem ein sekundärer Container, der als “Sidecar” bezeichnet wird, im gleichen Pod wie der Hauptcontainer deployed wird.

15.4.1 Beispiel: Sidecar-Muster mit Pod-Manifest

In diesem Beispiel erzeugt der Hauptcontainer log-generator jede Sekunde Einträge in einer Log-Datei. Der Sidecar-Container log-reader liest die Log-Datei und gibt ihre Inhalte aus.

apiVersion: v1
kind: Pod
metadata:
  name: log-app
spec:
  volumes:
    - name: log-volume
      emptyDir: {}
  containers:
    - name: log-generator
      image: busybox
      command: ["/bin/sh"]
      args: ["-c", "while true; do date >> /var/log/app.log; sleep 1; done"]
      volumeMounts:
        - name: log-volume
          mountPath: /var/log
    - name: log-reader
      image: busybox
      command: ["/bin/sh"]
      args: ["-c", "tail -f /var/log/app.log"]
      volumeMounts:
        - name: log-volume
          mountPath: /var/log

15.5 Ambassador Pattern in Kubernetes

Das Ambassador-Muster ist ein Entwurfsmuster, das verwendet wird, um den Zugang zu anderen Diensten zu vereinfachen, indem ein spezieller Container, der als “Ambassador” bezeichnet wird, im gleichen Pod wie der Hauptcontainer eingesetzt wird. Der Ambassador-Container handelt als Proxy für den Hauptcontainer und kann Anforderungen an externe Dienste weiterleiten oder Antworten von diesen Diensten zurück zum Hauptcontainer leiten. Dieses Muster wird oft verwendet, um die Umgebungsabhängigkeiten einer Anwendung zu entkoppeln und die Kommunikation mit externen Diensten zu erleichtern, wie zum Beispiel mit Caching-Servern wie Redis oder Memcached.

15.5.1 Beispiel Manifest für das Ambassador-Muster

Im folgenden Beispiel wird ein Ambassador-Container verwendet, um eine Redis-Client-Anwendung mit zwei Redis-Servern zu verbinden. Der Ambassador-Container verwendet Twemproxy, um Anfragen an die Redis-Server weiterzuleiten.

apiVersion: v1
kind: Pod
metadata:
  name: ambassador-example
spec:
  containers:
  - name: redis-client
    image: redis
  - name: ambassador
    image: malexer/twemproxy
    env:
    - name: REDIS_SERVERS
      value: redis-st-0.redis-svc.default.svc.cluster.local:6379:1 \
    redis-st-1.redis-svc.default.svc.cluster.local:6379:1
    ports:
    - containerPort: 6380

---
apiVersion: v1
kind: Service
metadata:
  name: redis-svc
  labels:
    app: redis
spec:
  ports:
  - port: 6379
    name: redis-port
  clusterIP: None
  selector:
    app: redis

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-st
spec:
  serviceName: "redis-svc"
  replicas: 2
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis
        ports:
        - containerPort: 6379
          name: redis
        volumeMounts:
        - name: redis-data
          mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: redis-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

In diesem Beispiel werden zwei Pods definiert:

  1. Der Anwendungspod: Dieser Pod führt das Redis-Image aus, wird aber als Client für andere Redis-Server verwendet.
  2. Der Ambassador-Pod: Dieser Container führt Twemproxy aus und benötigt die Redis-Instanzen als Umgebungsvariablen, um Anfragen an die richtigen Server weiterzuleiten.

15.6 Adapter Pattern in Kubernetes

Das Adapter-Muster in Kubernetes wird verwendet, um die Kommunikation zwischen Containern zu standardisieren, indem es die Ausgabe einer Anwendung in ein gewünschtes Format für Logging, Monitoring oder andere Zwecke umwandelt. Adapter-Container können verwendet werden, um die Ausgabe von Anwendungen zu transformieren, ohne den Code der Anwendung ändern zu müssen.

15.6.1 Beispiel für das Adapter-Muster

In dem folgenden Beispiel wird ein Adapter-Container mit einem Nginx-Webserver verwendet, um die Ausgabe des Nginx-Statusendpunkts in ein für Prometheus geeignetes Format zu transformieren.

15.6.1.1 ConfigMap für Nginx

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  default.conf: |
    server {
      listen       80;
      server_name  localhost;
      location / {
          root   /usr/share/nginx/html;
          index  index.html index.htm;
      }
      error_page   500 502 503 504  /50x.html;
      location = /50x.html {
          root   /usr/share/nginx/html;
      }
      location /nginx_status {
        stub_status;
        allow 127.0.0.1;  #only allow requests from localhost
        deny all;   #deny all other hosts
      }
    }

15.6.1.2 Pod-Manifest

apiVersion: v1
kind: Pod
metadata:
  name: webserver
spec:
  volumes:
  - name: nginx-conf
    configMap:
      name: nginx-conf
      items:
      - key: default.conf
        path: default.conf
  containers:
  - name: webserver
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - mountPath: /etc/nginx/conf.d
      name: nginx-conf
      readOnly: true
  - name: adapter
    image: nginx/nginx-prometheus-exporter:0.4.2
    args: ["-nginx.scrape-uri","http://localhost/nginx_status"]
    ports:
    - containerPort: 9113

In diesem Szenario wird zunächst eine ConfigMap erstellt, um die Nginx-Konfiguration zu speichern und den /nginx_status-Endpunkt zu aktivieren, der die Diagnoseinformationen von Nginx liefert. Anschließend wird ein Pod definiert, der zwei Container enthält: den Nginx-Container und den Adapter-Container. Der Adapter-Container verwendet den nginx/nginx-prometheus-exporter, um die von Nginx bereitgestellten Metriken in ein für Prometheus geeignetes Format zu transformieren.

15.7 Init Container in Kubernetes Pods

InitContainer

15.7.1 Überblick

Init Container sind in Kubernetes dafür zuständig, notwendige Vorbedingungen oder Einrichtungsschritte zu erfüllen, bevor die Hauptcontainer eines Pods ausgeführt werden. Sie eignen sich insbesondere für vorbereitende Aktionen wie das Überprüfen der Verfügbarkeit von Services oder das Anwenden von Konfigurationen.

15.7.2 Funktionsweise

15.7.2.1 Beispiel: Init Container in YAML

apiVersion: v1
kind: Pod
metadata:
  name: init-example
spec:
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  containers:
  - name: myservice
    image: myimage

15.7.2.2 Restart bei Fehlern

Wenn ein Init Container fehlschlägt, wird der Pod neu gestartet, unabhängig von der RestartPolicy, die auf Never gesetzt sein kann.