Zum Inhalt

Worker Nodes finalisieren

Ziel

In diesem Projekt geht es um die Finalisierung der Kubernetes Worker Nodes. Sie werden:

  • Kube-Proxy als DaemonSet installieren und konfigurieren
  • CNI-Plugin (Cilium) für Cluster-Networking installieren
  • CoreDNS für Service Discovery und DNS-Auflösung einrichten
  • Die Funktionalität aller Cluster-Komponenten testen

Vorbereitung

  • Erstellen Sie ein neues Arbeitsverzeichnis und wechseln Sie hinein

    cd ~/workspace
    mkdir kubeproxy
    cd kubeproxy
    

Aufgabe 1: Kube-Proxy installieren

Kube-Proxy Manifest erstellen

  • Erstellen Sie ein Manifest für kube-proxy als DaemonSet

    cat > kube-proxy.yaml << 'EOF'
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: kube-proxy
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: kubeadm:node-proxier
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:node-proxier
    subjects:
    - kind: ServiceAccount
      name: kube-proxy
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: kube-proxy
      namespace: kube-system
    rules:
    - apiGroups:
      - ""
      resourceNames:
      - kube-proxy
      resources:
      - configmaps
      verbs:
      - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: kube-proxy
      namespace: kube-system
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: kube-proxy
    subjects:
    - kind: Group
      name: system:bootstrappers:kubeadm:default-node-token
    ---
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: kube-proxy
      namespace: kube-system
      labels:
        app: kube-proxy
    data:
      kubeconfig.conf: |-
        apiVersion: v1
        kind: Config
        clusters:
        - cluster:
            certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
            server: https://<API_SERVER_IP>:6443
          name: default
        contexts:
        - context:
            cluster: default
            namespace: default
            user: default
          name: default
        current-context: default
        users:
        - name: default
          user:
            tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
      config.conf: |-
        apiVersion: kubeproxy.config.k8s.io/v1alpha1
        bindAddress: 0.0.0.0
        bindAddressHardFail: false
        clientConnection:
          acceptContentTypes: ""
          burst: 0
          contentType: ""
          kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
          qps: 0
        clusterCIDR: ""
        configSyncPeriod: 0s
        conntrack:
          maxPerCore: null
          min: null
          tcpBeLiberal: false
          tcpCloseWaitTimeout: null
          tcpEstablishedTimeout: null
          udpStreamTimeout: 0s
          udpTimeout: 0s
        detectLocal:
          bridgeInterface: ""
          interfaceNamePrefix: ""
        detectLocalMode: ""
        enableProfiling: false
        healthzBindAddress: ""
        hostnameOverride: ""
        iptables:
          localhostNodePorts: null
          masqueradeAll: false
          masqueradeBit: null
          minSyncPeriod: 0s
          syncPeriod: 0s
        ipvs:
          excludeCIDRs: null
          minSyncPeriod: 0s
          scheduler: ""
          strictARP: false
          syncPeriod: 0s
          tcpFinTimeout: 0s
          tcpTimeout: 0s
          udpTimeout: 0s
        kind: KubeProxyConfiguration
        logging:
          flushFrequency: 0
          options:
            json:
              infoBufferSize: "0"
            text:
              infoBufferSize: "0"
          verbosity: 0
        metricsBindAddress: ""
        mode: ""
        nftables:
          masqueradeAll: false
          masqueradeBit: null
          minSyncPeriod: 0s
          syncPeriod: 0s
        nodePortAddresses: null
        oomScoreAdj: null
        portRange: ""
        showHiddenMetricsForVersion: ""
        winkernel:
          enableDSR: false
          forwardHealthCheckVip: false
          networkName: ""
          rootHnsEndpointName: ""
          sourceVip: ""
    
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      labels:
        k8s-app: kube-proxy
      name: kube-proxy
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          k8s-app: kube-proxy
      updateStrategy:
        type: RollingUpdate
      template:
        metadata:
          labels:
            k8s-app: kube-proxy
        spec:
          priorityClassName: system-node-critical
          containers:
          - name: kube-proxy
            image: registry.k8s.io/kube-proxy:v1.34.0
            imagePullPolicy: IfNotPresent
            command:
            - /usr/local/bin/kube-proxy
            - --config=/var/lib/kube-proxy/config.conf
            - --hostname-override=$(NODE_NAME)
            securityContext:
              privileged: true
            volumeMounts:
            - mountPath: /var/lib/kube-proxy
              name: kube-proxy
            - mountPath: /run/xtables.lock
              name: xtables-lock
              readOnly: false
            - mountPath: /lib/modules
              name: lib-modules
              readOnly: true
            env:
              - name: NODE_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: spec.nodeName
          hostNetwork: true
          serviceAccountName: kube-proxy
          volumes:
          - name: kube-proxy
            configMap:
              name: kube-proxy
          - name: xtables-lock
            hostPath:
              path: /run/xtables.lock
              type: FileOrCreate
          - name: lib-modules
            hostPath:
              path: /lib/modules
          tolerations:
          - operator: Exists
          nodeSelector:
            kubernetes.io/os: linux
    EOF
    

