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 17:43] – [Definir tiempo pod salta a otro worker] 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 | ||
- | |||
- | Las IPs púbicas son inventadas | ||
- | |||
- | ^ Stateless ^ Source ^ IP Protocol ^ Source Port Range ^ Destination Port Range ^ Description ^ | ||
- | | No | 0.0.0.0/0 | TCP | All | 31342 | nginx-ingress-controller-https | | ||
- | | No | 0.0.0.0/0 | TCP | All | 32386 | nginx-ingress-controller-http | | ||
- | | No | 0.0.0.0/0 | TCP | All | 443 | listener-https | | ||
- | | No | 0.0.0.0/0 | TCP | All | 80 | listener-http | | ||
- | | No | 1.2.3.5/32 | All | All | All | k8s1 | | ||
- | | No | 1.2.3.6/32 | All | All | All | k8s2 | | ||
- | | No | 1.2.3.7/32 | All | All | All | k8s3 | | ||
- | |||
- | Seguramente se puede restringir una miaja, pero así funciona. | ||
- | |||
- | Como se juega también con los listeners no es tab abierta como parece. Por ejemplo desde la DMZ NO se llega al puerto 31342 (porque no hay listener publicado). | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== 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 | ||
- | #- --enable-admission-plugins=NodeRestriction | ||
- | - --enable-admission-plugins=NodeRestriction, | ||
- | - --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.1656092626.txt.gz · Last modified: 2022/06/24 17:43 by javi