ansible
速成
yum install ansible -y # 安装
ssh-keygen -t rsa # 生成密钥
ssh-copy-id root@192.168.248.12 # 拷贝密钥
ansible all -m ping # 测试连通性
vi /etc/ansible/hosts # 编辑主机列表
[k8s-node]
192.168.248.12 ansible_ssh_user=root
192.168.248.13 ansible_ssh_user=root
ansible k8s-node -m copy -a "src=/etc/kubernetes/admin.conf dest=/etc/kubernetes/admin.conf mode=0644 owner=root group=root" # 拷贝文件
ansible k8s-node -m shell -a "kubectl get nodes" # 执行命令
Ansible目录结构
| 配置文件目录 | /etc/ansible/ |
| 配置文件目录 | /usr/bin/ |
| Lib库依赖目录 | /usr/lib/pythonX.X/site-packages/ansible/ |
| Help文档目录 | /usr/share/doc/ansible-X.X.X/ |
| Man文档目录 | /usr/share/man/man1/ |
Ansible Ad-Hoc命令集
命令
ansible all -m ping # 测试连通性
ansible-inventory --graph # 展示当前的 inventory(清单)结构
ansible nginx --list # 列出nginx组所有主机列表信息
ansible web_servers -m systemd -a 'name=nginx state=status' # 相当于执行systemctl status nginx
参数
❑-v, --verbose:输出更详细的执行过程信息,-vvv可得到执行过程所有信息。
❑-i PATH, --inventory=PATH:指定inventory信息,默认/etc/ansible/hosts。
❑-f NUM, --forks=NUM:并发线程数,默认5个线程。-->通过multiprocessing实现
❑--private-key=PRIVATE_KEY_FILE:指定密钥文件。
❑-m NAME, --module-name=NAME:指定执行使用的模块。
❑-M DIRECTORY, --module-path=DIRECTORY:指定模块存放路径,默认/usr/share/ansible,也可通过ANSIBLE_LIBRARY设定默认路径。
❑-a 'ARGUMENTS', --args='ARGUMENTS':模块参数。
❑-k, --ask-pass SSH:认证密码。
❑-K, --ask-sudo-pass sudo:用户的密码(--sudo时使用)。
❑-o, --one-line:标准输出至一行。
❑-s, --sudo:相当于Linux系统下的sudo命令
❑-t DIRECTORY, --tree=DIRECTORY:输出信息至DIRECTORY目录下,结果文件以远程主机名命名。
❑-T SECONDS, --timeout=SECONDS:指定连接远程主机的最大超时,单位是秒。
❑-B NUM, --background=NUM:后台执行命令,超NUM秒后中止正在执行的任务。
❑-P NUM, --poll=NUM:定期返回后台任务进度。
❑-u USERNAME, --user=USERNAME:指定远程主机以USERNAME运行命令。
❑-U SUDO_USERNAME, --sudo-user=SUDO_USERNAME:使用sudo,相当于Linux下的sudo命令。
❑-c CONNECTION, --connection=CONNECTION:指定连接方式,可用选项paramiko (SSH)、ssh、local, local方式常用于crontab和kickstarts。
❑-l SUBSET, --limit=SUBSET:指定运行主机。
❑-l ~REGEX, --limit=~REGEX:指定运行主机(正则)。
❑--list-hosts:列出符合条件的主机列表,不执行任何命令。
常用模块
- debug
debug 模块是 Ansible 内置的调试工具,用于:
- 输出变量值:通过
var参数直接打印变量内容。 - 自定义消息:通过
msg参数结合 Jinja2 模板输出格式化信息,例如:
debug:
msg: "当前主机名是 {{ ansible_hostname }}" # 使用 Jinja2 语法
- Shell--在远程主机上执行命令,支持 shell 特性(如管道、变量)。
- name: 执行带管道的命令
shell: cat /etc/passwd | grep root
- Copy-将文件从本地复制到远程主机。
- name: 复制文件
copy:
src: /local/path/file.txt
dest: /remote/path/file.txt
mode: '0644' # 设置权限
- File
- name: 创建目录
file:
path: /remote/dir
state: directory # 可选:file、directory、link、absent
mode: '0755'
- name: 删除文件
file:
path: /remote/file.txt
state: absent
- Template --使用 Jinja2 模板生成配置文件并复制到远程主机。
- name: 生成配置文件
template:
src: /local/template.j2
dest: /remote/config.conf
template.j2
server_name {{ ansible_hostname }};
port {{ port | default(80) }};
- yum/apt--包管理模块(
yum用于 RHEL/CentOS,apt用于 Debian/Ubuntu)。
- name: 安装Nginx
yum:
name: nginx
state: present # 可选:present、absent、latest
- Service --管理服务(启动、停止、重启等)。
- name: 启动并启用Nginx
service:
name: nginx
state: started
enabled: yes
- User--管理用户账号
- name: 创建用户
user:
name: john
state: present
password: "{{ 'password' | password_hash('sha512') }}"
groups: wheel
shell: /bin/bash
- Cron--管理 Cron 任务。
- name: 添加Cron任务
cron:
name: "每日备份"
minute: "0"
hour: "2"
job: "/usr/bin/backup.sh"
- uri和get_url
- name: 调用API
uri:
url: https://api.example.com/data
method: GET
return_content: yes
- name: Download Nginx source (idempotent)
get_url:
url: https://nginx.org/download/nginx-1.26.1.tar.gz
dest: /wise/nginx-1.26.1.tar.gz
mode: '0644'
checksum: "sha256:{{ lookup('url', 'https://nginx.org/download/nginx-1.26.1.tar.gz.sha256', wantlist=True)[0].split(' ')[0] }}" # 动态获取校验和
1.Ansible 先检查本地文件是否存在。
2.若存在,计算其 SHA256 值并与远程文件的校验和对比。
3,一致则跳过下载,不一致则重新下载。
- lineinfile--修改文件中的特定行
lineinfile 默认仅修改最后一个匹配行
- name: 修改配置文件
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
state: present
Ansible配置
公钥认证
ssh-keygen # 生成密钥对
ssh-copy-id root@192.168.137.30 # 传输公钥
配置主机清单
默认的主机清单文件路径:/etc/ansible/hosts[由 /etc/ansible/ansible.cfg 定义] 或 通过 -i 指定自定义文件
-
示例
[nginx] 192.168.248.10 ansible_user=root ansible_password=123456 192.168.248.20 ansible_user=root ansible_password=123456 ansible_python_interpreter=/usr/bin/python2.7
实战
下载安装包和编译环境
mkdir yaml
vi download.yaml
执行ansible-play download.yaml
- name: 下载基础安装包
- hosts: all
- tasks:
- name: 安装阿里云基础软件源
get_url:
url=http://mirrors.aliyun.com/repo/Centos-7.repo
dest=/etc/yum.repos.d/CentOS-Base.repo
mode=0644
- name: 创建源码目录
file:
path: /wise
state: directory
mode: '0755'
- name: 创建rpm目录
file:
path: /wise/rpm
state: directory
mode: '0755'
- name: 安装编译依赖
yum:
name:
- gcc-c++
- pcre
- pcre-devel
- zlib
- zlib-devel
- patch
- libffi-devel
- python-devel
- bzip2-devel
- openssl-devel
- ncurses-devel
- sqlite-devel
- readline-devel
- tk-devel
- gdbm-devel
- libpcap-devel
- xz-devel
- openssl
state: present
update_cache: true # 更新缓存
- name: 下载Nginx源码包
get_url:
url: https://nginx.org/download/nginx-1.26.1.tar.gz
dest: /wise/nginx-1.26.1.tar.gz
mode: '0644'
- name: 导入 Elasticsearch GPG 密钥
ansible.builtin.rpm_key: # 修正模块引用
key: https://artifacts.elastic.co/GPG-KEY-elasticsearch
state: present
- name: 创建 Elasticsearch yum 仓库配置文件
ansible.builtin.copy:
content: |
[elastic-8.x]
name=Elastic repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
dest: /etc/yum.repos.d/elasticsearch.repo
mode: '0644'
owner: root
group: root
- name: 下载Elasticsearch RPM包
get_url:
url: https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.13.4-x86_64.rpm
dest: /wise/rpm/elasticsearch-8.13.4-x86_64.rpm
mode: '0644'
checksum: sha512:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.13.4-x86_64.rpm.sha512
- name: 下载Kibana RPM包
get_url:
url: https://artifacts.elastic.co/downloads/kibana/kibana-8.13.4-x86_64.rpm
dest: /wise/rpm/kibana-8.13.4-x86_64.rpm
mode: '0644'
- name: 下载Filebeat RPM包
get_url:
url: "https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.13.4-x86_64.rpm"
dest: "/wise/rpm/filebeat-8.13.4-x86_64.rpm"
mode: '0644'
checksum: "sha512:{{ lookup('url', 'https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.13.4-x86_64.rpm.sha512', wantlist=True)[0].split(' ')[0] }}"
timeout: 300 # 5分钟超时,应对大文件下载
validate_certs: true # 验证HTTPS证书
安装Nginx
- name: Deploy Nginx
hosts: all
become: yes # 需要root权限
tasks:
- name: 解压Nginx源码包
unarchive:
src: /wise/nginx-1.26.1.tar.gz
dest: /wise
remote_src: yes
creates: /wise/nginx-1.26.1/configure
- name: 配置Nginx编译选项
shell: |
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_v2_module
args:
chdir: /wise/nginx-1.26.1
creates: /wise/nginx-1.26.1/Makefile
- name: 编译并安装Nginx
shell: make && make install
args:
chdir: /wise/nginx-1.26.1
creates: /usr/sbin/nginx
- name: 创建Nginx日志目录
file:
path: /var/log/nginx
state: directory
mode: '0755'
owner: root
group: root
- name: 创建Nginx网页根目录
file:
path: /usr/share/nginx/html
state: directory
mode: '0755'
owner: root
group: root
- name: 创建conf.d目录
file:
path: /etc/nginx/conf.d
state: directory
mode: '0755'
owner: root
group: root
- name: 创建默认首页
copy:
content: |
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Welcome to Nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
</body>
</html>
dest: /usr/share/nginx/html/index.html
mode: '0644'
owner: root
group: root
- name: 配置Nginx服务文件
copy:
content: |
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/nginx.service
mode: '0644'
owner: root
group: root
- name: 重载systemd服务
systemd:
daemon_reload: yes
- name: 写入默认的nginx配置
ansible.builtin.copy:
content: |
server {
listen 8080;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
add_header X-Received-XFF $http_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
dest: /etc/nginx/conf.d/default.conf
mode: '0644'
owner: root
group: root
- name: 写入nginx.conf
ansible.builtin.copy:
content: |
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}
dest: /etc/nginx/nginx.conf
mode: '0644'
owner: root
group: root
- name: 启动并启用Nginx服务
systemd:
name: nginx
state: started
enabled: yes
- name: 验证Nginx服务状态
command: systemctl is-active nginx
register: service_status
failed_when: "'active' not in service_status.stdout"
ansible all -m shell -a 'systemctl status nginx'
安装ES
---
- name: 安装配置 Elasticsearch 并创建 Ingest Pipeline
hosts: 192.168.137.30
become: yes
gather_facts: yes
vars:
es_host: "http://{{ ansible_default_ipv4.address }}:9200"
pipeline_name: "mynginx"
pipeline_definition:
description: "Wise Nginx Access Log"
processors:
- grok:
field: "message"
patterns:
- "%{IP:remote_addr} - %{DATA:remote_user} \\[%{HTTPDATE:time_local}\\] \"%{DATA:method} %{DATA:uri} %{DATA:server_protocol}\" %{NUMBER:status_code:long} %{NUMBER:response_bytes:long} \"%{DATA:referer}\" \"%{DATA:user_agent}\" \"%{DATA:x_forwarded_for}\""
- remove:
field: "message"
tasks:
- name: 安装 Elasticsearch RPM 包
yum:
name: /wise/rpm/elasticsearch-8.13.4-x86_64.rpm
state: present
- name: 备份原配置文件
copy:
src: /etc/elasticsearch/elasticsearch.yml
dest: /etc/elasticsearch/elasticsearch.yml.bak
remote_src: yes
mode: '0644'
ignore_errors: true # 首次安装可能不存在原文件
- name: 写入 Elasticsearch 配置
copy:
content: |
# ---------------------------------- Cluster -----------------------------------
cluster.name: Ansible_ES
# ----------------------------------- Paths ------------------------------------
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
# ---------------------------------- Network -----------------------------------
network.host: {{ ansible_default_ipv4.address }}
http.port: 9200
transport.port: 9300
# --------------------------------- Discovery ----------------------------------
cluster.initial_master_nodes: ["{{ ansible_default_ipv4.address }}"]
# --------------------------------------------------------------------------------
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
dest: /etc/elasticsearch/elasticsearch.yml
mode: '0644'
owner: root
group: elasticsearch
- name: 启动并启用 Elasticsearch 服务
systemd:
name: elasticsearch
state: started
enabled: yes
daemon_reload: yes
- name: 等待 Elasticsearch 服务就绪
wait_for:
host: "{{ ansible_default_ipv4.address }}"
port: 9200
timeout: 60
delay: 10
register: es_available
retries: 3
until: es_available is succeeded
- name: 创建 Ingest Pipeline
uri:
url: "{{ es_host }}/_ingest/pipeline/{{ pipeline_name }}"
method: PUT
body: "{{ pipeline_definition | to_json }}"
body_format: json
status_code: 200
headers:
Content-Type: "application/json"
register: pipeline_result
retries: 3
delay: 5
until: pipeline_result.status == 200
- name: 验证 Pipeline 创建结果
debug:
var: pipeline_result.json
安装kibana
---
- name: 配置 Kibana
hosts: 192.168.137.30
become: yes # 添加权限提升,因为需要root权限
tasks:
- name: 安装Kibana RPM包
yum:
name: /wise/rpm/kibana-8.13.4-x86_64.rpm
state: present
- name: 写入Kibana配置
ansible.builtin.copy:
content: |
server.port: 5601
server.host: {{ ansible_default_ipv4.address }}
elasticsearch.hosts: ["http://{{ ansible_default_ipv4.address }}:9200"]
i18n.locale: "zh-CN" # 添加这一行,设置为中文
dest: /etc/kibana/kibana.yml
mode: '0644'
- name: 启动并启用 kibana 服务
systemd:
name: kibana
state: started
enabled: yes
daemon_reload: yes
安装filebeat
---
- name: 配置 Filebeat
hosts: filebeat
tasks:
- name: 安装filebeat RPM包
yum:
name: /wise/rpm/filebeat-8.13.4-x86_64.rpm
state: present
- name: 写入 filebeat 配置
ansible.builtin.copy:
content: |
logging.level: info
# 配置日志输出格式(plain 或 json)
logging.to_files: true
logging.files:
path: /var/log/filebeat # 日志文件路径
name: filebeat # 日志文件名前缀
keepfiles: 7 # 保留的旧日志文件数量
permissions: 0644 # 日志文件权限
rotateeverybytes: 104857600 # 日志文件大小限制(100MB)
# 可选:启用 JSON 格式日志(便于机器解析)
logging.json: true
filebeat.inputs:
- type: log
id: nginx-access
paths:
- /var/log/nginx/access.log
fields_under_root: true
processors:
- drop_fields:
fields: ["agent.name", "agent.ephemeral_id", "agent.type", "agent.version", "log.offset", "agent.id"]
ignore_missing: true
output.elasticsearch:
hosts: ["192.168.137.30:9200"]
pipeline: "mynginx"
indices:
- index: "nginx-access"
dest: /etc/filebeat/filebeat.yml
mode: '0644'
owner: root
group: root
- name: 启动并启用 filebeat 服务
systemd:
name: filebeat
state: started
enabled: yes
daemon_reload: yes

