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.