De plus en plus souvent, les clients se tournent vers nous avec une demande d'accÚs au cluster Kubernetes pour la possibilité d'accéder à des services au sein du cluster: afin de pouvoir se connecter directement à une base de données ou un service, pour connecter l'application locale avec des applications au sein du cluster ...
Par exemple, il est nécessaire de se connecter de votre machine locale au service memcached.staging.svc.cluster.local
. Nous fournissons cette opportunité avec un VPN à l'intérieur du cluster auquel le client se connecte. Pour ce faire, nous annonçons les sous-réseaux de pods, services et push DNS du cluster au client. Ainsi, lorsque le client tente de se connecter au service memcached.staging.svc.cluster.local
, la demande est envoyĂ©e au DNS du cluster et reçoit en rĂ©ponse l'adresse de ce service du rĂ©seau de services du cluster ou l'adresse du pod.Nous configurons les clusters K8s Ă l'aide de kubeadm, oĂč le sous-rĂ©seau de service est par dĂ©faut 192.168.0.0/16
et le réseau de pods 10.244.0.0/16
. Habituellement, tout fonctionne bien, mais il y a quelques points:- Le sous-réseau est
192.168.*.*
souvent utilisĂ© dans les rĂ©seaux bureautiques de clients, et encore plus souvent dans les rĂ©seaux domestiques de dĂ©veloppeurs. Et puis nous obtenons des conflits: les routeurs domestiques fonctionnent sur ce sous-rĂ©seau et le VPN pousse ces sous-rĂ©seaux du cluster vers le client. - Nous avons plusieurs clusters (production, Ă©tape et / ou plusieurs clusters de dĂ©veloppement). Ensuite, dans chacun d'eux par dĂ©faut, il y aura les mĂȘmes sous-rĂ©seaux pour les pods et les services, ce qui crĂ©e de grandes difficultĂ©s pour travailler avec des services dans plusieurs clusters simultanĂ©ment.
Depuis un certain temps, nous avons adopté la pratique d'utiliser différents sous-réseaux pour les services et les pods dans le cadre d'un projet - en général, de sorte que tous les clusters soient avec des réseaux différents. Cependant, il existe un grand nombre de clusters en fonctionnement que je ne voudrais pas rouler à partir de zéro, car ils exécutent de nombreux services, applications avec état, etc.Et puis nous nous sommes demandé: comment changer le sous-réseau dans un cluster existant?Recherche de décisions
La pratique la plus courante consiste à recréer tous les services avec le type ClusterIP. Alternativement, ils peuvent également le conseiller :Le processus suivant a un problÚme: aprÚs tout configuré, les pods proposent l'ancien IP en tant que serveur de noms DNS dans /etc/resolv.conf.
Comme je n'ai toujours pas trouvé la solution, j'ai dû réinitialiser l'ensemble du cluster avec la réinitialisation de kubeadm et l'initier à nouveau.
Mais cela ne convient pas à tout le monde ... Voici des notes d'introduction plus détaillées pour notre cas:- Utilisé par Flannel;
- Il y a des grappes Ă la fois dans les nuages ââet sur le fer;
- Je voudrais éviter le déploiement répété de tous les services du cluster;
- Il faut tout faire avec un minimum de problĂšmes;
- La version de Kubernetes est 1.16.6 (cependant, d'autres actions seront similaires pour les autres versions);
- La tĂąche principale consiste Ă le
192.168.0.0/16
remplacer par un cluster déployé à l'aide de kubeadm avec un sous-réseau de service 172.24.0.0/16
.
Et il se trouve que pendant longtemps, il Ă©tait intĂ©ressant pour nous de voir quoi et comment dans Kubernetes il est stockĂ© dans etcd, ce qui peut ĂȘtre fait avec tout cela ... Nous avons donc pensĂ©: « Pourquoi ne pas simplement mettre Ă jour les donnĂ©es dans etcd en remplaçant les anciennes adresses IP (sous-rĂ©seau) aux nouveaux ? "Ă la recherche d'outils prĂȘts Ă l'emploi pour travailler avec des donnĂ©es dans etcd, nous n'avons rien trouvĂ© qui rĂ©sout complĂštement la tĂąche. (Soit dit en passant, si vous connaissez des utilitaires pour travailler directement avec des donnĂ©es dans etcd, nous vous serons reconnaissants pour les liens.) Cependant, OpenShift etcdhelper est devenu un bon point de dĂ©part (grĂące Ă ses auteurs!) .Cet utilitaire est capable de se connecter Ă l' aide de certificats ETCD et lire les donnĂ©es en utilisant les commandes ls
, get
, dump
.Ajouter etcdhelper
La pensĂ©e suivante est logique: "Qu'est-ce qui empĂȘche d'ajouter cet utilitaire, ajoutant la possibilitĂ© d'Ă©crire des donnĂ©es dans etcd?"Il a Ă©tĂ© traduit dans une version modifiĂ©e de etcdhelper avec deux nouvelles changeServiceCIDR
et fonctionnalités changePodCIDR
. Vous pouvez voir son code ici .Que font les nouvelles fonctionnalités? Algorithme changeServiceCIDR
:- créer un désérialiseur;
- compiler une expression réguliÚre pour remplacer CIDR;
- nous passons par tous les services avec le type ClusterIP dans le cluster:
- décode la valeur de etcd en l'objet Go;
- en utilisant une expression réguliÚre, remplacez les deux premiers octets de l'adresse;
- attribuer au service une adresse IP à partir d'un nouveau sous-réseau;
- créer un sérialiseur, convertir l'objet Go en protobuf, écrire de nouvelles données dans etcd.
La fonction changePodCIDR
est essentiellement la mĂȘme changeServiceCIDR
- seulement au lieu de modifier la spĂ©cification de service, nous le faisons pour le nĆud et le changeons .spec.PodCIDR
en un nouveau sous-réseau.Entraine toi
Changer de serviceCIDR
Le plan de mise en Ćuvre de la tĂąche est trĂšs simple, mais implique des temps d'arrĂȘt au moment de la recrĂ©ation de tous les pods du cluster. AprĂšs avoir dĂ©crit les principales Ă©tapes, nous partagerons Ă©galement nos rĂ©flexions sur la façon dont, en thĂ©orie, cette simple Ă©tape peut ĂȘtre minimisĂ©e.Actions prĂ©paratoires:- installer le logiciel nĂ©cessaire et assembler le etcdhelper patchĂ©;
- sauvegarde etcd et
/etc/kubernetes
.
Plan d'action court pour changer de serviceCIDR:- Modification des manifestes Apiserver et Controller-Manager
- réémission de certificats;
- Les services ClusterIP changent dans etcd;
- redémarrez tous les pods d'un cluster.
Ce qui suit est une séquence complÚte d'actions en détail.1. Installez etcd-client pour le vidage des données:apt install etcd-client
2. Nous collectons etcdhelper:- Nous mettons 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
- Nous nous sauvons
etcdhelper.go
, chargeons les dépendances, collectons:
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. Faites une sauvegarde etcd: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. Modifiez le sous-réseau de service dans les manifestes du plan de contrÎle Kubernetes. Dans les fichiers /etc/kubernetes/manifests/kube-apiserver.yaml
et /etc/kubernetes/manifests/kube-controller-manager.yaml
remplacez le paramĂštre --service-cluster-ip-range
par un nouveau sous-réseau: à la 172.24.0.0/16
place 192.168.0.0/16
.5. Ătant donnĂ© que nous modifions le sous-rĂ©seau de service auquel kubeadm Ă©met des certificats pour apiserver (y compris), ils doivent ĂȘtre réémis:- Voyons quels domaines et adresses IP le certificat actuel est Ă©mis:
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
- Préparez la configuration minimale pour 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"
- Supprimons l'ancien crt et la clé, car sans cela, aucun nouveau certificat ne sera émis:
rm /etc/kubernetes/pki/apiserver.{key,crt}
- Réémettez les certificats pour le serveur 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
- Il reste à redémarrer tous les pods du cluster:
kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(\S+)\s+(\S+).*/kubectl --namespace \1 delete pod \2/e'
Temps d'arrĂȘt minimisĂ©s
RĂ©flexions sur la façon de minimiser les temps d'arrĂȘt:- AprĂšs avoir modifiĂ© les manifestations du plan de contrĂŽle, crĂ©ez un nouveau service kube-dns, par exemple, avec un nom
kube-dns-tmp
et une nouvelle adresse 172.24.0.10
. - Make
if
in etcdhelper, qui ne modifiera pas le service kube-dns. - Remplacez l'adresse dans tous les kubelet
ClusterDNS
par une nouvelle, tandis que l'ancien service continuera de fonctionner simultanément avec le nouveau. - Attendez que les modules contenant des applications se déplacent seuls pour des raisons naturelles ou à une heure convenue.
- Supprimez le service
kube-dns-tmp
et modifiez-le serviceSubnetCIDR
pour le service kube-dns.
Ce plan minimisera les temps d'arrĂȘt jusqu'Ă ~ une minute - au moment de la suppression du service kube-dns-tmp
et du remplacement du sous-réseau du service kube-dns
.PodNetwork de modification
Dans le mĂȘme temps, nous avons dĂ©cidĂ© de voir comment modifier podNetwork en utilisant le etcdhelper rĂ©sultant. La sĂ©quence d'actions est la suivante:- nous corrigeons les configurations
kube-system
; - nous corrigeons le manifeste de kube-controller-manager;
- nous changeons podCIDR directement dans etcd;
- redĂ©marrez tous les nĆuds du cluster.
En savoir plus sur ces actions:1. Modifiez ConfigMap dans l'espace de noms kube-system
:kubectl -n kube-system edit cm kubeadm-config
- fixé data.ClusterConfiguration.networking.podSubnet
sur un nouveau sous-réseau 10.55.0.0/16
.kubectl -n kube-system edit cm kube-proxy
- nous corrigeons data.config.conf.clusterCIDR: 10.55.0.0/16
.2. Modifiez le manifeste du contrĂŽleur-gestionnaire:vim /etc/kubernetes/manifests/kube-controller-manager.yaml
- nous corrigeons --cluster-cidr=10.55.0.0/16
.3. Regardez les valeurs actuelles .spec.podCIDR
, .spec.podCIDRs
, .InternalIP
, .status.addresses
pour tous les nĆuds du 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. Remplacez podCIDR en apportant des modifications directement Ă 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. Vérifiez que podCIDR a vraiment changé: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. Ă son tour, nous redĂ©marrerons tous les nĆuds du cluster.7. Si au moins un nĆud quitte l'ancien podCIDR , le gestionnaire de contrĂŽleur de kube ne pourra pas dĂ©marrer et les pods du cluster ne seront pas planifiĂ©s.En fait, le changement de podCIDR peut ĂȘtre facilitĂ© (par exemple, comme ceci ). Mais nous voulions apprendre Ă travailler directement avec etcd, car il y a des cas oĂč l'Ă©dition d'objets Kubernetes dans etcd est la seule option possible. (Par exemple, vous ne pouvez pas simplement modifier le champ d'un service sans interruption spec.clusterIP
.)Total
L'article considÚre la possibilité de travailler directement avec des données dans etcd, c'est-à -dire contourner l'API Kubernetes. Parfois, cette approche vous permet de faire des «choses délicates». Les opérations décrites dans le texte ont été testées sur de vrais clusters K8. Cependant, leur état de préparation à une utilisation généralisée est PoC (preuve de concept) . Par conséquent, si vous souhaitez utiliser une version modifiée de l'utilitaire etcdhelper sur vos clusters, faites-le à vos risques et périls.PS
Lisez aussi dans notre blog: