Semakin sering, pelanggan meminta kami untuk memberikan akses ke kluster Kubernet untuk kemungkinan mengakses layanan di dalam kluster: agar dapat terhubung langsung ke beberapa basis data atau layanan, untuk menghubungkan aplikasi lokal dengan aplikasi di dalam kluster ...Misalnya, ada kebutuhan untuk menyambungkan dari mesin lokal Anda ke layanan memcached.staging.svc.cluster.local
. Kami memberikan kesempatan seperti itu menggunakan VPN di dalam kluster tempat klien terhubung. Untuk melakukan ini, kami mengumumkan subnet pods, layanan, dan push DNS cluster ke klien. Dengan demikian, ketika klien mencoba untuk terhubung ke layanan memcached.staging.svc.cluster.local
, permintaan pergi ke DNS cluster dan sebagai tanggapannya menerima alamat layanan ini dari jaringan layanan cluster atau alamat pod.Kami mengkonfigurasi cluster K8 menggunakan kubeadm, di mana subnet layanan secara default 192.168.0.0/16
dan jaringan pod 10.244.0.0/16
. Biasanya semuanya bekerja dengan baik, tetapi ada beberapa poin:- Subnet
192.168.*.*
sering digunakan di jaringan kantor klien, dan bahkan lebih sering di jaringan rumah pengembang. Dan kemudian kita mendapatkan konflik: router rumah bekerja pada subnet ini dan VPN mendorong subnet ini dari cluster ke klien. - Kami memiliki beberapa cluster (produksi, panggung, dan / atau beberapa cluster dev). Kemudian di semua dari mereka secara default akan ada subnet yang sama untuk pod dan layanan, yang menciptakan kesulitan besar untuk bekerja dengan layanan di beberapa cluster secara bersamaan.
Untuk beberapa waktu sekarang kami telah mengadopsi praktik menggunakan subnet yang berbeda untuk layanan dan polong dalam proyek yang sama - secara umum, sehingga semua cluster dengan jaringan yang berbeda. Namun, ada sejumlah besar cluster yang beroperasi yang saya tidak ingin gulung dari awal, karena mereka menjalankan banyak layanan, aplikasi stateful, dll.Dan kemudian kami bertanya pada diri sendiri: bagaimana saya akan mengubah subnet di cluster yang ada?Mencari keputusan
Praktik paling umum adalah membuat kembali semua layanan dengan tipe ClusterIP. Atau, mereka juga dapat menyarankan ini:Proses berikut memiliki masalah: setelah semuanya dikonfigurasi, pod muncul dengan IP lama sebagai server nama DNS di /etc/resolv.conf.
Karena saya masih belum menemukan solusinya, saya harus mengatur ulang seluruh cluster dengan reset kubeadm dan init lagi.
Tapi ini tidak cocok untuk semua orang ... Berikut adalah catatan pengantar yang lebih rinci untuk kasus kami:- Digunakan oleh Flannel;
- Ada kelompok di awan dan di atas besi;
- Saya ingin menghindari penyebaran berulang semua layanan di cluster;
- Ada kebutuhan untuk melakukan segalanya dengan masalah minimal;
- Versi Kubernetes adalah 1.16.6 (namun, tindakan lebih lanjut akan serupa untuk versi lain);
- Tugas utama adalah untuk
192.168.0.0/16
menggantinya dengan cluster yang digunakan menggunakan kubeadm dengan subnet layanan 172.24.0.0/16
.
Dan kebetulan bahwa untuk waktu yang lama itu menarik bagi kami untuk melihat apa dan bagaimana di Kubernet disimpan di etcd, apa yang dapat dilakukan dengan itu sama sekali ... Jadi kami berpikir: โ Mengapa tidak memperbarui data di etcd dengan mengganti alamat IP lama (subnet) ke yang baru ? "Mencari alat yang sudah jadi untuk bekerja dengan data di etcd, kami tidak menemukan apa pun yang sepenuhnya menyelesaikan tugas. (Omong-omong, jika Anda tahu tentang utilitas untuk bekerja dengan data secara langsung di etcd, kami akan berterima kasih atas tautannya .) Namun, OpenShift etcdhelper menjadi titik awal yang baik (terima kasih kepada penulisnya!) .Utilitas ini dapat terhubung ke etcd menggunakan sertifikat dan membaca data dengan menggunakan perintah ls
, get
, dump
.Tambahkan etcdhelper
Pikiran berikut ini logis: "Apa yang mencegah untuk menambah utilitas ini, menambahkan kemampuan untuk menulis data ke etcd?"Ini telah diterjemahkan ke dalam versi modifikasi etcdhelper dengan dua fitur baru changeServiceCIDR
dan changePodCIDR
. Anda dapat melihat kodenya di sini .Apa yang dilakukan fitur baru? Algoritma changeServiceCIDR
:- buat deserializer;
- kompilasi ekspresi reguler untuk menggantikan CIDR;
- kami melewati semua layanan dengan tipe ClusterIP di cluster:
- mendekode nilai dari etcd ke objek Go;
- menggunakan ekspresi reguler, ganti dua byte pertama dari alamat;
- menetapkan layanan alamat IP dari subnet baru;
- membuat serializer, mengonversi objek Go ke protobuf, menulis data baru ke etcd.
Fungsinya changePodCIDR
pada dasarnya sama changeServiceCIDR
- hanya alih-alih mengedit spesifikasi layanan, kami melakukannya untuk node dan mengubahnya .spec.PodCIDR
ke subnet baru.Praktek
Ubah serviceCIDR
Rencana untuk implementasi tugas sangat sederhana, tetapi melibatkan downtime pada saat penciptaan kembali semua pod di cluster. Setelah menjelaskan langkah-langkah utama, kami juga akan membagikan pemikiran kami tentang bagaimana, secara teori, yang sederhana ini dapat diminimalisir.Tindakan persiapan:- menginstal perangkat lunak yang diperlukan dan memasang etcdhelper yang ditambal;
- dlld cadangan dan
/etc/kubernetes
.
Rencana tindakan singkat untuk mengubah serviceCIDR:- Memodifikasi manifestasi apiserver dan pengontrol-manajer
- penerbitan kembali sertifikat;
- Layanan ClusterIP berubah di etcd;
- mulai ulang semua pod dalam sebuah cluster.
Berikut ini adalah urutan lengkap tindakan secara terperinci.1. Instal etcd-client untuk dump data:apt install etcd-client
2. Kami mengumpulkan bantuan dll:- Kami menempatkan 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
- Kami menyelamatkan diri
etcdhelper.go
, memuat dependensi, mengumpulkan:
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. Buat cadangan dlld: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. Ubah subnet layanan di manifes kontrol Kubernetes. Dalam file /etc/kubernetes/manifests/kube-apiserver.yaml
dan /etc/kubernetes/manifests/kube-controller-manager.yaml
ubah parameter --service-cluster-ip-range
ke subnet baru: 172.24.0.0/16
sebagai gantinya 192.168.0.0/16
.5. Karena kami mengubah subnet layanan yang kubeadm mengeluarkan sertifikat untuk apiserver (termasuk), mereka harus diterbitkan kembali:- Mari kita lihat domain dan alamat IP mana sertifikat saat ini dikeluarkan:
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
- Siapkan konfigurasi minimum untuk 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"
- Mari kita hapus crt dan kunci lama, karena tanpa ini sertifikat baru tidak akan dikeluarkan:
rm /etc/kubernetes/pki/apiserver.{key,crt}
- Pasang kembali sertifikat untuk server API:
kubeadm init phase certs apiserver --config=kubeadm-config.yaml
- , :
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
- API- :
docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
admin.conf
:
kubeadm alpha certs renew admin.conf
- 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
! , pod' /etc/resolv.conf
CoreDNS (kube-dns), kube-proxy iptables . . - 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
. - kube-dns, kubelet :
kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
- Tetap memulai ulang semua pod di kluster:
kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(\S+)\s+(\S+).*/kubectl --namespace \1 delete pod \2/e'
Meminimalkan Downtime
Pikiran tentang cara meminimalkan downtime:- Setelah mengubah manifestasi bidang kontrol, buat layanan kube-dns baru, misalnya, dengan nama
kube-dns-tmp
dan alamat baru 172.24.0.10
. - Buat
if
di etcdhelper, yang tidak akan mengubah layanan kube-dns. - Ganti alamat di semua kubelet
ClusterDNS
dengan yang baru, sementara layanan lama akan terus bekerja secara bersamaan dengan yang baru. - Tunggu polong dengan aplikasi bergulir sendiri karena alasan alami, atau pada waktu yang disepakati.
- Hapus layanan
kube-dns-tmp
dan ubah serviceSubnetCIDR
untuk layanan kube-dns.
Paket ini akan meminimalkan waktu henti hingga ~ satu menit - untuk saat layanan dihapus kube-dns-tmp
dan subnet untuk layanan diganti kube-dns
.Modifikasi podNetwork
Pada saat yang sama, kami memutuskan untuk melihat cara memodifikasi podNetwork menggunakan etcdhelper yang dihasilkan. Urutan tindakan adalah sebagai berikut:- kami memperbaiki konfigurasi di
kube-system
; - kami memperbaiki manifes dari kube-controller-manager;
- kami mengubah podCIDR langsung di etcd;
- reboot semua node cluster.
Sekarang lebih lanjut tentang tindakan ini:1. Ubah ConfigMap di namespace kube-system
:kubectl -n kube-system edit cm kubeadm-config
- Memperbaiki data.ClusterConfiguration.networking.podSubnet
subnet baru 10.55.0.0/16
.kubectl -n kube-system edit cm kube-proxy
- kami benar data.config.conf.clusterCIDR: 10.55.0.0/16
.2. Ubah manifes controller-manager:vim /etc/kubernetes/manifests/kube-controller-manager.yaml
- kami benar --cluster-cidr=10.55.0.0/16
.3. Lihatlah nilai-nilai saat ini .spec.podCIDR
, .spec.podCIDRs
, .InternalIP
, .status.addresses
untuk semua node di cluster: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. Ganti podCIDR dengan membuat perubahan langsung ke 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. Periksa apakah podCIDR benar-benar berubah: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. Pada gilirannya, kami akan reboot semua node cluster.7. Jika setidaknya satu node meninggalkan podCIDR lama , maka kube-controller-manager tidak akan dapat memulai, dan pod di cluster tidak akan direncanakan.Bahkan, mengubah podCIDR dapat dibuat lebih mudah (misalnya, seperti ini ). Tapi kami ingin belajar bagaimana bekerja dengan etcd secara langsung, karena ada kasus ketika mengedit objek Kubernetes di etcd adalah satu - satunya pilihan yang mungkin. (Misalnya, Anda tidak bisa hanya mengubah bidang Layanan tanpa downtime spec.clusterIP
.)Total
Artikel ini mempertimbangkan kemungkinan bekerja dengan data di etcd secara langsung, mis. melewati API Kubernetes. Terkadang pendekatan ini memungkinkan Anda untuk melakukan "hal-hal yang rumit." Operasi yang dijelaskan dalam teks diuji pada kelompok K8 nyata. Namun, status kesiapan mereka untuk digunakan secara luas adalah PoC (proof of concept) . Karena itu, jika Anda ingin menggunakan versi modifikasi dari utilitas etcdhelper pada cluster Anda, lakukan dengan risiko dan risiko Anda sendiri.PS
Baca juga di blog kami: