## Аддоны (group_vars/all/addons.yml)
- Создан group_vars/all/addons.yml — единое место для включения/отключения
аддонов (addon_ingress_nginx: true/false и т.д.) и их основных настроек
- Из group_vars/all/main.yml убраны все секции аддонов (NFS, CSI, ingress,
cert-manager, etcd backup, Istio, Prometheus) — остался только core кластер
- Создан playbooks/addons.yml — комбинированный плейбук с 10 плеями,
каждый с `when: addon_X | default(false) | bool`; запускает только включённые
- make install-full: core (site.yml) + аддоны по addons.yml
- make install-addons: только аддоны без переустановки core
- Убраны все *_enabled флаги из аддонов (cert_manager_enabled, istio_enabled,
prometheus_stack_enabled и др.) — аддон ставится явным вызовом
- kube-vip: убран skip guard и kube_vip_enabled флаг (core, всегда ставится)
- TLS defaults в argocd/longhorn/kubernetes-dashboard: убрана зависимость
от cert_manager_enabled, теперь просто false (задаётся явно)
- Kiali: убрана зависимость от prometheus_stack_enabled, добавлены переменные
kiali_prometheus_enabled/url и kiali_grafana_enabled/url
## Внешний etcd кластер
- Новая переменная k3s_etcd_type: embedded|external в main.yml
- inventory/hosts.ini: добавлена группа [etcd_nodes] — любые серверы,
не обязательно мастера
- roles/etcd/: полная роль для установки внешнего etcd кластера:
- install.yml — скачивает бинарник, создаёт пользователя и директории
- pki.yml — генерирует CA + server/peer/client сертификаты через openssl
на Ansible-контроллере; раскладывает на etcd ноды и k3s мастера
- service.yml — разворачивает etcd.env и systemd сервис, проверяет здоровье
- etcd.env.j2 и etcd.service.j2 — шаблоны конфигурации
- etcd_pki_local_dir: persistent путь (<project>/etcd-pki/) вместо /tmp,
etcd-pki/ добавлен в .gitignore
- roles/k3s/templates/k3s-server-config.yaml.j2: при external режиме
подставляет datastore-endpoint со всеми etcd нодами + пути к клиентским
сертификатам; при embedded — прежняя логика cluster-init
- playbooks/site.yml: условный плей для etcd перед k3s (тег etcd)
- make install-etcd: отдельная команда для развёртывания etcd кластера
## Управление etcd нодами
- playbooks/add-etcd-node.yml: добавить ноду в работающий etcd кластер
(PKI генерация → install → etcdctl member add → start с state=existing → verify)
- playbooks/remove-etcd-node.yml: безопасно удалить ноду из etcd кластера
(проверка кворума → member remove → stop → clean up PKI)
- playbooks/add-node.yml: при k3s_etcd_type=external и наличии ноды в
[etcd_nodes] автоматически добавляет её в etcd кластер после k3s
- playbooks/remove-node.yml: при k3s_etcd_type=external сначала удаляет
ноду из etcd (member remove + stop), затем из k3s
- make add-etcd-node NODE=etcd04 / make remove-etcd-node NODE=etcd04
- Команды add-etcd-node / remove-etcd-node в docker/entrypoint.sh
215 lines
9.5 KiB
YAML
215 lines
9.5 KiB
YAML
---
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# Добавить ноду в внешний etcd кластер
|
||
#
|
||
# Использование:
|
||
# make add-etcd-node NODE=etcd04 — добавить ноду etcd04
|
||
# make add-etcd-node NODE=master04 — добавить мастер-ноду как etcd-участника
|
||
#
|
||
# Перед запуском:
|
||
# 1. Добавь ноду в [etcd_nodes] в inventory/hosts.ini
|
||
# 2. Убедись что etcd PKI существует (etcd-pki/ca.key, etcd-pki/ca.crt)
|
||
# 3. k3s_etcd_type: external в group_vars/all/main.yml
|
||
#
|
||
# PKI:
|
||
# Серверные/peer сертификаты для новой ноды генерируются на Ansible-контроллере
|
||
# и подписываются существующим CA из etcd-pki/. CA ключ должен быть доступен.
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
|
||
# ── Валидация ─────────────────────────────────────────────────────────────────
|
||
- name: Validate prerequisites
|
||
hosts: localhost
|
||
gather_facts: false
|
||
become: false
|
||
tags: [always]
|
||
tasks:
|
||
- name: Check node_to_add is specified
|
||
ansible.builtin.assert:
|
||
that: node_to_add is defined and node_to_add | length > 0
|
||
fail_msg: "Укажи ноду: make add-etcd-node NODE=<nodename>"
|
||
|
||
- name: Check node is in etcd_nodes group
|
||
ansible.builtin.assert:
|
||
that: node_to_add in groups['etcd_nodes']
|
||
fail_msg: >
|
||
Нода '{{ node_to_add }}' не найдена в группе [etcd_nodes].
|
||
Добавь её в inventory/hosts.ini и повтори запуск.
|
||
|
||
- name: Check etcd PKI CA exists
|
||
ansible.builtin.stat:
|
||
path: "{{ etcd_pki_local_dir }}/ca.key"
|
||
register: _ca_key_stat
|
||
|
||
- name: Fail if CA key missing
|
||
ansible.builtin.assert:
|
||
that: _ca_key_stat.stat.exists
|
||
fail_msg: >
|
||
CA ключ не найден: {{ etcd_pki_local_dir }}/ca.key
|
||
Запусти первоначальную установку etcd: make install-etcd
|
||
|
||
- name: Check node is not already in cluster
|
||
ansible.builtin.shell: |
|
||
EXISTING_NODES=$(ls "{{ etcd_pki_local_dir }}"/server-*.crt 2>/dev/null \
|
||
| xargs -I{} basename {} .crt \
|
||
| sed 's/server-//')
|
||
echo "${EXISTING_NODES}" | grep -qx "{{ node_to_add }}" && echo "exists" || echo "new"
|
||
register: _node_cert_check
|
||
changed_when: false
|
||
|
||
- name: Warn if certs already exist (will be regenerated)
|
||
ansible.builtin.debug:
|
||
msg: >
|
||
Сертификаты для ноды {{ node_to_add }} уже существуют в PKI.
|
||
Они будут пересозданы.
|
||
when: _node_cert_check.stdout == "exists"
|
||
|
||
# ── Генерируем сертификаты для новой ноды ────────────────────────────────────
|
||
- name: Generate PKI certificates for new etcd node
|
||
hosts: localhost
|
||
gather_facts: false
|
||
become: false
|
||
tags: [pki]
|
||
vars:
|
||
_new_node_ip: "{{ hostvars[node_to_add]['ansible_host'] }}"
|
||
tasks:
|
||
- name: Generate server/peer certs for new node
|
||
ansible.builtin.shell: |
|
||
set -e
|
||
NODE="{{ node_to_add }}"
|
||
NODE_IP="{{ _new_node_ip }}"
|
||
PKI="{{ etcd_pki_local_dir }}"
|
||
SAN="subjectAltName=IP:${NODE_IP},IP:127.0.0.1,DNS:${NODE},DNS:localhost"
|
||
|
||
# Принудительно пересоздаём (нода могла быть заменена с тем же именем)
|
||
rm -f "${PKI}/server-${NODE}."{crt,key,csr} "${PKI}/peer-${NODE}."{crt,key,csr}
|
||
|
||
openssl genrsa -out "${PKI}/server-${NODE}.key" 2048
|
||
openssl req -new -key "${PKI}/server-${NODE}.key" -out "${PKI}/server-${NODE}.csr" \
|
||
-subj "/CN=${NODE}/O=etcd"
|
||
openssl x509 -req -days 3650 \
|
||
-in "${PKI}/server-${NODE}.csr" -CA "${PKI}/ca.crt" -CAkey "${PKI}/ca.key" \
|
||
-CAcreateserial -out "${PKI}/server-${NODE}.crt" \
|
||
-extfile <(printf "${SAN}")
|
||
|
||
openssl genrsa -out "${PKI}/peer-${NODE}.key" 2048
|
||
openssl req -new -key "${PKI}/peer-${NODE}.key" -out "${PKI}/peer-${NODE}.csr" \
|
||
-subj "/CN=${NODE}/O=etcd-peer"
|
||
openssl x509 -req -days 3650 \
|
||
-in "${PKI}/peer-${NODE}.csr" -CA "${PKI}/ca.crt" -CAkey "${PKI}/ca.key" \
|
||
-CAcreateserial -out "${PKI}/peer-${NODE}.crt" \
|
||
-extfile <(printf "${SAN}")
|
||
args:
|
||
executable: /bin/bash
|
||
changed_when: true
|
||
|
||
# ── Устанавливаем etcd на новую ноду ─────────────────────────────────────────
|
||
- name: Install etcd binary on new node
|
||
hosts: "{{ node_to_add }}"
|
||
gather_facts: true
|
||
become: true
|
||
tags: [install]
|
||
tasks:
|
||
- name: Install etcd binary
|
||
ansible.builtin.include_role:
|
||
name: etcd
|
||
tasks_from: install
|
||
|
||
- name: Copy CA cert
|
||
ansible.builtin.copy:
|
||
src: "{{ etcd_pki_local_dir }}/ca.crt"
|
||
dest: "{{ etcd_pki_dir }}/ca.crt"
|
||
owner: etcd
|
||
group: etcd
|
||
mode: '0644'
|
||
|
||
- name: Copy server/peer certs for new node
|
||
ansible.builtin.copy:
|
||
src: "{{ etcd_pki_local_dir }}/{{ item.src }}"
|
||
dest: "{{ etcd_pki_dir }}/{{ item.dest }}"
|
||
owner: etcd
|
||
group: etcd
|
||
mode: "{{ item.mode }}"
|
||
loop:
|
||
- { src: "server-{{ inventory_hostname }}.crt", dest: "server.crt", mode: "0644" }
|
||
- { src: "server-{{ inventory_hostname }}.key", dest: "server.key", mode: "0600" }
|
||
- { src: "peer-{{ inventory_hostname }}.crt", dest: "peer.crt", mode: "0644" }
|
||
- { src: "peer-{{ inventory_hostname }}.key", dest: "peer.key", mode: "0600" }
|
||
|
||
# ── Регистрируем новый member в кластере ─────────────────────────────────────
|
||
- name: Register new etcd member
|
||
hosts: "{{ (groups['etcd_nodes'] | reject('equalto', node_to_add) | list)[0] }}"
|
||
gather_facts: false
|
||
become: true
|
||
tags: [register]
|
||
vars:
|
||
_new_node_ip: "{{ hostvars[node_to_add]['ansible_host'] }}"
|
||
tasks:
|
||
- name: Add new member via etcdctl
|
||
ansible.builtin.shell: |
|
||
ETCDCTL_API=3 etcdctl \
|
||
--endpoints="https://{{ ansible_host }}:{{ etcd_client_port }}" \
|
||
--cacert="{{ etcd_pki_dir }}/ca.crt" \
|
||
--cert="{{ etcd_pki_dir }}/server.crt" \
|
||
--key="{{ etcd_pki_dir }}/server.key" \
|
||
member add "{{ node_to_add }}" \
|
||
--peer-urls="https://{{ _new_node_ip }}:{{ etcd_peer_port }}"
|
||
register: _member_add
|
||
changed_when: true
|
||
|
||
- name: Show member add output
|
||
ansible.builtin.debug:
|
||
msg: "{{ _member_add.stdout_lines }}"
|
||
|
||
# ── Запускаем etcd на новой ноде ─────────────────────────────────────────────
|
||
- name: Start etcd on new node
|
||
hosts: "{{ node_to_add }}"
|
||
gather_facts: true
|
||
become: true
|
||
tags: [start]
|
||
vars:
|
||
# Для новой ноды которая присоединяется к существующему кластеру
|
||
etcd_initial_cluster_state: "existing"
|
||
tasks:
|
||
- name: Build initial cluster members string
|
||
ansible.builtin.set_fact:
|
||
etcd_initial_cluster_members: >-
|
||
{%- set members = [] -%}
|
||
{%- for h in groups['etcd_nodes'] -%}
|
||
{%- set _ = members.append(h ~ '=https://' ~ hostvars[h]['ansible_host'] ~ ':' ~ etcd_peer_port) -%}
|
||
{%- endfor -%}
|
||
{{ members | join(',') }}
|
||
|
||
- name: Configure and start etcd service
|
||
ansible.builtin.include_role:
|
||
name: etcd
|
||
tasks_from: service
|
||
|
||
# ── Верификация кластера ──────────────────────────────────────────────────────
|
||
- name: Verify etcd cluster
|
||
hosts: "{{ node_to_add }}"
|
||
gather_facts: false
|
||
become: true
|
||
tags: [verify]
|
||
tasks:
|
||
- name: Show etcd cluster members
|
||
ansible.builtin.shell: |
|
||
ETCDCTL_API=3 etcdctl \
|
||
--endpoints="{% for h in groups['etcd_nodes'] %}https://{{ hostvars[h]['ansible_host'] }}:{{ etcd_client_port }}{% if not loop.last %},{% endif %}{% endfor %}" \
|
||
--cacert="{{ etcd_pki_dir }}/ca.crt" \
|
||
--cert="{{ etcd_pki_dir }}/server.crt" \
|
||
--key="{{ etcd_pki_dir }}/server.key" \
|
||
member list -w table
|
||
register: _members
|
||
changed_when: false
|
||
|
||
- name: Display cluster members
|
||
ansible.builtin.debug:
|
||
msg: "{{ _members.stdout_lines }}"
|
||
|
||
- name: Summary
|
||
ansible.builtin.debug:
|
||
msg: >
|
||
Нода {{ node_to_add }} ({{ hostvars[node_to_add]['ansible_host'] }})
|
||
успешно добавлена в etcd кластер.
|
||
Не забудь обновить k3s конфиг если нода новая: make install-k3s.
|