informatica:linux:docker:kubernetes
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| informatica:linux:docker:kubernetes [2022/06/24 09:56] – [Security list] javi | informatica:linux:docker:kubernetes [2022/09/24 07:41] (current) – removed javi | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Instalación ====== | ||
| - | |||
| - | El proceso instalar un cluster de kubernetes en " | ||
| - | |||
| - | 1. Instalar nodos (al menos un control plane y un worker) | ||
| - | |||
| - | 2. Iniciar el cluster (se ejecuta en el primer control plane) | ||
| - | |||
| - | 3. (Opcional, solo para alta disponibilidad) Unir control plane adicionales al cluster | ||
| - | |||
| - | 4. Unir worker (al menos uno) al cluster | ||
| - | |||
| - | ===== Nodo (común para control plane y worker) ===== | ||
| - | |||
| - | Estas instrucciones detallan como instalar un nodo de kubernetes, por tanto es COMÚN para todos los nodos, con independencia de su posterior rol dentro del cluster (control plane o worker). | ||
| - | |||
| - | 1. Verificar que el nodo cumple todos los siguientes requisitos: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | 2. Instalar un runtime | ||
| - | |||
| - | **IMPORTANTE**: | ||
| - | |||
| - | * Kubernetes usa CRI, que NO es compatible con Docker Engine, por eso mejor NO usarlo (Docker Engine) | ||
| - | |||
| - | * Para instalar containerd usaremos los paquetes, que los distribuye Docker Inc. | ||
| - | |||
| - | * Habrá que instalar luego los plugins CNI, que NO vienen en los paquetes que distribuye Docker Inc. | ||
| - | |||
| - | 2.1. Instalar containerd | ||
| - | |||
| - | Este ejemplo es para ubuntu | ||
| - | |||
| - | sudo apt-get remove docker docker-engine docker.io containerd runc | ||
| - | |||
| - | sudo apt-get update | ||
| - | |||
| - | < | ||
| - | sudo apt-get install \ | ||
| - | ca-certificates \ | ||
| - | curl \ | ||
| - | gnupg \ | ||
| - | lsb-release | ||
| - | </ | ||
| - | |||
| - | sudo mkdir -p / | ||
| - | |||
| - | < | ||
| - | curl -fsSL https:// | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | echo \ | ||
| - | "deb [arch=$(dpkg --print-architecture) signed-by=/ | ||
| - | $(lsb_release -cs) stable" | ||
| - | </ | ||
| - | |||
| - | sudo apt-get update | ||
| - | |||
| - | **IMPORTANTE**: | ||
| - | |||
| - | sudo apt install containerd.io | ||
| - | |||
| - | Verificar: | ||
| - | |||
| - | systemctl status containerd | ||
| - | |||
| - | q | ||
| - | | ||
| - | 2.2. Redirigir IPv4 y permitir a iptables ver el trafico " | ||
| - | |||
| - | < | ||
| - | cat <<EOF | sudo tee / | ||
| - | overlay | ||
| - | br_netfilter | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | sudo modprobe overlay | ||
| - | sudo modprobe br_netfilter | ||
| - | </ | ||
| - | |||
| - | # sysctl params required by setup, params persist across reboots | ||
| - | |||
| - | < | ||
| - | cat <<EOF | sudo tee / | ||
| - | net.bridge.bridge-nf-call-iptables | ||
| - | net.bridge.bridge-nf-call-ip6tables = 1 | ||
| - | net.ipv4.ip_forward | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | # Apply sysctl params without reboot | ||
| - | |||
| - | < | ||
| - | sudo sysctl --system | ||
| - | </ | ||
| - | |||
| - | 2.3. Configurar systemd cgroup driver | ||
| - | |||
| - | 2.3.1. Copia de seguridad y gener archivo nuevo de trinca | ||
| - | |||
| - | sudo cp / | ||
| - | sudo containerd config default | sudo tee / | ||
| - | |||
| - | 2.3.2. Reemplazar: | ||
| - | |||
| - | sudo sed -i ' | ||
| - | |||
| - | Esto es el equivalente a: | ||
| - | |||
| - | sudo vim / | ||
| - | |||
| - | Y dejar esta linea tal que así: | ||
| - | |||
| - | < | ||
| - | # anyadido | ||
| - | # | ||
| - | SystemdCgroup = true | ||
| - | </ | ||
| - | |||
| - | 2.3.3. Reiniciar el servicio: | ||
| - | |||
| - | sudo systemctl restart containerd | ||
| - | |||
| - | 3. Instalar plugins CNI | ||
| - | |||
| - | En este ejemplo la arquitectura es ARM | ||
| - | |||
| - | sudo mkdir -p / | ||
| - | |||
| - | Escoger de: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | **OJO**: en este ejemplo la arquitectura es ARM | ||
| - | |||
| - | sudo wget https:// | ||
| - | |||
| - | sudo tar Cxzvf / | ||
| - | |||
| - | sudo systemctl restart containerd | ||
| - | |||
| - | 4. Instalar kubeadm, kubelet and kubectl | ||
| - | |||
| - | < | ||
| - | sudo apt-get update | ||
| - | sudo apt-get install -y apt-transport-https ca-certificates curl | ||
| - | </ | ||
| - | |||
| - | sudo curl -fsSLo / | ||
| - | |||
| - | echo "deb [signed-by=/ | ||
| - | |||
| - | < | ||
| - | sudo apt-get update | ||
| - | sudo apt-get install -y kubelet kubeadm kubectl | ||
| - | sudo apt-mark hold kubelet kubeadm kubectl | ||
| - | </ | ||
| - | |||
| - | 5. Configurar driver cgroup | ||
| - | |||
| - | 5.1. Configurar container runtime cgroup driver | ||
| - | |||
| - | Ya hecho en pasos anteriores, eb este caso containerd | ||
| - | |||
| - | 5.2. Configurar kubelet cgroup driver | ||
| - | |||
| - | https:// | ||
| - | |||
| - | Entiendo que NO es necesario porque desde la versión 1.22 configurará por defecto systemd | ||
| - | ===== Primer control plane ===== | ||
| - | |||
| - | Este paso solo se tiene que hacer **UNA VEZ POR CLUSTER**, y se ejecutará en aquel nodo, ya instalado, que vaya a ser el **PRIMER CONTROL PLANE**. | ||
| - | |||
| - | ==== Sin alta disponibilidad ==== | ||
| - | |||
| - | 1. Conectarse al servidor | ||
| - | |||
| - | ssh k8s2 | ||
| - | | ||
| - | 2. Iniciar el cluster. Ejecutar: | ||
| - | |||
| - | < | ||
| - | sudo kubeadm init \ | ||
| - | --control-plane-endpoint " | ||
| - | --pod-network-cidr=10.244.0.0/ | ||
| - | --upload-certs \ | ||
| - | --v=5 | ||
| - | </ | ||
| - | |||
| - | Comentarios: | ||
| - | |||
| - | * Aunque no sea alta disponibilidad es conveniente usar ' | ||
| - | * Debe ser un nombre que todos los nodos (control plane y workers) resuelvan, o bien la IP privada del control plane | ||
| - | * El puerto es el 6443, es en el que escucha el servicio ' | ||
| - | * El parámetro ' | ||
| - | |||
| - | 3. Anotar de la salida del comando anterior los comandos para unir control planes y workers al cluster: | ||
| - | |||
| - | 3.1. Anotar el comando para unir un control plane: | ||
| - | |||
| - | < | ||
| - | sudo kubeadm join \ | ||
| - | k8s2.local: | ||
| - | --token r6mawr.wsgooc91h45a55i8 \ | ||
| - | --discovery-token-ca-cert-hash sha256: | ||
| - | --control-plane \ | ||
| - | --certificate-key 7b04bab444d4a5515c514a8b8eeb7a2df6629ee80d46b7f1ed5bd4b1aa3d80ed \ | ||
| - | --v=8 | ||
| - | </ | ||
| - | |||
| - | Opciones: | ||
| - | |||
| - | * Añadir ' | ||
| - | * Añadir ' | ||
| - | |||
| - | 3.2. Anoter el comando para unir un worker: | ||
| - | |||
| - | < | ||
| - | sudo kubeadm join \ | ||
| - | k8s2.local: | ||
| - | --token 9sljzd.hm5i967gzi802cah \ | ||
| - | --discovery-token-ca-cert-hash sha256: | ||
| - | --v=8 | ||
| - | </ | ||
| - | |||
| - | Opciones: | ||
| - | |||
| - | * Añadir ' | ||
| - | * Añadir ' | ||
| - | |||
| - | 4. Instalar plugin CNI, en este ejemplo " | ||
| - | |||
| - | kubectl apply -f https:// | ||
| - | |||
| - | 5. Configurar archivos para poder usar ' | ||
| - | |||
| - | < | ||
| - | mkdir -p $HOME/.kube | ||
| - | sudo cp -i / | ||
| - | sudo chown $(id -u):$(id -g) $HOME/ | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | sudo mkdir -p /root/.kube | ||
| - | sudo cp -i / | ||
| - | </ | ||
| - | |||
| - | 6. Comprobar: | ||
| - | |||
| - | kubectl get nodes | ||
| - | | ||
| - | Salida esperada similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | </ | ||
| - | |||
| - | ==== Con alta disponibilidad ==== | ||
| - | |||
| - | En este ejemplo tendremos 3 nodos que actuarán como control plane: | ||
| - | |||
| - | ^ DNS ^ IP ^ Puerto ^ Comentario ^ | ||
| - | | k8s.local | ||
| - | | k8s2.local | 192.168.95.71 | 6443 | Primer control plane | | ||
| - | | k8s3.local | 192.168.95.72 | 6443 | Control plane adicional | | ||
| - | | k8s3.local | 192.168.95.73 | 6443 | Control plane adicional | | ||
| - | |||
| - | Antes de empezar para cada uno de los tres control plane [[informatica: | ||
| - | |||
| - | 1. Conectarse al servidor | ||
| - | |||
| - | ssh k8s2 | ||
| - | | ||
| - | 2. Iniciar el cluster. Ejecutar: | ||
| - | |||
| - | < | ||
| - | sudo kubeadm init \ | ||
| - | --control-plane-endpoint " | ||
| - | --pod-network-cidr=10.244.0.0/ | ||
| - | --upload-certs \ | ||
| - | --v=5 | ||
| - | </ | ||
| - | |||
| - | Comentarios: | ||
| - | |||
| - | * El parámetro ' | ||
| - | * El puerto es el 8443, es en el que escucha balanceador capa 4 kube-apiserver ' | ||
| - | * El parámetro ' | ||
| - | |||
| - | 3. Anotar de la salida del comando anterior los comandos para unir control planes y workers al cluster: | ||
| - | |||
| - | 3.1. Anotar el comando para unir un control plane: | ||
| - | |||
| - | < | ||
| - | sudo kubeadm join \ | ||
| - | k8s.local: | ||
| - | --token r6mawr.wsgooc91h45a55i8 \ | ||
| - | --discovery-token-ca-cert-hash sha256: | ||
| - | --control-plane \ | ||
| - | --certificate-key 7b04bab444d4a5515c514a8b8eeb7a2df6629ee80d46b7f1ed5bd4b1aa3d80ed \ | ||
| - | --v=8 | ||
| - | </ | ||
| - | |||
| - | Opciones: | ||
| - | |||
| - | * Añadir ' | ||
| - | * Añadir ' | ||
| - | |||
| - | 3.2. Anoter el comando para unir un worker: | ||
| - | |||
| - | < | ||
| - | sudo kubeadm join \ | ||
| - | k8s.local: | ||
| - | --token 9sljzd.hm5i967gzi802cah \ | ||
| - | --discovery-token-ca-cert-hash sha256: | ||
| - | --v=8 | ||
| - | </ | ||
| - | |||
| - | Opciones: | ||
| - | |||
| - | * Añadir ' | ||
| - | * Añadir ' | ||
| - | |||
| - | 4. Instalar plugin CNI, en este ejemplo " | ||
| - | |||
| - | kubectl apply -f https:// | ||
| - | |||
| - | 5. Configurar archivos para poder usar ' | ||
| - | |||
| - | < | ||
| - | mkdir -p $HOME/.kube | ||
| - | sudo cp -i / | ||
| - | sudo chown $(id -u):$(id -g) $HOME/ | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | sudo mkdir -p /root/.kube | ||
| - | sudo cp -i / | ||
| - | </ | ||
| - | |||
| - | 6. Comprobar: | ||
| - | |||
| - | kubectl get nodes | ||
| - | | ||
| - | Salida esperada similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | </ | ||
| - | |||
| - | ===== Unir nodos al cluster ===== | ||
| - | |||
| - | Una vez se ha iniciado el cluster en el primer control plane hay que añadir nodos al cluster: | ||
| - | |||
| - | * Control plane. Solo en alta disponibilidad. Si no vamos a configurar alta disponibilidad, | ||
| - | * Workers. Al menos uno. | ||
| - | |||
| - | ==== Control plane (solo alta disponibilidad) ==== | ||
| - | |||
| - | Solo debemos añadir control plane adicionales al cluster si vamos a configurar alta disponibilidad. | ||
| - | |||
| - | 1. Conectarse al control plane: | ||
| - | |||
| - | ssh k8s3 | ||
| - | | ||
| - | 2. Ejecutar el comando obtenido en el paso 3.1. de [[informatica: | ||
| - | |||
| - | * Si hemos configurado alta disponibilidad con [[https:// | ||
| - | * Añadir ' | ||
| - | * (Opcional) Añadir ' | ||
| - | |||
| - | < | ||
| - | sudo kubeadm join \ | ||
| - | k8s.local: | ||
| - | --token r6mawr.wsgooc91h45a55i8 \ | ||
| - | --discovery-token-ca-cert-hash sha256: | ||
| - | --control-plane \ | ||
| - | --certificate-key 7b04bab444d4a5515c514a8b8eeb7a2df6629ee80d46b7f1ed5bd4b1aa3d80ed \ | ||
| - | --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests \ | ||
| - | --v=8 | ||
| - | </ | ||
| - | |||
| - | 3. Pasos opcionales. Los pasos que se listan a continuación son opcionales, y solo son necesarios si queremos usar el comando ' | ||
| - | |||
| - | 3.1. Configurar archivos para poder usar ' | ||
| - | |||
| - | < | ||
| - | mkdir -p $HOME/.kube | ||
| - | sudo cp -i / | ||
| - | sudo chown $(id -u):$(id -g) $HOME/ | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | sudo mkdir -p /root/.kube | ||
| - | sudo cp -i / | ||
| - | </ | ||
| - | |||
| - | 3.2. Comprobar: | ||
| - | |||
| - | kubectl get nodes | ||
| - | | ||
| - | Salida esperada similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | </ | ||
| - | |||
| - | 4. Repetir los pasos 1 a 3 con el resto de control plane que queramos añadir al cluster. | ||
| - | |||
| - | ==== Worker ==== | ||
| - | |||
| - | Al menos un nodo debe tener el rol de worker. Las instrucciones son casi idénticas se haya configurado o no alta diponibilidad, | ||
| - | |||
| - | === Sin alta disponibilidad === | ||
| - | |||
| - | 1. Conectarse al worker: | ||
| - | |||
| - | ssh k8s3 | ||
| - | | ||
| - | 2. Ejecutar el comando obtenido en el paso 3.2. de [[http:// | ||
| - | |||
| - | * Añadir ' | ||
| - | * (Opcional) Añadir ' | ||
| - | |||
| - | < | ||
| - | sudo kubeadm join \ | ||
| - | k8s2.local: | ||
| - | --token 9sljzd.hm5i967gzi802cah \ | ||
| - | --discovery-token-ca-cert-hash sha256: | ||
| - | --v=8 | ||
| - | </ | ||
| - | |||
| - | 3. Comprobar | ||
| - | |||
| - | 3.1. Conectarse al control plane: | ||
| - | |||
| - | ssh k8s2 | ||
| - | | ||
| - | 3.2. Ejecutar: | ||
| - | |||
| - | kubectl get nodes | ||
| - | | ||
| - | Salida esperada similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | </ | ||
| - | |||
| - | 4. (Opcional) Repetir los pasos 1 a 4 con el resto de workers que se quiera unir al cluster de kubernetes. | ||
| - | |||
| - | === Con alta disponibilidad === | ||
| - | |||
| - | 1. Conectarse al worker: | ||
| - | |||
| - | ssh k8s5 | ||
| - | | ||
| - | 2. Ejecutar el comando obtenido en el paso 3.2. de [[informatica: | ||
| - | |||
| - | * Añadir ' | ||
| - | * (Opcional) Añadir ' | ||
| - | |||
| - | < | ||
| - | sudo kubeadm join \ | ||
| - | k8s.local: | ||
| - | --token 9sljzd.hm5i967gzi802cah \ | ||
| - | --discovery-token-ca-cert-hash sha256: | ||
| - | --v=8 | ||
| - | </ | ||
| - | |||
| - | 3. Comprobar | ||
| - | |||
| - | 3.1. Conectarse a cualquiera de los control plane: | ||
| - | |||
| - | ssh k8s4 | ||
| - | | ||
| - | 3.2. Ejecutar: | ||
| - | |||
| - | kubectl get nodes | ||
| - | | ||
| - | Salida esperada similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | k8s4 | ||
| - | k8s5 | ||
| - | </ | ||
| - | |||
| - | 4. (Opcional) Repetir los pasos 1 a 4 con el resto de workers que se quiera unir al cluster de kubernetes. | ||
| - | ====== Balanceador capa 4 kube-apiserver ====== | ||
| - | |||
| - | https:// | ||
| - | |||
| - | Paso requerido para alta disponibilidad. | ||
| - | |||
| - | Vamos a crear un balanceador de carga capa 4 para el servicio [[https:// | ||
| - | |||
| - | El objetivo es crear una IP virtual o flotante (' | ||
| - | |||
| - | Las peticiones TCP que lleguen a ese nombre (' | ||
| - | |||
| - | Todos los nodos (control plane o workers) deben resolver el nombre que elijamos para el balanceador de carga, en este ejemplo ' | ||
| - | |||
| - | Todos los miembros de ese balanceador de carga, los 3 control plane en este ejemplo, deben ser capaces de resolver el nombre DNS de todos y cada uno de sus miembros, ya que usaremos nombres DNS. | ||
| - | |||
| - | En este ejemplo tendremos 3 nodos que actuarán como control plane: | ||
| - | |||
| - | ^ DNS ^ IP ^ Puerto ^ Comentario ^ | ||
| - | | k8s.local | ||
| - | | k8s2.local | 10.0.0.2 | 6443 | Primer control plane | | ||
| - | | k8s3.local | 10.0.0.3 | 6443 | Control plane adicional | | ||
| - | | k8s3.local | 10.0.0.4 | 6443 | Control plane adicional | | ||
| - | |||
| - | ===== Oracle cloud ===== | ||
| - | |||
| - | Oracle cloud ofrece por la patilla y para siempre un balanceador de capa 4 con IP pública y estática. | ||
| - | |||
| - | Resumen de máquinas, nombres, IPs, etc. (las IPs públicas están cambiadas) | ||
| - | |||
| - | ^ DNS ^ IP privada ^ IP pública ^ Comentario ^ | ||
| - | | k8s.legido.com | ||
| - | | k8s1 | 1.2.3.5 | 10.0.0.2 | Primer control plane | | ||
| - | | k8s2 | 1.2.3.6 | 10.0.0.2 | Segundo control plane | | ||
| - | | k8s3 | 1.2.3.7 | 10.0.0.2 | Tercer control plane | | ||
| - | |||
| - | ==== Load balancer ==== | ||
| - | |||
| - | Listener | ||
| - | |||
| - | ^ Protocol ^ Ingress Traffic Port ^ Backend Set ^ | ||
| - | | TCP | Specify the port, 6443 | listener-kube-apiserver | | ||
| - | |||
| - | Backend set | ||
| - | |||
| - | ^ Load Balancing Policy ^ Preserve Source IP ^ Backend Set ^ | ||
| - | | 5-tuple hash | Checked | listener-kube-apiserver | | ||
| - | |||
| - | Backends | ||
| - | |||
| - | ^ Name ^ IP address ^ Port ^ Weight ^ | ||
| - | | k8s1 | 10.0.0.3 | 6443 | 100 | | ||
| - | | k8s2 | 10.0.0.4 | 6443 | 99 | | ||
| - | | k8s3 | 10.0.0.5 | 6443 | 99 | | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | ==== Security list ==== | ||
| - | |||
| - | Se creó una VNC siguiendo el asistente. | ||
| - | |||
| - | El load balancer usa la subnet pública, " | ||
| - | |||
| - | Esta tiene una security list, que hay que retocar para que: | ||
| - | |||
| - | * No permita conexiones desde la DMZ al listener kube-apiserver | ||
| - | * Permita que lleguen los health check del load balancer a los nodos | ||
| - | |||
| - | Seguramente se puede restringir una miaja | ||
| - | |||
| - | |||
| - | |||
| - | ===== Haproxy y keepalived como servicios ===== | ||
| - | |||
| - | 1. Keepalived | ||
| - | |||
| - | 1.1. Instalar | ||
| - | |||
| - | sudo apt install keepalived | ||
| - | | ||
| - | 1.2. Crear: | ||
| - | |||
| - | sudo vim / | ||
| - | |||
| - | Con el siguiente contenido: | ||
| - | |||
| - | < | ||
| - | ! / | ||
| - | ! Configuration File for keepalived | ||
| - | global_defs { | ||
| - | router_id LVS_DEVEL | ||
| - | } | ||
| - | vrrp_script check_apiserver { | ||
| - | script "/ | ||
| - | interval 3 | ||
| - | weight -2 | ||
| - | fall 10 | ||
| - | rise 2 | ||
| - | } | ||
| - | |||
| - | vrrp_instance VI_1 { | ||
| - | state MASTER | ||
| - | interface enp0s3 | ||
| - | virtual_router_id 51 | ||
| - | priority 101 | ||
| - | authentication { | ||
| - | auth_type PASS | ||
| - | auth_pass 42 | ||
| - | } | ||
| - | virtual_ipaddress { | ||
| - | 10.0.0.200 | ||
| - | } | ||
| - | track_script { | ||
| - | check_apiserver | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Explicación: | ||
| - | |||
| - | * STATE: MASTER para master, BACKUP para el resto | ||
| - | * INTERFACE: enp0s3 | ||
| - | * ROUTER_ID: 51 | ||
| - | * PRIORITY: 101 para el master, 100 para el resto | ||
| - | * AUTH_PASS: 42 | ||
| - | * APISERVER_VIP: | ||
| - | |||
| - | 1.2. Crear: | ||
| - | |||
| - | sudo vim / | ||
| - | |||
| - | Con el siguiente contenido: | ||
| - | |||
| - | < | ||
| - | #!/bin/sh | ||
| - | |||
| - | APISERVER_VIP=" | ||
| - | APISERVER_DEST_PORT=" | ||
| - | |||
| - | errorExit() { | ||
| - | echo "*** $*" 1>&2 | ||
| - | exit 1 | ||
| - | } | ||
| - | |||
| - | curl --silent --max-time 2 --insecure https:// | ||
| - | if ip addr | grep -q ${APISERVER_VIP}; | ||
| - | curl --silent --max-time 2 --insecure https:// | ||
| - | fi | ||
| - | </ | ||
| - | |||
| - | 2. haproxy | ||
| - | |||
| - | 2.1. Instalar | ||
| - | |||
| - | sudo apt install haproxy | ||
| - | | ||
| - | 2.2. Crear: | ||
| - | |||
| - | sudo vim / | ||
| - | |||
| - | Con el siguiente contenido: | ||
| - | |||
| - | < | ||
| - | # / | ||
| - | # | ||
| - | # Global settings | ||
| - | # | ||
| - | global | ||
| - | log /dev/log local0 | ||
| - | log /dev/log local1 notice | ||
| - | daemon | ||
| - | |||
| - | # | ||
| - | # common defaults that all the ' | ||
| - | # use if not designated in their block | ||
| - | # | ||
| - | defaults | ||
| - | mode http | ||
| - | log | ||
| - | option | ||
| - | option | ||
| - | option http-server-close | ||
| - | option forwardfor | ||
| - | option | ||
| - | retries | ||
| - | timeout http-request | ||
| - | timeout queue 20s | ||
| - | timeout connect | ||
| - | timeout client | ||
| - | timeout server | ||
| - | timeout http-keep-alive 10s | ||
| - | timeout check 10s | ||
| - | |||
| - | # | ||
| - | # apiserver frontend which proxys to the control plane nodes | ||
| - | # | ||
| - | frontend apiserver | ||
| - | bind *:8443 | ||
| - | mode tcp | ||
| - | option tcplog | ||
| - | default_backend apiserver | ||
| - | |||
| - | # | ||
| - | # round robin balancing for apiserver | ||
| - | # | ||
| - | backend apiserver | ||
| - | option httpchk GET /healthz | ||
| - | http-check expect status 200 | ||
| - | mode tcp | ||
| - | option ssl-hello-chk | ||
| - | balance | ||
| - | server k8s1 k8s1.local: | ||
| - | server k8s2 k8s2.local: | ||
| - | server k8s3 k8s3.local: | ||
| - | </ | ||
| - | |||
| - | 3. Arrancar servicios: | ||
| - | |||
| - | sudo systemctl enable haproxy --now | ||
| - | sudo systemctl enable keepalived --now | ||
| - | |||
| - | IMPORTANTE: no va a funcionar hasta que el backend (apiserver) empiece a escuchar en el puerto 6443 | ||
| - | | ||
| - | |||
| - | ===== Kube-vip ===== | ||
| - | |||
| - | Antiguo | ||
| - | No funciona en Oracle OCI | ||
| - | |||
| - | ^ DNS ^ IP ^ Puerto ^ Comentario ^ | ||
| - | | k8s.local | ||
| - | | k8s2.local | 192.168.95.71 | 6443 | Primer control plane | | ||
| - | | k8s3.local | 192.168.95.72 | 6443 | Control plane adicional | | ||
| - | | k8s3.local | 192.168.95.73 | 6443 | Control plane adicional | | ||
| - | |||
| - | |||
| - | 1. Conectarse al control plane. Ejecutar: | ||
| - | |||
| - | ssh k8s2 | ||
| - | |||
| - | 2. Ejecutar: | ||
| - | |||
| - | < | ||
| - | sudo mkdir -p / | ||
| - | sudo vim / | ||
| - | </ | ||
| - | |||
| - | Con el siguiente contenido, ajustando: | ||
| - | |||
| - | * localPeer. Id lo que queramos, address la IP privada del control plane. | ||
| - | * remotePeers. Igual que ' | ||
| - | * vip. La misma para todo el cluster. | ||
| - | * startAsLeader. Para el primer control plane ' | ||
| - | * interface. En este ejemplo se tiene solo una interfaz, por tanto la ' | ||
| - | * loadBalancers. El cluster escucha en el puerto 8433, cada uno de los control plane escucha en el puerto 6443 | ||
| - | |||
| - | < | ||
| - | localPeer: | ||
| - | id: k8s2.local | ||
| - | address: 192.168.95.71 | ||
| - | port: 10000 | ||
| - | remotePeers: | ||
| - | - id: k8s3.local | ||
| - | address: 192.168.95.72 | ||
| - | port: 10000 | ||
| - | - id: k8s4.local | ||
| - | address: 192.168.95.73 | ||
| - | port: 10000 | ||
| - | vip: 192.168.95.69 | ||
| - | gratuitousARP: | ||
| - | singleNode: false | ||
| - | startAsLeader: | ||
| - | interface: eth0 | ||
| - | loadBalancers: | ||
| - | - name: API Server Load Balancer | ||
| - | type: tcp | ||
| - | port: 8443 | ||
| - | bindToVip: false | ||
| - | backends: | ||
| - | - port: 6443 | ||
| - | address: 192.168.95.71 | ||
| - | - port: 6443 | ||
| - | address: 192.168.95.72 | ||
| - | - port: 6443 | ||
| - | address: 192.168.95.73 | ||
| - | </ | ||
| - | |||
| - | 3. Ejecutar | ||
| - | |||
| - | < | ||
| - | docker run -it --rm plndr/ | ||
| - | | sed " | ||
| - | | sudo tee / | ||
| - | </ | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | apiVersion: v1 | ||
| - | kind: Pod | ||
| - | metadata: | ||
| - | creationTimestamp: | ||
| - | name: kube-vip | ||
| - | namespace: kube-system | ||
| - | spec: | ||
| - | containers: | ||
| - | - command: | ||
| - | - /kube-vip | ||
| - | - start | ||
| - | - -c | ||
| - | - /vip.yaml | ||
| - | image: ' | ||
| - | name: kube-vip | ||
| - | resources: {} | ||
| - | securityContext: | ||
| - | capabilities: | ||
| - | add: | ||
| - | - NET_ADMIN | ||
| - | - SYS_TIME | ||
| - | volumeMounts: | ||
| - | - mountPath: /vip.yaml | ||
| - | name: config | ||
| - | hostNetwork: | ||
| - | volumes: | ||
| - | - hostPath: | ||
| - | path: / | ||
| - | name: config | ||
| - | status: {} | ||
| - | </ | ||
| - | |||
| - | **IMPORTANTE**: | ||
| - | |||
| - | < | ||
| - | --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests | ||
| - | </ | ||
| - | |||
| - | 4. Repetir los pasos 1 a 4, ajustando los parámetros que se indica en cada paso, hasta que no queden más control plane por añadir al balanceador de carga de capa 4. | ||
| - | |||
| - | Cuando se inicie el cluster (primer control plane) o se una el control plane al cluster (segundo y subsiguientes control planes) se iniciará un pod que gestionará la IP virtual (' | ||
| - | |||
| - | ====== Deployment ====== | ||
| - | |||
| - | Vamos a desplegar un POD con la imagen [[https:// | ||
| - | |||
| - | 1. Conectarse al master | ||
| - | |||
| - | ssh master | ||
| - | |||
| - | 2. Ejecutar: | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: apps/v1 | ||
| - | kind: Deployment | ||
| - | metadata: | ||
| - | name: deployment-whoami | ||
| - | labels: | ||
| - | app: deployment-whoami | ||
| - | spec: | ||
| - | replicas: 1 | ||
| - | selector: | ||
| - | matchLabels: | ||
| - | app: deployment-whoami | ||
| - | template: | ||
| - | metadata: | ||
| - | labels: | ||
| - | app: deployment-whoami | ||
| - | spec: | ||
| - | containers: | ||
| - | - name: whoami | ||
| - | image: containous/ | ||
| - | ports: | ||
| - | - containerPort: | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | 3. Comprobar | ||
| - | |||
| - | kubectl get deployments | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME READY | ||
| - | deployment-whoami | ||
| - | </ | ||
| - | |||
| - | ====== Service ====== | ||
| - | |||
| - | Un [[https:// | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * Un [[informatica: | ||
| - | |||
| - | 1. Conectarse al master | ||
| - | |||
| - | ssh master | ||
| - | |||
| - | 2. Ejecutar: | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | name: service-whoami | ||
| - | spec: | ||
| - | selector: | ||
| - | app: deployment-whoami | ||
| - | ports: | ||
| - | - protocol: TCP | ||
| - | port: 80 | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | 3. Comprobar | ||
| - | |||
| - | kubectl get services --field-selector metadata.name=service-whoami | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | service-whoami | ||
| - | </ | ||
| - | |||
| - | ====== Metallb ====== | ||
| - | |||
| - | Se trata de un balanceador de carga por software para instalaciones "bare metal", | ||
| - | |||
| - | Es necesario instalarlo para poder instalar un servicio de tipo " | ||
| - | |||
| - | Más información [[https:// | ||
| - | |||
| - | En este ejemplo vamos a usar: | ||
| - | |||
| - | * Layer 2 | ||
| - | * IPs privadas | ||
| - | |||
| - | ===== Layer 2 ===== | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * Tener un rango de IPs **que no se usen**. Es decir, no vale ni las que tienen los nodos del cluster, ni las que usa flannel. En este ejemplo tenemos: | ||
| - | * 192.168.95.68 | ||
| - | * 192.168.95.69 | ||
| - | |||
| - | 1. Conectarse al master | ||
| - | |||
| - | ssh master | ||
| - | | ||
| - | 2. Instalar. Ejecutar: | ||
| - | |||
| - | kubectl apply -f https:// | ||
| - | |||
| - | kubectl apply -f https:// | ||
| - | |||
| - | Solo la primera vez: | ||
| - | |||
| - | kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey=" | ||
| - | |||
| - | 3. Configuración. Ajustar: | ||
| - | |||
| - | * Nombre del pool de direcciones. En este ejemplo " | ||
| - | * IPs. En este ejemplo " | ||
| - | * Protocolo. En este ejemplo " | ||
| - | |||
| - | Ejecutar: | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: v1 | ||
| - | kind: ConfigMap | ||
| - | metadata: | ||
| - | namespace: metallb-system | ||
| - | name: config | ||
| - | data: | ||
| - | config: | | ||
| - | address-pools: | ||
| - | - name: default | ||
| - | protocol: layer2 | ||
| - | addresses: | ||
| - | - 192.168.95.68-192.168.95.69 | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | 4. Probar | ||
| - | |||
| - | 4.1. Crear un " | ||
| - | |||
| - | Ejecutar: | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | name: test-service-canberemoved | ||
| - | annotations: | ||
| - | metallb.universe.tf/ | ||
| - | spec: | ||
| - | ports: | ||
| - | - port: 80 | ||
| - | targetPort: 80 | ||
| - | selector: | ||
| - | app: nonexistantdeployment | ||
| - | type: LoadBalancer | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | 4.2. Comprobar: | ||
| - | |||
| - | kubectl get services --field-selector metadata.name=test-service-canberemoved | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAMESPACE | ||
| - | default | ||
| - | </ | ||
| - | |||
| - | El campo ' | ||
| - | |||
| - | 4.3. Limpieza | ||
| - | |||
| - | kubectl delete services --field-selector metadata.name=test-service-canberemoved | ||
| - | |||
| - | ===== Cambiar ' | ||
| - | |||
| - | [[https:// | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * Tener instalado [[informatica: | ||
| - | |||
| - | 1. Conectarnos al master | ||
| - | |||
| - | ssh k8s2 | ||
| - | | ||
| - | 2. Editar el servicio, en nuestro caso se llama ' | ||
| - | |||
| - | kubectl edit services -n ingress-nginx ingress-nginx-controller | ||
| - | |||
| - | 3. Cambiar: | ||
| - | |||
| - | externalTrafficPolicy: | ||
| - | |||
| - | Por: | ||
| - | |||
| - | externalTrafficPolicy: | ||
| - | |||
| - | **IMPORTANTE**: | ||
| - | |||
| - | 4. Comprobar. En mi caso accediendo al nombre DNS público: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | El valor de ' | ||
| - | |||
| - | * Cluster => aparecía la IP de la interfaz de flannel del nodo que estaba ejecutando el pod ' | ||
| - | * Local => aparece la IP privada del edge router. Todavía tengo que afinar, debería aparecer la IP pública del cliente que hizo la petición HTTPS. | ||
| - | |||
| - | |||
| - | |||
| - | ====== Addons ====== | ||
| - | |||
| - | [[https:// | ||
| - | |||
| - | ===== Cert manager ===== | ||
| - | |||
| - | [[https:// | ||
| - | |||
| - | Para instalarlo: | ||
| - | |||
| - | 1. Conectarse al master | ||
| - | |||
| - | ssh master | ||
| - | | ||
| - | 2. Instalar los manifiestos de la [[https:// | ||
| - | |||
| - | kubectl apply -f https:// | ||
| - | kubectl apply -f https:// | ||
| - | |||
| - | 3. Probar | ||
| - | |||
| - | 3.1. Ejecutar: | ||
| - | |||
| - | watch -n 5 kubectl get pods --namespace cert-manager | ||
| - | |||
| - | Hastq que el pod ' | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | cert-manager-7dd5854bb4-zz8wj | ||
| - | cert-manager-cainjector-64c949654c-j7s9h | ||
| - | cert-manager-webhook-6b57b9b886-9ghg5 | ||
| - | </ | ||
| - | |||
| - | Suele tardar menos de un minuto. | ||
| - | |||
| - | 3.2. Crear: | ||
| - | |||
| - | * Namespace | ||
| - | * Issuer | ||
| - | * Certificate | ||
| - | |||
| - | Ejecutar: | ||
| - | |||
| - | < | ||
| - | cat <<EOF > test-resources.yaml | ||
| - | apiVersion: v1 | ||
| - | kind: Namespace | ||
| - | metadata: | ||
| - | name: cert-manager-test | ||
| - | --- | ||
| - | apiVersion: cert-manager.io/ | ||
| - | kind: Issuer | ||
| - | metadata: | ||
| - | name: test-selfsigned | ||
| - | namespace: cert-manager-test | ||
| - | spec: | ||
| - | selfSigned: {} | ||
| - | --- | ||
| - | apiVersion: cert-manager.io/ | ||
| - | kind: Certificate | ||
| - | metadata: | ||
| - | name: selfsigned-cert | ||
| - | namespace: cert-manager-test | ||
| - | spec: | ||
| - | dnsNames: | ||
| - | - example.com | ||
| - | secretName: selfsigned-cert-tls | ||
| - | issuerRef: | ||
| - | name: test-selfsigned | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | 3.3. Cargar el manifiesto creado en el paso anterior. | ||
| - | |||
| - | **IMPORTANTE**: | ||
| - | |||
| - | x509: certificate signed by unknown authority | ||
| - | |||
| - | Yo no fui capaz de resolver ese error. | ||
| - | |||
| - | Ejecutar: | ||
| - | |||
| - | kubectl apply -f test-resources.yaml | ||
| - | |||
| - | 3.4. Ver el certificado. Ejecutar: | ||
| - | |||
| - | kubectl describe certificate -n cert-manager-test | grep Message | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | Message: | ||
| - | |||
| - | 3.5. Limpieza. Ejecutar: | ||
| - | |||
| - | kubectl delete -f test-resources.yaml | ||
| - | |||
| - | ====== Issuer ====== | ||
| - | |||
| - | Se trata de un [[https:// | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * Tener instalado [[informatica: | ||
| - | |||
| - | Para instalarlo: | ||
| - | |||
| - | 1. Conectarse al control plane | ||
| - | |||
| - | ssh k8s2 | ||
| - | | ||
| - | 2. Ejecutar: | ||
| - | |||
| - | Ajustando: | ||
| - | |||
| - | * email. Si es del dominio ' | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: cert-manager.io/ | ||
| - | kind: Issuer | ||
| - | metadata: | ||
| - | name: letsencrypt-production | ||
| - | namespace: default | ||
| - | spec: | ||
| - | acme: | ||
| - | # Staging | ||
| - | #server: https:// | ||
| - | # Production | ||
| - | server: https:// | ||
| - | # Email address used for ACME registration | ||
| - | email: letsencrypt@example.com | ||
| - | # Name of a secret used to store the ACME account private key | ||
| - | privateKeySecretRef: | ||
| - | name: letsencrypt-production | ||
| - | # Enable the HTTP-01 challenge provider | ||
| - | solvers: | ||
| - | # An empty ' | ||
| - | - selector: {} | ||
| - | http01: | ||
| - | ingress: | ||
| - | class: nginx | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | En este ejemplo estamos usando la API de producción de letsencrypt: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | Pero podemos usar si queremos la de staging: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | 3. Comprobar. Ejecutar: | ||
| - | |||
| - | watch -n 5 kubectl get issuers.cert-manager.io | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | letsencrypt-production | ||
| - | </ | ||
| - | |||
| - | Tarda menos de un minuto. | ||
| - | |||
| - | ====== Edge router ====== | ||
| - | |||
| - | Se trata de un servidor completamente por fuera de kubernetes, pero se menciona aquí para completar el ejemplo. | ||
| - | |||
| - | Se encarga de escuchar peticiones en los puertos TCP 80 y TCP 443 y dirigirlas al cluster kuberntes. Los nombres DNS de los servicios con certificados SSL válidos, por ejemplo con letsencrypt, | ||
| - | |||
| - | [Cliente] => example.com => [Edge router] => [Worker] => [Ingress route] => [Service] => [Deployment] | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * IP pública | ||
| - | * IP privada en el mismo rango que los nodos del clúster de kubernetes (" | ||
| - | * (Opcional) Docker instalado. Usamos docker para hacer más rápido y sencillo el despliegue de nginx | ||
| - | |||
| - | ===== NodePort (usar este) ===== | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * IPs privadas de los workers del clúster | ||
| - | * Puertos en los que escuchan los Nodeport tanto HTTP como HTTPS. Ver paso 8 de [[informatica: | ||
| - | * [[https:// | ||
| - | |||
| - | 1. Acceder al servidor | ||
| - | |||
| - | ssh k8s1 | ||
| - | | ||
| - | 2. Crear el archivo ' | ||
| - | |||
| - | vim default.conf | ||
| - | |||
| - | Con el siguiente contenido: | ||
| - | |||
| - | < | ||
| - | proxy_set_header X-Real-IP | ||
| - | proxy_set_header X-Forwarded-For $remote_addr; | ||
| - | # To avoid 404. Credits: | ||
| - | # https:// | ||
| - | proxy_set_header Host $host: | ||
| - | |||
| - | server { | ||
| - | listen 80; | ||
| - | location / { | ||
| - | proxy_pass http://k8s; | ||
| - | } | ||
| - | error_page 404 /404.html; | ||
| - | location = /404.html { | ||
| - | root / | ||
| - | internal; | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | 3. Crear el archivo ' | ||
| - | |||
| - | vim nginx.conf | ||
| - | |||
| - | Con el siguiente contenido: | ||
| - | |||
| - | < | ||
| - | user nginx; | ||
| - | worker_processes | ||
| - | |||
| - | error_log | ||
| - | pid / | ||
| - | |||
| - | |||
| - | events { | ||
| - | worker_connections | ||
| - | } | ||
| - | |||
| - | |||
| - | http { | ||
| - | include | ||
| - | default_type | ||
| - | |||
| - | log_format | ||
| - | ' | ||
| - | '" | ||
| - | |||
| - | access_log | ||
| - | |||
| - | sendfile | ||
| - | # | ||
| - | |||
| - | keepalive_timeout | ||
| - | |||
| - | #gzip on; | ||
| - | |||
| - | include / | ||
| - | |||
| - | upstream k8s { | ||
| - | # IP: kubernetes node private IP. Port: nginx ingress controller in NodePort port for HTTP traffic | ||
| - | server 192.168.95.74: | ||
| - | server 192.168.95.75: | ||
| - | server 192.168.95.76: | ||
| - | } | ||
| - | } | ||
| - | |||
| - | stream { | ||
| - | |||
| - | server { | ||
| - | listen 443; | ||
| - | |||
| - | proxy_pass k8s_https; | ||
| - | # Requires ' | ||
| - | # https:// | ||
| - | proxy_protocol on; | ||
| - | |||
| - | } | ||
| - | |||
| - | upstream k8s_https { | ||
| - | # IP: kubernetes node private IP. Port: nginx ingress controller in NodePort port for HTTP traffic | ||
| - | server 192.168.95.74: | ||
| - | server 192.168.95.75: | ||
| - | server 192.168.95.76: | ||
| - | } | ||
| - | |||
| - | log_format basic ' | ||
| - | ' | ||
| - | ''; | ||
| - | |||
| - | access_log | ||
| - | |||
| - | } | ||
| - | </ | ||
| - | |||
| - | Modificar: | ||
| - | |||
| - | * IPs y puertos de los workers del clúster de kubernetes. En este ejemplo las IPs son: | ||
| - | * 192.168.95.74 | ||
| - | * 192.168.95.75 | ||
| - | * 192.168.95.76 | ||
| - | * Puerto en el que escucha el servicio NodePort para las conexiones HTTP. En este ejemplo ' | ||
| - | * Puerto en el que escucha el servicio NodePort para las conexiones HTTPS. En este ejemplo ' | ||
| - | | ||
| - | 4. Arrancar el contenedor docker, ajustando la ruta a los archivos creados en el paso anterior: | ||
| - | |||
| - | < | ||
| - | docker run \ | ||
| - | --name edge-router \ | ||
| - | --v / | ||
| - | -v / | ||
| - | -p 80:80 \ | ||
| - | -p 443:443 \ | ||
| - | -d nginx | ||
| - | </ | ||
| - | |||
| - | 5. Probar | ||
| - | |||
| - | Para esta prueba necesitamos los siguientes requisitos: | ||
| - | |||
| - | * Ingress de nginx instalado y configurado [[informatica: | ||
| - | * Nombre DNS (en este ejemplo ' | ||
| - | * [[informatica: | ||
| - | |||
| - | 5.1. Pronbar que el contenedor está corriendo: | ||
| - | |||
| - | docker logs -f edge-router | ||
| - | |||
| - | 5.2. Abrir un navegador y acceder a la URL configurada en el ingress route, en este ejemplo " | ||
| - | |||
| - | https:// | ||
| - | | ||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | Hostname: deployment-whoami-6b6dc7c84-tbv7d | ||
| - | IP: 127.0.0.1 | ||
| - | IP: 10.244.2.4 | ||
| - | RemoteAddr: 10.244.2.8: | ||
| - | GET / HTTP/1.1 | ||
| - | Host: example.com | ||
| - | User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/ | ||
| - | Accept: text/ | ||
| - | Accept-Encoding: | ||
| - | Accept-Language: | ||
| - | Upgrade-Insecure-Requests: | ||
| - | X-Forwarded-For: | ||
| - | X-Forwarded-Host: | ||
| - | X-Forwarded-Port: | ||
| - | X-Forwarded-Proto: | ||
| - | X-Real-Ip: 8.8.8.8 | ||
| - | X-Request-Id: | ||
| - | X-Scheme: https | ||
| - | </ | ||
| - | |||
| - | Donde ' | ||
| - | |||
| - | ===== LoadBalancer ===== | ||
| - | |||
| - | **AVISO**: funciona, pero no devuelve la IP origen. Igual cambiando algo se puede conseguir | ||
| - | |||
| - | |||
| - | En nuestro caso se van a redirigir todas las peticiones no a un servicio de tipo ' | ||
| - | |||
| - | Esquema: | ||
| - | |||
| - | [Cliente DMZ] => https:// | ||
| - | |||
| - | Si lo hiciéramos con servicios de tipo [[https:// | ||
| - | |||
| - | Nuestro edge router: | ||
| - | |||
| - | * Tiene una IP pública. | ||
| - | * Tiene una IP privada del rango de IPs del [[informatica: | ||
| - | * Tiene instalado docker (porque el servicio nginx va a ser creado mediante un contenedor). | ||
| - | |||
| - | Instalación: | ||
| - | |||
| - | 1. Conectarnos al edge router | ||
| - | |||
| - | ssh edgerouter | ||
| - | | ||
| - | 2. Crear el siguiente archivo, ajustando la IP a la que le ha sido asignada al [[informatica: | ||
| - | |||
| - | vim nginx.conf | ||
| - | | ||
| - | Con el siguiente contenido: | ||
| - | |||
| - | < | ||
| - | user nginx; | ||
| - | worker_processes | ||
| - | |||
| - | error_log | ||
| - | pid / | ||
| - | |||
| - | |||
| - | events { | ||
| - | worker_connections | ||
| - | } | ||
| - | |||
| - | |||
| - | http { | ||
| - | include | ||
| - | default_type | ||
| - | |||
| - | log_format main ' | ||
| - | '" | ||
| - | '" | ||
| - | |||
| - | access_log | ||
| - | |||
| - | sendfile | ||
| - | # | ||
| - | |||
| - | keepalive_timeout | ||
| - | |||
| - | #gzip on; | ||
| - | |||
| - | include / | ||
| - | } | ||
| - | |||
| - | stream { | ||
| - | |||
| - | map $ssl_preread_server_name $targetBackend { | ||
| - | ~^(.*)$ 192.168.95.68: | ||
| - | } | ||
| - | |||
| - | server { | ||
| - | listen 443; | ||
| - | |||
| - | proxy_pass $targetBackend; | ||
| - | ssl_preread on; | ||
| - | } | ||
| - | |||
| - | log_format basic ' | ||
| - | ' | ||
| - | ''; | ||
| - | |||
| - | access_log | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | 3. Crear el siguiente archivo, ajustando la IP a la que le ha sido asignada al [[informatica: | ||
| - | |||
| - | vim default.conf | ||
| - | | ||
| - | Con el siguiente contenido: | ||
| - | |||
| - | < | ||
| - | proxy_set_header X-Real-IP | ||
| - | proxy_set_header X-Forwarded-For $remote_addr; | ||
| - | |||
| - | server { | ||
| - | listen 80; | ||
| - | location / { | ||
| - | # | ||
| - | proxy_pass http://php; | ||
| - | proxy_set_header Host $host; | ||
| - | proxy_set_header X-Forwarded-For $remote_addr; | ||
| - | } | ||
| - | error_page 404 /404.html; | ||
| - | location = /404.html { | ||
| - | root / | ||
| - | internal; | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | 4. Arrancar el contenedor, ajustando las rutas a los archivos de configuración, | ||
| - | |||
| - | < | ||
| - | docker run \ | ||
| - | --name reverse-proxy \ | ||
| - | -v / | ||
| - | -v / | ||
| - | -p 80:80 \ | ||
| - | -p 443:443 \ | ||
| - | -d nginx | ||
| - | docker logs -f reverse-proxy | ||
| - | </ | ||
| - | |||
| - | ===== Redundancia ===== | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * Dos servidores | ||
| - | * Cada uno de los cuales tiene una IP pública | ||
| - | * Existe una tercera IP pública (" | ||
| - | * Las 3 IPs públicas (las de cada servidor y la flotante) están en la misma subred | ||
| - | |||
| - | 1. Instalar los dos servidores [[informatica: | ||
| - | |||
| - | 2. Instalar y configurar en ambos servidores [[informatica: | ||
| - | ====== Ingress ====== | ||
| - | |||
| - | Según su propia [[https:// | ||
| - | |||
| - | |||
| - | An API object that manages external access to the services in a cluster, typically HTTP. | ||
| - | |||
| - | ===== Nginx ===== | ||
| - | |||
| - | [[https:// | ||
| - | |||
| - | ==== Nginx NodePort con afinitty (usar este) ==== | ||
| - | |||
| - | Con este procedimiento podremos obtener la IP de origen en los pods, con las otras aproximaciones todavía no lo he conseguido. | ||
| - | |||
| - | Características: | ||
| - | |||
| - | * Usaremos [[https:// | ||
| - | * Usaremos " | ||
| - | * Usaremos " | ||
| - | * La contrapartida a la regla anterior es que usaremos [[https:// | ||
| - | |||
| - | 1. Conectarse al master | ||
| - | |||
| - | ssh k8s2 | ||
| - | |||
| - | 2. Obtener el [[https:// | ||
| - | |||
| - | wget https:// | ||
| - | |||
| - | 3. Añadir réplicas, tantas como worker nodes, en este ejemplo 3. Editar: | ||
| - | |||
| - | vim deploy.yaml | ||
| - | | ||
| - | Y añadir ' | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: apps/v1 | ||
| - | kind: Deployment | ||
| - | metadata: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | </ | ||
| - | |||
| - | Por: | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: apps/v1 | ||
| - | kind: Deployment | ||
| - | metadata: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | # Tantas replicas como node worker | ||
| - | replicas: 3 | ||
| - | </ | ||
| - | | ||
| - | 4. Forzar que los pods solo envien tráfico a los deployments, | ||
| - | |||
| - | vim deploy.yaml | ||
| - | | ||
| - | Y cambiar: | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | annotations: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | </ | ||
| - | |||
| - | Por: | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | annotations: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | # this setting is t make sure the source IP address is preserved. | ||
| - | externalTrafficPolicy: | ||
| - | </ | ||
| - | |||
| - | 5. Forzar que solo haya un pod de tipo nginx ingress controller corriendo en cada worker node, y que no levante ninguno de esos pods en los control plane. Lo hacemos añadiendo la clave ' | ||
| - | |||
| - | vim deploy.yml | ||
| - | | ||
| - | Y cambiar: | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: apps/v1 | ||
| - | kind: Deployment | ||
| - | metadata: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | # We need one pod running on each node | ||
| - | replicas: 3 | ||
| - | selector: | ||
| - | matchLabels: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | revisionHistoryLimit: | ||
| - | minReadySeconds: | ||
| - | template: | ||
| - | metadata: | ||
| - | labels: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | spec: | ||
| - | </ | ||
| - | |||
| - | Por: | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: apps/v1 | ||
| - | kind: Deployment | ||
| - | metadata: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | # We need one pod running on each node | ||
| - | replicas: 3 | ||
| - | selector: | ||
| - | matchLabels: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | revisionHistoryLimit: | ||
| - | minReadySeconds: | ||
| - | template: | ||
| - | metadata: | ||
| - | labels: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | spec: | ||
| - | affinity: | ||
| - | # Prevent starting pod in a node which already have one pod started | ||
| - | podAntiAffinity: | ||
| - | requiredDuringSchedulingIgnoredDuringExecution: | ||
| - | - labelSelector: | ||
| - | matchExpressions: | ||
| - | - key: app.kubernetes.io/ | ||
| - | operator: In | ||
| - | values: | ||
| - | - controller | ||
| - | topologyKey: | ||
| - | # Prevent starting pod in the master node | ||
| - | nodeAffinity: | ||
| - | requiredDuringSchedulingIgnoredDuringExecution: | ||
| - | nodeSelectorTerms: | ||
| - | - matchExpressions: | ||
| - | - key: node-role.kubernetes.io/ | ||
| - | operator: DoesNotExist | ||
| - | </ | ||
| - | |||
| - | 6. Reemplazar para el tipo de balanceo para el servicio | ||
| - | |||
| - | vim deploy.yml | ||
| - | | ||
| - | Y cambiar: | ||
| - | |||
| - | < | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | labels: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | externalTrafficPolicy: | ||
| - | ports: | ||
| - | - appProtocol: | ||
| - | name: http | ||
| - | port: 80 | ||
| - | protocol: TCP | ||
| - | targetPort: http | ||
| - | - appProtocol: | ||
| - | name: https | ||
| - | port: 443 | ||
| - | protocol: TCP | ||
| - | targetPort: https | ||
| - | selector: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | type: LoadBalancer | ||
| - | </ | ||
| - | |||
| - | Por: | ||
| - | |||
| - | < | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | labels: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | externalTrafficPolicy: | ||
| - | ports: | ||
| - | - appProtocol: | ||
| - | name: http | ||
| - | port: 80 | ||
| - | protocol: TCP | ||
| - | targetPort: http | ||
| - | - appProtocol: | ||
| - | name: https | ||
| - | port: 443 | ||
| - | protocol: TCP | ||
| - | targetPort: https | ||
| - | selector: | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | # anyadido | ||
| - | #type: LoadBalancer | ||
| - | type: NodePort | ||
| - | </ | ||
| - | |||
| - | 7. Instalar. Ejecutar: | ||
| - | |||
| - | kubectl apply -f deploy.yaml | ||
| - | |||
| - | 8. Probar | ||
| - | |||
| - | 8.1. Ejecutar: | ||
| - | |||
| - | kubectl get pods \ | ||
| - | -n ingress-nginx \ | ||
| - | -l app.kubernetes.io/ | ||
| - | -o wide \ | ||
| - | --watch | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | ingress-nginx-controller-55bc4f5576-78rmm | ||
| - | ingress-nginx-controller-55bc4f5576-f27v5 | ||
| - | ingress-nginx-controller-55bc4f5576-v7f6h | ||
| - | ingress-nginx-controller-6f7c7fb6f8-xvzcs | ||
| - | </ | ||
| - | |||
| - | **IMPORTANTE**: | ||
| - | |||
| - | 8.2. Verificar que efectivamente cada servicio (ingress controller) corre en un node worker distinto. Ejecutar: | ||
| - | |||
| - | kubectl get nodes | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | k8s4 | ||
| - | k8s5 | ||
| - | k8s6 | ||
| - | k8s7 | ||
| - | </ | ||
| - | |||
| - | Tenemos pues tres workers: | ||
| - | |||
| - | * k8s5 | ||
| - | * k8s6 | ||
| - | * k8s7 | ||
| - | |||
| - | Todo correcto, cada worker tiene al menos un pod corriendo. | ||
| - | |||
| - | 8.3. Comprobar la versión. Ejecutar: | ||
| - | |||
| - | < | ||
| - | POD_NAMESPACE=ingress-nginx | ||
| - | POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/ | ||
| - | kubectl exec -it $POD_NAME -n $POD_NAMESPACE -- / | ||
| - | </ | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | ------------------------------------------------------------------------------- | ||
| - | NGINX Ingress controller | ||
| - | Release: | ||
| - | Build: | ||
| - | Repository: | ||
| - | nginx version: nginx/ | ||
| - | |||
| - | ------------------------------------------------------------------------------- | ||
| - | </ | ||
| - | |||
| - | 9. Obtener los puertos expuestos. Esto es necesario para instalar y configura el edge router. Ejecutar: | ||
| - | |||
| - | kubectl get services -n ingress-nginx --field-selector metadata.name=ingress-nginx-controller | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | ingress-nginx-controller | ||
| - | </ | ||
| - | |||
| - | Por lo tanto en este ejemplo: | ||
| - | |||
| - | * HTTP => 31104 | ||
| - | * HTTPS => 30893 | ||
| - | |||
| - | 10. [[informatica: | ||
| - | |||
| - | ==== Nginx LoadBalancer ==== | ||
| - | |||
| - | En este ejemplo asumimos que tenemos un LoadBalancer habilitado, porque hemos instalado [[informatica: | ||
| - | |||
| - | 1. Conectarse al master: | ||
| - | |||
| - | ssh master | ||
| - | |||
| - | 2. Obtener el manifiesto: | ||
| - | |||
| - | wget https:// | ||
| - | | ||
| - | 3. Editarlo: | ||
| - | |||
| - | vim deploy.yaml | ||
| - | | ||
| - | Y substituir "type: NodePort": | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | annotations: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | type: NodePort | ||
| - | </ | ||
| - | |||
| - | por "type: LoadBalancer": | ||
| - | |||
| - | < | ||
| - | # Source: ingress-nginx/ | ||
| - | apiVersion: v1 | ||
| - | kind: Service | ||
| - | metadata: | ||
| - | annotations: | ||
| - | labels: | ||
| - | helm.sh/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | app.kubernetes.io/ | ||
| - | name: ingress-nginx-controller | ||
| - | namespace: ingress-nginx | ||
| - | spec: | ||
| - | type: LoadBalancer | ||
| - | </ | ||
| - | |||
| - | 4. Instalar el manifiesto: | ||
| - | |||
| - | kubectl apply -f deploy.yaml | ||
| - | |||
| - | 5. Probar. | ||
| - | |||
| - | 5.1. Ejecutar: | ||
| - | |||
| - | kubectl get pods -n ingress-nginx \ | ||
| - | -l app.kubernetes.io/ | ||
| - | |||
| - | Hasta que el ' | ||
| - | |||
| - | < | ||
| - | NAME READY | ||
| - | ingress-nginx-admission-create-jw7f8 | ||
| - | ingress-nginx-admission-patch-b99q4 | ||
| - | ingress-nginx-controller-55bc4f5576-77bh8 | ||
| - | </ | ||
| - | |||
| - | 5.2. Ejecutar: | ||
| - | |||
| - | kubectl get services --field-selector metadata.name=ingress-nginx-controller -n ingress-nginx | ||
| - | |||
| - | El resultado esperado es similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | ingress-nginx-controller | ||
| - | </ | ||
| - | |||
| - | Vemos que ha tomado una ' | ||
| - | |||
| - | 5.3. Ejecutar: | ||
| - | |||
| - | < | ||
| - | POD_NAMESPACE=ingress-nginx | ||
| - | POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/ | ||
| - | kubectl exec -it $POD_NAME -n $POD_NAMESPACE -- / | ||
| - | </ | ||
| - | | ||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | ------------------------------------------------------------------------------- | ||
| - | NGINX Ingress controller | ||
| - | Release: | ||
| - | Build: | ||
| - | Repository: | ||
| - | nginx version: nginx/ | ||
| - | |||
| - | ------------------------------------------------------------------------------- | ||
| - | </ | ||
| - | |||
| - | Por tanto en este ejemplo las peticiones que lleguen a la IP " | ||
| - | |||
| - | ===== Ejemplo ingress ===== | ||
| - | |||
| - | Este ejemplo requiere: | ||
| - | |||
| - | * Un [[informatica: | ||
| - | * Tener instalado un [[https:// | ||
| - | |||
| - | 1. Conectarse al master | ||
| - | |||
| - | ssh master | ||
| - | | ||
| - | 2. Ejecutar: | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: networking.k8s.io/ | ||
| - | kind: Ingress | ||
| - | metadata: | ||
| - | annotations: | ||
| - | kubernetes.io/ | ||
| - | name: ingress-whoami | ||
| - | spec: | ||
| - | rules: | ||
| - | - host: example.com | ||
| - | http: | ||
| - | paths: | ||
| - | - backend: | ||
| - | service: | ||
| - | name: service-whoami | ||
| - | port: | ||
| - | number: 80 | ||
| - | path: / | ||
| - | pathType: Prefix | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | 3. Verificar | ||
| - | |||
| - | kubectl get ingress --field-selector metadata.name=ingress-whoami | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | ingress-whoami | ||
| - | </ | ||
| - | |||
| - | Con esta configuración: | ||
| - | |||
| - | * Las peticiones que le lleguen a la IP que tiene le servicio ' | ||
| - | * Si se recibe una petición HTTP en el puerto TCP 80 o TCP 443 con un ' | ||
| - | |||
| - | ===== Ejemplo ingress con letsencrypt ===== | ||
| - | |||
| - | Este ejemplo requiere: | ||
| - | |||
| - | * Un [[informatica: | ||
| - | * Tener instalado un [[https:// | ||
| - | * Tener instalado el [[https:// | ||
| - | * Tener instalado un [[informatica: | ||
| - | * [[informatica: | ||
| - | * Nginx | ||
| - | * Reverse proxy a ingress-nginx-controller ' | ||
| - | * Que no termine las conexiones SSL, es decr, que redirija en capa 4 lo que le llegue a TCP 443 | ||
| - | * Un nombre DNS, en este ejemplo " | ||
| - | |||
| - | 1. Conectarse al master: | ||
| - | |||
| - | ssh master | ||
| - | | ||
| - | 2. Ejecutar: | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: networking.k8s.io/ | ||
| - | kind: Ingress | ||
| - | metadata: | ||
| - | annotations: | ||
| - | # Should match ' | ||
| - | cert-manager.io/ | ||
| - | kubernetes.io/ | ||
| - | name: ingress-whoami | ||
| - | spec: | ||
| - | rules: | ||
| - | - host: example.com | ||
| - | http: | ||
| - | paths: | ||
| - | - path: / | ||
| - | pathType: Prefix | ||
| - | backend: | ||
| - | service: | ||
| - | name: service-whoami | ||
| - | port: | ||
| - | number: 80 | ||
| - | tls: | ||
| - | - hosts: | ||
| - | - example.com | ||
| - | secretName: quickstart-example-tls | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | 3. Comprobar | ||
| - | |||
| - | 3.1. Ejecutar: | ||
| - | |||
| - | watch -n 5 kubectl get certificate | ||
| - | |||
| - | El resultado esperado, tras aproximadamente un minuto, es: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | quickstart-example-tls | ||
| - | </ | ||
| - | |||
| - | 3.2. Se ha creado un secret llamado ' | ||
| - | |||
| - | kubectl describe secrets quickstart-example-tls | ||
| - | | ||
| - | Salida esperada similar a: | ||
| - | |||
| - | < | ||
| - | Name: | ||
| - | Namespace: | ||
| - | Labels: | ||
| - | Annotations: | ||
| - | cert-manager.io/ | ||
| - | cert-manager.io/ | ||
| - | cert-manager.io/ | ||
| - | cert-manager.io/ | ||
| - | cert-manager.io/ | ||
| - | cert-manager.io/ | ||
| - | cert-manager.io/ | ||
| - | |||
| - | Type: kubernetes.io/ | ||
| - | |||
| - | Data | ||
| - | ==== | ||
| - | tls.crt: | ||
| - | tls.key: | ||
| - | </ | ||
| - | |||
| - | 3.3. Abrir un navegador e ir a: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | Debería aparecer el contenido servido por el [[informatica: | ||
| - | ' | ||
| - | |||
| - | ===== Ejemplo ingress con modsecurity ===== | ||
| - | |||
| - | Requisitos: | ||
| - | |||
| - | * Crear un servicio " | ||
| - | |||
| - | < | ||
| - | cat <<EOF | kubectl apply -f - | ||
| - | apiVersion: networking.k8s.io/ | ||
| - | kind: Ingress | ||
| - | metadata: | ||
| - | annotations: | ||
| - | # https:// | ||
| - | nginx.ingress.kubernetes.io/ | ||
| - | nginx.ingress.kubernetes.io/ | ||
| - | SecRuleEngine On | ||
| - | SecRequestBodyAccess On | ||
| - | SecAuditEngine RelevantOnly | ||
| - | SecAuditLogParts ABIJDEFHZ | ||
| - | SecAuditLog / | ||
| - | SecRule REQUEST_HEADERS: | ||
| - | name: ingress-echoserver | ||
| - | spec: | ||
| - | rules: | ||
| - | - host: example.com | ||
| - | http: | ||
| - | paths: | ||
| - | - path: / | ||
| - | pathType: Prefix | ||
| - | backend: | ||
| - | service: | ||
| - | name: service-echoserver | ||
| - | port: | ||
| - | number: 80 | ||
| - | EOF | ||
| - | </ | ||
| - | |||
| - | Probar: | ||
| - | |||
| - | curl http:// | ||
| - | |||
| - | Respuesta esperada: 403 | ||
| - | ====== ConfigMaps ====== | ||
| - | |||
| - | [[https:// | ||
| - | |||
| - | ===== Editar ConfigMaps para habilitar ' | ||
| - | |||
| - | **IMPORTANTE**: | ||
| - | |||
| - | En este ejemplo: | ||
| - | |||
| - | * Vamos a editar un ConfigMap | ||
| - | * Vamos a ver los cambios que se aplican inmediatamente en el pod | ||
| - | |||
| - | 1. Identificar el ConfigMap. En nuestro caso queremos modificar [[https:// | ||
| - | |||
| - | kubectl get configmaps -n ingress-nginx | ||
| - | | ||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME DATA AGE | ||
| - | ingress-controller-leader-nginx | ||
| - | ingress-nginx-controller | ||
| - | kube-root-ca.crt | ||
| - | </ | ||
| - | |||
| - | En nuestro caso es [[https:// | ||
| - | |||
| - | 2. Editamos el ' | ||
| - | |||
| - | kubectl edit configmaps -n ingress-nginx ingress-nginx-controller | ||
| - | |||
| - | Vamos a seguir [[https:// | ||
| - | |||
| - | < | ||
| - | data: | ||
| - | use-proxy-protocol: | ||
| - | </ | ||
| - | |||
| - | 3. Comprobar | ||
| - | |||
| - | 3.1. Buscar el pod que usa ese ' | ||
| - | |||
| - | kubectl get pods -n ingress-nginx | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME READY | ||
| - | ingress-nginx-admission-create-glxnx | ||
| - | ingress-nginx-admission-patch-njb2p | ||
| - | ingress-nginx-controller-598dd75597-lkpp8 | ||
| - | ingress-nginx-controller-598dd75597-s9kwg | ||
| - | </ | ||
| - | |||
| - | 3.2. Ver los logs | ||
| - | |||
| - | kubectl logs -f -n ingress-nginx ingress-nginx-controller-598dd75597-lkpp8 | ||
| - | |||
| - | Resultado similar a: | ||
| - | |||
| - | < | ||
| - | I0520 15: | ||
| - | I0520 15: | ||
| - | I0520 15: | ||
| - | I0520 15: | ||
| - | </ | ||
| - | |||
| - | 3.3. Comprobar si se ha añadido un setting [[https:// | ||
| - | |||
| - | kubectl exec -ti -n ingress-nginx ingress-nginx-controller-598dd75597-lkpp8 -- cat / | ||
| - | |||
| - | Salida esperada similar a: | ||
| - | |||
| - | < | ||
| - | listen 80 proxy_protocol default_server reuseport backlog=511 ; | ||
| - | listen 443 proxy_protocol default_server reuseport backlog=511 ssl http2 ; | ||
| - | listen 80 proxy_protocol ; | ||
| - | listen 443 proxy_protocol ssl http2 ; | ||
| - | </ | ||
| - | |||
| - | Por tanto el ' | ||
| - | ====== Desconectar nodo ====== | ||
| - | |||
| - | {{https:// | ||
| - | |||
| - | ===== Worker ===== | ||
| - | |||
| - | 1. Conectarnos a un control plane | ||
| - | |||
| - | ssh k8s2 | ||
| - | | ||
| - | 2. Listar nodos: | ||
| - | |||
| - | kubectl get nodes | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | k8s4 | ||
| - | k8s5 | ||
| - | k8s6 | ||
| - | k8s7 | ||
| - | </ | ||
| - | |||
| - | 3. Vaciar de pods el worker node: | ||
| - | |||
| - | kubectl drain k8s7 | ||
| - | |||
| - | Em este caso nos aparece el siguiente error: | ||
| - | |||
| - | < | ||
| - | node/k8s7 cordoned | ||
| - | error: unable to drain node " | ||
| - | |||
| - | There are pending nodes to be drained: | ||
| - | k8s7 | ||
| - | error: cannot delete DaemonSet-managed Pods (use --ignore-daemonsets to ignore): kube-system/ | ||
| - | </ | ||
| - | |||
| - | 4. Reintentar el comando anterior añadiendo algunos parámetros: | ||
| - | |||
| - | kubectl drain k8s7 --ignore-daemonsets | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | node/k8s7 already cordoned | ||
| - | WARNING: ignoring DaemonSet-managed Pods: kube-system/ | ||
| - | evicting pod ingress-nginx/ | ||
| - | evicting pod cert-manager/ | ||
| - | evicting pod cert-manager/ | ||
| - | evicting pod ingress-nginx/ | ||
| - | pod/ | ||
| - | pod/ | ||
| - | pod/ | ||
| - | pod/ | ||
| - | node/k8s7 evicted | ||
| - | </ | ||
| - | |||
| - | En este punto: | ||
| - | |||
| - | * El worker ' | ||
| - | * Todavía está corriendo pods de tipo [[https:// | ||
| - | |||
| - | 5. (Opcional) Comprobar el estado de los nodos: | ||
| - | |||
| - | kubectl get nodes | ||
| - | | ||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | k8s4 | ||
| - | k8s5 | ||
| - | k8s6 | ||
| - | k8s7 | ||
| - | </ | ||
| - | |||
| - | 6. (Opcional) Listar los pods que todavía están corriendo en el worker ' | ||
| - | |||
| - | kubectl get pods --all-namespaces -o wide | grep k8s7 | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | kube-system | ||
| - | kube-system | ||
| - | </ | ||
| - | |||
| - | 7. Eliminar el nodo | ||
| - | |||
| - | kubectl delete node k8s7 | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | node " | ||
| - | |||
| - | 8. Comprobar: | ||
| - | |||
| - | kubectl get nodes -w | ||
| - | |||
| - | Después de un minuto aproximadamente habrá desaparecido: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | k8s4 | ||
| - | k8s5 | ||
| - | k8s6 | ||
| - | </ | ||
| - | |||
| - | ====== Definir tiempo pod salta a otro worker ====== | ||
| - | |||
| - | Por defecto un pod saltará a otro worker tras **5 minutos** de que el worker esté marcado como " | ||
| - | |||
| - | **AVISO**: el parámetro [[https:// | ||
| - | |||
| - | 1. Conectarse al control plane | ||
| - | |||
| - | ssh k8s2 | ||
| - | | ||
| - | 2. Realizar una copia de seguridad: | ||
| - | |||
| - | sudo cp / | ||
| - | |||
| - | 3. Editar: | ||
| - | |||
| - | sudo vim / | ||
| - | |||
| - | Y añadir ' | ||
| - | |||
| - | < | ||
| - | # anyadido | ||
| - | - --default-not-ready-toleration-seconds=30 | ||
| - | - --default-unreachable-toleration-seconds=30 | ||
| - | </ | ||
| - | |||
| - | Ejemplo: | ||
| - | |||
| - | < | ||
| - | apiVersion: v1 | ||
| - | kind: Pod | ||
| - | metadata: | ||
| - | annotations: | ||
| - | kubeadm.kubernetes.io/ | ||
| - | creationTimestamp: | ||
| - | labels: | ||
| - | component: kube-apiserver | ||
| - | tier: control-plane | ||
| - | name: kube-apiserver | ||
| - | namespace: kube-system | ||
| - | spec: | ||
| - | containers: | ||
| - | - command: | ||
| - | - kube-apiserver | ||
| - | - --advertise-address=192.168.95.71 | ||
| - | # anyadido | ||
| - | - --default-not-ready-toleration-seconds=30 | ||
| - | - --default-unreachable-toleration-seconds=30 | ||
| - | ... | ||
| - | </ | ||
| - | |||
| - | 4. Repetir los pasos 1 a 3 para el resto de control plane, en el caso de que haya más por ser un entorno de alta disponibilidad | ||
| - | |||
| - | 5. Comprobar | ||
| - | |||
| - | 5.1. Comprobar que todos y cada uno de los control plane tienen un pod ' | ||
| - | |||
| - | watch -n 5 " | ||
| - | |||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | kube-system | ||
| - | kube-system | ||
| - | kube-system | ||
| - | </ | ||
| - | |||
| - | 5.2. Identificar los pods que corren en un worker: | ||
| - | |||
| - | kubectl get pods -o wide | ||
| - | | ||
| - | Resultado esperado similar a: | ||
| - | |||
| - | < | ||
| - | NAME READY | ||
| - | deployment-whoami-6b6dc7c84-2swm9 | ||
| - | </ | ||
| - | |||
| - | 5.3. Detener el worker donde está corriendo el pod | ||
| - | |||
| - | 5.3.1. Conectarse al worker | ||
| - | |||
| - | ssh k8s5 | ||
| - | | ||
| - | 5.3.2. Apagarlo | ||
| - | |||
| - | sudo shutdown -h now | ||
| - | | ||
| - | 5.3.3. Anotar la hora | ||
| - | |||
| - | date | ||
| - | | ||
| - | 5.4. Monitorizar nodos | ||
| - | |||
| - | watch -n 5 kubectl get nodes | ||
| - | |||
| - | Resultado esperado similar a **tras aproximadamente 30 segundos**: | ||
| - | |||
| - | < | ||
| - | NAME | ||
| - | k8s2 | ||
| - | k8s3 | ||
| - | k8s4 | ||
| - | k8s5 | ||
| - | k8s6 | ||
| - | </ | ||
| - | |||
| - | 5.5. Monitorizar pods | ||
| - | |||
| - | watch -n 5 kubectl get pods -o wide | ||
| - | |||
| - | Resultado esperado similar a **tras aproximadamente 60 segundos**: | ||
| - | |||
| - | < | ||
| - | NAME READY | ||
| - | ODE | ||
| - | deployment-whoami-6b6dc7c84-2swm9 | ||
| - | 8s5 < | ||
| - | deployment-whoami-6b6dc7c84-mrjjw | ||
| - | 8s6 < | ||
| - | </ | ||
| - | ====== LOCAL ====== | ||
| - | Bajamos código fuente de kubernetes e instalamos: | ||
| - | |||
| - | # git clone https:// | ||
| - | # cd kubernetes | ||
| - | # make quick-release | ||
| - | |||
| - | Ahora para acabar de instalar hay que decir en que proveedor crea las máquinas virtuales. Lista sacada de https:// | ||
| - | |||
| - | Google Compute Engine [default] | ||
| - | KUBERNETES_PROVIDER=gce | ||
| - | | ||
| - | Google Container Engine | ||
| - | KUBERNETES_PROVIDER=gke | ||
| - | | ||
| - | Amazon EC2 | ||
| - | KUBERNETES_PROVIDER=aws | ||
| - | | ||
| - | Libvirt (with CoreOS as a guest operating system) | ||
| - | KUBERNETES_PROVIDER=libvirt-coreos | ||
| - | | ||
| - | Microsoft Azure | ||
| - | KUBERNETES_PROVIDER=azure-legacy | ||
| - | | ||
| - | Vagrant (local virtual machines) | ||
| - | KUBERNETES_PROVIDER=vagrant | ||
| - | | ||
| - | VMWare Photon Controller | ||
| - | KUBERNETES_PROVIDER=photon-controller | ||
| - | | ||
| - | Rackspace | ||
| - | KUBERNETES_PROVIDER=rackspace | ||
| - | | ||
| - | OpenStack-Heat | ||
| - | KUBERNETES_PROVIDER=openstack-heat | ||
| - | |||
| - | En nuestro caso elegimos vagrant que es virtualbox. Instalamos virtualbox: | ||
| - | # apt-get install vagrant virtualbox | ||
| - | |||
| - | Para que nos cree las dos máquinas virtuales de virtualbox y configure kubernetes ejecutamos este script que se baja los binarios: | ||
| - | # export KUBERNETES_PROVIDER=vagrant | ||
| - | # wget -q -O - https:// | ||
| - | |||
| - | Nos dice que pongamos la ruta en el PATH y volvamos a ejecutarlo: | ||
| - | Add '/ | ||
| - | |||
| - | Lo ponemos y ejecutamos: | ||
| - | # export PATH=$PATH:/ | ||
| - | # wget -q -O - https:// | ||
| - | |||
| - | Crea dos máquinas con fedora: | ||
| - | # VBoxManage list vms | ||
| - | " | ||
| - | " | ||
| - | |||
| - | La instalación acabo con: | ||
| - | < | ||
| - | Each machine instance has been created/ | ||
| - | Now waiting for the Salt provisioning process to complete on each machine. | ||
| - | This can take some time based on your network, disk, and cpu speed. | ||
| - | It is possible for an error to occur during Salt provision of cluster and this could loop forever. | ||
| - | Validating master | ||
| - | .................................. | ||
| - | </ | ||
| - | Parece que se queda colgado..... | ||
| - | |||
| - | Lo lanzo en casa y funciona: | ||
| - | < | ||
| - | Each machine instance has been created/ | ||
| - | Now waiting for the Salt provisioning process to complete on each machine. | ||
| - | This can take some time based on your network, disk, and cpu speed. | ||
| - | It is possible for an error to occur during Salt provision of cluster and this could loop forever. | ||
| - | Validating master | ||
| - | Validating node-1 | ||
| - | |||
| - | Waiting for each node to be registered with cloud provider | ||
| - | Flag --api-version has been deprecated, flag is no longer respected and will be deleted in the next release | ||
| - | Validating we can run kubectl commands. | ||
| - | No resources found. | ||
| - | |||
| - | Kubernetes cluster is running. | ||
| - | |||
| - | The master is running at: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | Administer and visualize its resources using Cockpit: | ||
| - | |||
| - | https:// | ||
| - | |||
| - | For more information on Cockpit, visit http:// | ||
| - | |||
| - | The user name and password to use is located in / | ||
| - | |||
| - | ... calling validate-cluster | ||
| - | Found 1 node(s). | ||
| - | NAME STATUS | ||
| - | kubernetes-node-1 | ||
| - | Validate output: | ||
| - | NAME | ||
| - | scheduler | ||
| - | controller-manager | ||
| - | etcd-0 | ||
| - | etcd-1 | ||
| - | Cluster validation succeeded | ||
| - | Done, listing cluster services: | ||
| - | |||
| - | Kubernetes master is running at https:// | ||
| - | Heapster is running at https:// | ||
| - | KubeDNS is running at https:// | ||
| - | kubernetes-dashboard is running at https:// | ||
| - | Grafana is running at https:// | ||
| - | InfluxDB is running at https:// | ||
| - | |||
| - | To further debug and diagnose cluster problems, use ' | ||
| - | |||
| - | Kubernetes binaries at / | ||
| - | You may want to add this directory to your PATH in $HOME/ | ||
| - | Installation successful! | ||
| - | |||
| - | </ | ||
| - | |||
| - | Arrancamos el proxy y ya podemos acceder a la UI del dashboard de Kubernetes: | ||
| - | # ./ | ||
| - | | ||
| - | Starting to serve on 127.0.0.1: | ||
| - | |||
| - | http:// | ||
| - | |||
| - | usuario: vagrant | ||
| - | contraseña: | ||
| - | |||
| - | |||
| - | ====== MINIKUBE ====== | ||
| - | https:// | ||
| - | |||
| - | 1. Instalamos kubectl | ||
| - | |||
| - | https:// | ||
| - | |||
| - | curl -LO https:// | ||
| - | |||
| - | Lo ponemos en el path: | ||
| - | chmod +x ./kubectl | ||
| - | sudo mv ./kubectl / | ||
| - | |||
| - | 2. Instalamos minikube | ||
| - | https:// | ||
| - | |||
| - | Ojo que puede cambiar versión, id a web: | ||
| - | curl -Lo minikube https:// | ||
| - | |||
| - | Creamos el cluster. Primero crea la VM en virtualbox y luego la levanta y configura los servicios: | ||
| - | # minikube start | ||
| - | | ||
| - | Starting local Kubernetes cluster... | ||
| - | Downloading Minikube ISO | ||
| - | 84.07 MB / 84.07 MB [==============================================] 100.00% 0s | ||
| - | Kubectl is now configured to use the cluster. | ||
| - | |||
| - | |||
| - | # vboxmanage list vms | ||
| - | | ||
| - | " | ||
| - | |||
| - | |||
| - | Para conectar a la VM de virtualbox llamada minikube: | ||
| - | ssh docker@192.168.99.100 | ||
| - | docker/ | ||
| - | Miramos que tiene desplegado: | ||
| - | # kubectl get pods --all-namespaces | ||
| - | | ||
| - | NAMESPACE | ||
| - | kube-system | ||
| - | Instalamos el dashboard: | ||
| - | # kubectl create -f https:// | ||
| - | | ||
| - | deployment " | ||
| - | service " | ||
| - | |||
| - | # kubectl get services --all-namespaces | ||
| - | | ||
| - | NAMESPACE | ||
| - | default | ||
| - | kube-system | ||
| - | | ||
| - | **Dashboard: | ||
| - | minikube dashboard | ||
| - | Te abre http:// | ||
| - | |||
| - | También he hecho un tunel 8080: | ||
| - | ssh -L 8080: | ||
| - | |||
| - | Url de acceso: http:// | ||
| - | |||
| - | ====== Autoescalado ====== | ||
| - | https:// | ||
| - | |||
| - | http:// | ||
| - | |||
| - | https:// | ||
| - | |||
| - | https:// | ||
| - | |||
| - | Autoescalamos la aplicación: | ||
| - | kubectl autoscale deployment apache --min=2 --max=5 --cpu-percent=20 | ||
| - | |||
| - | deployment " | ||
| - | |||
| - | Vemos el autoescalado. Desde la UI se ve en deployments: | ||
| - | kubectl get hpa | ||
| - | |||
| - | NAME REFERENCE | ||
| - | apache | ||
| - | |||
| - | Con mas detalle: | ||
| - | kubectl describe hpa apache | ||
| - | < | ||
| - | Name: | ||
| - | Namespace: | ||
| - | Labels: | ||
| - | Annotations: | ||
| - | CreationTimestamp: | ||
| - | Reference: | ||
| - | Metrics: | ||
| - | resource cpu on pods (as a percentage of request): | ||
| - | Min replicas: | ||
| - | Max replicas: | ||
| - | Events: | ||
| - | FirstSeen LastSeen Count From SubObjectPath Type Reason Message | ||
| - | --------- -------- ----- ---- ------------- -------- ------ ------- | ||
| - | 6m 6m 1 horizontal-pod-autoscaler Normal SuccessfulRescale New size: 2; reason: Current number of replicas below Spec.MinReplicas | ||
| - | 5m 27s 12 horizontal-pod-autoscaler Warning FailedGetResourceMetric unable to get metrics for resource cpu: failed to get pod resource metrics: the server could not find the requested resource (get services http: | ||
| - | 5m 27s 12 horizontal-pod-autoscaler Warning FailedComputeMetricsReplicas failed to get cpu utilization: | ||
| - | </ | ||
| - | |||
| - | Daba el error: | ||
| - | kubectl describe hpa | ||
| - | |||
| - | 35m 18s 72 horizontal-pod-autoscaler Warning FailedComputeMetricsReplicas failed to get cpu utilization: | ||
| - | |||
| - | El problema es que en el deployment hay que decir que quiere monitorizar, | ||
| - | < | ||
| - | ...... | ||
| - | spec: | ||
| - | containers: | ||
| - | name: httpd | ||
| - | image: httpd | ||
| - | resources: | ||
| - | requests: | ||
| - | cpu:400m | ||
| - | ...... | ||
| - | </ | ||
| - | |||
| - | Después da este error, pero tarda un poco en coger las métricas de heapster: | ||
| - | kubectl describe hpa | ||
| - | |||
| - | 2m 1m 3 horizontal-pod-autoscaler Warning FailedComputeMetricsReplicas failed to get cpu utilization: | ||
| - | |||
| - | ====== LOCAL kubeadm ====== | ||
| - | Instalamos docker | ||
| - | |||
| - | apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common | ||
| - | curl -fsSL https:// | ||
| - | add-apt-repository "deb [arch=amd64] https:// | ||
| - | |||
| - | |||
| - | |||
| - | ====== Local en Centos ====== | ||
| - | https:// | ||
| - | |||
| - | Installing kubelet and kubeadm | ||
| - | |||
| - | < | ||
| - | cat <<EOF > / | ||
| - | [kubernetes] | ||
| - | name=Kubernetes | ||
| - | baseurl=https:// | ||
| - | enabled=1 | ||
| - | gpgcheck=1 | ||
| - | repo_gpgcheck=1 | ||
| - | gpgkey=https:// | ||
| - | https:// | ||
| - | EOF | ||
| - | setenforce 0 | ||
| - | yum install -y docker kubelet kubeadm kubernetes-cni | ||
| - | systemctl enable docker && systemctl start docker | ||
| - | systemctl enable kubelet && systemctl start kubelet | ||
| - | </ | ||
| - | |||
| - | ====== Debian ====== | ||
| - | |||
| - | < | ||
| - | apt-get update && apt-get install -y apt-transport-https | ||
| - | curl -s https:// | ||
| - | cat <<EOF >/ | ||
| - | deb http:// | ||
| - | EOF | ||
| - | apt-get update | ||
| - | # Install docker if you don't have it already. | ||
| - | apt-get install -y docker-engine | ||
| - | apt-get install -y kubelet kubeadm kubernetes-cni | ||
| - | </ | ||
| - | |||
| - | Arrancamos kubeadm | ||
| - | kubeadm init | ||
| - | |||
| - | < | ||
| - | Your Kubernetes master has initialized successfully! | ||
| - | |||
| - | To start using your cluster, you need to run (as a regular user): | ||
| - | |||
| - | sudo cp / | ||
| - | sudo chown $(id -u):$(id -g) $HOME/ | ||
| - | export KUBECONFIG=$HOME/ | ||
| - | |||
| - | You should now deploy a pod network to the cluster. | ||
| - | Run " | ||
| - | http:// | ||
| - | |||
| - | You can now join any number of machines by running the following on each node | ||
| - | as root: | ||
| - | |||
| - | kubeadm join --token bad112.b2514df7739b0845 192.168.1.133: | ||
| - | </ | ||
| - | |||
| - | Como usuario normal ejecutamos: | ||
| - | |||
| - | sudo cp / | ||
| - | sudo chown $(id -u):$(id -g) $HOME/ | ||
| - | export KUBECONFIG=$HOME/ | ||
| - | | ||
| - | Ahora podemos ver los pods: | ||
| - | kubectl get pods --all-namespaces | ||
| - | |||
| - | Debug errores: | ||
| - | sudo journalctl -r -u kubelet | ||
| - | |||
| - | Vemos que el pod de dns se queda colgado, hay que configurar la RED | ||
| - | | ||
| - | Plugin RED https:// | ||
| - | kubectl apply -n kube-system -f " | ||
| - | | ||
| - | Ahora miramos que todos los pods están activos | ||
| - | kubectl get pods --all-namespaces | ||
| - | |||
| - | NAMESPACE | ||
| - | kube-system | ||
| - | kube-system | ||
| - | kube-system | ||
| - | kube-system | ||
| - | kube-system | ||
| - | kube-system | ||
| - | kube-system | ||
| - | |||
| - | |||
| - | Vemos que el nodo está funcionando | ||
| - | kubectl get nodes | ||
| - | NAME STATUS | ||
| - | avtp110 | ||
| - | |||
| - | |||
| - | Instalamos dashboard | ||
| - | kubectl create -f https:// | ||
| - | |||
| - | Para mirar el estado: | ||
| - | kubectl describe services kubernetes-dashboard --namespace=kube-system | ||
| - | |||
| - | Arrancamos proxy para poder acceder: | ||
| - | kubectl proxy | ||
| - | Starting to serve on 127.0.0.1: | ||
| - | |||
| - | Ya se puede acceder en http:// | ||
| - | |||
| - | |||
| - | Al desplegar cualquier cosa me da error: | ||
| - | No nodes are available that match all of the following predicates:: | ||
| - | |||
| - | Solución: | ||
| - | kubectl describe node | ||
| - | |||
| - | < | ||
| - | Name: | ||
| - | Role: | ||
| - | Labels: | ||
| - | beta.kubernetes.io/ | ||
| - | kubernetes.io/ | ||
| - | node-role.kubernetes.io/ | ||
| - | Annotations: | ||
| - | volumes.kubernetes.io/ | ||
| - | Taints: | ||
| - | CreationTimestamp: | ||
| - | Phase: | ||
| - | Conditions: | ||
| - | Type Status LastHeartbeatTime LastTransitionTime Reason Message | ||
| - | ---- ------ ----------------- ------------------ ------ ------- | ||
| - | OutOfDisk False Sat, 24 Jun 2017 01:00:18 +0200 Sat, 24 Jun 2017 00:33:04 +0200 KubeletHasSufficientDisk kubelet has sufficient disk space available | ||
| - | MemoryPressure False Sat, 24 Jun 2017 01:00:18 +0200 Sat, 24 Jun 2017 00:33:04 +0200 KubeletHasSufficientMemory kubelet has sufficient memory available | ||
| - | DiskPressure False Sat, 24 Jun 2017 01:00:18 +0200 Sat, 24 Jun 2017 00:33:04 +0200 KubeletHasNoDiskPressure kubelet has no disk pressure | ||
| - | Ready True Sat, 24 Jun 2017 01:00:18 +0200 Sat, 24 Jun 2017 00:34:54 +0200 KubeletReady kubelet is posting ready status | ||
| - | Addresses: | ||
| - | Capacity: | ||
| - | | ||
| - | | ||
| - | | ||
| - | Allocatable: | ||
| - | | ||
| - | | ||
| - | | ||
| - | System Info: | ||
| - | | ||
| - | | ||
| - | Boot ID: | ||
| - | | ||
| - | OS Image: | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | ExternalID: | ||
| - | Non-terminated Pods: (8 in total) | ||
| - | Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits | ||
| - | --------- ---- ------------ ---------- --------------- ------------- | ||
| - | kube-system etcd-avtp110 0 (0%) 0 (0%) 0 (0%) 0 (0%) | ||
| - | kube-system kube-apiserver-avtp110 250m (6%) 0 (0%) 0 (0%) 0 (0%) | ||
| - | kube-system kube-controller-manager-avtp110 200m (5%) 0 (0%) 0 (0%) 0 (0%) | ||
| - | kube-system kube-dns-692378583-f0sk0 260m (6%) 0 (0%) 110Mi (0%) 170Mi (0%) | ||
| - | kube-system kube-proxy-1j5hd 0 (0%) 0 (0%) 0 (0%) 0 (0%) | ||
| - | kube-system kube-scheduler-avtp110 100m (2%) 0 (0%) 0 (0%) 0 (0%) | ||
| - | kube-system kubernetes-dashboard-2039414953-s1k99 0 (0%) 0 (0%) 0 (0%) 0 (0%) | ||
| - | kube-system weave-net-sw6k7 20m (0%) 0 (0%) 0 (0%) 0 (0%) | ||
| - | Allocated resources: | ||
| - | (Total limits may be over 100 percent, i.e., overcommitted.) | ||
| - | CPU Requests CPU Limits Memory Requests Memory Limits | ||
| - | ------------ ---------- --------------- ------------- | ||
| - | 830m (20%) 0 (0%) 110Mi (0%) 170Mi (0%) | ||
| - | Events: | ||
| - | FirstSeen LastSeen Count From SubObjectPath Type Reason Message | ||
| - | --------- -------- ----- ---- ------------- -------- ------ ------- | ||
| - | 27m 27m 1 kubelet, | ||
| - | 27m 27m 1 kubelet, | ||
| - | 27m 27m 28 kubelet, | ||
| - | 27m 27m 28 kubelet, | ||
| - | 27m 27m 28 kubelet, | ||
| - | 27m 27m 1 kube-proxy, | ||
| - | 25m 25m 1 kubelet, | ||
| - | </ | ||
| - | |||
| - | Nos fijamos en la línea: | ||
| - | Taints: node-role.kubernetes.io/ | ||
| - | Lanzamos el comando: | ||
| - | kubectl taint nodes avtp110 node-role.kubernetes.io/ | ||
| - | node " | ||
| - | |||
| - | Para monitorización: | ||
| - | kubectl create -f https:// | ||
| - | |||
| - | ====== Balanceador de carga ====== | ||
| - | La gracia de Kubernetes es que no hay que poner ips, se configura por nombres. | ||
| - | |||
| - | Por ejemplo, deplegamos un apache y lo llamamos httpd. Si levantamos varios pods serán accesibles a sus ips por el puerto 80 | ||
| - | |||
| - | Podemos crear un balanceador con el siguiente fichero apuntado a la aplicación httpd: | ||
| - | < | ||
| - | { | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | }, | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | }], | ||
| - | " | ||
| - | " | ||
| - | }, | ||
| - | " | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | Lo desplegamos en kubernetes: | ||
| - | kubectl create -f balancecador.yaml | ||
| - | Vemos su configuración: | ||
| - | kubectl describe services ejemplo-balanceador | ||
| - | |||
| - | < | ||
| - | Name: | ||
| - | Namespace: | ||
| - | Labels: | ||
| - | Annotations: | ||
| - | Selector: | ||
| - | Type: | ||
| - | IP: | ||
| - | Port: | ||
| - | NodePort: | ||
| - | Endpoints: | ||
| - | Session Affinity: | ||
| - | Events: | ||
| - | </ | ||
| - | |||
| - | Si accedemos a http:// | ||
| - | |||
| - | ====== CLOUD ====== | ||
| - | Sitios para instalar en cloud:\\ | ||
| - | https:// | ||
| - | |||
| - | ====== Seguridad ====== | ||
| - | https:// | ||
| - | |||
| - | ====== Balanceo de un nodo físico ====== | ||
| - | https:// | ||
| - | |||
| - | Si queremos parar un nodo por mantenimiento: | ||
| - | |||
| - | kubectl --server=192.168.2.1: | ||
| - | | ||
| - | node " | ||
| - | error: DaemonSet-managed pods (use --ignore-daemonsets to ignore): kube-proxy-648gj, | ||
| - | Parece que no funciona. Lo lanzamos con el comando: | ||
| - | < | ||
| - | kubectl | ||
| - | node " | ||
| - | WARNING: Ignoring DaemonSet-managed pods: kube-proxy-648gj, | ||
| - | |||
| - | pod " | ||
| - | pod " | ||
| - | pod " | ||
| - | pod " | ||
| - | pod " | ||
| - | pod " | ||
| - | node " | ||
| - | </ | ||
| - | |||
| - | Para volver a dejarlo funcionando: | ||
| - | kubectl | ||
| - | |||
| - | |||
| - | ====== Flecos ====== | ||
| - | |||
| - | **TODO**: revisar si lo que hay aquí anotado se conserva o se suprime | ||
| - | |||
| - | Mesos fleet tutum grafana | ||
| - | |||
| - | Monitorización: | ||
| - | |||
| - | System metrics: Datadog \\ | ||
| - | Container logs: Papertrail | ||
| - | |||
| - | ====== Ejemplo ====== | ||
| - | |||
| - | En este ejemplo: | ||
| - | |||
| - | * Configuramos kubernetes en alta disponibilidad | ||
| - | * Exponemos un servicio a través de un certificado SSL válido | ||
| - | * El pod que recibe la petición muestra la IP pública del cliente | ||
| - | |||
| - | Máquinas: | ||
| - | |||
| - | ^ DNS ^ IP privada ^ IP pública ^ Comentario ^ | ||
| - | | k8s.local | ||
| - | | k8s1.local | 192.168.95.71 | 8.8.8.8 | Edge router. La IP pública es figurada | | ||
| - | | k8s2.local | 192.168.95.71 | - | Primer control plane | | ||
| - | | k8s3.local | 192.168.95.72 | - | Control plane adicional | | ||
| - | | k8s3.local | 192.168.95.73 | - | Control plane adicional | | ||
| - | | k8s4.local | 192.168.95.74 | - | Worker | | ||
| - | | k8s5.local | 192.168.95.75 | - | Worker | | ||
| - | | k8s6.local | 192.168.95.76 | - | Worker | | ||
| - | |||
| - | 1. Crear el cluster | ||
| - | |||
| - | 1.1. [[https:// | ||
| - | |||
| - | 1.2. [[informatica: | ||
| - | |||
| - | 1.3. Crear un [[informatica: | ||
| - | |||
| - | 1.4. [[informatica: | ||
| - | |||
| - | 1.5. [[informatica: | ||
| - | |||
| - | 1.6. [[informatica: | ||
| - | |||
| - | En este momento ya tenemos el cluster de kubernetes montado. | ||
| - | |||
| - | 2. Exponer un servicio con certificado SSL válido y que muestre la IP pública del cliente | ||
| - | |||
| - | 2.1. Instalar [[informatica: | ||
| - | |||
| - | Como dice el paso 8, anotar los puertos HTTP y HTTPS que exponen cada uno de los nodos. | ||
| - | |||
| - | 2.2. Instalar [[informatica: | ||
| - | |||
| - | 2.3. Crear [[informatica: | ||
| - | |||
| - | 2.4. Crear un [[informatica: | ||
| - | |||
| - | 2.5. Exponer el anterior deployment a través de un [[informatica: | ||
| - | |||
| - | 2.6. Crear un [[http:// | ||
| - | |||
| - | En este punto si: | ||
| - | |||
| - | * Se deshabilita momentáneamente proxy protoco (revirtiendo [[informatica: | ||
| - | * Se obtiene el worker donde está corriendo el pod ' | ||
| - | * Se obtiene la IP privada de ese worker | ||
| - | * Se obtiene el puerto en el que escucha el servicio HTTP Nodeport (ver paso 2.1. de estas instrucciones) | ||
| - | * Se le pasa la cabecera " | ||
| - | |||
| - | Se podría llegar al pod. Ejemplo: | ||
| - | |||
| - | < | ||
| - | _HOST=192.168.95.75 | ||
| - | _PORT=32079 | ||
| - | curl -L -s -i -H "Host: example.com" | ||
| - | </ | ||
| - | |||
| - | 3. Configurar edge router | ||
| - | |||
| - | En este ejemplo vamos a instalar dos servidores, que van a compartir una IP flotante para tener redundancia. | ||
| - | |||
| - | 3.1. Seguir [[informatica: | ||
| - | |||
| - | 3.2. Crear un nombre DNS, " | ||
| - | |||
| - | 4. Probar | ||
| - | |||
| - | https:// | ||
| - | |||
| - | Resultado esperado: | ||
| - | |||
| - | * Debería mostrar un certificado SSL válido | ||
| - | * Debería mostrar la IP pública del equipo que realizó la petición | ||
| - | |||
| - | ====== Bash completion ====== | ||
| - | |||
| - | https:// | ||
| - | |||
| - | < | ||
| - | source / | ||
| - | echo ' | ||
| - | </ | ||
| - | |||
| - | < | ||
| - | sudo su | ||
| - | kubectl completion bash >/ | ||
| - | exit | ||
| - | </ | ||
| - | |||
| - | exit | ||
| - | | ||
| - | ====== Desplegar pods en control plane ====== | ||
| - | |||
| - | No es lo recomendable, | ||
| - | |||
| - | Para cada uno de los nodos del cluster, en este caso " | ||
| - | |||
| - | kubectl taint nodes k8s1 node-role.kubernetes.io/ | ||
| - | kubectl taint nodes k8s1 node-role.kubernetes.io/ | ||
informatica/linux/docker/kubernetes.1656064605.txt.gz · Last modified: by javi