API-Server IP konfigurieren

  • Ermitteln Sie die IP-Adresse Ihres API-Servers

    # IP-Adresse des controlplane-0 ermitteln
    API_SERVER_IP=$(ssh -G controlplane-0 | awk '/^hostname /{print $2}')
    echo "API Server IP: $API_SERVER_IP"
    
  • Ersetzen Sie <API_SERVER_IP> im Manifest mit der tatsächlichen IP

    # IP-Adresse im Manifest ersetzen
    sed -i "s/<API_SERVER_IP>/$API_SERVER_IP/g" kube-proxy.yaml
    
    # Überprüfen, ob die Ersetzung erfolgreich war
    grep "server: https://" kube-proxy.yaml
    

Kube-Proxy deployen

  • Deployen Sie das kube-proxy Manifest

    kubectl apply -f kube-proxy.yaml
    
  • Überprüfen Sie, ob alle kube-proxy Pods laufen

    kubectl get pods -n kube-system -o wide -l k8s-app=kube-proxy
    
    # Warten Sie, bis alle Pods im Status "Running" sind
    kubectl wait --for=condition=Ready pod -l k8s-app=kube-proxy -n kube-system --timeout=300s
    

Aufgabe 2: CNI Plugin (Cilium) installieren

Cilium CLI installieren

  • Laden Sie die Cilium CLI herunter und installieren Sie sie

    curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/v0.18.6/cilium-linux-amd64.tar.gz{,.sha256sum}
    sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
    tar xzvfC cilium-linux-amd64.tar.gz .
    rm cilium-linux-amd64.tar.gz{,.sha256sum}
    
    # Cilium CLI ausführbar machen
    chmod +x cilium
    

Cilium installieren

  • Installieren Sie Cilium als CNI-Plugin

    ./cilium install --version 1.18.1
    
  • Überprüfen Sie die Installation

    # Status der Cilium-Installation prüfen
    ./cilium status
    
    # Alle Cilium Pods anzeigen
    kubectl get pods -n kube-system -o wide -l app.kubernetes.io/part-of=cilium
    
    # Warten Sie, bis alle Pods bereit sind
    kubectl wait --for=condition=Ready pod -l app.kubernetes.io/part-of=cilium -n kube-system --timeout=300s
    

Aufgabe 3: CoreDNS installieren

CoreDNS Manifest erstellen

  • Erstellen Sie ein Manifest für CoreDNS

    cat > coredns.yaml << 'EOF'
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: coredns
      namespace: kube-system
      labels:
        k8s-app: kube-dns
    spec:
      replicas: 2
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 1
      selector:
        matchLabels:
          k8s-app: kube-dns
      template:
        metadata:
          labels:
            k8s-app: kube-dns
        spec:
          priorityClassName: system-cluster-critical
          serviceAccountName: coredns
          affinity:
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 100
                podAffinityTerm:
                  labelSelector:
                    matchExpressions:
                    - key: k8s-app
                      operator: In
                      values: ["kube-dns"]
                  topologyKey: kubernetes.io/hostname
          tolerations:
          - key: CriticalAddonsOnly
            operator: Exists
          - key: node-role.kubernetes.io/control-plane
            effect: NoSchedule
          nodeSelector:
            kubernetes.io/os: linux
          containers:
          - name: coredns
            image: registry.k8s.io/coredns/coredns:v1.12.1
            imagePullPolicy: IfNotPresent
            resources:
              limits:
                memory: 170Mi
              requests:
                cpu: 100m
                memory: 70Mi
            args: [ "-conf", "/etc/coredns/Corefile" ]
            volumeMounts:
            - name: config-volume
              mountPath: /etc/coredns
              readOnly: true
            ports:
            - containerPort: 53
              name: dns
              protocol: UDP
            - containerPort: 53
              name: dns-tcp
              protocol: TCP
            - containerPort: 9153
              name: metrics
              protocol: TCP
            - containerPort: 8080
              name: liveness-probe
              protocol: TCP
            - containerPort: 8181
              name: readiness-probe
              protocol: TCP
            livenessProbe:
              httpGet:
                path: /health
                port: liveness-probe
                scheme: HTTP
              initialDelaySeconds: 60
              timeoutSeconds: 5
              successThreshold: 1
              failureThreshold: 5
            readinessProbe:
              httpGet:
                path: /ready
                port: readiness-probe
                scheme: HTTP
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                add:
                - NET_BIND_SERVICE
                drop:
                - ALL
              readOnlyRootFilesystem: true
          dnsPolicy: Default
          volumes:
            - name: config-volume
              configMap:
                name: coredns
                items:
                - key: Corefile
                  path: Corefile
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: coredns
      namespace: kube-system
    data:
      Corefile: |
        .:53 {
            errors
            health {
               lameduck 5s
            }
            ready
            kubernetes cluster.local in-addr.arpa ip6.arpa {
               pods insecure
               fallthrough in-addr.arpa ip6.arpa
               ttl 30
            }
            prometheus :9153
            forward . /etc/resolv.conf {
               max_concurrent 1000
            }
            cache 30 {
               disable success cluster.local
               disable denial cluster.local
            }
            loop
            reload
            loadbalance
        }
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        k8s-app: kube-dns
        kubernetes.io/cluster-service: "true"
        kubernetes.io/name: "CoreDNS"
      name: kube-dns
      namespace: kube-system
      annotations:
        prometheus.io/port: "9153"
        prometheus.io/scrape: "true"
      # Without this resourceVersion value, an update of the Service between versions will yield:
      #   Service "kube-dns" is invalid: metadata.resourceVersion: Invalid value: "": must be specified for an update
      resourceVersion: "0"
    spec:
      clusterIP: 10.96.0.10
      ports:
      - name: dns
        port: 53
        protocol: UDP
        targetPort: 53
      - name: dns-tcp
        port: 53
        protocol: TCP
        targetPort: 53
      - name: metrics
        port: 9153
        protocol: TCP
        targetPort: 9153
      selector:
        k8s-app: kube-dns
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: system:coredns
    rules:
    - apiGroups:
      - ""
      resources:
      - endpoints
      - services
      - pods
      - namespaces
      verbs:
      - list
      - watch
    - apiGroups:
      - discovery.k8s.io
      resources:
      - endpointslices
      verbs:
      - list
      - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: system:coredns
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:coredns
    subjects:
    - kind: ServiceAccount
      name: coredns
      namespace: kube-system
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: coredns
      namespace: kube-system
    EOF
    

