package services // PlaybookTemplate Playbook模板定义 type PlaybookTemplate struct { ID string `json:"id"` Name string `json:"name"` Category string `json:"category"` Description string `json:"description"` Icon string `json:"icon"` Content string `json:"content"` Tags []string `json:"tags"` } // TemplateCategory 模板分类 type TemplateCategory struct { ID string `json:"id"` Name string `json:"name"` Icon string `json:"icon"` Count int `json:"count"` } // GetTemplateCategories 获取所有模板分类 func GetTemplateCategories() []TemplateCategory { cats := map[string]TemplateCategory{} for _, t := range GetPlaybookTemplates() { c, ok := cats[t.Category] if !ok { c = TemplateCategory{ID: t.Category, Name: categoryNames[t.Category], Icon: categoryIcons[t.Category]} } c.Count++ cats[t.Category] = c } var result []TemplateCategory // 按固定顺序输出 order := []string{"system", "web", "database", "container", "cluster", "devops", "security", "monitoring"} for _, id := range order { if c, ok := cats[id]; ok { result = append(result, c) } } return result } var categoryNames = map[string]string{ "system": "系统管理", "web": "Web服务", "database": "数据库", "container": "容器化", "cluster": "集群部署", "devops": "DevOps", "security": "安全加固", "monitoring": "监控告警", } var categoryIcons = map[string]string{ "system": "🖥️", "web": "🌐", "database": "🗄️", "container": "🐳", "cluster": "☸️", "devops": "🔧", "security": "🔒", "monitoring": "📊", } // GetPlaybookTemplates 获取所有Playbook模板 func GetPlaybookTemplates() []PlaybookTemplate { return []PlaybookTemplate{ // ===== 系统管理 ===== { ID: "update-packages", Name: "系统包更新", Category: "system", Description: "自动更新系统软件包,支持Debian/RedHat系列", Icon: "📦", Tags: []string{"update", "apt", "yum"}, Content: `--- - name: 系统包更新 hosts: "{{ target_hosts | default('all') }}" become: yes vars: update_cache: yes upgrade_type: dist # dist(完整升级) 或 safe(安全升级) tasks: - name: 更新apt缓存 apt: update_cache: yes when: ansible_os_family == "Debian" - name: 升级所有包(Debian) apt: upgrade: "{{ upgrade_type }}" autoremove: yes autoclean: yes when: ansible_os_family == "Debian" - name: 更新yum缓存 yum: update_cache: yes when: ansible_os_family == "RedHat" - name: 升级所有包(RedHat) yum: name: "*" state: latest when: ansible_os_family == "RedHat" - name: 检查是否需要重启 stat: path: /var/run/reboot-required register: reboot_required when: ansible_os_family == "Debian" - name: 提示重启 debug: msg: "⚠️ 系统需要重启以完成更新" when: ansible_os_family == "Debian" and reboot_required.stat.exists `, }, { ID: "check-system", Name: "系统信息采集", Category: "system", Description: "采集操作系统、硬件、网络等详细信息", Icon: "🔍", Tags: []string{"info", "facts", "inventory"}, Content: `--- - name: 系统信息采集 hosts: "{{ target_hosts | default('all') }}" gather_facts: yes tasks: - name: 操作系统信息 debug: msg: | ══════════ 系统信息 ══════════ 主机名: {{ ansible_facts['hostname'] }} 系统: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }} 内核: {{ ansible_facts['kernel'] }} 架构: {{ ansible_facts['architecture'] }} CPU: {{ ansible_facts['processor_vcpus'] }} vCPUs 内存: {{ (ansible_facts['memtotal_mb'] / 1024) | round(2) }} GB IP: {{ ansible_facts['default_ipv4']['address'] | default('N/A') }} ═══════════════════════════════ - name: 磁盘使用 shell: df -h | grep -E '^/dev/' register: disk_info - name: 显示磁盘 debug: msg: "{{ disk_info.stdout_lines }}" - name: 运行时间 shell: uptime -p register: uptime_info - name: 显示运行时间 debug: msg: "运行时间: {{ uptime_info.stdout }}" `, }, { ID: "check-resources", Name: "资源监控检查", Category: "system", Description: "检查CPU/内存/磁盘使用率,超阈值告警", Icon: "📈", Tags: []string{"monitor", "cpu", "memory", "disk"}, Content: `--- - name: 资源监控检查 hosts: "{{ target_hosts | default('all') }}" gather_facts: yes vars: warn_threshold: 80 crit_threshold: 90 tasks: - name: 获取CPU使用率 shell: top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1 register: cpu_result changed_when: false - name: 获取内存使用率 shell: free | grep Mem | awk '{printf "%.0f", $3/$2*100}' register: mem_result changed_when: false - name: 获取磁盘使用率 shell: df -h / | tail -1 | awk '{print $5}' | tr -d '%' register: disk_result changed_when: false - name: 显示资源报告 debug: msg: | ═══════ {{ inventory_hostname }} 资源报告 ═══════ CPU 使用率: {{ cpu_result.stdout }}% 内存使用率: {{ mem_result.stdout }}% 磁盘使用率: {{ disk_result.stdout }}% 告警阈值: {{ warn_threshold }}% / 严重: {{ crit_threshold }}% ═══════════════════════════════════════ - name: 严重告警 fail: msg: "🚨 严重: {{ inventory_hostname }} 资源使用率超过 {{ crit_threshold }}%" when: > (cpu_result.stdout | int >= crit_threshold) or (mem_result.stdout | int >= crit_threshold) or (disk_result.stdout | int >= crit_threshold) `, }, { ID: "log-cleanup", Name: "日志清理", Category: "system", Description: "清理系统日志、临时文件,释放磁盘空间", Icon: "🧹", Tags: []string{"cleanup", "log", "disk"}, Content: `--- - name: 日志清理 hosts: "{{ target_hosts | default('all') }}" become: yes vars: log_retention_days: 30 tmp_retention_days: 7 tasks: - name: 清理journal日志 shell: journalctl --vacuum-time={{ log_retention_days }}d register: journal_result changed_when: "'Vacuuming' in journal_result.stdout" - name: 清理旧日志文件 find: paths: /var/log patterns: "*.gz,*.old,*.[0-9]" age: "{{ log_retention_days }}d" register: old_logs - name: 删除旧日志 file: path: "{{ item.path }}" state: absent loop: "{{ old_logs.files }}" - name: 清理临时文件 find: paths: /tmp age: "{{ tmp_retention_days }}d" register: tmp_files - name: 删除临时文件 file: path: "{{ item.path }}" state: absent loop: "{{ tmp_files.files }}" ignore_errors: yes - name: 清理apt缓存 apt: autoclean: yes when: ansible_os_family == "Debian" - name: 显示磁盘空间 shell: df -h / register: disk_after - name: 清理完成 debug: msg: "{{ disk_after.stdout_lines }}" `, }, { ID: "time-sync", Name: "时间同步(NTP)", Category: "system", Description: "配置NTP时间同步,确保集群时间一致", Icon: "⏰", Tags: []string{"ntp", "time", "chrony"}, Content: `--- - name: 时间同步配置 hosts: "{{ target_hosts | default('all') }}" become: yes vars: ntp_servers: - ntp.aliyun.com - ntp1.aliyun.com - pool.ntp.org tasks: - name: 安装chrony package: name: chrony state: present - name: 配置NTP服务器 lineinfile: path: /etc/chrony.conf regexp: "^server " line: "server {{ item }} iburst" create: yes loop: "{{ ntp_servers }}" - name: 启动chrony service: name: chronyd state: started enabled: yes - name: 验证时间同步 shell: chronyc tracking register: chrony_status changed_when: false - name: 显示同步状态 debug: msg: "{{ chrony_status.stdout_lines }}" `, }, // ===== Web服务 ===== { ID: "deploy-nginx", Name: "部署Nginx", Category: "web", Description: "安装配置Nginx,支持自定义站点和反向代理", Icon: "🌐", Tags: []string{"nginx", "web", "proxy"}, Content: `--- - name: 部署Nginx hosts: "{{ target_hosts | default('all') }}" become: yes vars: nginx_worker_processes: auto nginx_worker_connections: 1024 server_name: localhost listen_port: 80 proxy_pass: "" root_dir: /var/www/html tasks: - name: 安装Nginx package: name: nginx state: present - name: 创建网站目录 file: path: "{{ root_dir }}" state: directory owner: www-data group: www-data mode: '0755' when: ansible_os_family == "Debian" - name: 创建网站目录(RedHat) file: path: "{{ root_dir }}" state: directory owner: nginx group: nginx mode: '0755' when: ansible_os_family == "RedHat" - name: 部署默认页面 copy: content: | {{ server_name }}

Deployed by Ansible Deploy

Server: {{ inventory_hostname }}

dest: "{{ root_dir }}/index.html" when: proxy_pass == "" - name: 配置Nginx站点 copy: content: | server { listen {{ listen_port }}; server_name {{ server_name }}; {% if proxy_pass != "" %} location / { proxy_pass {{ proxy_pass }}; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } {% else %} root {{ root_dir }}; index index.html; location / { try_files $uri $uri/ =404; } {% endif %} } dest: /etc/nginx/conf.d/{{ server_name }}.conf notify: Reload Nginx - name: 启动Nginx service: name: nginx state: started enabled: yes handlers: - name: Reload Nginx service: name: nginx state: reloaded `, }, { ID: "deploy-apache", Name: "部署Apache", Category: "web", Description: "安装配置Apache HTTP Server", Icon: "🪶", Tags: []string{"apache", "httpd", "web"}, Content: `--- - name: 部署Apache hosts: "{{ target_hosts | default('all') }}" become: yes vars: server_name: localhost listen_port: 80 document_root: /var/www/html tasks: - name: 安装Apache(Debian) apt: name: apache2 state: present when: ansible_os_family == "Debian" - name: 安装Apache(RedHat) yum: name: httpd state: present when: ansible_os_family == "RedHat" - name: 创建网站目录 file: path: "{{ document_root }}" state: directory mode: '0755' - name: 部署测试页面 copy: content: "

Apache on {{ inventory_hostname }}

" dest: "{{ document_root }}/index.html" - name: 启动Apache(Debian) service: name: apache2 state: started enabled: yes when: ansible_os_family == "Debian" - name: 启动Apache(RedHat) service: name: httpd state: started enabled: yes when: ansible_os_family == "RedHat" `, }, // ===== 数据库 ===== { ID: "deploy-mysql", Name: "部署MySQL", Category: "database", Description: "安装MySQL/MariaDB,配置root密码和基础优化", Icon: "🐬", Tags: []string{"mysql", "mariadb", "database"}, Content: `--- - name: 部署MySQL hosts: "{{ target_hosts | default('all') }}" become: yes vars: mysql_root_password: "ChangeMe@2024" mysql_port: 3306 mysql_max_connections: 500 mysql_datadir: /var/lib/mysql tasks: - name: 安装MySQL(Debian) apt: name: - mysql-server - mysql-client - python3-pymysql state: present when: ansible_os_family == "Debian" - name: 安装MariaDB(RedHat) yum: name: - mariadb-server - mariadb - python3-PyMySQL state: present when: ansible_os_family == "RedHat" - name: 启动MySQL service: name: "{{ 'mysql' if ansible_os_family == 'Debian' else 'mariadb' }}" state: started enabled: yes - name: 设置root密码 shell: | mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mysql_root_password }}'; FLUSH PRIVILEGES;" ignore_errors: yes no_log: true - name: 优化配置 copy: content: | [mysqld] port = {{ mysql_port }} max_connections = {{ mysql_max_connections }} datadir = {{ mysql_datadir }} innodb_buffer_pool_size = 256M character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 2 dest: /etc/mysql/conf.d/optimize.cnf when: ansible_os_family == "Debian" notify: Restart MySQL - name: 验证MySQL shell: mysql -u root -p{{ mysql_root_password }} -e "SELECT VERSION();" register: mysql_version changed_when: false no_log: true - name: 显示版本 debug: msg: "MySQL版本: {{ mysql_version.stdout_lines[-1] | default('unknown') }}" handlers: - name: Restart MySQL service: name: "{{ 'mysql' if ansible_os_family == 'Debian' else 'mariadb' }}" state: restarted `, }, { ID: "deploy-redis", Name: "部署Redis", Category: "database", Description: "安装Redis,配置密码、内存限制和持久化", Icon: "🔴", Tags: []string{"redis", "cache", "database"}, Content: `--- - name: 部署Redis hosts: "{{ target_hosts | default('all') }}" become: yes vars: redis_port: 6379 redis_password: "ChangeMe@2024" redis_maxmemory: "512mb" redis_maxmemory_policy: allkeys-lru redis_bind: "0.0.0.0" tasks: - name: 安装Redis package: name: redis-server state: present when: ansible_os_family == "Debian" - name: 安装Redis(RedHat) yum: name: redis state: present when: ansible_os_family == "RedHat" - name: 配置Redis lineinfile: path: /etc/redis/redis.conf regexp: "{{ item.regexp }}" line: "{{ item.line }}" loop: - { regexp: '^bind ', line: 'bind {{ redis_bind }}' } - { regexp: '^port ', line: 'port {{ redis_port }}' } - { regexp: '^requirepass ', line: 'requirepass {{ redis_password }}' } - { regexp: '^maxmemory ', line: 'maxmemory {{ redis_maxmemory }}' } - { regexp: '^maxmemory-policy ', line: 'maxmemory-policy {{ redis_maxmemory_policy }}' } notify: Restart Redis - name: 启动Redis service: name: "{{ 'redis-server' if ansible_os_family == 'Debian' else 'redis' }}" state: started enabled: yes - name: 验证Redis shell: redis-cli -a {{ redis_password }} ping register: redis_ping changed_when: false no_log: true - name: 显示状态 debug: msg: "Redis状态: {{ redis_ping.stdout }}" handlers: - name: Restart Redis service: name: "{{ 'redis-server' if ansible_os_family == 'Debian' else 'redis' }}" state: restarted `, }, { ID: "deploy-postgresql", Name: "部署PostgreSQL", Category: "database", Description: "安装PostgreSQL,配置用户和基础优化", Icon: "🐘", Tags: []string{"postgresql", "postgres", "database"}, Content: `--- - name: 部署PostgreSQL hosts: "{{ target_hosts | default('all') }}" become: yes vars: postgres_version: "15" postgres_password: "ChangeMe@2024" postgres_port: 5432 postgres_max_connections: 200 tasks: - name: 安装PostgreSQL(Debian) apt: name: - postgresql - postgresql-contrib - python3-psycopg2 state: present when: ansible_os_family == "Debian" - name: 安装PostgreSQL(RedHat) yum: name: - postgresql-server - postgresql-contrib - python3-psycopg2 state: present when: ansible_os_family == "RedHat" - name: 初始化数据库(RedHat) shell: postgresql-setup --initdb when: ansible_os_family == "RedHat" ignore_errors: yes - name: 启动PostgreSQL service: name: postgresql state: started enabled: yes - name: 设置postgres密码 become_user: postgres shell: psql -c "ALTER USER postgres PASSWORD '{{ postgres_password }}';" no_log: true - name: 验证安装 become_user: postgres shell: psql -c "SELECT version();" register: pg_version changed_when: false - name: 显示版本 debug: msg: "{{ pg_version.stdout_lines[0] | default('PostgreSQL installed') }}" `, }, // ===== 容器化 ===== { ID: "deploy-docker", Name: "部署Docker", Category: "container", Description: "安装Docker CE + Docker Compose,配置镜像加速", Icon: "🐳", Tags: []string{"docker", "container", "compose"}, Content: `--- - name: 部署Docker hosts: "{{ target_hosts | default('all') }}" become: yes vars: docker_mirror: "https://mirror.ccs.tencentyun.com" docker_data_root: /var/lib/docker docker_log_max_size: "100m" docker_log_max_file: "3" tasks: - name: 安装依赖(Debian) apt: name: - apt-transport-https - ca-certificates - curl - gnupg - lsb-release state: present when: ansible_os_family == "Debian" - name: 添加Docker GPG密钥 shell: | curl -fsSL https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg when: ansible_os_family == "Debian" ignore_errors: yes - name: 添加Docker仓库 shell: | echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable" > /etc/apt/sources.list.d/docker.list when: ansible_os_family == "Debian" - name: 安装Docker(Debian) apt: name: - docker-ce - docker-ce-cli - containerd.io - docker-compose-plugin state: present update_cache: yes when: ansible_os_family == "Debian" - name: 安装Docker(RedHat) yum: name: - docker - docker-compose-plugin state: present when: ansible_os_family == "RedHat" - name: 配置Docker copy: content: | { "data-root": "{{ docker_data_root }}", "registry-mirrors": ["{{ docker_mirror }}"], "log-driver": "json-file", "log-opts": { "max-size": "{{ docker_log_max_size }}", "max-file": "{{ docker_log_max_file }}" }, "storage-driver": "overlay2", "live-restore": true } dest: /etc/docker/daemon.json notify: Restart Docker - name: 启动Docker service: name: docker state: started enabled: yes - name: 添加用户到docker组 user: name: "{{ ansible_user }}" groups: docker append: yes ignore_errors: yes - name: 验证Docker shell: docker version --format '{{.Server.Version}}' register: docker_ver changed_when: false - name: 显示版本 debug: msg: "Docker版本: {{ docker_ver.stdout }}" handlers: - name: Restart Docker service: name: docker state: restarted `, }, { ID: "deploy-portainer", Name: "部署Portainer", Category: "container", Description: "部署Portainer CE容器管理面板", Icon: "🎛️", Tags: []string{"portainer", "docker", "ui"}, Content: `--- - name: 部署Portainer hosts: "{{ target_hosts | default('all') }}" become: yes vars: portainer_port: 9443 portainer_data: /opt/portainer tasks: - name: 创建数据目录 file: path: "{{ portainer_data }}" state: directory - name: 拉取并启动Portainer shell: | docker volume create portainer_data docker run -d \ -p 8000:8000 \ -p {{ portainer_port }}:9443 \ --name portainer \ --restart=always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer-ce:latest register: portainer_result ignore_errors: yes - name: 显示访问地址 debug: msg: "Portainer已部署: https://{{ ansible_host | default(inventory_hostname) }}:{{ portainer_port }}" `, }, // ===== DevOps ===== { ID: "deploy-nodejs", Name: "部署Node.js", Category: "devops", Description: "安装Node.js + PM2进程管理器", Icon: "💚", Tags: []string{"nodejs", "npm", "pm2"}, Content: `--- - name: 部署Node.js hosts: "{{ target_hosts | default('all') }}" become: yes vars: node_version: "20" install_pm2: true tasks: - name: 安装NodeSource仓库 shell: | curl -fsSL https://deb.nodesource.com/setup_{{ node_version }}.x | bash - when: ansible_os_family == "Debian" - name: 安装Node.js(Debian) apt: name: nodejs state: present update_cache: yes when: ansible_os_family == "Debian" - name: 安装Node.js(RedHat) yum: name: nodejs state: present when: ansible_os_family == "RedHat" - name: 安装PM2 npm: name: pm2 global: yes when: install_pm2 - name: 设置PM2开机启动 shell: pm2 startup systemd -u {{ ansible_user }} --hp /home/{{ ansible_user }} when: install_pm2 ignore_errors: yes - name: 验证安装 shell: node --version && npm --version register: node_ver changed_when: false - name: 显示版本 debug: msg: "{{ node_ver.stdout_lines }}" `, }, { ID: "deploy-python-app", Name: "部署Python应用", Category: "devops", Description: "配置Python环境 + Gunicorn + Systemd服务", Icon: "🐍", Tags: []string{"python", "gunicorn", "flask", "django"}, Content: `--- - name: 部署Python应用 hosts: "{{ target_hosts | default('all') }}" become: yes vars: app_name: myapp app_dir: /opt/myapp python_version: python3 venv_dir: /opt/myapp/venv gunicorn_port: 8000 gunicorn_workers: 4 app_user: www-data tasks: - name: 安装Python和依赖 package: name: - "{{ python_version }}" - "{{ python_version }}-venv" - python3-pip state: present - name: 创建应用目录 file: path: "{{ app_dir }}" state: directory owner: "{{ app_user }}" mode: '0755' - name: 创建虚拟环境 shell: "{{ python_version }} -m venv {{ venv_dir }}" args: creates: "{{ venv_dir }}/bin/activate" - name: 安装Gunicorn pip: name: gunicorn virtualenv: "{{ venv_dir }}" - name: 创建Systemd服务 copy: content: | [Unit] Description={{ app_name }} Gunicorn Service After=network.target [Service] User={{ app_user }} WorkingDirectory={{ app_dir }} ExecStart={{ venv_dir }}/bin/gunicorn --workers {{ gunicorn_workers }} --bind 0.0.0.0:{{ gunicorn_port }} app:app Restart=always [Install] WantedBy=multi-user.target dest: /etc/systemd/system/{{ app_name }}.service notify: Restart App - name: 启动服务 systemd: name: "{{ app_name }}" state: started enabled: yes daemon_reload: yes handlers: - name: Restart App systemd: name: "{{ app_name }}" state: restarted daemon_reload: yes `, }, { ID: "backup-data", Name: "数据备份", Category: "devops", Description: "定时备份指定目录到本地或远程", Icon: "💾", Tags: []string{"backup", "cron", "archive"}, Content: `--- - name: 数据备份 hosts: "{{ target_hosts | default('all') }}" become: yes vars: backup_source: /data backup_dest: /backup backup_retention_days: 7 backup_hour: "2" backup_minute: "0" tasks: - name: 创建备份目录 file: path: "{{ backup_dest }}" state: directory mode: '0700' - name: 创建备份脚本 copy: content: | #!/bin/bash DATE=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="{{ backup_dest }}/backup_${DATE}.tar.gz" tar -czf "$BACKUP_FILE" {{ backup_source }} 2>/dev/null find {{ backup_dest }} -name "backup_*.tar.gz" -mtime +{{ backup_retention_days }} -delete echo "Backup completed: $BACKUP_FILE" dest: /usr/local/bin/backup.sh mode: '0755' - name: 配置定时任务 cron: name: "daily-backup" hour: "{{ backup_hour }}" minute: "{{ backup_minute }}" job: "/usr/local/bin/backup.sh >> /var/log/backup.log 2>&1" - name: 立即执行一次备份 shell: /usr/local/bin/backup.sh register: backup_result - name: 备份结果 debug: msg: "{{ backup_result.stdout }}" `, }, // ===== 安全加固 ===== { ID: "security-hardening", Name: "安全加固", Category: "security", Description: "SSH加固、防火墙配置、禁用root远程登录", Icon: "🔒", Tags: []string{"security", "ssh", "firewall", "hardening"}, Content: `--- - name: 安全加固 hosts: "{{ target_hosts | default('all') }}" become: yes vars: ssh_port: 22 disable_root_login: true enable_firewall: true allowed_ssh_users: [] tasks: - name: 修改SSH端口 lineinfile: path: /etc/ssh/sshd_config regexp: "^#?Port " line: "Port {{ ssh_port }}" notify: Restart SSH - name: 禁用root登录 lineinfile: path: /etc/ssh/sshd_config regexp: "^#?PermitRootLogin " line: "PermitRootLogin no" when: disable_root_login notify: Restart SSH - name: 禁用密码认证(仅密钥) lineinfile: path: /etc/ssh/sshd_config regexp: "^#?PasswordAuthentication " line: "PasswordAuthentication no" notify: Restart SSH - name: 设置SSH超时 lineinfile: path: /etc/ssh/sshd_config regexp: "^#?ClientAliveInterval " line: "ClientAliveInterval 300" notify: Restart SSH - name: 安装UFW(Debian) apt: name: ufw state: present when: ansible_os_family == "Debian" and enable_firewall - name: 配置UFW规则 shell: | ufw allow {{ ssh_port }}/tcp ufw allow 80/tcp ufw allow 443/tcp ufw --force enable when: ansible_os_family == "Debian" and enable_firewall - name: 安装fail2ban package: name: fail2ban state: present ignore_errors: yes - name: 启动fail2ban service: name: fail2ban state: started enabled: yes ignore_errors: yes - name: 加固完成 debug: msg: "✅ 安全加固完成 - SSH端口: {{ ssh_port }}, Root登录: {{ '禁用' if disable_root_login else '允许' }}" handlers: - name: Restart SSH service: name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}" state: restarted `, }, { ID: "ssl-cert", Name: "SSL证书部署", Category: "security", Description: "使用Certbot自动申请Let's Encrypt证书", Icon: "📜", Tags: []string{"ssl", "https", "certbot", "letsencrypt"}, Content: `--- - name: SSL证书部署 hosts: "{{ target_hosts | default('all') }}" become: yes vars: domain: example.com email: admin@example.com webroot: /var/www/html tasks: - name: 安装Certbot package: name: - certbot - python3-certbot-nginx state: present - name: 申请证书 shell: | certbot certonly --webroot -w {{ webroot }} \ -d {{ domain }} \ --email {{ email }} \ --agree-tos --non-interactive args: creates: /etc/letsencrypt/live/{{ domain }}/fullchain.pem - name: 配置自动续期 cron: name: "certbot-renew" hour: "3" minute: "30" job: "certbot renew --quiet --post-hook 'systemctl reload nginx'" - name: 证书信息 shell: openssl x509 -in /etc/letsencrypt/live/{{ domain }}/fullchain.pem -noout -dates register: cert_info changed_when: false ignore_errors: yes - name: 显示证书 debug: msg: "{{ cert_info.stdout_lines | default(['证书已申请']) }}" `, }, // ===== 监控告警 ===== { ID: "deploy-node-exporter", Name: "部署Node Exporter", Category: "monitoring", Description: "部署Prometheus Node Exporter采集主机指标", Icon: "📡", Tags: []string{"prometheus", "monitoring", "exporter"}, Content: `--- - name: 部署Node Exporter hosts: "{{ target_hosts | default('all') }}" become: yes vars: exporter_version: "1.7.0" exporter_port: 9100 tasks: - name: 创建用户 user: name: node_exporter system: yes shell: /usr/sbin/nologin create_home: no - name: 下载Node Exporter get_url: url: "https://github.com/prometheus/node_exporter/releases/download/v{{ exporter_version }}/node_exporter-{{ exporter_version }}.linux-amd64.tar.gz" dest: /tmp/node_exporter.tar.gz - name: 解压 unarchive: src: /tmp/node_exporter.tar.gz dest: /tmp remote_src: yes - name: 安装二进制 copy: src: "/tmp/node_exporter-{{ exporter_version }}.linux-amd64/node_exporter" dest: /usr/local/bin/node_exporter mode: '0755' remote_src: yes - name: 创建Systemd服务 copy: content: | [Unit] Description=Node Exporter After=network.target [Service] User=node_exporter ExecStart=/usr/local/bin/node_exporter --web.listen-address=:{{ exporter_port }} Restart=always [Install] WantedBy=multi-user.target dest: /etc/systemd/system/node_exporter.service - name: 启动服务 systemd: name: node_exporter state: started enabled: yes daemon_reload: yes - name: 验证 shell: curl -s http://localhost:{{ exporter_port }}/metrics | head -5 register: metrics changed_when: false - name: 显示状态 debug: msg: "Node Exporter运行在端口 {{ exporter_port }}" `, }, { ID: "deploy-grafana", Name: "部署Grafana", Category: "monitoring", Description: "部署Grafana可视化监控面板", Icon: "📊", Tags: []string{"grafana", "dashboard", "visualization"}, Content: `--- - name: 部署Grafana hosts: "{{ target_hosts | default('all') }}" become: yes vars: grafana_port: 3000 grafana_admin_password: "admin123" tasks: - name: 安装依赖 apt: name: - apt-transport-https - software-properties-common state: present when: ansible_os_family == "Debian" - name: 添加Grafana仓库 shell: | curl -fsSL https://apt.grafana.com/gpg.key | gpg --dearmor -o /usr/share/keyrings/grafana.gpg echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main" > /etc/apt/sources.list.d/grafana.list when: ansible_os_family == "Debian" - name: 安装Grafana apt: name: grafana state: present update_cache: yes when: ansible_os_family == "Debian" - name: 配置端口 lineinfile: path: /etc/grafana/grafana.ini regexp: "^;?http_port" line: "http_port = {{ grafana_port }}" - name: 启动Grafana service: name: grafana-server state: started enabled: yes - name: 显示访问信息 debug: msg: "Grafana: http://{{ ansible_host | default(inventory_hostname) }}:{{ grafana_port }} (admin/{{ grafana_admin_password }})" `, }, // ===== 系统管理(新增) ===== { ID: "host-connectivity", Name: "主机连通性测试", Category: "system", Description: "批量检测主机SSH连通性、DNS解析、端口可达性", Icon: "🔗", Tags: []string{"ping", "connectivity", "network", "check"}, Content: `--- - name: 主机连通性测试 hosts: "{{ target_hosts | default('all') }}" gather_facts: no tasks: - name: Ansible Ping 测试 ping: register: ping_result ignore_errors: yes - name: 检测SSH端口 wait_for: host: "{{ ansible_host | default(inventory_hostname) }}" port: "{{ ansible_port | default(22) }}" timeout: 5 delegate_to: localhost register: ssh_port ignore_errors: yes - name: 检测DNS解析 shell: nslookup {{ inventory_hostname }} 2>/dev/null || host {{ inventory_hostname }} 2>/dev/null || echo "DNS解析失败" delegate_to: localhost register: dns_result changed_when: false ignore_errors: yes - name: 检测常用端口 wait_for: host: "{{ ansible_host | default(inventory_hostname) }}" port: "{{ item }}" timeout: 3 delegate_to: localhost loop: [80, 443] register: port_scan ignore_errors: yes - name: 输出连通性报告 debug: msg: | ═══════ {{ inventory_hostname }} 连通性报告 ═══════ SSH Ping: {{ '✅ 成功' if ping_result is succeeded else '❌ 失败' }} SSH 端口: {{ '✅ 开放' if ssh_port is succeeded else '❌ 不可达' }} DNS 解析: {{ dns_result.stdout | default('N/A') }} HTTP(80): {{ '✅ 开放' if port_scan.results[0] is succeeded else '❌ 关闭' }} HTTPS(443): {{ '✅ 开放' if port_scan.results[1] is succeeded else '❌ 关闭' }} ═══════════════════════════════════════ `, }, { ID: "ubuntu-multi-ip", Name: "Ubuntu 22.04 多IP配置", Category: "system", Description: "通过Netplan为Ubuntu 22.04配置多IP地址(主IP+辅助IP)", Icon: "🌐", Tags: []string{"ubuntu", "netplan", "network", "multi-ip"}, Content: `--- - name: Ubuntu 22.04 多IP地址配置 hosts: "{{ target_hosts | default('all') }}" become: yes vars: # 主网卡名称(根据实际修改) primary_nic: ens192 # 主IP配置 primary_ip: "192.168.1.100/24" primary_gateway: "192.168.1.1" primary_dns: - 223.5.5.5 - 119.29.29.29 # 辅助IP列表(可添加多个) secondary_ips: - "192.168.1.101/24" - "10.0.0.100/16" tasks: - name: 确认系统版本 assert: that: - ansible_distribution == "Ubuntu" - ansible_distribution_version is version('22.04', '>=') fail_msg: "此模板仅适用于 Ubuntu 22.04+" success_msg: "系统版本: {{ ansible_distribution }} {{ ansible_distribution_version }}" - name: 备份现有Netplan配置 shell: | mkdir -p /etc/netplan/backup cp /etc/netplan/*.yaml /etc/netplan/backup/ 2>/dev/null || true args: creates: /etc/netplan/backup - name: 生成Netplan配置 copy: content: | network: version: 2 ethernets: {{ primary_nic }}: addresses: - {{ primary_ip }} {% for ip in secondary_ips %} - {{ ip }} {% endfor %} routes: - to: default via: {{ primary_gateway }} nameservers: addresses: {% for dns in primary_dns %} - {{ dns }} {% endfor %} dest: /etc/netplan/01-multi-ip.yaml mode: '0600' register: netplan_config - name: 验证Netplan配置语法 shell: netplan try --timeout=10 environment: NETPLAN_TRY_TIMEOUT: "10" ignore_errors: yes register: netplan_try - name: 应用Netplan配置 shell: netplan apply when: netplan_config is changed - name: 等待网络恢复 wait_for: host: "{{ primary_ip | ansible.utils.ipaddr('address') }}" port: 22 timeout: 30 delegate_to: localhost when: netplan_config is changed ignore_errors: yes - name: 验证IP配置 shell: ip addr show {{ primary_nic }} | grep "inet " register: ip_verify changed_when: false - name: 显示配置结果 debug: msg: | ═══════ 多IP配置完成 ═══════ 网卡: {{ primary_nic }} 主IP: {{ primary_ip }} 网关: {{ primary_gateway }} 辅助IP: {% for ip in secondary_ips %} - {{ ip }} {% endfor %} 当前IP列表: {{ ip_verify.stdout }} ═══════════════════════════ `, }, { ID: "ipmitool-bmc", Name: "IPMI配置BMC地址", Category: "system", Description: "使用ipmitool配置服务器BMC/IPMI管理口IP地址", Icon: "🔧", Tags: []string{"ipmi", "bmc", "ipmitool", "hardware"}, Content: `--- # ============================================================ # IPMI配置BMC地址 # 使用方法: # 在主机管理中为每台主机设置变量,例如: # bmc_ip=10.10.10.1 # bmc_netmask=255.255.255.0 # bmc_gateway=10.10.10.1 # bmc_user=admin # bmc_password=Admin@123 # 变量会写入inventory,本Playbook自动读取每台主机的值 # 未设置的主机将使用下方默认值 # ============================================================ - name: IPMI配置BMC地址 hosts: "{{ target_hosts | default('all') }}" become: yes vars: # 默认值(主机变量会覆盖这些) default_bmc_netmask: "255.255.255.0" default_bmc_gateway: "10.10.10.1" default_bmc_user: "admin" default_bmc_password: "Admin@123" bmc_channel: 1 # 是否启用DHCP(设为true则忽略静态IP配置) bmc_dhcp: false tasks: - name: 检查BMC变量 assert: that: - bmc_ip is defined fail_msg: "❌ 主机 {{ inventory_hostname }} 未配置 bmc_ip 变量,请在主机管理中设置" success_msg: "✅ {{ inventory_hostname }} → BMC IP: {{ bmc_ip }}" - name: 安装ipmitool package: name: ipmitool state: present - name: 加载IPMI内核模块 modprobe: name: "{{ item }}" state: present loop: - ipmi_devintf - ipmi_si ignore_errors: yes - name: 查看当前BMC配置 shell: ipmitool lan print {{ bmc_channel }} register: bmc_current changed_when: false ignore_errors: yes - name: 显示当前BMC信息 debug: msg: "{{ bmc_current.stdout_lines | default(['无法读取BMC信息']) }}" - name: 设置BMC为静态IP shell: ipmitool lan set {{ bmc_channel }} ipsrc static when: not bmc_dhcp - name: 配置BMC IP地址 shell: ipmitool lan set {{ bmc_channel }} ipaddr {{ bmc_ip }} when: not bmc_dhcp - name: 配置BMC子网掩码 shell: ipmitool lan set {{ bmc_channel }} netmask {{ bmc_netmask | default(default_bmc_netmask) }} when: not bmc_dhcp - name: 配置BMC默认网关 shell: ipmitool lan set {{ bmc_channel }} defgw ipaddr {{ bmc_gateway | default(default_bmc_gateway) }} when: not bmc_dhcp - name: 设置BMC为DHCP模式 shell: ipmitool lan set {{ bmc_channel }} ipsrc dhcp when: bmc_dhcp - name: 配置BMC用户密码 shell: | ipmitool user set name {{ bmc_channel }} 2 {{ bmc_user | default(default_bmc_user) }} 2>/dev/null || true ipmitool user set password 2 {{ bmc_password | default(default_bmc_password) }} ipmitool user enable 2 ipmitool channel setaccess {{ bmc_channel }} 2 privilege=4 no_log: true ignore_errors: yes - name: 验证BMC配置 shell: ipmitool lan print {{ bmc_channel }} register: bmc_verify changed_when: false - name: 显示最终配置 debug: msg: | ═══════ {{ inventory_hostname }} BMC配置完成 ═══════ 模式: {{ 'DHCP' if bmc_dhcp else '静态IP' }} IP: {{ bmc_ip }} 掩码: {{ bmc_netmask | default(default_bmc_netmask) }} 网关: {{ bmc_gateway | default(default_bmc_gateway) }} 用户: {{ bmc_user | default(default_bmc_user) }} ═══════════════════════════ {{ bmc_verify.stdout }} `, }, { ID: "apt-install", Name: "APT软件安装", Category: "system", Description: "通过apt批量安装/卸载软件包,支持指定版本和仓库", Icon: "📦", Tags: []string{"apt", "install", "package", "debian"}, Content: `--- - name: APT软件安装 hosts: "{{ target_hosts | default('all') }}" become: yes vars: # 要安装的软件包列表 packages_install: - vim - curl - wget - htop - net-tools - tree - unzip - git # 要卸载的软件包列表 packages_remove: [] # 是否更新缓存 update_cache: yes # 是否自动清理 autoremove: yes # 安装推荐包 install_recommends: no # 指定版本(可选,格式: "package=version") # 例: packages_install: ["nginx=1.18.0-0ubuntu1"] tasks: - name: 确认Debian系统 assert: that: ansible_os_family == "Debian" fail_msg: "此模板仅适用于 Debian/Ubuntu 系统" - name: 更新APT缓存 apt: update_cache: yes cache_valid_time: 3600 when: update_cache - name: 安装软件包 apt: name: "{{ packages_install }}" state: present install_recommends: "{{ install_recommends }}" register: install_result when: packages_install | length > 0 - name: 卸载软件包 apt: name: "{{ packages_remove }}" state: absent purge: yes when: packages_remove | length > 0 - name: 自动清理 apt: autoremove: yes autoclean: yes when: autoremove - name: 验证安装结果 shell: dpkg -l {{ packages_install | join(' ') }} 2>/dev/null | grep "^ii" | awk '{print $2, $3}' register: verify_result changed_when: false when: packages_install | length > 0 - name: 显示安装报告 debug: msg: | ═══════ APT安装报告 ═══════ 已安装: {{ packages_install | length }} 个包 已卸载: {{ packages_remove | length }} 个包 变更: {{ install_result.changed | default(false) }} {% if verify_result is defined and verify_result.stdout_lines is defined %} 已确认: {% for line in verify_result.stdout_lines %} ✓ {{ line }} {% endfor %} {% endif %} ═══════════════════════════ `, }, { ID: "dpkg-install", Name: "DPKG软件安装", Category: "system", Description: "通过dpkg安装本地.deb包,支持URL下载和依赖修复", Icon: "📥", Tags: []string{"dpkg", "deb", "install", "offline"}, Content: `--- - name: DPKG软件安装 hosts: "{{ target_hosts | default('all') }}" become: yes vars: # 本地deb包路径列表(服务器上的路径) local_deb_files: [] # 远程URL列表(会自动下载后安装) remote_deb_urls: [] # 下载临时目录 download_dir: /tmp/dpkg_install # 安装后是否修复依赖 fix_dependencies: yes # 是否保留下载的deb文件 keep_deb_files: no tasks: - name: 确认Debian系统 assert: that: ansible_os_family == "Debian" fail_msg: "此模板仅适用于 Debian/Ubuntu 系统" - name: 创建下载目录 file: path: "{{ download_dir }}" state: directory mode: '0755' when: remote_deb_urls | length > 0 - name: 下载远程deb包 get_url: url: "{{ item }}" dest: "{{ download_dir }}/{{ item | basename }}" mode: '0644' loop: "{{ remote_deb_urls }}" register: download_result when: remote_deb_urls | length > 0 - name: 安装本地deb包 apt: deb: "{{ item }}" state: present loop: "{{ local_deb_files }}" register: local_install when: local_deb_files | length > 0 - name: 安装下载的deb包 apt: deb: "{{ download_dir }}/{{ item | basename }}" state: present loop: "{{ remote_deb_urls }}" register: remote_install when: remote_deb_urls | length > 0 - name: 修复依赖关系 apt: update_cache: yes force_apt_get: yes shell: apt-get install -f -y when: fix_dependencies ignore_errors: yes - name: 清理下载文件 file: path: "{{ download_dir }}" state: absent when: not keep_deb_files and remote_deb_urls | length > 0 - name: 显示安装报告 debug: msg: | ═══════ DPKG安装报告 ═══════ 本地包: {{ local_deb_files | length }} 个 远程包: {{ remote_deb_urls | length }} 个 {% if local_deb_files | length > 0 %} 本地安装: {% for f in local_deb_files %} ✓ {{ f }} {% endfor %} {% endif %} {% if remote_deb_urls | length > 0 %} 远程安装: {% for u in remote_deb_urls %} ✓ {{ u | basename }} {% endfor %} {% 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(['等待挂载']) }}" `, }, } }