Después del curso de seguridad he vuelto un poco al mundo devops y sistemas y he comenzado uno de kubernetes, mas lo que estoy intentando aprender a través de la documentación oficial, que a priori resulta bastante buena.

Mi idea es montar un cluster en casa con unas cuentas cositas y de paso ir documentándolas en el blog, que siempre me viene muy bien para volver a recordar cómo se hace algo.

Así que voy a empezar por algo sencillo, para ir poniendo en práctica lo que he ido aprendiendo en el curso. Como siempre cualquier corrección o consejo es bienvenido, ya sea a través de comentario o redes sociales.

Lo primero que quiero hacer es crear un namespace para el tutorial, en él se encontrarán todos los elementos de kubernetes que voy a ir creando, así a la hora de eliminarlo todo nos bastará con eliminar el namespace.

Creación de un namespace

kubectl create namespace tutorial

Con este comando creamos un nuevo namespace donde podremos trabajar tranquilamente sin liarlo con otras cosas que tengamos en el cluster, como el cluster en si mismo.

Definimos el nuevo namespace como el actual

Para no tener que ir diciendo en todo momento en que namespace queremos realizar las acciones voy a definir el namespace tutorial como el actual, así todas las acciones que ejecute se harán dentro de él.

kubectl config set-context $(kubectl config current-context) --namespace=tutorial

Lo que hace es definir el contexto actual con el mismo valor que tenemos ahora mismo, esto es el cluster en el que vamos a realizar las acciones y el namespace que acabamos de crear.

¿Qué es un Pod?

Por definirlo con mis propias palabras, con lo que he aprendido (y si me equivoco corregidme): Es una unidad mínima escalable dentro de kubernetes en la cual pueden existir uno o mas contenedores.

Imaginemos que tenemos un Wordpress que queremos meter en un cluster, pues podríamos crear dos pods, uno con la base de datos, como es el caso y otra con el código como tal. Así a la hora de tener que escalar podemos escalar solo una de ellas. A parte quizás queramos meter algún contenedor de monitorización a la bbdd y al codigo, así que podríamos meterlo dentro de cada pod, para que escalasen juntos.

Creando una configuración MUY BÁSICA para MariaDB

A la hora de crear un pod o cualquier otro elemento de kubernetes lo podemos hacer a través de generadores (comandos) o de ficheros. Podemos ver los dos casos con el ejemplo siguiente:

kubectl run tutorial-db --image=mariadb:10.3.8 --restart=Never --port=3306 --dry-run -o yaml > tutorial_db.yaml

El comando anterior es un generador que crea un fichero. Los parámetros --dry-run y -o yaml hacen, primero que el generador no se ejecute contra el cluster, devuelva la salida y que lo haga en formato yaml.

Por otro lado estamos redirigiendo la salida a un fichero con > tutorial_db.yaml .

Si lo ejecutásemos sin los parámetros anteriores se lanzaría contra el cluster, creando el pod.

Destripando el generador

kubectl run tutorial-db --image=mariadb:10.3.8 --restart=Never --port=3306 --dry-run -o yaml > tutorial_db.yaml

Por partes:

run : Es la orden del generador

: Es la orden del generador tutorial-db : Es el nombre que recibirá el pod.

: Es el nombre que recibirá el pod. --image=mariadb:10.3.8 : Es la imagen que queremos que ejecute el pod.

: Es la imagen que queremos que ejecute el pod. --restart=Never : Esto es lo que realmente hace que sea un pod. Como podemos ver en ningún lado aparece la palabra pod. Kubectl sabe que queremos un pod porque con este parámetro le decimos que si muere el pod no levante otro. Con otro valor crearía un Deploy.

: Esto es lo que realmente hace que sea un pod. Como podemos ver en ningún lado aparece la palabra pod. Kubectl sabe que queremos un pod porque con este parámetro le decimos que si muere el pod no levante otro. Con otro valor crearía un Deploy. --port=3306 : El puerto que queremos que exponga el pod.

El resto de parámetros ya los he explicado mas arriba.

El fichero de salida

Este es el fichero de salida que nos ha generado el comando:

apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: tutorial-db name: tutorial-db spec: containers: - image: mariadb:10.3.8 name: tutorial-db ports: - containerPort: 3306 resources: {} dnsPolicy: ClusterFirst restartPolicy: Never status: {}

En él podemos ver que es de tipo Pod. El metadata podemos modificarlo a nuestro antojo y meter mas etiquetas, aquí podemos ver el nombre que le hemos dado al pod.