CoreDNS deployen

  • Deployen Sie CoreDNS

    kubectl apply -f coredns.yaml
    
  • Überprüfen Sie, ob alle CoreDNS Pods laufen

    kubectl get pods -n kube-system -o wide -l k8s-app=kube-dns
    
    # Warten Sie, bis alle Pods bereit sind
    kubectl wait --for=condition=Ready pod -l k8s-app=kube-dns -n kube-system --timeout=300s
    

Aufgabe 4: Cluster-Funktionalität testen

Node-Status überprüfen

  • Überprüfen Sie den Status aller Nodes

    kubectl get nodes -o wide
    
    # Alle Nodes sollten jetzt "Ready" sein
    kubectl wait --for=condition=Ready nodes --all --timeout=300s
    

Test-Pod deployen

  • Erstellen Sie einen Test-Pod zur Überprüfung der Cluster-Funktionalität

    # Test-Pod erstellen
    kubectl run test-pod --image=busybox --restart=Never -- sleep 3600
    
    # Warten bis Pod läuft
    kubectl wait --for=condition=Ready pod/test-pod --timeout=300s
    
    # Pod-Status prüfen
    kubectl get pod test-pod -o wide
    

DNS-Funktionalität testen

  • Testen Sie die DNS-Auflösung im Cluster

    # DNS-Test im Pod ausführen
    kubectl exec test-pod -- nslookup kubernetes.default.svc.cluster.local
    
    # CoreDNS Service testen
    kubectl exec test-pod -- nslookup kube-dns.kube-system.svc.cluster.local
    
    # Externe DNS-Auflösung testen
    kubectl exec test-pod -- nslookup google.com
    

Service-Konnektivität testen

  • Testen Sie die Service-Discovery

    # Kubernetes API Service testen
    kubectl exec test-pod -- wget -qO- https://kubernetes.default.svc.cluster.local:443 --no-check-certificate || echo "Connection established (certificate error expected)"
    
    # CoreDNS Metrics testen
    kubectl exec test-pod -- wget -qO- http://kube-dns.kube-system.svc.cluster.local:9153/metrics
    

Aufgabe 5: Gesamtübersicht

  • Zeigen Sie eine Übersicht aller wichtigen Cluster-Komponenten

    echo "=== NODES ==="
    kubectl get nodes
    
    echo "=== SYSTEM PODS ==="
    kubectl get pods -n kube-system
    
    echo "=== SYSTEM SERVICES ==="
    kubectl get services -n kube-system
    
    echo "=== DAEMONSETS ==="
    kubectl get daemonsets -n kube-system
    
    echo "=== DEPLOYMENTS ==="
    kubectl get deployments -n kube-system
    

Cleanup (Optional)

  • Löschen Sie den Test-Pod

    kubectl delete pod test-pod
    

Gratulation!

Sie haben erfolgreich einen vollständigen Kubernetes-Cluster aufgebaut! Alle wichtigen Komponenten sind installiert und funktionsfähig:

  • Kube-Proxy: Ermöglicht Service-Discovery und Load Balancing
  • Cilium: Stellt Cluster-Networking und Sicherheitsrichtlinien bereit
  • CoreDNS: Bietet DNS-Auflösung für Services und Pods

Der Cluster ist jetzt bereit für den produktiven Einsatz von Workloads.

Nächste Schritte

In einem produktiven Umgebung würden Sie zusätzlich folgende Komponenten installieren:

  • Ingress Controller für HTTP/HTTPS-Traffic
  • Monitoring Stack (Prometheus, Grafana)
  • Logging Stack (Fluentd, Elasticsearch)
  • Backup-Lösungen für etcd und persistente Daten
  • Security Tools für Policy Enforcement