0% encontró este documento útil (0 votos)
368 vistas241 páginas

Kubernetes CookBook

libro de kubernetes

Cargado por

randren16
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
368 vistas241 páginas

Kubernetes CookBook

libro de kubernetes

Cargado por

randren16
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

Prefacio

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y


comentarios: [email protected]

Bienvenido a Kubernetes Cookbook, ¡y gracias por elegirlo! Con este


libro, queremos ayudarte a resolver problemas concretos en torno a
Kubernetes. Hemos recopilado más de 100 recetas que abarcan temas
como la configuración de un clúster, la gestión de cargas de trabajo en
contenedores mediante objetos de la API de Kubernetes, el uso de
primitivas de almacenamiento, la configuración de la seguridad y mucho
más. Tanto si eres nuevo en Kubernetes como si llevas tiempo
utilizándolo, esperamos que encuentres aquí algo útil para mejorar tu
experiencia y uso de Kubernetes.

Quién debería leer este libro


Este libro se ha escrito para cualquiera que pertenezca a algún punto del
espectro DevOps. Puede que seas un desarrollador de aplicaciones que
debe interactuar ocasionalmente con Kubernetes, o un ingeniero de
plataformas que crea soluciones reutilizables para otros ingenieros de tu
organización, o cualquier otro punto intermedio. Este libro te ayudará a
navegar con éxito por la jungla de Kubernetes, desde el desarrollo hasta la
producción. Abarca conceptos básicos de Kubernetes, así como soluciones
del ecosistema más amplio que casi se han convertido en estándares de
facto en el sector.

Por qué escribimos este libro


Colectivamente, formamos parte de la comunidad de Kubernetes desde
hace muchos años y hemos visto los muchos problemas con los que se
encuentran los principiantes e incluso los usuarios más avanzados.
Queríamos compartir los conocimientos que hemos acumulado
ejecutando Kubernetes en producción, así como desarrollando sobre y en
Kubernetes, es decir, contribuyendo al código base o al ecosistema y
escribiendo aplicaciones que se ejecutan en Kubernetes. Tenía mucho
sentido trabajar en la segunda edición de este libro, teniendo en cuenta
que la adopción de Kubernetes ha seguido creciendo en los años
transcurridos desde que se publicó la primera edición del libro.
Navegar por este libro
Este libro de recetas contiene 15 capítulos. Cada capítulo se compone de
recetas escritas en el formato estándar de recetas de O'Reilly (Problema,
Solución, Discusión). Puedes leer este libro de principio a fin o saltar a un
capítulo o receta concretos. Cada receta es independiente de las demás, y
cuando se necesita comprender conceptos de otras recetas, se
proporcionan las referencias apropiadas. El índice también es un recurso
muy poderoso, porque a veces una receta también muestra un comando
específico, y el índice resalta estas conexiones.

Nota sobre las versiones de Kubernetes


En el momento de escribir este libro, Kubernetes 1.27 era la última
versión estable, publicada a finales de abril de 2023, y ésta es la versión
que utilizamos en todo el libro como referencia. Sin embargo, las
soluciones aquí presentadas deberían, en general, funcionar para
versiones anteriores; lo indicaremos explícitamente si no es así,
mencionando la versión mínima requerida.
Kubernetes sigue una cadencia de tres versiones al año. Un ciclo de
versiones tiene una duración aproximada de 15 semanas; por ejemplo, la
1.26 se publicó en diciembre de 2022, la 1.27 en abril de 2023 y la 1.28 en
agosto de 2023, cuando este libro entraba en producción. Las directrices
de versionado de versiones de Kubernetes indican que puedes esperar
compatibilidad con una función para las tres versiones menores más
recientes. La Comunidad Kubernetes admite series de versiones de
parches activas durante un periodo aproximado de 14 meses. Esto
significa que los objetos estables de la API de la versión 1.27 recibirán
soporte al menos hasta junio de 2024. Sin embargo, dado que las recetas
de este libro suelen utilizar únicamente API estables, si utilizas una
versión de Kubernetes más reciente, las recetas deberían seguir
funcionando.

Tecnología que debes comprender


Este libro de nivel intermedio requiere una comprensión mínima de
algunos conceptos de desarrollo y administración de sistemas. Antes de
sumergirte en el libro, quizá quieras repasar lo siguiente:
bash (shell Unix)
Es el shell Unix por defecto en Linux y macOS. Será beneficioso
estar familiarizado con el shell de Unix, por ejemplo para editar
archivos, establecer permisos de archivo y privilegios de usuario,
mover archivos por el sistema de archivos y hacer algo de
programación básica con el shell. Para una introducción general,
consulta libros como Learning the bash Shell, de Cameron Newham,
tercera edición, o bash Cookbook, de Carl Albing y JP Vossen,
segunda edición, ambos de O'Reilly.
Gestión de paquetes
Las herramientas de este libro suelen tener múltiples dependencias
que hay que cumplir al instalar algunos paquetes. Por tanto, es
necesario conocer el sistema de gestión de paquetes de tu máquina.
Puede ser apt en sistemas Ubuntu/Debian, yum en sistemas
CentOS/RHEL, o Homebrew en macOS. Sea cual sea, asegúrate de
que sabes instalar, actualizar y eliminar paquetes.
Git
Git se ha establecido como el estándar para el control de versiones
distribuido. Si aún no estás familiarizado con Git, te
recomendamos Version Control with Git, Third Edition, de Prem
Kumar Ponuthorai y Jon Loeliger (O'Reilly) como un buen punto de
partida. Junto con Git, el sitio web GitHub es un gran recurso para
empezar con un repositorio alojado propio. Para aprender sobre
GitHub, consulta el sitio GitHub Training Kit.
Ve a
Kubernetes está escrito en Go. Go se ha establecido como un
lenguaje de programación popular más ampliamente en la
comunidad Kubernetes y más allá. Este libro de cocina no trata
sobre la programación en Go, pero muestra cómo compilar algunos
proyectos Go. Será útil tener unos conocimientos mínimos sobre
cómo configurar un espacio de trabajo Go. Si quieres saber más, un
buen lugar para empezar es el curso de formación en vídeo de
O'Reilly Introducción a la Programación Go.

Convenciones utilizadas en este libro


En este libro se utilizan las siguientes convenciones tipográficas:

Cursiva
Indica nuevos términos, URL, direcciones de correo electrónico,
nombres de archivo y extensiones de archivo.
Constant width
Se utiliza en los listados de programas, así como dentro de los
párrafos para referirse a elementos del programa como nombres de
variables o funciones, bases de datos, tipos de datos, variables de
entorno, sentencias y palabras clave. También se utiliza para los
comandos y la salida de la línea de comandos.

Constant width bold


Muestra comandos u otros textos que deben ser tecleados
literalmente por el usuario.

Constant width italic


Muestra el texto que debe sustituirse por valores proporcionados
por el usuario o por valoresdeterminados por el contexto.
CONSEJO

Este elemento significa un consejo o sugerencia.


NOTA

Este elemento significa una nota general.


ADVERTENCIA

Este elemento indica una advertencia o precaución.

Utilizar ejemplos de código


El material complementario (manifiestos de Kubernetes, ejemplos de
código, ejercicios, etc.) está disponible para su descarga
en https://github.com/k8s-cookbook/recipes. Puedes clonar este
repositorio, ir al capítulo y receta pertinentes, y utilizar el código tal cual:
$ git clone https://github.com/k8s-cookbook/recipes
NOTA

Los ejemplos de este repositorio no pretenden


representar configuraciones optimizadas para su uso en producción. Te
proporcionan el mínimo básico necesario para ejecutar los ejemplos de las
recetas.

Si tienes una pregunta técnica o un problema al utilizar los ejemplos de


código, envía un correo electrónico a [email protected].
Este libro está aquí para ayudarte a hacer tu trabajo. En general, si se
ofrece código de ejemplo con este libro, puedes utilizarlo en tus
programas y documentación. No es necesario que te pongas en contacto
con nosotros para pedirnos permiso, a menos que estés reproduciendo
una parte importante del código. Por ejemplo, escribir un programa que
utilice varios trozos de código de este libro no requiere permiso. Vender o
distribuir un CD-ROM de ejemplos de los libros de O'Reilly sí requiere
permiso. Responder a una pregunta citando este libro y el código de
ejemplo no requiere permiso. Incorporar una cantidad significativa de
código de ejemplo de este libro en la documentación de tu producto sí
requiere permiso.

Agradecemos, pero no exigimos, la atribución. Una atribución suele


incluir el título, el autor, la editorial y el ISBN. Por ejemplo"Kubernetes
Cookbook", de Sameer Naik, Sébastien Goasguen y Jonathan Michaux
(O'Reilly). Copyright 2024 CloudTank SARL, Sameer Naik y Jonathan
Michaux, 978-1-098-14224-7".
Si crees que el uso que haces de los ejemplos de código no se ajusta al uso
legítimo o al permiso concedido anteriormente, no dudes en ponerte en
contacto con nosotros en [email protected].

Aprendizaje en línea O'Reilly


NOTA

Durante más de 40 años, O'Reilly Media ha proporcionado formación,


conocimientos y perspectivas sobre tecnología y negocios para ayudar a las
empresas a alcanzar el éxito.

Nuestra red única de expertos e innovadores comparten sus


conocimientos y experiencia a través de libros, artículos y nuestra
plataforma de aprendizaje online. La plataforma de aprendizaje en línea
de O'Reilly te ofrece acceso bajo demanda a cursos de formación en
directo, rutas de aprendizaje en profundidad, entornos de codificación
interactivos y una amplia colección de textos y vídeos de O'Reilly y de más
de 200 editoriales. Para más información, visita https://oreilly.com.

Cómo contactar con nosotros


Dirige tus comentarios y preguntas sobre este libro a la editorial:

 O'Reilly Media, Inc.


 1005 Gravenstein Highway Norte
 Sebastopol, CA 95472
 800-889-8969 (en Estados Unidos o Canadá)
 707-829-7019 (internacional o local)
 707-829-0104 (fax)
[email protected]
 https://www.oreilly.com/about/contact.html
Tenemos una página web para este libro en la que enumeramos erratas,
ejemplos y cualquier información adicional. Puedes acceder a esta página
en https://oreil.ly/kubernetes-cookbook-2e.
Para obtener noticias e información sobre nuestros libros y cursos,
visita https://oreilly.com.
Encuéntranos en LinkedIn: https://linkedin.com/company/oreilly-media.
Síguenos en Twitter: https://twitter.com/oreillymedia.
Míranos en YouTube: https://youtube.com/oreillymedia.

Agradecimientos
Gracias a toda la comunidad de Kubernetes por desarrollar un software
tan increíble y por ser un gran grupo de personas: abiertas, amables y
siempre dispuestas a ayudar.

Sameer y Jonathan tuvieron el honor de trabajar con Sébastien en la


segunda edición de este libro. Todos estamos agradecidos por las
revisiones de Roland Huß, Jonathan Johnson y Benjamin Muschko, que
han sido inestimables para mejorar el producto final. También estamos
agradecidos a John Devins, Jeff Bleiel y Ashley Stussy, nuestros editores en
O'Reilly, con los que ha sido un placer trabajar.
Capítulo 1. Introducción a Kubernetes
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este primer capítulo presentamos recetas que te ayudarán a iniciarte


en Kubernetes. Te mostramos cómo utilizar Kubernetes sin instalarlo e
introducimos componentes como la interfaz de línea de comandos (CLI) y
el panel de control, que te permiten interactuar con un clúster, así como
Minikube, una solución todo en uno que puedes ejecutar en tu portátil.

1.1 Instalación de la CLI de Kubernetes,


kubectl

Problema

Quieres instalar la interfaz de línea de comandos de Kubernetes para


poder interactuar con tu clúster de Kubernetes.

Solución

La opción más sencilla es descargar la última versión oficial. Por ejemplo,


en un sistema Linux, para obtener la última versión estable, introduce lo
siguiente:

$ wget https://dl.k8s.io/release/$(wget -qO -


https://dl.k8s.io/release/
stable.txt)/bin/linux/amd64/kubectl

$ sudo install -m 755 kubectl /usr/local/bin/kubectl


Utilizando el gestor de paquetes Homebrew, los usuarios de Linux y
macOS también pueden instalar kubectl:

$ brew install kubectl


Después de la instalación de , asegúrate de que tienes un kubectl que
funciona, listando su versión:
$ kubectl version --client
Client Version: v1.28.0
Kustomize Version: v5.0.4-0.20230...
Debate

kubectl es la CLI oficial de Kubernetes y está disponible como software de


código abierto, lo que significa que tú mismo podrías compilar el
binario kubectl si lo necesitaras. Consulta la Receta 15.1 para aprender a
compilar localmente el código fuente de Kubernetes.
Es útil tener en cuenta que los usuarios de Google Kubernetes Engine
(ver Receta 2.11) pueden instalar kubectl utilizando gcloud:

$ gcloud components install kubectl


Ten en cuenta también que en las últimas versiones de Minikube
(ver Receta 1.2), puedes invocar kubectl como subcomando
de minikube para ejecutar un kubectl binario que coincida con la versión
del clúster:

$ minikube kubectl -- version --client


Client Version: version.Info{Major:"1", Minor:"27",
GitVersion:"v1.27.4", ...}
Kustomize Version: v5.0.1
Ver también

 Documentación sobre la instalación kubectl

1.2 Instalar Minikube para ejecutar


unainstancia localde Kubernetes
Problema

Quieres utilizar Kubernetes para pruebas, desarrollo o formación en tu


máquina local.

Solución
Minikube es una herramienta que te permite utilizar fácilmente
Kubernetes en tu máquina local.
Para instalar la CLI de Minikube localmente, puedes obtener la última
versión precompilada o compilarla desde el código fuente. Para instalar la
última versión de minikube en una máquina basada en Linux,haz lo
siguiente:

$ wget
https://storage.googleapis.com/minikube/releases/latest/
minikube-linux-amd64 -O minikube

$ sudo install -m 755 minikube /usr/local/bin/minikube


Esto pondrá el binario minikube en tu ruta y lo hará accesible
desdecualquier lugar.
Una vez instalado, puedes verificar la versión de Minikube con el
siguiente comando:

$ minikube version
minikube version: v1.31.2
commit: fd7ecd...
Debate

Minikube puede implementarse como una máquina virtual, un


contenedor o un metal desnudo. Esto se configura utilizando la
bandera --driver al crear un clúster en Minikube. Cuando no se especifica
esta bandera, Minikube seleccionará automáticamente el mejor entorno
de ejecución disponible.
Un hipervisor es un componente de software o hardware que crea y
gestiona máquinas virtuales. Es responsable de asignar y gestionar los
recursos físicos (CPU, memoria, almacenamiento, red) de un sistema
anfitrión y de permitir que varias máquinas virtuales (VM) se ejecuten
simultáneamente en el mismo hardware físico. Minikube es compatible
con una serie de hipervisores, como VirtualBox, Hyperkit, Docker
Desktop, Hyper-V, etc. La página de controladores ofrece una visión
general de los tiempos de ejecución compatibles.
Minikube también puede utilizar un tiempo de ejecución de contenedores
para crear un clúster en una máquina anfitriona. Este controlador sólo
está disponible en un host basado en Linux, donde es posible ejecutar
contenedores Linux de forma nativa sin tener que utilizar una máquina
virtual. Aunque un tiempo de ejecución basado en contenedores no ofrece
el mismo nivel de aislamiento que una máquina virtual, sí ofrece el mejor
rendimiento y utilización de recursos. En el momento de escribir esto,
Minikube tiene soporte para Docker Engine y Podman (experimental).
Otras herramientas que pueden utilizarse para ejecutar clústeres locales
de Kubernetes utilizando contenedores Linux son las siguientes :

 Kubernetes en Docker Desktop (ver Receta 1.6)


 tipo (ver Receta 1.5)
 k3d
Ver también

 Guía de inicio de Minikube


 Controladores Minikube
 minikube fuente en GitHub

1.3 Utilizar Minikube localmente para


el desarrollo

Problema

Quieres utilizar Minikube localmente para probar y desarrollar tu


aplicación Kubernetes. Has instalado e iniciado minikube (ver Receta 1.2) y
quieres conocer algunos comandos adicionales para simplificar tu
experiencia de desarrollo.
Solución

Utiliza el comando minikube start para crear un clúster de Kubernetes


localmente:

$ minikube start
Por defecto, al clúster se le asignarán 2 GB de RAM. Si no te gustan los
valores predeterminados, puedes anular parámetros como la memoria y
el número de CPU, así como elegir una determinada versión de
Kubernetes para la máquina virtual Minikube, por ejemplo:
$ minikube start --cpus=4 --memory=4096 --kubernetes-
version=v1.27.0
Además, puedes especificar el número de nodos del cluster anulando el
valor por defecto de un nodo:

$ minikube start --cpus=2 --memory=4096 --nodes=2


Para inspeccionar el estado del clúster Minikube, haz lo siguiente:

$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

minikube-m02
type: Worker
host: Running
kubelet: Running
Del mismo modo, para inspeccionar el estado del clúster de Kubernetes
que se ejecuta dentro de Minikube,haz lo siguiente:

$ kubectl cluster-info
Kubernetes control plane is running at
https://192.168.64.72:8443
CoreDNS is running at
https://192.168.64.72:8443/api/v1/namespaces/
kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use


'kubectl cluster-info dump'.
El clúster de Kubernetes creado con Minikube utiliza recursos de la
máquina anfitriona, por lo que debes asegurarte de que tu anfitrión
dispone de los recursos necesarios. Y lo que es más importante, cuando
hayas terminado, no olvides detenerlo con minikube stop para liberar los
recursos del sistema.
Debate
La CLI de Minikube ofrece comandos que te hacen la vida más fácil. La
CLI tiene una ayuda integrada que puedes utilizar para descubrir los
subcomandos por ti mismo-aquí tienes un fragmento:

$ minikube
...
Basic Commands:
start Starts a local Kubernetes cluster
status Gets the status of a local Kubernetes
cluster
stop Stops a running local Kubernetes
cluster
delete Deletes a local Kubernetes cluster
...
Configuration and Management Commands:
addons Enable or disable a minikube addon
...
Aparte de start, stop, y delete, deberías familiarizarte con los
comandos ip, ssh, tunnel, dashboard, y docker-env.
CONSEJO

Si por alguna razón tu Minikube se vuelve inestable o quieres empezar de cero,


puedes eliminarlo con minikube stop y minikube delete.
Entonces minikube start te proporcionará una instalación nueva.

1.4 Iniciar tu primera aplicación en


Minikube

Problema

Has iniciado Minikube (ver Receta 1.3), y ahora quieres lanzar tu primera
aplicación en Kubernetes.
Solución

Por ejemplo, puedes iniciar la plataforma de microblogging Ghost en


Minikube utilizando dos comandos de kubectl:

$ kubectl run ghost --image=ghost:5.59.4 --


env="NODE_ENV=development"
$ kubectl expose pod ghost --port=2368 --type=NodePort
Monitoriza manualmente la cápsula para ver cuándo empieza a
funcionar:

$ kubectl get pods


NAME READY STATUS RESTARTS
AGE
ghost-8449997474-kn86m 1/1 Running 0
24s
Ahora puedes utilizar el comando minikube service para que cargue
automáticamente la URL del servicio de aplicación en el navegador web:

$ minikube service ghost


Debate

El comando kubectl run se llama generador; es un comando de


conveniencia para crear un objeto Pod (ver Receta 4.4). El
comando kubectl expose también es un generador, un comando de
conveniencia para crear un objeto Service (ver Receta 5.1) que dirige el
tráfico de red a los contenedores iniciados por tu implementación.
Cuando ya no necesites la aplicación, puedes eliminar Pod para liberar los
recursos del clúster:

$ kubectl delete pod ghost


Además, debes eliminar el servicio ghost que se creó con el
comando kubectl expose:

$ kubectl delete svc ghost

1.5 Usar kind para ejecutar Kubernetes


localmente

Problema
kind es una forma alternativa de ejecutar Kubernetes localmente. Se
diseñó originalmente para probar Kubernetes, pero ahora también se
utiliza a menudo como una forma de probar soluciones nativas de
Kubernetes en un ordenador portátil con un mínimo de
complicaciones. Quieres utilizar kind localmente para probar y
desarrollar tu aplicación Kubernetes.
Solución

Los requisitos mínimos para utilizar kind son Go y un runtime


Docker. kind es fácil de instalar en cualquier plataforma, por ejemplo
utilizando brew:

$ brew install kind


Luego, crear un clúster es tan sencillo como hacer esto:

$ kind create cluster


Borrarlo es igual de fácil:

$ kind delete cluster


Debate

Dado que kind se desarrolló originalmente para probar Kubernetes, uno


de sus principios básicos de diseño es que debe prestarse bien a la
automatización. Puedes considerar el uso de kind si planeas la
implementación automática de clusters de Kubernetes con fines de
prueba.
Ver también

 La amable guía oficial de inicio rápido

1.6 Utilizar Kubernetes en Docker


Desktop
Problema

Docker Desktop es una oferta construida sobre Docker Engine que


proporciona una serie de útiles herramientas para desarrolladores,
incluida una versión integrada de Kubernetes y un equilibrador de carga
asociado para dirigir el tráfico al clúster. Esto significa que puedes
instalar una única herramienta y tener acceso a prácticamente todo lo
que necesitas para empezar a trabajar localmente. Quieres utilizar Docker
Desktop localmente para probar y desarrollar tu aplicación Kubernetes.

Solución

Instala Docker Desktop y asegúrate de activar Kubernetes durante el


proceso de instalación.
Puedes activar y desactivar Kubernetes desde el panel de configuración
de Docker Desktop, como se muestra en la Figura 1-1. Puede que quieras
hacer esto si utilizas Docker Desktop para su motor Docker pero no
utilizas Kubernetes, ya que así ahorrarás recursos en tu ordenador. Como
se muestra aquí, el panel de configuración también te muestra qué
versión de Kubernetes proporciona Docker Desktop, lo que puede ser útil
al depurar, ya que ciertas soluciones pueden tener requisitos sobre la
versión mínima o máxima de Kubernetes en la que pueden ejecutarse.
Figura 1-1. Instantánea del panel de configuración de Docker Desktop Kubernetes

Cabe señalar que la versión de Kubernetes integrada en Docker Desktop


va unas cuantas versiones por detrás de la última versión de Kubernetes,
mientras que Minikube suele estar más actualizada.

Como se muestra en la Figura 1-2, el menú de la barra de herramientas de


Docker Desktop te permite cambiar fácilmente los contextos
de kubectl entre diferentes clusters locales, lo que significa que puedes
tener Minikube y Kubernetes de Docker Desktop ejecutándose al mismo
tiempo, pero cambiar entre ellos (no es que recomendemos hacer esto).
Para saber cómo hacerlo directamente desde kubectl, consulta la Receta
1.7.
Figura 1-2. Instantánea del conmutador contextual de Docker Desktop para kubectl

Debate

Aunque es una forma rápida y sencilla de iniciarse en Kubernetes, ten en


cuenta que Docker Desktop no es de código abierto, y que la versión
gratuita está restringida para su uso por particulares, pequeñas empresas,
estudiantes y educadores, y desarrolladores de código abierto no
comerciales.
Por otro lado, Docker Engine, que puede utilizarse para ejecutar
Minikube, tiene una licencia Apache 2.0, al igual que el propio Minikube.

1.7 Cambiar contextos kubectl

Problema

kubectl siempre está configurado para hablar con un determinado clúster


de Kubernetes por defecto, y esta configuración forma parte de algo
llamado contexto. Si has olvidado a qué clúster está configurado kubectl,
quieres cambiar entre clústeres o quieres cambiar otros parámetros
relacionados con el contexto, esta receta es para ti.
Solución

Para ver los contextos disponibles en kubectl, utiliza el comando kubectl


config get-contexts:

$ kubectl config get-contexts


CURRENT NAME CLUSTER AUTHINFO
NAMESPACE
docker-desktop docker-desktop docker-desktop
kind-kind kind-kind kind-kind
* minikube minikube minikube
default
Como puedes ver en la salida, en este caso hay tres clusters de Kubernetes
disponibles en kubectl, y el contexto actual está configurado para hablar
con el cluster minikube.
Para cambiar al clúster kind-kind, ejecuta el siguiente comando:

$ kubectl config use-context kind-kind


Switched to context "kind-kind".
Debate

Si quieres utilizar tu kubectl local para acceder a un clúster remoto,


puedes hacerlo editando el archivo kubeconfig. Más información sobre el
archivo kubeconfig en la documentación oficial.
1.8 Cambio de contextos y espacios de
nombres mediantekubectx y kubens
Problema

Quieres encontrar una forma más fácil de cambiar de contexto (es decir,
de clúster) y de espacio de nombres con kubectl, ya que los comandos
para cambiar de contexto son largos y bastante difíciles de recordar.
Solución

kubectx y kubens son un par de scripts populares de código abierto que


facilitan mucho el cambio de contextos para kubectl y el cambio de
espacios de nombres para que no tengas que establecer explícitamente el
nombre del espacio de nombres para cada comando.
Hay muchas opciones de instalación disponibles. Si puedes utilizar brew,
entonces puedes probar esto:

$ brew install kubectx


Así podrás listar fácilmente los contextos disponibles en kubectl:

$ kubectx
docker-desktop
kind-kind
minikube
y cambiar de contexto con la misma facilidad:

$ kubectx minikube
Switched to context "minikube".
Del mismo modo, kubens te permite listar y cambiar fácilmente de espacio
de nombres:

$ kubens
default
kube-node-lease
kube-public
kube-system
test

$ kubens test
default
Context "minikube" modified.
Active namespace is "test".
A partir de ese momento, todas las órdenes se ejecutarán en el contexto
del espacio de nombres elegido:

$ kubectl get pods


default
No resources found in test namespace.
Ver también

 El repositorio de las herramientas kubectl y kubens


Capítulo 2. Creación de un clúster
Kubernetes
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este capítulo analizamos múltiples formas de configurar un clúster


Kubernetes completo. Cubrimos las herramientas estandarizadas de bajo
nivel (kubeadm) que también sirven de base para otros instaladores y te
mostramos dónde encontrar los binarios relevantes para el plano de
control, así como para los nodos trabajadores. Demostramos cómo
escribir archivos unitarios systemd para supervisar los componentes de
Kubernetes y, por último, mostramos cómo configurar clústeres en Google
Cloud Platform y Azure.

2.1 Preparar un nuevo nodo para un


clúster de Kubernetes

Problema

Quieres preparar un nuevo nodo con todas las herramientas necesarias


para crear un nuevo clúster Kubernetes o añadirlo a un clúster existente.

Solución

Para preparar un host basado en Ubuntu para un clúster de Kubernetes,


primero tienes que activar el reenvío IPv4 y habilitar iptables para ver el
tráfico puenteado:

$ cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf


overlay
br_netfilter
EOF

$ sudo modprobe overlay


$ sudo modprobe br_netfilter

$ cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf


net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

$ sudo sysctl --system


Para que sea compatible con la herramienta kubeadm, el intercambio debe
estar desactivado en el nodo:

$ sudo apt install cron -y


$ sudo swapoff -a
$ (sudo crontab -l 2>/dev/null; echo "@reboot /sbin/swapoff
-a") | sudo crontab -
|| true
Los nodos de clúster requieren una implementación de la Interfaz de
Tiempo de Ejecución de Contenedores de Kubernetes (CRI). cri-o es una de
esas implementaciones. La versión de cri-o debe coincidir con la versión
de Kubernetes. Por ejemplo, si estás arrancando un clúster Kubernetes
1.27, configura la variable VERSION en consecuencia:

$ VERSION="1.27"
$ OS="xUbuntu_22.04"

$ cat <<EOF | sudo tee


/etc/apt/sources.list.d/devel:kubic:libcontainers:
stable.list
deb
https://download.opensuse.org/repositories/devel:/kubic:/li
bcontainers:
/stable/$OS/ /
EOF

$ cat <<EOF | sudo tee


/etc/apt/sources.list.d/devel:kubic:libcontainers:
stable:cri-o:$VERSION.list
deb
http://download.opensuse.org/repositories/devel:/kubic:/lib
containers:
/stable:/cri-o:/$VERSION/$OS/ /
EOF

$ curl -L
https://download.opensuse.org/repositories/devel:/kubic:/li
bcontainers:
/stable:/cri-o:/$VERSION/$OS/Release.key | \
sudo apt-key add -
$ curl -L
https://download.opensuse.org/repositories/devel:/kubic:/li
bcontainers:
/stable/$OS/Release.key | \
sudo apt-key add -

$ sudo apt-get update

$ sudo apt-get install cri-o cri-o-runc cri-tools -y


A continuación, recarga las configuraciones de systemd y habilita cri-o:

$ sudo systemctl daemon-reload


$ sudo systemctl enable crio --now
La herramienta kubeadm es necesaria para arrancar un clúster Kubernetes
desde cero, así como para unirse a un clúster existente. Habilita su
repositorio de software con esto:

$ cat <<EOF | sudo tee


/etc/apt/sources.list.d/kubernetes.list
deb [signed-by=/etc/apt/keyrings/k8s-archive-keyring.gpg]
https://apt.kubernetes.io/
kubernetes-xenial main
EOF

$ sudo apt-get install -y apt-transport-https ca-


certificates curl
$ sudo curl -fsSLo /etc/apt/keyrings/k8s-archive-
keyring.gpg \
https://dl.k8s.io/apt/doc/apt-key.gpg

$ sudo apt-get update


Ahora puedes instalar todas las herramientas necesarias para arrancar
un nodo del clúster Kubernetes. Necesitarás lo siguiente:

 El binario kubelet
 La CLI kubeadm
 El cliente kubectl
Ejecuta este comando para instalarlos:
$ sudo apt-get install -y kubelet kubeadm kubectl
A continuación, marca estos paquetes como retenidos, lo que impedirá
que se actualicen automáticamente:

$ sudo apt-mark hold kubelet kubeadm kubectl


Tu host Ubuntu ya está listo para formar parte de un clúster Kubernetes.

Debate

kubeadm es una herramienta de configuración que proporciona kubeadm


init y kubeadm join. kubeadm init se utiliza para arrancar un nodo del
plano de control de Kubernetes, mientras que kubeadm join se utiliza para
arrancar un nodo trabajador y unirlo al clúster. En
esencia, kubeadm proporciona las acciones necesarias para poner en
marcha un clúster mínimamente viable. kubelet es el agente de
nodo que se ejecuta en cada nodo.
Además de cri-o, otros tiempos de ejecución de contenedores que merece
la pena investigar son containerd, Docker Engine y Mirantis Container
Runtime.

2.2 Arrancar un nodo del plano de


control de Kubernetes

Problema

Has inicializado un host Ubuntu para Kubernetes (ver Receta 2.1) y ahora
necesitas arrancar un nuevo nodo del plano de control de Kubernetes.
Solución

Con el binario kubeadm instalado, estás listo para empezar a arrancar tu


clúster de Kubernetes. Inicializa el plano de control en el nodo con lo
siguiente:

$ NODENAME=$(hostname -s)
$ IPADDR=$(ip route get 8.8.8.8 | sed -n 's/.*src \
([^\ ]*\).*/\1/p')
$ POD_CIDR=192.168.0.0/16
ADVERTENCIA

El nodo del plano de control debe tener un mínimo de dos vCPUs y 2 GB de RAM.

Ahora inicializa el nodo del plano de control utilizando kubeadm:

$ sudo kubeadm init --apiserver-advertise-address=$IPADDR \


--apiserver-cert-extra-sans=$IPADDR \
--pod-network-cidr=$POD_CIDR \
--node-name $NODENAME \
--ignore-preflight-errors Swap
[init] Using Kubernetes version: v1.27.2
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a
Kubernetes cluster
...
La salida del comando init contiene la configuración para
configurar kubectl para que hable con tu clúster. Una vez
configurado kubectl, puedes verificar el estado de salud de los
componentes del clúster mediante el siguiente comando:

$ kubectl get --raw='/readyz?verbose'


Para obtener la información del clúster, utiliza

$ kubectl cluster-info
Debate

Las cargas de trabajo de usuario no se programan para ejecutarse en el


nodo del plano de control. Si estás creando un clúster experimental de un
solo nodo, tendrás que contaminar el nodo del plano de control para
programar las cargas de trabajo de usuario en el nodo del plano de
control:

$ kubectl taint nodes --all


node-role.kubernetes.io/control-plane-
Ver también
 Crear un clúster con kubeadm

2.3 Instalar un Complemento de Red de


Contenedores para laRed de Clústeres
Problema

Has arrancado un nodo del plano de control de Kubernetes (ver Receta


2.2) y ahora necesitas instalar un complemento de red de pods para que
los pods puedan comunicarse entre sí.
Solución

Puedes instalar el complemento de red Calico con el siguiente comando en


el nodo del plano de control:

$ kubectl apply -f
https://raw.githubusercontent.com/projectcalico/calico/
v3.26.1/manifests/calico.yaml
Debate

Debes utilizar un complemento de Interfaz de Red de Contenedores (CNI)


que sea compatible con tu clúster y que se adapte a tus necesidades. Hay
varios complementos que implementan la CNI. Echa un vistazo a la lista
no exhaustiva de complementos disponibles en la documentación de
Kubernetes.

2.4 Añadir nodos trabajadores a un


clúster de Kubernetes

Problema

Has inicializado tu nodo del plano de control de Kubernetes


(ver Receta 2.2) e instalado un complemento CNI (ver Receta 2.3), y ahora
quieres añadir nodos trabajadores a tu clúster.
Solución
Con el host Ubuntu inicializado para Kubernetes, como muestra en la
Receta 2.1, ejecuta el siguiente comando en el nodo del plano de control
para mostrar el comando join del clúster:

$ kubeadm token create --print-join-command


Ahora, ejecuta el comando join en el nodo trabajador:

$ sudo kubeadm join --token <token>


ADVERTENCIA

El nodo trabajador debe tener como mínimo una vCPU y 2 GB de RAM.

Vuelve a la sesión terminal de tu nodo del plano de control y verás


cómose unen tusnodos:

$ kubectl get nodes


NAME STATUS ROLES AGE VERSION
master Ready control-plane 28m v1.27.2
worker Ready <none> 10s v1.27.2
Puedes repetir estos pasos para añadir más nodos trabajadores al clúster
Kubernetes.

Debate

Los nodos de trabajo son donde se ejecutan tus cargas de trabajo. Cuando
tu cluster empiece a quedarse sin recursos, empezarás a notar el
estado Pendiente de nuevos pods. Llegados a este punto, deberías
plantearte añadir más recursos al clúster añadiendo más nodos
trabajadores.

2.5 Implementación del panel de


control de Kubernetes

Problema
Has creado un clúster Kubernetes, y ahora quieres crear, ver y gestionar
cargas de trabajo en contenedores en el clúster mediante una interfaz de
usuario.

Solución

Utiliza el panel de control de Kubernetes, que es una interfaz de usuario


basada en web para implementar aplicaciones en contenedores en un
clúster de Kubernetes y gestionar los recursos del clúster.
CONSEJO

Si utilizas Minikube, puedes instalar el panel de control de


Kubernetes simplemente activando el complemento dashboard:

$ minikube addons enable dashboard

Para implementar el panel de control de Kubernetes v2.7.0, haz esto:

$ kubectl apply -f
https://raw.githubusercontent.com/kubernetes/dashboard/
v2.7.0/aio/deploy/recommended.yaml
A continuación, comprueba que la implementación está lista:

$ kubectl get deployment kubernetes-dashboard -n


kubernetes-dashboard
NAME READY UP-TO-DATE AVAILABLE
AGE
kubernetes-dashboard 1/1 1 1
44s

2.6 Acceder al panel de control de


Kubernetes

Problema

Has instalado el panel de control de Kubernetes (ver Receta 2.5) en tu


clúster, y quieres acceder a él desde un navegador web.
Solución

Tienes que crear un ServiceAccount con privilegios para administrar el


clúster. Crea un archivo llamado sa.yaml con el siguiente contenido:
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
Crea el ServiceAccount con esto:

$ kubectl apply -f sa.yaml


Para acceder al panel de control de Kubernetes, debes crear un token de
autenticación asociado a esta cuenta. Guarda el token impreso en la salida
del siguiente comando:

$ kubectl -n kubernetes-dashboard create token admin-user


eyJhbGciOiJSUzI1NiIsImtpZCI6...
Como el panel de control de Kubernetes es un servicio local del clúster,
tienes que configurar una conexión proxy con el clúster:

$ kubectl proxy
Al visitar el sitio http://localhost:8001/api/v1/namespaces/kubernetes-
dashboard/services/https:kubernetes-dashboard:/proxy/#/workloads?
namespace=_all ya puedes abrir el panel de control de Kubernetes y
autenticarte utilizando el token de autenticación creado anteriormente.
En la interfaz de usuario que se abre en tu navegador, verás la página que
se muestra en la Figura 2-1.
Figura 2-1. Instantánea de la vista de creación de la aplicación del cuadro de mando
CONSEJO

Si eres y utilizas Minikube, todo lo que tienes que hacer es

$ minikube dashboard

Debate

Para crear una aplicación, haz clic en el signo más (+) de la esquina
superior derecha, selecciona la pestaña "Crear desde formulario", dale un
nombre a la aplicación y especifica la imagen del contenedor que quieres
utilizar. A continuación, haz clic en el botón Implementación y aparecerá
una nueva vista que muestra las implementaciones, los pods y los
conjuntos de réplicas. En Kubernetes hay docenas de tipos de recursos
importantes, como implementaciones, pods, conjuntos de réplicas,
servicios, etc., que exploraremos con más detalle en el resto del libro.

La instantánea de la Figura 2-2 presenta una vista típica del panel de


control tras haber creado una única aplicación utilizando el contenedor
Redis.
Figura 2-2. Visión general de un panel de control con una aplicación Redis

Si vuelves a una sesión de terminal y utilizas el cliente de línea de


comandos, verás lo mismo:

$ kubectl get all


NAME READY STATUS RESTARTS
AGE
pod/redis-584fd7c758-vwl52 1/1 Running 0
5m9s

NAME TYPE CLUSTER-IP EXTERNAL-IP


PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none>
443/TCP 19m

NAME READY UP-TO-DATE AVAILABLE


AGE
deployment.apps/redis 1/1 1 1
5m9s

NAME DESIRED CURRENT


READY AGE
replicaset.apps/redis-584fd7c758 1 1 1
5m9s
Tu vaina Redis estará ejecutando el servidor Redis, como muestran los
siguientes registros:

$ kubectl logs redis-3215927958-4x88v


...
1:C 25 Aug 2023 06:17:23.934 * oO0OoO0OoO0Oo Redis is
starting oO0OoO0OoO0Oo
1:C 25 Aug 2023 06:17:23.934 * Redis version=7.2.0,
bits=64, commit=00000000,
modified=0, pid=1, just started
1:C 25 Aug 2023 06:17:23.934 # Warning: no config file
specified, using the
default config. In order to specify a config file use
redis-server
/path/to/redis.conf
1:M 25 Aug 2023 06:17:23.934 * monotonic clock: POSIX
clock_gettime
1:M 25 Aug 2023 06:17:23.934 * Running mode=standalone,
port=6379.
1:M 25 Aug 2023 06:17:23.935 * Server initialized
1:M 25 Aug 2023 06:17:23.935 * Ready to accept connections
tcp

2.7 Implementación del servidor de


métricas de Kubernetes

Problema

Has implementado el panel de control de Kubernetes (consulta la Receta


2.5), pero no ves la información sobre el uso de CPU y memoria en el
panel.
Solución

El panel de control de Kubernetes requiere el Servidor de Métricas de


Kubernetes para visualizar el uso de CPU y memoria.
CONSEJO

Si utilizas Minikube en, puedes instalar el Servidor de Métricas de Kubernetes


simplemente activando el complemento metrics-server:

$ minikube addons enable metrics-server

Para implementar la última versión del servidor de métricas de


Kubernetes, haz lo siguiente:
$ kubectl apply -f
https://github.com/kubernetes-sigs/metrics-server/releases/
latest/download/components.yaml
A continuación, comprueba que la implementación está lista:

$ kubectl get deployment metrics-server -n kube-system


NAME READY UP-TO-DATE AVAILABLE AGE
metrics-server 1/1 1 1 7m27s
Si ves que la implementación no entra en el estado listo, comprueba los
registros del pod:

$ kubectl logs -f deployment/metrics-server -n kube-system


I0707 05:06:19.537981 1 server.go:187] "Failed probe"
probe="metric-storage-ready" err="no metrics to serve"
E0707 05:06:26.395852 1 scraper.go:140] "Failed to
scrape node" err="Get
\"https://192.168.64.50:10250/metrics/resource\": x509:
cannot validate
certificate for 192.168.64.50 because it doesn't contain
any IP SANs"
node="minikube"
Si aparece el mensaje de error "no se puede validar el certificado", tienes
que añadir la bandera --kubelet-insecure-tls a la implementación del
Servidor de métricas:

$ kubectl patch deployment metrics-server -n kube-system --


type='json'
-p='[{"op": "add", "path":
"/spec/template/spec/containers/0/args/-", "value":
"--kubelet-insecure-tls"}]'
CONSEJO

El Servidor de Métricas puede tardar varios minutos en estar disponible después


de haberlo iniciado. Si aún no está listo, las solicitudes de métricas pueden
producir errores.

Una vez iniciado el Servidor de Métricas , el panel de control de


Kubernetes mostrará las estadísticas de uso de CPU y memoria, como se
muestra en la Figura 2-3.
Figura 2-3. Vista de los nodos del clúster en el panel de control

Debate

Las métricas de nodo y pod también se pueden ver en la línea de


comandos mediante el comando kubectl top:

$ kubectl top pods -A


NAMESPACE NAME
CPU(cores) MEMORY(bytes)
kube-system coredns-5d78c9869d-5fh78 9m
9Mi
kube-system etcd-minikube 164m
36Mi
kube-system kube-apiserver-minikube 322m
254Mi
kube-system kube-controller-manager-minikube 123m
35Mi
kube-system kube-proxy-rvl8v 13m
12Mi
kube-system kube-scheduler-minikube 62m
15Mi
kube-system storage-provisioner 22m
7Mi
Del mismo modo, para ver las métricas de los nodos, haz lo siguiente:
$ kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
minikube 415m 10% 1457Mi 18%
Ver también

 Repositorio GitHub del servidor de métricas de Kubernetes


 Documentación de la canalización de métricas de recursos

2.8 Descargar una versión de


Kubernetes desde GitHub

Problema

Quieres descargar una versión oficial de Kubernetes en lugar de compilar


desde el código fuente.

Solución

El proyecto Kubernetes publica un archivo para cada versión. El enlace al


archivo se encuentra en el archivo CHANGELOG de la versión en
cuestión. Ve a la carpeta CHANGELOG de la página del proyecto y abre el
archivo CHANGELOG de la versión que elijas. Dentro del archivo
encontrarás un enlace para descargar el archivo kubernetes.tar.gz de esa
versión.
Por ejemplo, si quieres descargar la versión v1.28.0, sigue adelante y
abre CHANGELOG-1.28.md, y en la sección titulada "Descargas para
v1.28.0" encontrarás el enlace
a kubernetes.tar.gz(https://dl.k8s.io/v1.28.0/kubernetes.tar.gz).

$ wget https://dl.k8s.io/v1.28.0/kubernetes.tar.gz
Si quieres compilar Kubernetes desde el código fuente, consulta la Receta
15.1.
Debate

En el archivo CHANGELOG también aparece la dirección sha512 hash del


archivo kubernetes.tar.gz. Se recomienda que verifiques la integridad
del archivo kubernetes.tar.gz para asegurarte de que no ha sido
manipulado de ninguna manera. Para ello, genera localmente el
hash sha512 del archivo descargado y compáralo con el que aparece en el
CHANGELOG:

$ sha512sum kubernetes.tar.gz
9aaf7cc004d09297dc7bbc1f0149.... kubernetes.tar.gz

2.9 Descargar los binarios del cliente y


del servidor

Problema

Has descargado un archivo de lanzamiento (ver Receta 2.8), pero no


contiene los binarios reales.
Solución

El archivo de lanzamiento no contiene los binarios de lanzamiento (para


que el archivo de lanzamiento sea pequeño). Por tanto, tienes que
descargar los binarios por separado. Para ello, ejecuta el script get-kube-
binaries.sh, como se muestra aquí:

$ tar -xvf kubernetes.tar.gz


$ cd kubernetes/cluster
$ ./get-kube-binaries.sh
Una vez completado, tendrás los binarios del cliente en client/bin:

$ ls ../client/bin
kubectl kubectl-convert
y un archivo que contiene los binarios del servidor en server/kubernetes:

$ ls ../server/kubernetes
kubernetes-server-linux-amd64.tar.gz kubernetes-
manifests.tar.gz README
...
Debate

Si quieres saltarte la descarga de todo el archivo de la versión y descargar


rápidamente los binarios del cliente y del servidor, puedes obtenerlos
directamente de Descarga Kubernetes. En esta página encontrarás enlaces
directos a los binarios para varias combinaciones de sistemas operativos y
arquitecturas, como se muestra en la Figura 2-4.

Figura 2-4. downloadkubernetes.com, lista de binarios de la versión Kubernetes v1.28.0 para el


sistema operativo Darwin

2.10 Utilizar archivos unitarios systemd


para ejecutarcomponentes de
Kubernetes
Problema

Has utilizado Minikube (ver Receta 1.2) para aprender y sabes cómo
arrancar un clúster Kubernetes utilizando kubeadm (ver Receta 2.2), pero
quieres instalar un clúster desde cero.
Solución

Para ello, necesitas ejecutar los componentes de Kubernetes utilizando


archivos de unidad systemd. Sólo buscas ejemplos básicos para ejecutar
el kubelet a través de systemd.
Inspeccionar cómo kubeadm configura los demonios de Kubernetes para
que se lancen utilizando archivos de unidad systemd te ayudará a
entender cómo hacerlo por tu cuenta. Si observas detenidamente la
configuración de kubeadm, verás que kubelet se ejecuta en todos los nodos
de tu clúster, incluido el nodo del plano de control.
He aquí un ejemplo, que puedes reproducir iniciando sesión en cualquier
nodo de un cluster construido con kubeadm (ver Receta 2.2):

$ systemctl status kubelet


● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/lib/systemd/system/kubelet.service;
enabled;
vendor preset: enabled)
Drop-In: /etc/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Tue 2023-05-30
04:21:29 UTC; 2h 49min ago
Docs: https://kubernetes.io/docs/home/
Main PID: 797 (kubelet)
Tasks: 11 (limit: 2234)
Memory: 40.2M
CPU: 5min 14.792s
CGroup: /system.slice/kubelet.service
└─797 /usr/bin/kubelet \

--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-
kubelet.conf \

--kubeconfig=/etc/kubernetes/kubelet.conf \
--config=/var/lib/kubelet/config.yaml \

--container-runtime-endpoint=unix:///var/run/crio/crio.soc
k \
--pod-infra-container-
image=registry.k8s.io/pause:3.9
Esto te proporciona un enlace al archivo de unidad systemd
en /lib/systemd/system/kubelet.service y a su configuración
en /etc/systemd/system/kubelet.service.d/10-kubeadm.conf.
El archivo de unidad es sencillo: apunta al binario kubelet instalado
en /usr/bin:
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/home/
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10

[Install]
WantedBy=multi-user.target
El archivo de configuración te indica cómo se inicia el binario kubelet:
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/
kubernetes/
bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/
config.yaml"
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
EnvironmentFile=-/etc/default/kubelet

ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS
$KUBELET_CONFIG_ARGS
$KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
Todas las opciones especificadas, como --kubeconfig, definidas por la
variable de entorno $KUBELET_CONFIG_ARGS, son opciones de inicio del
binario kubelet.
Debate

systemd es un gestor de sistemas y servicios, a veces denominado sistema


init. Actualmente es el gestor de servicios por defecto en Ubuntu y CentOS.
El archivo de unidad que acabamos de mostrar sólo se ocupa de kubelet.
Puedes escribir tus propios archivos de unidad para todos los demás
componentes de un clúster Kubernetes (es decir, servidor API, gestor de
controladores, programador, proxy). Kubernetes the Hard Way contiene
ejemplos de archivos de unidad para cada componente.
Sin embargo, sólo tienes que ejecutar kubelet. De hecho, ten en cuenta que
la opción de configuración --pod-manifest-path te permite pasar un
directorio en el que kubelet buscará los manifiestos que iniciará
automáticamente. Con kubeadm, este directorio se utiliza para pasar los
manifiestos del servidor API, el planificador, etcd y el gestor de
controladores. De este modo, Kubernetes se gestiona a sí mismo, y lo
único gestionado por systemd es el proceso kubelet.
Para ilustrarlo, puedes listar el contenido del
directorio /etc/kubernetes/manifests de tu clúster basado en kubeadm:

$ ls -l /etc/kubernetes/manifests
total 16
-rw------- 1 root root 2393 May 29 11:04 etcd.yaml
-rw------- 1 root root 3882 May 29 11:04 kube-
apiserver.yaml
-rw------- 1 root root 3394 May 29 11:04 kube-controller-
manager.yaml
-rw------- 1 root root 1463 May 29 11:04 kube-
scheduler.yaml
Si miras los detalles del manifiesto etcd.yaml, puedes ver en que se trata
de un Pod con un único contenedor que ejecuta etcd:

$ cat /etc/kubernetes/manifests/etcd.yaml

apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/etcd.advertise-client-urls:
https://10.10.100.30:2379
creationTimestamp: null
labels:
component: etcd
tier: control-plane
name: etcd
namespace: kube-system
spec:
containers:
- command:
- etcd
- --advertise-client-urls=https://10.10.100.30:2379
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd
- --experimental-initial-corrupt-check=true
- --experimental-watch-progress-notify-interval=5s
- --initial-advertise-peer-urls=https://10.10.100.30:2380
- --initial-cluster=master=https://10.10.100.30:2380
- --key-file=/etc/kubernetes/pki/etcd/server.key
-
--listen-client-urls=https://127.0.0.1:2379,https://10.10.100.30:2379
- --listen-metrics-urls=http://127.0.0.1:2381
- --listen-peer-urls=https://10.10.100.30:2380
- --name=master
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
- --peer-client-cert-auth=true
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --snapshot-count=10000
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
image: registry.k8s.io/etcd:3.5.7-0
...

Ver también
 kubelet opciones de configuración

2.11 Crear un clúster Kubernetes en


GoogleKubernetes Engine
Problema

Quieres crear un clúster Kubernetes en Google Kubernetes Engine (GKE).

Solución

Para utilizar GKE, primero necesitas algunas cosas:

 Una cuenta de Google Cloud Platform (GCP) con la facturación


activada
 Un proyecto GCP con GKE activado
 SDK de Google Cloud instalado
El SDK de Google Cloud contiene la herramienta CLI gcloud para
interactuar con los servicios de GCP desde la línea de comandos. Una vez
instalado el SDK, autentifica gcloud para acceder a tu proyecto GCP:

$ gcloud auth login


Utilizando la interfaz de línea de comandos gcloud, crea un clúster
Kubernetes con el comando container clusters create de la siguiente
manera

$ gcloud container clusters create oreilly --zone us-east1-


b
Por defecto, esto creará un clúster Kubernetes con tres nodos
trabajadores en la zona o región especificada. El nodo maestro será
gestionado por el servicio GKE y no se podrá acceder a él.

CONSEJO

Si no estás seguro de qué zona o región utilizar para el --zone o--


region ejecuta gcloud compute zones list o gcloud compute regions
list y elige una cercana. Las zonas suelen consumir menos recursos que las
regiones.
Cuando hayas terminado de utilizar tu clúster, no olvides borrarlo para
evitar que te cobren:

$ gcloud container clusters delete oreilly --zone us-east1-


b
Debate

Puedes saltarte la instalación de la CLI de gcloud utilizando Google Cloud


Shell, una solución puramente online basada en navegador.
Puedes listar tus clusters GKE existentes utilizando este comando:

$ gcloud container clusters list --zone us-east1-b


NAME ZONE MASTER_VERSION MASTER_IP ...
STATUS
oreilly us-east1-b 1.24.9-gke.2000 35.187.80.94 ...
RUNNING
NOTA

La CLI gcloud te permite redimensionar tu cluster , actualizarlo y mejorarlo:

...

COMMANDS

...

resize

Resizes an existing cluster for running

containers.

update

Update cluster settings for an existing container

cluster.

upgrade

Upgrade the Kubernetes version of an existing


container cluster.

Ver también

 Inicio rápido de GKE


 Inicio rápido de Google Cloud Shell

2.12 Crear un Clúster Kubernetes en


elServicio AzureKubernetes
Problema

Quieres crear un clúster Kubernetes en el Servicio Azure Kubernetes


(AKS).

Solución

Para crear un clúster AKS, necesitarás lo siguiente:

 Una cuenta del portal de Microsoft Azure


 Azure CLI instalado
En primer lugar, asegúrate de que tienes instalada la versión 2.0 o
superior de Azure CLI y, a continuación, inicia sesión en en Azure:

$ az --version | grep "^azure-cli"


azure-cli 2.50.0 *

$ az login
To sign in, use a web browser to open the page
https://aka.ms/devicelogin and
enter the code XXXXXXXXX to authenticate.
[
{
"cloudName": "AzureCloud",
"id": "****************************",
"isDefault": true,
"name": "Free Trial",
"state": "Enabled",
"tenantId": "*****************************",
"user": {
"name": "******@hotmail.com",
"type": "user"
}
}
]
Crea un grupo de recursos de Azure llamado k8s para alojar todos tus
recursos AKS, como máquinas virtuales y componentes de red, y para
facilitar la limpieza y desmontaje posteriores de:

$ az group create --name k8s --location northeurope


{
"id":
"/subscriptions/************************/resourceGroups/k8
s",
"location": "northeurope",
"managedBy": null,
"name": "k8s",
"properties": {
"provisioningState": "Succeeded"
},
"tags": null,
"type": "Microsoft.Resources/resourceGroups"
}
CONSEJO

Si no estás seguro de qué región utilizar para el argumento --location,


ejecuta az account list-locations y elige una cercana a ti.

Ahora que ya tienes configurado el grupo de recursos k8s, puedes crear el


clúster con un nodo trabajador (agente en la terminología de Azure), del
siguiente modo:

$ az aks create -g k8s -n myAKSCluster --node-count 1 --


