Zum Inhalt

Control Plane Setup

Ziel

In diesem Projekt geht es um das Setup der Kubernetes Control Plane-Komponenten. Sie werden:

  • PKI-Zertifikate für API-Server, etcd-Client und Kubelet-Client erstellen
  • Kube-API-Server als Static Pod konfigurieren und starten
  • Admin-Kubeconfig für Cluster-Zugriff erstellen
  • Kube-Scheduler als Static Pod einrichten
  • Kube-Controller-Manager als Static Pod konfigurieren
  • Control Plane finalisieren und Nodes verwalten

Vorbereitung

  • Wechseln Sie ins workspace-Verzeichnis und erstellen Sie ein API-Server-Verzeichnis

    cd ~/workspace
    mkdir apiserver
    cd apiserver
    

Aufgabe 1: API-Server-Zertifikate erstellen

Zertifikat-Konfigurationsdateien

  • Erstellen Sie eine Template-Datei für das API-Server-Zertifikat

    cat > apiserver.cnf.tmpl << 'EOF'
    # apiserver.cnf
    [ req ]
    distinguished_name = dn
    req_extensions     = server_ext
    prompt             = no
    
    [ dn ]
    C  = DE
    O  = Corewire GmbH
    CN = kube-apiserver
    
    [ server_ext ]
    basicConstraints       = CA:FALSE
    keyUsage               = digitalSignature, keyEncipherment
    extendedKeyUsage       = serverAuth
    subjectAltName         = DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, IP:${IP_CONTROLPLANE_0}, IP:${IP_CONTROLPLANE_1}, IP:${IP_CONTROLPLANE_2}, IP:127.0.0.1, IP:10.96.0.1
    
    EOF
    
  • Erstellen Sie eine Konfigurationsdatei für das API-Server-etcd-Client-Zertifikat

    cat > apiserver-etcd-client.cnf << 'EOF'
    [ req ]
    distinguished_name = dn
    req_extensions     = client_ext
    prompt             = no
    
    [ dn ]
    C  = DE
    O  = Corewire GmbH
    CN = kube-apiserver-etcd-client
    
    [ client_ext ]
    basicConstraints       = CA:FALSE
    keyUsage               = digitalSignature, keyEncipherment
    extendedKeyUsage       = clientAuth
    EOF
    
  • Erstellen Sie eine Konfigurationsdatei für das API-Server-Kubelet-Client-Zertifikat

    cat > apiserver-kubelet-client.cnf << 'EOF'
    [ req ]
    distinguished_name = dn
    req_extensions     = client_ext
    prompt             = no
    
    [ dn ]
    C  = DE
    O  = kubeadm:cluster-admins
    CN = kube-apiserver-kubelet-client
    
    [ client_ext ]
    basicConstraints       = CA:FALSE
    keyUsage               = digitalSignature, keyEncipherment
    extendedKeyUsage       = clientAuth
    EOF
    

