ansible 主要的意义在于可以
- 提高运维工作效率,降低成本
- 提高准确度
离线安装
wget https://github.com/ansible/ansible/archive/refs/tags/v2.16.5.tar.gz
tar -zxvf v2.16.5.tar.gz
cd ansible-v2.16.5
python setup.py install
主要配置
- ansible.cfg : ansible执行需求的全局性、默认的配置文件
- hosts : 默认的主机资产清单文件
ansible.cfg
安装好ansible后会自动生成一个配置 /etc/ansible/ansible.cfg
按顺序寻找默认的配置文件:
- ANSIBLE_CONFIG
- ./ansible.cfg
- ~/ansible.cfg
- /etc/ansible/ansible.cfg
修改配置文件路径,可以此命令 export ANSIBLE_CONFIG=/root/test.cfg
可以通过version命令查看当前配置
╰─# ansible --version
ansible 2.9.27
config file = /etc/ansible/ansible.cfg # 默认配置文件路径
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Nov 14 2023, 16:14:06) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
常用配置项含义
1)inventory
该参数表示资源清单inventory文件的位置,资源清单就是一些Ansible需要连接管理的主机列表
inventory = /root/ansible/hosts
2)library
Ansible的操作动作,无论是本地或远程,都使用一小段代码来执行,这小段代码称为模块,这个library参数就是指向存放Ansible模块的目录
library = /usr/share/ansible
3)forks
设置默认情况下Ansible最多能有多少个进程同时工作,默认设置最多5个进程并行处理。具体需要设置多少个,可以根据控制主机的性能和被管理节点的数量来确定。
forks = 5
4)sudo_user
这是设置默认执行命令的用户,也可以在playbook中重新设置这个参数
sudo_user = root
//注意:新版本已经作了修改,如ansible2.4.1下已经为:
default_sudo_user = root
5)remote_port
这是指定连接被关节点的管理端口,默认是22,除非设置了特殊的SSH端口,不然这个参数一般是不需要修改的
remote_port = 22
6)host_key_checking
这是设置是否检查SSH主机的密钥。指纹校验报错,可以设置为False
host_key_checking = False
7)timeout
这是设置SSH连接的超时间隔,单位是秒。
timeout = 20
8)log_path
Ansible系统默认是不记录日志的,如果想把Ansible系统的输出记录到日志文件中,需要设置log_path来指定一个存储Ansible日志的文件
log_path = /var/log/ansible.log
另外需要注意,执行Ansible的用户需要有写入日志的权限,模块将会调用被管节点的syslog来记录,口令是不会出现的日志中的
9)private_key_file
在使用ssh公钥私钥登录系统时候,使用的密钥路径。
private_key_file=/path/to/file.pem
inventory 资产清单文件
默认资产文件路径在 /etc/ansible/hosts
[group1]
test1 ansible_ssh_host=192.168.1.1
192.168.1.2 ansible_ssh_port=22 ansible_password="123"
配置变量等方式
[web:vars]
ansible_port=22
ansible_password='1111'
[web]
172.38.80.[211:214]
[backup]
172.38.80.211 ansible_port=22 ansible_password='1111'
[group02:children]
web
backup
使用 ansible-vault 加密保护敏感变量
首先,您必须为ansible-vault本身创建一个密码。它被用作加密密钥,有了它,你可以在你的Ansible项目中加密几十个不同的密码。当你运行你的剧本时,你可以用一个密码(ansible-vault密码)访问所有这些秘密(加密值)。官网有一个简单的例子,可以参考。
创建一个文件,并将ansible-vault的密码写入其中:
echo "Your own password" > ~/my-ansible-vault-pw-file
生成加密后的密码
ansible-vault encrypt_string --vault-id my_user@~/my-ansible-vault-pw-file 'Your_SSH_password' --name 'ansible_password'
启动时指定密码文件
# ad-hoc
ansible all -i inventory.yml --vault-id root@~/my-ansible-vault-pw-file -m yum -a "name=docker-ce state=removed"
# playbook
ansible-playbook -i inventory --vault-id my_user@~/my-ansible-vault-pw-file first_playbook.yml
命令模式 ad-hoc
命令语法
ansible <host-pattern> [option]
host-pattern例如
ansible all -m shell -a "hostname"
ansible '192.168.1.*' -a "ls /tmp"
ansible group1 -a "ls /tmp"
ansible test1 -a "ls /tmp"
option:
- -v, --verbose:输出更详细的执行过程信息,-vvv可得到所有执行过程信息。
- -i PATH, --inventory=PATH:指定inventory信息,默认/etc/ansible/hosts。
- -f NUM, --forks=NUM:并发线程数,默认5个线程。
- --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秒后kill正在执行的任务。
- -P NUM, --poll=NUM:定期返回后台任务进度。
- -u USERNAME, --user=USERNAME:指定远程主机以USERNAME运行命令。
- -U SUDO_USERNAME, --sudo-user=SUDO_USERNAM:E使用sudo,相当于Linux下的sudo命令。
- -c CONNECTION, --connection=CONNECTION:指定连接方式,可用选项paramiko (SSH), ssh, local。Local方式常用于crontab 和 kickstarts。
- -l SUBSET, --limit=SUBSET:指定运行主机。
- -l ~REGEX, --limit=~REGEX:指定运行主机(正则)。
- --list-hosts:列出符合条件的主机列表,不执行任何其他命令
帮助命令
ansible-doc --help
ansible-doc -l
ansible-doc -s ping
ansible的状态,就是用如下颜色区分,可以看到不同的状态
- 绿色:命令以用户期望的执行了,但是状态没有发生改变;
- 黄色:命令以用户期望的执行了,并且状态发生了改变;
- 紫色:警告信息,说明ansible提示你有更合适的用法;
- 红色:命令错误,执行失败;
- 蓝色:详细的执行过程;
常用模块
参考:Ansible 学习总结(6)------ Ansible 19个常用模块使用示例
command 模块 默认模块
ansible webservers -a "/sbin/reboot" -f 10
与shell模块的区别是不支持特殊字符,只适用简单命令
shell 模块 在目标上执行shell命令
ansible中提供状态功能,如果想用到此功能,就必须是用它提供的特定模块,不能统统使用shell命令。可以通过使用 ansible-doc -l | grep xxx 来搜索模块
ansible test_group -m shell -a "echo $HOSTNAME" -f 5
copy 模块 将文件复制到远程位置
# 拷贝本机/etc/hosts文件到目标机器的/tmp中
ansible all -m copy -a "src=/etc/hosts dest=/tmp"
-f 5 # 并发5
-l 192.168.1.101 # 指定某主机
安装 Red Hat Ansible Automation Platform_哔哩哔哩_bilibili
setup 模块 搜集系统信息
# 搜集主机的所有系统信息
ansible test_group -m setup
# 过滤信息为ansible_distribution开头的信息
ansible all -m setup -a "filter=ansible_distribution*"
# 收集网卡信息
ansible all -m setup -a 'filter=ansible_eth[0-2]'
# 收集内存信息
ansible all -m setup -a "filter=ansible_*_mb"
# 搜集系统信息并以主机名为文件名分别保存在 /tmp/facts 目录
ansible 192.168.31.39 -m setup --tree /tmp/facts
大概内容如下:
hhhh01 | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "CentOS",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Core",
"ansible_distribution_version": "7.9",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
hhh02 | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "CentOS",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Core",
"ansible_distribution_version": "7.9",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
yum 模块 管理软件包
此模块只在CentOS下可用,Ubuntu系统需要使用apt模块
ansible all -m yum -a "name=telnet state=present"
- name 包名
- autoremove
- 默认为false,如果是 true ,则从系统中删除所有最初作为用户安装的软件包的依赖项安装但不再需要的"leaf"软件包。应单独使用 或在 state 为 absent 时使用
- 注意:此功能需要yum >= 3.4.3(RHEL/CentOS 7+)
- state
- present 如果安装了则不更新,如果没安装则安装
- installed 将简单地确保安装所需的软件包
- latest 如果安装则更新,没安装则安装最新
- removed 删除
- absent 删除
- 默认值为 None ,但实际上默认操作为 present ,除非为此模块启用了 autoremove 选项,则默认为 absent 。
yum 模块会记录执行的状态,第一次执行,装完之后,的确对目标机器产生了修改的状态,会给master-61返回一个命令的执行结果,执行状态,存储下来。ansible会检测目标机器,对比这个状态,如果状态没变,ansible就不会再执行该命令。因此效率很高
service 模块 服务管理
此模块用于启动服务
# 启动nginx服务
ansible all -m service -a "name=nginx state=started"
git 模块 GIT模块
此模块用于拉取git仓库上的代码,首先机器需要安装GIT客户端。
# 拉取最新代码
ansible all -m git -a "repo=https://github.com/ansible/awx.git version=HEAD"
user 模块 用户和组管理
-
comment # 用户的描述信息
-
createhome # 是否创建家目录
-
force # 在使用
state=absent'时, 行为与
userdel --force'一致. -
group # 指定基本组
-
groups # 指定附加组,如果指定为('groups=')表示删除所有组
-
home # 指定用户家目录
-
login_class # 可以设置用户的登录类 FreeBSD, OpenBSD and NetBSD系统.
-
move_home # 如果设置为`home='时, 试图将用户主目录移动到指定的目录
-
name= # 指定用户名
-
non_unique # 该选项允许改变非唯一的用户ID值
-
password # 指定用户密码
-
remove # 在使用
state=absent'时, 行为是与
userdel --remove'一致. -
shell # 指定默认shell
-
state #设置帐号状态,不指定为创建,指定值为absent表示删除
-
system # 当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户。
-
uid #指定用户的uid
-
update_password # 更新用户密码
添加用户 foo,指定密码,设置家目录,不允许远程登录
ansible all -m user -a "name=foo password=123456 home=/home/foo shell=/sbin/nologin"
彻底删除一个用户,包括家目录
ansible all -m user -a "name=foo remove=yes state=absent"
后台运行
ansible test -B 3500 -a "/usr/bin/running_operation --do-stuff"
Ansible Collection针对POSIX和POSIX平台。
PlayBooks剧本
剧本模式的一些官方示例
playbook的组成
- play: 定义的是主机的角色
- task: 定义的是具体执行的任务
- playbook: 由一个或多个play组成,一个play可以包含多个task
playbook的优势
- 功能比adhoc全
- 控制好依赖
- 展现更直观
- 持久使用
执行结果返回:
- 红色:表示有taak执行失败或者提醒的信息
- 黄色:表示执行了且改变了远程主机状态
- 绿色:表示执行成功
执行启动剧本命令
ansible-playbook playbook.yml [options]
option:
- -u REMOTE_USER, --user=REMOTE_USER # ssh 连接的用户名
- -k, --ask-pass #ssh登录认证密码
- -s, --sudo #sudo 到root用户,相当于Linux系统下的sudo命令
- -U SUDO_USER, --sudo-user=SUDO_USER #sudo 到对应的用户
- -K, --ask-sudo-pass #用户的密码(---sudo时使用)
- -T TIMEOUT, --timeout=TIMEOUT # ssh 连接超时,默认 10 秒
- -C, --check # 指定该参数后,执行 playbook 文件不会真正去执行,而是模拟执行一遍,然后输出本次执行会对远程主机造成的修改
- -e EXTRA_VARS, --extra-vars=EXTRA_VARS # 设置额外的变量如:key=value 形式 或者 YAML or JSON,以空格分隔变量,或用多个-e
- -f FORKS, --forks=FORKS # 进程并发处理,默认 5
- -i INVENTORY, --inventory-file=INVENTORY # 指定 hosts 文件路径,默认 default=/etc/ansible/hosts
- -l SUBSET, --limit=SUBSET # 指定一个 pattern,对hosts匹配到的主机再过滤一次
- --list-hosts # 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook
- --list-tasks # 列出该 playbook 中会被执行的 task
- --private-key=PRIVATE_KEY_FILE # 私钥路径
- --step # 同一时间只执行一个 task,每个 task 执行前都会提示确认一遍
- --syntax-check # 只检测 playbook 文件语法是否有问题,不会执行该 playbook
- -t TAGS, --tags=TAGS #当 play 和 task 的 tag 为该参数指定的值时才执行,多个 tag 以逗号分隔
- --skip-tags=SKIP_TAGS # 当 play 和 task 的 tag 不匹配该参数指定的值时,才执行
- -v, --verbose #输出更详细的执行过程信息,-vvv可得到所有执行过程信息。
剧本内部yaml语法
大小写敏感
用缩进表示层级关系,而且只能用空格不能用tab
以---作为文档开始
支持的数据结构
变量的引用:
myname: jeson
name: "{{ myname }}"
变量
变量定义
使用 --extra-vars 执行参数赋给变量
ansible-playbook ./xxx.yml --extra-vars "touch_file=jeson2"
在资产清单文件中定义变量
[test_group]
192.168.1.1
[test_group:vars]
touch_file=jeson3
yaml文件中定义变量赋值
---
- hosts: test1
remote_user: root
vars:
touch_file: jeson1
tasks:
- name: touch file
shell: "touch /tmp/{{ touch_file }}
注册变量
register 关键字可以存储指定命令的输出结果到一个自定义的变量中
- name: get time
command: date
register: date_output
- name: echo date_output
shell: "echo {{date_output.stdout}} > /tmp/xxx"
全局变量文件
- hosts: web
# 变量文件
vars_files: ./var.yml
tasks:
- name: print var
debug:
# 在变量开头时要加引号
msg: '{{dir}} 变量file的内容是{{file}}'
- group_vars/
- lb/vars.yml
- web/vars.yml
- data/vars.yml
- all/vars.yml
- command line values (for example, .u my_user, these are not variables)
- role defaults (defined in role/defaults/main.yml)
- inventory file or script group vars
- inventory group_vars/all
- playbook group_vars/all
- inventory group_vars/*
- playbook group_vars/*
- inventory file or script host vars
- inventory host_vars/*
- playbook host_vars/*
- host facts / cached set_facts
- play vars
- play vars_prompt
- play vars_files
- role vars (defined in role/vars/main.yml)
- block vars (only for tasks in block)
- task vars (only for the task)
- include_vars
- set_facts / registered vars
- role (and include_role) params
- include params
- extra vars (for example, .e "user=my_user")(always win precedence)
facts变量
条件判断
---
- hosts: hhhh01
remote_user: root
tasks:
- name: touch flag file
command: "touch /tmp/this_is_{{ ansible_distribution }}_system_{{ ansible_distribution_major_version }}"
when: (ansible_distribution == "CentOS") or (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
循环语句
Ansible 2.5中添加了 loop 。它还不是 with_ 的完全替代品,但推荐它用于大多数用例。
loop 循环
with_ 循环
循环类型 | 关键字 |
---|---|
标准循环 | with_items |
嵌套循环 | with_nested |
遍历字典 | with_dict |
并行遍历列表 | with_together |
遍历列表和索引 | with_indexed_items |
遍历文件列表的内容 | with_file |
遍历目录文件 | with_fileglob |
重试循环 | until |
查找第一个匹配文件 | with_first_found |
随机选择 | with_random_choice |
在序列中循环 | with_sequence |
标准循环 with_items
# 添加多个用户
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
# 添加多个用户,并将用户加入不同的组内。
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
锚点嵌套循环 with_nested
# 分别给用户授予3个数据库的所有权限
- name: give users access to multiple databases
mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo
with_nested:
- [ 'alice', 'bob' ]
- [ 'clientdb', 'employeedb', 'providerdb' ]
锚点遍历字典 with_dict
# 输出用户的姓名和电话
tasks:
- name: Print phone records
debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
with_dict: {'alice':{'name':'Alice Appleworth', 'telephone':'123-456-789'},'bob':{'name':'Bob Bananarama', 'telephone':'987-654-3210'} }
锚点并行遍历列表 with_together
# 如果列表数目不匹配,用None补全
tasks:
- debug: "msg={{ item.0 }} and {{ item.1 }}"
with_together:
- [ 'a', 'b', 'c', 'd','e' ]
- [ 1, 2, 3, 4 ]
锚点遍历列表和索引 with_indexed_items
# item.0 为索引,item.1为值
- name: indexed loop demo
debug: "msg='at array position {{ item.0 }} there is a value {{ item.1 }}'"
with_indexed_items: [1,2,3,4]
锚点遍历文件列表的内容 with_file
---
- hosts: all
tasks:
- debug: "msg={{ item }}"
with_file:
- first_example_file
- second_example_file
锚点遍历目录文件with_fileglob
with_fileglob匹配单个目录中的所有文件,非递归匹配模式。
拷贝所有文件到目标机器的/etc/fooapp/路径下。
---
- hosts: all
tasks:
- file: dest=/etc/fooapp state=directory
- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
with_fileglob:
- /playbooks/files/fooapp/*
当在role中使用with_fileglob的相对路径时,Ansible解析相对于 roles/<rolename>/files
目录的路径。
组合示例
---
- hosts: test1
remote_user: root
tasks:
- debug: msg="{{ item.key }} is the winner"
with_dict: { 'jeson': { 'english': 60, 'chinese': 30}, 'tom': { 'english': 20, 'chinese': 30} }
when: item.value.english >= 60
其他示例请参考 ansible_playbook语法中的循环语句归纳
错误处理
默认会检查命令和模块的返回状态,遇到错误就中断 playbook 的执行。
忽略错误 ignore_errors
ignore_errors: yes
示例
---
- hosts: test1
remote_user: root
tasks:
- name: ignore false
command: /bin/false
# 忽略错误,继续执行touch的task
ignore_errors: yes
- name: touch a file
file: path=/tmp/test state=touch
自定义错误
failed_when: [boolean]
示例
---
- hosts: test1
remote_user: root
tasks:
- name: get process
shell: ps -ef | wc -l
# 将变量注册到process_count变量中
register: process_count
# 如果进程数小于3 则抛出异常,终止剧本
failed_when: process_count < 3
- name: touch a file
file: path=/tmp/test state=touch
自定义change状态
changed_when: false
示例
---
- hosts: test1
remote_user: root
tasks:
- name: touch a file
file: path=/tmp/test state=touch
# 取消changed的状态显示
changed_when: false
tags标签处理
可以为单个task任务,include对象,roles对象打一个或多个标签
示例
tasks:
- name: Install the servers
ansible.builtin.yum:
name:
- httpd
- memcached
state: present
tags:
- packages
- webservers
- name: Configure the service
ansible.builtin.template:
src: templates/src.j2
dest: /etc/foo.conf
tags:
- configuration
使用时通过参数指定
-
-t: 执行指定的tag标签任务
-
--skip-tags: 执行指定标签之外的任务
只执行Install the servers任务
ansible-playbook test.yml -t packages
跳过Install the servers任务
ansible-playbook test.yml --skip-tags packages
剧本重用
Ansible提供了两种在剧本中重用文件和角色的方法:动态和静态。
为了动态重用,请在剧本的任务部分添加 include_* 任务:
- include_role
- include_tasks
- include_vars
对于静态重用,请在播放的任务部分添加 import_* 任务:
- import_role
- import_tasks
可以在任意深度使用任务include和import语句。
include_tasks/include: 动态的包含tasks任务列表执行
roles角色
roles是种利用在大型playbook中的剧本配置模式,有着自己的特定结构
和面向对象开发思想类似,利用于大型的项目任务中,尽可能的将公共的任务、变量等内容独立,方便功能复用
官方推荐
ansible官方网站的建议playbook剧本结构如下:
production # 正式环境的inventory文件
staging # 测试环境用得inventory文件
group_vars/ # 机器组的变量文件
group1
group2
host_vars/ # 执行机器成员的变量
hostname1
hostname2
================================================
site.yml # 主要的playbook剧本
webservers.yml # webserver类型服务所用的剧本
dbservers.yml # 数据库类型的服务所用的剧本
roles/
webservers/ # webservers这个角色相关任务和自定义变量
tasks/ # 存放任务所用
main.yml
handlers/ # 存放触发器
main.yml
vars/ # 存放当前目录所用变量
main.yml
dbservers/ # dbservers这个角色相关任务和定义变量
...
common/ # 公共的
tasks/ #
main.yml #
handlers/ #
main.yml # handlers file.
vars/ # 角色所用到的变量
main.yml #
===============================================
templates/ # 模板文件目录
ntp.conf.j2 # 模版文件
files/ # 用于上传存放文件的目录
bar.txt #
foo.sh #
meta/ # 角色的依赖
main.yml #
我们可以新建剧本项目到roles目录下,使用ansible-galaxy命令生成标准化目录模板
ansible-galaxy init module-name
设计思路
主机组独立,按照环境或机房分类
ansible-playbook -i ./production
将公共任务、资源、变量等对象尽可能独立
自动化项目
这里提供了一个可在Linux内网一键安装各种常用模块的项目。欢迎大家star