Zum Inhalt

Node Setup und Kubelet

Ziel

In diesem Projekt geht es um das Setup der Kubernetes-Nodes und die Installation von Kubelet. Sie werden:

  • Container-Runtime (runc, containerd) auf allen Nodes installieren
  • CNI-Plugins für Netzwerk-Funktionalität einrichten
  • PKI-Zertifikate für Kubelet-Authentifizierung erstellen
  • Kubelet konfigurieren und als systemd-Service starten
  • Den Status aller Komponenten überprüfen

Vorbereitung: Multi-Node-Script

  • Erstellen Sie ein Arbeitsverzeichnis und wechseln Sie hinein

    cd ~/workspace
    mkdir node-setup
    cd node-setup
    
  • Erstellen Sie ein Helper-Script für die Ausführung auf allen Nodes

    cat > run-on-nodes.sh << 'EOF'
    #!/bin/bash
    set -e
    servers=("controlplane-0" "controlplane-1" "controlplane-2" "worker-0" "worker-1")
    script_path="$1"
    
    for server in "${servers[@]}"; do
      echo "Running script on $server"
      ssh root@"$server" 'bash -s' < "$script_path"
    done
    EOF
    
    chmod +x run-on-nodes.sh
    

Aufgabe 1: Container-Runtime installieren

Runc installieren

  • Erstellen Sie ein Script zur Installation von runc

    cat > install-runc.sh << 'EOF'
    curl -L \
      https://github.com/opencontainers/runc/releases/download/v1.3.0/runc.amd64 \
      -o /usr/local/bin/runc
    chmod +x /usr/local/bin/runc
    echo
    echo "###"
    echo "### Installed runc on ${HOSTNAME}. Version:"
    runc --version
    echo
    echo
    EOF
    
  • Führen Sie das Script auf allen Nodes aus

    ./run-on-nodes.sh install-runc.sh
    

Containerd installieren

  • Erstellen Sie ein Script zur Installation von containerd mit systemd-Integration

    cat > install-containerd.sh << 'EOF'
    # Install containerd
    curl -L \
      https://github.com/containerd/containerd/releases/download/v1.7.28/containerd-1.7.28-linux-amd64.tar.gz \
      -o /tmp/containerd.tar.gz
    tar -xvf /tmp/containerd.tar.gz -C /usr/local
    echo
    echo "###"
    echo "### Installed containerd on ${HOSTNAME}. Version:"
    containerd --version
    echo
    
    # Containerd Systemd unit file
    mkdir -p /usr/local/lib/systemd/system/
    wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -O /usr/local/lib/systemd/system/containerd.service
    echo "### Installed containerd systemd unit file."
    echo
    
    # Containerd Config File
    mkdir -p /etc/containerd
    containerd config default | sed 's/SystemdCgroup = false/SystemdCgroup = true/' > /etc/containerd/config.toml
    echo "### Created containerd config file."
    echo
    
    systemctl daemon-reload
    systemctl enable --now containerd
    echo
    echo "###"
    echo "### Enabled containerd on ${HOSTNAME}."
    echo
    echo "### Containerd Status on Node $HOSTNAME"
    systemctl status containerd | grep -oP "(?<=Active: )(.*)"
    echo
    
    # Install CRICTL for container debugging
    VERSION="v1.30.0"
    curl -L https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-${VERSION}-linux-amd64.tar.gz --output crictl-${VERSION}-linux-amd64.tar.gz
    tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
    rm -f crictl-$VERSION-linux-amd64.tar.gz
    
    echo
    echo "###"
    echo "### Installed crictl on ${HOSTNAME}. Version:"
    crictl --version
    echo
    echo
    EOF
    
  • Führen Sie das Script auf allen Nodes aus

    ./run-on-nodes.sh install-containerd.sh
    

