K8s, Minikube : ¿Que son los replicasets?

Juan Spinelli
9 min readMay 11, 2020

--

Con esto de la cuarentena se pierde un poco la noción de los días así que continuamos con los posteos después de 2 semanas.

Estos son los post anteriores:

¿Que es un replicaset?

A grandes rasgos, es un objeto encargado de mantener el numero de replicas que nosotros vamos a definir en un template. Si algún pod se cae o alguien lo elimina, sera el replicaset el encargado de volverlo a levantar con las configuraciones que nosotros hayamos seteado.

Como vimos en el post anterior k8s, Minikube : ¿Que son los PODs?, los pods no pueden generarse por si solos, acá es donde entra en juego el replicaset y para hacerlo son necesarios los labels.

Resumiendo: Se encarga de mantener un numero n de pods definidos en el template.

Creando nuestro primer replicaset

Vamos a usar este ejemplo obtenido de la documentación (un poco modificado)

# https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: primerreplicaset
labels:
app: primerreplicaset
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: contpython1
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8082']
- name: contpython2
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8083']

Analizemoslo:

Lo primero diferente con respecto a los pods es el apiVersion

apps/v1

¿Por qué app? Porque es el APIGRUP, ¿donde lo veo?

kubectl api-resources

¿Y el kind? Mismo lugar

Este replicaset tiene la siguiente metadata:

  • name = primerreplicaset
  • label app =primerreplicaset

Va a estar monitoreando las replicas:

  • replicas: 4

Y va a tener un selector encargado de buscar en la metadata de los pods el label definido:

  • matchLabels = app: frontend

¿Que quiere decir esto?

Que si le decimos al replicaset que tienen que haber 2 replicas, lo primero que hacer es buscar si ya existe algún pod creado con el label definido y si no existe ninguno entonces crea el total de replicas (en unos min vamos a ver bien este tema)

Vamos a ejecutarlo:

kubectl apply -f nombre_del_archivo.yaml (en mi caso se llama replicas_set.yaml)kubectl apply -f replica_set.yaml

Se creo sin problemas y podemos ver los 4 pods que definimos en las replicas:

Si listamos los pods filtrando por el label que les pusimos nos tiene que traer lo mismo

labels: app: frontend

kubectl get pods -l app=frontend

Ahora podemos listar nuestro replicaset con el siguiente comando

kubectl get replicaset

O con el shortname

kubectl get rs

Los shortname también los vemos en el api-resources

Para ver el funcionamiento del replicaset vamos a eliminar 1 de los pods que se crearon con el label app= frontend

kubectl delete pod NAME_DE_ALGUN_POD

El ID es aleatorio, en este caso yo elimine el primerreplicaset-69hzr y automáticamente se creo el primerreplicaset-4w5g5

Ahora vamos a modificar el numero de replicas en el template a 3

# https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: primerreplicaset
labels:
app: primerreplicaset
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: contpython1
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8082']
- name: contpython2
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8083']

Aplicamos ese cambio

kubectl apply -f replica_set.yaml

Y automáticamente podemos ver como se eliminan los pods sobrantes con el label app frontend dejando el numero que pide el template, en este caso, 3

Al igual que en los pods, podemos usar comandos como el describe o mostrar el manifiesto para ver más información

kubectl describe replicaset primerreplicaset

Manifiesto en formato yaml o json

Owner references

Cuando el replicaset crea pods setea en sus metadatas el owner reference, o sea una referencia a si mismo para decir “estos pods son míos, yo me voy a encargar de replicarlos si alguno se cae o es eliminado”.

Como dije anteriormente cuando se ejecuta el replicaset primero busca si ya existe algún pod con el label definido, en caso de existir alguno se fija en la metadata si ese pod tiene un owner asociado, si no lo tiene, el replicaset “adopta” ese pod, entonces si tenia que crear 3 pods pero adopto 1, solo va a crear 2 para cumplir con el requerimiento.

En mi caso (luego de modificar las replicas para que hayan 3) se crearon estos pods:

  • primerreplicaset-8ltr8
  • primerreplicaset-psg9q
  • primerreplicaset-s6t5j

Vamos a ver el manifiesto del primerreplicaset-8ltr8

kubectl get pod primerreplicaset-8ltr8 -o yaml

Podemos ver el pod primerreplicaset-8ltr8 tiene como owner reference al replicaset primerreplicaset cuyo uid es 5183eda6–6a1c-49c6-bc75–75b3f83121ff

Ahora para ver que todo esta ok vamos a validar ese uid con el que tiene el replicaset

kubectl get replicaset primerreplicaset -o yaml

Ambos uid son idénticos, por lo que todo esta perfecto, el replicaset es “dueño” de ese pod.

replicaset 5183eda6-6a1c-49c6-bc75-75b3f83121ff == 
pod 5183eda6-6a1c-49c6-bc75-75b3f83121ff

Como un replicaset puede adoptar pods que ya estén creados en base al label y por qué esto puede generar problemas?

