ประสบการณ์ของเรากับข้อมูลในคลัสเตอร์ etcd Kubernetes โดยตรง (ไม่มี K8s API)

ลูกค้าขอให้เราให้การเข้าถึงคลัสเตอร์ Kubernetes มากขึ้นเพื่อให้สามารถเข้าถึงบริการภายในคลัสเตอร์ได้: เพื่อให้สามารถเชื่อมต่อกับฐานข้อมูลหรือบริการบางอย่างได้โดยตรง เพื่อเชื่อมต่อแอปพลิเคชันในเครื่องกับแอปพลิเคชันภายในคลัสเตอร์...

ประสบการณ์ของเรากับข้อมูลในคลัสเตอร์ etcd Kubernetes โดยตรง (ไม่มี K8s API)

ตัวอย่างเช่น จำเป็นต้องเชื่อมต่อจากเครื่องท้องถิ่นของคุณกับบริการ memcached.staging.svc.cluster.local. เรามอบความสามารถนี้โดยใช้ VPN ภายในคลัสเตอร์ที่ไคลเอนต์เชื่อมต่อ ในการดำเนินการนี้ เราจะประกาศซับเน็ตของพ็อด บริการ และพุช DNS ของคลัสเตอร์ไปยังไคลเอ็นต์ ดังนั้นเมื่อไคลเอนต์พยายามเชื่อมต่อกับบริการ memcached.staging.svc.cluster.localคำขอจะส่งไปที่ DNS ของคลัสเตอร์ และในการตอบสนองจะได้รับที่อยู่ของบริการนี้จากเครือข่ายบริการคลัสเตอร์หรือที่อยู่พ็อด

เรากำหนดค่าคลัสเตอร์ K8 โดยใช้ 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 โดยแทนที่ที่อยู่ IP เก่า (ซับเน็ต) ด้วยอันใหม่? "

หลังจากค้นหาเครื่องมือสำเร็จรูปสำหรับการทำงานกับข้อมูลใน ฯลฯ เราไม่พบสิ่งใดที่สามารถแก้ไขปัญหาได้อย่างสมบูรณ์ (อย่างไรก็ตาม หากคุณทราบเกี่ยวกับยูทิลิตี้ใด ๆ สำหรับการทำงานกับข้อมูลโดยตรงใน ฯลฯ เราจะขอบคุณลิงก์นี้) อย่างไรก็ตาม จุดเริ่มต้นที่ดีก็คือ ฯลฯผู้ช่วย จาก OpenShift (ขอบคุณผู้เขียน!).

ยูทิลิตี้นี้สามารถเชื่อมต่อกับ ฯลฯ โดยใช้ใบรับรองและอ่านข้อมูลจากที่นั่นโดยใช้คำสั่ง ls, get, dump.

เพิ่ม etcdhelper

ความคิดต่อไปก็มีเหตุผล: “อะไรขัดขวางไม่ให้คุณเพิ่มยูทิลิตี้นี้ด้วยการเพิ่มความสามารถในการเขียนข้อมูลลงใน etcd”

มันกลายเป็น etcdhelper เวอร์ชันดัดแปลงพร้อมฟังก์ชันใหม่สองฟังก์ชัน changeServiceCIDR и changePodCIDR. กับเธอ คุณสามารถดูรหัสได้ ที่นี่.

คุณสมบัติใหม่มีไว้ทำอะไร? อัลกอริทึม changeServiceCIDR:

  • สร้างดีซีเรียลไลเซอร์
  • รวบรวมนิพจน์ทั่วไปเพื่อแทนที่ CIDR
  • เราผ่านบริการทั้งหมดด้วยประเภท ClusterIP ในคลัสเตอร์:
    • ถอดรหัสค่าจาก etcd ลงในวัตถุ Go
    • การใช้นิพจน์ทั่วไปจะแทนที่สองไบต์แรกของที่อยู่
    • กำหนดที่อยู่ IP ให้กับบริการจากเครือข่ายย่อยใหม่
    • สร้างซีเรียลไลเซอร์, แปลงวัตถุ Go เป็น protobuf, เขียนข้อมูลใหม่ไปที่ etcd

ฟังก์ชัน changePodCIDR คล้ายกันโดยพื้นฐานแล้ว changeServiceCIDR - แทนที่จะแก้ไขข้อกำหนดการบริการ เราทำเพื่อโหนดและเปลี่ยนแปลง .spec.PodCIDR ไปยังซับเน็ตใหม่

การปฏิบัติ

เปลี่ยนบริการ CIDR

แผนการดำเนินงานนั้นง่ายมาก แต่เกี่ยวข้องกับการหยุดทำงานในขณะที่สร้างพ็อดทั้งหมดในคลัสเตอร์ขึ้นมาใหม่ หลังจากอธิบายขั้นตอนหลักแล้ว เราจะแบ่งปันความคิดเกี่ยวกับวิธีการลดการหยุดทำงานนี้ในทางทฤษฎีด้วย

ขั้นตอนการเตรียมการ:

  • ติดตั้งซอฟต์แวร์ที่จำเป็นและประกอบ etcdhelper ที่ได้รับการติดตั้งแล้ว
  • สำรองข้อมูล ฯลฯ และ /etc/kubernetes.

แผนปฏิบัติการโดยย่อสำหรับการเปลี่ยนแปลงบริการCIDR:

  • การเปลี่ยนรายการ apiserver และตัวควบคุม - ผู้จัดการ
  • การออกใบรับรองใหม่
  • การเปลี่ยนบริการ ClusterIP ใน etcd;
  • รีสตาร์ทพ็อดทั้งหมดในคลัสเตอร์

ต่อไปนี้เป็นลำดับการดำเนินการโดยละเอียด

1. ติดตั้ง etcd-client สำหรับการถ่ายโอนข้อมูล:

apt install etcd-client

2. สร้าง etcdhelper:

  • ติดตั้งโกลัง:
    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. แทนที่ที่อยู่ใน kubelets ทั้งหมด ClusterDNS ไปเป็นบริการใหม่ในขณะที่บริการเก่าจะยังคงทำงานไปพร้อมกับบริการใหม่
  4. รอจนกว่าพ็อดที่มีแอปพลิเคชันจะพลิกคว่ำด้วยตัวเองด้วยเหตุผลตามธรรมชาติหรือตามเวลาที่ตกลงกัน
  5. ลบบริการ kube-dns-tmp และเปลี่ยนแปลง serviceSubnetCIDR สำหรับบริการ kube-dns

แผนนี้จะช่วยให้คุณสามารถลดการหยุดทำงานให้เหลือ ~ นาที - ตลอดระยะเวลาของการลบบริการ kube-dns-tmp และเปลี่ยนซับเน็ตเพื่อใช้บริการ kube-dns.

การปรับเปลี่ยนพ็อดเครือข่าย

ในเวลาเดียวกัน เราตัดสินใจที่จะดูวิธีแก้ไข 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 โดยตรง เช่น ข้าม Kubernetes API บางครั้งวิธีนี้อาจทำให้คุณทำ "สิ่งที่ยุ่งยากได้" เราทดสอบการดำเนินการที่ให้ไว้ในข้อความบนคลัสเตอร์ K8 จริง อย่างไรก็ตามสถานะความพร้อมในการใช้งานอย่างแพร่หลายคือ PoC (พิสูจน์แนวคิด). ดังนั้น หากคุณต้องการใช้ยูทิลิตี้ etcdhelper เวอร์ชันแก้ไขบนคลัสเตอร์ของคุณ ให้ดำเนินการดังกล่าวด้วยความเสี่ยงของคุณเอง

PS

อ่านเพิ่มเติมในบล็อกของเรา:

ที่มา: will.com

เพิ่มความคิดเห็น