CNI-Plugins installieren

  • Erstellen Sie ein Script zur Installation der CNI-Plugins

    cat > install-cni-plugins.sh << 'EOF'
    mkdir -p /opt/cni/bin
    curl -L \
    https://github.com/containernetworking/plugins/releases/download/v1.6.2/cni-plugins-linux-amd64-v1.6.2.tgz \
      -o /tmp/cni-plugins.tgz
    tar -xvf  /tmp/cni-plugins.tgz -C /opt/cni/bin
    echo
    echo "###"
    echo "### Installed Network Plugins on ${HOSTNAME}."
    echo
    echo
    EOF
    
  • Führen Sie das Script auf allen Nodes aus

    ./run-on-nodes.sh install-cni-plugins.sh
    

Aufgabe 2: PKI für Kubelet einrichten

Root-CA erstellen

  • Wechseln Sie in ein PKI-Verzeichnis

    cd ../
    mkdir pki
    cd pki
    
  • Erstellen Sie eine CA-Konfigurationsdatei

    cat > ca.cnf << 'EOF'
    # ca.cnf
    [ req ]
    distinguished_name = dn
    x509_extensions    = ca_ext
    prompt             = no
    
    [ dn ]
    C  = DE
    O  = Corewire GmbH
    CN = Corewire Kubernetes Root CA
    
    [ ca_ext ]
    basicConstraints       = CA:true
    # Allows:
    #   keyCertSign = Signieren von Zertifikaten
    #   cRLSign = Signieren von Sperrlisten
    keyUsage               = keyCertSign, cRLSign
    EOF
    
  • Erstellen Sie das Root-Zertifikat

    # Privaten Schlüssel erzeugen
    openssl genrsa -out ca.key 4096
    
    # Root-Zertifikat erstellen
    openssl req -new -x509 -sha512 -days 3650 \
      -key ca.key \
      -out ca.crt \
      -config ca.cnf
    
    # Details anzeigen
    openssl x509 -in ca.crt -text -noout
    
  • Kopieren Sie das CA-Zertifikat auf alle Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2 worker-0 worker-1; do
        echo "## Copying CA cert to ${instance}"
        ssh ${instance} "mkdir -p /etc/kubernetes/pki"
        scp ./ca.crt ${instance}:/etc/kubernetes/pki/ca.crt
    done
    

Aufgabe 3: Kubelet-Zertifikate und Kubeconfig erstellen

  • Wechseln Sie zurück ins node-setup Verzeichnis und erstellen Sie ein config-Unterverzeichnis

    cd ../node-setup
    mkdir config
    cd config
    

Template-Dateien erstellen

  • Erstellen Sie ein Template für die Kubelet-Client-Zertifikate

    cat > kubelet-client.cnf.tmpl << 'EOF'
    # kubelet-client.cnf
    [ req ]
    distinguished_name = dn
    req_extensions     = client_ext
    prompt             = no
    
    [ dn ]
    CN = system:node:${NODE_NAME}
    O = system:nodes
    
    [ client_ext ]
    basicConstraints       = CA:FALSE
    keyUsage               = digitalSignature, keyEncipherment
    extendedKeyUsage       = clientAuth
    EOF
    
  • Erstellen Sie ein Template für die Kubelet-Kubeconfig

    cat > kubelet-kubeconfig.yaml.tmpl << 'EOF'
    apiVersion: v1
    clusters:
    - cluster:
        certificate-authority: /etc/kubernetes/pki/ca.crt
        server: https://${CONTROLPLANE_IP}:6443
      name: kubernetes
    contexts:
    - context:
        cluster: kubernetes
        user: system:node:${NODE_NAME}
      name: default
    current-context: default
    kind: Config
    preferences: {}
    users:
    - name: system:node:${NODE_NAME}
      user:
        client-certificate: /etc/kubernetes/pki/kubelet-client.crt
        client-key: /etc/kubernetes/pki/kubelet-client.key
    EOF
    

Script für Zertifikat-Generierung

  • Erstellen Sie ein Script, das für jeden Node Zertifikate und Kubeconfig generiert

    cat > generate-kubelet-certs-and-kubeconfig.sh << 'EOF'
    #!/bin/bash
    
    set -euo pipefail
    
    mkdir -p ./kubelet
    export CA_PATH=../../pki
    
    for instance in controlplane-0 controlplane-1 controlplane-2 worker-0 worker-1; do
        echo "## Running for ${instance}"
        echo "### Generating key"
        openssl genrsa -out ./kubelet/${instance}.key 4096
        echo "### Generating CNF"
        export NODE_NAME=${instance}
        cat ./kubelet-client.cnf.tmpl | envsubst > ./kubelet/${instance}.cnf
        echo "### Generating CSR"
        openssl req -new -sha512 \
            -key "./kubelet/${instance}.key" \
            -out "./kubelet/${instance}.csr" \
            -config "./kubelet/${instance}.cnf"
        echo "### Generating Cert"
        openssl x509 -req -days 365 -sha512 \
            -in "./kubelet/${instance}.csr" \
            -out "./kubelet/${instance}.crt" \
            -CA "${CA_PATH}/ca.crt" -CAkey "${CA_PATH}/ca.key" -CAcreateserial \
            -copy_extensions copyall
        echo "### Generating Kubeconfig"
        if [[ ${instance} == controlplane-* ]]
        then
            echo "#### Setting CONTROLPLANE_IP to 127.0.0.1 for controlplane nodes"
            export CONTROLPLANE_IP=127.0.0.1
        else
            export CONTROLPLANE_IP=$(ssh -G controlplane-0 | awk '/^hostname /{print $2}')
            echo "#### Setting CONTROLPLANE_IP to controlplane-0 (${CONTROLPLANE_IP}) for worker nodes"
        fi
        cat ./kubelet-kubeconfig.yaml.tmpl | envsubst > ./kubelet/${instance}-kubeconfig.yaml
        echo "### Copying certs and keys to ${instance}"
        scp ./kubelet/${instance}.crt ${instance}:/etc/kubernetes/pki/kubelet-client.crt
        scp ./kubelet/${instance}.key ${instance}:/etc/kubernetes/pki/kubelet-client.key
        echo "### Copying kubeconfig to ${instance}"
        scp ./kubelet/${instance}-kubeconfig.yaml ${instance}:/etc/kubernetes/kubelet-kubeconfig.yaml
    done
    EOF
    
    chmod +x generate-kubelet-certs-and-kubeconfig.sh
    
  • Führen Sie das Script aus

    bash generate-kubelet-certs-and-kubeconfig.sh
    

Aufgabe 4: Kubelet-Konfiguration

Kubelet-Config erstellen

  • Erstellen Sie eine Kubelet-Konfigurationsdatei

    cat > kubelet-config.yaml << 'EOF'
    apiVersion: kubelet.config.k8s.io/v1beta1
    authentication:
      anonymous:
        enabled: false
      webhook:
        cacheTTL: 0s
        enabled: true
      x509:
        clientCAFile: /etc/kubernetes/pki/ca.crt
    authorization:
      mode: Webhook
      webhook:
        cacheAuthorizedTTL: 0s
        cacheUnauthorizedTTL: 0s
    cgroupDriver: systemd
    clusterDNS:
    - 10.96.0.10
    clusterDomain: cluster.local
    containerRuntimeEndpoint: unix:///var/run/containerd/containerd.sock
    cpuManagerReconcilePeriod: 0s
    crashLoopBackOff: {}
    evictionPressureTransitionPeriod: 0s
    fileCheckFrequency: 0s
    healthzBindAddress: 127.0.0.1
    healthzPort: 10248
    httpCheckFrequency: 0s
    imageMaximumGCAge: 0s
    imageMinimumGCAge: 0s
    kind: KubeletConfiguration
    logging:
      flushFrequency: 0
      options:
        json:
          infoBufferSize: "0"
        text:
          infoBufferSize: "0"
      verbosity: 0
    memorySwap: {}
    nodeStatusReportFrequency: 0s
    nodeStatusUpdateFrequency: 0s
    resolvConf: /run/systemd/resolve/resolv.conf
    rotateCertificates: true
    runtimeRequestTimeout: 0s
    shutdownGracePeriod: 0s
    shutdownGracePeriodCriticalPods: 0s
    staticPodPath: /etc/kubernetes/manifests
    streamingConnectionIdleTimeout: 0s
    syncFrequency: 0s
    volumeStatsAggPeriod: 0s
    EOF
    
  • Kopieren Sie die Konfiguration auf alle Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2 worker-0 worker-1; do
        echo "## Copying kubelet config to ${instance}"
        scp ./kubelet-config.yaml ${instance}:/etc/kubernetes/kubelet-config.yaml
    done
    

Systemd Unit File erstellen

  • Erstellen Sie ein systemd Unit File für den Kubelet

    cat > kubelet.service << 'EOF'
    [Unit]
    Description=kubelet
    Documentation=https://github.com/kubernetes/kubernetes
    After=containerd.service
    Requires=containerd.service
    
    [Service]
    ExecStart=/usr/bin/kubelet \
      --config=/etc/kubernetes/kubelet-config.yaml \
      --kubeconfig=/etc/kubernetes/kubelet-kubeconfig.yaml \
      --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \
      --v=2
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target
    EOF
    
  • Kopieren Sie das Unit File auf alle Nodes

    for instance in controlplane-0 controlplane-1 controlplane-2 worker-0 worker-1; do
        echo "## Copying kubelet systemd unit file to ${instance}"
        scp ./kubelet.service ${instance}:/etc/systemd/system/kubelet.service
    done
    

Aufgabe 5: Kubelet installieren und starten

  • Wechseln Sie zurück ins node-setup Verzeichnis

    cd ..
    
  • Erstellen Sie ein Script zur Installation des Kubelet

    cat > install-kubelet.sh << 'EOF'
    apt-get update
    apt-get install -y apt-transport-https ca-certificates curl gpg
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key \
      | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' \
      | sudo tee /etc/apt/sources.list.d/kubernetes.list
    apt-get update
    
    apt install -y kubelet
    systemctl daemon-reload
    systemctl start kubelet
    echo
    echo "###"
    echo "### Installed kubelet on ${HOSTNAME}."
    echo
    echo
    echo "### Kubelet Status on Node $HOSTNAME"
    systemctl status kubelet | grep -oP "(?<=Active: )(.*)"
    echo
    EOF
    
  • Führen Sie das Script auf allen Nodes aus

    ./run-on-nodes.sh install-kubelet.sh
    

Aufgabe 6: Status überprüfen

  • Erstellen Sie ein Script zur Statusüberprüfung

    cat > status.sh << 'EOF'
    echo
    echo "### Status on Node $HOSTNAME"
    STATUS=$( { systemctl status containerd | grep -oP "(?<=Active: )(.*)"; } 2>&1 )
    echo "containerd: $STATUS"
    STATUS=$( { systemctl status kubelet | grep -oP "(?<=Active: )(.*)"; } 2>&1 )
    echo "kubelet:    $STATUS"
    echo
    EOF
    
  • Führen Sie das Script aus, um den Status aller Services zu überprüfen

    ./run-on-nodes.sh status.sh
    

Aufgabe 7: Troubleshooting (Optional)

  • Überprüfen Sie die Kubelet-Logs auf einem Node

    ssh controlplane-0 "journalctl -u kubelet -f"
    
  • Testen Sie die Container-Runtime

    ssh worker-0 "crictl version"
    ssh worker-0 "crictl info"
    
  • Überprüfen Sie, ob die Static Pod-Manifests-Verzeichnisse existieren

    ssh controlplane-0 "ls -la /etc/kubernetes/manifests"
    

Ausblick

Nach Abschluss dieser Aufgabe haben Sie eine vollständige Node-Infrastruktur mit Container-Runtime und Kubelet aufgebaut. Die Nodes sind bereit, um mit der Control Plane verbunden zu werden. Im nächsten Schritt würden Sie die Control Plane-Komponenten (API-Server, Controller Manager, Scheduler) als Static Pods oder systemd-Services installieren.

Hinweis

Der Kubelet wird momentan noch Fehler zeigen, da keine Control Plane verfügbar ist. Das ist normal und wird sich ändern, sobald der API-Server gestartet wird.