הניסיון שלנו עם נתונים באשכול Kubernetes etcd ישירות (ללא K8s API)

יותר ויותר, לקוחות מבקשים מאיתנו לספק גישה לאשכול Kubernetes כדי שנוכל לגשת לשירותים בתוך האשכול: כדי להיות מסוגלים להתחבר ישירות למסד נתונים או שירות כלשהו, ​​לחבר אפליקציה מקומית עם יישומים בתוך האשכול...

הניסיון שלנו עם נתונים באשכול Kubernetes etcd ישירות (ללא K8s API)

לדוגמה, יש צורך להתחבר מהמחשב המקומי שלך לשירות memcached.staging.svc.cluster.local. אנו מספקים יכולת זו באמצעות VPN בתוך האשכול שאליו הלקוח מתחבר. לשם כך, אנו מכריזים על רשתות משנה של פודים, שירותים ודוחפים DNS של אשכולות ללקוח. כך, כאשר לקוח מנסה להתחבר לשירות memcached.staging.svc.cluster.local, הבקשה עוברת ל-Cluster DNS ובתגובה מקבלת את הכתובת של שירות זה מרשת שירות האשכול או מכתובת הפוד.

אנו מגדירים אשכולות K8s באמצעות kubeadm, כאשר רשת המשנה של שירות ברירת המחדל היא 192.168.0.0/16, ורשת הפודים היא 10.244.0.0/16. בדרך כלל הכל עובד טוב, אבל יש כמה נקודות:

  • רשת משנה 192.168.*.* משמש לעתים קרובות ברשתות משרדיות של לקוחות, ואף לעתים קרובות יותר ברשתות ביתיות של מפתחים. ואז אנחנו מקבלים התנגשויות: נתבים ביתיים עובדים על רשת המשנה הזו וה-VPN דוחף את רשתות המשנה האלה מהאשכול ללקוח.
  • יש לנו מספר אשכולות (הפקה, במה ו/או מספר אשכולות פיתוח). לאחר מכן, כברירת מחדל, לכולם יהיו אותן רשתות משנה עבור פודים ושירותים, מה שיוצר קשיים גדולים לעבודה בו זמנית עם שירותים במספר אשכולות.

כבר מזמן אימצנו את הפרקטיקה של שימוש בתתי רשתות שונות עבור שירותים ופודים בתוך אותו פרויקט – באופן כללי, כך שלכל האשכולות יש רשתות שונות. עם זאת, ישנם מספר רב של אשכולות בפעולה שלא הייתי רוצה לגלגל עליהם מאפס, מכיוון שהם מריצים שירותים רבים, יישומים מצביים וכו'.

ואז שאלנו את עצמנו: איך משנים את רשת המשנה באשכול קיים?

חיפוש החלטות

הנוהג הנפוץ ביותר הוא ליצור מחדש כל שירותים עם סוג ClusterIP. כאופציה, יכול לייעץ וזה:

לתהליך הבא יש בעיה: לאחר שהכל מוגדר, הפודים מגיעים עם ה-IP הישן כשרת שמות DNS ב-/etc/resolv.conf.
מכיוון שעדיין לא מצאתי את הפתרון, הייתי צריך לאפס את כל האשכול עם איפוס kubeadm ולהפעיל אותו שוב.

אבל זה לא מתאים לכל אחד... להלן הקדמות מפורטות יותר למקרה שלנו:

  • נעשה שימוש בפלנל;
  • יש אשכולות גם בעננים וגם בחומרה;
  • ברצוני להימנע מפריסה מחדש של כל השירותים באשכול;
  • יש צורך בדרך כלל לעשות הכל עם מספר מינימלי של בעיות;
  • גרסת 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:

  • ליצור deserializer;
  • הידור ביטוי רגולרי כדי להחליף את CIDR;
  • אנו עוברים על כל השירותים עם סוג ClusterIP באשכול:
    • פענוח הערך מ-etcd לאובייקט Go;
    • באמצעות ביטוי רגולרי נחליף את שני הבייטים הראשונים של הכתובת;
    • להקצות לשירות כתובת IP מרשת המשנה החדשה;
    • ליצור סדרה, להמיר את האובייקט Go ל-protobuf, לכתוב נתונים חדשים ל-etcd.

פונקציה changePodCIDR דומה בעיקרו changeServiceCIDR - רק במקום לערוך את מפרט השירות, אנו עושים זאת עבור הצומת ומשנים .spec.PodCIDR לרשת משנה חדשה.

עיסוק

שנה שירות CIDR

התוכנית ליישום המשימה פשוטה מאוד, אך היא כרוכה בזמן השבתה בזמן יצירה מחדש של כל הפודים באשכול. לאחר תיאור השלבים העיקריים, נשתף גם מחשבות כיצד, בתיאוריה, ניתן למזער את זמן ההשבתה הזה.

שלבי הכנה:

  • התקנת התוכנה הדרושה והרכבת ה-patched etcdhelper;
  • גיבוי וכו' ו /etc/kubernetes.

תוכנית פעולה קצרה לשינוי שירותCIDR:

  • שינוי המניפסטים של שרת apiserver ובקר-מנהל;
  • הנפקה מחדש של תעודות;
  • שינוי שירותי ClusterIP ב-etcd;
  • הפעלה מחדש של כל התרמילים באשכול.

להלן רצף שלם של פעולות בפירוט.

1. התקן etcd-client עבור dump נתונים:

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. כל מה שנותר הוא להפעיל מחדש את כל הפודים באשכול:
    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. החלף את הכתובת בכל הקובלטים 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 במרחב השמות 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, כלומר. עקיפת ממשק ה-API של Kubernetes. לפעמים גישה זו מאפשרת לך לעשות "דברים מסובכים". בדקנו את הפעולות המפורטות בטקסט על אשכולות K8s אמיתיים. עם זאת, מצב המוכנות שלהם לשימוש נרחב הוא PoC (הוכחת הרעיון). לכן, אם אתה רוצה להשתמש בגרסה שונה של כלי השירות etcdhelper באשכולות שלך, עשה זאת על אחריותך בלבד.

נ.ב.

קרא גם בבלוג שלנו:

מקור: www.habr.com

הוספת תגובה