reiniciar_nodo.yml
# Reinicia un nodo sin cortar servicio: lo saca del clúster (drain), lo reinicia,
# espera a que vuelva Ready y lo devuelve (uncordon). Si algo falla, lo devuelve
# igualmente y para todo el playbook.
- name: El master-1 no se reinicia solo
ansible.builtin.debug:
msg: "⚠ {{ inventory_hostname }} pide reinicio, pero desde aquí corre el portal: reinícialo a mano cuando te venga bien."
when: controlador | default(false)
- name: Reiniciar {{ inventory_hostname }}
when: not (controlador | default(false))
block:
# Un master que vuelve con la red inestable puede hacer saltar la VIP (keepalived)
# o dejar etcd sin quórum. Es la comprobación de docs/operacion.md, con TCP en vez
# de ping porque el contenedor no tiene capacidades (NET_RAW).
- name: Red estable hasta el master (30 conexiones a la API, ninguna puede fallar)
ansible.builtin.command:
argv:
- python3
- -c
- |
import socket, sys, time
fallos = 0
for _ in range(30):
try:
socket.create_connection((sys.argv[1], 6443), timeout=2).close()
except OSError:
fallos += 1
time.sleep(0.5)
print(f"{fallos} de 30 conexiones fallidas")
sys.exit(1 if fallos else 0)
- "{{ ansible_host }}"
changed_when: false
delegate_to: localhost
when: inventory_hostname in groups['masters']
- name: Volúmenes local-path de este nodo (sus servicios se paran hasta que vuelva)
ansible.builtin.shell: |
set -o pipefail
kubectl --kubeconfig {{ kubeconfig }} get pv -o json | python3 -c '
import json, sys
for v in json.load(sys.stdin)["items"]:
s = v["spec"]
if (s.get("storageClassName") != "local-path" or not s.get("claimRef")
or v["status"].get("phase") != "Bound"): # los Released ya no dan servicio
continue
terms = s.get("nodeAffinity", {}).get("required", {}).get("nodeSelectorTerms", [])
nodos = [x for t in terms for e in t.get("matchExpressions", []) for x in e.get("values", [])]
if sys.argv[1] in nodos:
print(s["claimRef"]["namespace"] + "/" + s["claimRef"]["name"])
' {{ inventory_hostname | quote }}
args:
executable: /bin/bash
register: local_path
changed_when: false
delegate_to: localhost
- name: Aviso de corte
ansible.builtin.debug:
msg: "⚠ Sin servicio hasta que {{ inventory_hostname }} vuelva: {{ local_path.stdout_lines | join(', ') }}"
when: local_path.stdout_lines | length > 0
- name: Sacar el nodo del clúster (drain)
ansible.builtin.command: >-
kubectl --kubeconfig {{ kubeconfig }} drain {{ inventory_hostname }}
--ignore-daemonsets --delete-emptydir-data --timeout=10m
delegate_to: localhost
changed_when: true
- name: Reiniciar
ansible.builtin.command: sudo -n /usr/local/sbin/nodo-mantenimiento reiniciar
changed_when: true
- name: Esperar a que se apague
ansible.builtin.pause:
seconds: 40
- name: Esperar a que vuelva por SSH
ansible.builtin.wait_for_connection:
timeout: 900
sleep: 10
- name: Esperar a que el nodo esté Ready
ansible.builtin.command: >-
kubectl --kubeconfig {{ kubeconfig }} wait --for=condition=Ready
node/{{ inventory_hostname }} --timeout=10m
delegate_to: localhost
changed_when: false
always:
- name: Devolver el nodo al clúster (uncordon)
ansible.builtin.command: kubectl --kubeconfig {{ kubeconfig }} uncordon {{ inventory_hostname }}
delegate_to: localhost
changed_when: true