Η εμπειρία μας με δεδομένα στο σύμπλεγμα etcd Kubernetes απευθείας (χωρίς K8s API)

Όλο και περισσότερο, οι πελάτες μας ζητούν να παρέχουμε πρόσβαση στο σύμπλεγμα Kubernetes για να μπορούν να έχουν πρόσβαση σε υπηρεσίες εντός του συμπλέγματος: ώστε να μπορούν να συνδεθούν απευθείας σε κάποια βάση δεδομένων ή υπηρεσία, να συνδέσουν μια τοπική εφαρμογή με εφαρμογές εντός του συμπλέγματος...

Η εμπειρία μας με δεδομένα στο σύμπλεγμα etcd Kubernetes απευθείας (χωρίς K8s API)

Για παράδειγμα, υπάρχει ανάγκη σύνδεσης από το τοπικό σας μηχάνημα σε μια υπηρεσία memcached.staging.svc.cluster.local. Παρέχουμε αυτή τη δυνατότητα χρησιμοποιώντας ένα VPN μέσα στο σύμπλεγμα στο οποίο συνδέεται ο πελάτης. Για να γίνει αυτό, ανακοινώνουμε υποδίκτυα pods, υπηρεσιών και push Cluster DNS στον πελάτη. Έτσι, όταν ένας πελάτης προσπαθεί να συνδεθεί στην υπηρεσία memcached.staging.svc.cluster.local, το αίτημα πηγαίνει στο DNS του συμπλέγματος και ως απόκριση λαμβάνει τη διεύθυνση αυτής της υπηρεσίας από το δίκτυο υπηρεσιών συμπλέγματος ή τη διεύθυνση pod.

Διαμορφώνουμε τα συμπλέγματα K8s χρησιμοποιώντας το kubeadm, όπου βρίσκεται το προεπιλεγμένο υποδίκτυο υπηρεσίας 192.168.0.0/16, και το δίκτυο των λοβών είναι 10.244.0.0/16. Συνήθως όλα λειτουργούν καλά, αλλά υπάρχουν μερικά σημεία:

  • Υποδίκτυο 192.168.*.* χρησιμοποιείται συχνά σε δίκτυα γραφείων πελατών και ακόμη πιο συχνά σε οικιακά δίκτυα προγραμματιστών. Και τότε έχουμε συγκρούσεις: οι οικιακόι δρομολογητές λειτουργούν σε αυτό το υποδίκτυο και το VPN ωθεί αυτά τα υποδίκτυα από το σύμπλεγμα στον πελάτη.
  • Έχουμε πολλά clusters (παραγωγή, στάδιο και/ή πολλά dev cluster). Στη συνέχεια, από προεπιλογή, όλα θα έχουν τα ίδια υποδίκτυα για pods και υπηρεσίες, γεγονός που δημιουργεί μεγάλες δυσκολίες για ταυτόχρονη εργασία με υπηρεσίες σε πολλά cluster.

Έχουμε υιοθετήσει εδώ και πολύ καιρό την πρακτική της χρήσης διαφορετικών υποδικτύων για υπηρεσίες και pod στο ίδιο έργο - γενικά, έτσι ώστε όλα τα συμπλέγματα να έχουν διαφορετικά δίκτυα. Ωστόσο, υπάρχει ένας μεγάλος αριθμός συμπλεγμάτων σε λειτουργία που δεν θα ήθελα να μεταφέρω από την αρχή, καθώς εκτελούν πολλές υπηρεσίες, κρατικές εφαρμογές κ.λπ.

Και μετά αναρωτηθήκαμε: πώς να αλλάξουμε το υποδίκτυο σε ένα υπάρχον σύμπλεγμα;

Αναζήτηση αποφάσεων

Η πιο συνηθισμένη πρακτική είναι η αναδημιουργία όλα υπηρεσίες με τύπο ClusterIP. Ως επιλογή, μπορεί να συμβουλεύει και αυτό:

Η ακόλουθη διαδικασία έχει ένα πρόβλημα: αφού ρυθμιστούν όλες οι παραμέτρους, τα pods εμφανίζουν την παλιά IP ως διακομιστή ονομάτων DNS στο /etc/resolv.conf.
Επειδή ακόμα δεν βρήκα τη λύση, έπρεπε να επαναφέρω ολόκληρο το σύμπλεγμα με το kubeadm reset και να το ξεκινήσω ξανά.

Αυτό όμως δεν είναι κατάλληλο για όλους... Ακολουθούν αναλυτικότερες εισαγωγές για την περίπτωσή μας:

  • Χρησιμοποιείται φανέλα.
  • Υπάρχουν συστάδες τόσο στα σύννεφα όσο και στο υλικό.
  • Θα ήθελα να αποφύγω την εκ νέου ανάπτυξη όλων των υπηρεσιών στο σύμπλεγμα.
  • Υπάρχει ανάγκη γενικά να γίνονται τα πάντα με έναν ελάχιστο αριθμό προβλημάτων.
  • Η έκδοση Kubernetes είναι 1.16.6 (ωστόσο, τα περαιτέρω βήματα θα είναι παρόμοια για άλλες εκδόσεις).
  • Το κύριο καθήκον είναι να διασφαλιστεί ότι σε ένα σύμπλεγμα που αναπτύσσεται χρησιμοποιώντας kubeadm με ένα υποδίκτυο υπηρεσίας 192.168.0.0/16, αντικαταστήστε το με 172.24.0.0/16.

Και συνέβη που από καιρό μας ενδιέφερε να δούμε τι και πώς στο Kubernetes αποθηκεύεται στο etcd, τι μπορεί να γίνει με αυτό... Έτσι σκεφτήκαμε: «Γιατί να μην ενημερώσετε απλώς τα δεδομένα σε etcd, αντικαθιστώντας τις παλιές διευθύνσεις IP (υποδίκτυο) με νέες? "

Έχοντας ψάξει για έτοιμα εργαλεία για εργασία με δεδομένα στο etcd, δεν βρήκαμε κάτι που να έλυνε πλήρως το πρόβλημα. (Παρεμπιπτόντως, εάν γνωρίζετε κάποια βοηθητικά προγράμματα για την εργασία με δεδομένα απευθείας στο etcd, θα εκτιμούσαμε τους συνδέσμους.) Ωστόσο, μια καλή αφετηρία είναι etcdhelper από το OpenShift (ευχαριστώ τους συγγραφείς του!).

Αυτό το βοηθητικό πρόγραμμα μπορεί να συνδεθεί στο etcd χρησιμοποιώντας πιστοποιητικά και να διαβάσει δεδομένα από εκεί χρησιμοποιώντας εντολές ls, get, dump.

Προσθήκη etcdhelper

Η επόμενη σκέψη είναι λογική: "Τι σας εμποδίζει να προσθέσετε αυτό το βοηθητικό πρόγραμμα προσθέτοντας τη δυνατότητα εγγραφής δεδομένων στο etcd;"

Έγινε μια τροποποιημένη έκδοση του etcdhelper με δύο νέες λειτουργίες changeServiceCIDR и changePodCIDR. Σε αυτήν μπορείτε να δείτε τον κωδικό εδώ.

Τι κάνουν τα νέα χαρακτηριστικά; Αλγόριθμος changeServiceCIDR:

  • Δημιουργήστε έναν αποσειροποιητή.
  • να συντάξει μια τυπική έκφραση για να αντικαταστήσει το CIDR.
  • περνάμε από όλες τις υπηρεσίες με τον τύπο ClusterIP στο σύμπλεγμα:
    • Αποκωδικοποιήστε την τιμή από το etcd σε ένα αντικείμενο Go.
    • Χρησιμοποιώντας μια τυπική έκφραση αντικαθιστούμε τα δύο πρώτα byte της διεύθυνσης.
    • εκχωρήστε στην υπηρεσία μια διεύθυνση IP από το νέο υποδίκτυο.
    • δημιουργήστε έναν σειριακό, μετατρέψτε το αντικείμενο Go σε protobuf, γράψτε νέα δεδομένα στο etcd.

Λειτουργία changePodCIDR ουσιαστικά παρόμοια changeServiceCIDR - μόνο αντί να επεξεργαστούμε τις προδιαγραφές της υπηρεσίας, το κάνουμε για τον κόμβο και αλλάζουμε .spec.PodCIDR σε ένα νέο υποδίκτυο.

Πρακτική

Αλλαγή υπηρεσίας CIDR

Το σχέδιο για την υλοποίηση της εργασίας είναι πολύ απλό, αλλά περιλαμβάνει χρόνο διακοπής λειτουργίας τη στιγμή της εκ νέου δημιουργίας όλων των λοβών στο σύμπλεγμα. Αφού περιγράψουμε τα κύρια βήματα, θα μοιραστούμε επίσης σκέψεις για το πώς, θεωρητικά, μπορεί να ελαχιστοποιηθεί αυτός ο χρόνος διακοπής λειτουργίας.

Προπαρασκευαστικά βήματα:

  • εγκατάσταση του απαραίτητου λογισμικού και συναρμολόγηση του επιδιορθωμένου etcdhelper.
  • backup κ.λπ. και /etc/kubernetes.

Σύντομο σχέδιο δράσης για αλλαγή υπηρεσίαςCIDR:

  • αλλαγή του apiserver και του controller-manager manifest.
  • επανέκδοση πιστοποιητικών·
  • αλλαγή υπηρεσιών ClusterIP σε etcd.
  • επανεκκίνηση όλων των λοβών στο σύμπλεγμα.

Ακολουθεί μια πλήρης ακολουθία ενεργειών με λεπτομέρειες.

1. Εγκαταστήστε το etcd-client για την ένδειξη δεδομένων:

apt install etcd-client

2. Δημιουργία etcdhelper:

  • Εγκαταστήστε το golang:
    GOPATH=/root/golang
    mkdir -p $GOPATH/local
    curl -sSL https://dl.google.com/go/go1.14.1.linux-amd64.tar.gz | tar -xzvC $GOPATH/local
    echo "export GOPATH="$GOPATH"" >> ~/.bashrc
    echo 'export GOROOT="$GOPATH/local/go"' >> ~/.bashrc
    echo 'export PATH="$PATH:$GOPATH/local/go/bin"' >> ~/.bashrc
  • Αποταμιεύουμε για τον εαυτό μας etcdhelper.go, λήψη εξαρτήσεων, συλλογή:
    wget https://raw.githubusercontent.com/flant/examples/master/2020/04-etcdhelper/etcdhelper.go
    go get go.etcd.io/etcd/clientv3 k8s.io/kubectl/pkg/scheme k8s.io/apimachinery/pkg/runtime
    go build -o etcdhelper etcdhelper.go

3. Δημιουργήστε ένα αντίγραφο ασφαλείας κ.λπ.

backup_dir=/root/backup
mkdir ${backup_dir}
cp -rL /etc/kubernetes ${backup_dir}
ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --key=/etc/kubernetes/pki/etcd/server.key --cert=/etc/kubernetes/pki/etcd/server.crt --endpoints https://192.168.199.100:2379 snapshot save ${backup_dir}/etcd.snapshot

4. Αλλάξτε το υποδίκτυο υπηρεσίας στις δηλώσεις επιπέδου ελέγχου Kubernetes. Σε αρχεία /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml αλλάξτε την παράμετρο --service-cluster-ip-range σε νέο υποδίκτυο: 172.24.0.0/16 αντί για 192.168.0.0/16.

