¿Qué vamos a ver?
Basado en la documentación oficial de K8s (licencia CC-BY-4.0).
>_.source <(kubectl completion bash)
Comprueba que funciona escribiendo kubectl y presionando la tecla "TAB" 2 veces.Vamos a crear un nuevo clúster de K8s con más recursos para poder desplegar Zookeeper:
gcloud container clusters create lab-zookeeper --num-nodes 4 --machine-type n1-standard-2 --zone europe-west1-c
gcloud container clusters get-credentials lab-zookeeper --zone europe-west1-c
kubectl cluster-info
Para configurarlo, debemos crear una StorageClass disponible en el clúster.
volumes/fast-storageclass.yaml con este manifiesto:apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
kubectl apply -f volumes/fast-storageclass.yaml
Vamos a utilizar un manifiesto compuesto para desplegar múltiples objetos a la misma vez: un Servicio "headless", un Servicio, un PodDisruptionBudget y un StatefulSet.
app/zookeeper.yaml con este manifiesto:apiVersion: v1
kind: Service
metadata:
name: zk-hs
labels:
app: zk
spec:
ports:
- port: 2888
name: server
- port: 3888
name: leader-election
clusterIP: None
selector:
app: zk
---
apiVersion: v1
kind: Service
metadata:
name: zk-cs
labels:
app: zk
spec:
ports:
- port: 2181
name: client
selector:
app: zk
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
selector:
matchLabels:
app: zk
maxUnavailable: 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zk
spec:
selector:
matchLabels:
app: zk
serviceName: zk-hs
replicas: 3
updateStrategy:
type: RollingUpdate
podManagementPolicy: OrderedReady
template:
metadata:
labels:
app: zk
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- zk
topologyKey: "kubernetes.io/hostname"
containers:
- name: kubernetes-zookeeper
imagePullPolicy: Always
image: "k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10"
resources:
requests:
memory: "1Gi"
cpu: "0.5"
ports:
- containerPort: 2181
name: client
- containerPort: 2888
name: server
- containerPort: 3888
name: leader-election
command:
- sh
- -c
- "start-zookeeper \
--servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
readinessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
volumeMounts:
- name: datadir
mountPath: /var/lib/zookeeper
securityContext:
runAsUser: 1000
fsGroup: 1000
volumeClaimTemplates:
- metadata:
name: datadir
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
kubectl apply -f app/zookeeper.yaml
kubectl get services
kubectl get poddisruptionbudget
kubectl get statefulsets
kubectl get pods -l app=zk -w
kubectl describe services cassandra -n lab-statefulsets-cassandra
Una vez que el pod zk-2 esté en estado Running puedes detener el comando "watch" con CTRL + C.Cada servidor en el conjunto de Zookeeper necesita un identificador único, asociado con una dirección de red, que todos los servidores necesitan conocer.
Revisa los hostname de los Pods del StatefulSet:
for i in 0 1 2; do kubectl exec zk-$i -- hostname; done
Los servidores de Zookeeper usan enteros como identificadores únicos y guardan el identificador de cada servidor en un archivo myid en el directorio de datos.
Examina dicho archivo en cada servidor:
for i in 0 1 2; do echo "myid zk-$i; kubectl exec zk-$i -- cat /var/lib/zookeeper/data/myid; done
Lista el FQDN de cada Pod:
for in in 0 1 2; do kubectl exec zk-$i -- hostname -f; done
El K8s DNS resuelve los FQDN. Si el Pod es redesplegado en otro lugar, los registros A del DNS no cambiarán, sólo serán actualizados con las nuevas direcciones IP de los Pods.
Revisa el archivo de configuración de la aplicación:
kubectl exec zk-0 -- cat /opt/zookeeper/conf/zoo.cfg
Los protocolos de consenso requieren que los identificadores sean únicos para que puedan confirmar qué procesos han enviado qué datos.
Los registros A para cada Pod se crean cuando el Pod llega al estado Ready, por lo que los FQDN apuntan a un único endpoint, un único servidor.
Ésto se consigue gracias al despliegue escalonado de Pods del StatefulSet.
Vamos a escribir datos en un servidor Zookeeper y leerlos desde otro para confirmar que todo está desplegado correctamente.
world en el path /hello en el Pod zk-0:kubectl exec zk-0 zkCli.sh create /hello world
zk-1:kubectl exec zk-1 zkCli.sh get /hello
Ésto verificará que los datos que hemos escrito a zk-0 están disponibles en todos los servidores del conjunto.
Zookeeper mantiene todas las entradas en un WAL duradero y escribe instantáneas de memoria a un medio de almacenamiento para conseguir replicar el estado.
kubectl delete statefulset zk
kubectl get pods -l app=zk -w
Usa CTRL + C cuando se haya eliminado el último Pod, zk-0.kubectl apply -f app/zookeeper.yaml
kubectl get pods -l app=zk -w
kubectl exec zk-2 zkCli.sh get /hello
Podrás comprobar como los datos han persistido en el Volumen Persistente.kubectl get pvc -l app=zk
Cuando un Pod en el StatefulSet es recreado, mantiene el mismo PersistentVolume asociado montado en el directorio de datos.
Vamos a planificar ante el caso de eventos de mantenimiento que provoquen fallos en un Nodo.
kubectl get nodes
kubectl get pdb zk-pdb
kubectl get pods l app=zk -w
for i in 0 1 2; do kubectl get pod zk-$i --template {{.spec.nodeName}}; echo ""; done
zk-0:kubectl drain $(kubectl get pod zk-0 --template {{.spec.nodeName}}) --ignore-daemonsets --force --delete-local-data
El pod zk-0 será redesplegado en otro de los 3 Nodos disponibles.zk-1:kubectl drain $(kubectl get pod zk-0 --template {{.spec.nodeName}}) --ignore-daemonsets --force --delete-local-data
El Pod no puede ser redesplegado por la regla de podAntiAffinity, por lo que queda en estado de Pending.gcloud container clusters delete lab-zookeeper --zone europe-west1-c
En esta práctica hemos visto cómo: