CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
DevOps 入门实战/课时/Ansible
RawBlame
课时目录12 节

DevOps 入门实战

  1. 01DevOps 入门
  2. 02操作系统
  3. 03Git 与 GitHub
  4. 04脚本语言
  5. 05网络协议
  6. 06Docker
  7. 07AWS
  8. 08Terraform
  9. 09Ansible
  10. 10GitHub Actions
  11. 11Nginx
  12. 12综合练习

Ansible

配置管理。

25 分钟

Ansible

这一课你将能做到

  1. 说清楚 Ansible 与 Terraform 的分工:一个管「建房」,一个管「装修」
  2. 编写 Inventory 和 Playbook,对多台服务器执行批量配置(装 JDK、起服务、改配置)
  3. 使用 ansible-vault 管理敏感变量(数据库密码、SSH 密钥)

为什么要学

你已经用 Terraform 创建好了 3 台服务器:一台跑 Nginx,一台跑 Spring Boot,一台跑 MySQL。接下来要在每台机器上装 JDK、配 Nginx、起 Java 进程、改防火墙。手动 SSH 上去一台台改?下次再来 10 台机器你怎么办?Ansible 解决的就是「在大量服务器上批量执行配置和命令」的问题。

人话:Terraform 是建筑师,负责「把房子盖好」(创建 EC2、VPC、子网);Ansible 是装修队,负责「把家具摆好、水电接通」(装 JDK、配 Nginx、起服务)。两者配合,环境才真正可用。

Ansible 最大的优势:无 Agent。你不需要在目标服务器上装任何客户端,只要目标机器开了 SSH,Ansible 就能通过 SSH 远程执行 Python 脚本完成任务。这是它和 Puppet/Chef/SaltStack 最大的区别。

先建立图像

┌─────────────────┐
│  控制节点 (你的电脑) │
│  ansible-playbook │
│  site.yml         │
└────────┬────────┘
         │ SSH (不需要目标机装 Agent)
    ┌────┴────┬────────┐
    ▼         ▼        ▼
┌───────┐ ┌───────┐ ┌───────┐
│ Web01 │ │ Web02 │ │  DB01 │   ← 目标机器
│ Nginx │ │ Java  │ │ MySQL │   只需要开了 SSH + Python
└───────┘ └───────┘ └───────┘

Inventory(主机清单):定义有哪些机器、怎么分组
Playbook(剧本):定义在哪些机器上、执行哪些任务

跟着做

步骤 1:安装 Ansible 并配置 Inventory

# macOS
brew install ansible

# Ubuntu
sudo apt install ansible

# 验证
ansible --version

创建项目目录并写 inventory.ini(主机清单):

[web]
web1 ansible_host=1.2.3.4 ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/myapp-key.pem
web2 ansible_host=1.2.3.5 ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/myapp-key.pem

[db]
db1 ansible_host=10.0.2.10 ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/myapp-key.pem

[all:vars]
ansible_python_interpreter=/usr/bin/python3

步骤 2:第一个 Playbook——给 Web 服务器装 JDK 和 Nginx

创建 site.yml:

---
- name: 配置 Web 服务器
  hosts: web
  become: yes          # 相当于 sudo
  vars:
    java_version: "17"
    app_dir: "/opt/myapp"

  tasks:
    - name: 安装 JDK 和 Nginx
      yum:
        name:
          - java-17-amazon-corretto-devel
          - nginx
        state: present

    - name: 创建应用目录
      file:
        path: "{{ app_dir }}"
        state: directory
        owner: ec2-user
        group: ec2-user
        mode: '0755'

    - name: 创建 appuser 用户
      user:
        name: appuser
        shell: /sbin/nologin
        system: yes

    - name: 配置 Nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: 重启 Nginx

    - name: 启动并启用 Nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: 重启 Nginx
      systemd:
        name: nginx
        state: restarted

步骤 3:运行 Playbook

# 检查语法
ansible-playbook -i inventory.ini site.yml --syntax-check

# 先跑一遍「干跑」(dry-run),看会发生什么变更
ansible-playbook -i inventory.ini site.yml --check

# 真正执行
ansible-playbook -i inventory.ini site.yml

--check 模式非常重要:它会显示哪些任务会改变系统,但不会真正执行。这是 Ansible 的「plan」。

步骤 4:部署 Spring Boot 应用(结合 systemd)

扩展 site.yml,添加部署任务:

    - name: 上传应用 JAR
      copy:
        src: ./target/myapp-1.0.0.jar
        dest: "{{ app_dir }}/app.jar"
        owner: appuser
        group: appuser

    - name: 配置 systemd 服务
      template:
        src: myapp.service.j2
        dest: /etc/systemd/system/myapp.service
      notify:
        - 重载 systemd
        - 重启 myapp

    - name: 启动应用
      systemd:
        name: myapp
        state: started
        enabled: yes

对应的 myapp.service.j2 模板:

[Unit]
Description=MyApp Spring Boot
After=network.target

[Service]
Type=simple
User=appuser
WorkingDirectory={{ app_dir }}
ExecStart=/usr/bin/java -jar {{ app_dir }}/app.jar --spring.profiles.active=prod
Restart=always
RestartSec=5
Environment="SPRING_DATASOURCE_PASSWORD={{ db_password }}"

[Install]
WantedBy=multi-user.target

步骤 5:用 ansible-vault 加密敏感变量

# 创建加密文件
ansible-vault create group_vars/all/vault.yml
# 输入密码,然后写入:
# vault_db_password: "Str0ng!Pass"

# 在普通变量文件里引用
cat > group_vars/all/vars.yml << 'EOF'
db_password: "{{ vault_db_password }}"
EOF

# 运行时需要密码
ansible-playbook -i inventory.ini site.yml --ask-vault-pass

