ProHoster > Blog > administración > Nuestra experiencia con datos en etcd Kubernetes cluster directamente (sin API K8s)
Nuestra experiencia con datos en etcd Kubernetes cluster directamente (sin API K8s)
Cada vez más, los clientes nos piden que les demos acceso al cluster de Kubernetes para poder acceder a servicios dentro del cluster: para poder conectarnos directamente a alguna base de datos o servicio, para conectar una aplicación local con aplicaciones dentro del cluster…
Por ejemplo, es necesario conectarse desde su máquina local a un servicio memcached.staging.svc.cluster.local. Proporcionamos esta capacidad utilizando una VPN dentro del clúster al que se conecta el cliente. Para hacer esto, anunciamos subredes de pods, servicios y enviamos DNS del clúster al cliente. Así, cuando un cliente intenta conectarse al servicio memcached.staging.svc.cluster.local, la solicitud va al DNS del clúster y en respuesta recibe la dirección de este servicio de la red de servicios del clúster o la dirección del pod.
Configuramos clústeres K8 usando kubeadm, donde la subred de servicio predeterminada es 192.168.0.0/16, y la red de pods es 10.244.0.0/16. Normalmente todo funciona bien, pero hay un par de puntos:
Subred 192.168.*.* Se utiliza a menudo en redes de oficinas de clientes y, aún más a menudo, en redes domésticas de desarrolladores. Y luego tenemos conflictos: los enrutadores domésticos funcionan en esta subred y la VPN envía estas subredes desde el clúster al cliente.
Contamos con varios clusters (producción, stage y/o varios clusters de desarrollo). Luego, de forma predeterminada, todos tendrán las mismas subredes para pods y servicios, lo que crea grandes dificultades para trabajar simultáneamente con servicios en varios clústeres.
Hace mucho tiempo que adoptamos la práctica de utilizar diferentes subredes para servicios y pods dentro del mismo proyecto, en general, para que todos los clústeres tengan redes diferentes. Sin embargo, hay una gran cantidad de clústeres en funcionamiento que no me gustaría renovar desde cero, ya que ejecutan muchos servicios, aplicaciones con estado, etc.
Y entonces nos preguntamos: ¿cómo cambiar la subred en un cluster existente?
Buscar soluciones
La práctica más común es recrear todos servicios con tipo ClusterIP. Como una opción, puede aconsejar y tal:
El siguiente proceso tiene un problema: después de configurar todo, los pods muestran la IP anterior como servidor de nombres DNS en /etc/resolv.conf.
Como todavía no encontré la solución, tuve que restablecer todo el clúster con kubeadm reset e iniciarlo nuevamente.
Pero esto no es adecuado para todos... Aquí hay introducciones más detalladas para nuestro caso:
Se utiliza franela;
Hay clusters tanto en las nubes como en el hardware;
Me gustaría evitar volver a implementar todos los servicios en el clúster;
En general, es necesario hacer todo con un número mínimo de problemas;
La versión de Kubernetes es 1.16.6 (sin embargo, los pasos posteriores serán similares para otras versiones);
La tarea principal es garantizar que en un clúster implementado usando kubeadm con una subred de servicio 192.168.0.0/16, reemplácelo con 172.24.0.0/16.
Y resultó que hacía tiempo que estábamos interesados en ver qué y cómo se almacena en Kubernetes en etcd, qué se puede hacer con ello... Así que pensamos: “¿Por qué no simplemente actualizar los datos en etcd, reemplazando las direcciones IP antiguas (subred) por otras nuevas?? "
Después de buscar herramientas listas para usar para trabajar con datos en etcd, no encontramos nada que resolviera completamente el problema. (Por cierto, si conoce alguna utilidad para trabajar con datos directamente en etcd, agradeceríamos los enlaces). Sin embargo, un buen punto de partida es etcdhelper de OpenShift(¡gracias a sus autores!).
Esta utilidad puede conectarse a etcd mediante certificados y leer datos desde allí mediante comandos ls, get, dump.
Agregar etcdhelper
El siguiente pensamiento es lógico: "¿Qué le impide agregar esta utilidad agregando la capacidad de escribir datos en etcd?"
Se convirtió en una versión modificada de etcdhelper con dos nuevas funciones. changeServiceCIDR и changePodCIDR. sobre su puedes ver el código aquí.
¿Qué hacen las nuevas funciones? Algoritmo changeServiceCIDR:
crear un deserializador;
compilar una expresión regular para reemplazar CIDR;
Revisamos todos los servicios con el tipo ClusterIP en el cluster:
decodificar el valor de etcd en un objeto Go;
usando una expresión regular reemplazamos los dos primeros bytes de la dirección;
asignar al servicio una dirección IP de la nueva subred;
cree un serializador, convierta el objeto Go en protobuf, escriba nuevos datos en etcd.
Función changePodCIDR esencialmente similar changeServiceCIDR - solo que en lugar de editar la especificación del servicio, lo hacemos para el nodo y cambiamos .spec.PodCIDR a una nueva subred.
Práctica
Cambiar servicio CIDR
El plan para implementar la tarea es muy simple, pero implica un tiempo de inactividad al momento de recrear todos los pods en el clúster. Después de describir los pasos principales, también compartiremos ideas sobre cómo, en teoría, se puede minimizar este tiempo de inactividad.
Pasos preparatorios:
instalar el software necesario y ensamblar el etcdhelper parcheado;
copia de seguridad, etc. y /etc/kubernetes.
Breve plan de acción para cambiar el servicioCIDR:
cambiar los manifiestos de apiserver y controlador-administrador;
reemisión de certificados;
cambiar los servicios ClusterIP en etcd;
reinicio de todos los pods del clúster.
La siguiente es una secuencia completa de acciones en detalle.
Ahorramos para nosotros mismos etcdhelper.go, descargar dependencias, recopilar:
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
4. Cambie la subred del servicio en los manifiestos del plano de control de Kubernetes. en archivos /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml cambiar el parámetro --service-cluster-ip-range a una nueva subred: 172.24.0.0/16 en lugar de 192.168.0.0/16.
5. Dado que estamos cambiando la subred de servicio a la que kubeadm emite certificados para un servidor (incluido), es necesario volver a emitirlos:
Veamos para qué dominios y direcciones IP se ha emitido el certificado actual:
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
¡Atención! En este momento, la resolución de dominio deja de funcionar en el cluster, ya que en los pods existentes /etc/resolv.conf se registra la antigua dirección CoreDNS (kube-dns) y kube-proxy cambia las reglas de iptables de la subred antigua a la nueva. Más adelante en el artículo se describen posibles opciones para minimizar el tiempo de inactividad.
Arreglemos ConfigMap en el espacio de nombres kube-system:
kubectl -n kube-system edit cm kubelet-config-1.16
- reemplazar aquí clusterDNS a la nueva dirección IP del servicio kube-dns: kubectl -n kube-system get svc kube-dns.
kubectl -n kube-system edit cm kubeadm-config
- lo arreglaremos data.ClusterConfiguration.networking.serviceSubnet a una nueva subred.
Dado que la dirección de kube-dns cambió, es necesario actualizar la configuración de kubelet en todos los nodos:
Todo lo que queda es reiniciar todos los pods del clúster:
kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'
Minimizar el tiempo de inactividad
Pensamientos sobre cómo minimizar el tiempo de inactividad:
Después de cambiar los manifiestos del plano de control, cree un nuevo servicio kube-dns, por ejemplo, con el nombre kube-dns-tmp y nueva dirección 172.24.0.10.
hacer if en etcdhelper, que no modificará el servicio kube-dns.
Reemplazar la dirección en todos los kubelets. ClusterDNS a uno nuevo, mientras que el antiguo servicio seguirá funcionando simultáneamente con el nuevo.
Espere hasta que los módulos con aplicaciones se volteen solos por razones naturales o en un momento acordado.
Eliminar servicio kube-dns-tmp y cambio serviceSubnetCIDR para el servicio kube-dns.
Este plan le permitirá minimizar el tiempo de inactividad a ~un minuto, mientras dure la eliminación del servicio. kube-dns-tmp y cambiar la subred para el servicio kube-dns.
Red de pod de modificación
Al mismo tiempo, decidimos ver cómo modificar podNetwork usando el etcdhelper resultante. La secuencia de acciones es la siguiente:
arreglando configuraciones en kube-system;
arreglar el manifiesto kube-controller-manager;
cambie podCIDR directamente en etcd;
reinicie todos los nodos del clúster.
Ahora más sobre estas acciones:
1. Modifique ConfigMap en el espacio de nombres kube-system:
kubectl -n kube-system edit cm kubeadm-config
- corrigiendo data.ClusterConfiguration.networking.podSubnet a una nueva subred 10.55.0.0/16.
6. Reiniciemos todos los nodos del clúster uno por uno.
7. Si dejas al menos un nodo vaina viejaCIDR, entonces kube-controller-manager no podrá iniciarse y los pods en el clúster no se programarán.
De hecho, cambiar podCIDR se puede hacer aún más simple (por ejemplo, tan). Pero queríamos aprender a trabajar con etcd directamente, porque hay casos al editar objetos de Kubernetes en etcd: единственный posible variante. (Por ejemplo, no puedes simplemente cambiar el campo Servicio sin tiempo de inactividad spec.clusterIP.)
Total
El artículo analiza la posibilidad de trabajar con datos en etcd directamente, es decir. sin pasar por la API de Kubernetes. A veces, este enfoque te permite hacer "cosas complicadas". Probamos las operaciones indicadas en el texto en clústeres K8 reales. Sin embargo, su estado de preparación para un uso generalizado es PoC (prueba de concepto). Por lo tanto, si desea utilizar una versión modificada de la utilidad etcdhelper en sus clústeres, hágalo bajo su propia responsabilidad.