00:00:00
Ansible 简介
Ansible 是一款开源的自动化运维工具,具有以下特点:
- ✅ 无需代理:通过 SSH 连接,无需在目标主机安装客户端
- ✅ YAML 语法:易读易写的配置文件
- ✅ 幂等性:多次执行结果一致
- ✅ 丰富的模块:3000+ 内置模块
1. 安装与配置
1.1 安装 Ansible
bash
# Ubuntu/Debian
sudo apt update
sudo apt install ansible -y
# CentOS/RHEL
sudo yum install epel-release -y
sudo yum install ansible -y
# 使用 pip 安装(推荐)
pip3 install ansible
# 验证安装
ansible --version1.2 配置 SSH 免密登录
bash
# 生成 SSH 密钥对
ssh-keygen -t rsa -b 4096 -C "ansible@example.com"
# 复制公钥到目标主机
ssh-copy-id user@192.168.1.10
ssh-copy-id user@192.168.1.11
# 测试连接
ssh user@192.168.1.101.3 配置 Inventory(主机清单)
ini
# /etc/ansible/hosts
[web]
web1 ansible_host=192.168.1.10 ansible_user=ubuntu
web2 ansible_host=192.168.1.11 ansible_user=ubuntu
[db]
db1 ansible_host=192.168.1.20 ansible_user=ubuntu
db2 ansible_host=192.168.1.21 ansible_user=ubuntu
[all:vars]
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_python_interpreter=/usr/bin/python3YAML 格式:
yaml
# inventory.yml
all:
children:
web:
hosts:
web1:
ansible_host: 192.168.1.10
ansible_user: ubuntu
web2:
ansible_host: 192.168.1.11
ansible_user: ubuntu
db:
hosts:
db1:
ansible_host: 192.168.1.20
ansible_user: ubuntu2. 基础命令
2.1 Ad-Hoc 命令
bash
# 测试连通性
ansible all -m ping
# 执行命令
ansible web -m shell -a "uptime"
# 查看系统信息
ansible all -m setup
# 安装软件包
ansible web -m apt -a "name=nginx state=present" --become
# 重启服务
ansible web -m service -a "name=nginx state=restarted" --become
# 复制文件
ansible web -m copy -a "src=/tmp/test.txt dest=/tmp/test.txt"2.2 常用参数
| 参数 | 说明 |
|---|---|
-i | 指定 inventory 文件 |
-m | 指定模块 |
-a | 模块参数 |
--become | 使用 sudo 提权 |
-u | 指定用户 |
-f | 并发数 |
--check | 检查模式(不实际执行) |
3. Playbook 编写
3.1 基础 Playbook
yaml
# nginx_install.yml
---
- name: 安装和配置 Nginx
hosts: web
become: yes
tasks:
- name: 安装 Nginx
apt:
name: nginx
state: present
update_cache: yes
- name: 启动 Nginx
service:
name: nginx
state: started
enabled: yes
- name: 复制配置文件
copy:
src: ./nginx.conf
dest: /etc/nginx/nginx.conf
backup: yes
notify: reload nginx
handlers:
- name: reload nginx
service:
name: nginx
state: reloaded执行 Playbook:
bash
ansible-playbook nginx_install.yml
# 检查模式
ansible-playbook nginx_install.yml --check
# 详细输出
ansible-playbook nginx_install.yml -v3.2 变量使用
yaml
# lamp_stack.yml
---
- name: 部署 LAMP 环境
hosts: web
become: yes
vars:
packages:
- apache2
- mysql-server
- php
- php-mysql
apache_port: 80
tasks:
- name: 安装软件包
apt:
name: "{{ item }}"
state: present
loop: "{{ packages }}"
- name: 配置 Apache 端口
lineinfile:
path: /etc/apache2/ports.conf
regexp: '^Listen'
line: "Listen {{ apache_port }}"3.3 条件判断
yaml
---
- name: 根据操作系统安装软件
hosts: all
become: yes
tasks:
- name: 在 Ubuntu 上安装 Nginx
apt:
name: nginx
state: present
when: ansible_distribution == "Ubuntu"
- name: 在 CentOS 上安装 Nginx
yum:
name: nginx
state: present
when: ansible_distribution == "CentOS"3.4 循环
yaml
---
- name: 创建多个用户
hosts: all
become: yes
tasks:
- name: 创建用户
user:
name: "{{ item.name }}"
shell: "{{ item.shell }}"
groups: "{{ item.groups }}"
loop:
- { name: 'alice', shell: '/bin/bash', groups: 'sudo' }
- { name: 'bob', shell: '/bin/bash', groups: 'users' }
- { name: 'carol', shell: '/bin/zsh', groups: 'users' }4. 角色(Roles)
4.1 角色目录结构
roles/
└── nginx/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
├── files/
├── vars/
│ └── main.yml
├── defaults/
│ └── main.yml
└── meta/
└── main.yml4.2 创建角色
bash
# 创建角色目录结构
ansible-galaxy init nginxtasks/main.yml:
yaml
---
- name: 安装 Nginx
apt:
name: nginx
state: present
- name: 复制配置文件
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: reload nginx
- name: 启动 Nginx
service:
name: nginx
state: started
enabled: yeshandlers/main.yml:
yaml
---
- name: reload nginx
service:
name: nginx
state: reloadeddefaults/main.yml:
yaml
---
nginx_port: 80
nginx_user: www-datatemplates/nginx.conf.j2:
jinja2
user {{ nginx_user }};
worker_processes auto;
events {
worker_connections 1024;
}
http {
server {
listen {{ nginx_port }};
server_name _;
location / {
root /var/www/html;
index index.html;
}
}
}4.3 使用角色
yaml
# site.yml
---
- name: 配置 Web 服务器
hosts: web
become: yes
roles:
- nginx
- php
- mysql5. 实战案例
5.1 部署 Node.js 应用
yaml
# deploy_nodejs.yml
---
- name: 部署 Node.js 应用
hosts: app
become: yes
vars:
app_name: myapp
app_dir: /var/www/{{ app_name }}
node_version: "16.x"
app_port: 3000
tasks:
- name: 安装 Node.js
shell: |
curl -sL https://deb.nodesource.com/setup_{{ node_version }} | bash -
apt-get install -y nodejs
args:
creates: /usr/bin/node
- name: 创建应用目录
file:
path: "{{ app_dir }}"
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
- name: 复制应用代码
synchronize:
src: ./app/
dest: "{{ app_dir }}/"
delete: yes
- name: 安装依赖
npm:
path: "{{ app_dir }}"
state: present
- name: 创建 systemd 服务
template:
src: nodejs.service.j2
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: restartednodejs.service.j2:
ini
[Unit]
Description={{ app_name }} Node.js Application
After=network.target
[Service]
Type=simple
User={{ ansible_user }}
WorkingDirectory={{ app_dir }}
ExecStart=/usr/bin/node {{ app_dir }}/server.js
Restart=always
Environment=NODE_ENV=production
Environment=PORT={{ app_port }}
[Install]
WantedBy=multi-user.target5.2 批量配置服务器
yaml
# server_hardening.yml
---
- name: 服务器安全加固
hosts: all
become: yes
tasks:
# 更新系统
- name: 更新软件包
apt:
update_cache: yes
upgrade: dist
# 配置防火墙
- name: 安装 UFW
apt:
name: ufw
state: present
- name: 配置防火墙规则
ufw:
rule: allow
port: "{{ item }}"
loop:
- '22'
- '80'
- '443'
- name: 启用防火墙
ufw:
state: enabled
# SSH 安全配置
- name: 禁用密码登录
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
notify: restart ssh
- name: 禁用 root 登录
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
notify: restart ssh
# 配置时间同步
- name: 安装 chrony
apt:
name: chrony
state: present
- name: 启动 chrony
service:
name: chrony
state: started
enabled: yes
handlers:
- name: restart ssh
service:
name: ssh
state: restarted5.3 Docker 容器部署
yaml
# deploy_docker.yml
---
- name: 部署 Docker 容器
hosts: docker
become: yes
vars:
containers:
- name: nginx
image: nginx:latest
ports:
- "80:80"
- name: redis
image: redis:alpine
ports:
- "6379:6379"
tasks:
- name: 安装 Docker
apt:
name:
- docker.io
- python3-docker
state: present
- name: 启动 Docker 服务
service:
name: docker
state: started
enabled: yes
- name: 部署容器
docker_container:
name: "{{ item.name }}"
image: "{{ item.image }}"
ports: "{{ item.ports }}"
state: started
restart_policy: always
loop: "{{ containers }}"6. 常用模块
| 模块 | 用途 | 示例 |
|---|---|---|
ping | 测试连接 | ansible all -m ping |
shell | 执行命令 | shell: uptime |
copy | 复制文件 | copy: src=a dest=b |
template | 模板渲染 | template: src=x.j2 dest=/etc/x |
apt/yum | 包管理 | apt: name=nginx state=present |
service | 服务管理 | service: name=nginx state=started |
file | 文件操作 | file: path=/tmp state=directory |
user | 用户管理 | user: name=alice state=present |
lineinfile | 修改文件行 | lineinfile: path=/etc/hosts line='127.0.0.1 localhost' |
7. 最佳实践
7.1 使用 Ansible Vault 加密敏感信息
bash
# 创建加密文件
ansible-vault create secrets.yml
# 编辑加密文件
ansible-vault edit secrets.yml
# 执行时提供密码
ansible-playbook site.yml --ask-vault-pass7.2 使用标签
yaml
---
- name: 配置服务器
hosts: all
tasks:
- name: 安装软件
apt:
name: nginx
tags: install
- name: 配置服务
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags: configbash
# 只执行 install 标签的任务
ansible-playbook site.yml --tags install
# 跳过 config 标签
ansible-playbook site.yml --skip-tags config7.3 使用动态 Inventory
python
#!/usr/bin/env python3
# dynamic_inventory.py
import json
inventory = {
"web": {
"hosts": ["web1", "web2"],
"vars": {
"ansible_user": "ubuntu"
}
},
"_meta": {
"hostvars": {
"web1": {"ansible_host": "192.168.1.10"},
"web2": {"ansible_host": "192.168.1.11"}
}
}
}
print(json.dumps(inventory))bash
# 使用动态 Inventory
ansible-playbook -i dynamic_inventory.py site.yml8. 故障排查
bash
# 详细输出
ansible-playbook site.yml -vvv
# 语法检查
ansible-playbook site.yml --syntax-check
# 列出任务
ansible-playbook site.yml --list-tasks
# 列出主机
ansible-playbook site.yml --list-hosts
# 从指定任务开始
ansible-playbook site.yml --start-at-task="安装 Nginx"