Ansible 自动化运维入门指南
一、为什么选择 Ansible
1.1 自动化运维的痛点
在传统运维工作中,我们经常面临以下问题:
- 重复劳动:在多台服务器上执行相同的配置任务
- 人为错误:手动操作容易遗漏步骤或输入错误命令
- 效率低下:上百台服务器逐台操作耗时耗力
- 难以追溯:操作记录分散,故障复盘困难
- 环境不一致:不同服务器配置存在差异导致问题
1.2 Ansible 的优势
| 特性 |
说明 |
| 无代理架构 |
无需在目标机器安装客户端,SSH 即可 |
| 幂等性 |
多次执行结果一致,安全可重复 |
| 简单易学 |
YAML 语法,Playbook 可读性强 |
| 模块化 |
丰富的内置模块覆盖常见运维场景 |
| 生态完善 |
大量社区 Role,加速开发 |
二、基础概念
2.1 核心术语
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ┌─────────────────────────────────────────────────────────┐ │ Control Node (控制节点) │ │ - 安装 Ansible │ │ - 编写 Playbook │ │ - 执行任务 │ └────────────────────┬────────────────────────────────────┘ │ SSH ▼ ┌─────────────────────────────────────────────────────────┐ │ Managed Nodes (被管节点) │ │ - 无需安装 Ansible │ │ - 需要 Python 环境 │ │ - 接受 SSH 连接 │ └─────────────────────────────────────────────────────────┘
Inventory (清单) → 定义被管节点分组 Playbook (剧本) → 定义任务执行顺序 Module (模块) → 执行具体操作 Task (任务) → 调用模块完成单一操作 Role (角色) → 可复用的任务集合
|
2.2 目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ansible-project/ ├── ansible.cfg # 配置文件 ├── inventory/ # 主机清单 │ ├── production # 生产环境 │ └── staging # 测试环境 ├── playbooks/ # 剧本目录 │ ├── deploy.yml │ └── backup.yml ├── roles/ # 角色目录 │ ├── nginx/ │ ├── mysql/ │ └── common/ ├── group_vars/ # 组变量 │ ├── webservers.yml │ └── dbservers.yml ├── host_vars/ # 主机变量 │ └── web01.yml └── files/ # 静态文件 └── nginx.conf
|
三、快速开始
3.1 安装 Ansible
1 2 3 4 5 6 7 8 9 10 11 12
| apt update && apt install -y ansible
yum install -y epel-release yum install -y ansible
pip3 install ansible
ansible --version
|
3.2 配置 SSH 免密
1 2 3 4 5 6 7 8
| ssh-keygen -t ed25519 -C "ansible@control"
ssh-copy-id user@target-server
ssh user@target-server
|
3.3 创建 Inventory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
[webservers] web01.example.com ansible_user=deploy web02.example.com ansible_user=deploy
[dbservers] db01.example.com ansible_user=deploy db02.example.com ansible_user=deploy
[loadbalancers] lb01.example.com ansible_user=deploy
[all:vars] ansible_python_interpreter=/usr/bin/python3 ansible_ssh_common_args='-o StrictHostKeyChecking=no'
|
3.4 第一个 Playbook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| --- - name: Hello World Playbook hosts: all become: true gather_facts: true
tasks: - name: Print system information debug: msg: "Hostname: {{ ansible_hostname }}, OS: {{ ansible_distribution }}"
- name: Ensure NTP is installed apt: name: ntp state: present update_cache: yes
- name: Start NTP service service: name: ntp state: started enabled: yes
|
3.5 执行 Playbook
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ansible-playbook playbooks/hello.yml --syntax-check
ansible-playbook playbooks/hello.yml --check
ansible-playbook playbooks/hello.yml -i inventory/production
ansible-playbook playbooks/hello.yml -i inventory/production -l web01.example.com
ansible-playbook playbooks/hello.yml --tags "install"
|
四、常用模块详解
4.1 文件操作模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| - name: Copy configuration file copy: src: files/nginx.conf dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' backup: yes
- name: Generate config from template template: src: templates/app.conf.j2 dest: /etc/app/config.conf owner: app group: app mode: '0640'
- name: Create application directory file: path: /var/log/myapp state: directory owner: app group: app mode: '0755'
- name: Create symlink file: src: /opt/app/current dest: /opt/app/latest state: link
- name: Download package get_url: url: https://example.com/app.tar.gz dest: /tmp/app.tar.gz checksum: sha256:abc123...
|
4.2 包管理模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| - name: Install packages apt: name: - nginx - python3-pip - git state: present update_cache: yes
- name: Install packages yum: name: - httpd - mariadb-server state: latest
- name: Install Python packages pip: name: - requests - flask version: ">=2.0"
- name: Add repository apt_repository: repo: "ppa:nginx/stable" state: present
|
4.3 服务管理模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| - name: Manage services service: name: nginx state: restarted enabled: yes
- name: Configure systemd service systemd: name: myapp state: started enabled: yes daemon_reload: yes
|
4.4 用户与权限模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| - name: Create application user user: name: app group: app shell: /bin/bash home: /home/app create_home: yes system: yes
- name: Create group group: name: app state: present
- name: Add user to sudoers lineinfile: path: /etc/sudoers.d/app line: 'app ALL=(ALL) NOPASSWD: ALL' create: yes mode: '0440'
|
4.5 命令执行模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| - name: Check disk space command: df -h register: disk_info changed_when: false
- name: Get memory usage shell: free -m | grep Mem register: mem_info changed_when: false
- name: Restart if config changed service: name: nginx state: restarted when: nginx_config.changed
|
五、变量与模板
5.1 变量定义
1 2 3 4 5 6 7 8 9 10 11 12
| --- nginx_port: 80 nginx_worker_processes: 4 nginx_worker_connections: 1024 app_domain: "www.example.com" ssl_enabled: true
--- nginx_worker_processes: 8 server_role: "primary"
|
5.2 Jinja2 模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| # templates/nginx.conf.j2 worker_processes {{ nginx_worker_processes }};
events { worker_connections {{ nginx_worker_connections }}; }
http { server { listen {{ nginx_port }}; server_name {{ app_domain }};
{% if ssl_enabled %} listen 443 ssl; ssl_certificate /etc/ssl/certs/{{ app_domain }}.crt; ssl_certificate_key /etc/ssl/private/{{ app_domain }}.key; {% endif %}
location / { proxy_pass http://127.0.0.1:8080; } } }
|
5.3 变量优先级
1 2 3 4 5 6
| 1. 命令行变量 (-e "var=value") # 最高优先级 2. Playbook 中的 vars 3. host_vars/ 主机变量 4. group_vars/ 组变量 5. inventory 文件中定义 6. role defaults # 最低优先级
|
六、Roles 最佳实践
6.1 Role 结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| roles/ └── nginx/ ├── defaults/ │ └── main.yml # 默认变量 ├── vars/ │ └── main.yml # 角色变量 ├── tasks/ │ └── main.yml # 任务列表 ├── handlers/ │ └── main.yml # 处理器 ├── templates/ │ └── *.j2 # 模板文件 ├── files/ │ └── * # 静态文件 ├── meta/ │ └── main.yml # 角色元数据 └── tests/ └── test.yml # 测试用例
|
6.2 创建 Nginx Role
1 2 3 4 5 6 7
| --- nginx_version: "stable" nginx_port: 80 nginx_root: /var/www/html nginx_user: www-data nginx_ssl: false
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| --- - name: Install Nginx apt: name: nginx state: present update_cache: yes tags: install
- name: Create web root file: path: "{{ nginx_root }}" state: directory owner: "{{ nginx_user }}" group: "{{ nginx_user }}" mode: '0755' tags: config
- name: Deploy Nginx configuration template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' validate: 'nginx -t -c %s' notify: restart nginx tags: config
- name: Ensure Nginx is running service: name: nginx state: started enabled: yes tags: service
|
1 2 3 4 5 6
| --- - name: restart nginx service: name: nginx state: restarted
|
6.3 使用 Role
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| --- - name: Deploy Web Servers hosts: webservers become: true
roles: - common - nginx - app-deploy
tasks: - name: Custom task after roles debug: msg: "Deployment completed on {{ ansible_hostname }}"
|
七、实战案例
7.1 MySQL 主从复制部署
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| --- - name: Configure MySQL Master hosts: mysql_master become: true
vars: mysql_root_password: "{{ vault_mysql_root_password }}" replication_user: "repl" replication_password: "{{ vault_replication_password }}"
roles: - mysql
tasks: - name: Create replication user mysql_user: name: "{{ replication_user }}" host: "%" password: "{{ replication_password }}" priv: "*.*:REPLICATION SLAVE" state: present
- name: Get master status mysql_replication: mode: getmaster register: master_status
- name: Configure MySQL Slave hosts: mysql_slave become: true
vars: master_host: "{{ groups['mysql_master'][0] }}"
roles: - mysql
tasks: - name: Configure slave replication mysql_replication: mode: changeprimary primary_host: "{{ master_host }}" primary_user: repl primary_password: "{{ vault_replication_password }}" primary_log_file: "{{ hostvars[master_host]['master_status']['File'] }}" primary_log_pos: "{{ hostvars[master_host]['master_status']['Position'] }}"
- name: Start slave mysql_replication: mode: startslave
|
7.2 批量服务器安全加固
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| --- - name: Security Hardening hosts: all become: true gather_facts: true
tasks: - name: Disable root SSH login lineinfile: path: /etc/ssh/sshd_config regexp: "^PermitRootLogin" line: "PermitRootLogin no" notify: restart sshd
- name: Disable password authentication lineinfile: path: /etc/ssh/sshd_config regexp: "^PasswordAuthentication" line: "PasswordAuthentication no" notify: restart sshd
- name: Configure firewall ufw: rule: allow port: "{{ item }}" proto: tcp loop: - "22" - "80" - "443"
- name: Enable UFW ufw: state: enabled policy: deny
- name: Install security updates apt: upgrade: security update_cache: yes
- name: Configure fail2ban apt: name: fail2ban state: present
- name: Enable fail2ban service: name: fail2ban state: started enabled: yes
handlers: - name: restart sshd service: name: sshd state: restarted
|
7.3 应用部署流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| --- - name: Deploy Application hosts: webservers become: true serial: 1
vars: app_name: myapp app_version: "{{ lookup('env', 'APP_VERSION') | default('latest') }}" deploy_user: deploy
pre_tasks: - name: Disable load balancer command: /usr/bin/disable-in-lb {{ ansible_hostname }} delegate_to: localhost
tasks: - name: Pull latest code git: repo: "git@gitlab.com:company/{{ app_name }}.git" dest: "/opt/{{ app_name }}/repo" version: "{{ app_version }}" become_user: "{{ deploy_user }}"
- name: Install dependencies pip: requirements: "/opt/{{ app_name }}/repo/requirements.txt" virtualenv: "/opt/{{ app_name }}/venv" become_user: "{{ deploy_user }}"
- name: Run database migrations command: /opt/{{ app_name }}/venv/bin/python manage.py migrate become_user: "{{ deploy_user }}" environment: DJANGO_SETTINGS_MODULE: config.production
- name: Collect static files command: /opt/{{ app_name }}/venv/bin/python manage.py collectstatic --noinput become_user: "{{ deploy_user }}"
- name: Restart application systemd: name: "{{ app_name }}" state: restarted daemon_reload: yes
post_tasks: - name: Health check uri: url: "http://localhost:8080/health" status_code: 200 timeout: 30 register: health_check retries: 5 delay: 10 until: health_check.status == 200
- name: Enable load balancer command: /usr/bin/enable-in-lb {{ ansible_hostname }} delegate_to: localhost when: health_check.status == 200
|
八、Ansible Vault 密钥管理
8.1 创建加密文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ansible-vault create secrets.yml
ansible-vault encrypt secrets.yml
ansible-vault view secrets.yml
ansible-vault edit secrets.yml
ansible-vault decrypt secrets.yml
|
8.2 在 Playbook 中使用
1 2 3 4 5 6 7 8
| ansible-playbook deploy.yml --ask-vault-pass
ansible-playbook deploy.yml --vault-password-file ~/.vault_pass
ansible-playbook deploy.yml --vault-id dev@~/.vault_dev --vault-id prod@~/.vault_prod
|
1 2 3 4 5 6 7 8 9 10
| --- - hosts: all vars_files: - secrets.yml
tasks: - name: Use secret variable debug: msg: "DB Password is {{ db_password }}"
|
九、性能优化
9.1 并行控制
1 2 3 4 5 6 7 8 9 10 11 12 13
| [defaults]
forks = 20
timeout = 30
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
|
9.2 事实缓存
1 2 3 4 5 6 7 8 9 10 11
| [defaults] fact_caching = jsonfile fact_caching_connection = /tmp/ansible_facts fact_caching_timeout = 3600
- hosts: all gather_facts: no tasks: - ...
|
9.3 策略插件
1 2 3 4 5
| - hosts: all strategy: free tasks: - ...
|
十、调试与排错
10.1 调试技巧
1 2 3 4 5 6 7 8 9 10 11 12
| ansible-playbook deploy.yml -v ansible-playbook deploy.yml -vvv
ansible-playbook deploy.yml --start-at-task="Install Nginx"
ansible-playbook deploy.yml --list-tasks
ansible-playbook deploy.yml --list-hosts
|
10.2 常用调试模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| - name: Debug variable debug: var: my_variable
- name: Debug message debug: msg: "Current user: {{ ansible_user }}"
- name: Pause for debugging pause: prompt: "Check the server and press Enter to continue"
- name: Assert condition assert: that: - service_status.status == "running" fail_msg: "Service is not running!"
|
十一、总结
Ansible 是自动化运维的利器,掌握以下关键点:
- 理解幂等性 - 确保多次执行结果一致
- 合理使用 Roles - 提高代码复用性
- 变量管理 - 灵活运用不同层级的变量
- 密钥安全 - 使用 Vault 保护敏感信息
- 错误处理 - 添加适当的错误检查和回滚
学习路线建议:
- 基础:Ad-Hoc 命令 → 简单 Playbook
- 进阶:Variables → Templates → Roles
- 高级:Custom Modules → Plugins → Tower/AWX
参考资源: