feat: список пользователей cluster_service_users + роль chrony для синхронизации времени

Список пользователей (cluster_service_users):
- заменяет отдельные k8s_service_user и devops_service_user переменные
- поддерживает неограниченное число пользователей — добавь строку в список
- каждый пользователь: name, comment, shell, sudo, key_type, key_bits, key_comment, ssh_dir
- playbooks/k8s-user.yml полностью переработан — все plays используют loop: cluster_service_users
- generate_keys/distribute_keys/create_user вызываются через include_role + vars
- .gitignore: keys/*_id_rsa (паттерн вместо перечисления конкретных имён)

Роль chrony — синхронизация времени:
- устанавливается ПЕРЕД k3s как обязательный компонент (добавлена в site.yml play 0)
- часовой пояс: chrony_timezone: "Europe/Moscow" (переопределяется в group_vars)
- NTP серверы: pool.ntp.org (настраиваемые через chrony_ntp_servers)
- community.general.timezone: идемпотентная установка TZ
- chronyc makestep: принудительная синхронизация при первом деплое
- устанавливается также на lab_hosts в playbooks/k8s-user.yml
- make chrony — отдельная цель для переустановки/смены TZ (make chrony TZ=UTC)
- команда chrony в entrypoint.sh
This commit is contained in:
Sergey Antropoff
2026-04-24 07:11:38 +03:00
parent 7c71b69333
commit c6f3c60434
10 changed files with 249 additions and 189 deletions

View File

@@ -1,50 +1,66 @@
---
# ─────────────────────────────────────────────────────────────────────────────
# k8s-user: создание сервисных пользователей на всех серверах
#
# Роль k8s-user универсальна — вызывается дважды:
# • для пользователя k8s (автоматизация кластера)
# • для пользователя devops (инженеры DevOps)
# k8s-user: создание сервисных пользователей из списка cluster_service_users
#
# Обрабатывает ЛЮБОЕ количество пользователей из списка в group_vars.
# Для каждого пользователя:
# 1. Создать пользователя + sudo на всех нодах кластера
# 2. Сгенерировать RSA 4096 ключевую пару на первом мастере (один раз)
# 3. Сохранить ключи локально в ./keys/
# 4. Разложить ключи на все ноды кластера (SSH в любую сторону)
# 1. Создать на всех нодах кластера (пользователь + sudo)
# 2. Сгенерировать RSA 4096 ключевую пару на первом мастере
# 3. Сохранить ключи локально в ./keys/<user>_id_rsa
# 4. Разложить ключи на все ноды кластера
# 5. Обновить /etc/hosts на нодах кластера
# 6. То же самое для lab_hosts (через пароль из vault)
# 6. То же самое для lab_hosts (через bootstrap credentials из vault)
#
# Настройка пользователей: group_vars/all/main.yml → cluster_service_users
#
# Запуск: ansible-playbook playbooks/k8s-user.yml --ask-vault-pass
# Только один пользователь: ansible-playbook playbooks/k8s-user.yml --tags k8s
# Только кластер: ansible-playbook playbooks/k8s-user.yml --limit k3s_cluster
# ─────────────────────────────────────────────────────────────────────────────
# ════════════════════════════════════════════════════════════════════════════
# ПОЛЬЗОВАТЕЛЬ k8s
# ════════════════════════════════════════════════════════════════════════════
- name: "[k8s] Create service user on cluster nodes"
# ── 1. Создать всех пользователей на нодах кластера ──────────────────────────
- name: Create service users on cluster nodes
hosts: k3s_cluster
gather_facts: true
become: true
tags: [k8s, k8s_user]
roles:
- role: k8s-user
tasks:
- name: Create user {{ item.name }}
ansible.builtin.include_role:
name: k8s-user
tasks_from: create_user.yml
vars:
k8s_service_user: "{{ item.name }}"
k8s_service_user_comment: "{{ item.comment | default(item.name) }}"
k8s_service_user_shell: "{{ item.shell | default('/bin/bash') }}"
k8s_service_user_sudo: "{{ item.sudo | default(true) }}"
k8s_service_user_ssh_dir: "{{ item.ssh_dir | default('.ssh') }}"
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: "[k8s] Generate SSH key pair (first master only)"
# ── 2. Сгенерировать ключевые пары для всех пользователей (первый мастер) ────
- name: Generate SSH key pairs for all users
hosts: "{{ groups['k3s_master'][0] }}"
gather_facts: false
become: true
tags: [k8s, k8s_user]
tasks:
- name: Generate RSA key pair and store facts
- name: Generate key pair for {{ item.name }}
ansible.builtin.include_role:
name: k8s-user
tasks_from: generate_keys.yml
vars:
k8s_service_user: "{{ item.name }}"
k8s_service_user_key_type: "{{ item.key_type | default('rsa') }}"
k8s_service_user_key_bits: "{{ item.key_bits | default(4096) }}"
k8s_service_user_key_comment: "{{ item.key_comment | default(item.name + '@cluster') }}"
k8s_service_user_ssh_dir: "{{ item.ssh_dir | default('.ssh') }}"
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: "[k8s] Save SSH keys to local machine"
# ── 3. Сохранить все ключи локально в ./keys/ ────────────────────────────────
- name: Save SSH keys to local machine
hosts: "{{ groups['k3s_master'][0] }}"
gather_facts: false
tags: [k8s, k8s_user]
tasks:
- name: Create local keys directory
ansible.builtin.file:
@@ -54,53 +70,68 @@
delegate_to: localhost
become: false
- name: Save private key locally
- name: Save private key for {{ item.name }}
ansible.builtin.copy:
content: "{{ lookup('vars', k8s_service_user + '_ssh_private_key') }}"
dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa"
content: "{{ hostvars[inventory_hostname][item.name + '_ssh_private_key'] }}"
dest: "{{ k8s_local_keys_dir }}/{{ item.name }}_id_rsa"
mode: '0600'
delegate_to: localhost
become: false
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: Save public key locally
- name: Save public key for {{ item.name }}
ansible.builtin.copy:
content: "{{ lookup('vars', k8s_service_user + '_ssh_public_key') }}\n"
dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa.pub"
content: "{{ hostvars[inventory_hostname][item.name + '_ssh_public_key'] }}\n"
dest: "{{ k8s_local_keys_dir }}/{{ item.name }}_id_rsa.pub"
mode: '0644'
delegate_to: localhost
become: false
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: Show where keys were saved
- name: Show saved key locations
ansible.builtin.debug:
msg: "SSH keys saved to {{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa"
msg: "Keys saved: {{ k8s_local_keys_dir }}/{{ item.name }}_id_rsa"
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: "[k8s] Distribute SSH keys to all cluster nodes"
# ── 4. Разложить ключи на все ноды кластера ──────────────────────────────────
- name: Distribute SSH keys to all cluster nodes
hosts: k3s_cluster
gather_facts: false
become: true
tags: [k8s, k8s_user]
tasks:
- name: Deploy keys to node
- name: Deploy keys for {{ item.name }}
ansible.builtin.include_role:
name: k8s-user
tasks_from: distribute_keys.yml
vars:
k8s_service_user: "{{ item.name }}"
k8s_service_user_ssh_dir: "{{ item.ssh_dir | default('.ssh') }}"
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: "[k8s] Update /etc/hosts on cluster nodes"
# ── 5. Обновить /etc/hosts на нодах кластера (один раз на хост) ──────────────
- name: Update /etc/hosts on cluster nodes
hosts: k3s_cluster
gather_facts: false
become: true
tags: [k8s, k8s_user]
tasks:
- name: Update hosts file
ansible.builtin.include_role:
name: k8s-user
tasks_from: update_hosts.yml
- name: "[k8s] Setup user on lab hosts"
# ── 6. Настроить всё на lab_hosts (через bootstrap credentials из vault) ──────
- name: Setup service users on lab hosts
hosts: lab_hosts
gather_facts: true
become: true
tags: [k8s, k8s_user]
vars:
ansible_user: "{{ bootstrap_user }}"
ansible_password: "{{ bootstrap_password }}"
@@ -110,133 +141,47 @@
-o PasswordAuthentication=yes
-o PubkeyAuthentication=no
tasks:
- ansible.builtin.include_role:
- name: Create user {{ item.name }} on lab host
ansible.builtin.include_role:
name: k8s-user
tasks_from: create_user.yml
- ansible.builtin.include_role:
vars:
k8s_service_user: "{{ item.name }}"
k8s_service_user_comment: "{{ item.comment | default(item.name) }}"
k8s_service_user_shell: "{{ item.shell | default('/bin/bash') }}"
k8s_service_user_sudo: "{{ item.sudo | default(true) }}"
k8s_service_user_ssh_dir: "{{ item.ssh_dir | default('.ssh') }}"
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: Deploy keys for {{ item.name }} on lab host
ansible.builtin.include_role:
name: k8s-user
tasks_from: distribute_keys.yml
- ansible.builtin.include_role:
vars:
k8s_service_user: "{{ item.name }}"
k8s_service_user_ssh_dir: "{{ item.ssh_dir | default('.ssh') }}"
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
- name: Update /etc/hosts on lab host
ansible.builtin.include_role:
name: k8s-user
tasks_from: update_hosts.yml
# ════════════════════════════════════════════════════════════════════════════
# ПОЛЬЗОВАТЕЛЬ devops
# ════════════════════════════════════════════════════════════════════════════
- name: "[devops] Create service user on cluster nodes"
hosts: k3s_cluster
- name: Configure time synchronization on lab hosts
hosts: lab_hosts
gather_facts: true
become: true
tags: [devops, devops_user]
vars:
k8s_service_user: "{{ devops_service_user }}"
k8s_service_user_comment: "{{ devops_service_user_comment }}"
k8s_service_user_key_comment: "{{ devops_service_user_key_comment }}"
k8s_service_user_sudo: "{{ devops_service_user_sudo }}"
k8s_service_user_shell: "{{ devops_service_user_shell }}"
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
roles:
- role: k8s-user
- name: "[devops] Generate SSH key pair (first master only)"
hosts: "{{ groups['k3s_master'][0] }}"
gather_facts: false
become: true
tags: [devops, devops_user]
vars:
k8s_service_user: "{{ devops_service_user }}"
tasks:
- name: Generate RSA key pair and store facts
ansible.builtin.include_role:
name: k8s-user
tasks_from: generate_keys.yml
- name: "[devops] Save SSH keys to local machine"
hosts: "{{ groups['k3s_master'][0] }}"
gather_facts: false
tags: [devops, devops_user]
vars:
k8s_service_user: "{{ devops_service_user }}"
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: "{{ lookup('vars', k8s_service_user + '_ssh_private_key') }}"
dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa"
mode: '0600'
delegate_to: localhost
become: false
- name: Save public key locally
ansible.builtin.copy:
content: "{{ lookup('vars', k8s_service_user + '_ssh_public_key') }}\n"
dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_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 }}/{{ k8s_service_user }}_id_rsa"
- name: "[devops] Distribute SSH keys to all cluster nodes"
hosts: k3s_cluster
gather_facts: false
become: true
tags: [devops, devops_user]
vars:
k8s_service_user: "{{ devops_service_user }}"
tasks:
- name: Deploy keys to node
ansible.builtin.include_role:
name: k8s-user
tasks_from: distribute_keys.yml
- name: "[devops] Update /etc/hosts on cluster nodes"
hosts: k3s_cluster
gather_facts: false
become: true
tags: [devops, devops_user]
vars:
k8s_service_user: "{{ devops_service_user }}"
tasks:
- name: Update hosts file
ansible.builtin.include_role:
name: k8s-user
tasks_from: update_hosts.yml
- name: "[devops] Setup user on lab hosts"
hosts: lab_hosts
gather_facts: true
become: true
tags: [devops, devops_user]
vars:
k8s_service_user: "{{ devops_service_user }}"
k8s_service_user_comment: "{{ devops_service_user_comment }}"
k8s_service_user_key_comment: "{{ devops_service_user_key_comment }}"
k8s_service_user_sudo: "{{ devops_service_user_sudo }}"
k8s_service_user_shell: "{{ devops_service_user_shell }}"
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:
- ansible.builtin.include_role:
name: k8s-user
tasks_from: create_user.yml
- ansible.builtin.include_role:
name: k8s-user
tasks_from: distribute_keys.yml
- ansible.builtin.include_role:
name: k8s-user
tasks_from: update_hosts.yml
- role: chrony

View File

@@ -2,16 +2,27 @@
# ─────────────────────────────────────────────────────────────────────────────
# 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)
# 0. Chrony (синхронизация времени — ОБЯЗАТЕЛЬНО до k3s)
# 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
# ─────────────────────────────────────────────────────────────────────────────
# ── 0. Chrony — синхронизация времени (обязательно до k3s) ───────────────────
# Расхождение времени нарушает работу etcd, TLS и Kubernetes API
- name: Configure time synchronization (chrony)
hosts: k3s_cluster
gather_facts: true
become: true
tags: [chrony, time, prereqs]
roles:
- role: chrony
# ── 1. K3S Cluster ────────────────────────────────────────────────────────────
# serial: 1 — master01 запускается первым (cluster-init), остальные присоединяются
- name: Install K3S cluster (HA embedded etcd)