Script für Zertifikat-Generierung

  • Erstellen Sie ein Script zur automatischen Generierung aller API-Server-Zertifikate

    cat > generate-apiserver-certificates.sh << 'EOF'
    #!/bin/bash
    set -euo pipefail
    
    export IP_CONTROLPLANE_0=$(ssh -G controlplane-0 | awk '/^hostname /{print $2}')
    export IP_CONTROLPLANE_1=$(ssh -G controlplane-1 | awk '/^hostname /{print $2}')
    export IP_CONTROLPLANE_2=$(ssh -G controlplane-2 | awk '/^hostname /{print $2}')
    
    mkdir -p pki
    
    echo "### Generating apiserver.cnf from apiserver.cnf.tmpl"
    envsubst < apiserver.cnf.tmpl > apiserver.cnf
    
    echo "### Generating apiserver certificate and key"
    # Privaten Schlüssel erzeugen
    openssl genrsa -out pki/apiserver.key 4096
    
    # Certificate Signing Request erstellen
    openssl req -new -sha512 \
      -key "pki/apiserver.key" \
      -out "pki/apiserver.csr" \
      -config "apiserver.cnf"
    
    # Zertifikat erstellen
    openssl x509 -req -days 365 -sha512 \
      -in "pki/apiserver.csr" \
      -out "pki/apiserver.crt" \
      -CA "../pki/ca.crt" -CAkey "../pki/ca.key" -CAcreateserial \
      -copy_extensions copyall
    
    echo "### Generating apiserver-etcd-client certificate and key"
    # Privaten Schlüssel erzeugen
    openssl genrsa -out pki/apiserver-etcd-client.key 4096
    
    # Certificate Signing Request erstellen
    openssl req -new -sha512 \
      -key "pki/apiserver-etcd-client.key" \
      -out "pki/apiserver-etcd-client.csr" \
      -config "apiserver-etcd-client.cnf"
    
    # Zertifikat erstellen
    openssl x509 -req -days 365 -sha512 \
      -in "pki/apiserver-etcd-client.csr" \
      -out "pki/apiserver-etcd-client.crt" \
      -CA "../pki/etcd/ca.crt" -CAkey "../pki/etcd/ca.key" -CAcreateserial \
      -copy_extensions copyall
    
    echo "### Generating apiserver-kubelet-client certificate and key"
    # Privaten Schlüssel erzeugen
    openssl genrsa -out pki/apiserver-kubelet-client.key 4096
    
    # Certificate Signing Request erstellen
    openssl req -new -sha512 \
      -key "pki/apiserver-kubelet-client.key" \
      -out "pki/apiserver-kubelet-client.csr" \
      -config "apiserver-kubelet-client.cnf"
    
    # Zertifikat erstellen
    openssl x509 -req -days 365 -sha512 \
      -in "pki/apiserver-kubelet-client.csr" \
      -out "pki/apiserver-kubelet-client.crt" \
      -CA "../pki/ca.crt" -CAkey "../pki/ca.key" -CAcreateserial \
      -copy_extensions copyall
    
    echo "### Generating SA key and public key"
    # Service Account Schlüssel erzeugen (4096 Bit)
    openssl genrsa -out pki/sa.key 4096
    
    # Öffentlichen Schlüssel aus dem privaten extrahieren
    openssl rsa -in pki/sa.key -pubout -out pki/sa.pub
    EOF
    
    chmod +x generate-apiserver-certificates.sh
    
  • Führen Sie das Script aus

    bash generate-apiserver-certificates.sh
    
  • Kopieren Sie die Zertifikate auf alle Control Plane Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2; do
        echo "## Copying certificates to ${instance}"
        scp pki/* ${instance}:/etc/kubernetes/pki/
    done
    

Aufgabe 2: API-Server Static Pod Manifest

  • Erstellen Sie das API-Server Static Pod Manifest

    cat > kube-apiserver.yaml << 'EOF'
    apiVersion: v1
    kind: Pod
    metadata:
      name: kube-apiserver
      namespace: kube-system
      labels:
        component: kube-apiserver
    spec:
      hostNetwork: true
      containers:
      - name: kube-apiserver
        image: registry.k8s.io/kube-apiserver:v1.32.7
        command:
        - kube-apiserver
        - --allow-privileged=true
        - --service-cluster-ip-range=10.96.0.0/12
        - --enable-bootstrap-token-auth=true
        - --authorization-mode=Node,RBAC
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    
        # Etcd-Config
        - --etcd-servers=https://127.0.0.1:2379
        - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
        - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
        - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
    
        # Server-Zertifikat für SSL/TLS
        - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
        - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    
        # Root-Zertifikat für Authentifizierung
        - --client-ca-file=/etc/kubernetes/pki/ca.crt
    
        # Client-Zertifikat für Interaktion mit Kubelet
        - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
        - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
    
        # SA Zertifikate für das erstellen von Service Accounts
        - --service-account-issuer=https://kubernetes.default.svc.cluster.local
        - --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
        - --service-account-key-file=/etc/kubernetes/pki/sa.pub
        volumeMounts:
        - name: apiserver-certs
          mountPath: /etc/kubernetes/pki
      volumes:
      - name: apiserver-certs
        hostPath:
          path: /etc/kubernetes/pki
    EOF
    
  • Kopieren Sie das Manifest auf alle Control Plane Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2; do
        echo "## Copying kube-apiserver manifest to ${instance}"
        scp kube-apiserver.yaml ${instance}:/etc/kubernetes/manifests/
    done
    

Aufgabe 3: Admin-Kubeconfig erstellen

  • Wechseln Sie ins parent-Verzeichnis und erstellen Sie ein admin-config-Verzeichnis

    cd ..
    mkdir admin-config
    cd admin-config
    

Admin-Zertifikat erstellen

  • Erstellen Sie eine Konfigurationsdatei für das Admin-Zertifikat

    cat > admin.cnf << 'EOF'
    [ req ]
    distinguished_name = dn
    req_extensions     = req_ext
    prompt             = no
    
    [ dn ]
    CN = kubernetes-admin
    O  = system:masters
    
    [ req_ext ]
    keyUsage = digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth
    EOF
    
  • Generieren Sie Schlüssel und Zertifikat für den Admin

    # Privaten Schlüssel erzeugen
    openssl genrsa -out admin.key 4096
    
    # Certificate Signing Request erstellen
    openssl req -new -sha512 \
      -key "admin.key" \
      -out "admin.csr" \
      -config "admin.cnf"
    
    # Zertifikat erstellen
    openssl x509 -req -days 365 -sha512 \
      -in "admin.csr" \
      -out "admin.crt" \
      -CA "../pki/ca.crt" -CAkey "../pki/ca.key" -CAcreateserial \
      -copy_extensions copyall
    

Admin-Kubeconfig konfigurieren

  • Ermitteln Sie die IP-Adresse des ersten Control Plane Nodes

    export API_SERVER_IP=$(ssh -G controlplane-0 | awk '/^hostname /{print $2}')
    echo "API Server IP: $API_SERVER_IP"
    
  • Erstellen Sie die admin.conf Kubeconfig-Datei

    # Cluster konfigurieren
    kubectl config set-cluster kubernetes \
      --server="https://${API_SERVER_IP}:6443" \
      --certificate-authority=../pki/ca.crt \
      --embed-certs=true \
      --kubeconfig=admin.conf
    
    # Credentials konfigurieren
    kubectl config set-credentials kubernetes-admin \
      --client-certificate=./admin.crt \
      --client-key=./admin.key \
      --embed-certs=true \
      --kubeconfig=admin.conf
    
    # Context konfigurieren
    kubectl config set-context kubernetes-admin@kubernetes \
      --cluster=kubernetes \
      --user=kubernetes-admin \
      --kubeconfig=admin.conf
    
    # Context aktivieren
    kubectl config use-context kubernetes-admin@kubernetes \
      --kubeconfig=admin.conf
    
  • Kopieren Sie die admin.conf in Ihr kubectl-Konfigurationsverzeichnis

    mkdir -p ~/.kube
    cp admin.conf ~/.kube/config
    

API-Server-Verbindung testen

  • Testen Sie die Verbindung zum API-Server

    # Nodes anzeigen
    kubectl get nodes
    
    # Pods in allen Namespaces anzeigen
    kubectl get pods -A
    

Aufgabe 4: Kube-Scheduler einrichten

  • Wechseln Sie ins parent-Verzeichnis und erstellen Sie ein Scheduler-Verzeichnis

    cd ..
    mkdir kube-scheduler-setup
    cd kube-scheduler-setup
    

Scheduler-Zertifikat erstellen

  • Erstellen Sie eine Konfigurationsdatei für das Scheduler-Zertifikat

    cat > scheduler.cnf << 'EOF'
    [ req ]
    distinguished_name = dn
    req_extensions     = req_ext
    prompt             = no
    
    [ dn ]
    CN = system:kube-scheduler
    
    [ req_ext ]
    keyUsage = digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth
    EOF
    
  • Generieren Sie Schlüssel und Zertifikat für den Scheduler

    # Privaten Schlüssel erzeugen
    openssl genrsa -out scheduler.key 4096
    
    # Certificate Signing Request erstellen
    openssl req -new -sha512 \
      -key "scheduler.key" \
      -out "scheduler.csr" \
      -config "scheduler.cnf"
    
    # Zertifikat erstellen
    openssl x509 -req -days 365 -sha512 \
      -in "scheduler.csr" \
      -out "scheduler.crt" \
      -CA "../pki/ca.crt" -CAkey "../pki/ca.key" -CAcreateserial \
      -copy_extensions copyall
    

Scheduler-Kubeconfig erstellen

  • Erstellen Sie die Kubeconfig-Datei für den Scheduler

    # Cluster konfigurieren
    kubectl config set-cluster kubernetes \
      --certificate-authority=../pki/ca.crt \
      --server=https://127.0.0.1:6443 \
      --kubeconfig=scheduler.conf \
      --embed-certs=true
    
    # Credentials konfigurieren
    kubectl config set-credentials system:kube-scheduler \
      --client-certificate=scheduler.crt \
      --client-key=scheduler.key \
      --kubeconfig=scheduler.conf \
      --embed-certs=true
    
    # Context konfigurieren
    kubectl config set-context default \
      --cluster=kubernetes \
      --user=system:kube-scheduler \
      --kubeconfig=scheduler.conf
    
    # Context aktivieren
    kubectl config use-context default \
      --kubeconfig=scheduler.conf
    
  • Kopieren Sie die Kubeconfig auf alle Control Plane Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2; do
        echo "## Copying kube-scheduler kubeconfig to ${instance}"
        scp scheduler.conf ${instance}:/etc/kubernetes/scheduler.conf
    done
    

Scheduler Static Pod Manifest

  • Erstellen Sie das Scheduler Static Pod Manifest

    cat > kube-scheduler.yaml << 'EOF'
    apiVersion: v1
    kind: Pod
    metadata:
      name: kube-scheduler
      namespace: kube-system
      labels:
        component: kube-scheduler
    spec:
      hostNetwork: true
      containers:
      - name: kube-scheduler
        image: registry.k8s.io/kube-scheduler:v1.32.7
        command:
        - kube-scheduler
        - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
        - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
        - --bind-address=127.0.0.1
        - --kubeconfig=/etc/kubernetes/scheduler.conf
        - --leader-elect=true
        volumeMounts:
        - mountPath: /etc/kubernetes/scheduler.conf
          name: kubeconfig
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/scheduler.conf
          type: FileOrCreate
        name: kubeconfig
    EOF
    
  • Kopieren Sie das Manifest auf alle Control Plane Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2; do
        echo "## Copying kube-scheduler manifest to ${instance}"
        scp kube-scheduler.yaml ${instance}:/etc/kubernetes/manifests/
    done
    

Aufgabe 5: Kube-Controller-Manager einrichten

  • Wechseln Sie ins parent-Verzeichnis und erstellen Sie ein Controller-Manager-Verzeichnis

    cd ..
    mkdir kube-controller-manager-setup
    cd kube-controller-manager-setup
    

Controller-Manager-Zertifikat erstellen

  • Erstellen Sie eine Konfigurationsdatei für das Controller-Manager-Zertifikat

    cat > controller.cnf << 'EOF'
    [ req ]
    distinguished_name = dn
    req_extensions     = req_ext
    prompt             = no
    
    [ dn ]
    CN = system:kube-controller-manager
    
    [ req_ext ]
    keyUsage = digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth
    EOF
    
  • Generieren Sie Schlüssel und Zertifikat für den Controller Manager

    # Privaten Schlüssel erzeugen
    openssl genrsa -out controller.key 4096
    
    # Certificate Signing Request erstellen
    openssl req -new -sha512 \
      -key "controller.key" \
      -out "controller.csr" \
      -config "controller.cnf"
    
    # Zertifikat erstellen
    openssl x509 -req -days 365 -sha512 \
      -in "controller.csr" \
      -out "controller.crt" \
      -CA "../pki/ca.crt" -CAkey "../pki/ca.key" -CAcreateserial \
      -copy_extensions copyall
    

Controller-Manager-Kubeconfig erstellen

  • Erstellen Sie die Kubeconfig-Datei für den Controller Manager

    # Cluster konfigurieren
    kubectl config set-cluster kubernetes \
      --certificate-authority=../pki/ca.crt \
      --server=https://127.0.0.1:6443 \
      --kubeconfig=controller-manager.conf \
      --embed-certs=true
    
    # Credentials konfigurieren
    kubectl config set-credentials system:kube-controller-manager \
      --client-certificate=controller.crt \
      --client-key=controller.key \
      --kubeconfig=controller-manager.conf \
      --embed-certs=true
    
    # Context konfigurieren
    kubectl config set-context default \
      --cluster=kubernetes \
      --user=system:kube-controller-manager \
      --kubeconfig=controller-manager.conf
    
    # Context aktivieren
    kubectl config use-context default \
      --kubeconfig=controller-manager.conf
    
  • Kopieren Sie die Kubeconfig auf alle Control Plane Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2; do
        echo "## Copying kube-controller-manager kubeconfig to ${instance}"
        scp controller-manager.conf ${instance}:/etc/kubernetes/controller-manager.conf
    done
    

Controller-Manager Static Pod Manifest

  • Erstellen Sie das Controller-Manager Static Pod Manifest

    cat > kube-controller-manager.yaml << 'EOF'
    apiVersion: v1
    kind: Pod
    metadata:
      name: kube-controller-manager
      namespace: kube-system
      labels:
        component: kube-controller-manager
    spec:
      hostNetwork: true
      containers:
      - name: kube-controller-manager
        image: registry.k8s.io/kube-controller-manager:v1.32.7
        command:
        - kube-controller-manager
        - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
        - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
        - --bind-address=127.0.0.1
        - --kubeconfig=/etc/kubernetes/controller-manager.conf
        - --leader-elect=true
        - --use-service-account-credentials=true
        - --service-account-private-key-file=/etc/kubernetes/pki/sa.key
        - --root-ca-file=/etc/kubernetes/pki/ca.crt
        volumeMounts:
        - mountPath: /etc/kubernetes/pki
          name: k8s-certs
          readOnly: true
        - mountPath: /etc/kubernetes/controller-manager.conf
          name: kubeconfig
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/pki
          type: DirectoryOrCreate
        name: k8s-certs
      - hostPath:
          path: /etc/kubernetes/controller-manager.conf
          type: FileOrCreate
        name: kubeconfig
    EOF
    
  • Kopieren Sie das Manifest auf alle Control Plane Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2; do
        echo "## Copying kube-controller-manager manifest to ${instance}"
        scp kube-controller-manager.yaml ${instance}:/etc/kubernetes/manifests/
    done
    

Aufgabe 6: Control Plane finalisieren

ClusterRoleBinding erstellen

  • Erstellen Sie eine ClusterRoleBinding für die API-Server-Kubelet-Kommunikation

    kubectl create clusterrolebinding kube-apiserver-to-kubelet \
      --clusterrole=system:kubelet-api-admin \
      --user=kube-apiserver-kubelet-client
    

Control Plane Nodes mit Taint versehen

  • Tainten Sie die Control Plane Nodes, damit keine regulären Workloads darauf gescheduled werden

    for instance in controlplane-0 controlplane-1 controlplane-2; do
        echo "## Tainting node ${instance}"
        kubectl taint node ${instance} node-role.kubernetes.io/control-plane:NoSchedule
    done
    

Aufgabe 7: Cluster-Status überprüfen

  • Überprüfen Sie den Status aller Nodes

    kubectl get nodes -o wide
    
  • Überprüfen Sie alle Control Plane Pods

    kubectl get pods -n kube-system
    
  • Überprüfen Sie die Cluster-Informationen

    kubectl cluster-info
    
  • Testen Sie die Funktionalität mit einem Test-Pod

    # Test-Pod erstellen
    kubectl run test-pod --image=nginx --restart=Never
    
    # Pod-Status überprüfen
    kubectl get pods
    
    # Pod-Details anzeigen
    kubectl describe pod test-pod
    
    # Test-Pod löschen
    kubectl delete pod test-pod
    

Aufgabe 8: Troubleshooting (Optional)

  • Überprüfen Sie die Static Pod-Logs auf einem Control Plane Node

    ssh controlplane-0 "journalctl -u kubelet -f"
    
  • Überprüfen Sie die API-Server-Logs

    kubectl logs -n kube-system kube-apiserver-controlplane-0
    
  • Überprüfen Sie die Scheduler-Logs

    kubectl logs -n kube-system kube-scheduler-controlplane-0
    
  • Überprüfen Sie die Controller-Manager-Logs

    kubectl logs -n kube-system kube-controller-manager-controlplane-0
    

Ausblick

Nach Abschluss dieser Aufgabe haben Sie eine vollständige Control Plane mit allen wichtigen Komponenten aufgebaut. Der Cluster ist bereit für die Installation von CNI-Plugins und weiteren Add-ons. Sie können nun beginnen, Workloads auf dem Cluster zu deployen.

Glückwunsch!

Sie haben erfolgreich einen Kubernetes-Cluster manuell aufgebaut und verstehen nun die grundlegenden Komponenten und deren Interaktionen. Diese Kenntnisse helfen Ihnen beim Troubleshooting und bei der Administration von Kubernetes