工作实用
ansible -i host_sudo_list_x86 all -m shell "cp /etc/sudoers /root/sudoers.bak.20250808"
ansible -i host_sudo_list_x86 all -m copy "src=/data/tmp/sudo-1.8.23-10.tl2.3.1_x86_64.tar.gz dest=/tmp/sudo-1.8.23-10.tl2.3.1_x86_64.tar.gz"
ansible -i host_sudo_list_x86 all -m shell "cd /tmp/ && tar xvf sudo-1.8.23-10.tl2.3.1_x86_64.tar.gz"
ansible -i host_sudo_list_x86 all -m shell "rpm -Uvh sudo-1.8.23-10.tl2.3.1.x86_64.rpm"
踩坑
lineinfille和blockinfile
lineinfile
坑一:当使用 insertafter 或 insertbefore 时,如果没找到匹配行,会将新行添加到文件末尾
坑二:当使用 backrefs: yes 时,确实需要同时指定 regexp 参数
坑三:当同时使用 regexp 和 backrefs: yes 时,lineinfile 会执行替换操作而非插入操作;
backrefs: yes + regexp 的组合会触发替换行为
blockinfile
| 参数 | 是否必须 | 说明 |
|---|---|---|
path |
是 | 目标文件路径 |
block |
是 | 要插入/替换的文本块 |
marker |
否 | 标记文本,用于标识块边界 |
state |
否 | present(默认)或 absent(删除) |
insertafter |
否 | 在匹配行后插入 |
insertbefore |
否 | 在匹配行前插入 |
marker: "" 确保不会添加任何注释标记
blockinfile 模块的 insertafter 和 insertbefore 参数是互斥的,不能同时使用
配置实例
--- name: 测试
hosts: 192.168.137.30
tasks:
- name: 在文件末尾插入配置块
ansible.builtin.blockinfile:
path: /etc/elasticsearch/elasticsearch.yml
block: |
Ending
marker: ""
- name: 匹配替换测试 -->测试通过
ansible.builtin.lineinfile:
path: /etc/elasticsearch/elasticsearch.yml
regexp: '^cluster\.name' # 如果没有匹配行,不会替换
line: 'cluster.name: Test'
backrefs: yes # 确保只有匹配时才替换
- name: 不匹配不替换测试 -->测试通过
ansible.builtin.lineinfile:
path: /etc/elasticsearch/elasticsearch.yml
regexp: '^http\.ports' # 如果没有匹配行,不会替换
line: 'Error'
backrefs: yes # 确保只有匹配时才替换
- name: 匹配插入测试
ansible.builtin.blockinfile:
path: /etc/elasticsearch/elasticsearch.yml
block: |
node.name: ES30
insertafter: '^cluster\.name'
marker: ""
排障
现象:
执行
ansible 192.168.248.10 -m command -a "service ntpd status"
收到警告
[WARNING]: Consider using the service module rather than running 'service'. If you need to use
command because service is insufficient you can add 'warn: false' to this command task or set
'command_warnings=False' in ansible.cfg to get rid of this message.
原因:
1. 推荐使用 Ansible 专门的 service 模块来管理服务。
ansible 192.168.248.10 -m service -a "name=ntpd state=started"
2. 在 ansible.cfg 文件中关闭警告信息
[defaults]
command_warnings = False
现象:
Error reading config file (/etc/ansible/ansible.cfg): File contains no section headers.
原因:
配置文件可能类似这样(缺少 [defaults] 标题)

浙公网安备 33010602011771号