From 0cc2103a90082ab44753fd07427eb19ec5ade516 Mon Sep 17 00:00:00 2001 From: cnbugs Date: Thu, 30 Jul 2026 23:02:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E9=9B=86=E7=BE=A4?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=A8=A1=E6=9D=BF=20-=20K8S/Ceph/Rook-Ceph/E?= =?UTF-8?q?TCD/Harbor/NFS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增'集群部署'分类(6个模板) - Kubernetes集群部署(kubeadm, Master+Worker, Calico/Flannel) - Ceph存储集群部署(cephadm, MON+OSD+MDS+RGW+Dashboard) - K8S + Rook-Ceph持久化存储(Operator+CephCluster+StorageClass) - ETCD集群部署(3/5节点, Systemd服务) - Harbor镜像仓库部署(HTTPS+Trivy扫描) - NFS共享存储集群(服务端+客户端自动挂载) - 总模板数: 24 -> 30 --- internal/services/templates.go | 997 ++++++++++++++++++++++++++++++++- 1 file changed, 996 insertions(+), 1 deletion(-) diff --git a/internal/services/templates.go b/internal/services/templates.go index 99acb38..1403af5 100644 --- a/internal/services/templates.go +++ b/internal/services/templates.go @@ -32,7 +32,7 @@ func GetTemplateCategories() []TemplateCategory { } var result []TemplateCategory // 按固定顺序输出 - order := []string{"system", "web", "database", "container", "devops", "security", "monitoring"} + order := []string{"system", "web", "database", "container", "cluster", "devops", "security", "monitoring"} for _, id := range order { if c, ok := cats[id]; ok { result = append(result, c) @@ -46,6 +46,7 @@ var categoryNames = map[string]string{ "web": "Web服务", "database": "数据库", "container": "容器化", + "cluster": "集群部署", "devops": "DevOps", "security": "安全加固", "monitoring": "监控告警", @@ -56,6 +57,7 @@ var categoryIcons = map[string]string{ "web": "🌐", "database": "🗄️", "container": "🐳", + "cluster": "☸️", "devops": "🔧", "security": "🔒", "monitoring": "📊", @@ -1652,6 +1654,999 @@ func GetPlaybookTemplates() []PlaybookTemplate { {% endif %} 依赖修复: {{ '是' if fix_dependencies else '否' }} ═══════════════════════════ +`, + }, + + // ===== 集群部署 ===== + { + ID: "k8s-cluster", Name: "Kubernetes集群部署", Category: "cluster", + Description: "使用kubeadm部署K8S集群(Master+Worker),含容器运行时、网络插件、Dashboard", + Icon: "☸️", Tags: []string{"kubernetes", "k8s", "kubeadm", "cluster"}, + Content: `--- +# ============================================================ +# Kubernetes 集群部署 (kubeadm) +# 使用方法: +# 1. 在inventory中定义 k8s_master 和 k8s_worker 组 +# 2. 修改下方 vars 中的版本和网段 +# 3. 执行本Playbook +# ============================================================ +- name: K8S集群 - 基础环境准备 + hosts: "{{ target_hosts | default('all') }}" + become: yes + vars: + k8s_version: "1.29" + pod_network_cidr: "10.244.0.0/16" + service_cidr: "10.96.0.0/12" + cni_plugin: calico # calico 或 flannel + + tasks: + - name: 关闭swap + shell: | + swapoff -a + sed -i '/swap/s/^/#/' /etc/fstab + + - name: 加载内核模块 + modprobe: + name: "{{ item }}" + state: present + loop: + - overlay + - br_netfilter + + - name: 持久化内核模块 + copy: + content: | + overlay + br_netfilter + dest: /etc/modules-load.d/k8s.conf + + - name: 设置内核参数 + sysctl: + name: "{{ item.key }}" + value: "{{ item.value }}" + sysctl_set: yes + reload: yes + loop: + - { key: "net.bridge.bridge-nf-call-iptables", value: "1" } + - { key: "net.bridge.bridge-nf-call-ip6tables", value: "1" } + - { key: "net.ipv4.ip_forward", value: "1" } + + - name: 关闭防火墙 + service: + name: firewalld + state: stopped + enabled: no + ignore_errors: yes + + - name: 关闭SELinux + shell: setenforce 0 && sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config + ignore_errors: yes + + - name: 时间同步检查 + shell: timedatectl set-ntp true + ignore_errors: yes + +- name: K8S集群 - 安装容器运行时和K8S组件 + hosts: "{{ target_hosts | default('all') }}" + become: yes + vars: + k8s_version: "1.29" + + tasks: + - name: 安装containerd依赖 + apt: + name: + - apt-transport-https + - ca-certificates + - curl + - gnupg + state: present + update_cache: yes + when: ansible_os_family == "Debian" + + - name: 安装containerd + shell: | + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list + apt-get update && apt-get install -y containerd.io + when: ansible_os_family == "Debian" + ignore_errors: yes + + - name: 配置containerd + shell: | + mkdir -p /etc/containerd + containerd config default > /etc/containerd/config.toml + sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml + systemctl restart containerd && systemctl enable containerd + ignore_errors: yes + + - name: 添加K8S APT源 + shell: | + curl -fsSL https://pkgs.k8s.io/core:/stable:/v{{ k8s_version }}/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg + echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v{{ k8s_version }}/deb/ /" > /etc/apt/sources.list.d/kubernetes.list + apt-get update + when: ansible_os_family == "Debian" + + - name: 安装kubeadm/kubelet/kubectl + apt: + name: + - kubelet + - kubeadm + - kubectl + state: present + update_cache: yes + when: ansible_os_family == "Debian" + + - name: 锁定K8S包版本 + shell: apt-mark hold kubelet kubeadm kubectl + when: ansible_os_family == "Debian" + + - name: 启动kubelet + service: + name: kubelet + state: started + enabled: yes + +- name: K8S集群 - 初始化Master + hosts: k8s_master + become: yes + vars: + pod_network_cidr: "10.244.0.0/16" + service_cidr: "10.96.0.0/12" + cni_plugin: calico + + tasks: + - name: 初始化Master节点 + shell: | + kubeadm init \ + --pod-network-cidr={{ pod_network_cidr }} \ + --service-cidr={{ service_cidr }} \ + --upload-certs \ + --ignore-preflight-errors=NumCPU + register: kubeadm_init + ignore_errors: yes + + - name: 配置kubectl + shell: | + mkdir -p $HOME/.kube + cp -f /etc/kubernetes/admin.conf $HOME/.kube/config + chown $(id -u):$(id -g) $HOME/.kube/config + ignore_errors: yes + + - name: 部署Calico网络 + shell: kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml + when: cni_plugin == "calico" + ignore_errors: yes + + - name: 部署Flannel网络 + shell: kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml + when: cni_plugin == "flannel" + ignore_errors: yes + + - name: 获取Worker加入命令 + shell: kubeadm token create --print-join-command + register: join_command + changed_when: false + + - name: 显示加入命令 + debug: + msg: | + ═══════ K8S Master 初始化完成 ═══════ + Worker加入命令: + {{ join_command.stdout }} + ═══════════════════════════════════ + +- name: K8S集群 - Worker加入集群 + hosts: k8s_worker + become: yes + vars: + master_ip: "{{ hostvars[groups['k8s_master'][0]]['ansible_host'] | default(groups['k8s_master'][0]) }}" + + tasks: + - name: 获取加入命令 + shell: ssh -o StrictHostKeyChecking=no {{ master_ip }} "kubeadm token create --print-join-command" + register: join_cmd + delegate_to: "{{ groups['k8s_master'][0] }}" + ignore_errors: yes + + - name: 加入集群 + shell: "{{ join_cmd.stdout }}" + when: join_cmd is succeeded + ignore_errors: yes + + - name: 验证节点状态 + shell: kubectl get nodes + delegate_to: "{{ groups['k8s_master'][0] }}" + register: nodes_status + changed_when: false + ignore_errors: yes + + - name: 显示集群状态 + debug: + msg: "{{ nodes_status.stdout_lines | default(['等待Master就绪']) }}" +`, + }, + { + ID: "ceph-cluster", Name: "Ceph存储集群部署", Category: "cluster", + Description: "使用cephadm部署Ceph集群(MON+OSD+MDS+RGW),含Dashboard", + Icon: "🐙", Tags: []string{"ceph", "storage", "cephadm", "cluster"}, + Content: `--- +# ============================================================ +# Ceph 存储集群部署 (cephadm) +# 使用方法: +# 1. 在inventory中定义 ceph_mon, ceph_osd, ceph_mds 组 +# 2. 修改下方 vars 中的网络和磁盘配置 +# 3. 执行本Playbook +# ============================================================ +- name: Ceph集群 - 基础环境准备 + hosts: "{{ target_hosts | default('all') }}" + become: yes + vars: + ceph_release: reef # quincy 或 reef + cluster_network: "10.0.0.0/24" + public_network: "192.168.1.0/24" + + tasks: + - name: 安装基础依赖 + package: + name: + - python3 + - lvm2 + - chrony + - podman + state: present + + - name: 配置时间同步 + service: + name: chronyd + state: started + enabled: yes + ignore_errors: yes + + - name: 关闭防火墙 + service: + name: firewalld + state: stopped + enabled: no + ignore_errors: yes + + - name: 设置主机名解析 + lineinfile: + path: /etc/hosts + line: "{{ hostvars[item]['ansible_host'] | default(item) }} {{ item }}" + create: yes + loop: "{{ groups['all'] }}" + when: hostvars[item]['ansible_host'] is defined + +- name: Ceph集群 - 安装cephadm + hosts: ceph_mon + become: yes + vars: + ceph_release: reef + + tasks: + - name: 安装cephadm + shell: | + curl --silent --remote-name --location https://github.com/ceph/ceph/raw/{{ ceph_release }}/src/cephadm/cephadm + chmod +x cephadm + ./cephadm add-repo --release {{ ceph_release }} + ./cephadm install + args: + creates: /usr/sbin/cephadm + ignore_errors: yes + + - name: 验证cephadm + shell: cephadm version + register: cephadm_ver + changed_when: false + + - name: 显示版本 + debug: + msg: "{{ cephadm_ver.stdout }}" + +- name: Ceph集群 - 引导集群 + hosts: ceph_mon[0] + become: yes + vars: + cluster_network: "10.0.0.0/24" + public_network: "192.168.1.0/24" + mon_ip: "{{ ansible_host | default(ansible_default_ipv4.address) }}" + + tasks: + - name: 引导Ceph集群 + shell: | + cephadm bootstrap \ + --mon-ip {{ mon_ip }} \ + --cluster-network {{ cluster_network }} \ + --allow-overwrite + args: + creates: /etc/ceph/ceph.conf + register: bootstrap_result + ignore_errors: yes + + - name: 配置Dashboard + shell: | + ceph dashboard set-rgw-api-ssl-verify False + ceph mgr services + ignore_errors: yes + + - name: 获取Dashboard地址 + shell: ceph mgr services | grep dashboard + register: dashboard_url + changed_when: false + ignore_errors: yes + + - name: 显示集群信息 + debug: + msg: | + ═══════ Ceph集群引导完成 ═══════ + MON IP: {{ mon_ip }} + 集群网络: {{ cluster_network }} + 公共网络: {{ public_network }} + Dashboard: {{ dashboard_url.stdout | default('http://' + mon_ip + ':8443') }} + ═══════════════════════════════════ + +- name: Ceph集群 - 添加节点 + hosts: ceph_osd + become: yes + vars: + mon_host: "{{ groups['ceph_mon'][0] }}" + + tasks: + - name: 获取SSH公钥 + shell: cat /etc/ceph/ceph.pub + delegate_to: "{{ mon_host }}" + register: ceph_pub_key + changed_when: false + + - name: 分发SSH公钥 + authorized_key: + user: root + key: "{{ ceph_pub_key.stdout }}" + + - name: 添加节点到集群 + shell: ceph orch host add {{ inventory_hostname }} {{ ansible_host | default(inventory_hostname) }} + delegate_to: "{{ mon_host }}" + ignore_errors: yes + +- name: Ceph集群 - 部署OSD + hosts: ceph_mon[0] + become: yes + vars: + # OSD磁盘配置(根据实际修改) + osd_devices: + - /dev/sdb + - /dev/sdc + osd_all_available: false # 设为true则自动使用所有可用磁盘 + + tasks: + - name: 部署指定磁盘OSD + shell: ceph orch daemon add osd {{ item.split('/')[2] }}:{{ item }} + loop: "{{ osd_devices }}" + when: not osd_all_available + ignore_errors: yes + + - name: 部署所有可用磁盘OSD + shell: ceph orch apply osd --all-available-devices + when: osd_all_available + ignore_errors: yes + + - name: 等待OSD就绪 + shell: ceph osd stat + register: osd_stat + changed_when: false + retries: 10 + delay: 10 + until: osd_stat.rc == 0 + ignore_errors: yes + + - name: 显示OSD状态 + debug: + msg: "{{ osd_stat.stdout | default('等待OSD初始化') }}" + +- name: Ceph集群 - 部署MDS和RGW + hosts: ceph_mon[0] + become: yes + vars: + deploy_mds: true + deploy_rgw: true + mds_placement: "ceph_mds" + rgw_placement: "ceph_rgw" + + tasks: + - name: 部署MDS(CephFS元数据服务) + shell: ceph orch apply mds cephfs --placement="{{ mds_placement }}" + when: deploy_mds + ignore_errors: yes + + - name: 部署RGW(对象存储网关) + shell: ceph orch apply rgw ceph-rgw --placement="{{ rgw_placement }}" --port=8080 + when: deploy_rgw + ignore_errors: yes + + - name: 显示集群状态 + shell: ceph -s + register: ceph_status + changed_when: false + + - name: 最终报告 + debug: + msg: "{{ ceph_status.stdout_lines }}" +`, + }, + { + ID: "k8s-rook-ceph", Name: "K8S + Rook-Ceph存储", Category: "cluster", + Description: "在K8S集群上部署Rook-Ceph operator,提供持久化存储", + Icon: "💎", Tags: []string{"kubernetes", "rook", "ceph", "storage", "csi"}, + Content: `--- +# ============================================================ +# Rook-Ceph on Kubernetes +# 前提: K8S集群已部署完成 +# ============================================================ +- name: Rook-Ceph - 部署Operator + hosts: k8s_master[0] + become: yes + vars: + rook_version: "v1.13.3" + + tasks: + - name: 克隆Rook仓库 + git: + repo: https://github.com/rook/rook.git + dest: /tmp/rook + version: "{{ rook_version }}" + depth: 1 + ignore_errors: yes + + - name: 部署CRD和Operator + shell: | + cd /tmp/rook/deploy/examples + kubectl create -f crds.yaml -f common.yaml -f operator.yaml + ignore_errors: yes + + - name: 等待Operator就绪 + shell: kubectl -n rook-ceph get pod -l app=rook-ceph-operator -o jsonpath='{.items[0].status.phase}' + register: operator_status + retries: 30 + delay: 10 + until: operator_status.stdout == "Running" + ignore_errors: yes + + - name: 显示Operator状态 + debug: + msg: "Rook Operator: {{ operator_status.stdout | default('等待中') }}" + +- name: Rook-Ceph - 创建CephCluster + hosts: k8s_master[0] + become: yes + vars: + # 存储设备配置 + use_all_devices: false + devices: + - name: sdb + - name: sdc + # 或使用目录(测试环境) + use_directories: false + data_dir_host_path: /var/lib/rook + + tasks: + - name: 创建CephCluster + shell: | + cat <<'EOF' | kubectl apply -f - + apiVersion: ceph.rook.io/v1 + kind: CephCluster + metadata: + name: rook-ceph + namespace: rook-ceph + spec: + cephVersion: + image: quay.io/ceph/ceph:v18.2 + dataDirHostPath: {{ data_dir_host_path }} + mon: + count: 3 + allowMultiplePerNode: false + mgr: + count: 1 + dashboard: + enabled: true + ssl: false + storage: + useAllNodes: true + {% if use_all_devices %} + useAllDevices: true + {% elif devices | length > 0 %} + nodes: + - name: "*" + devices: + {% for d in devices %} + - name: "{{ d.name }}" + {% endfor %} + {% elif use_directories %} + directories: + - path: {{ data_dir_host_path }} + {% endif %} + EOF + ignore_errors: yes + + - name: 等待CephCluster就绪 + shell: kubectl -n rook-ceph get cephcluster -o jsonpath='{.items[0].status.phase}' + register: cluster_phase + retries: 60 + delay: 15 + until: cluster_phase.stdout == "Ready" + ignore_errors: yes + + - name: 显示集群状态 + shell: kubectl -n rook-ceph get cephcluster + register: cluster_status + changed_when: false + + - name: 报告 + debug: + msg: "{{ cluster_status.stdout_lines }}" + +- name: Rook-Ceph - 创建StorageClass + hosts: k8s_master[0] + become: yes + vars: + create_rbd_pool: true + create_cephfs_pool: true + rbd_pool_name: replicapool + rbd_pool_replicas: 3 + + tasks: + - name: 创建RBD StorageClass + shell: | + cat <<'EOF' | kubectl apply -f - + apiVersion: ceph.rook.io/v1 + kind: CephBlockPool + metadata: + name: {{ rbd_pool_name }} + namespace: rook-ceph + spec: + failureDomain: host + replicated: + size: {{ rbd_pool_replicas }} + --- + apiVersion: storage.k8s.io/v1 + kind: StorageClass + metadata: + name: rook-ceph-block + provisioner: rook-ceph.rbd.csi.ceph.com + parameters: + clusterID: rook-ceph + pool: {{ rbd_pool_name }} + imageFormat: "2" + imageFeatures: layering + csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner + csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph + csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node + csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph + reclaimPolicy: Delete + allowVolumeExpansion: true + EOF + when: create_rbd_pool + ignore_errors: yes + + - name: 创建CephFS StorageClass + shell: | + cat <<'EOF' | kubectl apply -f - + apiVersion: ceph.rook.io/v1 + kind: CephFilesystem + metadata: + name: ceph-filesystem + namespace: rook-ceph + spec: + metadataPool: + replicated: + size: 3 + dataPools: + - name: data0 + replicated: + size: 3 + metadataServer: + activeCount: 1 + activeStandby: true + --- + apiVersion: storage.k8s.io/v1 + kind: StorageClass + metadata: + name: rook-cephfs + provisioner: rook-ceph.cephfs.csi.ceph.com + parameters: + clusterID: rook-ceph + fsName: ceph-filesystem + pool: ceph-filesystem-data0 + csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner + csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph + csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node + csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph + reclaimPolicy: Delete + EOF + when: create_cephfs_pool + ignore_errors: yes + + - name: 设置默认StorageClass + shell: kubectl patch storageclass rook-ceph-block -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' + ignore_errors: yes + + - name: 显示StorageClass + shell: kubectl get sc + register: sc_list + changed_when: false + + - name: 最终报告 + debug: + msg: | + ═══════ Rook-Ceph 部署完成 ═══════ + {{ sc_list.stdout }} + ═══════════════════════════════════ +`, + }, + { + ID: "etcd-cluster", Name: "ETCD集群部署", Category: "cluster", + Description: "部署3/5节点ETCD集群,支持TLS加密和自动发现", + Icon: "🔐", Tags: []string{"etcd", "cluster", "kv", "consensus"}, + Content: `--- +# ============================================================ +# ETCD 集群部署 +# 使用方法: 在inventory中定义 etcd 组(3或5个节点) +# ============================================================ +- name: ETCD集群 - 安装部署 + hosts: etcd + become: yes + vars: + etcd_version: "3.5.12" + etcd_data_dir: /var/lib/etcd + etcd_initial_cluster_token: "etcd-cluster-prod" + # 节点间通信端口 + client_port: 2379 + peer_port: 2380 + # 是否启用TLS + enable_tls: false + + tasks: + - name: 创建etcd用户 + user: + name: etcd + system: yes + shell: /usr/sbin/nologin + create_home: no + + - name: 下载ETCD + get_url: + url: "https://github.com/etcd-io/etcd/releases/download/v{{ etcd_version }}/etcd-v{{ etcd_version }}-linux-amd64.tar.gz" + dest: /tmp/etcd.tar.gz + + - name: 解压安装 + unarchive: + src: /tmp/etcd.tar.gz + dest: /tmp + remote_src: yes + + - name: 安装二进制 + copy: + src: "/tmp/etcd-v{{ etcd_version }}-linux-amd64/{{ item }}" + dest: "/usr/local/bin/{{ item }}" + mode: '0755' + remote_src: yes + loop: [etcd, etcdctl] + + - name: 创建数据目录 + file: + path: "{{ etcd_data_dir }}" + state: directory + owner: etcd + group: etcd + mode: '0700' + + - name: 构建集群节点列表 + set_fact: + etcd_initial_cluster: "{{ groups['etcd'] | map('extract', hostvars, 'inventory_hostname') | zip(groups['etcd'] | map('extract', hostvars, ['ansible_host'])) | map('join', '=http://') | map('regex_replace', '^(.*)$', '\\1:' + (peer_port | string)) | join(',') }}" + + - name: 创建Systemd服务 + copy: + content: | + [Unit] + Description=ETCD Key-Value Store + After=network.target + + [Service] + Type=notify + User=etcd + ExecStart=/usr/local/bin/etcd \ + --name {{ inventory_hostname }} \ + --data-dir {{ etcd_data_dir }} \ + --listen-client-urls http://0.0.0.0:{{ client_port }} \ + --advertise-client-urls http://{{ ansible_host | default(inventory_hostname) }}:{{ client_port }} \ + --listen-peer-urls http://0.0.0.0:{{ peer_port }} \ + --initial-advertise-peer-urls http://{{ ansible_host | default(inventory_hostname) }}:{{ peer_port }} \ + --initial-cluster {{ etcd_initial_cluster }} \ + --initial-cluster-token {{ etcd_initial_cluster_token }} \ + --initial-cluster-state new + Restart=always + RestartSec=5 + LimitNOFILE=65536 + + [Install] + WantedBy=multi-user.target + dest: /etc/systemd/system/etcd.service + + - name: 启动ETCD + systemd: + name: etcd + state: started + enabled: yes + daemon_reload: yes + +- name: ETCD集群 - 验证 + hosts: etcd[0] + become: yes + vars: + client_port: 2379 + + tasks: + - name: 检查集群健康 + shell: etcdctl endpoint health --cluster + register: health + changed_when: false + ignore_errors: yes + + - name: 检查成员列表 + shell: etcdctl member list -w table + register: members + changed_when: false + ignore_errors: yes + + - name: 显示集群状态 + debug: + msg: | + ═══════ ETCD集群状态 ═══════ + 健康检查: {{ health.stdout | default('检查中...') }} + 成员列表: + {{ members.stdout | default('等待集群就绪') }} + ═══════════════════════════ +`, + }, + { + ID: "harbor-cluster", Name: "Harbor镜像仓库部署", Category: "cluster", + Description: "部署Harbor企业级容器镜像仓库,含HTTPS和持久化存储", + Icon: "⚓", Tags: []string{"harbor", "registry", "docker", "images"}, + Content: `--- +# ============================================================ +# Harbor 容器镜像仓库部署 +# ============================================================ +- name: Harbor - 安装部署 + hosts: "{{ target_hosts | default('harbor') }}" + become: yes + vars: + harbor_version: "2.10.0" + harbor_hostname: "harbor.example.com" + harbor_admin_password: "Harbor@12345" + harbor_data_dir: /data/harbor + # 协议: http 或 https + harbor_protocol: https + # HTTPS证书(自签名或已有证书) + ssl_cert: "" + ssl_cert_key: "" + + tasks: + - name: 安装Docker(如未安装) + shell: | + if ! command -v docker &>/dev/null; then + curl -fsSL https://get.docker.com | sh + systemctl enable docker && systemctl start docker + fi + ignore_errors: yes + + - name: 安装Docker Compose + shell: | + if ! command -v docker-compose &>/dev/null; then + curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose + fi + ignore_errors: yes + + - name: 创建数据目录 + file: + path: "{{ harbor_data_dir }}" + state: directory + mode: '0755' + + - name: 下载Harbor离线安装包 + get_url: + url: "https://github.com/goharbor/harbor/releases/download/v{{ harbor_version }}/harbor-offline-installer-v{{ harbor_version }}.tgz" + dest: /tmp/harbor.tgz + timeout: 300 + + - name: 解压安装包 + unarchive: + src: /tmp/harbor.tgz + dest: "{{ harbor_data_dir }}" + remote_src: yes + + - name: 生成自签名证书 + shell: | + mkdir -p /etc/harbor/ssl + openssl req -newkey rsa:4096 -nodes -sha256 \ + -keyout /etc/harbor/ssl/harbor.key \ + -x509 -days 3650 \ + -subj "/CN={{ harbor_hostname }}" \ + -addext "subjectAltName=DNS:{{ harbor_hostname }}" \ + -out /etc/harbor/ssl/harbor.crt + when: harbor_protocol == "https" and ssl_cert == "" + args: + creates: /etc/harbor/ssl/harbor.crt + + - name: 配置Harbor + shell: | + cd {{ harbor_data_dir }}/harbor + cp harbor.yml.tmpl harbor.yml + sed -i "s/^hostname: .*/hostname: {{ harbor_hostname }}/" harbor.yml + sed -i "s/^harbor_admin_password: .*/harbor_admin_password: {{ harbor_admin_password }}/" harbor.yml + sed -i "s|^data_volume: .*|data_volume: {{ harbor_data_dir }}/data|" harbor.yml + {% if harbor_protocol == "https" %} + sed -i "s|^ certificate: .*| certificate: {{ ssl_cert | default('/etc/harbor/ssl/harbor.crt') }}|" harbor.yml + sed -i "s|^ private_key: .*| private_key: {{ ssl_cert_key | default('/etc/harbor/ssl/harbor.key') }}|" harbor.yml + {% else %} + sed -i '/^https:/,/^[a-z]/{ /^https:/d; /^ port:/d; /^ certificate:/d; /^ private_key:/d }' harbor.yml + {% endif %} + + - name: 运行Harbor安装脚本 + shell: | + cd {{ harbor_data_dir }}/harbor + ./install.sh --with-trivy + register: harbor_install + ignore_errors: yes + + - name: 等待Harbor启动 + wait_for: + port: "{{ 443 if harbor_protocol == 'https' else 80 }}" + timeout: 120 + ignore_errors: yes + + - name: 显示部署信息 + debug: + msg: | + ═══════ Harbor 部署完成 ═══════ + 地址: {{ harbor_protocol }}://{{ harbor_hostname }} + 用户: admin + 密码: {{ harbor_admin_password }} + 数据目录: {{ harbor_data_dir }} + ═══════════════════════════════════ +`, + }, + { + ID: "nfs-cluster", Name: "NFS共享存储集群", Category: "cluster", + Description: "部署NFS服务端+客户端,配置共享存储和自动挂载", + Icon: "📂", Tags: []string{"nfs", "storage", "share", "mount"}, + Content: `--- +# ============================================================ +# NFS 共享存储部署 +# 使用方法: +# 1. 在inventory中定义 nfs_server 和 nfs_client 组 +# 2. 修改共享目录和客户端挂载配置 +# ============================================================ +- name: NFS - 服务端部署 + hosts: nfs_server + become: yes + vars: + # 共享目录配置 + nfs_exports: + - path: /data/nfs/share + clients: "192.168.1.0/24" + options: "rw,sync,no_root_squash,no_subtree_check" + - path: /data/nfs/backup + clients: "192.168.1.0/24" + options: "rw,sync,no_root_squash" + # NFS版本 + nfs_versions: "4.2,4.1,4,3" + + tasks: + - name: 安装NFS服务端 + package: + name: nfs-kernel-server + state: present + when: ansible_os_family == "Debian" + + - name: 安装NFS服务端(RedHat) + package: + name: nfs-utils + state: present + when: ansible_os_family == "RedHat" + + - name: 创建共享目录 + file: + path: "{{ item.path }}" + state: directory + mode: '0777' + loop: "{{ nfs_exports }}" + + - name: 配置exports + lineinfile: + path: /etc/exports + line: "{{ item.path }} {{ item.clients }}({{ item.options }})" + create: yes + loop: "{{ nfs_exports }}" + register: exports_config + + - name: 重启NFS服务 + service: + name: nfs-kernel-server + state: restarted + when: ansible_os_family == "Debian" and exports_config is changed + + - name: 重启NFS服务(RedHat) + service: + name: nfs-server + state: restarted + when: ansible_os_family == "RedHat" and exports_config is changed + + - name: 导出共享 + shell: exportfs -ra + changed_when: false + + - name: 验证导出 + shell: exportfs -v + register: export_list + changed_when: false + + - name: 显示共享信息 + debug: + msg: "{{ export_list.stdout_lines }}" + +- name: NFS - 客户端挂载 + hosts: nfs_client + become: yes + vars: + nfs_server_ip: "{{ hostvars[groups['nfs_server'][0]]['ansible_host'] | default(groups['nfs_server'][0]) }}" + # 客户端挂载配置 + nfs_mounts: + - server_path: "/data/nfs/share" + local_path: "/mnt/nfs/share" + options: "rw,soft,timeo=30" + - server_path: "/data/nfs/backup" + local_path: "/mnt/nfs/backup" + options: "rw,soft,timeo=30" + + tasks: + - name: 安装NFS客户端 + package: + name: nfs-common + state: present + when: ansible_os_family == "Debian" + + - name: 安装NFS客户端(RedHat) + package: + name: nfs-utils + state: present + when: ansible_os_family == "RedHat" + + - name: 创建挂载点 + file: + path: "{{ item.local_path }}" + state: directory + mode: '0755' + loop: "{{ nfs_mounts }}" + + - name: 挂载NFS共享 + mount: + path: "{{ item.local_path }}" + src: "{{ nfs_server_ip }}:{{ item.server_path }}" + fstype: nfs + opts: "{{ item.options }}" + state: mounted + loop: "{{ nfs_mounts }}" + + - name: 验证挂载 + shell: df -h | grep nfs + register: mount_check + changed_when: false + ignore_errors: yes + + - name: 显示挂载状态 + debug: + msg: "{{ mount_check.stdout_lines | default(['等待挂载']) }}" `, }, }