generate-ssh-keys
{
"aadProfile": null,
"addonProfiles": null,
"agentPoolProfiles": [
{
"availabilityZones": null,
"count": 1,
"creationData": null,
"currentOrchestratorVersion": "1.26.6",
Ten en cuenta que el comando az aks create puede tardar varios minutos
en completarse. Una vez completado, el comando devuelve un objeto
JSON con información sobre el cluster creado.
Como resultado, en el portal de Azure deberías ver algo parecido a la
Figura 2-5. Empieza por buscar el grupo de recursos k8s y luego dirígete a
la pestaña Implementaciones.

Figura 2-5. Portal Azure, mostrando un clúster AKS en el grupo de recursos k8s

Ahora estás en condiciones de conectarte al clúster:

$ az aks get-credentials --resource-group k8s --name


myAKSCluster
Ahora puedes hurgar en el entorno y verificar la configuración:

$ kubectl cluster-info
Kubernetes master is running at https://k8scb-k8s-
143f1emgmt.northeurope.cloudapp
.azure.com
Heapster is running at https://k8scb-k8s-
143f1emgmt.northeurope.cloudapp.azure

.com/api/v1/namespaces/kube-system/services/heapster/proxy
KubeDNS is running at https://k8scb-k8s-
143f1emgmt.northeurope.cloudapp.azure

.com/api/v1/namespaces/kube-system/services/kube-dns/proxy
kubernetes-dashboard is running at https://k8scb-k8s-
143f1emgmt.northeurope

.cloudapp.azure.com/api/v1/namespaces/kube-system/services
/kubernetes-dashboard
/proxy
tiller-deploy is running at https://k8scb-k8s-
143f1emgmt.northeurope.cloudapp

.azure.com/api/v1/namespaces/kube-system/services/tiller-
deploy/proxy

To further debug and diagnose cluster problems, use


'kubectl cluster-info dump'.

$ kubectl get nodes


NAME STATUS ROLES AGE
VERSION
aks-nodepool1-78916010-vmss000000 Ready agent 26m
v1.24.9
Efectivamente, como puedes ver en la salida, hemos creado un clúster de
un solo nodo.

CONSEJO

Si no quieres o no puedes instalar Azure CLI, una alternativa es utilizar Azure


Cloud Shell desde tu navegador.

Cuando hayas terminado de descubrir AKS, no olvides apagar el clúster y


eliminar todos los recursos borrando el grupo de recursos k8s:

$ az group delete --name k8s --yes --no-wait


Aunque el comando az group delete retorna inmediatamente, debido a la
presencia de la bandera --no-wait, pueden pasar hasta 10 minutos hasta
que se eliminen todos los recursos y se destruya realmente el grupo de
recursos. Puede que quieras comprobarlo en el portal de Azure para
asegurarte de que todo ha ido según lo previsto.
Ver también
 "Inicio rápido: Implementación de un clúster del servicio Azure
Kubernetes mediante Azure CLI" en la documentación de
Microsoft Azure

2.13 Crear un clúster de Kubernetes


enel servicio AmazonElastic
Kubernetes
Problema

Quieres crear un clúster de Kubernetes en Amazon Elastic Kubernetes


Service (EKS).

Solución

Para crear un clúster en Amazon EKS, necesitas lo siguiente :

 Una cuenta de Amazon Web Services


 AWS CLI instalado
 Herramienta CLIeksctl instalada
Una vez que hayas instalado la CLI de AWS, autentica el cliente para
acceder a tu cuenta de AWS:

$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]:
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: eu-central-1
Default output format [None]:
La herramienta eksctl es la CLI oficial de Amazon EKS. Utiliza las
credenciales de AWS que hayas configurado para autenticarte con AWS.
Utilizando eksctl, crea el clúster:

$ eksctl create cluster --name oreilly --region eu-central-


1
2023-08-29 13:21:12 [i] eksctl version 0.153.0-
dev+a79b3826a.2023-08-18T...
2023-08-29 13:21:12 [i] using region eu-central-1
...
2023-08-29 13:36:52 [✔] EKS cluster "oreilly" in "eu-
central-1" region is ready
Por defecto, eksctl crea un cluster con dos nodos trabajadores en la región
especificada. Puedes ajustar este parámetro especificando la bandera --
nodes.
CONSEJO

Para obtener la latencia más baja, elige la región de AWS más cercana a ti.

Cuando ya no necesites el clúster EKS, elimínalo para evitar que te cobren


por los recursos no utilizados:

$ eksctl delete cluster oreilly --region eu-central-1


Ver también

 eksctl Introducción
 Servicio Amazon Elastic Kubernetes
Capítulo 3. Aprender a utilizar el
cliente de Kubernetes
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

Este capítulo reúne recetas en torno al uso básico de la CLI de


Kubernetes, kubectl. Consulta el Capítulo 1 para saber cómo instalar la
herramienta CLI; para casos de uso avanzados, consulta el Capítulo 7,
donde mostramos cómo utilizar la API de Kubernetes.

3.1 Listado de recursos

Problema

Quieres listar recursos Kubernetes de un determinado tipo.

Solución

Utiliza el verbo get de kubectl junto con el tipo de recurso. Para listar
todos los pods, haz esto

$ kubectl get pods


Para listar todos los servicios e Implementaciones de (ten en cuenta que
no hay ningún espacio después de la coma), haz esto:

$ kubectl get services,deployments


Para listar una Implementación concreta, haz esto:

$ kubectl get deployment <deployment-name>


Para listar todos los recursos, haz esto

$ kubectl get all


Ten en cuenta que kubectl get es un comando muy básico pero
extremadamente útil para obtener una visión general rápida de lo que
ocurre en el clúster; es esencialmente el equivalente a ps en Unix.
NOMBRES CORTOS PARA LOS RECURSOS DE KUBERNETES

Muchos recursos tienen nombres cortos que puedes utilizar con kubectl,
ahorrándote tiempo y cordura. Aquí tienes algunos ejemplos:
 configmaps (alias cm)
 daemonsets (alias ds)
 deployments (alias deploy)
 endpoints (alias ep)
 events (alias ev)
 horizontalpodautoscalers (alias hpa)
 ingresses (alias ing)
 namespaces (alias ns)
 nodes (alias no)
 persistentvolumeclaims (alias pvc)
 persistentvolumes (alias pv)
 pods (alias po)
 replicasets (alias rs)
 replicationcontrollers (alias rc)
 resourcequotas (alias quota)
 serviceaccounts (alias sa)
 services (alias svc)

Debate

Recomendamos encarecidamente activar el autocompletado para evitar


tener que recordar todos los nombres de recursos de
Kubernetes. Consulta la Receta 12.1 para saber cómo hacerlo.

3.2 Borrar recursos

Problema

Ya no necesitas recursos y quieres deshacerte de ellos.

Solución

Utiliza el verbo delete de kubectl junto con el tipo y el nombre del recurso
que quieres eliminar.
Para eliminar todos los recursos del espacio de nombres my-app, así como
el propio espacio de nombres, haz lo siguiente:

$ kubectl get ns
NAME STATUS AGE
default Active 2d
kube-public Active 2d
kube-system Active 2d
my-app Active 20m

$ kubectl delete ns my-app


namespace "my-app" deleted
Ten en cuenta que no puedes eliminar el espacio de nombres default en
Kubernetes. Ésta es otra razón por la que merece la pena crear tus
propios espacios de nombres, ya que puede ser mucho más fácil limpiar el
entorno. Dicho esto, puedes eliminar todos los objetos de un espacio de
nombres, como el espacio de nombres default, con el siguiente comando:

$ kubectl delete all --all -n <namespace>


Si te preguntas cómo crear un espacio de nombres, consulta la Receta 7.3.
También puedes eliminar recursos concretos y/o influir en el proceso por
el que se destruyen. Para eliminar servicios e Implementaciones
etiquetados con app=niceone, haz lo siguiente:

$ kubectl delete svc,deploy -l app=niceone


Para forzar la eliminación de un pod llamado hangingpod, haz esto:

$ kubectl delete pod hangingpod --grace-period=0 --force


Para eliminar todos los pods del espacio de nombres test, haz lo
siguiente:

$ kubectl delete pods --all --namespace test


Debate
No elimines objetos supervisados, como pods o conjuntos de réplicas, que
estén directamente controlados por una implementación. Más bien, mata
a sus supervisores o utiliza operaciones dedicadas para deshacerte de los
recursos gestionados. Por ejemplo, si escalas una implementación a cero
réplicas (ver Receta 9.1), eliminarás todos los pods de los que se ocupa.
Otro aspecto a tener en cuenta es el borrado en cascada frente al borrado
directo: por ejemplo, cuando borras una definición de recurso
personalizada (CRD), como se muestra en la Receta 15.4, se borran
también todos sus objetos dependientes. Para saber más sobre cómo
influir en la política de borrado en cascada, lee Recogida de Basura en la
documentación de Kubernetes.

3.3 Vigilar los cambios de recursos con


kubectl

Problema

Quieres ver los cambios en los objetos de Kubernetes de forma interactiva


en el terminal.

Solución

El comando kubectl tiene una opción --watch que te proporciona este


comportamiento. Por ejemplo, para ver pods, haz esto:

$ kubectl get pods --watch


Ten en cuenta que se trata de un comando de bloqueo y actualización
automática, similar a top.
Debate

La opción --watch es útil, pero algunos prefieren el formato de la salida


del comandowatch , como en:

$ watch kubectl get pods

3.4 Editar objetos con kubectl


Problema

Quieres actualizar las propiedades de un objeto Kubernetes.

Solución

Utiliza el verbo edit de kubectl junto con el tipo de objeto:

$ kubectl run nginx --image=nginx


$ kubectl edit pod/nginx
Ahora edita la vaina nginx en tu editor; por ejemplo, añade una nueva
etiqueta llamada mylabel con el valor true. Una vez guardado, verás algo
como esto:

pod/nginx edited

Debate

Si tu editor no se abre o quieres especificar qué editor debe utilizarse,


establece la variable de entorno EDITOR o KUBE_EDITOR con el nombre del
editor que quieras utilizar. Por ejemplo:

$ export EDITOR=vi
Ten en cuenta también que no todos los cambios provocan una
actualización del objeto.

Algunos activadores tienen atajos; por ejemplo, si quieres cambiar la


versión de imagen que utiliza una implementación, basta con que
utilices kubectl set image, que actualiza las imágenes de contenedor
existentes de los recursos (válido para implementaciones, conjuntos de
réplica/controladores de replicación, conjuntos de demonios, trabajos y
pods simples).
3.5 Pedir a kubectl que explique
recursos y campos

Problema

Quieres conocer mejor un determinado recurso -por ejemplo, Service- y/o


saber qué significa exactamente un determinado campo de un manifiesto
de Kubernetes, incluidos los valores por defecto y si es obligatorio u
opcional.
Solución

Utiliza el verbo explain de kubectl:

$ kubectl explain svc


KIND: Service
VERSION: v1

DESCRIPTION:
Service is a named abstraction of software service (for
example, mysql)
consisting of local port (for example 3306) that the proxy
listens on, and the
selector that determines which pods will answer requests
sent through the proxy.

FIELDS:
status <Object>
Most recently observed status of the service.
Populated by the system.
Read-only. More info:
https://git.k8s.io/community/contributors/devel/
api-conventions.md#spec-and-status/

apiVersion <string>
APIVersion defines the versioned schema of this
representation of an
object. Servers should convert recognized schemas to
the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/api-
conventions.md#resources
kind <string>
Kind is a string value representing the REST resource
this object
represents. Servers may infer this from the endpoint
the client submits
requests to. Cannot be updated. In CamelCase. More
info:
https://git.k8s.io/community/contributors/devel/api-
conventions
.md#types-kinds

metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/api-
conventions.md#metadata

spec <Object>
Spec defines the behavior of a service.
https://git.k8s.io/community/
contributors/devel/api-conventions.md#spec-and-
status/

$ kubectl explain svc.spec.externalIPs


KIND: Service
VERSION: v1

FIELD: externalIPs <[]string>

DESCRIPTION:
externalIPs is a list of IP addresses for which nodes
in the cluster will
also accept traffic for this service. These IPs are
not managed by
Kubernetes. The user is responsible for ensuring
that traffic arrives at a
node with this IP. A common example is external
load-balancers that are not
part of the Kubernetes system.
Debate

El comando kubectl explain extrae las descripciones de recursos y


campos de las definiciones Swagger/OpenAPI, expuestas por el servidor
API.
Puedes pensar en kubectl explain como una forma de describir la
estructura de los recursos de Kubernetes, mientras que kubectl
describe es una forma de describir los valores de los objetos, que son
instancias de esos recursos estructurados.
Ver también

 La entrada del blog de Ross Kukulinski, "kubectl explicar -


#HeptioProTip"
Capítulo 4. Crear y modificar cargas de
trabajo fundamentales
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este capítulo, presentamos recetas que te muestran cómo gestionar


tipos fundamentales de cargas de trabajo de Kubernetes: pods e
implementaciones. Mostramos cómo crear implementaciones y pods
mediante comandos CLI y a partir de un manifiesto YAML, y explicamos
cómo escalar y actualizar una implementación.

4.1 Crear un Pod mediante kubectl run

Problema

Quieres lanzar rápidamente una aplicación de larga ejecución, como un


servidor web.

Solución

Utiliza el comando kubectl run, un generador que crea un pod sobre la


marcha. Por ejemplo, para crear un pod que ejecute el proxy inverso
NGINX, haz lo siguiente:

$ kubectl run nginx --image=nginx

$ kubectl get pod/nginx


NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 3m55s
Debate

El comando kubectl run puede tomar varios argumentos para configurar


parámetros adicionales de los pods. Por ejemplo, puedes hacer lo
siguiente
 Establece variables de entorno con --env.
 Define los puertos de contenedores con --port.
 Define un comando para ejecutarlo utilizando --command.
 Crea automáticamente un servicio asociado con --expose.
 Prueba una ejecución sin ejecutar nada realmente con --dry-
run=client.
Los usos típicos son los siguientes. Para lanzar NGINX sirviendo en el
puerto 2368 y crear un servicio junto con él, introduce lo siguiente:

$ kubectl run nginx --image=nginx --port=2368 --expose


Para iniciar MySQL con la contraseña de root de establecida, introduce
esto:

$ kubectl run mysql --image=mysql --


env=MYSQL_ROOT_PASSWORD=root
Para lanzar un contenedor busybox y que ejecute el comando sleep 3600 al
iniciarse, introduce esto:

$ kubectl run myshell --image=busybox:1.36 --command -- sh


-c "sleep 3600"
Consulta también kubectl run --help para obtener más detalles sobre los
argumentos disponibles.

4.2 Crear una Implementación con


kubectl create

Problema

Quieres lanzar rápidamente una aplicación de larga duración, como un


sistemade gestión de contenidos.
Solución

Utiliza kubectl create deployment para crear un manifiesto de


implementación sobre la marcha. Por ejemplo, para crear una
implementación que ejecute elsistema de gestión de contenidos
WordPress, haz lo siguiente:
$ kubectl create deployment wordpress --image
wordpress:6.3.1

$ kubectl get deployments.apps/wordpress


NAME READY UP-TO-DATE AVAILABLE AGE
wordpress 1/1 1 1 90s
Debate

El comando kubectl create deployment puede tomar varios argumentos


para configurar parámetros adicionales de las Implementaciones. Por
ejemplo, puedes hacer lo siguiente
 Define los puertos de contenedores con --port.
 Define el número de réplicas utilizando --replicas.
 Prueba una ejecución sin ejecutar nada realmente con --dry-
run=client.
 Proporciona el manifiesto creado utilizando --output yaml.
Consulta también kubectl create deployment --help para obtener más
detalles sobre los argumentos disponibles.

4.3 Crear objetos a partir de archivos


manifiestos

Problema

En lugar de crear un objeto mediante un generador como kubectl run,


quieres indicar explícitamente sus propiedades y luego crearlo.
Solución

Utiliza kubectl apply así:

$ kubectl apply -f <manifest>


En la Receta 7.3 verás cómo crear un espacio de nombres utilizando un
manifiesto YAML. Éste es uno de los ejemplos más sencillos, ya que el
manifiesto es muy breve. Puede escribirse en YAML o JSON; por ejemplo,
con un archivo de manifiesto YAML myns.yaml como éste:
apiVersion: v1
kind: Namespace
metadata:
name: myns
Puedes crear este objeto con esto
$ kubectl apply -f myns.yaml
Comprueba que el espacio de nombres se creó con esto:

$ kubectl get namespaces


Debate

Puedes indicar a kubectl apply una URL en lugar de un nombre de


archivo en tu sistema de archivos local. Por ejemplo, para crear el
frontend de la aplicación canónica Libro de visitas, obtén la URL del
YAML en bruto que define la aplicación en un único manifiesto e
introduce esto:

$ kubectl apply -f
https://raw.githubusercontent.com/kubernetes/examples/
master/guestbook/all-in-one/guestbook-all-in-one.yaml
Comprueba los recursos creados por esta operación, por ejemplo con esto:

$ kubectl get all

4.4 Escribir un Manifiesto Pod desde


cero

Problema

Quieres escribir un manifiesto de vaina desde cero y aplicarlo de forma


declarativa, en lugar de utilizar un comando como kubectl run, que es
imperativo y no requiere editar manualmente un manifiesto.
Solución

Un pod es un objeto /api/v1, y como cualquier otro objeto de Kubernetes,


su archivo de manifiesto contiene los siguientes campos:
 apiVersionque especifica la versión de la API
 kindque indica el tipo de objeto
 metadataque proporciona algunos metadatos sobre el objeto
 specque proporciona la especificación del objeto
El manifiesto del pod contiene una matriz de contenedores y una matriz
opcional de volúmenes (ver Capítulo 8). En su forma más simple, con un
único contenedor y ningún volumen, tiene este aspecto:
apiVersion: v1
kind: Pod
metadata:
name: oreilly
spec:
containers:
- name: oreilly
image: nginx:1.25.2
Guarda este manifiesto YAML en un archivo llamado oreilly.yaml y luego
utiliza kubectl para crearlo:

$ kubectl apply -f oreilly.yaml


Comprueba los recursos creados por esta operación, por ejemplo con esto:

$ kubectl get all


Debate

La especificación de la API de un pod es mucho más rica que lo que se


muestra en la Solución, que es el pod de funcionamiento más básico. Por
ejemplo, un pod puede contener varios contenedores, como se muestra
aquí:

apiVersion: v1
kind: Pod
metadata:
name: oreilly
spec:
containers:
- name: oreilly
image: nginx:1.25.2
- name: safari
image: redis:7.2.0
Un pod también puede contener definiciones de volumen para cargar
datos en los contenedores (ver Receta 8.1), así como sondas para
comprobar la salud de la aplicación en contenedores (ver
Recetas 11.2 y 11.3).
En la documentación se detalla una descripción del razonamiento que
subyace a muchos de los campos de especificación y un enlace a la
especificación completa del objeto API.
NOTA

Salvo por razones muy específicas, nunca crees un pod por sí solo. Utiliza un
objeto Deployment (ver Receta 4.5) para supervisar los pods: vigilará los pods a
través de otro objeto llamado ReplicaSet.

4.5 Lanzar una Implementación


utilizando un Manifiesto

Problema

Quieres tener un control total sobre cómo se lanza ysupervisa una


aplicación (de larga duración).
Solución

Escribe un manifiesto de implementación. Para lo básico, consulta


también la Receta 4.4.
Supongamos que tienes un archivo de manifiesto
llamado fancyapp.yaml con el siguiente contenido:
apiVersion: apps/v1
kind: Deployment
metadata:
name: fancyapp
spec:
replicas: 5
selector:
matchLabels:
app: fancy
template:
metadata:
labels:
app: fancy
env: development
spec:
containers:
- name: sise
image: gcr.io/google-samples/hello-app:2.0
ports:
- containerPort: 8080
env:
- name: SIMPLE_SERVICE_VERSION
value: "2.0"
Como puedes ver, hay un par de cosas que quizá quieras hacer
explícitamente al iniciar la aplicación:
 Establece el número de vainas (replicas), o copias idénticas, que
deben lanzarse y supervisarse.
 Etiquétalo, por ejemplo con env=development (ver también las
Recetas 7.5 y 7.6).
 Establece variables de entorno, como SIMPLE_SERVICE_VERSION.
Veamos ahora qué implica la implementación:

$ kubectl apply -f fancyapp.yaml


deployment.apps/fancyapp created

$ kubectl get deployments


NAME READY UP-TO-DATE AVAILABLE AGE
fancyapp 5/5 5 5 57s

$ kubectl get replicasets


NAME DESIRED CURRENT READY AGE
fancyapp-1223770997 5 5 0 59s

$ kubectl get pods -l app=fancy


NAME READY STATUS
RESTARTS AGE
fancyapp-74c6f7cfd7-98d97 1/1 Running 0
115s
fancyapp-74c6f7cfd7-9gm2l 1/1 Running 0
115s
fancyapp-74c6f7cfd7-kggsx 1/1 Running 0
115s
fancyapp-74c6f7cfd7-xfs6v 1/1 Running 0
115s
fancyapp-74c6f7cfd7-xntk2 1/1 Running 0
115s
ADVERTENCIA

Cuando quieras deshacerte de una implementación, y con ella de los conjuntos


de réplicas y pods que supervisa, ejecuta un comando como kubectl delete
deploy/fancyapp. No intentes eliminar pods individuales, ya que volverán a
ser creados por la implementación. Esto es algo que suele confundir a los
principiantes.

Las Implementaciones te permiten escalar la aplicación (ver Receta 9.1),


así como desplegar una nueva versión o retroceder una ReplicaSet a una
versión anterior. En general, son buenos para aplicaciones sin estado que
requieren pods con características idénticas.
Debate
Una implementación es un supervisor de pods y conjuntos de réplicas
(RS), que te proporciona un control detallado sobre cómo y cuándo se
lanza una nueva versión de un pod o se retrocede a un estado
anterior. Los RS y pods que supervisa una implementación no suelen
interesarte, a menos que, por ejemplo, necesites depurar un pod (véase la
Receta 12.5). La Figura 4-1 ilustra cómo puedes avanzar y retroceder entre
las revisiones de las implementaciones.

Figura 4-1. Revisiones de la Implementación

Para generar el manifiesto de una implementación, puedes utilizar el


comando kubectl create y la opción --dry-run=client. Esto te permitirá
generar el manifiesto en formato YAML o JSON y guardarlo para su uso
posterior. Por ejemplo, para crear el manifiesto de una implementación
denominada fancy-app utilizando la imagen de contenedor nginx, emite el
siguiente comando:

$ kubectl create deployment fancyapp --image nginx:1.25.2 -


o yaml \
--dry-run=client
kind: Deployment
apiVersion: apps/v1
metadata:
name: fancyapp
creationTimestamp:
labels:
app: fancyapp
...
Ver también

 Documentación de Kubernetes Deployment

4.6 Actualizar una Implementación

Problema

Tienes una implementación y quieres lanzar una nueva versión de tu


aplicación.

Solución

Actualiza tu implementación y deja que la estrategia de actualización por


defecto, RollingUpdate, se encargue automáticamente del despliegue.
Por ejemplo, si creas una nueva imagen de contenedor y quieres
actualizar en ella la implementación basada en, puedes hacer lo siguiente:

$ kubectl create deployment myapp --image=gcr.io/google-


samples/hello-app:1.0
deployment.apps/myapp created

$ kubectl set image deployment/myapp \


hello-app=gcr.io/google-samples/hello-app:2.0
deployment.apps/myapp image updated

$ kubectl rollout status deployment myapp


deployment "myapp" successfully rolled out

$ kubectl rollout history deployment myapp


deployment.apps/myapp
REVISION CHANGE-CAUSE
1 <none>
2 <none>
Ya has desplegado con éxito una nueva revisión de tu implementación en
la que sólo ha cambiado la imagen del contenedor utilizado. Todas las
demás propiedades de la implementación, como el número de réplicas,
permanecen inalteradas. Pero, ¿y si quieres actualizar otros aspectos de la
implementación, como cambiar las variables de entorno? Puedes utilizar
varios comandos de kubectl para actualizar la implementación. Por
ejemplo, para añadir una definición de puerto a la implementación
actual, puedes utilizar kubectl edit:

$ kubectl edit deploy myapp


Este comando abrirá la implementación actual en tu editor
predeterminado o, cuando se haya configurado y exportado, en el
editor especificado por la variable de entorno KUBE_EDITOR.
Supongamos que quieres añadir la siguiente definición de puerto
(consulta la Figura 4-2 para ver el archivo completo):
...
ports:
- containerPort: 9876
...
El resultado del proceso de edición (en este caso, con KUBE_EDITOR ajustado
a vi) se muestra en la Figura 4-2.
Cuando guardes y salgas del editor, Kubernetes iniciará una nueva
implementación, ahora con el puerto definido. Vamos a verificarlo:

$ kubectl rollout history deployment myapp


deployments "sise"
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
Efectivamente, vemos que la revisión 3 se ha desplegado con los cambios
que introdujimos con kubectl edit. Sin embargo, la columna CHANGE-
CAUSE está vacía. Puedes especificar en una causa de cambio para una
revisión utilizando una anotación especial. A continuación se muestra un
ejemplo de establecimiento de una causa de cambio para la revisión más
reciente:

$ kubectl annotate deployment/myapp \


kubernetes.io/change-cause="Added port definition."
deployment.apps/myapp annotate
Figura 4-2. Edición de una Implementación

Como ya se ha dicho, hay más comandos kubectl que puedes utilizar para
actualizar tu implementación:
 Utiliza kubectl apply para actualizar una implementación (o
crearla si no existe) a partir de un archivo de manifiesto; por
ejemplo, kubectl apply -f simpleservice.yaml.
 Utiliza kubectl replace para sustituir una implementación de un
archivo de manifiesto; por ejemplo, kubectl replace -f
simpleservice.yaml. Ten en cuenta que, a diferencia de apply,
para utilizar replace, la implementación ya debe existir.
 Utiliza kubectl patch para actualizar una clave concreta, por
ejemplo:

 kubectl patch deployment myapp -p '{"spec": {"template":

 {"spec": {"containers":

[{"name": "sise", "image": "gcr.io/google-samples/hello-


app:2.0"}]}}}}'

¿Y si cometes un error o tienes problemas con la nueva versión de la


implementación? Por suerte, Kubernetes hace que sea muy fácil volver a
un estado bueno conocido utilizando el comando kubectl rollout
undo. Por ejemplo, supongamos que la última edición fue un error y
quieres retroceder a la revisión 2. Puedes hacerlo con el siguiente
comando:

$ kubectl rollout undo deployment myapp ‐‐to‐revision 2


A continuación, puedes comprobar que se ha eliminado la definición del
puerto con kubectl get deploy/myapp -o yaml.
NOTA

El despliegue de una implementación sólo se desencadena si se modifican partes


de de la plantilla del pod (es decir, claves por debajo de .spec.template), como
variables de entorno, puertos o la imagen del contenedor. Los cambios en
aspectos de las Implementaciones, como el recuento de réplicas, no
desencadenan una nueva implementación.

4.7 Ejecutar un trabajo por lotes

Problema

Quieres ejecutar un proceso que se ejecuta durante un tiempo


determinado hasta su finalización, como una conversión por lotes, una
operación de copia de seguridad o una actualización del esquema de la
base de datos.
Solución

Utiliza un Kubernetes Job para lanzar y supervisar el pod o los pods que
llevarán a cabo el proceso por lotes.
Primero, define el manifiesto de Kubernetes para el trabajo en un archivo
llamado counter-batch-job.yaml:
apiVersion: batch/v1
kind: Job
metadata:
name: counter
spec:
template:
metadata:
name: counter
spec:
containers:
- name: counter
image: busybox:1.36
command:
- "sh"
- "-c"
- "for i in 1 2 3 ; do echo $i ; done"
restartPolicy: Never
A continuación, lanza el trabajo y echa un vistazo a su estado en :

$ kubectl apply -f counter-batch-job.yaml


job.batch/counter created

$ kubectl get jobs


NAME COMPLETIONS DURATION AGE
counter 1/1 7s 12s

$ kubectl describe jobs/counter


Name: counter
Namespace: default
Selector: controller-uid=2d21031e-7263-4ff1-becd-
48406393edd5
Labels: controller-uid=2d21031e-7263-4ff1-becd-
48406393edd5
job-name=counter
Annotations: batch.kubernetes.io/job-tracking:
Parallelism: 1
Completions: 1
Completion Mode: NonIndexed
Start Time: Mon, 03 Apr 2023 18:19:13 +0530
Completed At: Mon, 03 Apr 2023 18:19:20 +0530
Duration: 7s
Pods Statuses: 0 Active (0 Ready) / 1 Succeeded / 0
Failed
Pod Template:
Labels: controller-uid=2d21031e-7263-4ff1-becd-
48406393edd5
job-name=counter
Containers:
counter:
Image: busybox:1.36
Port: <none>
Host Port: <none>
Command:
sh
-c
for i in 1 2 3 ; do echo $i ; done
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 30s job-controller Created
pod: counter-5c8s5
Normal Completed 23s job-controller Job
completed
Por último, quieres comprobar que realmente ha realizado la tarea
(contando de 1 a 3):

$ kubectl logs jobs/counter


1
2
3
Efectivamente, como puedes ver, el trabajo de counter contó como se
esperaba.
Debate

Después de que un trabajo se haya ejecutado correctamente, el pod


creado por el trabajo estará en el estado Completado. Puedes eliminar el
trabajo si ya no lo necesitas, lo que limpiará los pods que creó:

$ kubectl delete jobs/counter


También puedes suspender temporalmente la ejecución de un trabajo
de y reanudarla más tarde. Suspender un trabajo también limpiará los
pods que creó:

$ kubectl patch jobs/counter --type=strategic --patch


'{"spec":{"suspend":true}}'
Para reanudar el trabajo, simplemente gira la bandera suspend:

$ kubectl patch jobs/counter --type=strategic \


--patch '{"spec":{"suspend":false}}'

4.8 Ejecutar una Tarea en una


Programación dentro de un Pod

Problema

Quieres ejecutar una tarea en un horario concreto dentro de un pod


gestionado por Kubernetes.

Solución

Utiliza los objetos CronJob de Kubernetes. El objeto CronJob es un derivado


del objeto más genérico Job (ver Receta 4.7).
Puedes programar periódicamente un trabajo escribiendo un manifiesto
similar al que se muestra aquí. En el spec, ves una sección schedule que
sigue el formato crontab. También puedes utilizar algunas macros,
como @hourly, @daily, @weekly, @monthly, y @yearly. La
sección template describe el pod que se ejecutará y el comando que se
ejecutará (éste imprime la fecha y hora actuales cada hora en stdout):
apiVersion: batch/v1
kind: CronJob
metadata:
name: hourly-date
spec:
schedule: "0 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: date
image: busybox:1.36
command:
- "sh"
- "-c"
- "date"
restartPolicy: OnFailure

Debate

Al igual que una tarea, una tarea cron también se puede suspender y
reanudar cambiando la bandera suspend. Por ejemplo:

$ kubectl patch cronjob.batch/hourly-date --


type=strategic \
--patch '{"spec":{"suspend":true}}'
Si ya no necesitas la tarea cron, elimínala para limpiar los pods que creó:

$ kubectl delete cronjob.batch/hourly-date


Ver también

 Documentación de Kubernetes CronJob

4.9 Ejecutar demonios de


infraestructura por nodo

Problema

Quieres lanzar un demonio de infraestructura -por ejemplo, un


recopilador de registros o un agente de monitoreo- asegurándote de que
se ejecuta exactamente un pod por nodo.

Solución

Utiliza un DaemonSet para lanzar y supervisar el proceso demonio. Por


ejemplo, para lanzar un agente Fluentd en cada nodo de tu cluster, crea
un archivo llamado fluentd-daemonset.yaml con el siguiente contenido:
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
name: fluentd
spec:
containers:
- name: fluentd
image: gcr.io/google_containers/fluentd-elasticsearch:1.3
env:
- name: FLUENTD_ARGS
value: -qq
volumeMounts:
- name: varlog
mountPath: /varlog
- name: containers
mountPath: /var/lib/docker/containers
volumes:
- hostPath:
path: /var/log
name: varlog
- hostPath:
path: /var/lib/docker/containers
name: containers
Ahora lanza el DaemonSet, así:

$ kubectl apply -f fluentd-daemonset.yaml


daemonset.apps/fluentd created

$ kubectl get ds
NAME DESIRED CURRENT READY UP-TO-DATE
AVAILABLE NODE SELECTOR AGE
fluentd 1 1 1 1 1
<none> 60s

$ kubectl describe ds/fluentd


Name: fluentd
Selector: app=fluentd
Node-Selector: <none>
Labels: <none>
Annotations: deprecated.daemonset.template.generation:
1
Desired Number of Nodes Scheduled: 1
Current Number of Nodes Scheduled: 1
Number of Nodes Scheduled with Up-to-date Pods: 1
Number of Nodes Scheduled with Available Pods: 1
Number of Nodes Misscheduled: 0
Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0
Failed
...
Debate

Observa que en la salida anterior, como el comando se ejecuta en


Minikube, sólo ves un pod en ejecución, ya que sólo hay un nodo en esta
configuración. Si tuvieras 15 nodos en tu clúster, tendrías 15 pods en total
con 1 pod por nodo ejecutándose. También puedes restringir el demonio a
determinados nodos utilizando la sección nodeSelector en el spec del
manifiesto DaemonSet.
Capítulo 5. Trabajar con servicios
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este capítulo hablamos de cómo se comunican los pods dentro del


clúster, cómo se descubren las aplicaciones entre sí y cómo exponer los
pods para que se pueda acceder a ellos desde fuera del clúster.

El recurso que utilizaremos aquí se llama servicio Kubernetes, como se


muestra en la Figura 5-1.
Figura 5-1. El concepto de servicio Kubernetes

Un servicio proporciona una dirección IP virtual (VIP) estable para un


conjunto de pods. Aunque los pods pueden ir y venir, los servicios
permiten a los clientes descubrir y conectarse de forma fiable a los
contenedores que se ejecutan en los pods utilizando la VIP. El "virtual" en
VIP significa que no es una dirección IP real conectada a una interfaz de
red; su propósito es puramente reenviar tráfico a uno o más pods.
Mantener actualizado el mapeo entre los VIPs y los pods es tarea de kube-
proxy, un proceso que se ejecuta en cada nodo del clúster. Este proceso
de kube-proxy consulta al servidor API para conocer los nuevos servicios
del clúster y actualiza en consecuencia las reglas iptables (iptables) del
nodo para proporcionar la información de enrutamiento necesaria.

5.1 Crear un servicio para exponer tu


aplicación

Problema

Quieres proporcionar una forma estable y fiable de descubrir y acceder a


tu aplicación dentro del clúster.

Solución

Crea un servicio Kubernetes para los pods que componen tu aplicación.

Suponiendo que hayas creado una implementación de nginx con kubectl


create deployment nginx --image nginx:1.25.2, puedes crear
automáticamente un objeto Service utilizando el comando kubectl
expose, de este modo:

$ kubectl expose deploy/nginx --port 80


service "nginx" exposed

$ kubectl describe svc/nginx


Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.97.137.240
IPs: 10.97.137.240
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 172.17.0.3:80
Session Affinity: None
Events: <none>
Entonces verás que el objeto aparece al listar Service:
$ kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP
PORT(S) AGE
nginx ClusterIP 10.97.137.240 <none>
80/TCP 2s
Debate

Para acceder a este servicio a través de tu navegador, ejecuta a proxy en


un terminal independiente, de la siguiente manera:

$ kubectl proxy
Starting to serve on 127.0.0.1:8001
A continuación, abre tu navegador con esto:

$ open
http://localhost:8001/api/v1/namespaces/default/services/ng
inx/proxy/
Deberías ver la página por defecto de NGINX.

CONSEJO

Si tu servicio no parece funcionar correctamente, comprueba las etiquetas


utilizadas en el selector y verifica que se está rellenando un conjunto de puntos
finales con kubectl get endpoints <service-name>. Si no es así, lo más
probable es que tu selector no esté encontrando ningún pod coincidente.

Si quisieras crear a mano un objeto Service para la misma


implementación nginx, escribirías el siguiente archivo YAML:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- port: 80
A lo que hay que prestar atención en este archivo YAML es al selector,
que se utiliza para seleccionar todos los pods que componen esta
abstracción de microservicio. Kubernetes utiliza el objeto Service para
configurar dinámicamente las iptables de todos los nodos para poder
enviar el tráfico de red a los contenedores que componen el
microservicio. La selección se realiza como una consulta de etiquetas
(ver Receta 7.6) y da como resultado una lista de endpoints.
NOTA

Los supervisores de pods, como Deployments o ReplicationSets, funcionan


ortogonalmente a Services. Tanto los supervisores como Services encuentran
los pods que cuidan mediante etiquetas, pero tienen tareas diferentes: los
supervisores monitorean la salud de los pods y los reinician, y Services los
hacen accesibles de forma fiable.

Ver también

 Documentación de Kubernetes Service


 Tutorial de Kubernetes "Utilizar un servicio para exponer tu
aplicación"

5.2 Verificar la entrada DNS de un


servicio

Problema

Has creado un servicio (ver Receta 5.1) y quieres comprobar que el


registro de tu Sistema de Nombres de Dominio (DNS) funciona
correctamente.
Solución

Por defecto, Kubernetes utiliza ClusterIP como tipo de servicio, y eso


expone el servicio en una IP interna del clúster. Si el complemento de
clúster DNS está disponible y funciona correctamente, puedes acceder al
servicio a través de un nombre de dominio completo (FQDN) con la
forma $SERVICENAME.$NAMESPACE.svc.cluster.local.
Para verificar que esto funciona como se espera, obtén un intérprete de
comandos interactivo dentro de un contenedor de tu clúster. La forma
más sencilla de hacerlo es utilizar kubectl run con la imagen busybox, de la
siguiente manera:

$ kubectl run busybox --rm -it --image busybox:1.36 --


/bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx
Server: 10.96.0.10
Address: 10.96.0.10:53

Name: nginx.default.svc.cluster.local
Address: 10.100.34.223
La dirección IP devuelta para el servicio debe corresponder a la IP de su
cluster.

Escribe exit y pulsa Intro para salir del contenedor.


Debate

Por defecto, una consulta DNS tendrá como ámbito el mismo espacio de
nombres que el pod que realiza la solicitud. Si, en el ejemplo anterior,
ejecutas el pod busybox en un espacio de nombres distinto del que
ejecuta nginx, por defecto la búsqueda no devolverá ningún
resultado. Para especificar el espacio de nombres correcto, utiliza la
sintaxis <service-name>.<namespace>; por ejemplo, nginx.staging.

5.3 Cambiar el tipo de un servicio

Problema

Tienes un servicio existente, digamos del tipo ClusterIP, como se explica


en la Receta 5.2, y quieres cambiar su tipo para poder exponer tu
aplicación como NodePort o a través de un equilibrador de carga de un
proveedor en la nube utilizando el tipo de servicio LoadBalancer.
Solución

Utiliza el comando kubectl edit junto con tu editor preferido para


cambiar el tipo de servicio. Supongamos que tienes un archivo de
manifiesto llamado simple-nginx-svc.yaml con este contenido:
kind: Service
apiVersion: v1
metadata:
name: webserver
spec:
ports:
- port: 80
selector:
app: nginx
Crea el servicio webserver y consúltalo:
$ kubectl apply -f simple-nginx-svc.yaml

$ kubectl get svc/webserver


NAME TYPE CLUSTER-IP EXTERNAL-IP
PORT(S) AGE
webserver ClusterIP 10.98.223.206 <none>
80/TCP 11s
A continuación, cambia el tipo de servicio a, por ejemplo, NodePort, de esta
forma:

$ kubectl edit svc/webserver


Este comando descargará la especificación actual que el servidor API tiene
del servicio y la abrirá en tu editor predeterminado. Fíjate en la zona en
negrita hacia el final, donde hemos cambiado el tipo
de ClusterIP a NodePort:

# Please edit the object below. Lines beginning with a '#'


will be ignored,

# and an empty file will abort the edit. If an error


occurs while saving this...

# reopened with the relevant failures.

apiVersion: v1

kind: Service

metadata:

annotations:

kubectl.kubernetes.io/last-applied-configuration: |

{"apiVersion":"v1","kind":"Service","metadata":
{"annotations":{},"name"...

creationTimestamp: "2023-03-01T14:07:55Z"
name: webserver

namespace: default

resourceVersion: "1128"

uid: 48daed0e-a16f-4923-bd7e-1d879dc2221f

spec:

clusterIP: 10.98.223.206

clusterIPs:

- 10.98.223.206

externalTrafficPolicy: Cluster

internalTrafficPolicy: Cluster

ipFamilies:

- IPv4

ipFamilyPolicy: SingleStack

ports:

- nodePort: 31275

port: 80

protocol: TCP

targetPort: 80

selector:

app: nginx

sessionAffinity: None

type: NodePort
status:
loadBalancer: {}
Una vez que hayas guardado las modificaciones
(cambiando type por NodePort), puedes verificar el servicio actualizado, de
este modo:

$ kubectl get svc/webserver


NAME TYPE CLUSTER-IP EXTERNAL-IP
PORT(S) AGE
webserver NodePort 10.98.223.206 <none>
80:31275/TCP 4m

$ kubectl get svc/webserver -o yaml


apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":
{"annotations":{},"name"...
creationTimestamp: "2023-03-01T14:07:55Z"
name: webserver
namespace: default
resourceVersion: "1128"
uid: 48daed0e-a16f-4923-bd7e-1d879dc2221f
spec:
clusterIP: 10.98.223.206
clusterIPs:
- 10.98.223.206
externalTrafficPolicy: Cluster
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- nodePort: 31275
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
Debate
Ten en cuenta que puedes cambiar el tipo de servicio por el que mejor se
adapte a tu caso de uso; sin embargo, ten en cuenta las implicaciones de
ciertos tipos, como LoadBalancer, que pueden desencadenar el
aprovisionamiento de componentes de infraestructura de nube pública
que pueden resultar costosos si se utilizan sin conocimiento y/o
monitoreo.
Ver también

 Detalles sobre los distintos tipos de servicios Kubernetes

5.4 Implementación de un controlador


de entrada

Problema

Quieres implementar un controlador de entrada para conocer los


objetos Ingress. Los objetos Ingress te interesan porque quieres
proporcionar acceso a tus aplicaciones que se ejecutan en Kubernetes
desde fuera de tu clúster Kubernetes; sin embargo, no quieres crear un
servicio del tipo NodePort-o LoadBalancer-.
Solución

Un controlador de entrada actúa como proxy inverso y equilibrador de


carga. Enruta el tráfico desde fuera del clúster y equilibra la carga hacia
los pods que se ejecutan dentro de la plataforma, permitiéndote
implementar múltiples aplicaciones en el clúster, cada una direccionable
por nombre de host y/o ruta URI.

Para que los objetos de Ingress (de los que se habla en la Receta 5.5)
surtan efecto y proporcionen una ruta desde fuera del clúster a tus pods,
tienes que implementar un controlador de entrada:

$ kubectl apply -f
https://raw.githubusercontent.com/kubernetes/ingress-nginx/
controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
CONSEJO

En Minikube, puedes simplemente activar el complemento ingress así:


$ minikube addons enable ingress

Al cabo de un minuto o menos, se iniciará un nuevo pod en el espacio de


nombres ingress-nginx recién creado:

$ kubectl get pods -n ingress-nginx


NAME READY STATUS
RESTARTS AGE
ingress-nginx-admission-create-xpqbt 0/1
Completed 0 3m39s
ingress-nginx-admission-patch-r7cnf 0/1
Completed 1 3m39s
ingress-nginx-controller-6cc5ccb977-l9hvz 1/1 Running
0 3m39s
Ya estás preparado para crear objetos Ingress.
Debate

NGINX es uno de los controladores de entrada admitidos oficialmente por


el proyecto Kubernetes, pero hay muchas otras soluciones comerciales y
de código abierto que admiten la especificación de entrada, muchas de las
cuales ofrecen capacidades de gestión de API más amplias.
En el momento de escribir estas líneas, la nueva especificación de la API
de pasarela de Kubernetes se perfila como un futuro sustituto de la
especificación de entrada y ya cuenta con el apoyo de muchos
proveedores de pasarelas de terceros. Si estás empezando con ingress,
merece la pena considerar la pasarela de API como un punto de partida
más preparado para el futuro.
Ver también

 Documentación de Kubernetes Ingress


 Controlador de entrada basado en NGINX
 Complemento de Minikube ingress-dns

5.5 Hacer accesibles los servicios desde


fuera del Cluster

Problema
Quieres acceder a un servicio Kubernetes por ruta URI desde fuera del
clúster.

Solución

Utiliza un controlador de entrada (ver Receta 5.4), configurado mediante


la creación de objetos Ingress.
Supongamos que quieres implementar un servicio sencillo que pueda
invocarse y devuelva "¡Hola, mundo!". Empieza por crear la
implementación:

$ kubectl create deployment web --image=gcr.io/google-


samples/hello-app:2.0
A continuación, expón el servicio:

$ kubectl expose deployment web --port=8080


Comprueba que todos estos recursos se han creado correctamente con lo
siguiente:

$ kubectl get all -l app=web


NAME READY STATUS RESTARTS
AGE
pod/web-79b7b8f988-95tjv 1/1 Running 0
47s

NAME TYPE CLUSTER-IP EXTERNAL-IP


PORT(S) AGE
service/web ClusterIP 10.100.87.233 <none>
8080/TCP 8s

NAME READY UP-TO-DATE AVAILABLE AGE


deployment.apps/web 1/1 1 1 47s

NAME DESIRED CURRENT READY


AGE
replicaset.apps/web-79b7b8f988 1 1 1
47s
A continuación se muestra el manifiesto de un objeto Ingress que
configura la ruta URI /web al servicio hello-app:
$ cat nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-public
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host:
http:
paths:
- path: /web
pathType: Prefix
backend:
service:
name: web
port:
number: 8080

$ kubectl apply -f nginx-ingress.yaml


Ahora puedes ver el objeto Ingress creado para NGINX en tupanel de
control de Kubernetes(Figura 5-2).
Figura 5-2. Objeto NGINX Ingress

En el panel de control de Kubernetes, puedes ver que NGINX estará


disponible a través de la dirección IP 192.168.49.2 (la tuya puede ser
diferente). Basándote en esta información, puedes acceder a NGINX desde
fuera del clúster en la ruta /web URI de la siguiente manera:

$ curl https://192.168.49.2/web
Hello, world!
Version: 1.0.0
Hostname: web-68487bc957-v9fj8
PROBLEMA CONOCIDO CON MINIKUBE

Debido a las limitaciones de red conocidas cuando se utiliza Minikube con


el controlador Docker (por ejemplo, con Docker Desktop), es posible que
no puedas acceder externamente a tu servicio utilizando la dirección IP
proporcionada por el objeto Ingress, como se ha mostrado
anteriormente. En este caso, la solución recomendada es crear un túnel
hacia el clúster utilizando el comando minikube service. Por ejemplo, para
exponer el servicio web que hemos creado en esta receta, utiliza el
siguiente comando:
$ minikube service web
Por defecto, este comando abrirá el servicio en tu navegador
predeterminado. Añade la opción --url, y la URL del túnel se imprimirá
en el terminal. Ten en cuenta que el comando minikube service bloqueará
tu terminal mientras se ejecuta, por lo que te recomendamos que lo
ejecutes en una ventana de terminal dedicada.
En la documentación de Minikube puedes leer más sobre esta limitación.
Debate

Una alternativa al uso del panel para ver las IPs de tus servicios es utilizar
el siguiente comando:

$ kubectl describe ingress


En general, la entrada funciona como se muestra en la Figura 5-3: el
controlador de entrada escucha el punto final /ingresses del servidor API,
para conocer las nuevas reglas. A continuación, configura las rutas para
que el tráfico externo llegue a un servicio específico (interno del
clúster):service1 en el puerto 9876 en el ejemplo representado.

Figura 5-3. Concepto de entrada

Ver también

 El repositorio kubernetes/ingress-nginx en GitHub


Capítulo 6. Gestión de manifiestos de
aplicación
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este capítulo, echaremos un vistazo a las formas de simplificar la


gestión de aplicaciones en Kubernetes con el uso de herramientas como
Helm, kompose, y kapp. Estas herramientas se centran principalmente en
la gestión de tus manifiestos YAML. Helm es una herramienta de
plantillas, empaquetado y despliegue de YAML, mientras que Kompose es
una herramienta que te ayuda a migrar tus archivos Docker Compose a
manifiestos de recursos de Kubernetes. kapp es una herramienta
relativamente nueva que te permite gestionar un grupo de archivos YAML
como una aplicación y, por tanto, gestionar su despliegue como una única
aplicación.

6.1 Instalación de Helm, el gestor de


paquetes de Kubernetes

Problema

No quieres escribir a mano todos tus manifiestos de Kubernetes. En lugar


de eso, quieres poder buscar un paquete en un repositorio y descargarlo e
instalarlo con una interfaz de línea de comandos.

Solución

Utiliza Helm. Helm consiste en una CLI del lado del cliente llamada helm y
se utiliza para buscar e implementar gráficos en un clúster Kubernetes.
Puedes descargar Helm desde la página de versiones de GitHub y mover
el binario helm a tu $PATH. Por ejemplo, en macOS (Intel), para la versión
v3.12.3, haz esto:

$ wget https://get.helm.sh/helm-v3.12.3-darwin-amd64.tar.gz
$ tar -xvf helm-v3.12.3-darwin-amd64.tar.gz
$ sudo mv darwin-amd64/helm /usr/local/bin
Alternativamente, puedes utilizar el práctico script instalador para
instalar la última versión de Helm:

$ wget -O get_helm.sh
https://raw.githubusercontent.com/helm/helm/main/
scripts/get-helm-3

$ chmod +x get_helm.sh
$ ./get_helm.sh
Debate

Helm es el gestor de paquetes de Kubernetes; define un paquete de


Kubernetes como un conjunto de manifiestos y algunos metadatos. Los
manifiestos son en realidad plantillas. Los valores de las plantillas se
rellenan cuando el paquete es instanciado por Helm. Un paquete de Helm
se denomina gráfico, y los gráficos empaquetados se ponen a disposición
de los usuarios en repositorios de gráficos.
Otro método para instalar Helm en Linux o macOS es utilizar el gestor de
paquetes Homebrew:

$ brew install helm

6.2 Añadir repositorios de gráficos a


Helm

Problema

Has instalado el cliente helm (ver Receta 6.1), y ahora quieres encontrar y
añadir repositorios de gráficos a Helm.
Solución

Un repositorio de gráficos consiste en gráficos empaquetados y algunos


metadatos que permiten a Helm buscar gráficos en el repositorio. Antes
de que puedas empezar a instalar una aplicación con Helm, necesitas
encontrar y añadir el repositorio de gráficos que proporciona el gráfico.
Como se ilustra en la Figura 6-1, Artifact Hub es un servicio basado en la
web que te permite buscar más de 10.000 gráficos de varios editores y
añadir repositorios de gráficos a Helm.

Figura 6-1. Artifact Hub, buscando un gráfico de Helm para Redis

Debate

El comando helm también se integra con Artifact Hub, lo que te permite


buscar en Artifact Hub directamente desde la línea de comandos helm.
Supongamos que quieres buscar un editor que proporcione un gráfico
Redis. Puedes utilizar el comando helm search hub para encontrar uno:

$ helm search hub --list-repo-url redis


URL CHART VER... APP VER...
DESCRIPTION REPO URL
https://art...s/redis 0.1.1 6.0.8.9 A Helm
cha... https://spy8...
https://art...s-arm/... 17.8.0 7.0.8 Redis(R)
i... https://libr...
https://art...ontain... 0.15.2 0.15.0 Provides
e... https://ot-c...
...
Si quieres implementar en el gráfico publicado por Bitnami, un conocido
editor de más de 100 gráficos con calidad de producción, añade el
repositorio del gráfico de la siguiente manera:
$ helm repo add bitnami https://charts.bitnami.com/bitnami
Ya estás preparado para instalar gráficos desde el repositorio.

6.3 Utilizar Helm para Instalar


Aplicaciones

Problema

Has añadido un repositorio de gráficos a Helm (ver Receta 6.2), y ahora


quieres buscar gráficos e implementarlos.
Solución

Supongamos que quieres implementar el gráfico de Redis desde


el repositorio de gráficos de Bitnami.
Antes de buscar en un repositorio de gráficos, es una buena práctica
actualizar el índice en caché local de los repositorios de gráficos:

$ helm repo update


Hang tight while we grab the latest from your chart
repositories...
...Successfully got an update from the "bitnami" chart
repository
Update Complete. ⎈Happy Helming!⎈
Busca redis en el repositorio gráfico de Bitnami:

$ helm search repo bitnami/redis


NAME CHART VERSION APP VERSION
DESCRIPTION
bitnami/redis 18.0.1 7.2.0 Redis(R)
is an...
bitnami/redis-cluster 9.0.1 7.2.0 Redis(R)
is an...
Y utiliza helm install para implementar el gráfico:

$ helm install redis bitnami/redis


Helm utilizará la configuración por defecto del gráfico y creará una
versión de Helm llamada redis. Una versión de Helm es la colección de
todos los objetos Kubernetes definidos en un gráfico que puedes gestionar
como una sola unidad.
Al cabo de un rato deberías ver las vainas redis en funcionamiento:

$ kubectl get all -l app.kubernetes.io/name=redis


NAME READY STATUS RESTARTS AGE
pod/redis-master-0 1/1 Running 0 114s
pod/redis-replicas-0 1/1 Running 0 114s
pod/redis-replicas-1 1/1 Running 0 66s
pod/redis-replicas-2 1/1 Running 0 38s

NAME TYPE CLUSTER-IP


EXTERNAL-IP PORT(S) AGE
service/redis-headless ClusterIP None <none>
6379/TCP 114s
service/redis-master ClusterIP 10.105.20.184 <none>
6379/TCP 114s
service/redis-replicas ClusterIP 10.105.27.109 <none>
6379/TCP 114s

NAME READY AGE


statefulset.apps/redis-master 1/1 114s
statefulset.apps/redis-replicas 3/3 114s
Debate

La salida del comando helm install podría contener información


importante sobre la implementación, como contraseñas recuperadas de
secretos, servicios desplegados, etc. Puedes utilizar el comando helm
list para listar las instalaciones de helm existentes, y luego helm
status <name> para ver los detalles de esa instalación:

% helm status redis

NAME: redis

LAST DEPLOYED: Fri Nov 10 09:42:17 2023

NAMESPACE: default
STATUS: deployed

...

Para saber más sobre los gráficos de Helm y cómo crear tus propios
gráficos, consulta la Receta 6.8.

6.4 Inspeccionar los parámetros


personalizables de un gráfico

Problema

Quieres conocer los parámetros personalizables de un gráfico y sus


valores por defecto.

Solución

Los editores de gráficos exponen varios parámetros de un gráfico que


pueden configurarse al instalarlo. Los valores por defecto de estos
parámetros se configuran en un archivo de Valores cuyo contenido se
puede ver utilizando el comando helm show values -por ejemplo:

$ helm show values bitnami/redis


...
...
## @param architecture Redis® architecture. Allowed
values: `standalone` or
`replication`
##
architecture: replication
...
...
Debate

Es una práctica habitual que los editores documenten los parámetros del
gráfico en el archivo Valores. Sin embargo, el archivo Léeme de un
gráfico puede proporcionar una documentación más extensa de los
distintos parámetros, junto con instrucciones de uso específicas. Para ver
el archivo Léame de un gráfico, utiliza el comando helm show readme.
Por ejemplo

$ helm show readme bitnami/redis


...
...
### Redis® common configuration parameters

| Name | Description
| Value |
| -------------------------- |
--------------------------------| ------------- |
| `architecture` | Redis® architecture...
| `replication` |
| `auth.enabled` | Enable password
authentication | `true` |
...
...
Merece la pena señalar que este Léame es el mismo que el elaborado para
el gráfico en Artifact Hub.

6.5 Anulación de los parámetros del


gráfico

Problema

Ya conoces los distintos parámetros personalizables de un gráfico


(ver Receta 6.4), y ahora quieres personalizar la implementación del
gráfico.
Solución

Los parámetros por defecto de un gráfico Helm pueden anularse pasando


la dirección --set. key=value al instalar el gráfico. La bandera puede
especificarse varias veces, o puedes separar los pares clave/valor con
comas de la siguiente manera key1=value1,key2=value2.
Por ejemplo, puedes anular la configuración de implementación del
gráfico bitnami/redis para utilizar la arquitectura standalone del
siguiente modo:
$ helm install redis bitnami/redis --set
architecture=standalone
Debate

Cuando anules muchos parámetros del gráfico, puedes proporcionar la


bandera --values para introducir un archivo con formato YAML con
todos los parámetros que quieras anular. Para el ejemplo anterior, crea
un archivo llamado values.yaml que contenga esta línea:
architecture: standalone
A continuación, introduce el archivo en helm install:

$ helm install redis bitnami/redis --values values.yaml


La configuración standalone del gráfico bitnami/redis genera menos
recursos de pods y es adecuada para fines de desarrollo. Echemos un
vistazo:

$ kubectl get pods


NAME READY STATUS RESTARTS AGE
redis-master-0 1/1 Running 0 3m14s

6.6 Obtener los parámetros


suministrados por el usuario de
unaliberación de Helm
Problema

Tu clúster Kubernetes tiene una versión de Helm, y quieres conocer los


parámetros del gráfico proporcionados por el usuario que se
especificaron cuando se instaló el gráfico.

Solución

El comando helm list obtiene la lista de objetos de lanzamiento de


Helm presentes en el cluster:
$ helm list
NAME NAMESPACE REVISION UPDATED STATUS
CHART APP VERSION
redis default 1 2022-12-30 14:02... deployed
redis-17.4.0 7.0.7
Puedes obtener información ampliada sobre una versión de Helm, como
los valores proporcionados por el usuario, utilizando el comando helm
get:

$ helm get values redis


USER-SUPPLIED VALUES:
architecture: standalone
Debate

Además de values, también puedes recuperar los manifiestos YAML, las


notas posteriores a la implementación y los ganchos configurados en el
gráfico mediante elcomando helm get.

6.7 Desinstalar aplicaciones con Helm

Problema

Ya no quieres una aplicación que se instaló con Helm (ver Receta 6.3) y
quieres eliminarla.
Solución

Cuando instalas una aplicación utilizando un gráfico, se crea una versión


de Helm que puede gestionarse como una sola unidad. Para eliminar una
aplicación que se instaló utilizando Helm, todo lo que tienes que hacer es
eliminar la versión utilizando el comando helm uninstall.
Supongamos que quieres eliminar una versión de Helm llamada Redis:

$ helm uninstall redis


release "redis" uninstalled
Helm eliminará todos los objetos Kubernetes asociados a la versión y
liberará los recursos del clúster asociados a sus objetos.
6.8 Crear tu propio gráfico para
empaquetar tuaplicación con Helm
Problema

Has escrito una aplicación con varios manifiestos de Kubernetes y quieres


empaquetarla como un gráfico de Helm.

Solución

Utiliza los comandos helm create y helm package.


Con helm create, genera el esqueleto de tu gráfico. Ejecuta el comando
en tu terminal, especificando el nombre de tu gráfico. Por ejemplo, para
crear un gráfico oreilly:

$ helm create oreilly


Creating oreilly

$ tree oreilly/
oreilly/
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml

3 directories, 10 files
Debate

El comando helm create genera un andamiaje para una aplicación web


típica. Puedes editar el andamiaje generado y adaptarlo a tu aplicación, o
si ya tienes escritos tus manifiestos, puedes borrar el contenido del
directorio templates/ y copiar en él tus plantillas existentes. Si quieres
crear plantillas para tus manifiestos, escribe los valores que deben
sustituirse en los manifiestos en el archivo values.yaml. Edita el archivo
de metadatos Chart.yaml, y si tienes gráficos dependientes, colócalos en el
directorio /charts.
Puedes probar tu gráfico localmente ejecutando esto:

$ helm install oreilly-app ./oreilly


Por último, puedes empaquetarlo con helm package oreilly/ para
generar un tarball redistribuible de tu gráfico. Si quieres publicar el
gráfico en un repositorio de gráficos, cópialo en el repositorio y genera un
nuevo index.yaml utilizando el comando helm repo index .. Una vez
completadas las actualizaciones del registro de gráficos, y siempre que
hayas añadido el repositorio de gráficos a Helm (ver Receta 6.2), helm
search repo oreilly debería devolverte tu gráfico:

$ helm search repo oreilly


NAME VERSION DESCRIPTION
oreilly/oreilly 0.1.0 A Helm chart for Kubernetes
Ver también

 "Crea tu primer gráfico de Helm" en los documentos del Catálogo


de aplicaciones de VMware
 "Guía de buenas prácticas de los gráficos" en los documentos de
Helm

6.9 Instalar Kompose

Problema

Has empezado a utilizar contenedores con Docker y has escrito algunos


archivos Docker compose para definir tu aplicación multicontenedor.
Ahora quieres empezar a utilizar Kubernetes y te preguntas si puedes
reutilizar tus archivos Docker compose y cómo.

Solución
Utiliza Kompose. Kompose es una herramienta que convierte los archivos
de composición de Docker en manifiestos de Kubernetes (u OpenShift).
Para empezar, descarga kompose de la página de publicación de GitHub y
muévelo a tu $PATH, por comodidad.
Por ejemplo, en macOS, haz lo siguiente:

$ wget
https://github.com/kubernetes/kompose/releases/download/v1.
27.0/
kompose-darwin-amd64 -O kompose

$ sudo install -m 755 kompose /usr/local/bin/kompose


$ kompose version
Alternativamente, los usuarios de Linux y macOS pueden instalar la
CLI kompose utilizando el gestor de paquetes Homebrew:

$ brew install kompose

6.10 Convertir tus archivos Docker


Compose enmanifiestos de Kubernetes
Problema

Has instalado el comando kompose (ver Receta 6.9), y ahora quieres


convertir tu archivo de composición Docker en manifiestos de
Kubernetes.
Solución

Supón que tienes el siguiente archivo Docker compose que inicia un


contenedor redis:
version: '2'

services:
redis:
image: redis:7.2.0
ports:
- "6379:6379"
Con Kompose, puedes convertirlo automáticamente en manifiestos de
Kubernetes con el siguiente comando:
$ kompose convert
Kompose leerá el contenido del archivo Docker compose y generará los
manifiestos de Kubernetes en el directorio actual. A continuación, puedes
utilizar kubectl apply para crear estos recursos en tu clúster.
Debate

Si añades el argumento --stdout al comando kompose convert, se


generará el YAML, que se puede pasar directamente a kubectl apply de
esta forma:

$ kompose convert --stdout | kubectl apply -f -


Algunas directivas de composición de Docker no se convierten a
Kubernetes. En este caso, kompose imprime una advertencia
informándote de que la conversión no se ha producido.
Aunque en general no causa problemas, es posible que la conversión no
dé como resultado un manifiesto que funcione en Kubernetes. Esto es de
esperar, ya que este tipo de transformación no puede ser perfecta. Sin
embargo, te acercará a un manifiesto de Kubernetes que funcione. En
particular, la gestión de los volúmenes y el aislamiento de la red
requerirán normalmente un trabajo manual y personalizado por tu parte.

6.11 Convertir tu archivo Docker


Compose en ungráfico Helm
Problema

Has instalado el comando kompose (ver Receta 6.9), y ahora quieres crear
un gráfico Helm a partir de tu archivo Docker compose.
Solución

Además de utilizar Kompose para convertir tus archivos de composición


de Docker en manifiestos de Kubernetes (ver Receta 6.10), también puedes
utilizarlo para generar un gráfico de Helm para los objetos convertidos.
Genera un gráfico Helm a partir de tu archivo Docker compose utilizando
Kompose de la siguiente manera:
$ kompose convert --chart
Se generará un nuevo gráfico Helm en el directorio actual. Este gráfico
puede empaquetarse, implementarse y gestionarse mediante la
CLI helm (consulta la Receta 6.3).

6.12 Instalar kapp

Problema

Has escrito los archivos YAML para desplegar tu aplicación en el clúster y


quieres desplegar y gestionar el ciclo de vida de la implementación, pero
no quieres empaquetarlo como un gráfico de Helm.

Solución

Utiliza kapp, que es una herramienta CLI que te permite gestionar


recursos en bloque. A diferencia de Helm, kapp considera la creación de
plantillas YAML fuera de su ámbito y se centra en gestionar las
Implementaciones de aplicaciones.
Para instalar kapp, utiliza el script de descarga para descargar la última
versión para tu plataforma desde la página de versiones de GitHub:

$ mkdir local-bin/
$ wget https://carvel.dev/install.sh -qO - | \
K14SIO_INSTALL_BIN_DIR=local-bin bash

$ sudo install -m 755 local-bin/kapp /usr/local/bin/kapp


$ kapp version
Debate

Los usuarios de Linux y macOS también pueden instalar kapp utilizando


el gestor de paquetes Homebrew:

$ brew tap vmware-tanzu/carvel


$ brew install kapp
$ kapp version
6.13 Implementación de manifiestos
YAML con kapp

Problema

Has instalado kapp (ver Receta 6.12), y ahora quieres implementar y


gestionar tus manifiestos YAML utilizando kapp.
Solución

kapp considera un conjunto de recursos con la misma etiqueta como una


aplicación. Supongamos que tienes una carpeta llamada manifests/ que
contiene el archivo YAML para implementar un servidor NGINX. kapp
tratará todos estos manifiestos como una única aplicación:

$ cat manifests/deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25.2
ports:
- containerPort: 80

$ cat manifests/svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- port: 80
Para implementar estos manifiestos como una aplicación con la
etiqueta nginx, utiliza lo siguiente:

$ kapp deploy -a nginx -f manifests/


...
Namespace Name Kind Age Op Op st. Wait to
Rs Ri
default nginx Deployment - create -
reconcile - -
^ nginx Service - create -
reconcile - -
...
Continue? [yN]:
kapp proporcionará una visión general de los recursos que se crearán en
el clúster y pedirá confirmación al usuario. Para actualizar la aplicación,
todo lo que tienes que hacer es actualizar los archivos YAML en la
carpeta manifests/ y volver a ejecutar el comando deploy. Puedes añadir
la opción --diff-changes para ver un diff del YAML actualizado.
Debate

Tras la implementación de aplicaciones mediante kapp, también puedes


gestionar su ciclo de vida. Por ejemplo, para inspeccionar los recursos
creados para la implementación de una aplicación, haz lo siguiente:

$ kapp inspect -a nginx


...
Name Namespaces Lcs Lca
nginx default true 4s
...
Para listar todas las aplicaciones implementadas, haz esto:

$ kapp ls
...
Name Namespaces Lcs Lca
nginx default true 4s
...
Y para eliminar una aplicación implementada mediante kapp, haz lo
siguiente:

$ kapp delete -a nginx


Capítulo 7. Explorar la API de
Kubernetes y los metadatos clave
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este capítulo, presentamos recetas que abordan las interacciones


básicas con los objetos de Kubernetes, así como con la API. Todos
los objetos de Kubernetes, independientemente de si tienen un espacio de
nombres como una implementación o un clúster como un nodo, tienen
ciertos campos disponibles, por ejemplo, metadata, spec y status.
El spec describe el estado deseado para un objeto (la especificación), y
el status captura el estado real del objeto, gestionado por el servidor de
la API de Kubernetes.

7.1 Descubrir los puntos finales del


servidor API de Kubernetes

Problema

Quieres descubrir los distintos puntos finales de API disponibles en el


servidor de API de Kubernetes.

Solución

Aquí asumimos que has puesto en marcha localmente un clúster de


desarrollo como kind o Minikube. Puedes ejecutar kubectl proxy en un
terminal independiente. El proxy te permite acceder fácilmente a la API
del servidor Kubernetes con un cliente HTTP como curl, sin necesidad de
preocuparte por la autenticación y los certificados. Después de
ejecutar kubectl proxy, deberías poder acceder al servidor API en el
puerto 8001, como se muestra aquí:

$ curl http://localhost:8001/api/v1/
{
"kind": "APIResourceList",
"groupVersion": "v1",
"resources": [
{
"name": "bindings",
"singularName": "",
"namespaced": true,
"kind": "Binding",
"verbs": [
"create"
]
},
{
"name": "componentstatuses",
"singularName": "",
"namespaced": false,
...
Aquí se enumeran todos los objetos expuestos por la API de Kubernetes.
En la parte superior de la lista puedes ver un ejemplo de un objeto
con kind establecido en Binding, así como las operaciones permitidas en
este objeto (aquí, create).
Ten en cuenta que otra forma cómoda de descubrir los puntos finales de
la API es utilizar el comando kubectl api-resources.
Debate

Puedes descubrir todos los grupos de la API llamando a al siguiente punto


final:

$ curl http://localhost:8001/apis/
{
"kind": "APIGroupList",
"apiVersion": "v1",
"groups": [
{
"name": "apiregistration.k8s.io",
"versions": [
{
"groupVersion": "apiregistration.k8s.io/v1",
"version": "v1"
}
],
"preferredVersion": {
"groupVersion": "apiregistration.k8s.io/v1",
"version": "v1"
}
},
{
"name": "apps",
"versions": [
...
Elige algunos grupos de API para explorar de esta lista, como los
siguientes:

 /apis/apps
 /apis/storage.k8s.io
 /apis/flowcontrol.apiserver.k8s.io
 /apis/autoscaling
Cada uno de estos puntos finales corresponde a un grupo API. Los objetos
API básicos están disponibles en el grupo v1 en /api/v1, mientras que
otros objetos API más recientes están disponibles en grupos con nombre
bajo el punto final /apis/, como storage.k8s.io/v1 y apps/v1. Dentro
de un grupo, los objetos de la API tienen una versión (por
ejemplo, v1, v2, v1alpha, v1beta1) para indicar la madurez de los
objetos. Los pods, servicios, mapas de configuración y secretos, por
ejemplo, forman parte del grupo API /api/v1, mientras que el
grupo /apis/autoscaling tiene versiones v1 y v2.
El grupo del que forma parte un objeto es lo que se
denomina apiVersion en la especificación del objeto, disponible a través
de la referencia API.
Ver también

 Visión general de la API de Kubernetes


 Convenciones de la API de Kubernetes

7.2 Comprender la estructura de un


manifiesto de Kubernetes

Problema

Aunque Kubernetes dispone de prácticos generadores como kubectl


run y kubectl create, debes aprender a escribir manifiestos de
Kubernetes para adoptar la naturaleza declarativa de las especificaciones
de objetos de Kubernetes. Para ello, debes comprender la estructura
general de los manifiestos.
Solución

En la Receta 7.1, aprendiste sobre los distintos grupos de la API y cómo


descubrir en qué grupo está un objeto concreto.
Todos los recursos de la API son objetos o listas. Todos los recursos tienen
un kind y un apiVersion. Además, todo objeto kind debe
tener metadata. El metadata contiene el nombre del objeto, el espacio de
nombres en el que se encuentra (ver Receta 7.3) y, opcionalmente, algunas
etiquetas (ver Receta 7.6) y anotaciones (ver Receta 7.7).
Un pod, por ejemplo , será de kind Pod y apiVersion v1, y el comienzo
de un manifiesto sencillo escrito en YAML tendrá este aspecto:
apiVersion: v1
kind: Pod
metadata:
name: mypod
...
Para completar un manifiesto, la mayoría de los objetos tendrán
un spec y, una vez creados, devolverán también un status que
describe el estado actual del objeto:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
...
status:
...

Debate

Los manifiestos de Kubernetes pueden utilizarse para definir el estado


deseado de tu clúster. Como los manifiestos son archivos, pueden
almacenarse en un sistema de control de versiones como Git. Esto permite
la colaboración distribuida y asíncrona entre desarrolladores y
operadores, así como la creación de conductos de automatización para la
integración y la implementación continuas. Esta es la idea básica de
GitOps, en la que cualquier cambio en un sistema se realiza modificando
una fuente de verdad en un sistema de control de versiones. Como todos
los cambios se registran en el sistema, es posible volver a estados
anteriores o reproducir un estado determinado varias veces.
Infraestructura como código (IaC) es un término que se utiliza a menudo
cuando la fuente de verdad declarativa describe el estado de la
infraestructura (a diferencia de las aplicaciones).

Ver también

 Objetos en Kubernetes

7.3 Crear espacios de nombres para


evitar colisiones de nombres
Problema

Quieres crear dos objetos con el mismo nombre pero quieres evitar
colisiones de nombres.

Solución

Crea dos espacios de nombres y crea un objeto en cada uno.

Si no especificas nada, los objetos se crean en el espacio de


nombres default. Prueba a crear un segundo espacio de nombres
llamado my-app, como se muestra aquí, y haz una lista de los espacios de
nombres existentes. Verás el espacio de nombres default, otros espacios
de nombres que se crearon al iniciarse (kube-system, kube-public,
y kube-node-lease), y el espacio de nombres my-app que acabas de
crear:

$ kubectl create namespace my-app


namespace/my-app created

$ kubectl get ns
NAME STATUS AGE
default Active 5d20h
kube-node-lease Active 5d20h
kube-public Active 5d20h
kube-system Active 5d20h
my-app Active 13s
NOTA

Como alternativa, puedes escribir un manifiesto para crear tu espacio de


nombres. Si guardas el siguiente manifiesto como app.yaml, podrás crear el
espacio de nombres con el comando kubectl apply -f app.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: my-app

Debate

Intentar iniciar dos objetos con el mismo nombre en el mismo espacio de


nombres (por ejemplo, default) provoca una colisión, y el servidor de la
API de Kubernetes devuelve un error. Sin embargo, si inicias el segundo
objeto en un espacio de nombres diferente, el servidor de la API lo creará:

$ kubectl run foobar --image=nginx:latest


pod/foobar created

$ kubectl run foobar --image=nginx:latest


Error from server (AlreadyExists): pods "foobar" already
exists

$ kubectl run foobar --image=nginx:latest --namespace my-


app
pod/foobar created
NOTA

El espacio de nombres kube-system está reservado a los administradores,


mientras que el espacio de nombreskube-public está destinado a almacenar
objetos públicos disponibles para cualquier usuario del clúster.

7.4 Establecer cuotas dentro de un


espacio de nombres

Problema

Quieres limitar los recursos disponibles en un espacio de nombres; por


ejemplo, el número total de pods que pueden ejecutarse en el espacio de
nombres.

Solución

Utiliza un objeto ResourceQuota para especificar las limitaciones en


función del espacio de nombres.
Empieza por crear un manifiesto para una cuota de recursos y guárdalo
en un archivo llamado resource-quota-pods.yaml:

apiVersion: v1

kind: ResourceQuota
metadata:

name: podquota

spec:

hard:

pods: "10"

A continuación, crea un nuevo espacio de nombres y aplícale la cuota:

$ kubectl create namespace my-app


namespace/my-app created

$ kubectl apply -f resource-quota-pods.yaml --namespace=my-


app
resourcequota/podquota created

$ kubectl describe resourcequota podquota --namespace=my-


app
Name: podquota
Namespace: my-app
Resource Used Hard
-------- ---- ----
pods 1 10

Debate

Puedes establecer una serie de cuotas por espacio de nombres,


incluyendo, entre otros, pods, secretos y mapas de configuración.

Ver también

 Configurar cuotas para objetos API

7.5 Etiquetar un objeto

Problema
Quieres etiquetar un objeto para poder encontrarlo fácilmente más
adelante. La etiqueta puede utilizarse para posteriores consultas del
usuario final (ver Receta 7.6) o en el contexto de la automatización del
sistema.
Solución

Utiliza el comando kubectl label. Por ejemplo, para etiquetar un pod


llamado foobar con el par clave/valor tier=frontend, haz lo siguiente:

$ kubectl label pods foobar tier=frontend


pod/foobar labeled
CONSEJO

Consulta la ayuda completa del comando (kubectl label --help). Puedes


utilizarla para saber cómo eliminar etiquetas, sobrescribir las existentes e
incluso etiquetar todos los recursos de un espacio de nombres.

Debate

En Kubernetes se utilizan etiquetas para organizar objetos de forma


flexible y no jerárquica. Una etiqueta es un par clave/valor sin significado
predefinido para Kubernetes. En otras palabras, el contenido del par
clave/valor no es interpretado por el sistema. Puedes utilizar etiquetas
para expresar pertenencia (por ejemplo, el objeto X pertenece al
departamento ABC), entornos (por ejemplo, este servicio se ejecuta en
producción), o realmente cualquier cosa que necesites para organizar tus
objetos. Hay algunas etiquetas útiles comunes sobre las que puedes leer
en la documentación de Kubernetes. Ten en cuenta que las etiquetas
tienen restricciones en cuanto a su longitud y valores permitidos. Sin
embargo, existe una directriz de la comunidad para nombrar las claves.

7.6 Utilizar etiquetas para las consultas

Problema

Quieres consultar objetos de forma eficaz.

Solución
Utiliza el comando kubectl get --selector. Por ejemplo, dados los
siguientes pods:

$ kubectl get pods --show-labels


NAME READY STATUS RESTARTS AGE
LABELS
foobar 1/1 Running 0 18m
run=foobar,tier=frontend
nginx1 1/1 Running 0 72s
app=nginx,run=nginx1
nginx2 1/1 Running 0 68s
app=nginx,run=nginx2
nginx3 1/1 Running 0 65s
app=nginx,run=nginx3

puedes seleccionar los pods que pertenecen a la aplicación NGINX


(app=nginx):

$ kubectl get pods --selector app=nginx


NAME READY STATUS RESTARTS AGE
nginx1 1/1 Running 0 3m45s
nginx2 1/1 Running 0 3m41s
nginx3 1/1 Running 0 3m38s
Debate

Las etiquetas forman parte de los metadatos de un objeto. Cualquier


objeto de Kubernetes puede ser etiquetado. Las etiquetas también son
utilizadas por el propio Kubernetes para la selección de pods por
implementaciones (ver Receta 4.1) y servicios (ver Capítulo 5).
Las etiquetas pueden añadirse manualmente con el comando kubectl
label (ver Receta 7.5), o puedes definir etiquetas en un manifiesto de
objeto, como se hace a continuación:
apiVersion: v1
kind: Pod
metadata:
name: foobar
labels:
tier: frontend
...
Una vez que las etiquetas estén presentes, puedes enumerarlas
con kubectl get, observando lo siguiente :
 -l es la forma abreviada de --selector y consultará los objetos
con un valor especificado key=value par.
 --show-labels mostrará todas las etiquetas de cada objeto
devuelto.
 -L añadirá una columna a los resultados devueltos con el valor
de la etiqueta especificada.
 Muchos tipos de objetos admiten consultas basadas en
conjuntos, lo que significa que puedes hacer una consulta del
tipo "debe estar etiquetado con X y/o Y". Por ejemplo, kubectl
get pods -l 'env in (production, development)' te daría los
pods que están en el entorno de producción o en el de
desarrollo.
Con dos pods en funcionamiento, uno con la etiqueta run=barfoo y el
otro con la etiqueta run=foobar, obtendrías salidas similares a las
siguientes:

$ kubectl get pods --show-labels


NAME READY ... LABELS
barfoo-76081199-h3gwx 1/1 ... pod-template-
hash=76081199,run=barfoo
foobar-1123019601-6x9w1 1/1 ... pod-template-
hash=1123019601,run=foobar

$ kubectl get pods -L run


NAME READY ... RUN
barfoo-76081199-h3gwx 1/1 ... barfoo
foobar-1123019601-6x9w1 1/1 ... foobar

$ kubectl get pods -l run=foobar


NAME READY ...
foobar-1123019601-6x9w1 1/1 ...
Ver también

 Documentación de Kubernetes sobre etiquetas y selectores

7.7 Anotar un recurso con un comando

Problema

Quieres anotar un recurso con un par clave/valor genérico, no


identificable,posiblemente utilizando datos no legibles por el ser humano.
Solución

Utiliza el comando kubectl annotate:

$ kubectl annotate pods foobar \


description='something that you can use for automation'
pod/foobar annotated
Debate

Las anotaciones suelen utilizarse para añadir automatización a


Kubernetes. Por ejemplo, cuando creas una implementación con el
comando kubectl create deployment, observarás que la
columna change-cause de tu historial de implementaciones (véase la
Receta 4.6) está vacía. A partir de Kubernetes v1.6.0, para empezar a
registrar los comandos que provocan cambios en la implementación,
puedes anotarla con la clave kubernetes.io/change-cause. Dada una
implementación foobar, podrías anotarla con lo siguiente:

$ kubectl annotate deployment foobar \


kubernetes.io/change-cause="Reason for creating a new
revision"
Se registrarán los cambios posteriores en la implementación.

Una de las principales diferencias entre anotaciones y etiquetas es que las


etiquetas pueden utilizarse como criterios de filtrado, mientras que las
anotaciones no. A menos que pienses utilizar tus metadatos para filtrar,
en general es preferible utilizar anotaciones.
Capítulo 8. Volúmenes y datos de
configuración
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

Un volumen en Kubernetes es un directorio accesible a todos los


contenedores que se ejecutan en un pod, con la garantía adicional de que
los datos se conservan en los reinicios de los contenedores individuales.
Podemos distinguir algunos tipos de volúmenes:

 Volúmenes efímeroslocales de nodo, como emptyDir


 Volúmenes genéricos en red, como nfs o cephfs
 Volúmenesespecíficos del proveedor de la nube, como AWS
EBS o AWS EFS
 Volúmenespara fines especiales, como secret o configMap
El tipo de volumen que elijas depende totalmente de tu caso de uso. Por
ejemplo, para un espacio scratch temporal, un emptyDir estaría bien, pero
cuando necesites asegurarte de que tus datos sobreviven a fallos de
nodos, querrás buscar alternativas más resistentes o soluciones
específicas para proveedores de la nube.

8.1 Intercambio de datos entre


contenedores a través de unvolumen
local
Problema

Tienes dos o más contenedores ejecutándose en un pod y quieres poder


intercambiar datos mediante operaciones del sistema de archivos.

Solución

Utiliza un volumen local del tipo emptyDir.


El punto de partida de es el siguiente manifiesto de
pod, exchangedata.yaml, que tiene dos contenedores (c1 y c2) que
montan cada uno el volumen local xchange en su sistema de archivos,
utilizando diferentes puntos de montaje:
apiVersion: v1
kind: Pod
metadata:
name: sharevol
spec:
containers:
- name: c1
image: ubuntu:20.04
command:
- "bin/bash"
- "-c"
- "sleep 10000"
volumeMounts:
- name: xchange
mountPath: "/tmp/xchange"
- name: c2
image: ubuntu:20.04
command:
- "bin/bash"
- "-c"
- "sleep 10000"
volumeMounts:
- name: xchange
mountPath: "/tmp/data"
volumes:
- name: xchange
emptyDir: {}
Ahora puedes lanzar el pod, exec en él, crear datos desde un contenedor, y
leerlos desde el otro:

$ kubectl apply -f exchangedata.yaml


pod/sharevol created

$ kubectl exec sharevol -c c1 -i -t -- bash


[root@sharevol /]# mount | grep xchange
/dev/vda1 on /tmp/xchange type ext4 (rw,relatime)
[root@sharevol /]# echo 'some data' > /tmp/xchange/data
[root@sharevol /]# exit

$ kubectl exec sharevol -c c2 -i -t -- bash


[root@sharevol /]# mount | grep /tmp/data
/dev/vda1 on /tmp/data type ext4 (rw,relatime)
[root@sharevol /]# cat /tmp/data/data
some data
[root@sharevol /]# exit
Debate

Un volumen local está respaldado por el nodo en el que se ejecutan el pod


y sus contenedores. Si el nodo se cae o tienes que realizar tareas de
mantenimiento en él (ver Receta 12.9), el volumen local desaparece y se
pierden todos los datos.
Hay algunos casos de uso en los que los volúmenes locales están bien -por
ejemplo, para algún espacio de scratch o cuando el estado canónico se
obtiene de algún otro lugar, como un bucket de S3-, pero en general
querrás utilizar un volumen persistente o uno respaldado por
almacenamiento en red (consulta la Receta 8.4).
Ver también

 Documentación de Kubernetes sobre volúmenes

8.2 Pasar una Clave de Acceso a la API a


un Pod utilizando un Secreto

Problema

Como administrador, quieres proporcionar a tus desarrolladores una


clave de acceso a la API de forma segura; es decir, sin compartirla en texto
claro en tus manifiestos de Kubernetes.

Solución

Utiliza un volumen local de tipo secret.


Supongamos que quieres dar acceso a tus desarrolladores a un servicio
externo accesible mediante la frase de contraseña open sesame.
Primero, crea un archivo de texto llamado frase de contraseña que
contenga la frase de contraseña:

$ echo -n "open sesame" > ./passphrase


A continuación, crea el secreto, utilizando el archivo de frase de
contraseña:

$ kubectl create secret generic pp --from-file=./passphrase


secret/pp created

$ kubectl describe secrets/pp


Name: pp
Namespace: default
Labels: <none>
Annotations: <none>

Type: Opaque

Data
====
passphrase: 11 bytes
Desde el punto de vista del administrador, ya lo tienes todo listo, y es hora
de que tus desarrolladores consuman el secreto. Así que cambiemos de
sombrero y supongamos que eres un desarrollador y quieres utilizar la
frase de contraseña desde dentro de un pod.

Consumirías el secreto, por ejemplo, montándolo como un volumen en tu


pod y leyéndolo después como un archivo normal. Crea y guarda el
siguiente manifiesto, llamado ppconsumer.yaml:
apiVersion: v1
kind: Pod
metadata:
name: ppconsumer
spec:
containers:
- name: shell
image: busybox:1.36
command:
- "sh"
- "-c"
- "mount | grep access && sleep 3600"
volumeMounts:
- name: passphrase
mountPath: "/tmp/access"
readOnly: true
volumes:
- name: passphrase
secret:
secretName: pp
Ahora lanza el pod y echa un vistazo a sus registros, donde esperarías ver
el archivo secreto ppconsumer montado como /tmp/access/passphrase:

$ kubectl apply -f ppconsumer.yaml


pod/ppconsumer created

$ kubectl logs ppconsumer


tmpfs on /tmp/access type tmpfs
(ro,relatime,size=7937656k)
Para acceder a la frase de contraseña desde dentro del contenedor en
ejecución, basta con leer el archivo de la frase de
contraseña en /tmp/access, así
$ kubectl exec ppconsumer -i -t -- sh

/ # cat /tmp/access/passphrase
open sesame
/ # exit
Debate

Los secretos existen en el contexto de un espacio de nombres, por lo que


debes tenerlo en cuenta al configurarlos y/o consumirlos.

Puedes acceder a un secreto desde un contenedor que se ejecuta en un


pod mediante una de las siguientes opciones:

 Un volumen (como se muestra en la Solución, donde el


contenido se almacena en un volumen tmpfs )
 Utilizar el secreto como variable de entorno
Además, ten en cuenta que el tamaño de un secreto está limitado a 1 MiB.

CONSEJO

kubectl create secret trata tres tipos de secretos, y dependiendo de tu caso


de uso, puede que quieras elegir diferentes :
 El tipo docker-registry es para utilizarlo con unregistro Docker.
 El tipo generic es el que utilizamos en la Solución; crea un secreto a
partir de un archivo local, directorio o valor literal (tienes que
codificarlo tú mismo en base64).
 Con tls puedes crear, por ejemplo, uncertificado SSL seguro para la
entrada.

kubectl describe no muestra el contenido del secreto en texto plano. Esto


evita los robos de contraseñas "por encima del hombro". Sin embargo,
puedes descifrarla fácilmente de forma manual, ya que no está
encriptada, sólo codificada en base64:

$ kubectl get secret pp -o yaml | \


grep passphrase | \
cut -d":" -f 2 | \
awk '{$1=$1};1' | \
base64 --decode
open sesame
En este comando, la primera línea recupera una representación YAML del
secreto, y la segunda línea con el grep extrae la línea passphrase:
b3BlbiBzZXNhbWU= (fíjate en el espacio en blanco inicial aquí). A
continuación, el comando cut extrae el contenido de la frase de
contraseña, y el comando awk se deshace del espacio en blanco inicial. Por
último, el comando base64 lo convierte de nuevo en los datos originales.
CONSEJO

Tienes la opción de cifrar los secretos en reposo utilizando la opción --


encryption-provider-config al iniciar el programa kube-apiserver.

Ver también

 Documentación de Kubernetes sobre secretos


 Documentación de Kubernetes sobre el cifrado de datos
confidenciales en reposo

8.3 Proporcionar datos de


configuración a una aplicación

Problema

Quieres proporcionar datos de configuración a una aplicación sin


almacenarlos en la imagen del contenedor ni codificarlos en la
especificación del pod.

Solución

Utiliza un mapa de configuración. Son recursos de Kubernetes de primera


clase con los que puedes proporcionar datos de configuración a un pod
mediante variables de entorno o un archivo.

Supongamos que quieres crear una configuración con la


clave siseversion y el valor 0.9. Es tan sencillo como esto

$ kubectl create configmap nginxconfig \


--from-literal=nginxgreeting="hello from nginx"
configmap/nginxconfig created
Ahora puedes utilizar el mapa de configuración en una implementación,
por ejemplo, en un archivo de manifiesto con el siguiente contenido:

apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.25.2
env:
- name: NGINX_GREETING
valueFrom:
configMapKeyRef:
name: nginxconfig
key: nginxgreeting
Guarda este manifiesto YAML como nginxpod.yaml y luego
utiliza kubectl para crear el pod:

$ kubectl apply -f nginxpod.yaml


pod/nginx created
A continuación, puedes listar las variables de entorno del contenedor del
pod con el siguientecomando:

$ kubectl exec nginx -- printenv


PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/
sbin:/bin
HOSTNAME=nginx
NGINX_GREETING=hello from nginx
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
...
Debate

Acabamos de mostrar cómo pasar la configuración como una variable de


entorno. Sin embargo, también puedes montarla en el pod como un
archivo, utilizando un volumen.

Supón que tienes el siguiente archivo de configuración, ejemplo.cfg:


debug: true
home: ~/abc
Puedes crear un mapa de configuración que contenga el archivo de
configuración, como se indica a continuación:
$ kubectl create configmap configfile --from-
file=example.cfg
configmap/configfile created
Ahora puedes utilizar el mapa de configuración como lo harías con
cualquier otro volumen. A continuación se muestra el archivo de
manifiesto de un pod llamado oreilly; utiliza la imagen busybox y sólo
duerme durante 3.600 segundos. En la sección volumes, hay un volumen
llamado oreilly que utiliza el mapa de configuración configfile que
acabamos de crear. Este volumen se monta en la ruta /oreilly dentro del
contenedor. Por lo tanto, el archivo será accesible dentro del pod:
apiVersion: v1
kind: Pod
metadata:
name: oreilly
spec:
containers:
- image: busybox:1.36
command:
- sleep
- "3600"
volumeMounts:
- mountPath: /oreilly
name: oreilly
name: busybox
volumes:
- name: oreilly
configMap:
name: configfile
Después de crear el pod, puedes comprobar que el
archivo example.cfg está efectivamente dentro de él:

$ kubectl exec -ti oreilly -- ls -l oreilly


total 0
lrwxrwxrwx 1 root root 18 Mar 31 09:39 example.cfg -
> ..data/example.cfg

$ kubectl exec -ti oreilly -- cat oreilly/example.cfg


debug: true
home: ~/abc
Para ver un ejemplo completo de cómo crear un mapa de configuración a
partir de un archivo, consulta la Receta 11.7.
Ver también

 "Configurar un Pod para utilizar un ConfigMap" en la


documentación de Kubernetes
8.4 Utilizar un Volumen Persistente con
Minikube

Problema

No quieres perder datos en un disco que utilice tu contenedor, es decir,


quieres asegurarte de que sobrevive a un reinicio del pod de alojamiento.

Solución

Utiliza un volumen persistente (VP). En el caso de Minikube, puedes crear


un VP de tipo hostPath y montarlo como un volumen normal en el sistema
de archivos del contenedor.
Primero, define el PV hostpathpv en un manifiesto llamado hostpath-
pv.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
name: hostpathpv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/pvdata"
Sin embargo, antes de que puedas crear el PV, tienes que preparar el
directorio /tmp/pvdata en el nodo, es decir, en la propia instancia de
Minikube. Puedes entrar en el nodo donde se ejecuta el clúster de
Kubernetes utilizando minikube ssh:

$ minikube ssh

$ mkdir /tmp/pvdata && \


echo 'I am content served from a delicious persistent
volume' > \
/tmp/pvdata/index.html

$ cat /tmp/pvdata/index.html
I am content served from a delicious persistent volume

$ exit
Ahora que has preparado el directorio en el nodo, puedes crear el PV a
partir del archivo de manifiesto hostpath-pv.yaml:

$ kubectl apply -f hostpath-pv.yaml


persistentvolume/hostpathpv created

$ kubectl get pv
NAME CAPACITY ACCESSMODES RECLAIMPOLICY
STATUS ... ... ...
hostpathpv 1Gi RWO Retain
Available ... ... ...

$ kubectl describe pv/hostpathpv


Name: hostpathpv
Labels: type=local
Annotations: <none>
Finalizers: [kubernetes.io/pv-protection]
StorageClass: manual
Status: Available
Claim:
Reclaim Policy: Retain
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 1Gi
Node Affinity: <none>
Message:
Source:
Type: HostPath (bare host directory volume)
Path: /tmp/pvdata
HostPathType:
Events: <none>
Hasta este punto, realizarías estos pasos en un rol de administrador.
Definirías los PV y los pondrías a disposición de los desarrolladores en el
clúster Kubernetes.

Ahora estás en condiciones de utilizar el VP en un pod, desde la


perspectiva de un desarrollador. Esto se hace mediante una reclamación
de volumen persistente (PVC), llamada así porque, bueno, literalmente
reclamas un PV que cumpla determinadas características, como el tamaño
o la clase de almacenamiento.
Crea un archivo de manifiesto llamado pvc.yaml que defina un PVC,
pidiendo a 200 MB de espacio:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Mi
A continuación, lanza el PVC y verifica su estado:

$ kubectl apply -f pvc.yaml


persistentvolumeclaim/mypvc created

$ kubectl get pv
NAME CAPACITY ACCESSMODES ... STATUS CLAIM
STORAGECLASS
hostpathpv 1Gi RWO ... Bound
default/mypvc manual
Observa que el estado del PV hostpathpv ha cambiado de Available a Bound.
Por último, es hora de consumir los datos de la PV en un contenedor, esta
vez mediante una implementación que los monte en el sistema de
archivos. Para ello, crea un archivo llamado nginx-using-pv.yaml con el
siguiente contenido:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-with-pv
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: webserver
image: nginx:1.25.2
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: webservercontent
volumes:
- name: webservercontent
persistentVolumeClaim:
claimName: mypvc
Y lanza la implementación, así:

$ kubectl apply -f nginx-using-pv.yaml


deployment.apps/nginx-with-pv created

$ kubectl get pvc


NAME STATUS VOLUME CAPACITY ACCESSMODES
STORAGECLASS AGE
mypvc Bound hostpathpv 1Gi RWO manual
12m
Como puedes ver, el PV está en uso a través del PVC que creaste
anteriormente.

Para comprobar que los datos han llegado realmente, ahora podrías crear
un servicio (ver Receta 5.1) junto con un objeto Ingress (ver Receta 5.5) y
luego acceder a él de esta forma:

$ curl -k -s https://192.168.99.100/web
I am content served from a delicious persistent volume
¡Bien hecho! Has (como administrador) aprovisionado un volumen
persistente y (como desarrollador) lo has reclamado mediante una
reclamación de volumen persistente y lo has utilizado desde una
implementación en un pod montándolo en el sistema de archivos del
contenedor.

Debate

En la Solución, utilizamos un volumen persistente del tipo hostPath. En un


entorno de producción, no deberías utilizar esto, sino pedir amablemente
al administrador de tu clúster que aprovisione un volumen en red
respaldado por NFS o un volumen de Amazon Elastic Block Store (EBS)
para asegurarte de que tus datos permanecen y sobreviven a los fallos de
un único nodo.
NOTA

Recuerda que los PV son recursos de todo el clúster; es decir, no están espaciados
por nombres. Sin embargo, los PVC tienen espacio de nombres. Puedes reclamar
FV de espacios de nombres específicos utilizando PVC con espacio de nombres.
Ver también

 Documentación sobre volúmenes persistentes de Kubernetes


 "Configurar un Pod para utilizar un PersistentVolume como
almacenamiento" en la documentación de Kubernetes

8.5 Comprender la persistencia de


datos en Minikube

Problema

Quieres utilizar Minikube para desplegar una aplicación con estado en


Kubernetes. En concreto, quieres implementar una base de datos MySQL.

Solución

Utiliza un objeto PersistentVolumeClaim (ver Receta 8.4) en la definición de


tu pod y/o en la plantilla de tu base de datos.
Primero tienes que solicitar una cantidad concreta de almacenamiento. El
siguiente manifiesto data.yaml solicita 1 GB de almacenamiento:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
En Minikube, crea este PVC e inmediatamente verás cómo se crea un
volumen persistente para que coincida con esta afirmación:

$ kubectl apply -f data.yaml


persistentvolumeclaim/data created

$ kubectl get pvc


NAME STATUS VOLUME
CAPACITY ... ... ...
data Bound pvc-da58c85c-e29a-11e7-ac0b-080027fcc0e7
1Gi ... ... ...
$ kubectl get pv
NAME
CAPACITY ... ... ... ... ...
pvc-da58c85c-e29a-11e7-ac0b-080027fcc0e7
1Gi ... ... ... ... ...
Ya estás listo para utilizar esta demanda en tu pod. En la
sección volumes del manifiesto del pod, define un volumen por nombre
con un tipo de PVC y una referencia al PVC que acabas de crear.
En el campo volumeMounts, montarás este volumen en una ruta específica
dentro de tu contenedor. Para MySQL, lo montarás en /var/lib/mysql:
apiVersion: v1
kind: Pod
metadata:
name: db
spec:
containers:
- image: mysql:8.1.0
name: db
volumeMounts:
- mountPath: /var/lib/mysql
name: data
env:
- name: MYSQL_ROOT_PASSWORD
value: root
volumes:
- name: data
persistentVolumeClaim:
claimName: data

Debate

Minikube está configurado de fábrica con una clase de almacenamiento


predeterminada que define un aprovisionador de volumen persistente
predeterminado. Esto significa que cuando se crea una demanda de
volumen persistente, Kubernetes creará dinámicamente un volumen
persistente correspondiente para llenar esa demanda.

Esto es lo que ocurrió en la Solución. Cuando creaste la reclamación de


volumen persistente llamada data, Kubernetes creó automáticamente un
volumen persistente para que coincidiera con esa reclamación. Si te fijas
un poco más en la clase de almacenamiento por defecto en Minikube,
verás el tipo de aprovisionador:

$ kubectl get storageclass


NAME PROVISIONER ...
standard (default) k8s.io/minikube-hostpath ...
$ kubectl get storageclass standard -o yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
...
provisioner: k8s.io/minikube-hostpath
reclaimPolicy: Delete
Esta clase de almacenamiento específica está utilizando un
aprovisionador de almacenamiento que crea volúmenes persistentes del
tipo hostPath. Puedes comprobarlo mirando el manifiesto del VP que se ha
creado para que coincida con la demanda que creaste anteriormente:

$ kubectl get pv
NAME CAPACITY ...
CLAIM ...
pvc-da58c85c-e29a-11e7-ac0b-080027fcc0e7 1Gi ...
default/data ...

$ kubectl get pv pvc-da58c85c-e29a-11e7-ac0b-080027fcc0e7 -


o yaml
apiVersion: v1
kind: PersistentVolume
...
hostPath:
path: /tmp/hostpath-provisioner/default/data
type: ""
...
Para verificar que el volumen anfitrión creado contiene la base de
datos data, puedes conectarte a Minikube y listar los archivos del
directorio:

$ minikube ssh

$ ls -l /tmp/hostpath-provisioner/default/data
total 99688
...
drwxr-x--- 2 999 docker 4096 Mar 31 11:11 mysql
-rw-r----- 1 999 docker 31457280 Mar 31 11:11 mysql.ibd
lrwxrwxrwx 1 999 docker 27 Mar 31 11:11 mysql.sock
-> /var/run/mysqld/...
drwxr-x--- 2 999 docker 4096 Mar 31 11:11
performance_schema
-rw------- 1 999 docker 1680 Mar 31 11:11
private_key.pem
-rw-r--r-- 1 999 docker 452 Mar 31 11:11
public_key.pem
...
Efectivamente, ahora tienes persistencia de datos. Si el pod muere (o lo
borras), tus datos seguirán estando disponibles.

En general, las clases de almacenamiento permiten al administrador del


clúster definir los distintos tipos de almacenamiento que puede
proporcionar. Para los desarrolladores, esto abstrae el tipo de
almacenamiento y les permite utilizar PVCs sin tener que preocuparse del
propio proveedor de almacenamiento.

Ver también

 Documentación de reclamación de volumen persistente de


Kubernetes
 Documentación de la clase de almacenamiento de Kubernetes

8.6 Almacenar secretos encriptados en


el control de versiones

Problema

Quieres almacenar todos tus manifiestos de Kubernetes en el control de


versiones y compartirlos de forma segura (incluso públicamente),
incluidos los secretos.

Solución

Utiliza sealed-secrets. Sealed-secrets es un controlador de Kubernetes que


descifra secretos encriptados unidireccionales y crea
objetos Secret dentro del clúster (consulta la Receta 8.2).
Para empezar, instala la versión v0.23.1 del controlador de secretos
sellados desde la página de la versión:

$ kubectl apply -f https://github.com/bitnami-labs/sealed-


secrets/
releases/download/v0.23.1/controller.yaml
El resultado será que tendrás un nuevo recurso personalizado y un nuevo
pod ejecutándose en el espacio de nombres kube-system:

$ kubectl get customresourcedefinitions


NAME CREATED AT
sealedsecrets.bitnami.com 2023-01-18T09:23:33Z

$ kubectl get pods -n kube-system -l name=sealed-secrets-


controller
NAME READY
STATUS RESTARTS AGE
sealed-secrets-controller-7ff6f47d47-dd76s 1/1
Running 0 2m22s
A continuación, descarga la versión correspondiente del
binario kubeseal de la página de versiones. Esta herramienta te permitirá
encriptar tus secretos.
Por ejemplo, en macOS (amd64), haz lo siguiente:

$ wget
https://github.com/bitnami-labs/sealed-secrets/releases/dow
nload/
v0.23.1/kubeseal-0.23.1-darwin-amd64.tar.gz

$ tar xf kubeseal-0.23.1-darwin-amd64.tar.gz

$ sudo install -m 755 kubeseal /usr/local/bin/kubeseal

$ kubeseal --version
kubeseal version: 0.23.1
Ya estás preparado para empezar a utilizar secretos sellados. Primero,
genera un manifiesto secreto genérico:

$ kubectl create secret generic oreilly --from-


literal=password=root -o json \
--dry-run=client > secret.json

$ cat secret.json
{
"kind": "Secret",
"apiVersion": "v1",
"metadata": {
"name": "oreilly",
"creationTimestamp": null
},
"data": {
"password": "cm9vdA=="
}
}
A continuación, utiliza el comando kubeseal para generar el nuevo objeto
personalizado SealedSecret:

$ kubeseal < secret.json > sealedsecret.json

$ cat sealedsecret.json
{
"kind": "SealedSecret",
"apiVersion": "bitnami.com/v1alpha1",
"metadata": {
"name": "oreilly",
"namespace": "default",
"creationTimestamp": null
},
"spec": {
"template": {
"metadata": {
"name": "oreilly",
"namespace": "default",
"creationTimestamp": null
}
},
"encryptedData": {
"password":
"AgCyN4kBwl/eLt7aaaCDDNlFDp5s93QaQZZ/mm5BJ6SK1WoKyZ45hz...
"
}
}
}
Crea el objeto SealedSecret utilizando el siguiente :

$ kubectl apply -f sealedsecret.json


sealedsecret.bitnami.com/oreilly created
Ahora puedes almacenar sealedsecret.json de forma segura en el control
de versiones.
Debate

Una vez creado el objeto SealedSecret, el controlador lo detectará, lo


desencriptará y generará el secreto correspondiente.
Tu información sensible se encripta en un objeto SealedSecret, que es un
recurso personalizado (ver Receta 15.4). El SealedSecret es seguro para
almacenarlo bajo control de versiones y compartirlo, incluso
públicamente. Una vez creado un SealedSecret en el servidor de la API de
Kubernetes, sólo la clave privada almacenada en el controlador sellado-
secreto puede descifrarlo y crear el objeto Secret correspondiente (que
sólo está codificado en base64). Nadie más, incluido el autor original,
puede descifrar el Secret original del SealedSecret.
Aunque los usuarios no pueden descifrar el Secret original
del SealedSecret, sí pueden acceder al Secret no sellado del clúster. Debes
configurar RBAC para prohibir a los usuarios con pocos privilegios que
lean objetos Secret de espacios de nombres a los que tengan acceso
restringido.
Puedes hacer una lista de los objetos SealedSecret del espacio de nombres
actual utilizando lo siguiente:

$ kubectl get sealedsecret


NAME AGE
oreilly 14s
Ver también

 El proyecto sealed-secrets en GitHub


 El artículo de Angus Lees "Secretos sellados: Cómo proteger tus
contraseñas antes de que lleguen a Kubernetes"
Capítulo 9. Escalando
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En Kubernetes, escalar puede significar cosas distintas para usuarios


distintos. Distinguimos dos casos:

Escalado de clústeres
A veces denominada elasticidad del clúster, se refiere al proceso
(automatizado) de añadir o eliminar nodos trabajadores en función
de la utilización del clúster.
Escalado a nivel de aplicación
A veces llamado escalado de pods, se refiere al proceso
(automatizado) de manipular las características de los pods
basándose en una serie de métricas, desde señales de bajo nivel,
como la utilización de la CPU, hasta otras de más alto nivel, como
las solicitudes HTTP servidas por segundo, para un pod
determinado.
Existen dos tipos de escaladores a nivel de vaina:

Autoescaladores horizontales (HPA)


Las HPA aumentan o disminuyen automáticamente el número de
réplicas de pods en función de determinadas métricas.

Autoescaladores verticales (VPA)


Los AVA aumentan o disminuyen automáticamente los requisitos
de recursos de los contenedores que se ejecutan en un pod.

En este capítulo, primero examinamos la elasticidad de los clústeres para


GKE, AKS y EKS y luego hablamos del escalado de vainas con HPA.

9.1 Escalar una Implementación

Problema

Tienes una implementación y quieres escalarla horizontalmente.

Solución
Utiliza el comando kubectl scale para ampliar una implementación.
Vamos a reutilizar la implementación fancyapp de la Receta 4.5, con cinco
réplicas. Si aún no se está ejecutando, créalo con kubectl apply -f
fancyapp.yaml.
Supón ahora que la carga ha disminuido y ya no necesitas cinco réplicas;
con tres es suficiente. Para reducir la implementación a tres réplicas, haz
lo siguiente:

$ kubectl get deploy fancyapp


NAME READY UP-TO-DATE AVAILABLE AGE
fancyapp 5/5 5 5 59s

$ kubectl scale deployment fancyapp --replicas=3


deployment "fancyapp" scaled

$ kubectl get deploy fancyapp


NAME READY UP-TO-DATE AVAILABLE AGE
fancyapp 3/3 3 3 81s
En lugar de escalar manualmente una implementación, puedes
automatizar este proceso; consulta la Receta 9.2 para ver un ejemplo.

9.2 Utilizar el Autoescalado Horizontal


de Pods

Problema

Quieres aumentar o disminuir automáticamente el número de pods de


una implementación, en función de la carga presente.

Solución

Utiliza un HPA, como se describe aquí.

Para utilizar las HPA, debe estar disponible la API de Métricas de


Kubernetes. Para instalar el Servidor de Métricas de Kubernetes,
consulta la Receta 2.7.
En primer lugar, crea en una aplicación -un entorno y un servidor PHP-
que puedas utilizar como objetivo de la HPA:
$ kubectl create deployment appserver --
image=registry.k8s.io/hpa-example \
--port 80
deployment.apps/appserver created
$ kubectl expose deployment appserver --port=80 --target-
port=80
$ kubectl set resources deployment appserver -c=hpa-example
--requests=cpu=200m
A continuación, crea una HPA y define el parámetro de activación --cpu-
percent=40, que significa que la utilización de la CPU no debe superar el
40%:

$ kubectl autoscale deployment appserver --cpu-percent=40


--min=1 --max=5
horizontalpodautoscaler.autoscaling/appserver autoscaled

$ kubectl get hpa --watch


NAME REFERENCE TARGETS MINPODS
MAXPODS REPLICAS AGE
appserver Deployment/appserver 1%/40% 1 5
1 2m29s
En una segunda sesión de terminal, vigila la implementación:

$ kubectl get deploy appserver --watch


Por último, en una tercera sesión del terminal , lanza el generador de
carga:

$ kubectl run -i -t loadgen --rm --image=busybox:1.36 --


restart=Never -- \
/bin/sh -c "while sleep 0.01; do wget -q -O-
http://appserver; done"
Como hay tres sesiones de terminal implicadas en paralelo, en la Figura 9-
1 se ofrece una visión general de toda la situación.
Figura 9-1. Sesiones de terminal para configurar una HPA

En la Figura 9-2, que muestra el panel de control de Kubernetes, puedes


ver el efecto de la HPA en la implementación de appserver.
Figura 9-2. Panel de control de Kubernetes, mostrando el efecto de un HPA

Ver también

 Autoescalado de Kubernetes basado en eventos


 El recorrido HPA en la documentación de Kubernetes

9.3 Redimensionar automáticamente


un cluster en GKE

Problema

Quieres que el número de nodos de tu clúster GKE aumente o disminuya


automáticamente, en función de la utilización.

Solución

Utiliza el GKE Cluster Autoscaler. Esta receta asume que tienes el


comando gcloud instalado y el entorno configurado (es decir, que has
creado un proyecto y activado la facturación).
Crea un clúster con un nodo trabajador y el autoescalado de clúster
activado:
$ gcloud container clusters create supersizeme --zone=us-
west1-a \
--machine-type=e2-small --num-nodes=1 \
--min-nodes=1 --max-nodes=3 --enable-autoscaling
Creating cluster supersizeme in us-west1-a... Cluster is
being health-checked
(master is healthy)...done.
Created [https://container.googleapis.com/v1/projects/k8s-
cookbook/zones/
us-west1-a/clusters/supersizeme].
To inspect the contents of your cluster, go to:
https://console.cloud.google.com/
kubernetes/workload_/gcloud/us-west1-a/supersizeme?
project=k8s-cookbook
kubeconfig entry generated for supersizeme.
NAME LOCATION ... MACHINE_TYPE NODE_VERSION
NUM_NODES STATUS
supersizeme us-west1-a ... e2-small 1.26.5-
gke.1200 1 RUNNING
En este momento, al mirar la consola de Google Cloud, deberías ver algo
parecido a lo que se muestra en la Figura 9-3.

Figura 9-3. Consola de Google Cloud, mostrando el tamaño inicial del clúster de un nodo
Ahora, lanza tres pods utilizando una implementación y solicita recursos
de clúster a para activar el autoescalado del clúster:

$ kubectl create deployment gogs --image=gogs/gogs:0.13 --


replicas=3
$ kubectl set resources deployment gogs -c=gogs --
requests=cpu=200m,memory=256Mi
Al cabo de un tiempo, la implementación se actualizará:

$ kubectl get deployment gogs


NAME READY UP-TO-DATE AVAILABLE AGE
gogs 3/3 3 3 2m27s
Ahora deberías tener un clúster de dos nodos, como se muestra en
la Figura 9-4.

Figura 9-4. Consola de Google Cloud, mostrando el clúster resultante escalado a dos nodos
Debate

El autoescalado de clústeres puede activarse o actualizarse en un clúster


GKE después de haberlo creado:

$ gcloud container clusters update supersizeme --zone=us-


west1-a \
--min-nodes=1 --max-nodes=3 --enable-autoscaling
La elección del tipo de máquina utilizada en los nodos del cluster es un
factor importante a tener en cuenta y depende de los recursos necesarios
para ejecutar tus cargas de trabajo. Si tus cargas de trabajo exigen más
recursos, entonces debes considerar el uso de un tipo de máquina mayor.
A diferencia del escalado de pods, el escalado de clústeres añade
dinámicamente recursos a tu clúster, lo que podría aumentar
significativamente tu factura en la nube. Asegúrate de configurar
adecuadamente el número máximo de nodos de tu clúster GKE para
evitar superar tu límite de gasto.

Cuando ya no necesites el clúster, debes eliminarlo para evitar que te


cobren por los recursos informáticos no utilizados:

$ gcloud container clusters delete supersizeme


Ver también

 Cluster Autoscaler en el repositorio kubernetes/autoscaler


 Cluster Autoscaler en la documentación de GKE

9.4 Redimensionar automáticamente


un clúster de Amazon EKS

Problema

Quieres que el número de nodos de tu clúster de AWS EKS aumente o


disminuya automáticamente, en función de la utilización.

Solución
Utiliza el Cluster Autoscaler, un paquete de Helm que aprovecha los
grupos de autoescalado de AWS. Sigue la Receta 6.1 para instalar el cliente
Helm necesario para instalar el paquete.
En primer lugar, crea un clúster con un nodo trabajador y asegúrate de
que puedes acceder a él con kubectl:

$ eksctl create cluster --name supersizeme \


--region eu-central-1 --instance-types t3.small \
--nodes 1 --nodes-min 1 --nodes-max 3
2023-04-11 12:00:50 [i] eksctl version 0.136.0-
dev+3f5a7c5e0.2023-03-31T10...
2023-04-11 12:00:50 [i] using region eu-central-1
...
2023-04-11 12:17:31 [i] kubectl command should work with
"/Users/sameersbn/
.kube/config", try 'kubectl get nodes'
2023-04-11 12:17:31 [✔] EKS cluster "supersizeme" in "eu-
central-1" region
is ready

$ aws eks update-kubeconfig --name supersizeme --region eu-


central-1
A continuación, implementa el gráfico de Cluster Autoscaler Helm:

$ helm repo add autoscaler


https://kubernetes.github.io/autoscaler
$ helm install autoscaler autoscaler/cluster-autoscaler \
--set autoDiscovery.clusterName=supersizeme \
--set awsRegion=eu-central-1 \
--set awsAccessKeyID=<YOUR AWS KEY ID> \
--set awsSecretAccessKey=<YOUR AWS SECRET KEY>
En este punto, el clúster sólo tiene un nodo:

$ kubectl get nodes


NAME STATUS ROLES AGE
VERSION
ip...eu-central-1.compute.internal Ready <none> 31m
v1.25.9-eks-0a21954
Ahora, lanza cinco pods utilizando una implementación y solicita recursos
de clúster para activar el autoescalado del clúster:
$ kubectl create deployment gogs --image=gogs/gogs:0.13 --
replicas=5
$ kubectl set resources deployment gogs -c=gogs --
requests=cpu=200m,memory=512Mi
Al cabo de un tiempo, la implementación se actualizará:

$ kubectl get deployment gogs


NAME READY UP-TO-DATE AVAILABLE AGE
gogs 5/5 5 5 2m7s
Ahora tu clúster debería haberse escalado para acomodar los recursos
solicitados:

$ kubectl get nodes


NAME STATUS ROLES AGE
VERSION
ip...eu-central-1.compute.internal Ready <none> 92s
v1.25.9-eks-0a21954
ip...eu-central-1.compute.internal Ready <none> 93s
v1.25.9-eks-0a21954
ip...eu-central-1.compute.internal Ready <none> 36m
v1.25.9-eks-0a21954
Para evitar que te cobren por los recursos no utilizados, elimina el clúster
siya no lo necesitas:

$ eksctl delete cluster --name supersizeme --region eu-


central-1
Capítulo 10. Seguridad
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

Ejecutar aplicaciones en Kubernetes conlleva una responsabilidad


compartida entre los desarrolladores y la gente de operaciones para
garantizar que se minimizan los vectores de ataque, se siguen los
principios de mínimos privilegios y se define claramente el acceso a los
recursos. En este capítulo, presentaremos recetas que puedes, y debes,
utilizar para asegurarte de que tu clúster y tus aplicaciones se ejecutan de
forma segura. Las recetas de este capítulo cubren lo siguiente:

 La función y el uso de las cuentas de servicio


 Control de acceso basado en roles (RBAC)
 Definir el contexto de seguridad de un pod

10.1 Proporcionar una identidad única


a una aplicación

Problema

Quieres conceder a una aplicación acceso a recursos restringidos a un


nivel de grano fino.

Solución

Crea una cuenta de servicio con acceso secreto específico y haz referencia
a ella dentro de la especificación de un pod.

Para empezar, crea un espacio de nombres dedicado para ésta y la


siguiente receta llamado sec:

$ kubectl create namespace sec


namespace/sec created
A continuación, crea una nueva cuenta de servicio llamada myappsa en ese
espacio de nombres y échale un vistazo:
$ kubectl create serviceaccount myappsa -n sec
serviceaccount/myappsa created

$ kubectl describe sa myappsa -n sec


Name: myappsa
Namespace: sec
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>
Puedes hacer referencia a esta cuenta de servicio en un manifiesto pod,
que llamaremos serviceaccountpod.yaml, como se muestra a
continuación. Observa que también estamos colocando este pod en el
espacio de nombres sec:
apiVersion: v1
kind: Pod
metadata:
name: myapp
namespace: sec
spec:
serviceAccountName: myappsa
containers:
- name: main
image: busybox:1.36
command:
- "bin/sh"
- "-c"
- "sleep 10000"
Crea la vaina:

$ kubectl apply -f serviceaccountpod.yaml


pod/myapp created
Las credenciales API de la cuenta de servicio se automontarán
en /var/run/secrets/kubernetes.io/serviceaccount/token:

$ kubectl exec myapp -n sec -- \


cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6IkdHeTRHOUUwNl ...
Efectivamente, el token de cuenta de servicio myappsa se ha montado en el
lugar esperado en el pod y se puede utilizar en adelante.
Aunque una cuenta de servicio por sí sola no es superútil, constituye la
base para un control de acceso de grano fino; consulta la Receta 10.2 para
saber más sobre esto.
Debate

Poder identificar a una entidad es el requisito previo para la


autenticación y la autorización. Desde el punto de vista del servidor API,
hay dos tipos de entidades: los usuarios humanos y las
aplicaciones. Mientras que la identidad (gestión) del usuario queda fuera
del ámbito de Kubernetes, existe un recurso de primera clase que
representa la identidad de una app: la cuenta de servicio.

Técnicamente, la autenticación de una app se captura mediante el token


disponible en un archivo en la
ubicación /var/run/secrets/kubernetes.io/serviceaccount/token, que se
monta automáticamente mediante un secreto. Las cuentas de servicio son
recursos namespaced y se representan como sigue:
system:serviceaccount:$NAMESPACE:$SERVICEACCOUNT
El listado de las cuentas de servicio de un determinado espacio de
nombres te da algo como lo siguiente:

$ kubectl get sa -n sec


NAME SECRETS AGE
default 0 3m45s
myappsa 0 3m2s
Observa aquí la cuenta de servicio llamada default. Ésta se crea
automáticamente; si no estableces explícitamente la cuenta de servicio
para un pod, como se hizo en la solución, se le asignará la cuenta de
servicio default en su espacio de nombres.
Ver también

 "Gestión de cuentas de servicio" en ladocumentación de


Kubernetes
 "Configurar cuentas de servicio para pods" en la documentación
de Kubernetes
 "Extraer una imagen de un registro privado" en la
documentación de Kubernetes

10.2 Listado y Visualización de la


Información de Control de Acceso
Problema

Quieres saber qué acciones puedes realizar, por ejemplo, actualizar


unaimplementación o listar secretos.
Solución

La siguiente solución asume que estás utilizando RBAC como modo de


autorización. RBAC es el modo por defecto para el control de acceso en
Kubernetes.
Para comprobar si una determinada acción sobre un recurso está
permitida para un usuario concreto, utiliza kubectl auth can-i. Por
ejemplo, puedes ejecutar este comando para comprobar si la cuenta de
servicio llamada system:serviceaccount:sec:myappsa que creaste en la
receta anterior está autorizada a listar pods en el espacio de nombres sec:

$ kubectl auth can-i list pods --


as=system:serviceaccount:sec:myappsa -n=sec
no
Puedes asignar funciones a una cuenta de servicio utilizando el sistema
RBAC integrado de Kubernetes. Por ejemplo, puedes dar a la cuenta de
servicio permiso para ver todos los recursos de un determinado espacio
de nombres asignándole el rol predefinido de clúster view para ese
espacio de nombres:

$ kubectl create rolebinding my-sa-view \


--clusterrole=view \
--serviceaccount=sec:myappsa \
--namespace=sec
rolebinding.rbac.authorization.k8s.io/my-sa-view created
Ahora, si ejecutas el mismo comando can-i, verás que la cuenta de
servicio tiene ahora permiso para leer pods en el espacio de nombres sec:

$ kubectl auth can-i list pods --


as=system:serviceaccount:sec:myappsa -n=sec
yes
NOTA
Para que esta receta funcione en Minikube, dependiendo de la versión que estés
ejecutando, puede que necesites añadir el parámetro --extra-
config=apiserver.authorization-mode=Node,RBAC al iniciar tu clúster
Minikube.

Para listar los roles disponibles en un espacio de nombres, haz esto:

$ kubectl get roles -n=kube-system


extension-apiserver-authentication-reader 2023-04-
14T15:06:36Z
kube-proxy 2023-04-
14T15:06:38Z
kubeadm:kubelet-config 2023-04-
14T15:06:36Z
kubeadm:nodes-kubeadm-config 2023-04-
14T15:06:36Z
system::leader-locking-kube-controller-manager 2023-04-
14T15:06:36Z
system::leader-locking-kube-scheduler 2023-04-
14T15:06:36Z
system:controller:bootstrap-signer 2023-04-
14T15:06:36Z
system:controller:cloud-provider 2023-04-
14T15:06:36Z
system:controller:token-cleaner 2023-04-
14T15:06:36Z
system:persistent-volume-provisioner 2023-04-
14T15:06:39Z

$ kubectl get clusterroles


NAME CREATED AT
admin 2023-04-14T15:06:36Z
cluster-admin 2023-04-14T15:06:36Z
edit 2023-04-14T15:06:36Z
kubeadm:get-nodes 2023-04-14T15:06:37Z
system:aggregate-to-admin 2023-04-14T15:06:36Z
system:aggregate-to-edit 2023-04-14T15:06:36Z
system:aggregate-to-view 2023-04-14T15:06:36Z
system:auth-delegator 2023-04-14T15:06:36Z
...
La salida muestra los roles predefinidos, que puedes utilizar directamente
para usuarios y cuentas de servicio.

Para explorar más a fondo un determinado rol y comprender qué


acciones están permitidas, utiliza lo siguiente:
$ kubectl describe clusterroles/view
Name: view
Labels: kubernetes.io/bootstrapping=rbac-defaults
rbac.authorization.k8s.io/aggregate-to-
edit=true
Annotations:
rbac.authorization.kubernetes.io/autoupdate=true
PolicyRule:
Resources Non-
Resource URLs ... ...
---------
----------------- --- ---
bindings []
... ...
configmaps []
... ...
cronjobs.batch []
... ...
daemonsets.extensions []
... ...
deployments.apps []
... ...
deployments.extensions []
... ...
deployments.apps/scale []
... ...
deployments.extensions/scale []
... ...
endpoints []
... ...
events []
... ...
horizontalpodautoscalers.autoscaling []
... ...
ingresses.extensions []
... ...
jobs.batch []
... ...
limitranges []
... ...
namespaces []
... ...
namespaces/status []
... ...
persistentvolumeclaims []
... ...
pods []
... ...
pods/log []
... ...
pods/status []
... ...
replicasets.extensions []
... ...
replicasets.extensions/scale []
... ...
...
Además de los roles por defecto definidos en el espacio de nombres kube-
system, puedes definir los tuyos propios; consulta la Receta 10.3.

Debate

Como puedes ver en la Figura 10-1, hay un par de partes móviles cuando
se trata de la autorización RBAC:
 Una entidad, es decir, un grupo, usuario o cuenta de servicio
 Un recurso, como un pod, un servicio o un secreto
 Un rol, que define reglas para las acciones sobre un recurso
 Un enlace de rol, que aplica un rol a una entidad

Figura 10-1. El concepto RBAC

Las acciones sobre un recurso que un rol utiliza en sus reglas son los
llamados verbos:

 get, list, watch


 create
 update/patch
 delete
En cuanto a los papeles, diferenciamos dos tipos:

En todo el clúster
Roles de clúster y sus respectivos enlaces de rol de clúster. Ten en
cuenta que también puedes adjuntar funciones de clúster a
vinculaciones de funciones normales.

En todo el espacio de nombres


Funciones y vinculaciones de funciones.

En la Receta 10.3 hablaremos más detalladamente de cómo puedes crear


tus propias reglas y aplicarlas a usuarios y recursos.
Ver también

 "Visión general de la autorización" en la documentación de


Kubernetes
 "Uso de la autorización RBAC" en la documentación de
Kubernetes

10.3 Controlar el acceso a los recursos

Problema

Para un determinado usuario o aplicación, quieres permitir o denegar


una determinada acción, como ver secretos o actualizar una
implementación.

Solución

Supongamos que quieres restringir una aplicación para que sólo pueda
ver pods, es decir, listar pods y obtener detalles sobre ellos.

Trabajaremos en un espacio de nombres llamado sec, así que empieza


creando ese espacio de nombres con kubectl create namespace sec.
A continuación, crea una definición de pod en un manifiesto YAML, pod-
with-sa.yaml, utilizando una cuenta de servicio
dedicada, myappsa (consulta la Receta 10.1):
apiVersion: v1
kind: Pod
metadata:
name: myapp
namespace: sec
spec:
serviceAccountName: myappsa
containers:
- name: main
image: busybox:1.36
command:
- "sh"
- "-c"
- "sleep 10000"
A continuación, define un rol -llamémoslo podreader en el manifiesto pod-
reader.yaml- quedefina las acciones permitidas sobre los recursos:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: podreader
namespace: sec
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
Por último, pero no menos importante, tienes que aplicar el
rol podreader a la cuenta de servicio myappsa, utilizando un enlace de
rol en pod-reader-binding.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: podreaderbinding
namespace: sec
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: podreader
subjects:
- kind: ServiceAccount
name: myappsa
namespace: sec
Al crear los recursos respectivos, puedes utilizar directamente los
manifiestos YAML (suponiendo que ya se haya creado la cuenta de
servicio):

$ kubectl create -f pod-reader.yaml


$ kubectl create -f pod-reader-binding.yaml
$ kubectl create -f pod-with-sa.yaml
En lugar de crear manifiestos para el rol y el enlace de rol, puedes utilizar
los siguientes comandos:

$ kubectl create role podreader \


--verb=get --verb=list \
--resource=pods -n=sec

$ kubectl create rolebinding podreaderbinding \


--role=sec:podreader \
--serviceaccount=sec:myappsa \
--namespace=sec
Ten en cuenta que éste es un caso de configuración de control de acceso
con espacio de nombres, ya que estás utilizando roles y vinculaciones de
roles. Para el control de acceso en todo el clúster, utilizarías los comandos
correspondientes create clusterrole y create clusterrolebinding.
Debate

A veces no es obvio si debes utilizar un rol o un rol de clúster y/o un


enlace de rol, así que aquí tienes unas cuantas reglas generales que
pueden resultarte útiles:

 Si quieres restringir el acceso a un recurso con espacio de


nombres (como un servicio o un pod) en un determinado
espacio de nombres, utiliza un rol y un enlace de rol (como
hicimos en esta receta).
 Si quieres reutilizar un rol en un par de espacios de nombres,
utiliza un rol de clúster con un enlace de rol.
 Si quieres restringir el acceso a recursos de todo el clúster, como
los nodos, o a recursos con espacio de nombres en todos los
espacios de nombres, utiliza un rol de clúster con un enlace de
rol de clúster.
Ver también

 Documentación de Kubernetes sobre el uso de la autorización


RBAC

10.4 Asegurar los Pods

Problema

Quieres definir el contexto de seguridad de una aplicación a nivel de


pod. Por ejemplo, quieres ejecutar la aplicación como un proceso sin
privilegios.

Solución

Para aplicar políticas a nivel de pod en Kubernetes, utiliza el


campo securityContext en la especificación de un pod.
Supongamos que quieres que una aplicación se ejecute como usuario no
root. Para ello, utilizarías el contexto de seguridad a nivel de contenedor,
como se muestra en el siguiente manifiesto, securedpod.yaml:
kind: Pod
apiVersion: v1
metadata:
name: secpod
spec:
containers:
- name: shell
image: ubuntu:20.04
command:
- "bin/bash"
- "-c"
- "sleep 10000"
securityContext:
runAsUser: 5000
Ahora crea el pod y comprueba el usuario bajo el que se ejecuta el
contenedor:

$ kubectl apply -f securedpod.yaml


pod/secpod created

$ kubectl exec secpod -- ps aux


USER PID %CPU %MEM VSZ RSS TTY STAT
START TIME COMMAND
5000 1 0.0 0.0 2204 784 ? Ss
15:56 0:00 sleep 10000
5000 13 0.0 0.0 6408 1652 ? Rs
15:56 0:00 ps aux
Como era de esperar, se está ejecutando como el usuario con ID 5000. Ten
en cuenta que también puedes utilizar el campo securityContext a nivel
de pod en lugar de en contenedores concretos.
Debate

Un método más potente para aplicar políticas a nivel de pod es utilizar la


admisión de seguridad de pod. Consulta "Admisión de seguridad de
pods" en la documentación de Kubernetes.
Ver también

 "Configurar un contexto de seguridad para un pod o


contenedor" en la documentación de Kubernetes
Capítulo 11. Monitoreo y registro
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este capítulo nos centraremos en recetas relacionadas con el


monitoreo y el registro, tanto a nivel de infraestructura como de
aplicación. En el contexto de Kubernetes, los distintos roles suelen tener
ámbitos diferentes:

Funciones de administrador
Los administradores, como los del clúster, los de operaciones de red
o los del espacio de nombres, se centran en el plano de control del
clúster. Algunos ejemplos de preguntas que pueden plantearse son
¿Están sanos los nodos? ¿Agregamos un nodo trabajador? ¿Cuál es
la utilización de todo el clúster? ¿Se acercan los usuarios a sus
cuotas de uso?

Funciones del desarrollador


Los desarrolladores piensan y actúan principalmente en el contexto
de la aplicación o del plano de datos, que bien puede ser -en la era
de los microservicios- de un puñado a una docena de vainas. Por
ejemplo, una persona con funciones de desarrollador podría
preguntarse ¿Tengo suficientes recursos asignados para ejecutar mi
aplicación? ¿A cuántas réplicas debo escalar mi aplicación? ¿Tengo
acceso a los volúmenes adecuados, y cómo de llenos están? ¿Está
fallando una de mis aplicaciones y, si es así, por qué?

Primero cubriremos recetas centradas en el monitoreo interno del clúster


aprovechando las sondas de liveness y readiness de Kubernetes, luego nos
centraremos en el monitoreo con el Servidor de Métricas y Prometheus, y
finalmente cubriremos recetas relacionadas con el registro.

11.1 Acceder a los Registros de un


Contenedor

Problema

Quieres acceder a los registros de la aplicación que se ejecuta dentro de


un contenedor que se está ejecutando en un pod específico.
Solución

Utiliza el comando kubectl logs. Para ver las distintas opciones,


comprueba el uso, así:

$ kubectl logs --help | more


Print the logs for a container in a pod or specified
resource. If the pod has
only one container, the container name is optional.

Examples:
# Return snapshot logs from pod nginx with only one
container
kubectl logs nginx
...
Por ejemplo, dado un pod iniciado por una implementación (ver Receta
4.1), puedes comprobar los registros de la siguiente forma

$ kubectl get pods


NAME READY STATUS
RESTARTS AGE
nginx-with-pv-7d6877b8cf-mjx5m 1/1 Running 0
140m

$ kubectl logs nginx-with-pv-7d6877b8cf-mjx5m


...
2023/03/31 11:03:24 [notice] 1#1: using the "epoll" event
method
2023/03/31 11:03:24 [notice] 1#1: nginx/1.23.4
2023/03/31 11:03:24 [notice] 1#1: built by gcc 10.2.1
20210110 (Debian 10.2.1-6)
2023/03/31 11:03:24 [notice] 1#1: OS: Linux 5.15.49-
linuxkit
2023/03/31 11:03:24 [notice] 1#1:
getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/03/31 11:03:24 [notice] 1#1: start worker processes
...
CONSEJO

Si un pod tiene varios contenedores, puedes obtener los registros de cualquiera


de ellos especificando el nombre del contenedor mediante la opción -
c de kubectl logs.
Debate

Stern es una alternativa útil para ver los registros de pods en Kubernetes.
Facilita la obtención de registros de todos los espacios de nombres y sólo
requiere que proporciones un nombre parcial de pod en la consulta (en
lugar de utilizar selectores, que a veces pueden ser más engorrosos).

11.2 Recuperación de un estado roto


con unasonda de vitalidad
Problema

Quieres asegurarte de que si las aplicaciones que se ejecutan dentro de


algunos de tus pods entran en un estado roto, Kubernetes reinicie los pods
automáticamente.

Solución

Utiliza una sonda de vida. Si la sonda falla, el kubelet reiniciará el pod


automáticamente. La sonda forma parte de la especificación del pod y se
añade a la sección containers. Cada contenedor de un pod puede tener
una sonda de vida.
Una sonda puede ser de tres tipos diferentes: puede ser un comando que
se ejecuta dentro del contenedor, una petición HTTP o gRPC a una ruta
específica servida por un servidor HTTP dentro del contenedor, o una
sonda TCP más genérica.

En el siguiente ejemplo, mostramos una sonda HTTP básica:

apiVersion: v1
kind: Pod
metadata:
name: liveness-nginx
spec:
containers:
- name: nginx
image: nginx:1.25.2
livenessProbe:
httpGet:
path: /
port: 80
Consulta la Receta 11.5 para ver un ejemplo completo.
Ver también
 Documentación sobre sondas de contenedores Kubernetes

11.3 Controlar el flujo de tráfico a un


Pod mediante unaSonda de
Preparación
Problema

Tus pods están en funcionamiento según las sondas de liveness


(ver Receta 11.2), pero quieres enviarles tráfico sólo si la aplicación está
preparada para servir las peticiones.
Solución

Añade sondas de preparación a las especificaciones de tu pod. A


continuación se muestra un ejemplo sencillo de ejecución de un único pod
con la imagen de contenedor nginx. La sonda de preparación realiza una
petición HTTP al puerto 80:
apiVersion: v1
kind: Pod
metadata:
name: readiness-nginx
spec:
containers:
- name: readiness
image: nginx:1.25.2
readinessProbe:
httpGet:
path: /
port: 80
Debate

Aunque la sonda de preparación que se muestra en esta receta es la


misma que la sonda de vitalidad de la Receta 11.2, normalmente deberían
ser diferentes, ya que las dos sondas pretenden dar información sobre
aspectos distintos de la aplicación. La sonda de actividad comprueba que
el proceso de la aplicación está vivo, pero puede que no esté preparado
para aceptar peticiones. La sonda de disponibilidad comprueba que la
aplicación atiende correctamente las peticiones. Por tanto, sólo cuando se
supera una sonda de disponibilidad, el pod pasa a formar parte de un
servicio (ver Receta 5.1).
Ver también

 Documentación sobre sondas de contenedores Kubernetes


11.4 Proteger los Contenedores de
Arranque Lento conuna Sonda de
Arranque
Problema

Tu pod contiene un contenedor que necesita tiempo de arranque


adicional en la primera inicialización, pero no quieres utilizar las sondas
de liveness (ver Receta 11.2), ya que esto es un requisito sólo para la
primera vez que se lanza el pod.
Solución

Añade una sonda de arranque a la especificación de tu vaina


con failureThreshold y periodSeconds configurados a un valor lo
suficientemente alto como para cubrir el tiempo de arranque de la
vaina. Al igual que las sondas de vida, las sondas de arranque pueden ser
de tres tipos. A continuación se muestra un ejemplo sencillo de ejecución
de un único pod con la imagen de contenedor nginx. La sonda de
arranque realiza una petición HTTP al puerto 80:
apiVersion: v1
kind: Pod
metadata:
name: startup-nginx
spec:
containers:
- name: startup
image: nginx:1.25.2
startupProbe:
httpGet:
path: /
port: 80
failureThreshold: 30
periodSeconds: 10

Debate

A veces tienes que lidiar con aplicaciones que necesitan mucho tiempo
para arrancar. Por ejemplo, una aplicación puede necesitar realizar
algunas migraciones de bases de datos que tardan mucho tiempo en
completarse. En tales casos, configurar una sonda de liveness, sin
comprometer la respuesta rápida a los bloqueos que la motivan, puede
ser complicado. Para evitarlo, además de la sonda de liveness, puedes
configurar una sonda de arranque con el mismo comando, comprobación
HTTP o comprobación TCP, pero con un failureThreshold *
periodSeconds lo suficientemente largo como para cubrir el tiempo de
arranque en el peor de los casos.
Si se configura una sonda de arranque, las sondas de liveness y readiness
no se inician hasta que tenga éxito, asegurándose de que esas sondas no
interfieren con el arranque de la aplicación. Esta técnica se puede utilizar
para implementar de forma segura comprobaciones de actividad en
contenedores que arrancan lentamente, evitando que el kubelet los mate
antes de que estén en funcionamiento.
Ver también

 Documentación sobre sondas de contenedores Kubernetes


 "Configurar las sondas de capacidad, preparación y
arranque" en la documentación de Kubernetes

11.5 Añadir Sondas de Capacidad y


Disponibilidad atus Implementaciones
Problema

Quieres poder comprobar automáticamente si tu aplicación está en buen


estado y dejar que Kubernetes actúe si no es así.

Solución

Para indicar a Kubernetes cómo va tu aplicación, añade sondas de


liveness y readiness como se describe aquí.

El punto de partida es un manifiesto de


implementación, webserver.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: webserver
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25.2
ports:
- containerPort: 80
Las sondas de actividad y preparación se definen en la
sección containers de la especificación del pod. Consulta los ejemplos
introductorios (Recetas 11.2 y 11.3) y añade lo siguiente a la especificación
del contenedor en la plantilla del pod de tu implementación:
...
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 10
...
Ahora puedes lanzarlo y comprobar las sondas:

$ kubectl apply -f webserver.yaml


deployment.apps/webserver created

$ kubectl get pods


NAME READY STATUS RESTARTS
AGE
webserver-4288715076-dk9c7 1/1 Running 0
2m

$ kubectl describe pod/webserver-4288715076-dk9c7


Name: webserver-4288715076-dk9c7
Namespace: default
Priority: 0

...
Status: Running
IP: 10.32.0.2
...
Containers:
nginx:
...
Ready: True
Restart Count: 0
Liveness: http-get http://:80/ delay=2s
timeout=1s period=10s #succe...
Readiness: http-get http://:80/ delay=2s
timeout=1s period=10s #succe...
...
...
Observa que la salida del comando kubectl describe se ha reducido a las
partes importantes; hay mucha más información disponible, pero no es
pertinente para nuestro problema aquí.
Debate

Para verificar si un contenedor de un pod está en buen estado y listo para


servir tráfico, Kubernetes proporciona una serie de mecanismos de
comprobación de estado.Las comprobaciones de estado, o sondas como se
denominan en Kubernetes, se definen a nivel de contenedor, no a nivel de
pod, y las llevan a cabo dos componentes diferentes:
 El kubelet de cada nodo trabajador utiliza la
directiva livenessProbe de la especificación para determinar
cuándo reiniciar un contenedor. Estas sondas de liveness
pueden ayudar a superar problemas de ramp-up o deadlocks.
 Un servicio que equilibra la carga de un conjunto de pods utiliza
la directiva readinessProbe para determinar si un pod está
preparado y, por tanto, debe recibir tráfico. Si no es así, se
excluye del conjunto de endpoints del servicio. Ten en cuenta
que un pod se considera listo cuando todos sus contenedores lo
están.
¿Cuándo debes utilizar qué sonda? En realidad, eso depende del
comportamiento del contenedor. Utiliza una sonda de caducidad y
una restartPolicy de Always o OnFailure si tu contenedor puede y debe
morir y reiniciarse si falla la sonda. Si quieres enviar tráfico a un pod sólo
cuando esté listo, utiliza una sonda de preparación. Ten en cuenta que, en
este último caso, la sonda de disponibilidad puede configurarse para que
utilice el mismo punto final de la declaración de sondeo (por ejemplo,
URL) que la sonda de disponibilidad.
Las sondas de arranque se utilizan para determinar si la aplicación de un
pod está en marcha y funcionando correctamente. Pueden utilizarse para
retrasar la inicialización de las sondas de liveness y readiness, que
probablemente fallarán si la aplicación aún no se ha iniciado
correctamente.

Ver también

 "Configurar las sondas de vida útil, preparación y arranque" en


la documentación de Kubernetes
 Documentación del ciclo de vida del pod Kubernetes
 Documentación sobre los contenedores init de
Kubernetes (estable en v1.6 y superiores)

11.6 Acceder a las métricas de


Kubernetes en la CLI

Problema

Has instalado el Servidor de Métricas de Kubernetes (ver Receta 2.7), y


quieres acceder a las métricas utilizando la CLI de Kubernetes.
Solución

La CLI de Kubernetes tiene el comando top que muestra el uso de recursos


de nodos y pods:

$ kubectl top node


NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
minikube 338m 8% 1410Mi 17%

$ kubectl top pods --all-namespaces


NAMESPACE NAME
CPU(cores) MEMORY(bytes)
default db 15m
440Mi
default liveness-nginx 1m
5Mi
default nginx-with-pv-7d6877b8cf-mjx5m 0m
3Mi
default readiness-nginx 1m
3Mi
default webserver-f4f7cb455-rhxwt 1m
4Mi
kube-system coredns-787d4945fb-jrp8j 4m
12Mi
kube-system etcd-minikube 48m
52Mi
kube-system kube-apiserver-minikube 78m
266Mi
...
Estas métricas también se pueden ver en una interfaz gráfica de usuario,
elpanel de control de Kubernetes (ver Receta 2.5).
CONSEJO
El Servidor de Métricas puede tardar varios minutos en estar disponible después
de haberlo iniciado. Si aún no está en estado listo, el comando top puede
producir errores.

11.7 Utilizar Prometheus y Grafana en


Minikube

Problema

Quieres ver y consultar las métricas del sistema y de las aplicaciones de tu


clúster desde un lugar central.

Solución

Implementación de Prometheus y Grafana en Minikube. Aprovecharemos


el proyecto kube-prometheus, un proyecto independiente que facilita la
instalación de Prometheus y Grafana en cualquier clúster de Kubernetes.
Ejecuta el siguiente comando para iniciar una nueva instancia de
Minikube que esté correctamente configurada para ejecutar kube-
prometheus:

$ minikube delete && minikube start --kubernetes-


version=v1.27.0 \
--memory=6g --bootstrapper=kubeadm \
--extra-config=kubelet.authentication-token-
webhook=true \
--extra-config=kubelet.authorization-mode=Webhook \
--extra-config=scheduler.bind-address=0.0.0.0 \
--extra-config=controller-manager.bind-address=0.0.0.0
Asegúrate de que el complemento metrics-server está desactivado en
Minikube:

$ minikube addons disable metrics-server


Clona el proyecto kube-prometheus:
$ git clone https://github.com/prometheus-operator/kube-
prometheus.git
Entra en el repositorio clonado y ejecuta el siguiente comando que creará
un espacio de nombres dedicado llamado monitoring y creará las
definiciones de recursos personalizados necesarias:

$ kubectl apply --server-side -f manifests/setup


$ kubectl wait \
--for condition=Established \
--all CustomResourceDefinition \
--namespace=monitoring
$ kubectl apply -f manifests/
Para abrir el panel de Prometheus, puedes utilizar un reenvío de puerto,
como se muestra aquí, o puedes utilizar el ingreso, como se define en la
Receta 5.5:

$ kubectl --namespace monitoring port-forward


svc/prometheus-k8s 9090
A continuación, puedes abrir Prometheus en localhost:9090 en tu
navegador.
Puedes hacer algo similar para acceder al panel de control de Grafana:

$ kubectl --namespace monitoring port-forward svc/grafana


3000
A continuación, abre el panel de control de Grafana en localhost:3000 en
tu navegador.
Utiliza las credenciales predeterminadas para iniciar sesión: nombre de
usuario admin y contraseña admin. Puedes omitir el cambio de contraseña
si sólo estás ejecutando esta receta en tu instancia local de Minikube.
Existe un panel de control integrado para el servidor API de Kubernetes.
Para encontrarlo, abre la URL http://localhost:3000/dashboards o
navega hasta los Cuadros de mando utilizando la barra de menú de la
izquierda. Busca el panel llamado "Kubernetes / Servidor API"; ábrelo y
verás una página como la que se muestra en la Figura 11-1.
Figura 11-1. El panel del servidor Kubernetes/API en Grafana

Debate

Esta receta es una forma estupenda de empezar a experimentar con


Grafana y Prometheus, y muestra cómo utilizar un panel de control
integrado de ejemplo para ponerte en marcha rápidamente. Una vez que
empieces a implementar tus propias cargas de trabajo y aplicaciones
personalizadas, podrás crear tus propias consultas y paneles
personalizados que proporcionarán métricas más específicas para tus
cargas de trabajo. Puedes obtener más información sobre las consultas de
Prometheus en la documentación de referencia de consultas de
Prometheus, y más información sobre los cuadros de mando de Grafana
en la documentación de Grafana.
Ver también

 kube-prometheus en GitHub
 Operador Prometheus en GitHub
 Operario de Prometheus
 Prometeo
 Grafana
Capítulo 12. Mantenimiento y
resolución de problemas
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

En este capítulo encontrarás recetas que tratan del mantenimiento tanto a


nivel de aplicación como de clúster. Cubrimos varios aspectos de la
resolución de problemas, desde la depuración de pods y contenedores
hasta la comprobación de la conectividad de servicios, la interpretación
del estado de un recurso y el mantenimiento de nodos. Por último, pero
no por ello menos importante, veremos cómo manejar etcd, el
componente de almacenamiento del plano de control de Kubernetes. Este
capítulo es relevante tanto para los administradores de clústeres como
para los desarrolladores de aplicaciones.

12.1 Activar Autocompletar para


kubectl

Problema

Es engorroso escribir comandos y argumentos completos para la CLI


de kubectl, por lo que quieres una función de autocompletar para ella.
Solución

Activa el autocompletado para kubectl.


Para el intérprete de comandos bash , puedes activar el
autocompletado kubectl en tu intérprete de comandos actual con el
siguiente comando:

$ source <(kubectl completion bash)


Añade esto a tu archivo ~/.bashrc para que autocompletar se cargue en
todas tus sesiones de shell:

$ echo 'source <(kubectl completion bash)' >>~/.bashrc


Ten en cuenta que el autocompletado para bash depende de que bash-
completado esté instalado.
Para el shell zsh, puedes activar el autocompletado kubectl con el
siguientecomando:

$ source <(kubectl completion zsh)


Y puedes añadir este mismo comando a tu archivo ~/.zshrc para que
autocompletar se cargue en todas tus sesiones de shell.
Para que el autocompletado funcione en zsh, puede que necesites tener
estos comandos al principio de tu archivo ~/.zshrc:

autoload -Uz compinit

compinit

Para otros sistemas operativos y shells, consulta la documentación.


Debate

Otra mejora popular de la experiencia del desarrollador de kubectl es


definir un alias para acortar kubectl a sólo la letra k. Esto se puede
conseguir ejecutando los siguientes comandos o añadiéndolos a tu script
de inicio del shell:

alias k=kubectl

complete -o default -F __start_kubectl k

Entonces, sólo tienes que escribir comandos como k apply -f


myobject.yaml. Esto, combinado con el autocompletado, te facilita mucho
la vida.
Ver también

 Visión general de kubectl


 kubectl Hoja de trucos

12.2 Eliminar un Pod de un Servicio


Problema

Tienes un servicio bien definido (ver Receta 5.1) respaldado por varios
pods. Pero uno de los pods está causando problemas (por ejemplo, se
bloquea o no responde), y quieres sacarlo de la lista de puntos finales para
examinarlo más adelante.
Solución

Reetiqueta el pod utilizando la opción --overwrite: esto te permitirá


cambiar el valor de la etiqueta run del pod. Al sobrescribir esta etiqueta,
puedes asegurarte de que no será seleccionado por el selector de
servicios(Receta 5.1) y será eliminado de la lista de endpoints. Al mismo
tiempo, el conjunto de réplicas que vigila tus pods verá que un pod ha
desaparecido e iniciará una nueva réplica.
Para verlo en acción, empieza con una implementación sencilla generada
con kubectl run (consulta la Receta 4.5):

$ kubectl create deployment nginx --image nginx:1.25.2 --


replicas 4
Cuando enumeras los pods y muestras la etiqueta con la clave app, verás
cuatro pods con el valor nginx (app=nginx es la etiqueta que genera
automáticamente el comando kubectl create deployment ):

$ kubectl get pods -Lapp


NAME READY STATUS RESTARTS AGE
APP
nginx-748c667d99-85zxr 1/1 Running 0 14m
nginx
nginx-748c667d99-jrhpc 1/1 Running 0 14m
nginx
nginx-748c667d99-rddww 1/1 Running 0 14m
nginx
nginx-748c667d99-x6h6h 1/1 Running 0 14m
nginx
A continuación, puedes exponer esta implementación con un servicio y
comprobar los puntos finales, que corresponden a las direcciones IP de
cada pod:
$ kubectl expose deployments nginx --port 80

$ kubectl get endpoints


NAME ENDPOINTS
AGE
kubernetes 192.168.49.2:8443
3h36m
nginx
10.244.0.10:80,10.244.0.11:80,10.244.0.13:80 + 1 more...
13m
Imaginemos que el primer pod de la lista está causando problemas,
aunque su estado sea En ejecución.
Sacar el primer pod del grupo de servicios mediante reetiquetado se hace
con un solo comando:

$ kubectl label pod nginx-748c667d99-85zxr app=notworking


--overwrite
CONSEJO

Para encontrar la dirección IP de un pod, puedes utilizar una plantilla Go para


formatear la información del pod y mostrar sólo su dirección IP:

$ kubectl get pod nginx-748c667d99-jrhpc \


--template '{{.status.podIP}}'
10.244.0.11

Verás que aparece un nuevo pod con la etiqueta app=nginx, y verás que tu
pod no operativo sigue existiendo pero ya no aparece en la lista de puntos
finales de servicio:

$ kubectl get pods -Lapp


NAME READY STATUS RESTARTS AGE
APP
nginx-748c667d99-85zxr 1/1 Running 0 14m
notworking
nginx-748c667d99-jrhpc 1/1 Running 0 14m
nginx
nginx-748c667d99-rddww 1/1 Running 0 14m
nginx
nginx-748c667d99-x6h6h 1/1 Running 0 14m
nginx
nginx-748c667d99-xfgqp 1/1 Running 0
2m17s nginx

$ kubectl describe endpoints nginx


Name: nginx
Namespace: default
Labels: app=nginx
Annotations: endpoints.kubernetes.io/last-change-trigger-
time: 2023-04-13T13...
Subsets:
Addresses:
10.244.0.10,10.244.0.11,10.244.0.13,10.244.0.9
NotReadyAddresses: <none>
Ports:
Name Port Protocol
---- ---- --------
<unset> 80 TCP

Events: <none>

12.3 Acceder a un servicio ClusterIP


fuera del Cluster

Problema

Tienes un servicio interno que te está causando problemas, y quieres


probar que funciona bien localmente sin exponer el servicio
externamente.

Solución

Utiliza un proxy local al servidor de la API de Kubernetes con kubectl


proxy.
Supongamos que has creado una implementación y un servicio como se
describe en la Receta 12.2. Deberías ver un servicio nginx cuando
enumeras los servicios:

$ kubectl get svc


NAME TYPE CLUSTER-IP EXTERNAL-IP
PORT(S) AGE
nginx ClusterIP 10.108.44.174 <none>
80/TCP 37m
Este servicio no es accesible fuera del clúster Kubernetes. Sin embargo,
puedes ejecutar un proxy en un terminal independiente y alcanzarlo
en localhost.
Empieza ejecutando el proxy en un terminal separado de:

$ kubectl proxy
Starting to serve on 127.0.0.1:8001
CONSEJO

Puedes especificar el puerto en el que quieres que se ejecute el proxy con la


opción --port.

En tu terminal original, puedes entonces utilizar tu navegador o curl para


acceder a la aplicación expuesta por tu servicio:

$ curl
http://localhost:8001/api/v1/namespaces/default/services/ng
inx/proxy/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
Fíjate en la ruta específica al servicio; contiene una parte /proxy. Sin esto,
obtendrás el objeto JSON que representa el servicio.
NOTA

Ten en cuenta que ahora también puedes acceder a toda la API de Kubernetes a
través de localhost utilizando curl.

Debate

Esta receta demuestra un enfoque que es adecuado para la depuración y


no debe utilizarse para el acceso regular a los servicios en producción. En
su lugar, utiliza la Receta segura 5.5 para escenarios de producción.

12.4 Comprender y analizar los estados


de los recursos

Problema
Quieres vigilar un objeto, como un pod, y reaccionar a los cambios de
estado del objeto. A veces, estos cambios de estado desencadenan eventos
en los pipelines CI/CD.

Solución

Utiliza kubectl get $KIND/$NAME -o json y analiza la salida JSON


utilizando uno de los dos métodos descritos aquí.
Si tienes instalada la utilidad de consulta JSON jq, puedes utilizarla para
analizar el estado de los recursos. Supongamos que tienes un pod
llamado jump. Puedes hacer esto para averiguar en qué clase de Calidad de
servicio (QoS) se encuentra el pod:

$ kubectl run jump --image=nginx


pod/jump created

$ kubectl get po/jump -o json | jq --raw-


output .status.qosClass
BestEffort
Ten en cuenta que el argumento --raw-output para jq mostrará el valor
bruto y que .status.qosClass es la expresión que coincide con el
subcampo correspondiente.
Otra consulta de estado podría ser en torno a eventos o transiciones de
estado. Por ejemplo:

$ kubectl get po/jump -o json | jq .status.conditions


[
{
"lastProbeTime": null,
"lastTransitionTime": "2023-04-13T14:00:13Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2023-04-13T14:00:18Z",
"status": "True",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2023-04-13T14:00:18Z",
"status": "True",
"type": "ContainersReady"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2023-04-13T14:00:13Z",
"status": "True",
"type": "PodScheduled"
}
]
Por supuesto, estas consultas no se limitan a los pods: puedes aplicar esta
técnica a cualquier recurso. Por ejemplo, puedes consultar las revisiones
de una implementación:

$ kubectl create deployment wordpress --image


wordpress:6.3.1
deployment.apps/wordpress created

$ kubectl get deploy/wordpress -o json |


jq .metadata.annotations
{
"deployment.kubernetes.io/revision": "1"
}
O puedes listar en todos los puntos finales que componen un servicio:

$ kubectl get ep/nginx -o json | jq '.subsets'


[
{
"addresses": [
{
"ip": "10.244.0.10",
"nodeName": "minikube",
"targetRef": {
"kind": "Pod",
"name": "nginx-748c667d99-x6h6h",
"namespace": "default",
"uid": "a0f3118f-32f5-4a65-8094-8e43979f7cec"
}
},
...
],
"ports": [
{
"port": 80,
"protocol": "TCP"
}
]
}
]

Ahora que has visto jq en acción, pasemos a un método que no requiere


herramientas externas, es decir, la función integrada de utilizar plantillas
Go.
El lenguaje de programación Go define plantillas en un paquete
llamado text/template que pueden utilizarse para cualquier tipo de
transformación de texto o datos, y kubectl tiene soporte incorporado para
ello. Por ejemplo, para listar todas las imágenes contenedoras utilizadas
en el espacio de nombres actual, haz lo siguiente:

$ kubectl get pods -o go-template \


--template="{{range .items}}{{range .spec.containers}}
{{.image}} \
{{end}}{{end}}"
fluent/fluentd:v1.16-1 nginx
Debate

También puedes echar un vistazo a JSONPath como forma alternativa de


analizar el JSON producido por kubectl. Proporciona una sintaxis que
puede considerarse más legible y más fácil de razonar. Puedes encontrar
ejemplos en la documentación de Kubernetes.
Ver también

 El manual jq
 jqplay para probar consultas sin instalar jq
 El paquete Go template

12.5 Depurar Pods

Problema

Te encuentras en una situación en la que un pod no llega al estado de


ejecución o permanece en él como se esperaba, o falla por completo al
cabo de un tiempo.
Solución

Para descubrir y solucionar sistemáticamente la causa del problema ,


entra en un bucle OODA:
1. Observa. ¿Qué ves en los registros del contenedor? ¿Qué eventos
se han producido? ¿Cómo es la conectividad de red?
2. Oriéntate. Formula una serie de hipótesis plausibles: mantén la
mente lo más abierta posible y no saques conclusiones
precipitadas.
3. Decide. Elige una de las hipótesis.
4. Actúa. Pon a prueba la hipótesis. Si se confirma, has terminado;
si no, vuelve al paso 1 y continúa.
Veamos un ejemplo concreto en el que falla un pod. Crea un manifiesto
llamado infeliz-pod.yaml con este contenido:
apiVersion: apps/v1
kind: Deployment
metadata:
name: unhappy
spec:
replicas: 1
selector:
matchLabels:
app: nevermind
template:
metadata:
labels:
app: nevermind
spec:
containers:
- name: shell
image: busybox:1.36
command:
- "sh"
- "-c"
- "echo I will just print something here and then exit"
Ahora, cuando lances esa implementación y mires el pod que crea, verás
que es infeliz:

$ kubectl apply -f unhappy-pod.yaml


deployment.apps/unhappy created

$ kubectl get pod -l app=nevermind


NAME READY STATUS
RESTARTS AGE
unhappy-576954b454-xtb2g 0/1 CrashLoopBackOff 2
(21s ago) 42s
$ kubectl describe pod -l app=nevermind
Name: unhappy-576954b454-xtb2g
Namespace: default
Priority: 0
Service Account: default
Node: minikube/192.168.49.2
Start Time: Thu, 13 Apr 2023 22:31:28 +0200
Labels: app=nevermind
pod-template-hash=576954b454
Annotations: <none>
Status: Running
IP: 10.244.0.16
IPs:
IP: 10.244.0.16
Controlled By: ReplicaSet/unhappy-576954b454
...
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-bff5c:
Type: Projected (a volume that
contains injected data...)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-
ready:NoExecute op=Exist...

node.kubernetes.io/unreachable:NoExecute op=Exist...
Events:
Type Reason ... Message
---- ------ --- -------
Normal Scheduled ... Successfully assigned
default/unhappy-576954b454-x...
Normal Pulled ... Successfully pulled image
"busybox" in 2.945704376...
Normal Pulled ... Successfully pulled image
"busybox" in 1.075044917...
Normal Pulled ... Successfully pulled image
"busybox" in 1.119703875...
Normal Pulling ... Pulling image "busybox"
Normal Created ... Created container shell
Normal Started ... Started container shell
Normal Pulled ... Successfully pulled image
"busybox" in 1.055005126...
Warning BackOff ... Back-off restarting failed
container shell in pod...
Como puedes ver al final de la descripción, en la sección Events,
Kubernetes considera que este pod no está preparado para servir tráfico
porque "Back-off restarting failed....".
Otra forma de observarlo es utilizando el panel de control de Kubernetes
para ver la implementación(Figura 12-1), así como el conjunto de réplicas
supervisadas y el pod(Figura 12-2). Con Minikube puedes abrir fácilmente
el panel de control ejecutando en elcomando minikube dashboard.

Figura 12-1. Implementación en estado de error


Figura 12-2. Pod en estado de error

Debate

Un problema, ya sea un pod que falla o un nodo que se comporta de


forma extraña, puede tener muchas causas diferentes. Aquí tienes
algunas cosas que querrás comprobar antes de sospechar que se trata de
un error de software:

 ¿Es correcto el manifiesto? Compruébalo con una herramienta


como Kubeconform.
 ¿Puedes ejecutar el contenedor localmente fuera de Kubernetes?
 ¿Puede Kubernetes llegar al registro de contenedores y extraer
realmente la imagen del contenedor?
 ¿Pueden los nodos hablar entre sí?
 ¿Pueden los nodos alcanzar el plano de control?
 ¿Está disponible el DNS en el clúster?
 ¿Hay suficientes recursos disponibles en los nodos, como CPU,
memoria y espacio en disco?
 ¿Restringiste el uso de recursos del contenedor o del espacio de
nombres?
 ¿Qué dicen los eventos de la descripción del objeto?
Ver también

 "Pods de depuración" en la documentación de Kubernetes


 "Depurar pods en ejecución" en la documentación de
Kubernetes
 "Servicios de depuración" en la documentación de Kubernetes
 "Resolución de problemas de clusters" en la documentación de
Kubernetes

12.6 Influir en el comportamiento de


arranque de un Pod

Problema

Para que tu pod funcione correctamente, depende de que algún otro


servicio esté disponible. Quieres influir en el comportamiento de
arranque del pod para que se inicie sólo cuando estén disponibles los
pods de los que depende.

Solución

Utiliza contenedores init para influir en el comportamiento de arranque


de un pod.
Imagina que quieres poner en marcha un servidor web NGINX que
depende de un servicio backend para servir contenido. Por tanto, quieres
asegurarte de que el pod NGINX sólo se inicie una vez que el servicio
backend esté en funcionamiento.

Primero, crea el servicio backend del que depende el servidor web:


$ kubectl create deployment backend --image=gcr.io/google-
samples/hello-app:2.0
deployment.apps/backend created
$ kubectl expose deployment backend --port=80 --target-
port=8080
A continuación, puedes utilizar el siguiente manifiesto, nginx-init-
container.yaml, para lanzar la instancia de NGINX y asegurarte de que
sólo se inicie cuando la implementación de backend esté lista para aceptar
conexiones:
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: webserver
image: nginx:1.25.2
ports:
- containerPort: 80
initContainers:
- name: checkbackend
image: busybox:1.36
command: ['sh', '-c', 'until nc -w 5
backend.default.svc.cluster.local
80; do echo
"Waiting for backend to accept connections"; sleep 3;
done; echo
"Backend is up, ready to launch web server"']
Ahora puedes lanzar la implementación de nginx y verificar si el
contenedor init ha hecho su trabajo mirando los registros del pod que está
supervisando:

$ kubectl apply -f nginx-init-container.yaml


deployment.apps/nginx created

$ kubectl get po
NAME READY STATUS RESTARTS
AGE
backend-8485c64ccb-99jdh 1/1 Running 0
4m33s
nginx-779d9fcdf6-2ntpn 1/1 Running 0
32s

$ kubectl logs nginx-779d9fcdf6-2ntpn -c checkbackend


Server: 10.96.0.10
Address: 10.96.0.10:53

Name: backend.default.svc.cluster.local
Address: 10.101.119.67

Backend is up, ready to launch web server


Como puedes ver, el comando del contenedor init ha funcionado como
estaba previsto.

Debate

Los contenedores de inicio son útiles para evitar que tu aplicación se


bloquee mientras espera a que un servicio esté disponible. Por ejemplo, si
estás implementando una aplicación que necesita conectarse a un
servidor de base de datos, puedes configurar un contenedor de inicio que
compruebe y espere a que el servidor de base de datos esté listo antes de
que tu aplicación intente conectarse a él.

Sin embargo, es importante tener en cuenta que Kubernetes técnicamente


puede matar un pod en cualquier momento, incluso después de haberlo
iniciado con éxito. Por tanto, también es importante que incorpores
resiliencia a tu aplicación para que pueda sobrevivir a fallos en otros
servicios dependientes.

12.7 Obtener una Instantánea


Detallada del Estado del Cluster

Problema

Quieres obtener una instantánea detallada del estado general del clúster
con fines de orientación, auditoría o resolución de problemas.
Solución

Utiliza el comando kubectl cluster-info dump. Por ejemplo, para crear un


volcado del estado del cluster en un subdirectorio cluster-state-2023-04-
13, haz lo siguiente:

$ mkdir cluster-state-2023-04-13

$ kubectl cluster-info dump --all-namespaces \


--output-directory=cluster-state-2023-04-13
Cluster info dumped to cluster-state-2023-04-13

$ tree ./cluster-state-2023-04-13
./cluster-state-2023-04-13
├── default
│ ├── daemonsets.json
│ ├── deployments.json
│ ├── es-598664765b-tpw59
│ │ └── logs.txt
│ ├── events.json
│ ├── fluentd-vw7d9
│ │ └── logs.txt
│ ├── jump
│ │ └── logs.txt
│ ├── kibana-5847789b45-bm6tn
│ │ └── logs.txt
...
├── ingress-nginx
│ ├── daemonsets.json
│ ├── deployments.json
│ ├── events.json
│ ├── ingress-nginx-admission-create-7qdjp
│ │ └── logs.txt
│ ├── ingress-nginx-admission-patch-cv6c6
│ │ └── logs.txt
│ ├── ingress-nginx-controller-77669ff58-rqdlq
│ │ └── logs.txt
│ ├── pods.json
│ ├── replicasets.json
│ ├── replication-controllers.json
│ └── services.json
├── kube-node-lease
│ ├── daemonsets.json
│ ├── deployments.json
│ ├── events.json
│ ├── pods.json
│ ├── replicasets.json
│ ├── replication-controllers.json
│ └── services.json
├── kube-public
│ ├── daemonsets.json
│ ├── deployments.json
│ ├── events.json
│ ├── pods.json
│ ├── replicasets.json
│ ├── replication-controllers.json
│ └── services.json
├── kube-system
│ ├── coredns-787d4945fb-9k8pn
│ │ └── logs.txt
│ ├── daemonsets.json
│ ├── deployments.json
│ ├── etcd-minikube
│ │ └── logs.txt
│ ├── events.json
│ ├── kube-apiserver-minikube
│ │ └── logs.txt
│ ├── kube-controller-manager-minikube
│ │ └── logs.txt
│ ├── kube-proxy-x6zdw
│ │ └── logs.txt
│ ├── kube-scheduler-minikube
│ │ └── logs.txt
│ ├── pods.json
│ ├── replicasets.json
│ ├── replication-controllers.json
│ ├── services.json
│ └── storage-provisioner
│ └── logs.txt
├── kubernetes-dashboard
│ ├── daemonsets.json
│ ├── dashboard-metrics-scraper-5c6664855-sztn5
│ │ └── logs.txt
│ ├── deployments.json
│ ├── events.json
│ ├── kubernetes-dashboard-55c4cbbc7c-ntjwk
│ │ └── logs.txt
│ ├── pods.json
│ ├── replicasets.json
│ ├── replication-controllers.json
│ └── services.json
└── nodes.json

30 directories, 66 files
12.8 Añadir nodos trabajadores de
Kubernetes

Problema

Necesitas añadir un nodo trabajador a tu clúster Kubernetes, por ejemplo,


porque quieres aumentar la capacidad de tu clúster.

Solución

Aprovisiona una nueva máquina de la forma que requiera tu entorno


(por ejemplo, en un entorno bare-metal puede que necesites instalar
físicamente un nuevo servidor en un rack, en un entorno de nube pública
necesitas crear una nueva VM, etc.), y luego instala, como demonios, los
tres componentes que forman un nodo trabajador de Kubernetes:

kubelet
Es el gestor del nodo y supervisor de todos los pods,
independientemente de si están controlados por el servidor API o se
ejecutan localmente, como los pods estáticos. Ten en cuenta
que kubelet es el árbitro final de qué pods pueden o no ejecutarse
en un nodo determinado, y se encarga de lo siguiente:
 Informar del estado de los nodos y pods al servidor API
 Ejecutar periódicamente sondas de liveness
 Montar los volúmenes pod y descargar secretos
 Controlar el tiempo de ejecución del contenedor (consulta
lo siguiente)
Tiempo de ejecución del contenedor
Se encarga de descargar las imágenes de los contenedores y de
ejecutarlos. Kubernetes requiere el uso de un tiempo de ejecución
que se ajuste a la Interfaz de Tiempo de Ejecución de Contenedores
(IRC), como cri-o, Docker Engine o containerd.
kube-proxy
Este proceso configura dinámicamente las reglas iptables en el
nodo para habilitar la abstracción del servicio Kubernetes
(redirigiendo el VIP a los endpoints, uno o varios pods que
representan el servicio).

La instalación real de los componentes depende en gran medida de tu


entorno y del método de instalación utilizado (nube, kubeadm, etc.). Para
obtener una lista de las opciones disponibles, consulta
la referencia kubelet y la referenciakube-proxy .
Debate

Los nodos de trabajador, a diferencia de otros recursos de Kubernetes


como las Implementaciones o los servicios, no son creados directamente
por el plano de control de Kubernetes, sino que sólo son gestionados por
él. Esto significa que cuando Kubernetes crea un nodo, en realidad sólo
crea un objeto que representa al nodo trabajador. Valida el nodo
mediante comprobaciones de salud basadas en el
campo metadata.name del nodo, y si el nodo es válido -es decir, todos los
componentes necesarios se están ejecutando- se considera parte del
clúster; de lo contrario, será ignorado para cualquier actividad del clúster
hasta que sea válido.
Ver también

 "Nodos" en los conceptos de arquitectura de clústeres


Kubernetes
 "Comunicación entre los nodos y el plano de control" en la
documentación de Kubernetes
 "Crear pods estáticos" en la documentación de Kubernetes

12.9 Drenaje de nodos Kubernetes para


mantenimiento

Problema

Necesitas realizar tareas de mantenimiento en un nodo, por ejemplo, para


aplicar un parche de seguridad o actualizar el sistema operativo.

Solución

Utiliza el comando kubectl drain. Por ejemplo, haz una lista de nodos
con kubectl get nodes, y luego para hacer mantenimiento en el nodo 123-
worker, haz esto:

$ kubectl drain 123-worker


Cuando estés listo para volver a poner el nodo en servicio, utiliza kubectl
uncordon 123-worker, que hará que el nodo vuelva a ser programable.

Debate

El comando kubectl drain primero marca el nodo especificado como no


programable para evitar que lleguen nuevos pods (esencialmente
un kubectl cordon). Después desaloja los pods si el servidor API admite
el desalojo. En caso contrario, utilizará kubectl delete para eliminar los
pods. Los documentos de Kubernetes contienen un diagrama de secuencia
conciso de los pasos, reproducido en la Figura 12-3.

Figura 12-3. Diagrama de secuencia de drenaje de nodos

El comando kubectl drain desaloja o borra todos los pods excepto los pods
espejo (que no pueden borrarse a través del servidor API). Para los pods
supervisados por un DaemonSet, drain no procederá sin utilizar --ignore-
daemonsets, y a pesar de ello no borrará ningún pod gestionado
por DaemonSet-esos pods serían sustituidos inmediatamente por el
controlador DaemonSet, que ignora las marcas no programables.
ADVERTENCIA

drain espera a la terminación graceful, por lo que no debes operar en este nodo
hasta que el comando kubectl drain haya finalizado. Ten en cuenta
que kubectl drain $NODE --force también desalojará los pods no
gestionados por un ReplicationController, ReplicaSet, Job, DaemonSet,
o StatefulSet.

Ver también

 "Drenar un nodo de forma segura" en la documentación de


Kubernetes
 kubectl drain documentos de referencia
Capítulo 13. Mallas de servicio
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

Este capítulo se centra en uno de los bloques de construcción que


facilitan el desarrollo de aplicaciones distribuidas basadas en
microservicios en Kubernetes: la malla de servicios. Las mallas de
servicios como Istio y Linkerd pueden realizar tareas como el monitoreo,
el descubrimiento de servicios, el control del tráfico y la seguridad, por
nombrar algunas. Al descargar estas responsabilidades en la malla, los
desarrolladores de aplicaciones pueden centrarse en aportar valor
añadido en lugar de reinventar la rueda resolviendo problemas
transversales de infraestructura.

Una de las principales ventajas de las mallas de servicios es que pueden


aplicar políticas a los servicios de forma transparente, sin que los
servicios (cliente y servidor) necesiten saber que forman parte de una
malla de servicios.

En este capítulo, recorreremos ejemplos básicos utilizando tanto Istio


como Linkerd. Para cada malla de servicios, mostraremos cómo puedes
ponerte en marcha rápidamente utilizando Minikube e implementar la
comunicación de servicio a servicio dentro de la malla mientras utilizas
políticas de malla de servicios sencillas pero ilustrativas. En ambos
ejemplos, desplegaremos un servicio basado en NGINX, y nuestro cliente
que invoque al servicio será un pod curl. Ambos se añadirán a la malla y
las interacciones entre los servicios se regirán por la malla.

13.1 Instalar la Malla de Servicios Istio

Problema

Tu organización está utilizando o tiene previsto utilizar una arquitectura


de microservicios , y quieres aligerar la carga de los desarrolladores
descargándoles de la necesidad de crear seguridad, descubrimiento de
servicios, telemetría, estrategias de implementación y otras cuestiones no
funcionales.

Solución
Instala Istio en Minikube. Istio es la malla de servicios más ampliamente
adoptada y puede descargar muchas responsabilidades de los
desarrolladores de microservicios, al tiempo que proporciona a los
operadores un gobierno centralizado sobre la seguridad y las operaciones.

En primer lugar, tendrás que iniciar Minikube con recursos suficientes


para ejecutar Istio. Los requisitos exactos de recursos dependen de tu
plataforma, y puede que tengas que ajustar las asignaciones de recursos.
Nosotros hemos conseguido que funcione con algo menos de 8 GB de
memoria y cuatro CPU:

$ minikube start --memory=7851 --cpus=4


Puedes utilizar un túnel Minikube como equilibrador de carga para
Istio. Para iniciarlo, ejecuta este comando en un nuevo terminal
(bloqueará el terminal para mostrar la información de salida):

$ minikube tunnel
Descarga y extrae la última versión de Istio con el siguiente comando
(Linux y macOS):

$ curl -L https://istio.io/downloadIstio | sh -
Para Windows, puedes instalarlo con choco o simplemente extraer
el .exe del archivo descargable. Para más información sobre la descarga
de Istio, visita la Guía de inicio de Istio.
Cambia al directorio Istio. Puede que tengas que adaptar el nombre del
directorio en función de la versión de Istio que hayas instalado:

$ cd istio-1.18.0
La herramienta de línea de comandos istioctl está diseñada para
ayudar a depurar y diagnosticar tu malla de servicios, y la utilizarás para
comprobar la configuración de Istio en otras recetas. Vive en el
directorio bin, así que añádela a tu ruta de la siguiente manera:
$ export PATH=$PWD/bin:$PATH
Ahora puedes instalar Istio. El siguiente archivo YAML contiene un
ejemplo de configuración de demostración. Desactiva intencionadamente
el uso de Istio como pasarela de entrada o salida, ya que aquí no
utilizaremos Istio para la entrada. Guarda esta configuración en un
archivo llamado istio-demo-config.yaml:

apiVersion: install.istio.io/v1alpha1

kind: IstioOperator

spec:

profile: demo

components:

ingressGateways:

- name: istio-ingressgateway

enabled: false

egressGateways:

- name: istio-egressgateway

enabled: false

Ahora utiliza istioctl para aplicar esta configuración de a Minikube:

$ istioctl install -f istio-demo-config.yaml -y


✔ Istio core installed
✔ Istiod installed
✔ Installation complete
Por último, asegúrate de que Istio está configurado para inyectar
automáticamente proxies sidecar Envoy a los servicios que
implementes. Puedes activar esto para el espacio de nombres
predeterminado con el siguiente comando:
$ kubectl label namespace default istio-injection=enabled
namespace/default labeled
Debate

Esta guía utiliza las versiones por defecto (lo que a veces implica las
últimas) de proyectos subyacentes como Kubernetes e Istio.

Puedes personalizar estas versiones para que coincidan con las versiones
de tu entorno de producción actual, por ejemplo. Para establecer la
versión de Istio que quieres utilizar, utiliza los
parámetros ISTIO_VERSION y TARGET_ARCH cuando descargues Istio. Por
ejemplo

$ curl -L https://istio.io/downloadIstio |
ISTIO_VERSION=1.18.0 \
TARGET_ARCH=x86_64 sh -
Ver también

 La guía oficial de inicio de Istio

13.2 Implementación de un
microservicio con un sidecar Istio

Problema

Quieres implementar un nuevo servicio en la malla de servicios, lo que


implica que se debe inyectar automáticamente un sidecar en el pod del
servicio. El sidecar interceptará todo el tráfico entrante y saliente del
servicio y permitirá implementar políticas de enrutamiento, seguridad y
monitoreo (entre otras) sin modificar la implementación del propio
servicio.

Solución

Utilizaremos NGINX como servicio sencillo con el que trabajar. Empieza


creando una implementaciónpara NGINX:
$ kubectl create deployment nginx --image nginx:1.25.2
deployment.apps/nginx created
A continuación, expón esto como un servicio Kubernetes:

$ kubectl expose deploy/nginx --port 80


service/nginx exposed
NOTA

Istio no crea nuevas entradas DNS en Kubernetes, sino que se basa en los
servicios existentes registrados por Kubernetes o cualquier otro registro de
servicios que puedas estar utilizando. Más adelante en el capítulo, desplegarás
un pod curl que invocará al servicio nginx y establecerá el
host curl en nginx para la resolución DNS, pero entonces Istio hará su magia
interceptando la petición y permitiéndote definir políticas adicionales de control
del tráfico.

Ahora lista los pods en el espacio de nombres por defecto. Deberías tener
dos contenedores en el pod del servicio:

$ kubectl get po
NAME READY STATUS RESTARTS
AGE
nginx-77b4fdf86c-kzqvt 2/2 Running 0
27s
Si investigas los detalles de este pod, descubrirás que el contenedor Istio
sidecar (basado en el proxy Envoy) se inyectó en el pod:

$ kubectl get pods -l app=nginx -o yaml


apiVersion: v1
items:
- apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx
...
spec:
containers:
- image: nginx:1.25.2
imagePullPolicy: IfNotPresent
name: nginx
resources: {}

...
kind: List
metadata:
resourceVersion: ""
Debate

Esta receta asume que has activado la inyección automática de sidecares


en el espacio de nombres mediante la técnica de etiquetado de espacios de
nombres, como se muestra en la Receta 13.1. Sin embargo, puede que no
quieras necesariamente inyectar sidecares en todos y cada uno de los
pods del espacio de nombres. En ese caso, puedes elegir manualmente qué
vainas deben incluir la sidecar y, por tanto, añadirse a la malla. Puedes
obtener más información sobre la inyección manual de sidecares en
la documentación oficial de Istio.
Ver también

 Más información sobre cómo instalar y configurar el sidecar


 Más información sobre el papel de los sidecars en Istio

13.3 Enrutar el tráfico utilizando un


servicio virtual Istio

Problema

Quieres desplegar otro servicio en el clúster que invoque al


servicio nginx que desplegaste antes, pero no quieres escribir ninguna
lógica de enrutamiento o seguridad en los propios servicios. También
quieres desacoplar el cliente y el servidor tanto como sea posible.
Solución

Simularemos la comunicación entre servicios dentro de la malla de


servicios desplegando un pod curl que se añadirá a la malla e invocará al
servicio nginx.
Para desacoplar el pod curl del pod específico que ejecuta nginx, crearás
un servicio virtual Istio. El pod curl sólo necesita conocer el servicio
virtual. Istio y sus sidecars interceptarán y dirigirán el tráfico del cliente
al servicio.
Crea la siguiente especificación de servicio virtual en un archivo
llamado virtualservice.yaml:

apiVersion: networking.istio.io/v1alpha3

kind: VirtualService

metadata:

name: nginx-vs

spec:

hosts:

- nginx

http:

- route:

- destination:

host: nginx

Crea el servicio virtual:

$ kubectl apply -f virtualservice.yaml


A continuación, ejecuta un pod curl que utilizarás para invocar el
servicio. Como has desplegado el pod curl en el espacio de
nombres default y has activado la inyección automática de sidecares en
este espacio de nombres(Receta 13.1), el pod curl obtendrá
automáticamente un sidecar y se añadirá a la malla:
$ kubectl run mycurlpod --image=curlimages/curl -i --tty --
sh
NOTA

Si accidentalmente sales del intérprete de comandos del pod curl, siempre


puedes volver a entrar en el pod con el comando kubectl exec:

$ kubectl exec -i --tty mycurlpod -- sh

Ahora puedes invocar el servicio virtual nginx desde el pod curl:

$ curl -v nginx
* Trying 10.152.183.90:80...
* Connected to nginx (10.152.183.90) port 80 (#0)
> GET / HTTP/1.1
> Host: nginx
> User-Agent: curl/8.1.2
> Accept: */*
>
> HTTP/1.1 200 OK
> server: envoy
...
Verás la respuesta del servicio nginx, pero fíjate en que la cabecera
HTTP server: envoy indica que la respuesta procede en realidad del
sidecar Istio que se ejecuta en el pod nginx.
NOTA

Para hacer referencia a los servicios virtuales desde curl, estamos utilizando
nombres cortos que hacen referencia a los nombres de los servicios de
Kubernetes (nginx en este ejemplo). Bajo el capó, estos nombres se traducen en
nombres de dominio totalmente cualificados,
como nginx.default.svc.cluster.local. Como puedes ver, el nombre
completo incluye un nombre de espacio de nombres (default en este
caso). Para mayor seguridad, en los casos de uso en producción se recomienda
utilizar explícitamente nombres totalmente cualificados para evitar
configuraciones erróneas.

Debate

Esta receta se centraba en la comunicación entre servicios dentro de una


malla de servicios (también conocida como comunicación este-oeste),
que es el punto dulce de esta tecnología. Sin embargo, Istio y otras mallas
de servicios también son capaces de realizar funciones de pasarela
(también conocidas como comunicación de entrada y norte-sur), como
las interacciones entre clientes que se ejecutan fuera de la malla (o del
clúster Kubernetes) y servicios que se ejecutan en la malla.
En el momento de escribir esto, el recurso de pasarela de Istio se está
eliminando gradualmente en favor de la nueva API de pasarela de
Kubernetes.
Ver también

 Documentación de referencia oficial de los servicios virtuales


Istio.
 Más información sobre cómo se espera que la pasarela de API de
Kubernetes sustituya a la pasarela de Istio.

13.4 Reescribir una URL utilizando un


servicio virtual Istio

Problema

Un cliente heredado está utilizando una URL y una ruta para un servicio
que ya no son válidas. Quieres reescribir la ruta dinámicamente para que
el servicio se invoque correctamente, sin tener que hacer cambios en el
cliente.

Puedes simular este problema desde tu pod curl invocando la


ruta /legacypath así, lo que produce una respuesta 404 No encontrado:

$ curl -v nginx/legacypath
* Trying 10.152.183.90:80...
* Connected to nginx (10.152.183.90) port 80 (#0)
> GET /legacypath HTTP/1.1
> Host: nginx
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 404 Not Found
< server: envoy
< date: Mon, 26 Jun 2023 09:37:43 GMT
< content-type: text/html
< content-length: 153
< x-envoy-upstream-service-time: 20
<
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.25.1</center>
</body>
</html>
Solución

Utiliza Istio para reescribir la ruta heredada de modo que llegue a un


punto final válido del servicio, que en nuestro ejemplo será la raíz del
servicio nginx.
Actualiza el servicio virtual para incluir una reescritura HTTP:

apiVersion: networking.istio.io/v1alpha3

kind: VirtualService

metadata:

name: nginx-vs

spec:

hosts:

- nginx

http:

- match:

- uri:

prefix: /legacypath

rewrite:

uri: /

route:
- destination:

host: nginx

- route:

- destination:

host: nginx

Y luego aplica el cambio:

$ kubectl apply -f virtualservice.yaml


El servicio virtual actualizado incluye un atributo match, que buscará la
ruta heredada y la reescribirá para apuntar simplemente al punto final
raíz.
Ahora, las llamadas a la ruta heredada desde el pod curl ya no
producirán un 404, sino un 200 OK:

$ curl -v nginx/legacypath
* Trying 10.152.183.90:80...
* Connected to nginx (10.152.183.90) port 80 (#0)
> GET /legacypath HTTP/1.1
> Host: nginx
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 200 OK
Debate

El papel de los servicios virtuales es principalmente definir el


enrutamiento de los clientes a los servicios ascendentes. Para un control
adicional sobre las peticiones al servicio ascendente, consulta la
documentación de Istio sobre reglas de destino.
Ver también

 Documentación de Istio HTTPRewrite


13.5 Instalar la Malla de Servicios
Linkerd

Problema

Tu proyecto requiere un espacio reducido y/o no necesita todas las


funciones que ofrece Istio, como la compatibilidad con cargas de trabajo
que no sean Kubernetes o la compatibilidad nativa con la salida.

Solución

Quizá te interese probar Linkerd, que se posiciona como una alternativa


más ligera a Istio.

En primer lugar, si estás siguiendo directamente las recetas de Istio,


puedes restablecer tu entorno utilizando un comando como kubectl
delete all --all (¡cuidado, esto eliminará todo de tu clúster!).
A continuación, puedes instalar manualmente Linkerd ejecutando el
siguiente comando y siguiendo las instrucciones del terminal:

$ curl --proto '=https' --tlsv1.2 -sSfL


https://run.linkerd.io/install | sh
La salida del comando anterior incluirá pasos adicionales, como la
actualización de tu PATH, así como otras comprobaciones y comandos de
instalación que son esenciales para completar la instalación de Linkerd. El
siguiente fragmento muestra estas instrucciones en el momento de
escribir estas líneas:

...

Add the linkerd CLI to your path with:

export PATH=$PATH:/Users/jonathanmichaux/.linkerd2/bin
Now run:

linkerd check --pre # validate that


Linkerd can be inst...

linkerd install --crds | kubectl apply -f - # install


the Linkerd CRDs

linkerd install | kubectl apply -f - # install the


control plane into the...

linkerd check # validate


everything worked!

...

Cuando ejecutes el segundo de estos comandos install, es posible que


aparezca un mensaje de error recomendándote que vuelvas a ejecutar ese
comando con un parámetro adicional, comose muestra aquí:

linkerd install --set proxyInit.runAsRoot=true | kubectl


apply -f -

Al final de la instalación, se te pedirá que ejecutes un comando para


comprobar que todo funciona correctamente:

$ linkerd check
...
linkerd-control-plane-proxy
---------------------------
√ control plane proxies are healthy
√ control plane proxies are up-to-date
√ control plane proxies and cli versions match

Status check results are √


También deberías poder ver en los pods de Linkerd que se ejecutan en el
espacio de nombres linkerd:
$ kubectl get pods -n linkerd
NAME READY STATUS
RESTARTS AGE
linkerd-destination-6b8c559b89-rx8f7 4/4 Running
0 9m23s
linkerd-identity-6dd765fb74-52plg 2/2 Running
0 9m23s
linkerd-proxy-injector-f54b7f688-lhjg6 2/2 Running
0 9m22s
Asegúrate de que Linkerd está configurado para inyectar
automáticamente el proxy Linkerd a los servicios que
implementes. Puedes activarlo para el espacio de nombres por defecto
con el siguiente comando:

$ kubectl annotate namespace default


linkerd.io/inject=enabled
namespace/default annotate
Debate

William Morgan, cofundador y director general de Buoyant Inc, fue el


primero en acuñar el término malla de servicios en 2016. Desde
entonces, la comunidad detrás de Linkerd de Bouyant ha mantenido su
enfoque en proporcionar un producto bien dimensionado y de alto
rendimiento.
Como se menciona en el planteamiento del problema, una de las
principales limitaciones de Linkerd que hay que tener en cuenta, en el
momento de escribir esto, es que sólo puede mallar servicios que se
ejecuten en Kubernetes.

Ver también

 La guía oficial de inicio de Linkerd

13.6 Implementación de un servicio en


la malla Linkerd

Problema
Quieres desplegar un servicio en la malla Linkerd e inyectar un sidecar en
su pod.

Solución

Despleguemos el mismo servicio nginx que hicimos con Istio, que


responde a solicitudes HTTP GET en su punto final raíz, y devuelve una
respuesta 404 en los demás.
Empieza creando una implementación para NGINX:

$ kubectl create deployment nginx --image nginx:1.25.2


deployment.apps/nginx created
A continuación, exponlo como un servicio Kubernetes:

$ kubectl expose deploy/nginx --port 80


service/nginx exposed
Ahora lista los pods en el espacio de nombres por defecto. Deberías tener
dos contenedores en el pod del servicio nginx:

$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-748c667d99-fjjm4 2/2 Running 0 13s
Si investigas los detalles de este pod, verás que se inyectaron dos
contenedores Linkerd en el pod. Uno es el contenedor init, que
desempeña un papel en el encaminamiento del tráfico TCP hacia y desde
el pod y que termina antes de que se inicien los otros pods. El otro
contenedor es el propio proxy Linkerd:

$ kubectl describe pod -l app=nginx | grep Image:


Image: cr.l5d.io/linkerd/proxy-init:v2.2.1
Image: cr.l5d.io/linkerd/proxy:stable-2.13.5
Image: nginx
Debate
Al igual que Istio, Linkerd se basa en un proxy sidecar, también conocido
como contenedor embajador, que se inyecta en los pods y proporciona
funcionalidad adicional al servicio que se ejecuta junto a él.
La CLI de Linkerd proporciona el comando linkerd inject como una
forma alternativa útil de decidir dónde y cuándo inyectar el contenedor
proxy de Linkerd en el pod de la aplicación, sin manipular tú mismo las
etiquetas. Puedes leer sobre ello en la documentación de Linkerd.
Ver también

 Más información sobre cómo configurar la inyección lateral


automática
 Más información sobre la arquitectura de Linkerd

13.7 Enrutar el tráfico a un servicio en


Linkerd

Problema

Quieres desplegar un servicio en la malla que invoque al


servicio nginx que desplegaste en la receta anterior, y verificar que
Linkerd y sus sidecars están interceptando y enrutando el tráfico.
Solución

Simularemos la comunicación entre servicios dentro de la malla de


servicios desplegando un pod curl que se añadirá a la malla e invocará al
servicio nginx. Como verás en esta receta, las políticas de enrutamiento
se definen de forma diferente en Linkerd.
En primer lugar, ejecuta un pod curl que utilizarás para invocar el
servicio. Como estás iniciando el pod curl en el espacio de nombres por
defecto y has activado la inyección automática de sidecares en este
espacio de nombres(Receta 13.5), el pod curl obtendrá automáticamente
un sidecar y se añadirá a la malla:

$ kubectl run mycurlpod --image=curlimages/curl -i --tty --


sh
Defaulted container "linkerd-proxy" out of: linkerd-proxy,
mycurlpod,
linkerd-init (init)
error: Unable to use a TTY - container linkerd-proxy did
not allocate one
If you don't see a command prompt, try pressing enter.
NOTA

Como Linkerd modifica la ordenación por defecto de los contenedores en un pod


mallado, el comando anterior run fallará porque intenta entrar en el proxy de
Linkerd, en lugar de en nuestro contenedor curl.
Para evitar este problema, puedes desbloquear el terminal con CTRL-C y luego
ejecutar un comando para conectarte al contenedor correcto utilizando la
bandera -c:

$ kubectl attach mycurlpod -c mycurlpod -i -t

Ahora puedes invocar el servicio nginx desde el pod curl:

$ curl -v nginx
* Trying 10.111.17.127:80...
* Connected to nginx (10.111.17.127) port 80 (#0)
> GET / HTTP/1.1
> Host: nginx
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 200 OK
< server: nginx/1.25.1
...
<
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
NOTA

Verás la respuesta del servicio nginx, pero a diferencia de lo que ocurre con
Istio, todavía no hay indicadores claros de que Linkerd haya interceptadocon
éxito esta petición.

Para empezar a añadir una política de enrutamiento Linkerd al


servicio nginx, define un recurso Linkerd Server en un archivo
llamado linkerd-server.yaml, que se muestra aquí:
apiVersion: policy.linkerd.io/v1beta1

kind: Server

metadata:

name: nginx

labels:

app: nginx

spec:

podSelector:

matchLabels:

app: nginx

port: 80

A continuación, crea el servidor:

$ kubectl apply -f linkerd-server.yaml


server.policy.linkerd.io/nginx created
Ahora, si vuelves a invocar el servicio desde el pod curl, obtendrás la
confirmación de que Linkerd está interceptando esta petición, porque por
defecto rechazará las peticiones a servidores que no tengan una política
de autorización asociada:

$ curl -v nginx
* Trying 10.111.17.127:80...
* Connected to nginx (10.111.17.127) port 80 (#0)
> GET / HTTP/1.1
> Host: nginx
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< l5d-proxy-error: client 10.244.0.24:53274: server:
10.244.0.23:80:
unauthorized request on route
< date: Wed, 05 Jul 2023 20:33:24 GMT
< content-length: 0
<
Debate

Como puedes ver, Linkerd utiliza etiquetas selectoras de pods para


determinar qué pods se rigen por las políticas de la malla. En
comparación, el recurso VirtualService de Istio hace referencia a un
servicio por su nombre directamente.

13.8 Autorizar el tráfico al servidor en


Linkerd

Problema

Has añadido un servicio como nginx a la malla y lo has declarado como


servidor Linkerd, pero ahora recibes respuestas 403 Prohibido porque la
malla requiere autorización por defecto en todos los servidores
declarados.
Solución

Linkerd proporciona diferentes políticas para definir qué clientes pueden


ponerse en contacto con qué servidores. En este ejemplo, utilizaremos un
Linkerd AuthorizationPolicy para especificar qué cuentas de servicio
pueden llamar al servicio nginx.
En tu entorno de desarrollo, el pod curl utiliza la cuenta de
servicio default, a menos que se especifique lo contrario. En producción,
tus servicios tendrían sus propias cuentas de servicio dedicadas.
Empieza creando un archivo llamado linkerd-auth-policy.yaml, como se
muestra aquí:

apiVersion: policy.linkerd.io/v1alpha1

kind: AuthorizationPolicy

metadata:
name: nginx-policy

spec:

targetRef:

group: policy.linkerd.io

kind: Server

name: nginx

requiredAuthenticationRefs:

- name: default

kind: ServiceAccount

Esta política declara que cualquier cliente que utilice la cuenta de


servicio default podrá acceder al servidor Linkerd llamado nginx que
creaste en la receta anterior.
Aplica la política:

$ kubectl apply -f linkerd-auth-policy.yaml


authorizationpolicy.policy.linkerd.io/nginx-policy created
Ahora puedes invocar el servicio nginx desde el pod curl y obtener un
200 OK:

$ curl -v nginx
* Trying 10.111.17.127:80...
* Connected to nginx (10.111.17.127) port 80 (#0)
> GET / HTTP/1.1
> Host: nginx
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 200 OK
...
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Debate

Entre las formas alternativas de controlar el acceso a los servidores están


las políticas basadas en identidad TLS, las políticas basadas en IP, la
referenciación específica de clientes mediante selectores pod, y cualquier
combinación de ellas.

Además, se pueden aplicar políticas por defecto que restrinjan el acceso a


servicios que no estén formalmente referenciados por un recurso
Linkerd Server.
Ver también

 Documentación de la política de autorización de Linkerd


Capítulo 14. Aplicaciones sin servidor y
dirigidas por eventos
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

Sin servidor representa un paradigma nativo de la nube para el


desarrollo, que permite a los desarrolladores crear e implementar
aplicaciones sin la carga de la gestión de servidores. Aunque los
servidores siguen formando parte de la ecuación, la plataforma los
abstrae de las complejidades del desarrollo de aplicaciones.

En este capítulo encontrarás recetas que te mostrarán cómo implementar


cargas de trabajo sin servidor en Kubernetes utilizando la pila Knative.

14.1 Instalación del Operador Knative

Problema

Quieres implementar la plataforma Knative en tu clúster.

Solución

Utilizando el Operador Knative, puedes implementar fácilmente los


componentes de la pila Knative en tu clúster. El operador define recursos
personalizados (CR), permitiéndote configurar, instalar, actualizar y
gestionar fácilmente el ciclo de vida de la pila Knative.
Para instalar la versión 1.11.4 del Operador Knative desde la página de la
versión, haz esto:

$ kubectl apply -f
https://github.com/knative/operator/releases/download/
knative-v1.11.4/operator.yaml
Comprueba que el operador está en marcha:

$ kubectl get deployment knative-operator


NAME READY UP-TO-DATE AVAILABLE AGE
knative-operator 1/1 1 1 13s
Debate

Knative es un proyecto de código abierto que desarrolla componentes


para la implementación, ejecución y gestión de aplicaciones nativas de la
nube sin servidor en Kubernetes. La plataforma consta de dos
componentes principales: Serving y Eventing.
Aunque el Operador Knative es el método preferido para desplegar y
configurar los componentes Knative, alternativamente estos componentes
pueden desplegarse utilizando archivos YAML disponibles en sus
respectivas páginas de lanzamiento.

14.2 Instalar el Componente Servidor


Knative

Problema

Has instalado el Operador Knative (ver Receta 14.1), y ahora quieres


implementar el componente Knative Serving para ejecutar aplicaciones
sin servidor.
Solución

Utiliza el KnativeServing recurso personalizado proporcionado por el


Operador Knative para instalar el componente Servidor de Knative.
Knative Serving debe instalarse en un espacio de nombres
llamado knative-serving:

$ kubectl create ns knative-serving


namespace/knative-serving created
Debes crear un KnativeServing CR, añadir una capa de red y configurar el
DNS. Para la capa de red, utilizaremos Kourier, que es un
objeto Ingress ligero para Knative Serving. Para el DNS, utilizaremos el
servicio DNS de sslip.io.
Crea un archivo llamado serving.yaml con el siguiente contenido:

apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing

metadata:

name: knative-serving

namespace: knative-serving

spec:

ingress:

kourier:

enabled: true

config:

network:

ingress-class:
"kourier.ingress.networking.knative.dev"

Ahora utiliza kubectl para aplicar esta configuración:

$ kubectl apply -f serving.yaml


knativeserving.operator.knative.dev/knative-serving
created
El componente Knative Serving tardará unos minutos en desplegarse
correctamente. Puedes ver el estado de su implementación de la siguiente
manera:

$ kubectl -n knative-serving get KnativeServing knative-


serving -w
NAME VERSION READY REASON
knative-serving 1.11.0 False NotReady
knative-serving 1.11.0 False NotReady
knative-serving 1.11.0 True
Alternativamente, puedes instalar Knative Serving utilizando archivos
YAML:
$ kubectl apply -f
https://github.com/knative/serving/releases/download/
knative-v1.11.0/serving-crds.yaml
$ kubectl apply -f
https://github.com/knative/serving/releases/download/
knative-v1.11.0/serving-core.yaml
Comprueba si al servicio kourier se le ha asignado una dirección IP
externa o CNAME:

$ kubectl -n knative-serving get service kourier


NAME TYPE CLUSTER-IP EXTERNAL-IP
PORT(S) AGE
kourier LoadBalancer 10.99.62.226 10.99.62.226
80:30227/T... 118s
CONSEJO

En un clúster Minikube, ejecuta el comando minikube tunnel en un terminal


para que se asigne al servicio kourier una dirección IP externa.

Por último, configura Knative Serving para que utilice sslip.io como sufijo
DNS:

$ kubectl apply -f
https://github.com/knative/serving/releases/download/
knative-v1.11.0/serving-default-domain.yaml
job.batch/default-domain created
service/default-domain-service created
Debate

El componente Knative Serving habilita la API Serving. Proporciona una


abstracción de alto nivel para la implementación, gestión y autoescalado
de cargas de trabajo sin servidor, centrándose principalmente en
aplicaciones sin estado y basadas en peticiones. Su objetivo es simplificar
el proceso de implementación y gestión de aplicaciones en contenedores
sin servidor, permitiendo a los desarrolladores centrarse en escribir
código sin necesidad de gestionar la infraestructura.

sslip.io es un servicio DNS que te permite acceder fácilmente a tus


aplicaciones implementadas en Knative utilizando nombres de dominio,
sin tener que gestionar registros DNS. Las URL del servicio tendrán el
sufijo sslip.io y cuando se consulte con un nombre de host con una
dirección IP incrustada, el servicio devolverá esa dirección IP.

En entornos de producción, es muy recomendable que configures un DNS


real para las cargas de trabajo implementadas en Knative.
Ver también

 Instalación de Knative
 Configurar DNS

14.3 Instalar la CLI Knative

Problema

Has instalado el Operador Knative(Receta 14.1), y ahora quieres una


forma fácil de gestionar los recursos Knative en lugar de tratar con
archivos YAML.
Solución

Utiliza knla CLI Knative.


Instala el binario kn de la página de publicación de GitHub y muévelo a
tu $PATH. Por ejemplo, para instalar kn v1.8.2 en macOS (Intel), haz lo
siguiente:

$ wget
https://github.com/knative/client/releases/download/knative
-v1.11.0/
kn-darwin-amd64

$ sudo install -m 755 kn-darwin-amd64 /usr/local/bin/kn


Alternativamente, los usuarios de Linux y macOS pueden instalar la CLI
Knative utilizando el gestor de paquetes Homebrew:

$ brew install knative/client/kn


La instalación de kn está ampliamente documentada en la página del
proyecto.
Debate
kn proporciona una forma rápida y sencilla de crear recursos Knative,
como servicios y fuentes de eventos, sin tener que tratar directamente con
archivos YAML. La herramienta kn proporciona una serie de comandos
para gestionar los recursos Knative.
Para obtener una visión general de los comandos disponibles en , haz
esto:

$ kn help
kn is the command line interface for managing Knative
Serving and Eventing

Find more information about Knative at:


https://knative.dev

Serving Commands:
service Manage Knative services
revision Manage service revisions
...

Eventing Commands:
source Manage event sources
broker Manage message brokers
...

Other Commands:
plugin Manage kn plugins
completion Output shell completion code
version Show the version of this client
Encontrarás ejemplos de uso de kn en el resto de este capítulo.

14.4 Crear un Servicio Knative

Problema

Has instalado Knative Serving (ver Receta 14.2) y ahora quieres desplegar
una aplicación en Kubernetes que libere los recursos del clúster cuando
no esté en uso.
Solución

Utiliza la API de servicio Knative para crear un Service Knative que se


reduzca automáticamente a cero cuando no se utilice.
Como ejemplo, vamos a desplegar la aplicación functions/nodeinfo, que
proporciona información sobre el nodo Kubernetes en el que se está
ejecutando. Crea un archivo llamado nodeinfo.yaml para desplegar la
aplicación como Knative Service:

apiVersion: serving.knative.dev/v1

kind: Service

metadata:

name: nodeinfo

spec:

template:

spec:

containers:

- image: functions/nodeinfo:latest

Es importante tener en cuenta que este tipo de servicio no es el mismo


que el objeto Service descrito en la Figura 5-1, sino que este
objeto Service se instancia desde la API de servicio Knative.
Implementa la aplicación con esto:

$ kubectl apply -f nodeinfo.yaml


service.serving.knative.dev/nodeinfo created
Comprueba el estado del servicio con esto:

$ kubectl get ksvc nodeinfo


NAME URL LATESTCREATED
LATESTREADY READY
nodeinfo http://nodeinfo...sslip.io nodeinfo-00001
nodeinfo-00001 True
Cuando el servicio se haya iniciado correctamente, abre la URL en tu
navegador para ver la información del nodo.

Ahora, echa un vistazo a los pods que se crearon para el servicio:

$ kubectl get po -l serving.knative.dev/service=nodeinfo -w


NAME READY STATUS RESTARTS
AGE
nodeinfo-00001-deploy... 0/2 Pending 0 0s
nodeinfo-00001-deploy... 0/2 Pending 0 0s
nodeinfo-00001-deploy... 0/2 ContainerCreating 0
0s
nodeinfo-00001-deploy... 1/2 Running 0
2s
nodeinfo-00001-deploy... 2/2 Running 0
2s
Cierra la ventana del navegador, y al cabo de unos dos minutos deberías
notar que las vainas nodeinfo se reducen automáticamente a cero:

$ kubectl get po -l serving.knative.dev/service=nodeinfo


No resources found in default namespace.
Ahora, si abres la URL en el navegador, se iniciará automáticamente un
nuevo objeto Pod para gestionar la solicitud entrante. Deberías notar un
retraso en la visualización de la página, ya que se crea un nuevo Pod para
gestionar esta petición.
Debate

Utilizando el cliente kn (ver Receta 14.3), puedes crear el servicio sin tener
que escribir archivos YAML:

$ kn service create nodeinfo --image


functions/nodeinfo:latest --port 8080
Creating service 'nodeinfo' in namespace 'default':

0.054s The Route is still working to reflect the latest


desired specification.
0.068s Configuration "nodeinfo" is waiting for a
Revision to become ready.
3.345s ...
3.399s Ingress has not yet been reconciled.
3.481s Waiting for load balancer to be ready
3.668s Ready to serve.

Service 'nodeinfo' created to latest revision 'nodeinfo-


00001' is available at
URL: http://nodeinfo.default.10.96.170.166.sslip.io

14.5 Instalar el Componente de Eventos


Knative

Problema

Has instalado el Operador Knative (ver Receta 14.1), y ahora quieres


implementar el componente Knative Eventing para
crearaplicaciones basadas en eventos.
Solución

Utiliza el KnativeEventing recurso personalizado proporcionado por el


Operador Knative para instalar el componente Eventing de Knative.
Knative Eventing debe instalarse en un espacio de nombres
llamado knative-eventing:

$ kubectl create ns knative-eventing


namespace/knative-eventing created
Crea un archivo llamado eventing.yaml con el siguiente contenido:

apiVersion: operator.knative.dev/v1beta1

kind: KnativeEventing

metadata:

name: knative-eventing

namespace: knative-eventing

Ahora utiliza kubectl para aplicar esta configuración:


$ kubectl apply -f eventing.yaml
knativeeventing.operator.knative.dev/knative-eventing
created
El componente Knative Eventing tardará unos minutos en desplegarse
correctamente. Puedes ver el estado de su implementación de la siguiente
manera:

$ kubectl --namespace knative-eventing get KnativeEventing


knative-eventing -w
NAME VERSION READY REASON
knative-eventing 1.11.1 False NotReady
knative-eventing 1.11.1 False NotReady
knative-eventing 1.11.1 False NotReady
knative-eventing 1.11.1 True
Alternativamente, para instalar Knative Eventing utilizando archivos
YAML, haz esto:

$ kubectl apply -f
https://github.com/knative/eventing/releases/download/
knative-v1.11.1/eventing-crds.yaml
$ kubectl apply -f
https://github.com/knative/eventing/releases/download/
knative-v1.11.1/eventing-core.yaml
Y luego instala el canal en memoria y MTChannelBasedBroker:

$ kubectl apply -f
https://github.com/knative/eventing/releases/download/
knative-v1.11.1/in-memory-channel.yaml
$ kubectl apply -f
https://github.com/knative/eventing/releases/download/
knative-v1.11.1/mt-channel-broker.yaml
Debate

El componente Knative Eventing habilita la API Eventing. Proporciona un


marco para gestionar y manejar eventos dentro de un entorno nativo en
la nube. Los eventos en este contexto se refieren a sucesos o cambios
dentro de un sistema, como la creación de un nuevo recurso,
actualizaciones de recursos existentes o desencadenantes externos. Este
componente permite a los desarrolladores crear aplicaciones reactivas y
flexibles que respondan a cambios y desencadenantes en tiempo real en
todo el ecosistema nativo de la nube.

14.6 Implementación de una fuente de


eventos Knative

Problema

Has instalado Knative Eventing (ver Receta 14.5), y ahora quieres


implementar una fuente que produzca eventos, de modo que puedas
utilizar esos eventos para activar flujos de trabajo en Knative.
Solución

Una fuente de eventos es un recurso personalizado de Kubernetes que


actúa como enlace entre un productor de eventos y un sumidero de
eventos. Para inspeccionar las fuentes de eventos disponibles
actualmente, haz esto:

$ kubectl api-resources --api-group='sources.knative.dev'


NAME SHORTNAMES APIVERSION
NAMESPACED KIND
apiserversources sources.kn...dev/v1 true
ApiServerSource
containersources sources.kn...dev/v1 true
ContainerSource
pingsources sources.kn...dev/v1 true
PingSource
sinkbindings sources.kn...dev/v1 true
SinkBinding
PingSource es una fuente de eventos que genera eventos que contienen
una carga útil fija a intervalos regulares definidos por una programación
cron. Despleguemos un PingSource y enganchémoslo a
un Fregadero llamado sockeye.
Empieza creando el servicio sockeye:
$ kubectl apply -f
https://github.com/n3wscott/sockeye/releases/download/
v0.7.0/release.yaml
service.serving.knative.dev/sockeye created
Comprueba que el servicio sockeye se ha creado correctamente:

$ kubectl get ksvc sockeye


NAME URL LATESTCREATED
LATESTREADY READY
sockeye http://sockeye...sslip.io sockeye-00001
sockeye-00001 True
Crea un archivo llamado pingsource.yaml para crear el PingSource y
conectarlo con la aplicación sockeye:

apiVersion: sources.knative.dev/v1

kind: PingSource

metadata:

name: ping-source

spec:

schedule: "* * * * *"

contentType: "application/json"

data: '{ "message": "Hello, world!" }'

sink:

ref:

apiVersion: serving.knative.dev/v1

kind: Service

name: sockeye
Aplica el manifiesto con esto:

$ kubectl apply -f pingsource.yaml


pingsource.sources.knative.dev/ping-source created
Comprueba que el PingSource se ha creado correctamente:

$ kubectl get pingsource ping-source -w


NAME ... AGE READY REASON
ping-source ... 52s False
MinimumReplicasUnavailable
ping-source ... 59s True
Obtén la URL del servicio sockeye utilizando esto:

$ kubectl get ksvc sockeye -o jsonpath={.status.url}


http://sockeye.default.10.99.62.226.sslip.io
Al abrir la URL en tu navegador web, deberías ver aparecer nuevos
eventos cada minuto, como se muestra en la Figura 14-1.
Figura 14-1. Eventos que aparecen en Sockeye

Debate

Si no quieres escribir archivos YAML, puedes utilizar en su lugar el


cliente kn (ver Receta 14.3).
Crea el servicio sockeye con esto:

$ kn service create sockeye --image


docker.io/n3wscott/sockeye:v0.7.0
A continuación, crea la página PingSource:

$ kn source ping create ping-source --data '{ "message":


"Hello, world!" }' \
--schedule '* * * * *' --sink sockeye
14.7 Habilitar las Fuentes de Eventos
Knative

Problema

Has instalado el componente de Eventos Knative (ver Receta 14.5), y


quieres habilitar las fuentes de eventos Knative que no están habilitadas
por defecto.
Solución

Las fuentes de eventos adicionales desarrolladas por la comunidad


Knative, como las de GitHub, GitLab, Apache Kafka, etc., pueden
configurarse en el recurso personalizado Knative Eventing. Por ejemplo,
para instalar la fuente de eventos de GitHub, actualiza el
archivo eventing.yaml de la Receta 14.5 de la siguiente manera:

apiVersion: operator.knative.dev/v1beta1

kind: KnativeEventing

metadata:

name: knative-eventing

namespace: knative-eventing

spec:

source:

github:

enabled: true

Aplica los cambios con esto:


$ kubectl apply -f eventing.yaml
knativeeventing.operator.knative.dev/knative-eventing
configured
Mira el estado de la actualización:

$ kubectl -n knative-eventing get KnativeEventing knative-


eventing -w
NAME VERSION READY REASON
knative-eventing 1.11.1 False NotReady
knative-eventing 1.11.1 True
Ahora, si inspeccionas las fuentes disponibles, deberías ver la fuente de
eventos GitHubSource:

$ kubectl api-resources --api-group='sources.knative.dev'


NAME APIVERSION
NAMESPACED KIND
apiserversources sources.kn..dev/v1 true
ApiServerSource
containersources sources.kn..dev/v1 true
ContainerSource
githubsources sources.kn..dev/v1alpha1 true
GitHubSource
pingsources sources.kn..dev/v1 true
PingSource
sinkbindings sources.kn..dev/v1 true
SinkBinding
Debate

La fuente de eventos GitHubSource se registra para eventos en una


organización o repositorio de GitHub especificado y activa un nuevo
evento para los tipos de eventos de GitHub seleccionados.
También están disponibles fuentes de eventos de código abierto para
GitLab, Apache Kafka, RabbitMQ, etc.

14.8 Instalar fuentes de eventos desde


TriggerMesh

Problema
Has instalado Knative Eventing (ver Receta 14.5), y ahora quieres instalar
fuentes de eventos de TriggerMesh para tener acceso a fuentes de eventos
de una amplia gama de plataformas y servicios.
Solución

Para instalar la v1.26.0 de TriggerMesh, haz lo siguiente:

$ kubectl apply -f
https://github.com/triggermesh/triggermesh/releases/
download/v1.26.0/triggermesh-crds.yaml
...k8s.io/awscloudwatchlogssources.sources.triggermesh.io
created
...k8s.io/awscloudwatchsources.sources.triggermesh.io
created
...k8s.io/awscodecommitsources.sources.triggermesh.io
create
...

$ kubectl apply -f
https://github.com/triggermesh/triggermesh/releases/
download/v1.26.0/triggermesh.yaml
namespace/triggermesh created
clusterrole.rbac.authorization.k8s.io/triggermesh-
namespaced-admin created
clusterrole.rbac.authorization.k8s.io/triggermesh-
namespaced-edit created
clusterrole.rbac.authorization.k8s.io/triggermesh-
namespaced-view created
...
Puedes inspeccionar las fuentes proporcionadas por la API TriggerMesh
utilizando esto:

$ kubectl api-resources --api-


group='sources.triggermesh.io'
NAME APIVERSION NAMESPACED KIND
awscloudwatchlog... sources.tri... true
AWSCloudWatchLogsSource
awscloudwatchsou... sources.tri... true
AWSCloudWatchSource
awscodecommitsou... sources.tri... true
AWSCodeCommitSource
...
Del mismo modo, puedes listar todos los sumideros proporcionados por la
API TriggerMesh utilizando esto:

$ kubectl api-resources --api-


group='targets.triggermesh.io'
NAME SHORT... APIVERSION NAMESPACED
KIND
awscomprehendtar... targets.tri... true
AWSComprehendTarget
awsdynamodbtarge... targets.tri... true
AWSDynamoDBTarget
awseventbridgeta... targets.tri... true
AWSEventBridgeTarget
...
Debate

TriggerMesh es un software gratuito de código abierto que te permite


crear fácilmente aplicaciones basadas en eventos. TriggerMesh
proporciona fuentes de eventos para una amplia gama de plataformas y
servicios, como AWS, Google Cloud, Azure, Salesforce, Zendesk, etc.
Además de fuentes de eventos, TriggerMesh proporciona componentes
que te permiten transformar los eventos de la nube.
Visita la documentación de TriggerMesh para saber más.
Ver también

 Fuentes TriggerMesh
 Objetivos TriggerMesh
 Transformaciones TriggerMesh
Capítulo 15. Ampliación de Kubernetes
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y
comentarios: [email protected]

Ahora que ya has visto cómo instalar, interactuar y utilizar Kubernetes


para implementar y gestionar aplicaciones, en este capítulo nos
centraremos en adaptar Kubernetes a tus necesidades. Para las recetas de
este capítulo, necesitarás Go instalado y acceso al código fuente de
Kubernetes alojado en GitHub. Mostramos cómo compilar Kubernetes en
su conjunto, y cómo compilar componentes específicos como el
cliente kubectl. También mostramos cómo utilizar Python para hablar
con el servidor API de Kubernetes y cómo ampliar Kubernetes con una
definición de recursos personalizada.

15.1 Compilar desde el código fuente

Problema

Quieres construir tus propios binarios de Kubernetes desde el código


fuente en lugar de descargar los binarios de la versión oficial (ver Receta
2.9) o artefactos de terceros.
Solución

Clona el repositorio Git de Kubernetes y construye desde el código fuente.

Si tu máquina de desarrollo tiene instalado Docker Engine, puedes


utilizar el objetivo quick-release del Makefile raíz, como se muestra
aquí:

$ git clone https://github.com/kubernetes/kubernetes.git


$ cd kubernetes
$ make quick-release
CONSEJO

Esta compilación basada en Docker requiere al menos 8 GB de RAM para


completarse. Asegúrate de que tu demonio Docker tiene acceso a esa cantidad de
memoria. En macOS, accede a las preferencias de Docker para Mac y aumenta la
RAM asignada.

Los binarios se encontrarán en el directorio _output/release-stage, y un


paquete completo estará en el directorio _output/release-tars.
Alternativamente, si tienes un entorno Golang correctamente
configurado, utiliza el objetivo release del Makefile raíz:

$ git clone https://github.com/kubernetes/kubernetes.git


$ cd kubernetes
$ make
Los binarios se ubicarán en el directorio _output/bin.
Ver también

 Las guías para desarrolladores de Kubernetes

15.2 Compilar un componente


específico

Problema

Quieres construir un componente específico de Kubernetes a partir del


código fuente. Por ejemplo, sólo quieres construir el cliente kubectl.
Solución

En lugar de utilizar make quick-release o simplemente make, como se


muestra en la Receta 15.1, utiliza make kubectl.
Hay objetivos en el Makefile raíz para compilar componentes
individuales. Por ejemplo, para compilar kubectl, kubeadm, y kubelet,
haz esto:

$ make kubectl kubeadm kubelet


Los binarios se ubicarán en el directorio _output/bin.
CONSEJO

Para obtener la lista completa de objetivos de compilación Makefile,


ejecuta make help.

15.3 Utilizar un cliente Python para


interactuar con la API de Kubernetes
Problema

Como desarrollador, quieres utilizar Python para escribir scripts que


utilicen la API de Kubernetes.

Solución

Instala el módulo Python kubernetes. Este módulo es la biblioteca cliente


oficial de Python para Kubernetes. Puedes instalar el módulo desde el
código fuente o desde el sitio Python Package Index (PyPi):

$ pip install kubernetes


Con un clúster de Kubernetes accesible mediante tu contexto
predeterminado kubectl, ya estás preparado para utilizar este módulo
de Python para hablar con la API de Kubernetes. Por ejemplo, el siguiente
script Python lista todos los pods e imprime sus nombres:
from kubernetes import client, config

config.load_kube_config()

v1 = client.CoreV1Api()
res = v1.list_pod_for_all_namespaces(watch=False)
for pod in res.items:
print(pod.metadata.name)
La llamada a config.load_kube_config() en este script cargará tus
credenciales de Kubernetes y el punto final desde tu archivo de
configuración kubectl. Por defecto, cargará el punto final del clúster y las
credenciales de tu contexto actual.
Debate

El cliente Python se construye utilizando la especificación OpenAPI de la


API de Kubernetes. Está actualizado y es autogenerado. Todas las API
están disponibles a través de este cliente.

Cada grupo de API corresponde a una clase específica, por lo que para
llamar a un método de un objeto API que forma parte del grupo de
API /api/v1, necesitarás instanciar la clase CoreV1Api. Para utilizar
Implementaciones, tendrás que instanciar la
clase extensionsV1beta1Api. Puedes encontrar todos los métodos y las
instancias de grupo API correspondientes en el README autogenerado.
Ver también

 Ejemplos en el repositorio del proyecto

15.4 Ampliar la API


utilizandodefiniciones de
recursos personalizadas
Problema

Tienes una carga de trabajo personalizada y ninguno de los recursos


existentes, como Deployment, Job, o StatefulSet, se adapta bien. Así
que quieres ampliar la API de Kubernetes con un nuevo recurso que
represente tu carga de trabajo, sin dejar de utilizar kubectl de la forma
habitual.
Solución

Utiliza una definición de recurso personalizada (CRD).


Supongamos que quieres definir un recurso personalizado del
tipo Function. Esto representa un tipo de recurso de corta duración
similar a Job, parecido a lo que ofrece AWS Lambda, que es una función
como servicio (FaaS, o a veces engañosamente llamada "función sin
servidor").
NOTA

Para una solución FaaS lista para producción que se ejecuta en Kubernetes,
consulta el Capítulo 14.

Primero, define el CRD en un archivo de manifiesto llamado functions-


crd.yaml:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: functions.example.com
spec:
group: example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
code:
type: string
ram:
type: string
scope: Namespaced
names:
plural: functions
singular: function
kind: Function
A continuación, informa al servidor API de tu nuevo CRD (el registro
puede tardar varios minutos):

$ kubectl apply -f functions-crd.yaml


customresourcedefinition.apiextensions.k8s.io/
functions.example.com created
Ahora que tienes definido el recurso personalizado Function y que el
servidor de la API lo conoce, puedes instanciarlo utilizando un
manifiesto llamado myfaas.yaml con el siguiente contenido:
apiVersion: example.com/v1
kind: Function
metadata:
name: myfaas
spec:
code: "http://src.example.com/myfaas.js"
ram: 100Mi
Y crea el recurso myfaas del tipo Function como de costumbre:

$ kubectl apply -f myfaas.yaml


function.example.com/myfaas created

$ kubectl get crd functions.example.com -o yaml


apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
creationTimestamp: "2023-05-02T12:12:03Z"
generation: 1
name: functions.example.com
resourceVersion: "2494492251"
uid: 5e0128b3-95d9-412b-b84d-b3fac030be75
spec:
conversion:
strategy: None
group: example.com
names:
kind: Function
listKind: FunctionList
plural: functions
shortNames:
- fn
singular: function
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
properties:
spec:
properties:
code:
type: string
ram:
type: string
type: object
type: object
served: true
storage: true
status:
acceptedNames:
kind: Function
listKind: FunctionList
plural: functions
shortNames:
- fn
singular: function
conditions:
- lastTransitionTime: "2023-05-02T12:12:03Z"
message: no conflicts found
reason: NoConflicts
status: "True"
type: NamesAccepted
- lastTransitionTime: "2023-05-02T12:12:03Z"
message: the initial names have been accepted
reason: InitialNamesAccepted
status: "True"
type: Established
storedVersions:
- v1

$ kubectl describe functions.example.com/myfaas


Name: myfaas
Namespace: triggermesh
Labels: <none>
Annotations: <none>
API Version: example.com/v1
Kind: Function
Metadata:
Creation Timestamp: 2023-05-02T12:13:07Z
Generation: 1
Resource Version: 2494494012
UID: bed83736-6c40-4039-97fb-
2730c7a4447a
Spec:
Code: http://src.example.com/myfaas.js
Ram: 100Mi
Events: <none>
Para descubrir los CRD, basta con acceder al servidor API. Por ejemplo,
utilizando kubectl proxy, puedes acceder localmente al servidor API y
consultar el espacio de claves (example.com/v1 en nuestro caso):

$ curl 127.0.0.1:8001/apis/example.com/v1/ | jq .
{
"kind": "APIResourceList",
"apiVersion": "v1",
"groupVersion": "example.com/v1",
"resources": [
{
"name": "functions",
"singularName": "function",
"namespaced": true,
"kind": "Function",
"verbs": [
"delete",
"deletecollection",
"get",
"list",
"patch",
"create",
"update",
"watch"
],
"shortNames": [
"fn"
],
"storageVersionHash": "FLWxvcx1j74="
}
]
}
Aquí puedes ver el recurso junto con los verbos permitidos.

Cuando quieras deshacerte de tu instancia de recurso personalizado,


simplemente elimínala:
$ kubectl delete functions.example.com/myfaas
function.example.com "myfaas" deleted
Debate

Como has visto, es sencillo crear un CRD. Desde el punto de vista del
usuario final, los CRD presentan una API coherente y son más o menos
indistinguibles de los recursos nativos, como los pods o los jobs. Todos los
comandos habituales, como kubectl get y kubectl delete, funcionan
como se espera.
Sin embargo, crear un CRD es en realidad menos de la mitad del trabajo
necesario para ampliar completamente la API de Kubernetes. Por sí solos,
los CRD sólo te permiten almacenar y recuperar datos personalizados a
través del servidor API en etcd. Necesitas escribir también un controlador
personalizado que interprete los datos personalizados expresando la
intención del usuario, establezca un bucle de control comparando el
estado actual con el estado declarado, e intenteconciliar ambos.
Ver también

 "Ampliar la API de Kubernetes con CustomResourceDefinitions "


en la documentación de Kubernetes
 "Recursos personalizados" en la documentación de Kubernetes
Apéndice. Recursos
General
 Documentación sobre Kubernetes
 Repositorio GitHub de Kubernetes
 Comunidad Kubernetes GitHub
 Comunidad Slack de Kubernetes

Tutoriales y ejemplos
 Kube con el ejemplo
 Juega con Kubernetes
 Kubernetes: Up and Running, Segunda edición, de Brendan
Burns, Joe Beda y Kelsey Hightower (O'Reilly)
Sobre los autores
Sameer Naik es un ingeniero nativo de la nube con experiencia en
sistemas integrados. Ha participado en varios proyectos de código abierto
y fue uno de los primeros en adoptar el proyecto Docker. Es autor de
varias imágenes populares de aplicaciones Docker de código abierto.
Sameer ha participado en el proyecto Kubernetes desde una fase
temprana y es miembro fundador del proyecto de gráficos de Helm.
Sameer trabajó anteriormente en VMware y Bitnami, y es cofundador de
NextBit Computing, una start-up de sistemas embebidos.

Sébastien Goasguen es cofundador de TriggerMesh y un veterano del


código abierto con 20 años de experiencia. Miembro de la Apache
Software Foundation, trabajó en Apache CloudStack y Libcloud durante
varios años antes de sumergirse en el mundo de los contenedores.
Sébastien es también el fundador de Skippbox, una start-up de
Kubernetes adquirida por Bitnami. Como ávido bloguero, disfruta
divulgando las nuevas tecnologías de perímetro. Sébastien es autor de
O'Reilly Docker Cookbook y 60 Recipes for Apache CloudStack.

Jonathan Michaux es gestor de productos, ingeniero de software e


informático, con una carrera que abarca múltiples empresas de nueva
creación y compañías que cotizan en bolsa. Su misión siempre ha girado
en torno a la entrega de herramientas transformadoras para
desarrolladores, incluidos los ámbitos de la gestión de API, la integración
de datos y aplicaciones, los microservicios y, más recientemente, las
aplicaciones impulsadas por eventos en Kubernetes. Es doctor en
informática, especializado en métodos formales para sistemas
concurrentes.

También podría gustarte