ansible
介绍
常用运维工具比较
-
Puppet
- 基于Ruby开发,采用C/S架构,扩展性强,基于SSL,远程命令执行相对较弱
-
SaltStack
- 基于Python开发,采用C/S架构,相对puppet更轻量级,配置语法使用YAML,配置脚本更简单
-
Ansible
- 基于Python paramiko开发,分布式,无需客户端,轻量级,配置语法使用YAML及Jinja2模板语言,更强的远程命令执行操作
Ansible简介
-
Ansible基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
-
ansible是基于模块工作的,本身没有批量部署的能力,通过运行的模块实现,ansible只是提供一种框架
-
模块
-
connection plugins
- 连接插件,负责和被管理端实现通信,有SSH,ZEROMQ等,默认使用SSH连接
-
host inventory
- 主机清单,是一个配置文件里面定义管控的主机
-
modules
- 核心模块、command模块、自定义模块等
-
plugins
- modules功能的补充,包括连接插件,邮件插件等
-
playbook
- 编排、定义Ansible多任务配置文件,非必需
-
Ansible特性
-
no agents
- 不需要在被管控主机上安装任何客户端,更新时,只需在操作机上进行一次更新即可
-
no server
- 无服务器端,使用时直接运行命令即可
-
modules in any languages
- 基于模块工作,可使用任意语言开发模块
-
yaml,not code
- 使用yaml语言定制剧本playbook
-
ssh by default
- 基于SSH工作
-
strong multi-tier solution
- 可实现多级指挥
Ansible工作原理
- 在ANSIBLE管理体系中,存在"管理节点" 和 “被管理节点” 两种角色。被管理节点通常被称为"资产"
- 在管理节点上,Ansible将AdHoc或PlayBook转换为Python脚本,并通过SSH将这些Python脚本传递到资产上
- 在被管理服务器上依次执行,并实时的将结果返回给管理节点
Ansible执行过程
- 1). 加载自己的配置文件,默认/etc/ansible/ansible.cfg
- 2). 查找对应的主机配置文件,找到要执行的主机或者组
- 3). 加载自己对应的模块文件,如command
- 4). 通过ansible将模块或命令生成对应的临时py文件(python脚本), 并将该文件传输至远程服务器
- 5). 给文件添加执行权限
- 6). 对应执行用户的家目录的.ansible/tmp/XXX/XXX.PY文件
- 7). 返回执行结果给管理节点
- 8). 删除临时py文件,sleep 0退出
Ansible中的关键字
- https://docs.ansible.com/ansible/2.9/reference_appendices/playbooks_keywords.html
Ansible安装
-
yum
- yum -y install ansible
-
pip
- yum -y install python-pip
- pip install ansible
配置文件
配置文件查找顺序
-
- 检查环境变量ANSIBLE_CONFIG指向的路径文件(export ANSIBLE_CONFIG=/etc/ansible.cfg)
-
- ./ansible.cfg,检查当前目录下的ansible.cfg配置文件,即执行ansible命令的目录
-
- ~/.ansible.cfg,检查当前用户家目录下的隐藏.ansible.cfg配置文件
-
- /etc/ansible.cfg检查etc目录的配置文件
主配置文件
-
路径
- /etc/ansible/ansible.cfg
-
参数
-
inventory = /etc/ansible/hosts
- 资源清单inventory文件的位置
-
library = /usr/share/ansible
- 指向存放Ansible模块的目录,支持多个目录方式,用冒号(:)隔开
-
sudo_user = root
- 设置默认执行命令的用户
-
remote_port = 22
- 指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
-
forks = 5
- 并发连接数,默认为5
-
host_key_checking = False
- 设置是否检查SSH主机的密钥,True/False (取消注释)
-
timeout = 60
- 设置SSH连接的超时时间,单位为秒
-
log_path = /var/log/ansible.log
- 指定存储ansible日志的文件(默认不记录日志)
-
Inventory
作用
- 用于定义要管理主机的认证信息,例如ssh登录用户名、密码以及key相关信息
缺省路径
- /etc/ansible/hosts
配置
-
单独定义主机
-
192.168.10.128
- 放在主机组前面
-
-
定义主机组
- [webservers]
192.168.10.128
Bar.example.com
up.example.com:5309 #指定SSH端口5309
web1 ansible_ssh_host=1.1.1.12 #设置主机别名为web1
www[01:50].example.com #支持通配符匹配www01,…,www50
db-[a:f].example.com #通配符匹配db-a,db-b,…,db-f
- [webservers]
-
定义变量
-
[atlanta]
host1 http_port=80 maxRequests=808
host2 http_port=303 maxRequests=909- 为每个主机单独指定一些变量,这些变量可以在playbooks中使用
-
[atlanta]
host1
host2
-
[atlanta:vars] #组名:vars
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
- 为一个组指定变量,组内每个主机都可以使用该变量
-
组包含其他组
- [atlanta]
host1
host2
- [atlanta]
[raleigh]
host3
host4
[southeast:children] #组名:children
atlanta
raleigh
[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
Ad-Hoc
作用
- ansible中需要快速执行、不需要保存、简单的命令
语法
-
ansible -m <module_name> -a
-
pattern
-
inventory文件里定义的主机组名,主机名,IP,别名等。支持通配符,正则
-
all
- 表示所有的主机,
-
:
- 多个组,组名之间用冒号隔开
-
web
- 组名或主机名中含web的
-
webservers[0]
- webservers组中的第一台主机, -1表示最后一台主机
- 支持切片(正), [1:2]表示组中的第二台和第三台
-
-
-m module_name
- 指定模块,默认为command
-
-a arguments
- 传递给模块的参数
-
-i file_name
- 指定inventory文件, 默认为/etc/ansible/hosts
-
-k
- 询问密码.如果没有传公钥到被管理端,必须要接此选项
配置过程
-
- 在控制节点安装ansible
-
- 编辑主机清单文件,加入被管控节点
-
- 在控制节点生成密钥,把公钥传到所有的被控制节点(建议)
帮助信息
-
ansible-doc -l
- 查看所有模块信息
-
ansible-doc module_name
- 查看指定模块帮助信息
-
"="开头的为必选项,示例的格式为列表
Modules
command
-
作用
- 默认模块,支持多数shell命令,但不支持某些shell变量及管道
-
示例
- ansible 1.1.1.12 -a ‘hostname’
setup
-
作用
-
查看远程主机的基本信息
-
Facts - 用于采集被管理主机信息
- 物理内存容量 ansible_memtotal_mb
CPU型号 ansible_processor
CPU核心数 ansible_processor_cores
操作系统类型 ansible_os_family
操作系统内核 ansible_kernel
硬盘挂载名及容量 ansible_mounts
服务器主机名 ansible_nodename
服务器ipv4地址 ansible_all_ipv4_addresses - 信息内容中{}表示字典,[]表示列表
- 物理内存容量 ansible_memtotal_mb
-
-
选项
-
filter
- 仅列出匹配到的facts, 默认值为*
-
-
示例
- ansible webservers -m setup
- ansible webservers -m setup -a ‘filter=ansible_mounts’
ping
-
作用
- 测试远程主机的运行状态
-
示例
- ansible 1.1.1.12 -m ping
file
-
作用
- 文件管理
-
选项
-
path
- 必选项,定义文件/目录的路径,还可以写成name或dest
-
force
- 强制创建软链接,源文件不存在或目标软链接已存在时。yes|no(默认no)
- ansible 1.1.1.12 -m file -a ‘src=/opt/aa.txt dest=/opt/c.txt force=yes’
-
group
- 定义文件/目录的属组
- ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt group=tom’
-
mode
- 定义文件/目录的权限
- ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt mode=777’
-
owner
- 定义文件/目录的属主
- ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt owner=tom’
-
recurse
- 递归设置文件的属性,只对目录有效。yes|no(默认no)
- ansible 1.1.1.12 -m file -a ‘dest=/opt/a owner=tom mode=777 recurse=yes’
-
src
- 被链接的源文件路径,只应用于state=link或state=hard的情况
-
state
-
file
- 改变文件的属性(默认值)
- ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt mode=777 state=file’
-
directory
- 如果目录不存在,就创建目录
- ansible 1.1.1.12 -m file -a ‘dest=/opt/a state=directory’
-
touch
- 若文件不存在则创建,若文件已存在则更新其最后修改时间
- ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt state=touch’
-
link
- 创建软链接
- ansible 1.1.1.12 -m file -a ‘src=/opt/a/b/c.txt dest=/opt/c.txt state=link’
-
hard
- 创建硬链接
- ansible 1.1.1.12 -m file -a ‘src=/opt/a/b/c.txt dest=/opt/d.txt state=hard’
-
absent
- 删除文件
- ansible 1.1.1.12 -m file -a ‘dest=/opt/d.txt state=absent’
-
-
copy
-
作用
- 把主控端的文件复制到远程主机
-
选项
-
dest
- 必选项。远程主机的目标绝对路径,如果源文件是一个目录,那该路径也必须是个目录
-
src
- 被复制到远程主机的本地文件,绝对路径或相对路径。如果路径是一个目录,将递归复制
- 如果src以“/”结尾,则只复制目录里的内容,如果非“/”结尾,则复制目录及目录里的内容
-
content
- 将指定内容覆盖写入目标文件
- ansible 1.1.1.12 -m copy -a ‘content=“kkk\n” dest=/opt/a.txt’
-
directory_mode
- 递归设定目录的权限,默认为系统默认权限
- ansible 1.1.1.12 -m copy -a ‘src=./a dest=/opt directory_mode=777’
-
force
- 如果目标主机包含该文件,若内容不同则强制覆盖。yes|no(默认yes)
- ansible 1.1.1.12 -m copy -a ‘src=./a/ dest=/opt/ force=no’
-
backup
- 在覆盖之前,将源文件备份,备份文件包含时间信息。yes|no(默认no)
- ansible 1.1.1.12 -m copy -a ‘src=./a/ dest=/opt/ backup=yes’
-
others
- 所有的file模块里的选项都可以在这里使用
-
fetch
-
作用
- 从远程某主机获取(复制)文件到本地
-
选项
-
dest
- 用来存放文件的目录(本地路径)
-
src
- 从远程拉取的文件,并且必须是一个file,不能是目录
-
-
示例
- ansible webservers -m fetch -a ‘dest=/opt src=/etc/passwd’
shell
-
作用
- 在远程主机上执行shell命令
-
选项
-
cmd
- 要运行的命令
-
chdir
- 运行命令前先切换到的目录
-
-
示例
- ansible 1.1.1.12 -m shell -a ‘cat /etc/passwd |wc -l’
user
-
作用
- 远程主机用户管理
-
选项
-
name
- 要操作的用户名
-
uid
- 设置用户的UID
-
group
- 设置用户的基本组
-
shell
- 设置用户登录shell
-
groups
- 设置用户的附加组,如果设置为空,则将用户从所有附加组中退出来
-
home
- 设置用户家目录
-
create_home
- 创建家目录,yes|no(默认yes)
-
system
- 创建为系统用户,yes|no(默认no)
-
state
-
present
- 创建(默认值)
-
absent
- 删除
-
remove
- 当state=absent时,使用remove=yes干净的删除,默认值为no
-
-
-
示例
- ansible 1.1.1.12 -m user -a ‘name=lili uid=1111 group=tom groups=root shell=/bin/bash home=/root’
- ansible 1.1.1.12 -m user -a ‘name=lili state=absent remove=yes’
cron
-
作用
- 远程主机计划任务管理
-
选项
-
name
- 计划任务条目名称
-
minute
- 分
-
hour
- 时
-
day
- 日
-
month
- 月
-
weekday
- 周
-
job
- 要执行的命令
-
user
- 用户
-
state
-
present
- 创建(默认值)
-
absent
- 删除, 会列出现有的所有的任务
-
-
-
示例
- ansible 1.1.1.12 -m cron -a ‘name=“shutdown” minute=0 hour=3 job=“/usr/sbin/shutdown now”’
- ansible 1.1.1.12 -m cron -a ‘name=“shutdown” state=absent’
script
-
作用
- 将本地脚本传输到远程执行
-
选项
-
chdir
- 在执行脚本前先cd到此目录下
-
creates
- 接一个文件名,如果此文件不存在才执行
- ansible 1.1.1.12 -m script -a ‘./touch.sh chdir=/opt creates=/opt/a.txt’
-
removes
- 接一个文件名,如果此文件存在才执行
- ansible 1.1.1.12 -m script -a ‘./touch.sh chdir=/opt removes=/opt/b.txt’
-
service
-
作用
- 远程主机服务管理(el7:systemd)
-
选项
-
name
- 服务名称
-
state
-
started
- 启动服务
-
stopped
- 停止服务
-
restarted
- 重启服务
-
reloaded
- 重新加载配置文件
-
enabled
- 是否开机启动 yes|no
-
-
-
示例
- ansible 1.1.1.12 -m systemd -a ‘name=httpd state=started’
- ansible 1.1.1.12 -m systemd -a ‘name=httpd enabled=yes’
lineinfile
-
作用
- 远程主机文件编辑
-
选项
-
dest
- 指定要修改的文件
-
regexp
- 正则匹配模式
-
line
- 要增加或者修改的内容
-
insertafter
- 在后面插入。Used with ‘state=present’
-
insertbefore
- 在前面插入。Used with ’state=present’
-
firstmatch
- 配合insertbefore或insertafter, 如果设置了,在第一次正则匹配到的行进行插入
-
state
-
present
- 当匹配到时进行修改,当没有匹配到时在最后增加一行(默认)
-
absent
- 当匹配到时进行删除
-
-
backrefs
-
no
- 表示如果没有匹配到,则增加line;如果匹配成功,则替换line(默认)
-
yes
- 表示如果没有匹配到,则不变line;如果匹配成功,则替换line
-
-
backup
- 备份原文件。yes|no
-
-
示例
- ansible 1.1.1.12 -m lineinfile -a ‘path=/etc/selinux/config regexp=“^SELINUX=” line=“SELINUX=enforcing”’
- ansible 1.1.1.12 -m lineinfile -a ‘path=/etc/sudoers regexp=“^%wheel” state=absent’
yum
-
作用
- 使用yum管理软件包
-
选项
-
name
- 要安装软件包的名字,可以带上版本号
-
state
-
present | installd
- 安装(默认)
-
lastest
- 安装最新版
-
absent | removed
- 删除
-
-
package
-
作用
- 使用操作系统相应的软件包管理工具模块处理,如centos: yum, ubuntu: apt
-
选项
-
name
- 要管理的包名,可以带上版本号
-
state
-
present
- 安装
-
absent
- 删除
-
-
-
示例
- ansible 1.1.1.12 -m package -a ‘name=httpd state=present’
- ansible 1.1.1.12 -m package -a ‘name=httpd state=absent’
unarchive
-
作用
- 解压缩
-
选项
-
src
- 必选项, 要解压的包名
-
dest
- 必选项, 解压到哪个目录下
-
remote_src
-
no(默认)
- 将管理机上的包传到远程主机上解压
-
yes
- 解压远程主机上的包
-
-
-
示例
- ansible 1.1.1.12 -m unarchive -a ‘src=./nginx-1.12.2.tar.gz dest=/root’
- ansible 1.1.1.12 -m unarchive -a ‘src=/opt/nginx-1.12.2.tar.gz dest=/root remote_src=yes’
template
-
作用
- 基于jinja2模板创建配置文件
-
选项
-
src
- 模板路径,先要定义模板文件
-
dest
- 目标路径
-
-
示例
- ansbile 1.1.1.12 -m template -a 'src=/tmp/nginx.conf.j2 dest=/etc/nginx/nginx.conf
Variable
facts组件变量
-
变量值类型
-
字符串
- ansible_fqdn = “web1.qf.com”
-
列表(相当于索引数组)
- ipv4 = [ ‘192.168.10.11’ , ‘192.168.10.100’ , ‘192.168.10.101’ ]
-
字典(相当于关联数组)
- tom = { ‘age’:18 , ‘sex’:‘male’ , ‘class’:‘yunjisuan’ }
-
-
常用facts变量
-
使用setup模块来获取,可直接调用
-
ansible_all_ipv4_addresses
- 仅显示ipv4的信息 —> [“192.168.95.143”]
-
ansible_eth0[‘ipv4’][‘address’]
- 仅显示ipv4的信息 —> eth0 的ip地址
-
ansible_devices
- 仅显示磁盘设备信息
-
ansible_distribution
- 显示是什么系统,例:centos,suse等
-
ansible_distribution_version
- 仅显示系统版本
-
ansible_machine
- 显示系统类型,例:32位,还是64位
-
ansible_eth0
- 仅显示eth0的信息
-
ansible_hostname
- 仅显示主机名
-
ansible_kernel
- 仅显示内核版本
-
ansible_lvm
- 显示lvm相关信息
-
ansible_memtotal_mb
- 显示系统总内存
-
ansible_memfree_mb
- 显示可用系统内存
-
ansible_memory_mb
- 详细显示内存情况
-
ansible_swapfree_mb
- 显示swap内存的可用内存
-
ansible_swaptotal_mb
- 显示总的swap内存
-
ansible_mounts
- 显示系统磁盘挂载情况
-
ansible_processor
- 显示cpu个数(具体显示每个cpu的型号)
-
ansible_processor_vcpus
- 显示cpu个数(只显示总的个数)
-
ansible_python_version
- 显示python版本
-
通过命令行传入变量
- ansible-playbook命令的命令行中接 “-e key=value”
- ansible-playbook jinjia2-if.yaml -e PORT=‘’
在playbook中定义变量
-
vars:
- var1: value1
- var2: value2
在Host Inventory中定义变量
-
向不同的主机传递不同的变量
- ip/hostname var1=value1 var2=value2
-
向组中的主机传递相同的变量
- [groupname:vars]
var1=value1
var2=value2
- [groupname:vars]
通过roles传递变量
user: nginx
pkg: nginx-1.20.2.tar.gz
pkgdir: nginx-1.20.2
basedir: /usr/local/nginx
通过register定义变量
-
- name: create user tom
user:
name: tom
register: user_info #主机级变量
- name: create user tom
- name: show user_info
debug:
var: user_info
优先级
- 命令行传入 > playbook定义 > host主机变量 > host主机组变量 > default
PlayBook
简介
- Playbook是ansible用于配置、部署和管理被控节点的剧本
- 通过playbook的详细描述,执行其中的一系列 tasks ,可以让远端主机达到预期的状态
- playbook就像Ansible控制器给被控节点列出的的一系列to-do-list ,而被控节点必须要完成
- 对一些简单的任务,ad-hoc可以方便地解决,但对于过于复杂、需要大量的操作时,最好使用playbook
- 类似于执行shell命令与写shell脚本,不过playbook有自己的语法格式。使用playbook可以方便的重用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码
组成
-
Target section
- 定义将要执行 playbook 的远程主机组
-
Variable section
- 定义 playbook 运行时需要使用的变量
-
Task section
- 定义将要在远程主机上执行的任务列表
-
Handler section
- 定义 task 执行完成以后需要调用的任务
YAML语法简介
-
官方文档
- https://docs.ansible.com/ansible/2.9/reference_appendices/YAMLSyntax.html
-
介绍
- Playbook 采用 YAML 语法。后缀 .yaml或 .yml
- YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等
- YAML格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写
-
常用格式
- yaml文件以—开始,以…结束,但开始和结束标志都是可选的
- 在同一行中,#之后的内容表示注释,类似于shell,python和ruby
- YAML中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容
- 同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理
- play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":“分隔表示,”:"后接空格
-
数据类型
- 字符串
- 列表
- 字典
编写
-
基本写法
-
hosts: webservers #需执行的主机,值类型为字符串,写法与adhoc一致
gather_facts: false #关闭Gathering Facts任务,默认开启(需调用变量时要开启)
tasks: #定义任务列表,值的数据类型为列表- name: create user tom #任务描述信息,在执行过程中显示(便于排错)
user: name=tom state=present #调用user模块,值类型为字典(写法一) - name: create file /tmp/tom.txt
file: #调用file模块,值类型为字典(写法二)
dest: /tmp/tom.txt #file模块参数
owner: tom
mode: 777
state: touch
- name: create user tom #任务描述信息,在执行过程中显示(便于排错)
-
变量定义及使用
-
hosts: webservers
gather_facts: false
vars: #自定义变量。调用变量必须先自定义或用facts中变量- user_name: “tom” #变量值最好使用引号
- file_name: “tom.txt”
tasks: - name: create user “{{user_name}}”
user:
name: “{{user_name}}” #调用变量使用 “{{}}” - name: touoch file “/tmp/{{file_name}}”
file:
dest: “/tmp/{{file_name}}” #路径调用变量写法
state: touch
owner: “{{user_name}}”
-
hosts: 1.1.1.12
tasks:- name: str #facts中字符串变量调用方法
shell: echo “{{ansible_architecture}}” > /tmp/facts.txt # - name: list #facts中列表变量调用方法
shell: echo “{{ansible_all_ipv4_addresses[1]}}” >> /tmp/facts.txt - name: dict1 #facts中字典变量调用方法一
shell: echo “{{ansible_apparmor.status}}” >> /tmp/facts.txt - name: dict2 #facts中字典变量调用方法二
shell: echo “{{ansible_apparmor[‘status’]}}” >> /tmp/facts.txt - name: dict3 #facts中字典列表混合调用一
shell: echo “{{ansible_mounts[0].block_used}}” > /tmp/facts.txt - name: dict4 #facts中字典列表混合调用二
shell: echo “{{ansible_devices[‘dm-1’].links.uuids[0]}}” >> /tmp/facts.txt
#若变量名含有‘-’,则改变量必须要用[‘’]调用,如[‘dm-1’]
- name: str #facts中字符串变量调用方法
-
条件判断
-
hosts: all
tasks:- name: create user tom
user:
name: tom
#when: ansible_hostname == “web03” #写法一:当变量值等于某个字符串
when: “‘1.1.1.11’ in ansible_all_ipv4_addresses” #写法二:当变量包含某个字符串
#要求多条件同时满足可用and连接或写成列表的形式 - name: create file /tmp/a.txt
file:
dest: /tmp/a.txt
state: touch
when: “‘1.1.1.12’ in ansible_all_ipv4_addresses” #when中变量调用无需“{{}}”
- name: create user tom
-
handlers
-
hosts: all
tasks:- name: create user tom
user:
name: tom
notify: create file #任务执行结果为changed则通知指定handler
handlers: #所有tasks执行完后,若收到notify则执行对应handler - name: create file
file:
dest: /tmp/a.txt
state: touch
owner: tom
- name: create user tom
-
循环
-
hosts: 1.1.1.12
gather_facts: false
tasks:- name: install lamp
yum:
name: “{{item}}” #固定变量item取值源于loop
loop: #列表循环,写法一- httpd
- mariadb-server
- php
- php-mysql
#loop: [‘httpd’,‘mariadb-server’,‘php’,‘php-mysql’] #列表循环,写法二
- name: install lamp
-
hosts: 1.1.1.12
gather_facts: false
tasks:- name: create hard links
file:
dest: “/tmp/{{item.dest}}” #变量取值源于字典
src: “/opt/{{item.src}}” #变量取值源于字典
state: hard
loop: #字典循环- {‘src’:‘x’,‘dest’:‘y’}
- {‘src’:‘z’,‘dest’:‘k’}
- name: create hard links
-
tags
-
hosts: 1.1.1.12
gather_facts: false
tasks:- name: task1 #任务可以有1个或多个标签
file:
dest: /opt/task1
state: touch
#tags: t1 #写法一
#tags: [‘t2’,‘t3’] #写法二
#tags: #写法三
#- t1
#- t2 - name: task2
file:
dest: /opt/task2
state: touch
tags: always #仅–skip-tags=always,tagged可禁止 - name: task3
file:
dest: /opt/task3
state: touch
tags: never #仅–tags=never可启用-
标签
-
自定义
-
always
- 仅–skip-tags=always,tagged可禁止
-
never
- 仅–tags=never可启用
-
特殊值
-
tagged
- 配合–tags,除never外所有带标签的运行
- 配合–skip-tags,所有带标签的不运行
-
untagged
- 配合–tags ,always以及所有不带标签的运行
- 配合–skip-tags,never以及所有不带标签的不运行
-
all
- 配合–tags ,仅never不运行
- 配合–skip-tags,仅always运行
-
-
-
运行
-
–tags=tag
- 运行指定标签,always无需指定
- ansible-playbook tags.yaml --tags=t1,t2
-
–skip-tags=tag
- 不运行指定标签,never无需指定
- ansible-playbook tags.yaml --tags=test --skip-tags=t2
-
一条指令中,–tags和–skip-tags关系与,–tags或–skip-tags中多个标签关系或
-
-
- name: task1 #任务可以有1个或多个标签
-
register
- register 是个寄存器,接收任务的返回值或者状态
-
hosts: 1.1.1.12
tasks:- name: create user tom
user:
name: tom
register: user_info #定义变量保存任务执行的状态信息 - name: show user_info
debug:
var: user_info #输出变量内容
- name: create user tom
-
hosts: 1.1.1.12
gather_facts: false
tasks:- name: weekday_info
shell: date +%w
register: weekday - name: show weekday
debug:
var: weekday.stdout #状态信息中的stdout字段 - name: do ceping every wed
shell: echo ceping > /tmp/a.txt
when: weekday.stdout == ‘3’ #调用register变量中的字段
- name: weekday_info
执行
-
语法检测
- ansible-playbook --syntax-check /path/to/playbook.yaml
-
测试运行
- ansible-playbook -C /path/to/playbook.yaml
-
执行
-
ansible-playbook /path/to/playbook.yaml
-
执行结果
-
黄色changed
- 执行成功,系统状态发生改变
-
绿色ok
- 执行成功,系统保持原样
-
红色fatal
- 执行失败,显示错误输出(看msg)
-
紫色WARNING
- 警告提醒
-
蓝色skipping
- 跳过未执行
-
-
jinjia2简介
介绍
- Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity
- 它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛
- Jinja2的语法是由variables(变量)和statement(语句)组成
variables
-
可以替换数据
- 如: listen {{ nginxport }};
statement
-
可以用来创建条件和循环等
-
if语句
- hosts: all
tasks:-
template:
src=/tmp/if.j2
dest=/tmp/if.conf- # vim /tmp/if.j2
-
{% if PORT %}
Listen {{ PORT }}
{% else %}
Listen 80
{% endif %}
- # vim /tmp/if.j2
Listen {{ PORT | default(80) }}
- hosts: all
tasks:-
template:
src=/tmp/for.j2
dest=/tmp/host.for- # vim /tmp/for.j2
-
{% for id in range(11,15) %}
192.168.10.{{ id }} web{{ id }}.test.com
{% endfor %}
- 执行结果
- # cat /tmp/hosts.for
192.168.10.11 web11.test.com
192.168.10.12 web12.test.com
192.168.10.13 web13.test.com
192.168.10.14 web14.test.com
192.168.10.15 web15.test.com
模板支持
-
字符串
- 使用单引号或双引号
-
数字
- 整数,浮点数
-
列表
- [item1, item2, …]
-
元组
- (item1, item2, …)
-
字典
- {key1:value1, key2:value2, …}
-
布尔型
- true/false
-
算术运算
- +, -, *, /, //, %, **
-
比较操作
- ==, !=, >, >=, <, <=
-
逻辑运算
- and, or, not
Templates
介绍
- 模板是一个文本文件,嵌套有脚本,脚本使用模板编程语言(jinja2)编写
- 通常来说,模板都是通过引用变量来运用的
- 用于针对不同主机需要配置不同参数的场景,如配置文件
示例
-
要求
-
nginx配置文件中工作进程按主机cpu数进行配置,分别配置不同的监听端口
-
监听端口
- 1.1.1.12:90
- 1.1.1.13:8080
1.1.1.14:8080 - 1.1.1.15:80
-
-
定义模板
work_processes {{ansible_processor_vcpus}}
listen {{nginx_port | default(80)}} #nginx_port若未定义默认80
1.1.1.15
[webservers]
web2 ansible_ssh_host=1.1.1.12 nginx_port=90 #定义主机变量
1.1.1.13 #ansible_ssh_host为hosts自带变量
1.1.1.14
[webservers:vars]
nginx_port=8080 #定义主机组变量,优先级低于主机变量
- hosts: all
#vars #playbook中定义的变量优先级高于hosts
tasks:- template:
src: /tmp/nginx.conf.j2
dest: /usr/local/nginx/conf/nginx.conf
- template:
项目实践
-
目标
- 通过ansible实现批量编译安装nginx
-
环境准备
-
本机准备安装包
- /root/nginx-1.20.2.tar.gz
-
本机准备配置文件模板
- tar xf /root/nginx-1.20.2.tar.gz
cp nginx-1.20.2/conf/nginx.conf /tmp/nginx.conf.j2
- tar xf /root/nginx-1.20.2.tar.gz
-
远程主机卸载原有nginx,关闭80端口服务,删除nginx用户
-
-
定义模板
- # vim /tmp/nginx.conf.j2
user {{user}}
work_processes {{ansible_processor_vcpus}}
- # vim /tmp/nginx.conf.j2
-
编写资产文件
- # vim /etc/ansible/hosts
[nginx]
1.1.1.12
1.1.1.13
1.1.1.14
- # vim /etc/ansible/hosts
-
编写playbook
- # vim nginx.yaml
-
hosts: nginx
vars:- user: nginx
- pkg: nginx-1.20.2.tar.gz
- pkgdir: /tmp/nginx-1.20.2
- basedir: /usr/local/nginx
tasks: - name: 拷贝安装包
unarchive:
src: “/root/{{package}}”
dest: /tmp/ - name: 创建nginx用户
user:
name: “{{user}}”
shell: /sbin/nologin
create_home: false
system: true - name: 安装依赖包
yum:
name: “{{item}}”
loop:- gcc
- gcc-c++
- pcre-devel
- openssl-devel
- name: 编译安装
shell:
cmd: “{{item}}”
chdir: “{{pkgdir}}”
loop:- ./configure --prefix=“{{basedir}}” --user=“{{user}}” --group=“{{user}}” --with-http_stub_status_module --with-http_ssl_module --sbin-path=/usr/sbin/
- make
- make install
- name: 拷贝配置文件
template:
src: /tmp/nginx.conf.j2
dest: “{{basedir}}/conf/nginx.conf” - name: 测试
shell: nginx -t
notify: 运行
handlers: - name: 运行
shell: nginx
-
运行playbook
- ansible-playbook nginx.yaml --syntax-check
- ansible-playbook nginx.yaml
Roles
简介
- playbook存在弊端即无法实现复用,很难实现灵活的调用
- ansible提供了一种目录树结构的编排方式,顶层目录对应roles,里面包含子目录,比如defaults、files、tasks、templates等,不同的子目录对应不同的功能
- roles 能够根据层次型结构自动装载变量文件、tasks以及handlers等
- 角色中在编写task时本地文件只需写文件名,不需要写路径
角色集合
- roles目录下,可以创建多个角色目录,每个目录都是一个角色
子目录
-
每个角色目录可以包含如下子目录,按需配置
-
tasks/
- 用于定义各task
-
handlers/
- 用于定义各handler
-
vars/
- 用于定义各variable
-
defaults/
- 用于设定默认变量,优先级最低
-
meta/
- 定义当前角色的特殊设定及其依赖关系
-
files/
- 存储由copy、script、unarchive模块调用的文件
-
templates/
- 存储由template模块调用的模板文本
项目一
-
目标
- 通过ansible实现一键编译安装redis并部署主从复制及哨兵
-
创建目录
- mkdir -p /etc/ansible/playbooks/roles/redis/{defaults,files,tasks,templates}/
-
配置hosts
- # vim /etc/ansible/hosts
[redis]
1.1.1.12
1.1.1.13
1.1.1.14
1.1.1.15
- # vim /etc/ansible/hosts
-
配置files/
- 上传redis源码安装包redis-4.0.10.tar.gz
-
配置defaults/
- # vim /etc/ansible/playbooks/roles/redis/defaults/main.yml
redisPort: 6380
senPort: 26380
passwd: 123
master: 1.1.1.12
pkg: redis-4.0.10.tar.gz
basedir: /usr/local/redis-4.0.10
- # vim /etc/ansible/playbooks/roles/redis/defaults/main.yml
-
配置templates/
-
准备配置文件
- tar xf …/files/redis-4.0.10.tar.gz -C ./
- cp redis-4.0.10/redis.conf redis.conf.j2
- cp redis-4.0.10/sentinel.conf sentinel.conf.j2
- rm -rf redis-4.0.10/
-
定义模板
-
redis
- # vim redis.conf.j2
bind 127.0.0.1 {{ansible_ssh_host}}
protected-mode no
port {{redisPort}}
daemonize yes
pidfile “/var/run/redis_{{redisPort}}.pid”
logfile “/var/local/redis_{{redisPort}}.log”
{% if ansible_ssh_host != master %}
slaveof {{master}} {{redisPort}}
{% endif %}
masterauth {{passwd}}
requirepass {{passwd}}
- # vim redis.conf.j2
-
哨兵
-
-
bind {{ansible_ssh_host}}
port {{senPort}}
daemonize yes
logfile “/var/log/sentinel_{{senPort}}.log”
sentinel monitor mymaster {{master}} {{redisPort}} 2
sentinel auth-pass mymaster {{passwd}}
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
-
配置tasks/
- # vim /etc/ansible/playbooks/roles/redis/tasks/main.yml
-
name: 拷贝安装包
unarchive:
src: “{{pkg}}”
dest: /usr/local/ -
name: 安装依赖包
yum:
name: “{{item}}”
loop:- gcc
- gcc-c++
-
name: 编译安装
shell:
cmd: make MALLOC=libc
chdir: “{{basedir}}” -
name: 制作软链接
file:
src: “{{basedir}}/src/{{item}}”
dest: “/usr/bin/{{item}}”
state: link
loop:- redis-server
- redis-cli
- redis-sentinel
-
name: 拷贝配置文件
template:
src: “{{item.src}}”
dest: “{{basedir}}/{{item.dest}}”
loop:- {‘src’:‘redis.conf.j2’,‘dest’:‘redis.conf’}
- {‘src’:‘sentinel.conf.j2’,‘dest’:‘sentinel.conf’}
-
name: 启动redis
shell: redis-server “{{basedir}}/redis.conf” -
name: 启动哨兵
shell: redis-sentinel “{{basedir}}/sentinel.conf”
when: ansible_ssh_host != master -
编写playbook
- # vim /etc/ansible/playbooks/redis.yaml
-
hosts: redis
roles: #表示选择部署哪个角色-
redis
- playbook文件和roles目录放在同一级目录中
-
-
运行playbook
- ansible-playbook /etc/ansible/playbooks/redis.yaml --syntax-check
- ansible-playbook /etc/ansible/playbooks/redis.yaml
-
目录结构
- # tree .
├── redis.yaml
└── roles
└── redis
├── defaults
│ └── main.yml
├── files
│ └── redis-4.0.10.tar.gz
├── tasks
│ └── main.yml
└── templates
├── redis.conf.j2
└── sentinel.conf.j2
- # tree .
项目二
-
目标
- 一键部署MySQL主从复制(传统方式)
-
创建目录
- mkdir -p /etc/ansible/playbooks/roles/mysql/{defaults,files,tasks,templates}/
-
配置hosts
- # vim /etc/ansible/hosts
[mysql]
1.1.1.12
1.1.1.13
1.1.1.14
- # vim /etc/ansible/hosts
-
配置files/
- # vim mysql57.repo
[mysql57]
name=mysql5.7
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-x86_64/
enabled=1
gpgcheck=1
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
- # vim mysql57.repo
-
配置defaults/
- # vim main.yml
master: 1.1.1.13
passwd: Zqs@123456
- # vim main.yml
-
配置templates/
- # vim my.cnf.j2
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
log-bin = my-bin
binlog_format = MIXED
{% if ansible_ssh_host == master %}
server-id = 1
{% else %}
server-id = 2
{% endif %}
- # vim my.cnf.j2
-
配置tasks/
- # vim main.yml
-
name: 拷贝MySQL源
copy:
src: mysql57.repo
dest: /etc/yum.repos.d/ -
name: 安装MySQL
yum:
name: mysql-community-server -
name: 拷贝配置文件
template:
src: my.cnf.j2
dest: /etc/my.cnf -
name: 启动MySQL
shell:
cmd: “{{item}}”
loop:- systemctl start mysqld
- systemctl enable mysqld
-
name: 获取初始密码
shell: grep “password” /var/log/mysqld.log |awk ‘{print $NF}’
register: pass1 -
name: 修改密码
shell: mysqladmin -u root -p"{{pass1.stdout}}" password “{{passwd}}”
tags: never -
name: 创建复制账号
shell: mysql -u root -p"{{passwd}}" -e “grant replication slave,replication client on . to ‘slave’@‘1.1.1.%’ identified by ‘{{passwd}}’;”
when: ansible_ssh_host == master
tags: never -
name: 获取log_file
shell: mysql -u slave -p"{{passwd}}" -h “{{master}}” -e “show master status\G” |awk NR==2’{print $2}’
register: log_file
when: ansible_ssh_host != master -
name: 获取log_pos
shell: mysql -u slave -p"{{passwd}}" -h “{{master}}” -e “show master status\G” |awk NR==3’{print $2}’
register: log_pos
when: ansible_ssh_host != master -
name: slave配置AB
shell:
cmd: “{{item}}”
loop:- mysql -u root -p"{{passwd}}" -e “change master to master_host=‘{{master}}’,master_user=‘slave’,master_password=‘{{passwd}}’,master_log_file=‘{{log_file.stdout}}’,master_log_pos={{log_pos.stdout}};”
- mysql -u root -p"{{passwd}}" -e “start slave;”
when: ansible_ssh_host != master
-
编写playbook
- # vim /etc/ansible/playbooks/mysql.yaml
-
hosts: mysql
roles:- mysql
-
运行playbook
- ansible-playbook /etc/ansible/playbooks/mysql.yaml --syntax-check
- ansible-playbook /etc/ansible/playbooks/mysql.yaml