تجربه ما با داده ها در etcd خوشه Kubernetes به طور مستقیم (بدون K8s API)

مشتریان به طور فزاینده ای از ما می خواهند که دسترسی به خوشه Kubernetes را فراهم کنیم تا بتوانند به خدمات درون خوشه دسترسی داشته باشند: به طوری که آنها بتوانند مستقیماً به پایگاه داده یا سرویس متصل شوند تا یک برنامه محلی را با برنامه های درون خوشه متصل کنند.

تجربه ما با داده ها در etcd خوشه Kubernetes به طور مستقیم (بدون K8s API)

به عنوان مثال، نیاز به اتصال از دستگاه محلی خود به یک سرویس وجود دارد memcached.staging.svc.cluster.local. ما این قابلیت را با استفاده از VPN در خوشه ای که مشتری به آن متصل می شود، ارائه می دهیم. برای انجام این کار، ما زیرشبکه‌های پادها، سرویس‌ها و push Cluster DNS را به مشتری اعلام می‌کنیم. بنابراین، هنگامی که یک مشتری سعی می کند به سرویس متصل شود memcached.staging.svc.cluster.local، درخواست به DNS خوشه می رود و در پاسخ آدرس این سرویس را از شبکه سرویس کلاستر یا آدرس پاد دریافت می کند.

ما خوشه‌های K8s را با استفاده از kubeadm پیکربندی می‌کنیم، جایی که زیرشبکه سرویس پیش‌فرض است 192.168.0.0/16، و شبکه غلاف ها است 10.244.0.0/16. معمولا همه چیز خوب کار می کند، اما چند نکته وجود دارد:

  • زیر شبکه 192.168.*.* اغلب در شبکه های اداری مشتری و حتی بیشتر در شبکه های خانگی توسعه دهندگان استفاده می شود. و سپس با تداخل مواجه می‌شویم: روترهای خانگی روی این زیرشبکه کار می‌کنند و VPN این زیرشبکه‌ها را از خوشه به مشتری هل می‌دهد.
  • ما چندین خوشه داریم (تولید، مرحله و/یا چندین خوشه توسعه دهنده). سپس به صورت پیش‌فرض، همه آن‌ها زیرشبکه‌های یکسانی برای پادها و سرویس‌ها خواهند داشت که مشکلات زیادی را برای کار همزمان با سرویس‌ها در چندین کلاستر ایجاد می‌کند.

ما مدت ها پیش روش استفاده از زیرشبکه های مختلف برای سرویس ها و پادها در یک پروژه را اتخاذ کرده ایم - به طور کلی، به طوری که همه خوشه ها دارای شبکه های مختلف هستند. با این حال، تعداد زیادی خوشه در حال کار هستند که من نمی‌خواهم از ابتدا آن‌ها را تغییر دهم، زیرا آنها بسیاری از خدمات، برنامه‌های دولتی و غیره را اجرا می‌کنند.

و سپس از خود پرسیدیم: چگونه می توان زیر شبکه را در یک خوشه موجود تغییر داد؟

جستجوی تصمیمات

متداول ترین روش بازآفرینی است همه خدمات با نوع ClusterIP. به عنوان یک گزینه، می تواند مشاوره دهد و این:

فرآیند زیر یک مشکل دارد: پس از پیکربندی همه چیز، پادها با IP قدیمی به عنوان سرور نام DNS در /etc/resolv.conf می آیند.
از آنجایی که هنوز راه حل را پیدا نکردم، مجبور شدم کل کلاستر را با reset 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 را تغییر دهید

طرح اجرای کار بسیار ساده است، اما شامل زمان از کار افتادن در زمان ایجاد مجدد همه غلاف ها در خوشه است. پس از تشریح مراحل اصلی، همچنین نظراتی را در مورد اینکه چگونه از نظر تئوری می توان این زمان از کار افتادگی را به حداقل رساند، به اشتراک خواهیم گذاشت.

مراحل مقدماتی:

  • نصب نرم افزار لازم و مونتاژ etcdhelper پچ شده.
  • پشتیبان گیری etcd و /etc/kubernetes.

برنامه اقدام مختصر برای تغییر سرویسCIDR:

  • تغییر مانیفست apiserver و controller-manager.
  • صدور مجدد گواهینامه؛
  • تغییر خدمات ClusterIP در etcd.
  • راه اندازی مجدد همه غلاف ها در خوشه.

در ادامه یک توالی کامل از اقدامات به تفصیل آمده است.

1. etcd-client را برای داده dump نصب کنید:

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. آدرس را در همه کوبلت ها جایگزین کنید 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. با ایجاد تغییرات مستقیم در etcd، podCIDR را جایگزین کنید:

./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 ویرایش می کنیم - تک تک نوع ممکن (به عنوان مثال، شما نمی توانید فقط قسمت Service را بدون خرابی تغییر دهید spec.clusterIP.)

مجموع

این مقاله امکان کار با داده ها در etcd را به طور مستقیم مورد بحث قرار می دهد. دور زدن Kubernetes API. گاهی اوقات این رویکرد به شما امکان می دهد "کارهای پیچیده" را انجام دهید. ما عملیات داده شده در متن را روی خوشه های واقعی K8 آزمایش کردیم. با این حال، وضعیت آمادگی آنها برای استفاده گسترده است PoC (اثبات مفهوم). بنابراین، اگر می خواهید از نسخه اصلاح شده ابزار etcdhelper در خوشه های خود استفاده کنید، این کار را با مسئولیت خود انجام دهید.

PS

در وبلاگ ما نیز بخوانید:

منبع: www.habr.com

اضافه کردن نظر