--- - name: 验证拓扑和签发配置 ansible.builtin.assert: that: - groups['etcd'] | length == 3 - groups['etcd'] | map('extract', hostvars, 'etcd_address') | unique | length == 3 - ansible_facts['architecture'] == 'x86_64' - etcd_bao_url is match('^https://') - etcd_archive_checksum is match('^sha256:[a-f0-9]{64}$') no_log: true - name: 安装证书处理依赖 ansible.builtin.package: name: [python3-cryptography, openssl] state: present - name: 创建独立 etcd 组 ansible.builtin.group: name: homelab-etcd system: true - name: 创建独立 etcd 用户 ansible.builtin.user: name: homelab-etcd group: homelab-etcd system: true shell: /usr/sbin/nologin create_home: false - name: 创建受管目录 ansible.builtin.file: path: "{{ item.path }}" state: directory owner: "{{ item.owner }}" group: homelab-etcd mode: "{{ item.mode }}" loop: - {path: "{{ etcd_config_dir }}", owner: root, mode: '0750'} - {path: "{{ etcd_data_dir }}", owner: homelab-etcd, mode: '0700'} - {path: "{{ etcd_install_dir }}", owner: root, mode: '0755'} - name: 下载固定版本及校验归档 ansible.builtin.get_url: url: >- https://github.com/etcd-io/etcd/releases/download/v{{ etcd_version }}/etcd-v{{ etcd_version }}-linux-amd64.tar.gz dest: "{{ etcd_install_dir }}/etcd-v{{ etcd_version }}.tar.gz" checksum: "{{ etcd_archive_checksum }}" mode: '0644' register: etcd_download retries: 3 delay: 5 until: etcd_download is succeeded - name: 展开固定版本 ansible.builtin.unarchive: src: "{{ etcd_install_dir }}/etcd-v{{ etcd_version }}.tar.gz" dest: "{{ etcd_install_dir }}" remote_src: true creates: "{{ etcd_install_dir }}/etcd-v{{ etcd_version }}-linux-amd64/etcd" - name: 安装版本链接 ansible.builtin.file: src: "{{ etcd_install_dir }}/etcd-v{{ etcd_version }}-linux-amd64/{{ item }}" dest: "{{ etcd_install_dir }}/{{ item }}" state: link loop: [etcd, etcdctl, etcdutl] register: etcd_binary_links - name: 签发成员与管理员证书 ansible.builtin.include_tasks: certificate.yml loop: - {name: server, role: homelab-etcd-server, cn: "{{ inventory_hostname }}", eku: [serverAuth], group: homelab-etcd} - {name: peer, role: homelab-etcd-peer, cn: homelab-etcd-peer, eku: [serverAuth, clientAuth], group: homelab-etcd} - {name: gateway, role: homelab-etcd-gateway, cn: "", eku: [clientAuth], group: homelab-etcd} - {name: admin, role: homelab-etcd-admin, cn: root, eku: [clientAuth], group: root} loop_control: loop_var: etcd_cert - name: 写入独立 etcd 配置 ansible.builtin.template: src: etcd.yml.j2 dest: "{{ etcd_config_dir }}/etcd.yml" owner: root group: homelab-etcd mode: '0640' register: etcd_config_file - name: 写入独立 systemd unit ansible.builtin.template: src: homelab-etcd.service.j2 dest: /etc/systemd/system/homelab-etcd.service mode: '0644' register: etcd_unit # 跨失败重跑记录激活状态,防止上一轮写文件后中断导致漏掉必要重启。 - name: 计算受管文件校验和 ansible.builtin.stat: path: "{{ item }}" checksum_algorithm: sha256 loop: - "{{ etcd_config_dir }}/etcd.yml" - "{{ etcd_config_dir }}/server.crt" - "{{ etcd_config_dir }}/peer.crt" - "{{ etcd_config_dir }}/gateway.crt" - "{{ etcd_config_dir }}/ca.crt" - /etc/systemd/system/homelab-etcd.service register: etcd_managed_files - name: 计算期望激活指纹 ansible.builtin.set_fact: etcd_config_fingerprint: >- {{ ((etcd_managed_files.results | map(attribute='stat.checksum') | list | join(':')) ~ ':' ~ etcd_version) | hash('sha256') }} when: not ansible_check_mode - name: 检查已激活指纹 ansible.builtin.stat: path: "{{ etcd_config_dir }}/activated.sha256" register: etcd_activated_file - name: 读取已激活指纹 ansible.builtin.slurp: src: "{{ etcd_config_dir }}/activated.sha256" register: etcd_activated when: etcd_activated_file.stat.exists - name: 判断是否需要滚动激活 ansible.builtin.set_fact: etcd_config_changed: >- {{ not etcd_activated_file.stat.exists or (etcd_activated.content | default('') | b64decode | trim) != etcd_config_fingerprint | default('check-mode') }} - name: 管理本地快照任务 ansible.builtin.import_tasks: snapshot.yml