From c6f3c60434b7ee07051d0bb9af49ee8061e0250a Mon Sep 17 00:00:00 2001 From: Sergey Antropoff Date: Fri, 24 Apr 2026 07:11:38 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D1=81=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9=20cluster=5Fservice=5Fusers=20+=20=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=20chrony=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=B8?= =?UTF-8?q?=D0=BD=D1=85=D1=80=D0=BE=D0=BD=D0=B8=D0=B7=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Список пользователей (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 --- .gitignore | 5 +- Makefile | 8 +- docker/entrypoint.sh | 7 + group_vars/all/main.yml | 55 +++--- playbooks/k8s-user.yml | 261 ++++++++++---------------- playbooks/site.yml | 21 ++- roles/chrony/defaults/main.yml | 17 ++ roles/chrony/handlers/main.yml | 6 + roles/chrony/tasks/main.yml | 47 +++++ roles/chrony/templates/chrony.conf.j2 | 11 ++ 10 files changed, 249 insertions(+), 189 deletions(-) create mode 100644 roles/chrony/defaults/main.yml create mode 100644 roles/chrony/handlers/main.yml create mode 100644 roles/chrony/tasks/main.yml create mode 100644 roles/chrony/templates/chrony.conf.j2 diff --git a/.gitignore b/.gitignore index 86a17cd..020ab4a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,8 @@ id_rsa id_ed25519 id_ecdsa -# Локально сохранённые приватные ключи (публичные ключи *_id_rsa.pub — ок коммитить) -keys/k8s_id_rsa -keys/devops_id_rsa +# Локально сохранённые приватные ключи из keys/ (публичные *_id_rsa.pub — ок коммитить) +keys/*_id_rsa # Docker артефакты .docker/ diff --git a/Makefile b/Makefile index e05f17a..db01e3c 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ DOCKER_RUN := docker run --rm -it \ $(IMAGE_NAME) .PHONY: help setup build rebuild \ - bootstrap k8s-user mdadm k3s-certs \ + bootstrap k8s-user mdadm k3s-certs chrony \ install install-k3s install-cni install-kubevip install-nfs install-ingress \ install-cert-manager install-istio install-monitoring \ add-node remove-node \ @@ -205,6 +205,12 @@ mdadm: _check_env _check_image ## Найти RAID массив и смонтир $(DOCKER_RUN) ansible-playbook playbooks/mdadm.yml \ $(if $(NODE),--limit $(NODE),) +chrony: _check_env _check_image ## Установить и настроить chrony (синхронизация времени + часовой пояс) + @printf "$(CYAN)Настройка chrony (timezone: $(or $(TZ),из group_vars))...$(NC)\n" + $(DOCKER_RUN) ansible-playbook playbooks/site.yml --tags chrony \ + $(if $(TZ),-e chrony_timezone=$(TZ),) \ + $(if $(NODE),--limit $(NODE),) + k3s-certs: _check_env _check_image ## Установить systemd таймер автоматической ротации сертификатов K3S @printf "$(CYAN)Настройка автоматической ротации сертификатов K3S...$(NC)\n" $(DOCKER_RUN) ansible-playbook playbooks/k3s-certs.yml \ diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index b64fe4e..362f0f8 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -61,6 +61,7 @@ print_help() { echo " bootstrap — создать пользователя + задеплоить SSH ключ" echo " k8s-user — создать k8s пользователя + разложить SSH ключи" echo " mdadm — найти RAID массив и смонтировать в /storage" + echo " chrony — установить chrony + настроить timezone" echo " k3s-certs — установить systemd таймер ротации сертификатов" echo " install — полный стек (site.yml)" echo " install-k3s — только K3S" @@ -219,6 +220,12 @@ case "${COMMAND}" in run_playbook playbooks/mdadm.yml "$@" ;; + # ── chrony ──────────────────────────────────────────────────────────────── + chrony) + log "Настройка chrony и синхронизации времени..." + run_playbook playbooks/site.yml --tags chrony "$@" + ;; + # ── k3s-certs ───────────────────────────────────────────────────────────── k3s-certs) log "Установка systemd таймера ротации сертификатов K3S..." diff --git a/group_vars/all/main.yml b/group_vars/all/main.yml index aa83486..21a9b1e 100644 --- a/group_vars/all/main.yml +++ b/group_vars/all/main.yml @@ -195,32 +195,43 @@ etcd_backup_local_dir: "./etcd-backups" # Отключить на конкретной ноде: задай mdadm_enabled: false в host_vars//main.yml mdadm_enabled: false -# ─── k8s-user ───────────────────────────────────────────────────────────────── -# Сервисный пользователь k8s — создаётся на всех серверах (кластер + lab_hosts) -# RSA 4096 ключ генерируется один раз на первом мастере, затем раскладывается везде -k8s_service_user: k8s -k8s_service_user_shell: /bin/bash -k8s_service_user_comment: "K8S Service Account" -k8s_service_user_key_type: rsa -k8s_service_user_key_bits: 4096 -k8s_service_user_key_comment: "k8s@cluster" -k8s_service_user_ssh_dir: ".ssh" -k8s_service_user_sudo: true - -# ─── devops-user ────────────────────────────────────────────────────────────── -# Дополнительный пользователь для инженеров DevOps -# Создаётся на тех же серверах что и k8s, та же RSA 4096 схема с ключами -devops_service_user: devops -devops_service_user_shell: /bin/bash -devops_service_user_comment: "DevOps Engineer" -devops_service_user_key_comment: "devops@cluster" -devops_service_user_sudo: true +# ─── Сервисные пользователи ─────────────────────────────────────────────────── +# Список пользователей, создаваемых на ВСЕХ серверах (кластер + lab_hosts). +# Для каждого: RSA 4096 ключевая пара, authorized_keys, sudo NOPASSWD. +# Добавь любое количество пользователей — всё остальное Ansible сделает сам. +# +# Обязательные поля: name +# Опциональные: comment, shell, sudo, key_type, key_bits, key_comment, ssh_dir +cluster_service_users: + - name: k8s + comment: "K8S Service Account" + key_comment: "k8s@cluster" + sudo: true + shell: /bin/bash + key_type: rsa + key_bits: 4096 + - name: devops + comment: "DevOps Engineer" + key_comment: "devops@cluster" + sudo: true + shell: /bin/bash + key_type: rsa + key_bits: 4096 # Локальная директория для сохранения сгенерированных SSH ключей -# Сохраняется на машине запуска Ansible (./keys/ относительно корня проекта) -# Файлы: keys/k8s_id_rsa, keys/k8s_id_rsa.pub, keys/devops_id_rsa, keys/devops_id_rsa.pub +# Файлы: keys/_id_rsa, keys/_id_rsa.pub k8s_local_keys_dir: "./keys" +# ─── Chrony — синхронизация времени ─────────────────────────────────────────── +# Устанавливается на все ноды кластера и lab_hosts как обязательный компонент. +# Критично для корректной работы etcd, TLS и Kubernetes API. +chrony_timezone: "Europe/Moscow" +chrony_ntp_servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 2.pool.ntp.org + - 3.pool.ntp.org + # ─── k3s-certs — автоматическая ротация сертификатов K3S ───────────────────── # K3S выпускает сертификаты с фиксированным сроком жизни 1 год. # Systemd таймер обеспечивает автоматическое обновление до истечения срока, diff --git a/playbooks/k8s-user.yml b/playbooks/k8s-user.yml index 2c1c152..968d210 100644 --- a/playbooks/k8s-user.yml +++ b/playbooks/k8s-user.yml @@ -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/_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 diff --git a/playbooks/site.yml b/playbooks/site.yml index 3dfdcd7..6723655 100644 --- a/playbooks/site.yml +++ b/playbooks/site.yml @@ -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) diff --git a/roles/chrony/defaults/main.yml b/roles/chrony/defaults/main.yml new file mode 100644 index 0000000..ab63bd0 --- /dev/null +++ b/roles/chrony/defaults/main.yml @@ -0,0 +1,17 @@ +--- +# ─── chrony — синхронизация времени ────────────────────────────────────────── + +# Часовой пояс (формат IANA: Europe/Moscow, UTC, Asia/Novosibirsk, и т.д.) +chrony_timezone: "Europe/Moscow" + +# NTP серверы (iburst — быстрая первоначальная синхронизация) +chrony_ntp_servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 2.pool.ntp.org + - 3.pool.ntp.org + +# Максимальный шаг коррекции при старте (секунды) — важно для k8s кластера +# Слишком большое расхождение времени нарушает работу TLS и etcd +chrony_makestep_threshold: 1.0 +chrony_makestep_limit: 3 diff --git a/roles/chrony/handlers/main.yml b/roles/chrony/handlers/main.yml new file mode 100644 index 0000000..9cfa758 --- /dev/null +++ b/roles/chrony/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart chrony + ansible.builtin.systemd: + name: chrony + state: restarted + become: true diff --git a/roles/chrony/tasks/main.yml b/roles/chrony/tasks/main.yml new file mode 100644 index 0000000..a892bdc --- /dev/null +++ b/roles/chrony/tasks/main.yml @@ -0,0 +1,47 @@ +--- +- name: Install chrony + ansible.builtin.apt: + name: chrony + state: present + update_cache: false + become: true + +- name: Set system timezone + community.general.timezone: + name: "{{ chrony_timezone }}" + become: true + notify: restart chrony + +- name: Deploy chrony configuration + ansible.builtin.template: + src: chrony.conf.j2 + dest: /etc/chrony/chrony.conf + owner: root + group: root + mode: '0644' + backup: true + become: true + notify: restart chrony + +- name: Enable and start chrony service + ansible.builtin.systemd: + name: chrony + enabled: true + state: started + become: true + +- name: Force immediate time synchronization + ansible.builtin.command: chronyc makestep + become: true + changed_when: false + failed_when: false + +- name: Show synchronization status + ansible.builtin.command: chronyc tracking + register: chrony_tracking + changed_when: false + become: true + +- name: Display time sync status + ansible.builtin.debug: + msg: "{{ chrony_tracking.stdout_lines }}" diff --git a/roles/chrony/templates/chrony.conf.j2 b/roles/chrony/templates/chrony.conf.j2 new file mode 100644 index 0000000..5ef5043 --- /dev/null +++ b/roles/chrony/templates/chrony.conf.j2 @@ -0,0 +1,11 @@ +# Managed by Ansible — не редактируй вручную +# K3S Cluster — Time Synchronization (chrony) + +{% for server in chrony_ntp_servers %} +server {{ server }} iburst +{% endfor %} + +driftfile /var/lib/chrony/drift +makestep {{ chrony_makestep_threshold }} {{ chrony_makestep_limit }} +rtcsync +logdir /var/log/chrony