5. Εφόσον αλλάζουμε το υποδίκτυο υπηρεσίας στο οποίο το kubeadm εκδίδει πιστοποιητικά για apiserver (συμπεριλαμβανομένων), αυτά πρέπει να επανεκδοθούν:

  1. Ας δούμε για ποιους τομείς και διευθύνσεις IP έχει εκδοθεί το τρέχον πιστοποιητικό:
    openssl x509 -noout -ext subjectAltName </etc/kubernetes/pki/apiserver.crt
    X509v3 Subject Alternative Name:
        DNS:dev-1-master, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:apiserver, IP Address:192.168.0.1, IP Address:10.0.0.163, IP Address:192.168.199.100
  2. Ας ετοιμάσουμε μια ελάχιστη διαμόρφωση για το kubeadm:
    cat kubeadm-config.yaml
    apiVersion: kubeadm.k8s.io/v1beta1
    kind: ClusterConfiguration
    networking:
      podSubnet: "10.244.0.0/16"
      serviceSubnet: "172.24.0.0/16"
    apiServer:
      certSANs:
      - "192.168.199.100" # IP-адрес мастер узла
  3. Ας διαγράψουμε το παλιό crt και το κλειδί, αφού χωρίς αυτό το νέο πιστοποιητικό δεν θα εκδοθεί:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Ας επανεκδώσουμε πιστοποιητικά για τον διακομιστή API:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Ας ελέγξουμε ότι το πιστοποιητικό εκδόθηκε για το νέο υποδίκτυο:
    openssl x509 -noout -ext subjectAltName </etc/kubernetes/pki/apiserver.crt
    X509v3 Subject Alternative Name:
        DNS:kube-2-master, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, IP Address:172.24.0.1, IP Address:10.0.0.163, IP Address:192.168.199.100
  6. Μετά την επανέκδοση του πιστοποιητικού διακομιστή API, επανεκκινήστε το κοντέινέρ του:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Ας δημιουργήσουμε ξανά τη διαμόρφωση για admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Ας επεξεργαστούμε τα δεδομένα σε etcd:
    ./etcdhelper -cacert /etc/kubernetes/pki/etcd/ca.crt -cert /etc/kubernetes/pki/etcd/server.crt -key /etc/kubernetes/pki/etcd/server.key -endpoint https://127.0.0.1:2379 change-service-cidr 172.24.0.0/16 

    Προσοχή! Αυτή τη στιγμή, η ανάλυση τομέα σταματά να λειτουργεί στο σύμπλεγμα, καθώς σε υπάρχουσες ομάδες διαφημίσεων /etc/resolv.conf η παλιά διεύθυνση CoreDNS (kube-dns) είναι καταχωρημένη και το kube-proxy αλλάζει τους κανόνες iptables από το παλιό υποδίκτυο στο νέο. Περαιτέρω στο άρθρο γράφεται για πιθανές επιλογές για την ελαχιστοποίηση του χρόνου διακοπής λειτουργίας.

  9. Ας διορθώσουμε το ConfigMap στον χώρο ονομάτων kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - αντικαταστήστε εδώ clusterDNS στη νέα διεύθυνση IP της υπηρεσίας kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - θα το φτιάξουμε data.ClusterConfiguration.networking.serviceSubnet σε ένα νέο υποδίκτυο.

  10. Δεδομένου ότι η διεύθυνση kube-dns έχει αλλάξει, είναι απαραίτητο να ενημερώσετε τη διαμόρφωση kubelet σε όλους τους κόμβους:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Το μόνο που μένει είναι να επανεκκινήσετε όλα τα pod στο σύμπλεγμα:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Ελαχιστοποιήστε το χρόνο διακοπής λειτουργίας

Σκέψεις για το πώς να ελαχιστοποιήσετε το χρόνο διακοπής λειτουργίας:

  1. Μετά την αλλαγή των μανιφέστων του επιπέδου ελέγχου, δημιουργήστε μια νέα υπηρεσία kube-dns, για παράδειγμα, με το όνομα kube-dns-tmp και νέα διεύθυνση 172.24.0.10.
  2. κάνω if στο etcdhelper, το οποίο δεν θα τροποποιήσει την υπηρεσία kube-dns.
  3. Αντικαταστήστε τη διεύθυνση σε όλα τα kubelets ClusterDNS σε νέο, ενώ η παλιά υπηρεσία θα συνεχίσει να λειτουργεί ταυτόχρονα με τη νέα.
  4. Περιμένετε έως ότου οι λοβοί με τις εφαρμογές κυλήσουν είτε μόνες τους για φυσικούς λόγους είτε σε μια συμφωνημένη ώρα.
  5. Διαγραφή υπηρεσίας kube-dns-tmp και αλλαγή serviceSubnetCIDR για την υπηρεσία kube-dns.

Αυτό το σχέδιο θα σας επιτρέψει να ελαχιστοποιήσετε το χρόνο διακοπής λειτουργίας σε ~ ένα λεπτό - για τη διάρκεια της αφαίρεσης της υπηρεσίας kube-dns-tmp και αλλαγή του υποδικτύου για την υπηρεσία kube-dns.

Τροποποίηση podNetwork

Ταυτόχρονα, αποφασίσαμε να δούμε πώς να τροποποιήσουμε το podNetwork χρησιμοποιώντας το etcdhelper που προκύπτει. Η σειρά των ενεργειών είναι η εξής:

  • διόρθωση ρυθμίσεων σε kube-system;
  • διόρθωση του μανιφέστου kube-controller-manager.
  • Αλλάξτε το podCIDR απευθείας σε etcd.
  • επανεκκίνηση όλων των κόμβων συμπλέγματος.

Τώρα περισσότερα για αυτές τις ενέργειες:

1. Τροποποιήστε το ConfigMap's στον χώρο ονομάτων kube-system:

kubectl -n kube-system edit cm kubeadm-config

- διόρθωση data.ClusterConfiguration.networking.podSubnet σε ένα νέο υποδίκτυο 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

- διόρθωση data.config.conf.clusterCIDR: 10.55.0.0/16.

2. Τροποποιήστε τη δήλωση ελεγκτή-διαχειριστή:

vim /etc/kubernetes/manifests/kube-controller-manager.yaml

- διόρθωση --cluster-cidr=10.55.0.0/16.

3. Κοιτάξτε τις τρέχουσες τιμές .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses για όλους τους κόμβους συμπλέγματος:

kubectl get no -o json | jq '[.items[] | {"name": .metadata.name, "podCIDR": .spec.podCIDR, "podCIDRs": .spec.podCIDRs, "InternalIP": (.status.addresses[] | select(.type == "InternalIP") | .address)}]'

[
  {
    "name": "kube-2-master",
    "podCIDR": "10.244.0.0/24",
    "podCIDRs": [
      "10.244.0.0/24"
    ],
    "InternalIP": "192.168.199.2"
  },
  {
    "name": "kube-2-master",
    "podCIDR": "10.244.0.0/24",
    "podCIDRs": [
      "10.244.0.0/24"
    ],
    "InternalIP": "10.0.1.239"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.244.1.0/24",
    "podCIDRs": [
      "10.244.1.0/24"
    ],
    "InternalIP": "192.168.199.222"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.244.1.0/24",
    "podCIDRs": [
      "10.244.1.0/24"
    ],
    "InternalIP": "10.0.4.73"
  }
]

4. Αντικαταστήστε το podCIDR κάνοντας αλλαγές απευθείας στο etcd:

./etcdhelper -cacert /etc/kubernetes/pki/etcd/ca.crt -cert /etc/kubernetes/pki/etcd/server.crt -key /etc/kubernetes/pki/etcd/server.key -endpoint https://127.0.0.1:2379 change-pod-cidr 10.55.0.0/16

5. Ας ελέγξουμε ότι το podCIDR έχει πραγματικά αλλάξει:

kubectl get no -o json | jq '[.items[] | {"name": .metadata.name, "podCIDR": .spec.podCIDR, "podCIDRs": .spec.podCIDRs, "InternalIP": (.status.addresses[] | select(.type == "InternalIP") | .address)}]'

[
  {
    "name": "kube-2-master",
    "podCIDR": "10.55.0.0/24",
    "podCIDRs": [
      "10.55.0.0/24"
    ],
    "InternalIP": "192.168.199.2"
  },
  {
    "name": "kube-2-master",
    "podCIDR": "10.55.0.0/24",
    "podCIDRs": [
      "10.55.0.0/24"
    ],
    "InternalIP": "10.0.1.239"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.55.1.0/24",
    "podCIDRs": [
      "10.55.1.0/24"
    ],
    "InternalIP": "192.168.199.222"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.55.1.0/24",
    "podCIDRs": [
      "10.55.1.0/24"
    ],
    "InternalIP": "10.0.4.73"
  }
]

6. Ας επανεκκινήσουμε όλους τους κόμβους συμπλέγματος έναν προς έναν.

7. Εάν αφήσετε τουλάχιστον έναν κόμβο παλιό podCIDR, τότε το kube-controller-manager δεν θα μπορεί να ξεκινήσει και οι ομάδες στο σύμπλεγμα δεν θα προγραμματιστούν.

Στην πραγματικότητα, η αλλαγή του podCIDR μπορεί να γίνει ακόμα πιο απλή (για παράδειγμα, έτσι). Αλλά θέλαμε να μάθουμε πώς να εργαζόμαστε απευθείας με το etcd, επειδή υπάρχουν περιπτώσεις κατά την επεξεργασία αντικειμένων Kubernetes σε etcd - μονό πιθανή παραλλαγή. (Για παράδειγμα, δεν μπορείτε απλώς να αλλάξετε το πεδίο Υπηρεσία χωρίς χρόνο διακοπής λειτουργίας spec.clusterIP.)

Σύνολο

Το άρθρο συζητά τη δυνατότητα απευθείας εργασίας με δεδομένα σε etcd, π.χ. παρακάμπτοντας το Kubernetes API. Μερικές φορές αυτή η προσέγγιση σας επιτρέπει να κάνετε «δύσκολα πράγματα». Δοκιμάσαμε τις πράξεις που δίνονται στο κείμενο σε πραγματικά συμπλέγματα K8. Ωστόσο, η κατάσταση ετοιμότητάς τους για ευρεία χρήση είναι PoC (απόδειξη ιδέας). Επομένως, εάν θέλετε να χρησιμοποιήσετε μια τροποποιημένη έκδοση του βοηθητικού προγράμματος etcdhelper στα συμπλέγματά σας, κάντε το με δική σας ευθύνη.

PS

Διαβάστε επίσης στο blog μας:

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο