refactor: перемещение плейбуков в playbooks/, ротация сертификатов, сохранение ключей локально
Организация плейбуков: - все .yml плейбуки перенесены из корня в playbooks/ - Makefile и entrypoint.sh обновлены — все пути с playbooks/ префиксом - k8s-user.yml переработан: include_tasks → include_role (корректная работа из подкаталога) Сохранение ключей и kubeconfig локально: - k8s-user.yml: новый play сохраняет k8s SSH ключи в ./keys/ на машине запуска - переменная k8s_local_keys_dir: "./keys" (настраивается в group_vars) - .gitignore: keys/k8s_id_rsa исключён (публичный ключ можно коммитить) - kubeconfig уже сохранялся роль k3s (k3s_kubeconfig_local_path: "./kubeconfig") Автоматическая ротация сертификатов K3S (роль k3s-certs): - K3S выпускает сертификаты на 1 год (hardcoded), таймер обеспечивает их обновление - скрипт k3s-cert-check.sh: проверяет срок через openssl, ротирует при k3s_cert_rotate_before_days - systemd service + timer: запуск по расписанию k3s_cert_check_schedule (по умолчанию monthly) - RandomizedDelaySec: снижает нагрузку при одновременном запуске на нескольких нодах - переменные: k3s_cert_validity_years: 5, k3s_cert_rotate_before_days: 90 - добавлен в site.yml (тег certs) и отдельный плейбук playbooks/k3s-certs.yml - make k3s-certs и команда k3s-certs в entrypoint.sh
This commit is contained in:
99
playbooks/add-node.yml
Normal file
99
playbooks/add-node.yml
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Добавить новую ноду в кластер
|
||||
#
|
||||
# Использование:
|
||||
# make add-node NODE=master04 — новый мастер (etcd участник)
|
||||
# make add-node NODE=worker04 — новый воркер (только agent)
|
||||
#
|
||||
# Перед запуском:
|
||||
# 1. Добавь ноду в inventory/hosts.ini в нужную группу
|
||||
# 2. Убедись что SSH доступ настроен
|
||||
# 3. Запусти make ping NODE=<nodename> для проверки
|
||||
#
|
||||
# Новые мастера: подключаются через VIP (kube-vip должен быть запущен)
|
||||
# Новые воркеры: подключаются через VIP как agents (без etcd)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
# ── Читаем token и факты первого мастера ─────────────────────────────────────
|
||||
- name: Gather cluster info from first master
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [always]
|
||||
tasks:
|
||||
- name: Read node-token from first master
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ k3s_data_dir }}/server/node-token"
|
||||
register: _node_token_raw
|
||||
|
||||
- name: Set shared token fact
|
||||
ansible.builtin.set_fact:
|
||||
k3s_node_token: "{{ _node_token_raw.content | b64decode | trim }}"
|
||||
|
||||
# ── Устанавливаем K3S на новую ноду ──────────────────────────────────────────
|
||||
- name: Add new master node
|
||||
hosts: "{{ node_to_add | default('') }}"
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [k3s]
|
||||
serial: 1
|
||||
|
||||
vars:
|
||||
# Новые мастера используют VIP (kube-vip уже работает)
|
||||
k3s_join_address: "{{ kube_vip_address }}"
|
||||
k3s_fetch_kubeconfig: true
|
||||
|
||||
pre_tasks:
|
||||
- name: Verify node is in k3s_master or k3s_workers group
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- inventory_hostname in groups['k3s_master'] or
|
||||
(groups['k3s_workers'] is defined and inventory_hostname in groups['k3s_workers'])
|
||||
fail_msg: >
|
||||
Нода '{{ inventory_hostname }}' не найдена в группах k3s_master или k3s_workers.
|
||||
Добавь её в inventory/hosts.ini и повтори запуск.
|
||||
|
||||
- name: Check if K3S already installed
|
||||
ansible.builtin.stat:
|
||||
path: /usr/local/bin/k3s
|
||||
register: k3s_installed
|
||||
|
||||
- name: Abort if K3S already running
|
||||
ansible.builtin.assert:
|
||||
that: not k3s_installed.stat.exists
|
||||
fail_msg: >
|
||||
K3S уже установлен на {{ inventory_hostname }}.
|
||||
Используй make upgrade для обновления или make remove-node для удаления.
|
||||
|
||||
roles:
|
||||
- role: k3s
|
||||
|
||||
post_tasks:
|
||||
- name: Verify new node in cluster
|
||||
ansible.builtin.command: >
|
||||
k3s kubectl get node {{ inventory_hostname }} -o wide
|
||||
delegate_to: "{{ groups['k3s_master'][0] }}"
|
||||
become: true
|
||||
register: new_node_status
|
||||
changed_when: false
|
||||
retries: 10
|
||||
delay: 10
|
||||
until: "'Ready' in new_node_status.stdout"
|
||||
|
||||
- name: Show node status
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ new_node_status.stdout_lines }}"
|
||||
|
||||
- name: Install NFS client on new node (if CSI NFS enabled)
|
||||
ansible.builtin.apt:
|
||||
name: nfs-common
|
||||
state: present
|
||||
update_cache: true
|
||||
when: csi_nfs_enabled | default(true) | bool
|
||||
|
||||
- name: Summary
|
||||
ansible.builtin.debug:
|
||||
msg: >
|
||||
Нода {{ inventory_hostname }} успешно добавлена в кластер.
|
||||
Тип: {{ 'master (etcd participant)' if inventory_hostname in groups['k3s_master'] else 'worker (agent)' }}
|
||||
56
playbooks/bootstrap.yml
Normal file
56
playbooks/bootstrap.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Bootstrap — первоначальная настройка нод
|
||||
#
|
||||
# Запускать ОДИН РАЗ перед make install.
|
||||
# Подключается с начальными логином/паролем из vault (host_vars/<node>/vault.yml).
|
||||
# Создаёт пользователя k3s_admin_user, раскладывает SSH ключ.
|
||||
# После этого все playbook работают по ключу без пароля.
|
||||
#
|
||||
# Использование:
|
||||
# make bootstrap
|
||||
# make bootstrap NODE=master01 — только одна нода
|
||||
#
|
||||
# Требования vault (в host_vars/<node>/vault.yml для каждой ноды):
|
||||
# bootstrap_user: ubuntu # начальный пользователь
|
||||
# bootstrap_password: "секрет" # пароль SSH
|
||||
# bootstrap_sudo_password: "секрет" # пароль sudo (часто тот же)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
- name: Bootstrap cluster nodes
|
||||
hosts: "{{ node_to_bootstrap | default('k3s_cluster') }}"
|
||||
gather_facts: false
|
||||
serial: 1
|
||||
|
||||
vars:
|
||||
# Подключаемся с первоначальными credentials из vault каждой ноды
|
||||
ansible_user: "{{ bootstrap_user }}"
|
||||
ansible_password: "{{ bootstrap_password }}"
|
||||
ansible_become_password: "{{ bootstrap_sudo_password | default(bootstrap_password) }}"
|
||||
ansible_ssh_common_args: >-
|
||||
-o StrictHostKeyChecking=no
|
||||
-o UserKnownHostsFile=/dev/null
|
||||
-o PasswordAuthentication=yes
|
||||
-o PubkeyAuthentication=no
|
||||
|
||||
pre_tasks:
|
||||
- name: Validate bootstrap credentials are defined
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- bootstrap_user is defined
|
||||
- bootstrap_user | length > 0
|
||||
- bootstrap_password is defined
|
||||
- bootstrap_password | length > 0
|
||||
fail_msg: >
|
||||
Для {{ inventory_hostname }} не заданы bootstrap credentials.
|
||||
Создай host_vars/{{ inventory_hostname }}/vault.yml с полями:
|
||||
bootstrap_user: ubuntu
|
||||
bootstrap_password: "пароль"
|
||||
Зашифруй файл: ansible-vault encrypt host_vars/{{ inventory_hostname }}/vault.yml
|
||||
|
||||
- name: Test initial SSH connection
|
||||
ansible.builtin.ping:
|
||||
register: ping_result
|
||||
|
||||
roles:
|
||||
- role: bootstrap
|
||||
20
playbooks/etcd-backup.yml
Normal file
20
playbooks/etcd-backup.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Резервное копирование etcd
|
||||
# Запуск: make etcd-backup
|
||||
# make etcd-backup SNAPSHOT=my-backup (своё имя)
|
||||
# make etcd-backup ETCD_COPY=true (скопировать локально)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
- name: Backup etcd snapshot
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [etcd, backup]
|
||||
|
||||
vars:
|
||||
etcd_backup_name: "{{ lookup('env', 'SNAPSHOT') | default('', true) }}"
|
||||
etcd_backup_copy_to_local: "{{ lookup('env', 'ETCD_COPY') | default(false, true) | bool }}"
|
||||
|
||||
tasks:
|
||||
- name: Run etcd backup
|
||||
ansible.builtin.include_tasks: roles/etcd/tasks/backup.yml
|
||||
60
playbooks/etcd-restore.yml
Normal file
60
playbooks/etcd-restore.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Восстановление etcd из снимка
|
||||
# ВНИМАНИЕ: останавливает K3S на ВСЕХ нодах и восстанавливает данные!
|
||||
#
|
||||
# Запуск: make etcd-restore SNAPSHOT=k3s-etcd-20250101T120000.db
|
||||
# make etcd-list-snapshots — посмотреть доступные снимки
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
- name: List available etcd snapshots
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [etcd, list]
|
||||
tasks:
|
||||
- name: List snapshots
|
||||
ansible.builtin.command: k3s etcd-snapshot ls
|
||||
register: snap_list
|
||||
changed_when: false
|
||||
- ansible.builtin.debug:
|
||||
msg: "{{ snap_list.stdout_lines }}"
|
||||
|
||||
- name: Restore etcd snapshot
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [etcd, restore]
|
||||
serial: 1
|
||||
|
||||
vars:
|
||||
etcd_restore_snapshot: "{{ lookup('env', 'SNAPSHOT') }}"
|
||||
etcd_restore_force: "{{ lookup('env', 'FORCE') | default(false, true) | bool }}"
|
||||
|
||||
tasks:
|
||||
- name: Run etcd restore
|
||||
ansible.builtin.include_tasks: roles/etcd/tasks/restore.yml
|
||||
|
||||
- name: Restart k3s on remaining master nodes
|
||||
hosts: k3s_master
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [etcd, restore]
|
||||
tasks:
|
||||
- name: Start k3s (skip first master — already running)
|
||||
ansible.builtin.systemd:
|
||||
name: k3s
|
||||
state: started
|
||||
when: inventory_hostname != groups['k3s_master'][0]
|
||||
failed_when: false
|
||||
|
||||
- name: Restart k3s-agent on worker nodes
|
||||
hosts: k3s_workers
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [etcd, restore]
|
||||
tasks:
|
||||
- name: Start k3s-agent on workers
|
||||
ansible.builtin.systemd:
|
||||
name: k3s-agent
|
||||
state: started
|
||||
failed_when: false
|
||||
13
playbooks/healthcheck.yml
Normal file
13
playbooks/healthcheck.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
# Плейбук диагностики кластера
|
||||
# Запуск: ansible-playbook healthcheck.yml
|
||||
|
||||
- name: K3S Cluster Health Check
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
tasks:
|
||||
- name: Run health checks
|
||||
ansible.builtin.include_role:
|
||||
name: k3s
|
||||
tasks_from: healthcheck
|
||||
22
playbooks/k3s-certs.yml
Normal file
22
playbooks/k3s-certs.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# k3s-certs: установка systemd таймера автоматической ротации сертификатов K3S
|
||||
#
|
||||
# K3S выпускает сертификаты сроком на 1 год. Этот плейбук устанавливает
|
||||
# systemd таймер, который автоматически проверяет и обновляет сертификаты
|
||||
# до их истечения, обеспечивая бесперебойную работу кластера.
|
||||
#
|
||||
# Настройка:
|
||||
# k3s_cert_validity_years: 5 — желаемый срок жизни без вмешательства
|
||||
# k3s_cert_rotate_before_days: 90 — ротация за N дней до истечения
|
||||
# k3s_cert_check_schedule: "monthly" — расписание проверки (systemd OnCalendar)
|
||||
#
|
||||
# Запуск: ansible-playbook playbooks/k3s-certs.yml --ask-vault-pass
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
- name: Setup K3S certificate auto-rotation
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
roles:
|
||||
- role: k3s-certs
|
||||
119
playbooks/k8s-user.yml
Normal file
119
playbooks/k8s-user.yml
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# k8s-user: создание сервисного пользователя k8s на всех серверах
|
||||
#
|
||||
# Последовательность:
|
||||
# 1. Создать пользователя k8s + sudo на всех нодах кластера
|
||||
# 2. Сгенерировать RSA 4096 ключевую пару на первом мастере (один раз)
|
||||
# 3. Сохранить ключи локально в ./keys/
|
||||
# 4. Разложить ключи на все ноды кластера (SSH в любую сторону)
|
||||
# 5. Обновить /etc/hosts на нодах кластера
|
||||
# 6. То же самое для lab_hosts (через пароль из vault)
|
||||
#
|
||||
# Запуск: ansible-playbook playbooks/k8s-user.yml --ask-vault-pass
|
||||
# Только кластер: ansible-playbook playbooks/k8s-user.yml --limit k3s_cluster
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
# ── 1. Создать пользователя k8s на всех нодах кластера ───────────────────────
|
||||
- name: Create k8s service user on cluster nodes
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
roles:
|
||||
- role: k8s-user
|
||||
|
||||
# ── 2. Сгенерировать ключевую пару на первом мастере ─────────────────────────
|
||||
- name: Generate k8s SSH key pair (first master only)
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Generate RSA key pair and store facts
|
||||
ansible.builtin.include_role:
|
||||
name: k8s-user
|
||||
tasks_from: generate_keys.yml
|
||||
|
||||
# ── 3. Сохранить ключи локально в ./keys/ ────────────────────────────────────
|
||||
- name: Save k8s SSH keys to local machine
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Create local keys directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ k8s_local_keys_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Save private key locally
|
||||
ansible.builtin.copy:
|
||||
content: "{{ k8s_ssh_private_key }}"
|
||||
dest: "{{ k8s_local_keys_dir }}/k8s_id_rsa"
|
||||
mode: '0600'
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Save public key locally
|
||||
ansible.builtin.copy:
|
||||
content: "{{ k8s_ssh_public_key }}\n"
|
||||
dest: "{{ k8s_local_keys_dir }}/k8s_id_rsa.pub"
|
||||
mode: '0644'
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Show where keys were saved
|
||||
ansible.builtin.debug:
|
||||
msg: "SSH keys saved to {{ k8s_local_keys_dir }}"
|
||||
|
||||
# ── 4. Разложить ключи на все ноды кластера ──────────────────────────────────
|
||||
- name: Distribute k8s SSH keys to all cluster nodes
|
||||
hosts: k3s_cluster
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Deploy keys to node
|
||||
ansible.builtin.include_role:
|
||||
name: k8s-user
|
||||
tasks_from: distribute_keys.yml
|
||||
|
||||
# ── 5. Обновить /etc/hosts на нодах кластера ─────────────────────────────────
|
||||
- name: Update /etc/hosts on cluster nodes
|
||||
hosts: k3s_cluster
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Update hosts file
|
||||
ansible.builtin.include_role:
|
||||
name: k8s-user
|
||||
tasks_from: update_hosts.yml
|
||||
|
||||
# ── 6. Bootstrap lab_hosts: создать пользователя, разложить ключи, обновить hosts
|
||||
# Подключение через логин/пароль из host_vars/<host>/vault.yml
|
||||
- name: Setup k8s user on lab hosts
|
||||
hosts: lab_hosts
|
||||
gather_facts: true
|
||||
become: true
|
||||
vars:
|
||||
ansible_user: "{{ bootstrap_user }}"
|
||||
ansible_password: "{{ bootstrap_password }}"
|
||||
ansible_become_password: "{{ bootstrap_sudo_password | default(bootstrap_password) }}"
|
||||
ansible_ssh_common_args: >-
|
||||
-o StrictHostKeyChecking=no
|
||||
-o PasswordAuthentication=yes
|
||||
-o PubkeyAuthentication=no
|
||||
tasks:
|
||||
- name: Create k8s user on lab host
|
||||
ansible.builtin.include_role:
|
||||
name: k8s-user
|
||||
tasks_from: create_user.yml
|
||||
|
||||
- name: Distribute k8s SSH keys to lab host
|
||||
ansible.builtin.include_role:
|
||||
name: k8s-user
|
||||
tasks_from: distribute_keys.yml
|
||||
|
||||
- name: Update /etc/hosts on lab host
|
||||
ansible.builtin.include_role:
|
||||
name: k8s-user
|
||||
tasks_from: update_hosts.yml
|
||||
15
playbooks/mdadm.yml
Normal file
15
playbooks/mdadm.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# mdadm: обнаружение RAID массива и монтирование в /storage
|
||||
#
|
||||
# Запуск: ansible-playbook mdadm.yml --ask-vault-pass
|
||||
# Только одна нода: ansible-playbook mdadm.yml --limit master01
|
||||
# Отключить: задай mdadm_enabled: false в host_vars или group_vars
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
- name: Configure mdadm RAID and mount /storage
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
roles:
|
||||
- role: mdadm
|
||||
125
playbooks/remove-node.yml
Normal file
125
playbooks/remove-node.yml
Normal file
@@ -0,0 +1,125 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Безопасное удаление ноды из кластера
|
||||
#
|
||||
# Использование:
|
||||
# make remove-node NODE=worker04
|
||||
# make remove-node NODE=master04 (ВНИМАНИЕ: теряется один etcd участник)
|
||||
#
|
||||
# Порядок:
|
||||
# 1. Cordon — запрещает планирование новых подов
|
||||
# 2. Drain — вытесняет все поды на другие ноды
|
||||
# 3. Delete — удаляет ноду из k8s API
|
||||
# 4. Uninstall — удаляет k3s с ноды
|
||||
#
|
||||
# После удаления мастера рекомендуется добавить новый: make add-node NODE=...
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
- name: Validate and prepare
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [always]
|
||||
tasks:
|
||||
- name: Validate NODE is specified
|
||||
ansible.builtin.assert:
|
||||
that: node_to_remove is defined and node_to_remove | length > 0
|
||||
fail_msg: "Укажи ноду: make remove-node NODE=<nodename>"
|
||||
|
||||
- name: Prevent removing the only/first master
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- node_to_remove != groups['k3s_master'][0]
|
||||
fail_msg: >
|
||||
Нельзя удалить первый мастер ({{ groups['k3s_master'][0] }}) —
|
||||
он является точкой инициализации кластера.
|
||||
Перенести роль первого мастера: поменяй порядок нод в inventory и выполни restore.
|
||||
|
||||
- name: Warn if removing etcd member
|
||||
ansible.builtin.debug:
|
||||
msg: >
|
||||
ВНИМАНИЕ: {{ node_to_remove }} является мастером (etcd участником).
|
||||
После удаления в кластере останется {{ groups['k3s_master'] | length - 1 }} мастер(а).
|
||||
Кворум: {{ (groups['k3s_master'] | length - 1) > (groups['k3s_master'] | length - 1) // 2 }}
|
||||
when: node_to_remove in groups['k3s_master']
|
||||
|
||||
- name: Check node exists in cluster
|
||||
ansible.builtin.command: k3s kubectl get node {{ node_to_remove }}
|
||||
register: node_exists
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Cordon node
|
||||
ansible.builtin.command: k3s kubectl cordon {{ node_to_remove }}
|
||||
changed_when: true
|
||||
when: node_exists.rc == 0
|
||||
|
||||
- name: Drain node (evict pods)
|
||||
ansible.builtin.command: >
|
||||
k3s kubectl drain {{ node_to_remove }}
|
||||
--ignore-daemonsets
|
||||
--delete-emptydir-data
|
||||
--timeout=180s
|
||||
--force
|
||||
changed_when: true
|
||||
when: node_exists.rc == 0
|
||||
register: drain_result
|
||||
failed_when: drain_result.rc != 0 and 'not found' not in drain_result.stderr
|
||||
|
||||
- name: Delete node from Kubernetes
|
||||
ansible.builtin.command: k3s kubectl delete node {{ node_to_remove }}
|
||||
changed_when: true
|
||||
when: node_exists.rc == 0
|
||||
|
||||
- name: Uninstall K3S from removed node
|
||||
hosts: "{{ node_to_remove | default('') }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [k3s]
|
||||
tasks:
|
||||
- name: Run K3S server uninstall script
|
||||
ansible.builtin.command: /usr/local/bin/k3s-uninstall.sh
|
||||
failed_when: false
|
||||
changed_when: true
|
||||
when: node_to_remove in groups['k3s_master']
|
||||
|
||||
- name: Run K3S agent uninstall script
|
||||
ansible.builtin.command: /usr/local/bin/k3s-agent-uninstall.sh
|
||||
failed_when: false
|
||||
changed_when: true
|
||||
when:
|
||||
- groups['k3s_workers'] is defined
|
||||
- node_to_remove in groups['k3s_workers']
|
||||
|
||||
- name: Clean up k3s data directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- "{{ k3s_config_dir }}"
|
||||
- "{{ k3s_data_dir }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Post-removal verification
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [verify]
|
||||
tasks:
|
||||
- name: Show remaining nodes
|
||||
ansible.builtin.command: k3s kubectl get nodes -o wide
|
||||
register: remaining_nodes
|
||||
changed_when: false
|
||||
|
||||
- name: Display cluster nodes
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ remaining_nodes.stdout_lines }}"
|
||||
|
||||
- name: Summary
|
||||
ansible.builtin.debug:
|
||||
msg: >
|
||||
Нода {{ node_to_remove }} успешно удалена из кластера.
|
||||
Удали её из inventory/hosts.ini.
|
||||
{% if node_to_remove in groups['k3s_master'] %}
|
||||
Рекомендуется добавить новую мастер-ноду: make add-node NODE=<новая-нода>
|
||||
{% endif %}
|
||||
147
playbooks/site.yml
Normal file
147
playbooks/site.yml
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# K3S Full Stack Playbook
|
||||
# Порядок установки:
|
||||
# 1. K3S cluster (master → workers)
|
||||
# 2. kube-vip (VIP для control plane + LoadBalancer)
|
||||
# 3. NFS Server (на master или отдельном хосте)
|
||||
# 4. CSI NFS Driver (StorageClass для PVC)
|
||||
# 5. ingress-nginx (Ingress controller через Helm)
|
||||
#
|
||||
# Запуск: ansible-playbook playbooks/site.yml --ask-vault-pass
|
||||
# Только отдельный компонент: ansible-playbook playbooks/site.yml --tags kube_vip
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
# ── 1. K3S Cluster ────────────────────────────────────────────────────────────
|
||||
# serial: 1 — master01 запускается первым (cluster-init), остальные присоединяются
|
||||
- name: Install K3S cluster (HA embedded etcd)
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
serial: 1
|
||||
tags: [k3s]
|
||||
roles:
|
||||
- role: k3s
|
||||
|
||||
# ── 2. CNI (calico/cilium; при flannel — пропускается) ───────────────────────
|
||||
- name: Deploy CNI plugin
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [cni]
|
||||
roles:
|
||||
- role: cni
|
||||
|
||||
# ── 3. kube-vip ───────────────────────────────────────────────────────────────
|
||||
- name: Deploy kube-vip (VIP + LoadBalancer)
|
||||
hosts: k3s_master
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [kube_vip]
|
||||
roles:
|
||||
- role: kube-vip
|
||||
|
||||
# ── 4. NFS Server ─────────────────────────────────────────────────────────────
|
||||
- name: Configure NFS server
|
||||
hosts: nfs_server
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [nfs, nfs_server]
|
||||
roles:
|
||||
- role: nfs-server
|
||||
|
||||
# ── 5. NFS client on all K3S nodes + CSI Driver ───────────────────────────────
|
||||
- name: Deploy CSI NFS Driver
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [nfs, csi_nfs]
|
||||
roles:
|
||||
- role: csi-nfs
|
||||
|
||||
# ── 6. ingress-nginx ──────────────────────────────────────────────────────────
|
||||
- name: Deploy ingress-nginx
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [ingress, ingress_nginx]
|
||||
roles:
|
||||
- role: ingress-nginx
|
||||
|
||||
# ── 7. cert-manager (опционально: cert_manager_enabled: true) ────────────────
|
||||
- name: Deploy cert-manager
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [cert_manager, certmanager]
|
||||
roles:
|
||||
- role: cert-manager
|
||||
|
||||
# ── 8. Istio (опционально: istio_enabled: true) ───────────────────────────────
|
||||
- name: Deploy Istio service mesh
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [istio]
|
||||
roles:
|
||||
- role: istio
|
||||
|
||||
# ── 9. kube-prometheus-stack (опционально: prometheus_stack_enabled: true) ─────
|
||||
- name: Deploy kube-prometheus-stack
|
||||
hosts: "{{ groups['k3s_master'][0] }}"
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [monitoring, prometheus]
|
||||
roles:
|
||||
- role: prometheus-stack
|
||||
|
||||
# ── Verify full stack ─────────────────────────────────────────────────────────
|
||||
- name: Verify full stack
|
||||
hosts: k3s_master
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [verify]
|
||||
tasks:
|
||||
- name: Nodes
|
||||
ansible.builtin.command: k3s kubectl get nodes -o wide
|
||||
register: nodes
|
||||
changed_when: false
|
||||
- ansible.builtin.debug:
|
||||
msg: "{{ nodes.stdout_lines }}"
|
||||
|
||||
- name: All pods
|
||||
ansible.builtin.command: k3s kubectl get pods -A
|
||||
register: pods
|
||||
changed_when: false
|
||||
- ansible.builtin.debug:
|
||||
msg: "{{ pods.stdout_lines }}"
|
||||
|
||||
- name: Services with External IPs
|
||||
ansible.builtin.command: k3s kubectl get svc -A
|
||||
register: svcs
|
||||
changed_when: false
|
||||
- ansible.builtin.debug:
|
||||
msg: "{{ svcs.stdout_lines }}"
|
||||
|
||||
- name: StorageClasses
|
||||
ansible.builtin.command: k3s kubectl get storageclass
|
||||
register: sc
|
||||
changed_when: false
|
||||
- ansible.builtin.debug:
|
||||
msg: "{{ sc.stdout_lines }}"
|
||||
|
||||
- name: IngressClasses
|
||||
ansible.builtin.command: k3s kubectl get ingressclass
|
||||
register: ic
|
||||
changed_when: false
|
||||
- ansible.builtin.debug:
|
||||
msg: "{{ ic.stdout_lines }}"
|
||||
|
||||
# ── Certificate Auto-Rotation (systemd timer) ─────────────────────────────────
|
||||
- name: Setup K3S certificate auto-rotation
|
||||
hosts: k3s_cluster
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [certs, k3s_certs]
|
||||
roles:
|
||||
- role: k3s-certs
|
||||
101
playbooks/uninstall.yml
Normal file
101
playbooks/uninstall.yml
Normal file
@@ -0,0 +1,101 @@
|
||||
---
|
||||
# Полное удаление всего стека
|
||||
# Порядок: обратный установке
|
||||
# Запуск: ansible-playbook uninstall.yml
|
||||
|
||||
- name: Confirm uninstall
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Ask for confirmation
|
||||
ansible.builtin.pause:
|
||||
prompt: |
|
||||
⚠️ ВНИМАНИЕ! Будут удалены: ingress-nginx, CSI NFS, kube-vip, K3S и ВСЕ данные.
|
||||
Введите 'yes' для подтверждения
|
||||
register: confirm
|
||||
when: confirm_uninstall is not defined
|
||||
|
||||
- name: Abort if not confirmed
|
||||
ansible.builtin.fail:
|
||||
msg: "Отменено."
|
||||
when:
|
||||
- confirm_uninstall is not defined
|
||||
- confirm.user_input != 'yes'
|
||||
|
||||
- name: Remove ingress-nginx
|
||||
hosts: k3s_master
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [ingress_nginx]
|
||||
tasks:
|
||||
- name: Uninstall ingress-nginx Helm release
|
||||
ansible.builtin.command: >
|
||||
helm uninstall ingress-nginx -n ingress-nginx
|
||||
failed_when: false
|
||||
changed_when: true
|
||||
environment:
|
||||
KUBECONFIG: "{{ k3s_kubeconfig_path }}"
|
||||
|
||||
- name: Delete ingress-nginx namespace
|
||||
ansible.builtin.command: k3s kubectl delete namespace ingress-nginx --ignore-not-found
|
||||
changed_when: true
|
||||
|
||||
- name: Remove CSI NFS Driver
|
||||
hosts: k3s_master
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [csi_nfs]
|
||||
tasks:
|
||||
- name: Uninstall CSI NFS Helm release
|
||||
ansible.builtin.command: >
|
||||
helm uninstall csi-driver-nfs -n kube-system
|
||||
failed_when: false
|
||||
changed_when: true
|
||||
environment:
|
||||
KUBECONFIG: "{{ k3s_kubeconfig_path }}"
|
||||
|
||||
- name: Delete NFS StorageClass
|
||||
ansible.builtin.command: >
|
||||
k3s kubectl delete storageclass nfs-client --ignore-not-found
|
||||
changed_when: true
|
||||
|
||||
- name: Remove kube-vip
|
||||
hosts: k3s_master
|
||||
gather_facts: false
|
||||
become: true
|
||||
tags: [kube_vip]
|
||||
tasks:
|
||||
- name: Remove kube-vip manifests
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- "{{ k3s_data_dir }}/server/manifests/kube-vip.yaml"
|
||||
- "{{ k3s_data_dir }}/server/manifests/kube-vip-rbac.yaml"
|
||||
|
||||
- name: Uninstall K3S workers
|
||||
hosts: k3s_workers
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [k3s]
|
||||
tasks:
|
||||
- ansible.builtin.include_role:
|
||||
name: k3s
|
||||
tasks_from: uninstall
|
||||
|
||||
- name: Uninstall K3S master
|
||||
hosts: k3s_master
|
||||
gather_facts: true
|
||||
become: true
|
||||
tags: [k3s]
|
||||
tasks:
|
||||
- ansible.builtin.include_role:
|
||||
name: k3s
|
||||
tasks_from: uninstall
|
||||
|
||||
- name: Done
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- ansible.builtin.debug:
|
||||
msg: "✓ Весь стек удалён."
|
||||
40
playbooks/upgrade.yml
Normal file
40
playbooks/upgrade.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
# Плейбук обновления K3S
|
||||
# Workers обновляются по одному (serial: 1) чтобы не потерять кворум
|
||||
#
|
||||
# Запуск: ansible-playbook upgrade.yml -e k3s_version=v1.30.0+k3s1
|
||||
|
||||
- name: Upgrade K3S master
|
||||
hosts: k3s_master
|
||||
gather_facts: true
|
||||
become: true
|
||||
tasks:
|
||||
- name: Upgrade K3S server
|
||||
ansible.builtin.include_role:
|
||||
name: k3s
|
||||
tasks_from: upgrade
|
||||
|
||||
- name: Upgrade K3S workers (one by one)
|
||||
hosts: k3s_workers
|
||||
gather_facts: true
|
||||
become: true
|
||||
serial: 1 # ← обновляем по одной ноде за раз
|
||||
tasks:
|
||||
- name: Upgrade K3S agent
|
||||
ansible.builtin.include_role:
|
||||
name: k3s
|
||||
tasks_from: upgrade
|
||||
|
||||
- name: Verify cluster after upgrade
|
||||
hosts: k3s_master
|
||||
gather_facts: false
|
||||
become: true
|
||||
tasks:
|
||||
- name: Final node status
|
||||
ansible.builtin.command: k3s kubectl get nodes -o wide
|
||||
register: final_status
|
||||
changed_when: false
|
||||
|
||||
- name: Show final cluster state
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ final_status.stdout_lines }}"
|
||||
Reference in New Issue
Block a user