# 或者把密码存在文件里(加进 .gitignore)
ansible-playbook -i inventory.ini site.yml --vault-password-file ~/.vault_pass.txt

步骤 6:常用 Ad-hoc 命令(不写 Playbook,直接批量执行)

# 检查所有 web 服务器是否存活
ansible web -i inventory.ini -m ping

# 在所有 web 服务器上查看磁盘
ansible web -i inventory.ini -m shell -a "df -h"

# 在 db 服务器上重启 MySQL
ansible db -i inventory.ini -m systemd -a "name=mysqld state=restarted" --become

讲清楚要点

  1. Ansible 是「推模式」:控制节点(你的电脑)通过 SSH 把任务推送到目标机器执行。不需要在目标机装 Agent,也不需要目标机有公网 IP(只要控制节点能 SSH 到它)。
  2. 幂等性:Ansible 的模块设计目标是「执行 N 次和执行 1 次结果一样」。state: present 表示「确保存在」,已存在就跳过,不存在才创建。这是和 Bash 脚本最大的区别——Bash 脚本重复执行会报错或产生副作用。
  3. Inventory 分组:[web]、[db] 是逻辑分组,Playbook 里 hosts: web 表示只在 web 组执行。组可以嵌套([production:children] web db)。
  4. Handler 用于触发重启:改配置文件后通常要重启服务,Handler 只在任务实际变更(changed)时触发,且无论有多少个任务 notify,Handler 只执行一次。
  5. 模板(Jinja2):配置文件的 IP、路径、密码不要写死,用 {{ variable }} 占位,不同环境(dev/prod)传不同变量。

你可能会懵的地方

  • Ansible 和 Shell 脚本有什么区别? Shell 脚本是命令式的(「执行 A 再执行 B」),重复执行会出问题;Ansible 是声明式的(「确保状态 X」),模块自动判断是否需要变更。另外 Ansible 有并行执行、错误处理、变量管理、加密等工程化能力,Shell 脚本没有。

  • Ansible 和 Terraform 到底怎么分工? Terraform 创建云资源(EC2、RDS、安全组、S3 Bucket),Ansible 配置这些资源(装软件、改配置文件、起服务)。边界:Terraform 管「资源存在」,Ansible 管「资源可用」。

  • Ansible 需要目标机器装 Python 吗? 是的,Ansible 通过 SSH 把 Python 脚本传到目标机器执行,所以目标机器需要 Python(大多数 Linux 发行版默认已装)。控制节点也需要 Python。

  • Ansible 能管 Windows 机器吗? 能,但要用 WinRM 协议而不是 SSH,模块也完全不同(win_* 系列)。本课程聚焦 Linux。

  • Playbook 执行到一半失败了怎么办? Ansible 默认会继续执行其他主机(因为各主机独立)。可以用 --start-at-task "任务名" 从失败处继续,或先 --check 模式预跑。修复后重新跑即可,幂等性保证已成功的任务不会重复执行。

错法对照

错法问题正解
敏感变量明文写在 Playbook泄露风险ansible-vault 加密,运行时输入密码
不用 Handler 直接 restart每次执行都重启,即使配置没变用 Handler 只在 changed 时触发
变量名冲突(vault_ 前缀)引用混乱vault_xxx 存加密值,xxx 引用它
Playbook 里写 IP 而不是变量换环境要改代码变量化,用 group_vars 管理
一次 Playbook 管所有服务器耦合太重,改一处全受影响拆分成 web.yml、db.yml,用 site.yml 汇总

卡点急救

  1. SSH 连接失败:ansible all -i inventory.ini -m ping -vvv 看详细错误。常见原因:密钥路径不对、安全组没放行 22、目标机 Python 不在 PATH(用 ansible_python_interpreter 指定)。
  2. Playbook 卡在 Gathering Facts:Ansible 默认先收集目标机信息(CPU、内存、OS),如果目标机很慢或网络差会卡。临时禁用:gather_facts: no。
  3. yum 安装报错 No package matching:Amazon Linux 的包名和 CentOS 不同。先 ansible web -m yum -a "list=java-17*" 查可用包名。

面试常问

  • Ansible 的优缺点? 优点:无 Agent、YAML 语法简单、幂等性好、社区模块丰富;缺点:大规模主机(几千台)性能不如 SaltStack,Windows 支持不如 Linux 成熟,复杂逻辑不如写 Python 脚本灵活。

  • Ansible 和 Puppet/Chef 的区别? Puppet/Chef 是「拉模式」:目标机装 Agent,定期向 Server 拉取配置。Ansible 是「推模式」:控制节点主动 SSH 推送。Ansible 更轻量、上手快,适合中小规模;Puppet/Chef 适合超大规模、需要持续合规检查的场景。

  • 如何测试 Ansible Playbook? ① --check 干跑模式;② --syntax-check 语法检查;③ 用 Molecule 框架做单元测试(在 Docker 容器里跑 Playbook 验证结果);④ 在 staging 环境先跑一遍再跑生产。

自测三问

  1. Ansible 的「幂等性」是什么意思?为什么它让批量运维更安全?
  2. 你写了一个 Playbook 给 100 台机器装 JDK,执行到第 50 台失败了,如何继续?
  3. 为什么 Handler 只在 changed 时触发?如果每次 Playbook 执行都重启 Nginx,会有什么后果?

小结一句话

Ansible 用 YAML 描述「目标状态」,通过 SSH 无 Agent 批量配置服务器,是「装修队」式的配置管理工具。

延伸

  • Ansible 官方文档
  • 下一课:GitHub Actions——把代码提交到 GitHub 自动触发构建和部署。
加载本节练习…
← 上一课Terraform下一课 →GitHub Actions