Introducción
Kubernetes (o k8s para abreviar) es una plataforma extensible de organización de contenedores de código abierto diseñada para administrar cargas de trabajo en contenedores y servicios a escala. Ayuda con la implementación automatizada, el escalado y la administración de cargas de trabajo de aplicaciones centradas en contenedores en un clúster de nodos (básicos, virtuales o en la nube) mediante la organización de la infraestructura del cálculo, la red y almacenamiento a partir de de esas cargas de trabajo de los usuarios.
Los dos tipos principales de nodos en un clúster de Kubernetes son:
Maestro: este nodo actúa a modo de control para todo el clúster. Es responsable de todas las implementaciones de carga de trabajo de las aplicaciones, planificación y decisiones, así como también de detectar y administrar cambios en el estado de las aplicaciones implementadas. Se compone de un almacén de valores clave, un servidor API, un planificador y un administrador de controladores.
Nodo(s) de trabajo: nodo(s) que realmente ejecutan los contenedores de aplicaciones. También se les conoce en ocasiones como Minion (s). El maestro también es un nodo, pero no está destinado a la implementación de aplicaciones. Se compone de un agente llamado kubelet, un proxy de red llamado kube-proxy y un motor de contenedores.
La siguiente Figura ilustra la descripción de la arquitectura de alto nivel de Kubernetes:
Los componentes básicos que forman un clúster de Kubernetes se describen a continuación:
KV Store: un almacén de datos valor-clave altamente confiable, distribuido y consistente que se utiliza para persistir y mantener información del estado sobre los diversos componentes del clúster de Kubernetes. Por defecto, Kubernetes usa etcd como el almacén de valores clave.
Servidor API: actúa como punto de entrada para el plano de control presentando un punto final API para todas las interacciones con y dentro del clúster de Kubernetes. A través del Servidor API se realizan solicitudes para la implementación, administración, gestión y operación de aplicaciones basadas en contenedores. Utiliza el almacén de valores clave para mantener la información de estado sobre todos los componentes del clúster de Kubernetes.
Pod(s): es la unidad de implementación más pequeña en Kubernetes. Uno o más contenedores se ejecutan dentro. Es algo así como un host lógico con red y almacenamiento compartidos. Los pods de aplicaciones están programados para ejecutarse en diferentes nodos de trabajo del clúster de Kubernetes en función de las necesidades de los recursos y las restricciones de la aplicación. Cada pod dentro del clúster tiene su propia dirección IP única. Los contenedores de aplicaciones dentro de un pod se comunican entre sí mediante localhost. Los Pods también son la unidad más pequeña de escalado en Kubernetes. Los Pod (s) son efímeros: pueden ir y venir en cualquier momento.
Scheduler: responsable de programar los pods de la aplicación para que se ejecuten en los nodos de trabajo seleccionados del clúster de Kubernetes partiendo de los requisitos de los recursos de la aplicación, así como las restricciones de afinidad específicas de la aplicación.
Service: proporciona un punto de red estable y lógico para un grupo de pod (s) (basado en una etiqueta relacionada con un pod de aplicación que se ejecuta en los nodos wor2ker del clúster de Kubernetes. Permiten el acceso a una aplicación a través del service-discovery y distribuyen las solicitudes mediante un simple equilibrio de carga. Para acceder a una aplicación, a cada servicio se le asigna una dirección IP interna:puerto en todo el clúster.
Controller Manager: gestiona diferentes tipos de controladores responsables de supervisar y detectar cambios en el estado del clúster de Kubernetes (a través del servidor API) y garantiza que el clúster cambie al estado deseado. Los diferentes tipos de controladores son:
- Node Controller => responsable de supervisar y detectar el estado y la solidez (arriba o abajo) de los nodos de trabajo en el clúster de Kubernetes.
- ReplicaSet => anteriormente denominado Controlador de replicación y es responsable de mantener el número deseado de réplicas de pod en el clúster.
- Endpoints Controller => responsable de detectar y gestionar cambios en los puntos de acceso al servicio de la aplicación (lista de direcciones IP:puerto).
Plugin Network: actúa como puente (red superpuesta) que permite la comunicación entre los pods que se ejecutan en diferentes nodos de trabajo del clúster. Hay diferentes implementaciones de este componente por parte de terceros como calico, franela, weave-net, etc. Todos ellos deben cumplir con una especificación común llamada Container Network Interface o CNI para abreviar.
kubelet: un agente que se ejecuta en cada nodo de trabajo del clúster de Kubernetes. Es responsable de crear e iniciar un pod de aplicación en el nodo de trabajo y asegurar de que todos los contenedores de aplicaciones estén en funcionamiento dentro del pod. Además, también es responsable de informar del estado y solidez del nodo de trabajo, así como de todos los pods que están en ejecución al maestro a través del servidor API.
kube-proxy: un proxy de red que se ejecuta en cada uno de los nodos de trabajo del clúster de Kubernetes y actúa como un punto de entrada para acceder a los diversos puntos del servicio de aplicaciones. Dirige las solicitudes hacía los pods apropiados dentro del clúster.
Container Engine: un tiempo de ejecución de contenedor que se ejecuta en cada uno de los nodos de trabajo para administrar el ciclo de vida de los contenedores, como obtener las imágenes, iniciar y detener contenedores, etc. El motor de contenedores comúnmente utilizado es Docker.
kubectl: herramienta de línea de comandos utilizada para interactuar con el servidor API. Utilizada por los administradores (u operadores) para la implementación y el escalado de aplicaciones, así como para la gestión del clúster de Kubernetes.
Instalación y configuración del sistema
La instalación la realizaremos en un clúster ODROID-N2 de 5 nodos con Armbian Ubuntu Linux.
La siguiente Figura muestra un clúster ODROID-N2 con 5 nodos en funcionamiento:
Para este tutorial, vamos a suponer que los 5 nodos en el clúster tienen los siguientes nombres de host y direcciones IP:
my-n2-1 192.168.1.51 my-n2-2 192.168.1.52 my-n2-3 192.168.1.53 my-n2-4 192.168.1.54 my-n2-5 192.168.1.55Abra una ventana de Terminal y abre una pestaña para cada uno de los 5 nodos my-n2-1 a través de my-n2-5. En cada una de las pestañas de Terminal, conectate por ssh al nodo correspondiente.
Cada uno de los nodos my-n2-1 hasta my-n2-5 debe tener un identificador único para que el clúster funcione sin conflictos. El identificador de nodo único se encuentra en el archivo /etc/machine-id, vemos que todos los nodos my-n2-1 hasta my-n2-5 tienen el mismo valor. Esto hay que solucionarlo*. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta los siguientes comandos:
$ sudo rm -f /etc/machine-id $ sudo dbus-uuidgen --ensure=/etc/machine-id $ sudo rm /var/lib/dbus/machine-id $ sudo dbus-uuidgen --ensure $ sudo reboot nowUna vez más, en cada una de las pestañas de Terminal, conéctate por ssh al nodo correspondiente.
A continuación, necesitamos configurar el repositorio de paquetes para Docker. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta los siguientes comandos:
$ sudo apt-get update $ sudo apt-get install apt-transport-https ca-certificates curl \ software-properties-common -y $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo \ apt-key add - $ sudo apt-get update $ sudo add-apt-repository "deb [arch=arm64] \ -https://download.docker.com/linux/ubuntu xenial stable" $ sudo apt-get updatePara la versión 1.16 de Kubernetes (la versión en el momento de publicar este artículo), la versión recomendada de Docker es la 18.09.
ATENCIÓN: Para Docker CE 19.xx (y superior) Asegúrate de que la versión de Docker instalada sea * 18.09 *. De lo contrario, te encontrarás con el siguiente error: [ERROR SystemVerification]: unsupported docker version: 19.xx
Necesitamos verificar el último paquete de Docker 18.09 en el repositorio. En cualquiera de los nodos (elegiremos my-n2-1), ejecuta el siguiente comando:
$ apt-cache madison docker-ceEl siguiente sería un resultado típico:
<span style="font-weight: 400;">Output.1</span> <span style="font-weight: 400;">docker-ce | 5:19.03.5~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:19.03.4~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:19.03.3~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:19.03.2~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:19.03.1~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:19.03.0~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.9~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.8~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.7~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.6~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.5~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.4~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.3~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.2~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.1~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 5:18.09.0~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 18.06.3~ce~3-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 18.06.2~ce~3-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 18.06.1~ce~3-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 18.06.0~ce~3-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 18.03.1~ce-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 18.03.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 17.12.1~ce-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 17.12.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 17.09.1~ce-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span> <span style="font-weight: 400;">docker-ce | 17.09.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable arm64 Packages</span>En el resultado anterior, vemos que el último paquete para Docker 18.09 es 5: 18.09.9 ~ 3-0 ~ ubuntu-xenial.
A continuación, necesitamos instalar la versión elegida de Docker. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta el siguiente comando:
$ sudo apt-get install docker-ce=5:18.09.9~3-0~ubuntu-xenial -yEl siguiente sería un resultado típico:
Output.2 Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: aufs-tools cgroupfs-mount containerd.io docker-ce-cli git git-man liberror-perl pigz Suggested packages: git-daemon-run | git-daemon-sysvinit git-doc git-el git-email git-gui gitk gitweb git-cvs git-mediawiki git-svn The following NEW packages will be installed: aufs-tools cgroupfs-mount containerd.io docker-ce docker-ce-cli git git-man liberror-perl pigz 0 upgraded, 9 newly installed, 0 to remove and 0 not upgraded. Need to get 61.3 MB of archives. After this operation, 325 MB of additional disk space will be used. Get:1 https://download.docker.com/linux/ubuntu xenial/stable arm64 containerd.io arm64 1.2.10-3 [14.5 MB] Get:2 http://ports.ubuntu.com/ubuntu-ports bionic/universe arm64 pigz arm64 2.4-1 [47.8 kB] Get:3 http://ports.ubuntu.com/ubuntu-ports bionic/universe arm64 aufs-tools arm64 1:4.9+20170918-1ubuntu1 [101 kB] Get:4 http://ports.ubuntu.com/ubuntu-ports bionic/universe arm64 cgroupfs-mount all 1.4 [6320 B] Get:5 http://ports.ubuntu.com/ubuntu-ports bionic/main arm64 liberror-perl all 0.17025-1 [22.8 kB] Get:6 http://ports.ubuntu.com/ubuntu-ports bionic-updates/main arm64 git-man all 1:2.17.1-1ubuntu0.4 [803 kB] Get:7 http://ports.ubuntu.com/ubuntu-ports bionic-updates/main arm64 git arm64 1:2.17.1-1ubuntu0.4 [2941 kB] Get:8 https://download.docker.com/linux/ubuntu xenial/stable arm64 docker-ce-cli arm64 5:19.03.5~3-0~ubuntu-xenial [29.6 MB] Get:9 https://download.docker.com/linux/ubuntu xenial/stable arm64 docker-ce arm64 5:18.09.9~3-0~ubuntu-xenial [13.3 MB] Fetched 61.3 MB in 5s (11.6 MB/s) Selecting previously unselected package pigz. (Reading database ... 156190 files and directories currently installed.) Preparing to unpack .../0-pigz_2.4-1_arm64.deb ... Unpacking pigz (2.4-1) ... Selecting previously unselected package aufs-tools. Preparing to unpack .../1-aufs-tools_1%3a4.9+20170918-1ubuntu1_arm64.deb ... Unpacking aufs-tools (1:4.9+20170918-1ubuntu1) ... Selecting previously unselected package cgroupfs-mount. Preparing to unpack .../2-cgroupfs-mount_1.4_all.deb ... Unpacking cgroupfs-mount (1.4) ... Selecting previously unselected package containerd.io. Preparing to unpack .../3-containerd.io_1.2.10-3_arm64.deb ... Unpacking containerd.io (1.2.10-3) ... Selecting previously unselected package docker-ce-cli. Preparing to unpack .../4-docker-ce-cli_5%3a19.03.5~3-0~ubuntu-xenial_arm64.deb ... Unpacking docker-ce-cli (5:19.03.5~3-0~ubuntu-xenial) ... Selecting previously unselected package docker-ce. Preparing to unpack .../5-docker-ce_5%3a18.09.9~3-0~ubuntu-xenial_arm64.deb ... Unpacking docker-ce (5:18.09.9~3-0~ubuntu-xenial) ... Selecting previously unselected package liberror-perl. Preparing to unpack .../6-liberror-perl_0.17025-1_all.deb ... Unpacking liberror-perl (0.17025-1) ... Selecting previously unselected package git-man. Preparing to unpack .../7-git-man_1%3a2.17.1-1ubuntu0.4_all.deb ... Unpacking git-man (1:2.17.1-1ubuntu0.4) ... Selecting previously unselected package git. Preparing to unpack .../8-git_1%3a2.17.1-1ubuntu0.4_arm64.deb ... Unpacking git (1:2.17.1-1ubuntu0.4) ... Setting up aufs-tools (1:4.9+20170918-1ubuntu1) ... Setting up git-man (1:2.17.1-1ubuntu0.4) ... Setting up containerd.io (1.2.10-3) ... Created symlink /etc/systemd/system/multi-user.target.wants/containerd.service → /lib/systemd/system/containerd.service. Setting up liberror-perl (0.17025-1) ... Setting up cgroupfs-mount (1.4) ... Setting up docker-ce-cli (5:19.03.5~3-0~ubuntu-xenial) ... Setting up pigz (2.4-1) ... Setting up git (1:2.17.1-1ubuntu0.4) ... Setting up docker-ce (5:18.09.9~3-0~ubuntu-xenial) ... update-alternatives: using /usr/bin/dockerd-ce to provide /usr/bin/dockerd (dockerd) in auto mode Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /lib/systemd/system/docker.service. Created symlink /etc/systemd/system/sockets.target.wants/docker.socket → /lib/systemd/system/docker.socket. Processing triggers for systemd (237-3ubuntu10.33) ... Processing triggers for man-db (2.8.3-2ubuntu0.1) ... Processing triggers for libc-bin (2.27-3ubuntu1) ...A continuación, debemos asegurarnos de que podemos ejecutar los comandos de Docker con el usuario conectado sin la necesidad de sudo. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta los siguientes comandos:
$ sudo usermod -aG docker $USER $ sudo reboot nowUna vez más, en cada una de las pestañas de Terminal, conéctate por ssh al nodo correspondiente.
Para verificar la instalación de Docker, en cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta el siguiente comando:
$ docker infoEl siguiente sería un resultado típico:
Output.3 Client: Debug Mode: false Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 18.09.9 Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: b34a5c8af56e510852c35414db4c1f4fa6172339 runc version: 3e425f80a8c931f88e6d94a8c831b9d5aa481657 init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 4.9.196-meson64 Operating System: Ubuntu 18.04.3 LTS OSType: linux Architecture: aarch64 CPUs: 6 Total Memory: 3.623GiB Name: my-n2-1 ID: QF32:QDZN:IQDM:34HX:NK3C:O3AP:Y6JZ:74DV:XXXL:KCBL:7K5D:36B4 Docker Root Dir: /var/lib/docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false Product License: Community EngineLuego, necesitamos configurar el repositorio de paquetes para Kubernetes. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta los siguientes comandos
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - $ echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list $ sudo apt-get updateA continuación, necesitamos instalar Kubernetes. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta el siguiente comando:
$ sudo apt-get install -y kubeadmEl siguiente sería un resultado típico:
Output.4 Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: conntrack cri-tools ebtables kubectl kubelet kubernetes-cni socat The following NEW packages will be installed: conntrack cri-tools ebtables kubeadm kubectl kubelet kubernetes-cni socat 0 upgraded, 8 newly installed, 0 to remove and 1 not upgraded. Need to get 48.3 MB of archives. After this operation, 280 MB of additional disk space will be used. Get:2 http://ports.ubuntu.com/ubuntu-ports bionic/main arm64 conntrack arm64 1:1.4.4+snapshot20161117-6ubuntu2 [27.3 kB] Get:7 http://ports.ubuntu.com/ubuntu-ports bionic-updates/main arm64 ebtables arm64 2.0.10.4-3.5ubuntu2.18.04.3 [74.2 kB] Get:8 http://ports.ubuntu.com/ubuntu-ports bionic/main arm64 socat arm64 1.7.3.2-2ubuntu2 [322 kB] Get:1 https://packages.cloud.google.com/apt kubernetes-xenial/main arm64 cri-tools arm64 1.13.0-00 [7965 kB] Get:3 https://packages.cloud.google.com/apt kubernetes-xenial/main arm64 kubernetes-cni arm64 0.7.5-00 [5808 kB] Get:4 https://packages.cloud.google.com/apt kubernetes-xenial/main arm64 kubelet arm64 1.16.3-00 [18.5 MB] Get:5 https://packages.cloud.google.com/apt kubernetes-xenial/main arm64 kubectl arm64 1.16.3-00 [8025 kB] Get:6 https://packages.cloud.google.com/apt kubernetes-xenial/main arm64 kubeadm arm64 1.16.3-00 [7652 kB] Fetched 48.3 MB in 5s (9383 kB/s) Selecting previously unselected package conntrack. (Reading database ... 157399 files and directories currently installed.) Preparing to unpack .../0-conntrack_1%3a1.4.4+snapshot20161117-6ubuntu2_arm64.deb ... Unpacking conntrack (1:1.4.4+snapshot20161117-6ubuntu2) ... Selecting previously unselected package cri-tools. Preparing to unpack .../1-cri-tools_1.13.0-00_arm64.deb ... Unpacking cri-tools (1.13.0-00) ... Selecting previously unselected package ebtables. Preparing to unpack .../2-ebtables_2.0.10.4-3.5ubuntu2.18.04.3_arm64.deb ... Unpacking ebtables (2.0.10.4-3.5ubuntu2.18.04.3) ... Selecting previously unselected package kubernetes-cni. Preparing to unpack .../3-kubernetes-cni_0.7.5-00_arm64.deb ... Unpacking kubernetes-cni (0.7.5-00) ... Selecting previously unselected package socat. Preparing to unpack .../4-socat_1.7.3.2-2ubuntu2_arm64.deb ... Unpacking socat (1.7.3.2-2ubuntu2) ... Selecting previously unselected package kubelet. Preparing to unpack .../5-kubelet_1.16.3-00_arm64.deb ... Unpacking kubelet (1.16.3-00) ... Selecting previously unselected package kubectl. Preparing to unpack .../6-kubectl_1.16.3-00_arm64.deb ... Unpacking kubectl (1.16.3-00) ... Selecting previously unselected package kubeadm. Preparing to unpack .../7-kubeadm_1.16.3-00_arm64.deb ... Unpacking kubeadm (1.16.3-00) ... Setting up conntrack (1:1.4.4+snapshot20161117-6ubuntu2) ... Setting up kubernetes-cni (0.7.5-00) ... Setting up cri-tools (1.13.0-00) ... Setting up socat (1.7.3.2-2ubuntu2) ... Setting up ebtables (2.0.10.4-3.5ubuntu2.18.04.3) ... Created symlink /etc/systemd/system/multi-user.target.wants/ebtables.service → /lib/systemd/system/ebtables.service. update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults Setting up kubectl (1.16.3-00) ... Setting up kubelet (1.16.3-00) ... Created symlink /etc/systemd/system/multi-user.target.wants/kubelet.service → /lib/systemd/system/kubelet.service. Setting up kubeadm (1.16.3-00) ... Processing triggers for man-db (2.8.3-2ubuntu0.1) ... Processing triggers for systemd (237-3ubuntu10.33) ...Necesitamos reiniciar todos los nodos. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta el siguiente comando:
$ sudo reboot nowUna vez más, en cada una de las pestañas de Terminal, conéctate por ssh al nodo correspondiente.
Para verificar la instalación de Kubernetes, en cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta el siguiente comando:
$ kubeadm versionEl siguiente sería un resultado típico:
Output.5 kubeadm version: &version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.3", GitCommit:"b3cbbae08ec52a7fc73d334838e18d17e8512749", GitTreeState:"clean", BuildDate:"2019-11-13T11:20:25Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/arm64"}A continuación, debemos asegurarnos de que los paquetes para Docker y Kubernetes no se actualicen en el futuro mediante el proceso de actualización de software. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta el siguiente comando:
$ sudo apt-mark hold kubelet kubeadm kubectl docker-ceEl siguiente sería un resultado típico:
Output.6 kubelet set on hold. kubeadm set on hold. kubectl set on hold. docker-ce set on hold.Por defecto, Docker usa cgroupfs como controlador cgroup. Kubernetes prefiere systemd como controlador cgroup. Necesitamos modificar la configuración del demonio Docker especificando las opciones en un archivo JSON llamado /etc/docker/daemon.json. En cada uno de los nodos my-n2-1 a través de my-n2-5, crea el archivo de configuración /etc/docker/daemon.json con el siguiente contenido:
/etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" }A continuación, debemos reiniciar el demonio Docker para que la configuración surta efecto. En cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta los siguientes comandos:
$ sudo mkdir -p /etc/systemd/system/docker.service.d $ sudo systemctl daemon-reload $ sudo systemctl restart dockerNota: No usar el controlador systemd cgroup provocará el siguiente error: [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
Para verificar que el demonio Docker se inició bien, en cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta el siguiente comando:
$ journalctl -u dockerEl siguiente sería un resultado típico:
Output.7 -- Logs begin at Sat 2019-12-14 21:14:19 EST, end at Sat 2019-12-14 21:49:26 EST. -- Dec 14 21:14:26 my-n2-1 systemd[1]: Starting Docker Application Container Engine... Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.806496732-05:00" level=info msg="systemd-resolved is running, so using resolvconf: /run/systemd/res Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.821800611-05:00" level=info msg="parsed scheme: \"unix\"" module=grpc Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.822661404-05:00" level=info msg="scheme \"unix\" not registered, fallback to default scheme" module Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.824226106-05:00" level=info msg="parsed scheme: \"unix\"" module=grpc Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.824838344-05:00" level=info msg="scheme \"unix\" not registered, fallback to default scheme" module Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.828116839-05:00" level=info msg="ccResolverWrapper: sending new addresses to cc: [{unix:///run/cont Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.828945714-05:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.828101672-05:00" level=info msg="ccResolverWrapper: sending new addresses to cc: [{unix:///run/cont Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.830093104-05:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.832076285-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x400014e610, CONNECT Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.844251802-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x40001343a0, CONNECT Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.846949059-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x40001343a0, READY" Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.851896887-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x400014e610, READY" Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.857097768-05:00" level=info msg="[graphdriver] using prior storage driver: overlay2" Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.886090322-05:00" level=info msg="Graph migration to content-addressability took 0.00 seconds" Dec 14 21:14:27 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:27.893602818-05:00" level=info msg="Loading containers: start." Dec 14 21:14:28 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:28.821256841-05:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0 Dec 14 21:14:29 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:29.134364234-05:00" level=info msg="Loading containers: done." Dec 14 21:14:29 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:29.374311397-05:00" level=info msg="Docker daemon" commit=039a7df graphdriver(s)=overlay2 version=18.0 Dec 14 21:14:29 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:29.376444960-05:00" level=info msg="Daemon has completed initialization" Dec 14 21:14:29 my-n2-1 systemd[1]: Started Docker Application Container Engine. Dec 14 21:14:29 my-n2-1 dockerd[3347]: time="2019-12-14T21:14:29.444607195-05:00" level=info msg="API listen on /var/run/docker.sock" Dec 14 21:49:11 my-n2-1 dockerd[3347]: time="2019-12-14T21:49:11.323542665-05:00" level=info msg="Processing signal 'terminated'" Dec 14 21:49:11 my-n2-1 dockerd[3347]: time="2019-12-14T21:49:11.328379659-05:00" level=info msg="stopping event stream following graceful shutdown" error="" m Dec 14 21:49:11 my-n2-1 systemd[1]: Stopping Docker Application Container Engine... Dec 14 21:49:11 my-n2-1 systemd[1]: Stopped Docker Application Container Engine. Dec 14 21:49:11 my-n2-1 systemd[1]: Starting Docker Application Container Engine... Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.499488062-05:00" level=info msg="systemd-resolved is running, so using resolvconf: /run/systemd/res Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.502141612-05:00" level=info msg="parsed scheme: \"unix\"" module=grpc Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.502209240-05:00" level=info msg="scheme \"unix\" not registered, fallback to default scheme" module Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.502278577-05:00" level=info msg="parsed scheme: \"unix\"" module=grpc Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.502295786-05:00" level=info msg="scheme \"unix\" not registered, fallback to default scheme" module Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.505887217-05:00" level=info msg="ccResolverWrapper: sending new addresses to cc: [{unix:///run/cont Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.506035600-05:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.506181190-05:00" level=info msg="ccResolverWrapper: sending new addresses to cc: [{unix:///run/cont Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.506446245-05:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.506671465-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x40007a2230, CONNECT Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.506255319-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x40008b0710, CONNECT Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.509814706-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x40008b0710, READY" Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.511738887-05:00" level=info msg="pickfirstBalancer: HandleSubConnStateChange: 0x40007a2230, READY" Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.525913142-05:00" level=info msg="Graph migration to content-addressability took 0.00 seconds" Dec 14 21:49:11 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:11.529808838-05:00" level=info msg="Loading containers: start." Dec 14 21:49:12 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:12.258591473-05:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0 Dec 14 21:49:12 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:12.540886055-05:00" level=info msg="Loading containers: done." Dec 14 21:49:12 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:12.614462758-05:00" level=info msg="Docker daemon" commit=039a7df graphdriver(s)=overlay2 version=18.0 Dec 14 21:49:12 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:12.614718313-05:00" level=info msg="Daemon has completed initialization" Dec 14 21:49:12 my-n2-1 dockerd[9629]: time="2019-12-14T21:49:12.640530153-05:00" level=info msg="API listen on /var/run/docker.sock" Dec 14 21:49:12 my-n2-1 systemd[1]: Started Docker Application Container Engine.A continuación, debemos deshabilitar el intercambio basado en disco. Para ello necesitamos realizar dos cosas.
Primer paso, en cada uno de los nodos my-n2-1 a través de my-n2-5, edita el archivo /etc/default/armbian-zram-config y cambia la línea ENABLED=true por ENABLED=false.
Segundo paso, en cada uno de los nodos my-n2-1 a través de my-n2-5, ejecuta los siguientes comandos:
$ sudo systemctl disable armbian-zram-config $ sudo reboot nowUna vez más, en cada una de las pestañas de Terminal, conéctate por ssh al nodo correspondiente.
Esto completa la instalación y la configuración del sistema de los nodos del clúster. Próxima parada: configuración de Kubernetes
Configuración de Kubernetes
Para empezar, designaremos el nodo my-n2-1 como nodo maestro y configuraremos el plano de control. Para hacer esto, ejecuta el siguiente comando en my-n2-1:
$ sudo kubeadm initEl siguiente sería un resultado típico:
Output.8 [init] Using Kubernetes version: v1.16.3 [preflight] Running pre-flight checks [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Starting the kubelet [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [my-n2-1 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.1.51] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [my-n2-1 localhost] and IPs [192.168.1.51 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [my-n2-1 localhost] and IPs [192.168.1.51 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" W1215 11:58:08.359442 4811 manifests.go:214] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC" [control-plane] Creating static Pod manifest for "kube-scheduler" W1215 11:58:08.366477 4811 manifests.go:214] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [apiclient] All control plane components are healthy after 25.513764 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.17" in namespace kube-system with the configuration for the kubelets in the cluster [upload-certs] Skipping phase. Please see --upload-certs [mark-control-plane] Marking the node my-n2-1 as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node my-n2-1 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: zcp5a6.w03lcuhx068wvkqv [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy¡Tu plano de control Kubernetes se ha iniciado con éxito!
Para empezar a usar tu clúster, debes ejecutar lo siguiente como usuario normal:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/configAhora debe implementar una red pod en el clúster. Ejecuta "kubectl apply -f [podnetwork] .yaml" con una de las opciones listadas en: https://kubernetes.io/docs/concepts/cluster-administration/addons/
Luego puedes unir cualquier número de nodos de trabajo ejecutando lo siguiente en cada uno como root:
kubeadm join 192.168.1.51:6443 --token zcp5a6.w03lcuhx068wvkqv \ --discovery-token-ca-cert-hash sha256:d2e38957f46a9eb089671924bca78ac4e02cdcc8db27e89677a014fe587b67c6
Para utilizar la herramienta de comandos kubectl como usuario no root en el nodo maestro (my-n2-1), ejecuta los siguientes comandos en my-n2-1:
$ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/configPara hacer una lista de todos los nodos en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get nodesEl siguiente sería un resultado típico:
Output.9 NAME STATUS ROLES AGE VERSION My-n2-1 NotReady master 2m37s v1.16.3Para verificar que el clúster de Kubernetes se haya iniciado correctamente, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get pods -n kube-system -o wideLo siguiente sería un resultado típico
Output.10 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES coredns-6955765f44-4gk4f 1/1 Running 0 40m 10.32.0.3 my-n2-1 coredns-6955765f44-wskl4 1/1 Running 0 40m 10.32.0.2 my-n2-1 etcd-my-n2-1 1/1 Running 0 40m 192.168.1.51 my-n2-1 kube-apiserver-my-n2-1 1/1 Running 0 40m 192.168.1.51 my-n2-1 kube-controller-manager-my-n2-1 1/1 Running 0 40m 192.168.1.51 my-n2-1 kube-proxy-tklp7 1/1 Running 0 40m 192.168.1.51 my-n2-1 kube-scheduler-my-n2-1 1/1 Running 0 40m 192.168.1.51 my-n2-1En el resultado anterior, podemos ver que todos los componentes principales (servidor api, administrador de controladores, etc. y planificador) se encutran funcionando.
Ahora, necesitamos instalar una red de plugins superpuesta para la comunicación entre pod. Para nuestro clúster, elegiremos la implementación weave-net. Para instalar la red superpuesta en el nodo maestro (my-n2-1), ejecuta el siguiente comando:
$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"El siguiente sería un resultado típico:
Output.11 serviceaccount/weave-net created clusterrole.rbac.authorization.k8s.io/weave-net created clusterrolebinding.rbac.authorization.k8s.io/weave-net created role.rbac.authorization.k8s.io/weave-net created rolebinding.rbac.authorization.k8s.io/weave-net created daemonset.apps/weave-net createdPara verificar que la red de superposición Weave se ha iniciado correcatente, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get pods -n kube-system -l name=weave-net -o wideEl siguiente sería un resultado típico:
Output.12 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES weave-net-2sjh4 2/2 Running 0 10m 192.168.1.51 my-n2-1Además, para verificar los registros de la red de superposición Weave, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl logs -n kube-system weave-net-ktjnv weaveEl siguiente sería un resultado típico:
Output.13 INFO: 2019/12/08 17:07:12.422554 Command line options: map[conn-limit:200 datapath:datapath db-prefix:/weavedb/weave-net docker-api: expect-npc:true host-root:/host http-addr:127.0.0.1:6784 ipalloc-init:consensus=0 ipalloc-range:10.32.0.0/12 metrics-addr:0.0.0.0:6782 name:9a:59:d0:9a:83:f0 nickname:my-n2-1 no-dns:true port:6783] INFO: 2019/12/08 17:07:12.422876 weave 2.6.0 INFO: 2019/12/08 17:07:12.780249 Bridge type is bridged_fastdp INFO: 2019/12/08 17:07:12.780350 Communication between peers is unencrypted. INFO: 2019/12/08 17:07:12.804023 Our name is 9a:59:d0:9a:83:f0(my-n2-1) INFO: 2019/12/08 17:07:12.804267 Launch detected - using supplied peer list: [] INFO: 2019/12/08 17:07:12.844222 Unable to fetch ConfigMap kube-system/weave-net to infer unique cluster ID INFO: 2019/12/08 17:07:12.844324 Checking for pre-existing addresses on weave bridge INFO: 2019/12/08 17:07:12.853900 [allocator 9a:59:d0:9a:83:f0] No valid persisted data INFO: 2019/12/08 17:07:12.866497 [allocator 9a:59:d0:9a:83:f0] Initialising via deferred consensus INFO: 2019/12/08 17:07:12.866684 Sniffing traffic on datapath (via ODP) INFO: 2019/12/08 17:07:12.872570 Listening for HTTP control messages on 127.0.0.1:6784 INFO: 2019/12/08 17:07:12.873074 Listening for metrics requests on 0.0.0.0:6782 INFO: 2019/12/08 17:07:13.540248 [kube-peers] Added myself to peer list &{[{9a:59:d0:9a:83:f0 my-n2-1}]} DEBU: 2019/12/08 17:07:13.558983 [kube-peers] Nodes that have disappeared: map[] INFO: 2019/12/08 17:07:13.661165 Assuming quorum size of 1 10.32.0.1 DEBU: 2019/12/08 17:07:13.911144 registering for updates for node delete eventsPara este tutorial, designamos que los nodos my-n2-2 a través de my-n2-5 sean los nodos de trabajo de este clúster de Kubernetes. En el resultado 8, podemos determinar el comando de combinación kubeadm para usar en cada nodo de trabajo. Para cada uno de los nodos my-n2-2 a través de my-n2-5 (en su respectiva pestaña Terminal), ejecuta el siguiente comando:
$ sudo kubeadm join 192.168.1.51:6443 --token zcp5a6.w03lcuhx068wvkqv --discovery-token-ca-cert-hash sha256:d2e38957f46a9eb089671924bca78ac4e02cdcc8db27e89677a014fe587b67c6El siguiente sería un resultado típico:
Output.14 [preflight] Running pre-flight checks [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.17" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...Este nodo se ha unido al clúster: * Se envió una solicitud de firma de certificado a un servidor y se recibió una respuesta. * El Kubelet ha sido informado de los nuevos detalles de conexión segura.
Ejecuta 'kubectl get node' en el plano de control para ver como este nodo se une al clúster.
Para hacer una relación de todos los nodos activos en este clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1) (después de esperar unos 30 segundos):
$ kubectl get nodes -o wideEl siguiente sería un resultado típico:
Output.15 NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME my-n2-1 Ready master 51m v1.17.0 192.168.1.51 Ubuntu 18.04.3 LTS 4.9.196-meson64 docker://18.9.9 my-n2-2 Ready 2m58s v1.17.0 192.168.1.52 Ubuntu 18.04.3 LTS 4.9.196-meson64 docker://18.9.9 my-n2-3 Ready 2m38s v1.17.0 192.168.1.53 Ubuntu 18.04.3 LTS 4.9.196-meson64 docker://18.9.9 my-n2-4 Ready 2m35s v1.17.0 192.168.1.54 Ubuntu 18.04.3 LTS 4.9.196-meson64 docker://18.9.9 my-n2-5 Ready 2m21s v1.17.0 192.168.1.55 Ubuntu 18.04.3 LTS 4.9.196-meson64 docker://18.9.9¡Eso es! Esto completa toda la configuración necesaria para este clúster de Kubernetes.
Práctica con Kubernetes
Para hacer un lista de todos los pod (s) que se ejecutan en el clúster de Kubernetes (incluidos los pods del sistema), ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get pods --all-namespaces -o wideEl siguiente sería un resultado típico:
Output.16 NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES kube-system coredns-6955765f44-4gk4f 1/1 Running 0 52m 10.32.0.3 my-n2-1 kube-system coredns-6955765f44-wskl4 1/1 Running 0 52m 10.32.0.2 my-n2-1 kube-system etcd-my-n2-1 1/1 Running 0 52m 192.168.1.51 my-n2-1 kube-system kube-apiserver-my-n2-1 1/1 Running 0 52m 192.168.1.51 my-n2-1 kube-system kube-controller-manager-my-n2-1 1/1 Running 0 52m 192.168.1.51 my-n2-1 kube-system kube-proxy-9zxfj 1/1 Running 0 3m36s 192.168.1.55 my-n2-5 kube-system kube-proxy-c7mns 1/1 Running 0 3m53s 192.168.1.53 my-n2-3 kube-system kube-proxy-dv52p 1/1 Running 0 4m13s 192.168.1.52 my-n2-2 kube-system kube-proxy-mpwkb 1/1 Running 0 3m50s 192.168.1.54 my-n2-4 kube-system kube-proxy-tklp7 1/1 Running 0 52m 192.168.1.51 my-n2-1 kube-system kube-scheduler-my-n2-1 1/1 Running 0 52m 192.168.1.51 my-n2-1 kube-system weave-net-2sjh4 2/2 Running 0 21m 192.168.1.51 my-n2-1 kube-system weave-net-68lcd 2/2 Running 0 3m50s 192.168.1.54 my-n2-4 kube-system weave-net-7fh98 2/2 Running 1 4m13s 192.168.1.52 my-n2-2 kube-system weave-net-krdtz 2/2 Running 1 3m36s 192.168.1.55 my-n2-5 kube-system weave-net-ljm6k 2/2 Running 0 3m53s 192.168.1.53 my-n2-3Como es evidente en el resultado 16 anterior, vemos una entrada para API Server, etcd, Controller Manager, Scheduler y Plugin Network (weave-net) que indica que están en funcionamiento.
Para mostrar información detallada sobre cualquier pod (digamos el Controller Manager) en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl describe pod kube-controller-manager-my-n2-1 -n kube-systemEl siguiente sería un resultado típico:
Output.17 Name: kube-controller-manager-my-n2-1 Namespace: kube-system Priority: 2000000000 Priority Class Name: system-cluster-critical Node: my-n2-1/192.168.1.51 Start Time: Sun, 15 Dec 2019 11:58:39 -0500 Labels: component=kube-controller-manager tier=control-plane Annotations: kubernetes.io/config.hash: 536dc7132dfd0d2ca1d968c9ede1e024 kubernetes.io/config.mirror: 536dc7132dfd0d2ca1d968c9ede1e024 kubernetes.io/config.seen: 2019-12-15T11:58:35.86446527-05:00 kubernetes.io/config.source: file Status: Running IP: 192.168.1.51 IPs: IP: 192.168.1.51 Controlled By: Node/my-n2-1 Containers: kube-controller-manager: Container ID: docker://63b0d105457f52849afa38d2e914b53e68b7e21786fc41cda322bb21bc5b86a4 Image: k8s.gcr.io/kube-controller-manager:v1.17.0 Image ID: docker-pullable://k8s.gcr.io/kube-controller-manager@sha256:0438efb5098a2ca634ea8c6b0d804742b733d0d13fd53cf62c73e32c659a3c39 Port: Host Port: Command: kube-controller-manager --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/etc/kubernetes/pki/ca.crt --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt --cluster-signing-key-file=/etc/kubernetes/pki/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=true --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt --root-ca-file=/etc/kubernetes/pki/ca.crt --service-account-private-key-file=/etc/kubernetes/pki/sa.key --use-service-account-credentials=true State: Running Started: Sun, 15 Dec 2019 11:58:22 -0500 Ready: True Restart Count: 0 Requests: cpu: 200m Liveness: http-get https://127.0.0.1:10257/healthz delay=15s timeout=15s period=10s #success=1 #failure=8 Environment: Mounts: /etc/ca-certificates from etc-ca-certificates (ro) /etc/kubernetes/controller-manager.conf from kubeconfig (ro) /etc/kubernetes/pki from k8s-certs (ro) /etc/ssl/certs from ca-certs (ro) /usr/libexec/kubernetes/kubelet-plugins/volume/exec from flexvolume-dir (rw) /usr/local/share/ca-certificates from usr-local-share-ca-certificates (ro) /usr/share/ca-certificates from usr-share-ca-certificates (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: ca-certs: Type: HostPath (bare host directory volume) Path: /etc/ssl/certs HostPathType: DirectoryOrCreate etc-ca-certificates: Type: HostPath (bare host directory volume) Path: /etc/ca-certificates HostPathType: DirectoryOrCreate flexvolume-dir: Type: HostPath (bare host directory volume) Path: /usr/libexec/kubernetes/kubelet-plugins/volume/exec HostPathType: DirectoryOrCreate k8s-certs: Type: HostPath (bare host directory volume) Path: /etc/kubernetes/pki HostPathType: DirectoryOrCreate kubeconfig: Type: HostPath (bare host directory volume) Path: /etc/kubernetes/controller-manager.conf HostPathType: FileOrCreate usr-local-share-ca-certificates: Type: HostPath (bare host directory volume) Path: /usr/local/share/ca-certificates HostPathType: DirectoryOrCreate usr-share-ca-certificates: Type: HostPath (bare host directory volume) Path: /usr/share/ca-certificates HostPathType: DirectoryOrCreate QoS Class: Burstable Node-Selectors: < none > Tolerations: :NoExecute Events: < none >Para hacer una relación de todos los pod(s) de aplicación que se ejecutan en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get podsEl siguiente sería un resultado típico:
Output.18 No resources found in default namespace.Para hacer una lista de todos los servicios que se ejecutan en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get servicesEl siguiente sería un resultado típico:
Output.19 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 64mCrearemos una simple aplicación web Python para mostrar el nombre del host, así como la dirección IP cuando se invoque a través de HTTP. El siguiente contenido pertenece a la aplicación web Python almacenada en el directorio /tmp en el nodo maestro (my-n2-1):
web-echo.py from flask import Flask import socket app = Flask(__name__) @app.route("/") def index(): host_name = socket.gethostname() host_ip = socket.gethostbyname(host_name) return 'Hello from container -> ' + host_name + ' [' + host_ip + ']' if __name__ == "__main__": app.run(host='0.0.0.0', port=8888)El siguiente es el contenido de Dockerfile para crear una imagen Docker para la simple aplicación web de Python almacenada en el directorio /tmp en el nodo maestro (my-n2-1):
Dockerfile FROM python:3.7.5-alpine3.9 RUN pip install flask ADD web-echo.py /web-echo.py CMD ["python", "/web-echo.py"]Para crear una imagen de Docker llamada py-web-echo con la etiqueta v1.0, ejecuta los siguientes comandos en el nodo maestro (my-n2-1):
cd /tmp docker build -t "py-web-echo:v1.0" .El siguiente sería un resultado típico:
Output.20 Sending build context to Docker daemon 3.072kB Step 1/4: FROM python:3.7.5-alpine3.9 3.7.5-alpine3.9: Pulling from library/python 0362ad1dd800: Pull complete 9b941924aae3: Pull complete fd7b3613915d: Pull complete 078d60b9b97e: Pull complete 7059e1dd9bc4: Pull complete Digest: sha256:064d9ce3e91a59535c528bc3c38888023791d9fc78ba9e5070f5064833f326ff Status: Downloaded newer image for python:3.7.5-alpine3.9 ---> 578ec6233872 Step 2/4: RUN pip install flask ---> Running in d248e23dd161 Collecting flask Downloading https://files.pythonhosted.org/packages/9b/93/628509b8d5dc749656a9641f4caf13540e2cdec85276964ff8f43bbb1d3b/Flask-1.1.1-py2.py3-none-any.whl (94kB) Collecting Jinja2>=2.10.1 Downloading https://files.pythonhosted.org/packages/65/e0/eb35e762802015cab1ccee04e8a277b03f1d8e53da3ec3106882ec42558b/Jinja2-2.10.3-py2.py3-none-any.whl (125kB) Collecting Werkzeug>=0.15 Downloading https://files.pythonhosted.org/packages/ce/42/3aeda98f96e85fd26180534d36570e4d18108d62ae36f87694b476b83d6f/Werkzeug-0.16.0-py2.py3-none-any.whl (327kB) Collecting itsdangerous>=0.24 Downloading https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl Collecting click>=5.1 Downloading https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl (81kB) Collecting MarkupSafe>=0.23 Downloading https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz Building wheels for collected packages: MarkupSafe Building wheel for MarkupSafe (setup.py): started Building wheel for MarkupSafe (setup.py): finished with status 'done' Created wheel for MarkupSafe: filename=MarkupSafe-1.1.1-cp37-none-any.whl size=12629 sha256=8a200864ca113d03b4de2d951ae4a1d0806a3ff84128349770dfe3fb018a6458 Stored in directory: /root/.cache/pip/wheels/f2/aa/04/0edf07a1b8a5f5f1aed7580fffb69ce8972edc16a505916a77 Successfully built MarkupSafe Installing collected packages: MarkupSafe, Jinja2, Werkzeug, itsdangerous, click, flask Successfully installed Jinja2-2.10.3 MarkupSafe-1.1.1 Werkzeug-0.16.0 click-7.0 flask-1.1.1 itsdangerous-1.1.0 Removing intermediate container d248e23dd161 ---> 4ee40e66a655 Step 3/4: ADD web-echo.py /web-echo.py ---> 31a0341bf9d7 Step 4/4: CMD ["python", "/web-echo.py"] ---> Running in 1ee52ea10ad3 Removing intermediate container 1ee52ea10ad3 ---> 7cd037d24ef7 Successfully built 7cd037d24ef7 Successfully tagged py-web-echo:v1.0Para hacer una relación de todas las imágenes de Docker en el nodo maestro (my-n2-1), ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ docker imagesEl siguiente sería un resultado típico:
Output.21 REPOSITORY TAG IMAGE ID CREATED SIZE py-web-echo v1.0 7cd037d24ef7 3 minutes ago 119MB k8s.gcr.io/kube-proxy v1.17.0 ac19e9cffff5 7 days ago 114MB k8s.gcr.io/kube-apiserver v1.17.0 aca151bf3e90 7 days ago 166MB k8s.gcr.io/kube-controller-manager v1.17.0 7045158f92f8 7 days ago 156MB k8s.gcr.io/kube-scheduler v1.17.0 0d5c120f87f3 7 days ago 93.7MB python 3.7.5-alpine3.9 578ec6233872 4 weeks ago 109MB weaveworks/weave-npc 2.6.0 1c672c2f5870 5 weeks ago 36.6MB weaveworks/weave-kube 2.6.0 81393394d17d 5 weeks ago 111MB k8s.gcr.io/coredns 1.6.5 f96217e2532b 5 weeks ago 39.3MB k8s.gcr.io/etcd 3.4.3-0 ab707b0a0ea3 7 weeks ago 363MB k8s.gcr.io/pause 3.1 6cf7c80fe444 24 months ago 525kBTen en cuenta que creamos la imagen de Docker en el nodo maestro (my-n2-1). Dado que los pods se implementarán en los nodos de trabajo, debemos asegurarnos de que las imágenes docker necesarias estén presentes en los nodos de trabajo.
Para cada uno de los nodos de trabajo my-n2-2 hasta my-n2-5 (en su respectiva pestaña Terminal), ejecuta el siguiente comando:
$ docker pull python:3.7.5-alpine3.9Para cada uno de los nodos de trabajo my-n2-2 a través de my-n2-5, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ docker save py-web-echo:v1.0 | bzip2 | ssh polarsparc@192.168.1.52 'bunzip2 | docker load' $ docker save py-web-echo:v1.0 | bzip2 | ssh polarsparc@192.168.1.53 'bunzip2 | docker load' $ docker save py-web-echo:v1.0 | bzip2 | ssh polarsparc@192.168.1.54 'bunzip2 | docker load' $ docker save py-web-echo:v1.0 | bzip2 | ssh polarsparc@192.168.1.55 'bunzip2 | docker load'!!! AVISO IMPORTANTE !!!
No tener las imágenes de Docker en los nodos de trabajo hará que los pod se queden atascados en el estado de creación de los contenedores.
En Kubernetes, un pod es lo que encapsula los contenedores Docker. Para implementar nuestra aplicación web Docker py-web-echo:v1.0 en nuestro clúster de Kubernetes, necesitamos un archivo manifiesto de pod en formato YAML.
Los siguientes son los contenidos del archivo manifiesto del pod llamado web-echo-pod.yaml almacenado en el directorio /tmp en el nodo maestro (my-n2-1):
web-echo-pod.yaml --- apiVersion: v1 kind: Pod metadata: name: web-echo-pod labels: app: web-echo spec: containers: - name: web-echo image: py-web-echo:v1.0 imagePullPolicy: Never ports: - containerPort: 8888A continuación explicaremos los elementos del archivo de manifiesto web-echo-pod.yaml:
- apiVersion: especifica la versión de la API (v1 en este ejemplo)
- kind: especifica el tipo de objeto Kubernetes a utilizar (Pod en este ejemplo)
- metadata: asocia un nombre (web-echo-pod en este ejemplo) con el tipo de objeto Kubernetes. Además, permite marcar algunas etiquetas, que son simples pares clave-valor, con los Kubernetes.
- object. En este ejemplo, tenemos una etiqueta con la aplicación clave que tiene un valor de web-echo
- spec: especifica lo que hay en el pod. En este ejemplo, queremos implementar la imagen Docker py-web-echo: v1.0 que se presenta a través del puerto de red 8888.
- imagePullPolicy: indica a Kubernetes que no tire de la imagen del contenedor.
Para implementar el pod en nuestro clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl apply -f /tmp/web-echo-pod.yamlEl siguiente sería un resultado típico:
Output.22 pod/web-echo-pod createdPara hacer una lista de todos los pods de aplicaciones que se ejecutan en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get pods -o wideEl siguiente sería un resultado típico:
Output.23 1En el resultado 23, vemos que nuestro pod de aplicación se ha implementado en el nodo my-n2-2 de nuestro clúster Kubernetes.
Para mostrar información detallada sobre el pod de aplicación web-echo-pod implementado, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl describe pods web-echo-podEl siguiente sería un resultado típico:
Output.24 Name: web-echo-pod Namespace: default Priority: 0 Node: my-n2-2/192.168.1.52 Start Time: Sun, 15 Dec 2019 14:58:21 -0500 Labels: app=web-echo Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"web-echo"},"name":"web-echo-pod","namespace":"default"},"spe... Status: Running IP: 10.44.0.1 IPs: IP: 10.44.0.1 Containers: web-echo: Container ID: docker://0af2c99fd074b5ee3c0b9876eb9ad44ca446400c2190b4af6fa1a18543bff723 Image: py-web-echo:v1.0 Image ID: docker://sha256:7cd037d24ef7c842ffe005cfcb548a802fc13661c08c8bb4635c365f77e5a3aa Port: 8888/TCP Host Port: 0/TCP State: Running Started: Sun, 15 Dec 2019 14:58:23 -0500 Ready: True Restart Count: 0 Environment: Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-tvl5x (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-tvl5x: Type: Secret (a volume populated by a Secret) SecretName: default-token-tvl5x Optional: false QoS Class: BestEffort Node-Selectors: Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 7m39s default-scheduler Successfully assigned default/web-echo-pod to my-n2-2 Normal Pulled 7m38s kubelet, my-n2-2 Container image "py-web-echo:v1.0" already present on machine Normal Created 7m38s kubelet, my-n2-2 Created container web-echo Normal Started 7m37s kubelet, my-n2-2 Started container web-echoEn el anterior resultado 23 (así como en el resultado 24), vemos que la dirección IP de la aplicación web implementada es 10.44.0.1.
Para probar la aplicación web desplegada utilizando el comando curl, ejecuta el siguiente comando en cualquiera de los nodos my-n2-1 a través de my-n2-5:
$ curl http://10.44.0.1:8888El siguiente sería un resultado típico:
Output.25 Hello from container -> web-echo-pod [10.44.0.1]Para mostrar los registros log de la aplicación web implementada web-echo-pod, ejecuta el siguienta comando en el nodo maestro (my-n2-1):
$ kubectl logs web-echo-podEl siguiente sería un resultado típico:
Output.26 * Serving Flask app "web-echo" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:8888/ (Press CTRL+C to quit) 10.32.0.1 - - [15/Dec/2019 20:11:33] "GET / HTTP/1.1" 200 - 10.36.0.0 - - [15/Dec/2019 20:11:58] "GET / HTTP/1.1" 200 -Para eliminar la aplicación web desplegada web-echo-pod, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl delete pod web-echo-podEl siguiente sería un resultado típico:
Output.27 pod "web-echo-pod" deleted*NOT* es muy común al implementar un único Pod. Es más normal implementar un objeto Kubernetes de nivel superior llamado ReplicaSet. Un ReplicaSet define cuántas réplicas de un Pod deben implementarse y mantenerse en el clúster de Kubernetes.
Los siguientes son los contenidos del archivo manifiesto de ReplicaSet llamado web-echo-rs.yaml almacenado en el directorio /tmp en el nodo maestro (my-n2-1):
web-echo-rs.yaml --- apiVersion: apps/v1 kind: ReplicaSet metadata: name: web-echo-rs spec: replicas: 3 selector: matchLabels: app: web-echo template: metadata: labels: app: web-echo spec: containers: - name: web-echo image: py-web-echo:v1.0 imagePullPolicy: Never ports: - containerPort: 8888Explicaremos ahora algunos de los elementos del archivo manifiesto web-echo-rs.yaml:
apiVersion: especifica la versión de la API (apps/v1 en este ejemplo) replicas: indica las instancias deseadas del Pod que se ejecutarán en el clúster de Kubernetes selector: identifica y selecciona un grupo de objetos de Kubernetes con la misma etiqueta de valor clave (aplicación clave y valor web-echo en este ejemplo)
template: es la especificación interna de un Pod
Para implementar ReplicaSet en nuestro clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl apply -f /tmp/web-echo-rs.yamlEl siguiente sería un resultado típico:
Output.28 replicaset.apps/web-echo-rs createdPara hacer una lista de todos los ReplicaSet implementados que se ejecutan en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get replicasets -o wideEl siguiente sería un resultado típico:
Output.29 NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR web-echo-rs 3 3 3 7m web-echo py-web-echo:v1.0 app=web-echoPara mostrar información detallada sobre el ReplicaSet implementado llamado web-echo-rs, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl describe replicasets web-echo-rsEl siguiente sería un resultado típico:
Output.30 Name: web-echo-rs Namespace: default Selector: app=web-echo Labels: Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"name":"web-echo-rs","namespace":"default"},"spec":{"replicas":3,... Replicas: 3 current / 3 desired Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: Labels: app=web-echo Containers: web-echo: Image: py-web-echo:v1.0 Port: 8888/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 14m replicaset-controller Created pod: web-echo-rs-xn94l Normal SuccessfulCreate 14m replicaset-controller Created pod: web-echo-rs-9x9b9 Normal SuccessfulCreate 14m replicaset-controller Created pod: web-echo-rs-tbd49Para hacer una lista de todos los pods de aplicaciones que se ejecutan en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get pods -o wideEl siguiente sería un resultado típico:
Output.31 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES web-echo-rs-9x9b9 1/1 Running 0 63s 10.42.0.1 my-n2-4 web-echo-rs-tbd49 1/1 Running 0 63s 10.44.0.1 my-n2-2 web-echo-rs-xn94l 1/1 Running 0 63s 10.36.0.1 my-n2-3En el resultado 31, vemos que nuestros pods de aplicación se han implementado en los 3 nodos my-n2-2, my-n2-3 y my-n2-4 con direcciones IP únicas de 10.44.0.1, 10.36 .0.1 y 10.42.0.1 respectivamente.
Como se ha mencionado al principio, los pods de aplicación son efímeros. Pueden aparecer y desaparecer en cualquier momento. Esto significa que sus direcciones IP pueden cambiar en cualquier momento. Necesitamos una abstracción de nivel superior que proporcione una dirección IP estable para que otros pod (s) de aplicaciones puedan usarla. Aquí es donde resula muy útil un objeto de Servicio. Proporciona una única dirección IP estable para que otras aplicaciones la usen y distribuye la carga a través de los diferentes pod (s) de aplicaciones del back-end que están delante.
Hay 3 tipos de servicio(s) en Kubernetes:
- ClusterIP: expone el Servicio en una dirección IP que es interna al clúster de Kubernetes. Esto significa que se puede acceder al Servicio *SOLO* desde dentro del clúster de Kubernetes. Este es el tipico por defecto.
- NodePort: expone al Servicio en la dirección IP de cada nodo de trabajo en un puerto alto en el rango de 30000 a 32767. Las aplicaciones externas al clúster de Kubernetes pueden acceder al Servicio en la dirección IP del nodo de trabajo y el puerto de nodo asignado
- LoadBalancer: Expone el Servicio externamente usando un Load Balancer de proveedores en la nube como AWS, Azure o Google Cloud
El siguiente es el contenido del archivo de manifiesto del Servicio basado en ClusterIP llamado web-echo-svc-cip.yaml almacenado bajo el directorio /tmp en el nodo maestro (my-n2-1):
web-echo-svc-cip.yaml --- apiVersion: v1 kind: Service metadata: name: web-echo-svc-cip spec: selector: app: web-echo ports: - name: http protocol: TCP port: 8888Para implementar el Servicio en nuestro clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl apply -f /tmp/web-echo-svc-cip.yamlEl siguiente sería un resultado típico:
Output.32 service/web-echo-svc createdPara hacer una lista de todos los Servicios que se ejecuten en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get services -o wideEl siguiente sería un resultado típico:
Output.33 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 443/TCP 9h web-echo-svc ClusterIP 10.96.238.16 8888/TCP 105s app=web-echoEn el resulado 33 anterior, vemos que se puede acceder a la aplicación web-echo desde cualquier lugar del clúster a través de la dirección IP 10.96.238.16 y el puerto 8888.
Para probar el punto final del Servicio implementado utilizando el comando curl, ejecuta el siguiente comando 5 veces en cualquiera de los nodos my-n2-1 a través de my-n2-5:
$ curl http://10.96.238.16:8888El siguiente sería un resultado típico:
Output.34 Hello from container -> web-echo-rs-xn94l [10.36.0.1] Hello from container -> web-echo-rs-9x9b9 [10.42.0.1] Hello from container -> web-echo-rs-tbd49 [10.44.0.1] Hello from container -> web-echo-rs-9x9b9 [10.42.0.1] Hello from container -> web-echo-rs-tbd49 [10.44.0.1]Para mostrar información detallada sobre el punto final del servicio etiquetado web-echo-svc, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl describe service web-echo-svcEl siguiente sería un resultado típico:
Output.35 Name: web-echo-svc Namespace: default Labels: Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"web-echo-svc","namespace":"default"},"spec":{"ports":[{"name":"ht... Selector: app=web-echo Type: ClusterIP IP: 10.96.238.16 Port: http 8888/TCP TargetPort: 8888/TCP Endpoints: 10.36.0.1:8888,10.42.0.1:8888,10.44.0.1:8888 Session Affinity: None Events:Para eliminar el objeto desplegado web-echo-svc, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl delete service web-echo-svcEl siguiente sería un resultado típico:
Output.36 service "web-echo-svc" deletedLos siguientes son los contenidos del archivo de manifiesto de servicio basado en NodePort llamado web-echo-svc-nop.yaml almacenado bajo el directorio /tmp en el nodo maestro (my-n2-1):
web-echo-svc-nop.yaml --- apiVersion: v1 kind: Service metadata: name: web-echo-svc spec: type: NodePort selector: app: web-echo ports: - name: http protocol: TCP port: 8888Para implementar el Servicio en nuestro clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl apply -f /tmp/web-echo-svc-nop.yamlEl siguiente sería un resultado típico:
Output.37 service/web-echo-svc createdPara hacer una lista de todos los Servicios que se ejecutan en el clúster de Kubernetes, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl get services -o wideEl siguiente sería un resultado típico
Output.38 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 443/TCP 9h web-echo-svc NodePort 10.96.144.75 8888:32546/TCP 38m app=web-echoPara mostrar información detallada sobre el punto del servicio etiquetado web-echo-svc, ejecuta el siguiente comando en el nodo maestro (my-n2-1):
$ kubectl describe service web-echo-svcEl siguiente sería un resultado típico:
Output.39 Name: web-echo-svc Namespace: default Labels: Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"web-echo-svc","namespace":"default"},"spec":{"ports":[{"name":"ht... Selector: app=web-echo Type: NodePort IP: 10.96.144.75 Port: http 8888/TCP TargetPort: 8888/TCP NodePort: http 32546/TCP Endpoints: 10.36.0.1:8888,10.42.0.1:8888,10.44.0.1:8888 Session Affinity: None External Traffic Policy: Cluster Events:En el resultado 39 anterior, vemos que el puerto del nodo de Servicio implementado es 32546.
Abre un navegador y acceda a la url http://192.168.1.53:32546. La siguiente imagen es la pantalla típica del navegador:
BINGO: ¡todo funciona como era de esperar!
Y con esto concluimos los ejercicios básicos que hemos realizado en nuestro grupo de Kubernetes.
Referencias
https://kubernetes.io/docs/home/?path=browse https://www.weave.works/docs/net/latest/overview/ https://docs.docker.com/ https://www.polarsparc.com/xhtml/Practical-K8S-N2.html
Be the first to comment