Ansible 自动化运维入门:批量部署 Web 服务器实战
引言:为什么每个运维都应该掌握 Ansible
还记得那个凌晨3点被电话叫醒的夜晚吗?生产环境的20台服务器需要紧急更新配置,你不得不一台一台手动SSH登录,重复执行相同的命令。两个小时后,当你拖着疲惫的身躯完成任务时,心里暗暗发誓:"一定要找个自动化工具!"
如果你有过类似的经历,那么恭喜你,今天这篇文章将彻底改变你的运维生涯。我将带你从零开始掌握Ansible,通过一个实际的Web服务器批量部署项目,让你体验自动化运维的魅力。读完这篇文章,你将能够:
10分钟内完成50台服务器的Nginx部署
一键实现应用的滚动更新和回滚
构建可复用的自动化部署流程
将重复性工作时间缩短90%以上
一、Ansible 是什么?它能解决什么问题?
1.1 传统运维的痛点
在深入Ansible之前,让我们先看看传统运维面临的挑战:
场景一:配置漂移问题你管理着100台服务器,理论上它们的配置应该完全一致。但随着时间推移,因为各种临时修改、紧急补丁,服务器配置开始出现差异。某天一个看似简单的更新,却因为配置不一致导致部分服务器故障。
场景二:规模化挑战公司业务快速增长,服务器数量从10台增长到100台。原本30分钟能完成的部署任务,现在需要5个小时。而且随着操作复杂度增加,人为错误的概率也在上升。
场景三:知识传承困难资深运维离职了,留下的只有一堆零散的Shell脚本和简单的文档。新人接手后发现,每个脚本的执行顺序、参数含义都需要猜测和试错。
1.2 Ansible 的优势
Ansible 是一个开源的IT自动化工具,它通过简单的YAML语法描述系统配置,实现:
无代理架构(Agentless):不需要在被管理节点安装任何客户端,通过SSH即可管理
声明式配置:描述"想要达到的状态",而不是"如何达到"
幂等性保证:多次执行产生相同结果,避免重复操作带来的问题
易学易用:YAML语法简单直观,降低学习门槛
强大的模块库:3000+内置模块,覆盖各种运维场景
二、快速上手:15分钟搭建 Ansible 环境
2.1 环境准备
我们将搭建一个实验环境,包含1台控制节点和3台被管理节点:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line # 控制节点(安装Ansible的机器) control-node:192.168.1.10 # 被管理节点(目标服务器) web-01:192.168.1.11 web-02:192.168.1.12 web-03:192.168.1.13
2.2 安装 Ansible
在控制节点上执行:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line # CentOS/RHEL 系统 sudoyum install -y epel-release sudoyum install -y ansible # Ubuntu/Debian 系统 sudoapt update sudoapt install -y ansible # 使用 pip 安装(推荐,获取最新版本) sudopip3 install ansible # 验证安装 ansible--version
2.3 配置 SSH 免密登录
自动化的前提是控制节点能够无密码访问被管理节点:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line # 生成SSH密钥对(如果还没有) ssh-keygen -t rsa -b2048 # 将公钥复制到所有被管理节点 forip in192.168.1.11192.168.1.12192.168.1.13; do ssh-copy-id -i ~/.ssh/id_rsa.pub root@$ip done # 测试连接 sshroot@192.168.1.11'hostname'
2.4 创建 Inventory 文件
Inventory文件定义了Ansible要管理的主机清单:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line # 创建 inventory.ini 文件 [webservers] web-01 ansible_host=192.168.1.11 web-02 ansible_host=192.168.1.12 web-03 ansible_host=192.168.1.13 [webservers:vars] ansible_user=root ansible_python_interpreter=/usr/bin/python3 [all:vars] ansible_connection=ssh
测试连接所有主机:
ounter(line ansible -iinventory.iniall-m ping
如果看到所有主机返回 "pong",恭喜你,环境搭建成功!
三、实战项目:批量部署 Nginx Web 服务器
现在让我们通过一个实际项目,深入理解Ansible的强大功能。我们将实现:
批量安装Nginx
部署自定义配置
部署静态网站
实现滚动更新
3.1 项目结构设计
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line nginx-deployment/ ├── inventory.ini # 主机清单 ├── ansible.cfg # Ansible配置文件 ├── site.yml # 主Playbook ├── roles/ # 角色目录 │ └── nginx/ │ ├── tasks/ # 任务定义 │ │ └── main.yml │ ├── templates/ # 模板文件 │ │ ├── nginx.conf.j2 │ │ └── index.html.j2 │ ├── handlers/ # 触发器 │ │ └── main.yml │ └──vars/ # 变量定义 │ └── main.yml └── group_vars/ # 组变量 └── webservers.yml
3.2 编写 Playbook
创建主Playbooksite.yml:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line --- -name: Deploy Nginx Web Servers hosts: webservers become: yes gather_facts: yes vars: nginx_port:80 nginx_worker_processes:"{{ ansible_processor_vcpus }}" nginx_worker_connections:1024 website_title:"Ansible自动化部署演示" tasks: -name: 更新系统包缓存 apt: update_cache: yes when: ansible_os_family =="Debian" -name: 安装Nginx package: name: nginx state: present -name: 创建网站目录 file: path: /var/www/html state: directory mode:'0755' -name: 部署Nginx配置文件 template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf backup: yes notify: restart nginx -name: 部署网站首页 template: src: index.html.j2 dest: /var/www/html/index.html mode:'0644' -name: 确保Nginx服务运行 service: name: nginx state: started enabled: yes -name: 等待端口就绪 wait_for: port:"{{ nginx_port }}" host:"{{ ansible_default_ipv4.address }}" delay:5 timeout:30 handlers: -name: restart nginx service: name: nginx state: restarted
3.3 创建配置模板
创建templates/nginx.conf.j2:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line user www-data; worker_processes {{ nginx_worker_processes }}; pid /run/nginx.pid; events { worker_connections {{ nginx_worker_connections }}; multi_accept on; use epoll; } http { # 基础配置 sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # 日志配置 access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # Gzip压缩 gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript; # 虚拟主机配置 server { listen {{ nginx_port }} default_server; listen [::]:{{ nginx_port }} default_server; root /var/www/html; index index.html index.htm; server_name {{ ansible_hostname }}.example.com; location / { try_files$uri$uri/ =404; } # 健康检查端点 location /health { access_log off; return200"healthy "; add_header Content-Type text/plain; } } }
创建templates/index.html.j2:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line{{ website_title }} {{ website_title }}
恭喜!您已成功使用 Ansible 部署了这个页面
服务器名称:{{ ansible_hostname }}
IP地址:{{ ansible_default_ipv4.address }}
操作系统:{{ ansible_distribution }} {{ ansible_distribution_version }}
部署时间:{{ ansible_date_time.iso8601 }}
3.4 执行部署
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line # 语法检查 ansible-playbook -iinventory.inisite.yml--syntax-check # 模拟执行(Dry Run) ansible-playbook -iinventory.inisite.yml--check # 正式部署 ansible-playbook -iinventory.inisite.yml # 查看详细输出 ansible-playbook -iinventory.inisite.yml-vvv
四、进阶技巧:让你的自动化更强大
4.1 滚动更新策略
在生产环境中,我们需要确保服务的持续可用性。Ansible支持滚动更新:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line --- -name: 滚动更新Web服务器 hosts: webservers become: yes serial:1 # 每次更新1台服务器 max_fail_percentage:30 # 允许30%的失败率 pre_tasks: -name: 从负载均衡器移除 uri: url:"http://lb.example.com/api/remove" method: POST body_format: json body: server:"{{ ansible_hostname }}" delegate_to: localhost tasks: -name: 更新应用代码 git: repo:https://github.com/yourapp/webapp.git dest: /var/www/html version:"{{ app_version | default('master') }}" -name: 重启服务 service: name: nginx state: restarted post_tasks: -name: 健康检查 uri: url:"http://{{ ansible_default_ipv4.address }}/health" status_code:200 retries:5 delay:10 -name: 重新加入负载均衡器 uri: url:"http://lb.example.com/api/add" method: POST body_format: json body: server:"{{ ansible_hostname }}" delegate_to: localhost
4.2 使用 Ansible Vault 保护敏感信息
生产环境中,密码和密钥需要加密存储:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line # 创建加密文件 ansible-vault create secrets.yml # 编辑加密文件 ansible-vault edit secrets.yml # 在secrets.yml中添加: db_password:"SuperSecret123!" api_key:"sk-1234567890abcdef" # 使用加密变量运行playbook ansible-playbook -i inventory.ini site.yml --ask-vault-pass
4.3 动态 Inventory
当服务器数量众多或经常变化时,可以使用动态Inventory:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line #!/usr/bin/env python3 # dynamic_inventory.py importjson importboto3 defget_inventory(): ec2 = boto3.client('ec2', region_name='us-west-2') response = ec2.describe_instances( Filters=[ {'Name':'tag:Environment','Values': ['production']}, {'Name':'instance-state-name','Values': ['running']} ] ) inventory = { 'webservers': { 'hosts': [], 'vars': { 'ansible_user':'ubuntu', 'ansible_ssh_private_key_file':'~/.ssh/aws-key.pem' } } } forreservationinresponse['Reservations']: forinstanceinreservation['Instances']: inventory['webservers']['hosts'].append(instance['PublicIpAddress']) returninventory if__name__ =='__main__': print(json.dumps(get_inventory()))
4.4 性能优化技巧
当管理大规模基础设施时,性能优化至关重要:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line # ansible.cfg [defaults] host_key_checking = False gathering = smart fact_caching = jsonfile fact_caching_connection = /tmp/ansible_cache fact_caching_timeout = 86400 pipelining = True forks = 50 [ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=60s control_path = /tmp/ansible-%%h-%%p-%%r
五、实战案例:构建完整的 CI/CD 流程
让我们通过一个完整的案例,展示如何将Ansible集成到CI/CD流程中:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line --- # deploy_pipeline.yml -name: 完整的部署流程 hosts: webservers become: yes vars: app_name: mywebapp app_version:"{{ lookup('env', 'BUILD_NUMBER') | default('latest') }}" deploy_user: webapp deploy_dir: /opt/{{ app_name }} backup_dir: /opt/backups/{{ app_name }} tasks: -name: 创建部署用户 user: name:"{{ deploy_user }}" shell: /bin/bash groups: www-data append: yes -name: 创建必要的目录 file: path:"{{ item }}" state: directory owner:"{{ deploy_user }}" group:"{{ deploy_user }}" mode:'0755' loop: -"{{ deploy_dir }}" -"{{ backup_dir }}" - /var/log/{{ app_name }} -name: 备份当前版本 archive: path:"{{ deploy_dir }}" dest:"{{ backup_dir }}/backup-{{ ansible_date_time.epoch }}.tar.gz" when: deploy_dir is directory -name: 拉取最新代码 git: repo:"https://github.com/company/{{ app_name }}.git" dest:"{{ deploy_dir }}" version:"{{ app_version }}" force: yes become_user:"{{ deploy_user }}" -name: 安装应用依赖 pip: requirements:"{{ deploy_dir }}/requirements.txt" virtualenv:"{{ deploy_dir }}/venv" virtualenv_python: python3 become_user:"{{ deploy_user }}" -name: 运行数据库迁移 command: | {{ deploy_dir }}/venv/bin/python manage.py migrate args: chdir:"{{ deploy_dir }}" become_user:"{{ deploy_user }}" run_once:true -name: 收集静态文件 command: | {{ deploy_dir }}/venv/bin/python manage.py collectstatic --noinput args: chdir:"{{ deploy_dir }}" become_user:"{{ deploy_user }}" -name: 配置Systemd服务 template: src: app.service.j2 dest: /etc/systemd/system/{{ app_name }}.service notify: - reload systemd - restart app -name: 配置Nginx反向代理 template: src: nginx_app.conf.j2 dest: /etc/nginx/sites-available/{{ app_name }} notify: reload nginx -name: 启用站点 file: src: /etc/nginx/sites-available/{{ app_name }} dest: /etc/nginx/sites-enabled/{{ app_name }} state: link notify: reload nginx -name: 运行冒烟测试 uri: url:"http://localhost/api/health" status_code:200 retries:5 delay:10 handlers: -name: reload systemd systemd: daemon_reload: yes -name: restart app systemd: name:"{{ app_name }}" state: restarted enabled: yes -name: reload nginx service: name: nginx state: reloaded
六、监控与日志:确保自动化的可观测性
自动化不是"一劳永逸",我们需要持续监控:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line --- # monitoring.yml -name: 配置监控和日志收集 hosts: webservers become: yes tasks: -name: 安装监控代理 package: name: - prometheus-node-exporter - filebeat state: present -name: 配置Prometheus Node Exporter lineinfile: path: /etc/default/prometheus-node-exporter regexp:'^ARGS=' line:'ARGS="--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|run)($|/)"' notify: restart node-exporter -name: 配置Filebeat template: src: filebeat.yml.j2 dest: /etc/filebeat/filebeat.yml mode:'0600' notify: restart filebeat -name: 配置自定义指标收集脚本 copy: content: | #!/bin/bash # 收集应用自定义指标 echo"app_requests_total $(curl -s localhost/metrics | grep requests_total | awk '{print$2}')" echo"app_errors_total $(grep ERROR /var/log/{{ app_name }}/app.log | wc -l)" echo"app_response_time_seconds $(tail -n 100 /var/log/nginx/access.log | awk '{sum+=$10} END {print sum/NR}')" dest: /usr/local/bin/collect_metrics.sh mode:'0755' -name: 添加指标收集定时任务 cron: name:"收集应用指标" minute:"*/5" job:"/usr/local/bin/collect_metrics.sh > /var/lib/node_exporter/textfile_collector/app_metrics.prom" handlers: -name: restart node-exporter service: name: prometheus-node-exporter state: restarted -name: restart filebeat service: name: filebeat state: restarted
七、故障恢复:当事情出错时
即使是最完善的自动化,也可能出现问题。让我们准备一个快速回滚方案:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line --- # rollback.yml -name: 紧急回滚程序 hosts: webservers become: yes serial:1 vars_prompt: -name: confirm_rollback prompt:"确认要回滚到上一个版本吗?(yes/no)" private: no tasks: -name: 验证确认 fail: msg:"回滚操作已取消" when: confirm_rollback !="yes" -name: 查找最新的备份 find: paths:"{{ backup_dir }}" patterns:"backup-*.tar.gz" register: backup_files -name: 确保有可用备份 fail: msg:"没有找到可用的备份文件" when: backup_files.files | length ==0 -name: 获取最新备份 set_fact: latest_backup:"{{ (backup_files.files | sort(attribute='mtime') | last).path }}" -name: 停止应用服务 systemd: name:"{{ app_name }}" state: stopped -name: 清理当前版本 file: path:"{{ deploy_dir }}" state: absent -name: 恢复备份 unarchive: src:"{{ latest_backup }}" dest: /opt/ remote_src: yes -name: 启动应用服务 systemd: name:"{{ app_name }}" state: started -name: 验证服务状态 uri: url:"http://localhost/api/health" status_code:200 retries:3 delay:5 -name: 发送回滚通知 mail: to: ops-team@example.com subject:"紧急回滚完成 - {{ ansible_hostname }}" body:"服务器 {{ ansible_hostname }} 已成功回滚到备份版本:{{ latest_backup }}" delegate_to: localhost
总结:从手动到自动的蜕变
通过这篇文章,我们一起经历了从传统手动运维到Ansible自动化的完整旅程。让我们回顾一下关键收获:
效率提升:原本需要数小时的部署任务,现在只需要几分钟
一致性保证:通过代码化的配置管理,消除了环境差异
可追溯性:每次变更都有记录,便于审计和问题排查
知识沉淀:运维经验转化为可复用的Playbook
降低风险:自动化减少人为错误,回滚机制保障业务连续性
但这仅仅是开始。Ansible的生态系统远比我们今天探索的要丰富:
Ansible Tower/AWX 提供企业级的管理界面
Ansible Galaxy 社区分享了数千个现成的角色
与Kubernetes、Docker、云平台的深度集成
网络设备、数据库、中间件的自动化配置
下一步行动建议
立即实践:选择一个简单的重复性任务,尝试用Ansible自动化
逐步推广:从开发环境开始,逐步扩展到生产环境
持续学习:关注Ansible官方文档和社区最佳实践
分享交流:将你的自动化经验分享给团队,共同成长
记住,自动化不是目的,而是让我们能够专注于更有价值工作的手段。当你不再被重复性任务束缚,你就有更多时间去思考架构优化、性能调优、安全加固这些真正体现运维价值的工作。
如果这篇文章对你有帮助,欢迎关注我的技术博客,我会持续分享更多运维实战经验。下一篇,我们将探讨"Kubernetes + Ansible:打造云原生时代的自动化运维体系",敬请期待!
互动话题:你在实施自动化运维过程中遇到过哪些挑战?欢迎在评论区分享你的经验和困惑,让我们一起探讨解决方案。
-
Web
+关注
关注
2文章
1294浏览量
72158 -
服务器
+关注
关注
13文章
9916浏览量
88813 -
开源
+关注
关注
3文章
3820浏览量
44330
原文标题:Ansible 自动化运维入门:批量部署 Web 服务器实战
文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
宝界科技WEB服务器立体防御解决方案
宝界科技WEB服务器立体防御解决方案
使用IIS为Web内容配置Web服务器权限
基于Linux的WEB服务器的设计与实现

如何辨别Web服务器,应用程序服务器,HTTP服务器
云服务器如何部署web项目,一起来看看吧
利用Ansible批量100台服务器添加Crontab
Ansible代码上线项目实战案例
利用Ansible自动化部署Linux服务器
什么是服务器虚拟化?一文读懂原理、优势与实战部署

评论