En specs vemos los contenedores que tiene dentro, en este caso uno, y las imágenes que corren y los puertos.

Podemos ejecutar el pod con el siguiente comando

kubectl create -f tutorial_db.yaml

Podemos ver los pods con:

kubectl get pods

Si habéis seguido hasta aquí tendréis un bonito pod roto. ¿Por qué?

Depurando el error del pod

Cuando tenemos un pod lo primero que podemos hacer es describirlo, esto nos devolverá información sobre la ejecución, reinicios y mas cosas. Para ver esta información debemos ejecutar el siguiente comando:

kubectl describe pod tutorial-db

Esta es la salida que me devuelve ahora mismo. No me devuelve el motivo del error.

Name: tutorial-db Namespace: tutorial Priority: 0 PriorityClassName: <none> Node: debian/192.168.1.61 Start Time: Fri, 28 Jun 2019 23:10:47 +0200 Labels: run=tutorial-db Annotations: cni.projectcalico.org/podIP: 192.168.245.202/32 Status: Failed IP: 192.168.245.202 Containers: tutorial-db: Container ID: docker://d69c0a3f834fca644f44825a99e3de4f6f1f8ff4fa0dc13943aaaa7089f3797e Image: mariadb:10.3.8 Image ID: docker-pullable://[email protected]:edef80de393cf4a79504168c663f8b0c6b15060333e5a7d7aee3dc0a4de6e927 Port: 3306/TCP Host Port: 0/TCP State: Terminated Reason: Error Exit Code: 1 Started: Fri, 28 Jun 2019 23:10:51 +0200 Finished: Fri, 28 Jun 2019 23:10:52 +0200 Ready: False Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-5t7vz (ro) Conditions: Type Status Initialized True Ready False ContainersReady False PodScheduled True Volumes: default-token-5t7vz: Type: Secret (a volume populated by a Secret) SecretName: default-token-5t7vz Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <invalid> default-scheduler Successfully assigned tutorial/tutorial-db to debian Normal Pulled <invalid> kubelet, debian Container image "mariadb:10.3.8" already present on machine Normal Created <invalid> kubelet, debian Created container tutorial-db Normal Started <invalid> kubelet, debian Started container tutorial-db

Como esto en principio no nos dice el motivo del error, o yo no se cómo verlo, lo mejor será sacar el log del pod de la siguiente forma:

kubectl logs tutorial-db

Lo cual nos devuelve lo siguiente:

error: database is uninitialized and password option is not specified You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD

Pues ya sabemos cual es el problema, no le estamos pasando las variables de entorno necesarias para la creación del contenedor, estas son las mismas que necesitaría el contenedor de docker para ejecutarse en nuestro local.

Seteando las variables de entorno de aquella manera

SPOILER Esta no es la manera de hacerlo, pero como quiero ir paso a paso vamos a empezar por lo mas básico.

Lo que vamos a hacer es crear las variables de entorno directamente en el fichero de creación del pod. Para ello lo editaremos y lo dejaremos como el que tenéis a continuación:

apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: tutorial-db name: tutorial-db spec: containers: - image: mariadb:10.3.8 name: tutorial-db env: - name: MYSQL_ROOT_PASSWORD value: root_password - name: MYSQL_DATABASE value: tutorial - name: MYSQL_USER value: usuario - name: MYSQL_PASSWORD value: password ports: - containerPort: 3306 resources: {} dnsPolicy: ClusterFirst restartPolicy: Never status: {}

Como podéis ver lo que hacemos es setear env en el fichero con los nombres de las variables y sus valores. La forma correcta de hacerlo es con secrets pero ya llegaré a ello.

Eliminar el pod con errores

Para eliminar el pod es tan sencillo como ejecutar:

kubectl delete pod tutorial-db

Ahora ya podemos lanzar el nuevo fichero con las variables de entorno ya modificadas.

Conclusión

Por ahora tenemos un pod con una base de datos dentro de un namespace dentro de un cluster, pero no es accesible ni se comunica con nada. Esto es lo que he hecho en mi primer día trasteando con kubernetes, a parte de romper varias veces el cluster. El error es real y he querido reproducir todos los pasos que voy siguiendo, errores incluidos. La idea es ir continuando todo hasta montar algo mas o menos útil.

Para cualquier corrección puedes dejarme un comentario abajo, un mensaje en GnuSocial o en Twitter.

Referencias