Los pods tienen que ser creados por un elemento de mayor nivel, si creamos pods sueltos puede pasar que al momento de ejecutar un replicaset usemos justo el mismo label que esos pods huérfanos. Al no tener owner reference el replicaset los va a adoptar y esto puede generar problemas porque pueden ser pods totalmente distintos a los que definimos en el template.

Vamos a verlo. Primero eliminamos todo lo que esta creado y después vamos a crear 2 pods sueltos con nginx:alpine

kubectl delete -f replica_set.yamlkubectl run test1 –image=nginx:alpinekubectl run test2 –image=nginx:alpin2

Esos pods no tienen label así que les colocamos los mismos que el replicaset (va a ser el mismo que corrimos antes con 4 replicas)

kubectl label pods test1 app=frontendkubectl label pods test2 app=frontend

Y ahora corremos el replica set pidiéndole 4 replicas, pero, el replicaset tiene detallado en el spec que los contenedores sean de python:3.6-alpine, así que vamos a tener pods con nginx y otros con python pero todos con el mismo label

# https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: primerreplicaset
labels:
app: primerreplicaset
spec:
replicas: 4
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: contpython1
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8082']
- name: contpython2
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8083']

Y aplicamos el yaml

kubectl apply -f replica_set.yaml

Acá empezaron los problemas. Si hacemos un get pods y ponemos como filtro el app=frontend podemos ver que están los dos que creamos antes mas 2 nuevos que creo el replicaset ya que le dijimos que queríamos 4 pods con el label app=frontend.

Como los dos que creamos sueltos no tenían owner reference el replicaset los “adopto” y ahora tenemos 2 pods con nginx:alpine cuando en el template declaramos que queremos que sean con python:3.6-alpine

kubectl get pods -l app=frontend

Veamos los owner references de primerreplicaset-9sk6d y de test1. Son dos pods totalmente distintos que ahora tienen el mismo owner reference

Comparemos contra el uid del replicaset

kubectl get replicasets primerreplicaset -o yaml

Replicaset uid = be8a7eb0–728c-405f-a24a-23d9d1ce673f

Pod suelto owner = be8a7eb0–728c-405f-a24a-23d9d1ce673f

Pod replicaset owner = be8a7eb0–728c-405f-a24a-23d9d1ce673f

Y ahí esta el problema, distintos pods asociados al mismo replicaset.

En este caso yo podría eliminar uno de los dos pods sueltos y el replicaset va a levantar uno nuevo pero basándose en lo que definimos en el template, o sea, eliminamos un pod de nginx y va a levantar uno de python.

Ahora si eliminamos el replicaset se van a eliminar los pods asociados inclusive el que creamos suelto porque tiene el mismo owner reference que los otros.

Hablemos de los problemas de los replicaset

El replicaset es el encargado de mantener un numero n de pods en base a un template

Pero que pasa si al ejemplo del replicaset que usamos queremos actualizarle la versión de python o queremos eliminar un contenedor? O sea un cambio directo en los containers.

No va a pasar nada, ya que lo único que esta haciendo el replicaset es ver un numero de pods que cumplan con los labels determinados, así que si aumentamos containers o cambiamos versiones, al ser el label igual el replicaset no va a detectar cambios y no va a tomar acciones.

Veamos un ejemplo.

Ejecutemos este replicaset con 2 replicas y 2 containers con python 3.6-alpine

apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: primerreplicaset
labels:
app: primerreplicaset
spec:
replicas:2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: contpython1
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8082']
- name: contpython2
image: python:3.6-alpine
command: ['sh', '-c', 'python -m http.server 8083']

Y ahora modificamos el replicaset para que solo cree un contenedor y modifique la versión de python a la 3.7-alpine

apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: primerreplicaset
labels:
app: primerreplicaset
spec:
replicas:2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: contpython1
image: python:3.7-alpine
command: ['sh', '-c', 'python -m http.server 8082']

Si aplicamos los cambios y hacemos un describe podemos ver que efectivamente se modifico EL replicaset

¿Pero que paso con los pods?

No se actualizaron, tenemos versiones antiguas con 2 containers

Si hacemos un describe del pod primerreplicaset-8kb5p

kubectl describe pod primerreplicaset-8kb5p

Podemos ver que siguen teniendo la versión antigua de python

¿Cómo podemos forzar la actualización?

Eliminando un pod, para que el replicaset lo genere con su nueva configuración

Pueden ver que se creo un nuevo pod con un solo container y si hacemos un describe podemos ver que tiene la versión python:3.7-alpine

kubectl describe pods primerreplicaset-j74ng

Actualizar 1000 pods de esta forma? Imposible

Conclusión

Un replica set (dueño de los pods) solo sirve para mantener el número de replicas definidos en el template

Para manejar actualizaciones, configuraciones, etc, existe otro elemento de más alto nivel llamado Deployment (dueño de los replicasets)

Pero este es un tema que vamos a ver en próximos post.

--

--

Juan Spinelli

… It has to start somewhere, it has to start sometime What better place than here, what better time than now?