ansible快速文档
ansible
what:ansible是基于python模块paramiko开发的自动化运维工具
why:实现了批量系统配置、批量程序部署、批量运行命令等功能
Ansible is Simple IT Automation
马哥ansible入门到精通及企业实战_哔哩哔哩_bilibili
运维自动化发展历程,运维职业发展路线 – 运维派 (yunweipai.com)
自动化运维工具——ansible详解(一) - 珂儿吖 - 博客园 (cnblogs.com)
自动化运维工具——ansible详解(二) - 珂儿吖 - 博客园 (cnblogs.com)
Ansible 发展史
作者:Michael DeHaan( Cobbler 与 Func 作者)
ansible 的名称来自科幻小说《安德的游戏》中跨越时空的即时通信工具,使用它可以在相距数光年的距离,远程实时控制前线的舰队战斗
2012-03-09,发布0.0.1版,2015-10-17,Red Hat宣布1.5亿美元收购
Ansible 特性
- 模块化:调用特定的模块完成特定任务,支持自定义模块,可使用任何编程语言写模块
- Paramiko(python对ssh的实现),PyYAML,Jinja2(模板语言)三个关键模块
- 基于Python语言实现
- 部署简单,基于python和SSH(默认已安装),agentless,无需代理不依赖PKI(无需ssl)
- 安全,基于OpenSSH
- 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
- 支持playbook编排任务,YAML格式,编排任务,支持丰富的数据结构
- 较强大的多层解决方案role
注意事项
- 基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架
- ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的
- 执行ansible的主机一般称为主控端,中控,master或堡垒机
- 主控端Python版本需要2.6或以上
- 被控端Python版本小于2.4,需要安装python-simplejson
- 被控端如开启SELinux需要安装libselinux-python
- windows 不能做为主控端
Ansible 架构
组合INVENTORY、API、MODULES、PLUGINS的绿框,可以理解为是ansible命令工具,其为核心执行工具
- INVENTORY:Ansible管理主机的清单/etc/anaible/hosts
- MODULES:Ansible执行命令的功能模块,多数为内置核心模块,也可自定义
- PLUGINS:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用
- API:供第三方程序调用的应用程序编程接口
Ansible命令执行过程
- 加载自己的配置文件,默认/etc/ansible/ansible.cfg
- 加载自己对应的模块文件,如:command
- 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
- 给文件+x执行权限
- 执行并返回结果
- 删除临时py文件,退出
1.ansible install
1.1使用yum安装
ansible在epel源
yum -y install epel-release yum makecache yum -y install ansible
安装的依赖: Installing: ansible noarch 2.9.24-2.el7 epel 17 M Installing for dependencies: python-babel noarch 0.9.6-8.el7 base 1.4 M python-backports x86_64 1.0-8.el7 base 5.8 k python-backports-ssl_match_hostname noarch 3.5.0.1-1.el7 base 13 k python-cffi x86_64 1.6.0-5.el7 base 218 k python-enum34 noarch 1.0.4-1.el7 base 52 k python-idna noarch 2.4-1.el7 base 94 k python-ipaddress noarch 1.0.16-2.el7 base 34 k python-jinja2 noarch 2.7.2-4.el7 base 519 k python-markupsafe x86_64 0.11-10.el7 base 25 k python-paramiko noarch 2.1.1-9.el7 base 269 k python-ply noarch 3.4-11.el7 base 123 k python-pycparser noarch 2.14-1.el7 base 104 k python-setuptools noarch 0.9.8-7.el7 base 397 k python2-cryptography x86_64 1.7.2-2.el7 base 502 k python2-httplib2 noarch 0.18.1-3.el7 epel 125 k python2-jmespath noarch 0.9.4-2.el7 epel 41 k python2-pyasn1 noarch 0.1.9-7.el7 base 100 k sshpass x86_64 1.06-2.el7 extras 21 k
##
2.免密认证
ssh免密码认证 - omgasw - 博客园 (cnblogs.com)
3.配置文件
3.1./etc/ansible/ansible.cfg
ansible的主配置文件,其中大部分配置内容无需修改
[defaults] # some basic default values... #inventory = /etc/ansible/hosts ## 主机列表配置文件 #library = /usr/share/my_modules/ ## 库文件存放目录 #module_utils = /usr/share/my_module_utils/ #remote_tmp = ~/.ansible/tmp ## 临时python命令文件存放在远程主机目录 #local_tmp = ~/.ansible/tmp ## 本机的临时命令执行目录 #forks = 5 ## 默认并发数 #sudo_user = root ## 默认sudo用户 #ask_sudo_pass = True ##每次执行ansible命令是否询问ssh密码 #ask_pass = True #remote_port = 22 #host_key_checking = False ## 检查对应服务器的host_key,建议取消注释 #log_path = /var/log/ansible.log ## 日志文件,建议启用 #module_name = command ## 默认模块,可以修改为shell模块
3.2./etc/ansible/hosts
主机清单,可以进行分组
# Ex 1: Ungrouped hosts, specify before any group headers. ## green.example.com ## blue.example.com ## 192.168.100.1 ## 192.168.100.10 # Ex 2: A collection of hosts belonging to the 'webservers' group ## [webservers] ## alpha.example.org ## beta.example.org ## 192.168.1.100 ## 192.168.1.110 # If you have multiple hosts following a pattern you can specify # them like this: ## www[001:006].example.com # Ex 3: A collection of database servers in the 'dbservers' group ## [dbservers] ## ## db01.intranet.mydomain.net ## db02.intranet.mydomain.net ## 10.25.1.56 ## 10.25.1.57
3.3./etc/ansible/roles
用于默认存放roles的文件夹
[root@ansible01 ~]# ansible-galaxy list # /root/.ansible/roles # /usr/share/ansible/roles # /etc/ansible/roles
4.ansible模块
command
默认模块,不支持管道通配等符号
shell
可以修改为默认模块
[root@ansible01 ~]# ansible test -m shell -a 'df -Th' 10.1.10.72 | CHANGED | rc=0 >> Filesystem Type Size Used Avail Use% Mounted on devtmpfs devtmpfs 979M 0 979M 0% /dev tmpfs tmpfs 991M 0 991M 0% /dev/shm tmpfs tmpfs 991M 9.5M 981M 1% /run tmpfs tmpfs 991M 0 991M 0% /sys/fs/cgroup /dev/mapper/centos-root xfs 25G 1.8G 24G 8% / /dev/mapper/centos-var xfs 50G 555M 50G 2% /var /dev/mapper/centos-home xfs 10G 33M 10G 1% /home /dev/sda1 xfs 5.0G 196M 4.8G 4% /boot tmpfs tmpfs 199M 0 199M 0% /run/user/0
ping
[root@ansible01 ~]# ansible 10.1.10.72 -m ping 10.1.10.72 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } [root@ansible01 ~]# ansible all -m ping 10.1.10.72 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" }
script
[root@ansible01 ~]# ansible test -m script -a /root/df.sh 10.1.10.72 | CHANGED => { "changed": true, "rc": 0, "stderr": "Shared connection to 10.1.10.72 closed.\r\n", "stderr_lines": [ "Shared connection to 10.1.10.72 closed." ], "stdout": "Filesystem Type Size Used Avail Use% Mounted on\r\ndevtmpfs devtmpfs 979M 0 979M 0% /dev\r\ntmpfs tmpfs 991M 0 991M 0% /dev/shm\r\ntmpfs tmpfs 991M 9.5M 981M 1% /run\r\ntmpfs tmpfs 991M 0 991M 0% /sys/fs/cgroup\r\n/dev/mapper/centos-root xfs 25G 1.8G 24G 8% /\r\n/dev/mapper/centos-var xfs 50G 555M 50G 2% /var\r\n/dev/mapper/centos-home xfs 10G 33M 10G 1% /home\r\n/dev/sda1 xfs 5.0G 196M 4.8G 4% /boot\r\ntmpfs tmpfs 199M 0 199M 0% /run/user/0\r\n", "stdout_lines": [ "Filesystem Type Size Used Avail Use% Mounted on", "devtmpfs devtmpfs 979M 0 979M 0% /dev", "tmpfs tmpfs 991M 0 991M 0% /dev/shm", "tmpfs tmpfs 991M 9.5M 981M 1% /run", "tmpfs tmpfs 991M 0 991M 0% /sys/fs/cgroup", "/dev/mapper/centos-root xfs 25G 1.8G 24G 8% /", "/dev/mapper/centos-var xfs 50G 555M 50G 2% /var", "/dev/mapper/centos-home xfs 10G 33M 10G 1% /home", "/dev/sda1 xfs 5.0G 196M 4.8G 4% /boot", "tmpfs tmpfs 199M 0 199M 0% /run/user/0" ] }
copy
#如目标存在,默认覆盖,此处指定先备份 ansible websrvs -m copy -a “src=/root/test1.sh dest=/tmp/test2.sh owner=wang mode=600 backup=yes” #指定内容,直接生成目标文件 ansible websrvs -m copy -a "content='test line1\ntest line2' dest=/tmp/test.txt" #复制/etc/下的文件,不包括/etc/目录自身 ansible websrvs -m copy -a “src=/etc/ dest=/backup”
fetch
从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录
[root@ansible ~]#ansible all -m fetch -a 'src=/etc/redhat-release dest=/data/os' [root@ansible ~]#tree /data/os/ /data/os/ ├── 10.0.0.6 │ └── etc │ └── redhat-release ├── 10.0.0.7 │ └── etc │ └── redhat-release └── 10.0.0.8 └── etc └── redhat-release
file
#创建空文件 ansible all -m file -a 'path=/data/test.txt state=touch' ansible all -m file -a 'path=/data/test.txt state=absent' ansible all -m file -a "path=/root/test.sh owner=wang mode=755“ #创建目录 ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql" #创建软链接 ansible all -m file -a ‘src=/data/testfile dest=/data/testfile-link state=link’
archive
打包压缩
ansible websrvs -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2 owner=wang mode=0600'
unarchive
解包解压缩
1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes
2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常见参数:
copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件
remote_src:和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible主机上
src:源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no
dest:远程主机上的目标路径
mode:设置解压缩后的文件权限
ansible all -m unarchive -a 'src=/data/foo.tgz dest=/var/lib/foo' ansible all -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777' ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no'
hostname
ansible node1 -m hostname -a “name=websrv” ansible 192.168.100.18 -m hostname -a 'name=node18.magedu.com'
cron
#备份数据库脚本 [root@centos8 ~]#cat mysql_backup.sh mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip > /data/mysql_date +%F_%T.sql.gz #创建任务 ansible 10.0.0.8 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh' ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime" #禁用计划任务 ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=yes" #启用计划任务 ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=no" #删除任务 ansible websrvs -m cron -a "name='backup mysql' state=absent" ansible websrvs -m cron -a 'state=absent name=Synctime'
yum
ansible websrvs -m yum -a ‘name=httpd state=present’ #安装 ansible websrvs -m yum -a ‘name=httpd state=absent’ #删除
service
ansible all -m service -a 'name=httpd state=started enabled=yes' ansible all -m service -a 'name=httpd state=stopped' ansible all -m service -a 'name=httpd state=reloaded’ ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf" ansible all -m service -a 'name=httpd state=restarted'
user
#创建用户 ansible all -m user -a 'name=user1 comment=“test user” uid=2048 home=/app/user1 group=root' ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx groups="root,daemon" shell=/sbin/nologin system=yes create_home=no home=/data/nginx non_unique=yes' #删除用户及家目录等数据 ansible all -m user -a 'name=nginx state=absent remove=yes'
group
#创建组 ansible websrvs -m group -a 'name=nginx gid=88 system=yes' #删除组 ansible websrvs -m group -a 'name=nginx state=absent'
lineinfile
ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换
功能:相当于sed,可以修改文件内容
ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=enforcing'" ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'
replace
该模块有点类似于sed命令,主要也是基于正则进行匹配和替换
ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'" ansible all -m replace -a "path=/etc/fstab regexp='^#(.*)' replace='\1'"
setup
功能: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度
可以使用 gather_facts: no 来禁止 Ansible 收集 facts 信息
[root@ansible01 ~]# ansible test -m setup 10.1.10.72 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "10.1.10.72" ],
[root@ansible01 ~]# ansible test -m setup -a 'filter=ansible_all_ipv4_addresses' 10.1.10.72 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "10.1.10.72" ], "discovered_interpreter_python": "/usr/bin/python" }, "changed": false }
##
Ansible常用模块详解 – 运维派 (yunweipai.com)
Ansible常用模块介绍_pushiqiang的博客-CSDN博客_ansible模块介绍
ansible 常用模块 - 一只宅男的自我修养 - 博客园 (cnblogs.com)
5.playbook
5.1.yaml语言
YAML是一种可读性高的,用来表达资料序列的格式
三种常见的数据格式
-
XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置
-
JSON:JavaScript Object Notation, JavaScript 对象表记法,主要用来数据交换或配置,不支持注释
-
YAML:YAML Ain’t Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感,不支持tab
可以用工具互相转换,参考网站:
http://www.bejson.com/json/json2yaml/
ansible-vault
用于加密yml文件
ansible-vault [create|decrypt|edit|encrypt|rekey|view]
ansible-vault encrypt hello.yml #加密 ansible-vault decrypt hello.yml #解密 ansible-vault view hello.yml #查看 ansible-vault edit hello.yml #编辑加密文件 ansible-vault rekey hello.yml #修改口令 ansible-vault create new.yml #创建新文件
5.1.1.YAML语法
-
在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾
-
次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
-
使用#号注释代码
-
缩进必须是统一的,不能空格和tab混用
-
缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
YAML文件内容是区别大小写的,key/value的值均需大小写敏感
-
多个key/value可同行写也可换行写,同行使用,分隔
-
v可是个字符串,也可是另一个列表
-
一个完整的代码块功能需最少元素需包括 name 和 task
-
一个name只能包括一个task
-
YAML文件扩展名通常为yml或yaml
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔
5.1.2.list
列表由多个元素组成,每个元素放在不同行,且元素前均使用“-”打头,或者将所有元素用 [ ] 括起来放在同一行
# A list of tasty fruits - Apple - Orange - Strawberry - Mango [Apple,Orange,Strawberry,Mango]
5.1.3.Dictionary字典
字典由多个key与value构成,key和value之间用 :分隔,所有k/v可以放在一行,或者每个 k/v 分别放在不同行
# An employee record name: Example Developer job: Developer skill: Elite 也可以将key:value放置于{}中进行表示,用,分隔多个key:value # An employee record {name: “Example Developer”, job: “Developer”, skill: “Elite”} 或 name: John Smith age: 41 gender: Male spouse: name: Jane Smith age: 37 gender: Female children: - name: Jimmy Smith age: 17 gender: Male - name: Jenny Smith age 13 gender: Female
5.2.核心元素
-
Hosts 执行的远程主机列表
-
Tasks 任务集
-
Variables 内置变量或自定义变量在playbook中调用
-
Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
-
Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
-
tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
5.2.1.hosts
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
one.example.com one.example.com:two.example.com 192.168.1.50 192.168.1.* Websrvs:dbsrvs #或者,两个组的并集 Websrvs:&dbsrvs #与,两个组的交集 webservers:!phoenix #在websrvs组,但不在dbsrvs组 举例: - hosts: websrvs:appsrvs
5.2.2.remote_user
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs remote_user: root tasks: - name: test connection ping: remote_user: magedu sudo: yes #默认sudo为root sudo_user:wang #sudo为wang
5.2.3.task列表
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出
task两种格式:
(1) action: module arguments
(2) module: arguments 建议使用
注意:shell和command模块后面跟命令,而非key=value
--- - hosts: websrvs remote_user: root tasks: - name: install httpd yum: name=httpd - name: start httpd service: name=httpd state=started enabled=yes
5.2.4.notify和handlers
某任务的状态在运行后为changed时,可通过'notify'通知给相应的'handlers'
- name: template configuration file template: src=template.j2 dest=/etc/foo.conf notify: - restart memcached - restart apache handlers: - name: restart memcached service: name=memcached state=restarted - name: restart apache service: name=apache state=restarted
5.2.5.tags
任务可以通过'tags'打标签,可在ansible-playbook命令上使用 -t 指定进行调用
--- - hosts: test70 remote_user: root tasks: - name: task1 file: path: /testdir/t1 state: touch tags: t1 - name: task2 file: path=/testdir/t2 state=touch tags: t2 - name: task3 file: path=/testdir/t3 state=touch tags: t3
5.3.变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:
variable=value
范例:
http_port=80
变量调用方式:
通过{{ variable_name }} 调用变量,且变量名前后建议加空格,有时用“{{ variable_name }}”才生效
变量来源:
5.3.1.ansible 的 setup facts 远程主机的所有变量都可直接调用
--- #var.yml - hosts: all remote_user: root gather_facts: yes tasks: - name: create log file file: name=/data/{{ ansible_nodename }}.log state=touch owner=wang mode=600 ansible-playbook var.yml
5.3.2.通过命令行指定变量,优先级最高
vim var2.yml --- - hosts: websrvs remote_user: root tasks: - name: install package yum: name={{ pkname }} state=present ansible-playbook –e pkname=httpd var2.yml
5.3.3.在playbook文件中定义
vim var3.yml --- - hosts: websrvs remote_user: root vars: - username: user1 - groupname: group1 tasks: - name: create group group: name={{ groupname }} state=present - name: create user user: name={{ username }} group={{ groupname }} state=present ansible-playbook -e "username=user2 groupname=group2” var3.yml
5.3.4.在独立的变量YAML文件中定义
可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比playbook中定义的变量优化级高
cat vars2.yml --- var1: httpd var2: nginx cat var5.yml --- - hosts: web remote_user: root vars_files: - vars2.yml tasks: - name: create httpd log file: name=/app/{{ var1 }}.log state=touch - name: create nginx log file: name=/app/{{ var2 }}.log state=touch
5.3.5.主机清单文件中定义变量
主机变量
在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用
[websrvs] www1.magedu.com http_port=80 maxRequestsPerChild=808 www2.magedu.com http_port=8080 maxRequestsPerChild=909
组(公共)变量
在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是同名,优先级低于主机变量
[websrvs] www1.magedu.com www2.magedu.com [websrvs:vars] ntp_server=ntp.magedu.com nfs_server=nfs.magedu.com
调用
vim /etc/ansible/hosts [websrvs] 192.168.0.101 hname=www1 domain=magedu.io 192.168.0.102 hname=www2 [websvrs:vars] mark=“-” domain=magedu.org ansible websvrs –m hostname –a ‘name={{ hname }}{{ mark }}{{ domain }}’ bash #命令行指定变量: ansible websvrs –e domain=magedu.cn –m hostname –a ‘name={{ hname }}{{ mark }}{{ domain }}’
5.4.when
when语句,可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式
--- - hosts: websrvs remote_user: root tasks: - name: "shutdown RedHat flavored systems" command: /sbin/shutdown -h now when: ansible_os_family == "RedHat"
--- - hosts: websrvs remote_user: root tasks: - name: install conf file to centos7 template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf when: ansible_distribution_major_version == "7" - name: install conf file to centos6 template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf when: ansible_distribution_major_version == "6"
--- - hosts: websrvs remote_user: root tasks: - name: add group nginx tags: user user: name=nginx state=present - name: add user nginx user: name=nginx state=present group=nginx - name: Install Nginx yum: name=nginx state=present - name: restart Nginx service: name=nginx state=restarted when: ansible_distribution_major_version == “6”
5.5.with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为"item"
要在task中使用with_items给定要迭代的元素列表
列表元素格式:
字符串
字典
--- - hosts: websrvs remote_user: root tasks: - name: add several users user: name={{ item }} state=present groups=wheel with_items: - testuser1 - testuser2 #上面语句的功能等同于下面的语句 - name: add user testuser1 user: name=testuser1 state=present groups=wheel - name: add user testuser2 user: name=testuser2 state=present groups=wheel
--- #remove mariadb server - hosts: appsrvs:!192.168.38.8 remote_user: root tasks: - name: stop service shell: /etc/init.d/mysqld stop - name: delete files and dir file: path={{item}} state=absent with_items: - /usr/local/mysql - /usr/local/mariadb-10.2.27-linux-x86_64 - /etc/init.d/mysqld - /etc/profile.d/mysql.sh - /etc/my.cnf - /data/mysql - name: delete user user: name=mysql state=absent remove=yes
--- - hosts:websrvs remote_user: root tasks - name: install some packages yum: name={{ item }} state=present with_items: - nginx - memcached - php-fpm
--- - hosts: websrvs remote_user: root tasks: - name: copy file copy: src={{ item }} dest=/tmp/{{ item }} with_items: - file1 - file2 - file3 - name: yum install httpd yum: name={{ item }} state=present with_items: - apr - apr-util - httpd
迭代嵌套子变量:
在迭代中,还可以嵌套子变量,关联多个变量在一起使用
--- - hosts: websrvs remote_user: root tasks: - name: add some groups group: name={{ item }} state=present with_items: - nginx - mysql - apache - name: add some users user: name={{ item.name }} group={{ item.group }} state=present with_items: - { name: 'nginx', group: 'nginx' } - { name: 'mysql', group: 'mysql' } - { name: 'apache', group: 'apache' }
--- - hosts: websrvs remote_user: root tasks: - name: add some groups group: name={{ item }} state=present with_items: - g1 - g2 - g3 - name: add some users user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=present with_items: - { name: 'user1', group: 'g1', home: '/data/user1' } - { name: 'user2', group: 'g2', home: '/data/user2' } - { name: 'user3', group: 'g3', home: '/data/user3' }
5.6.template
模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja语法
5.4.1.jinjia2语言
jinja2 语言使用字面量,有下面形式:
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, …]
元组:(item1, item2, …)
字典:{key1:value1, key2:value2, …}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When
字面量:
表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如“Hello World”
双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如42,42.23
数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不一样的
算术运算:
Jinja 允许用计算值。支持下面的运算符
+:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2
-:用第一个数减去第二个数。 {{ 3 – 2 }} 等于 1
/:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }}
//:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2
%:计算整数除法的余数。 {{ 11 % 7 }} 等于 4
:用右边的数乘左边的操作数。 {{ 2 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ 80 }} 会打印 80 个等号的横条\
*:取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8
比较操作符
== 比较两个对象是否相等
!= 比较两个对象是否不等
如果左边大于右边,返回 true
= 如果左边大于等于右边,返回 true
< 如果左边小于右边,返回 true
<= 如果左边小于等于右边,返回 true
逻辑运算符
对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
and 如果左操作数和右操作数同为真,返回 true
or 如果左操作数和右操作数有一个为真,返回 true
not 对一个表达式取反
(expr)表达式组
true / false true 永远是 true ,而 false 始终是 false
##
5.4.2.template使用
template功能:可以根据和参考模块文件,动态生成相类似的配置文件
template文件必须存放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
#修改文件nginx.conf.j2 mkdir templates vim templates/nginx.conf.j2 worker_processes {{ ansible_processor_vcpus }}; vim temnginx2.yml --- - hosts: websrvs remote_user: root tasks: - name: install nginx yum: name=nginx - name: template config to remote hosts template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf - name: start service service: name=nginx state=started enable=yes ansible-playbook temnginx2.yml
5.4.3.算术运算
[root@ansible ansible]#vim templates/nginx.conf.j2 worker_processes {{ ansible_processor_vcpus**3 }}; [root@ansible ansible]#cat templnginx.yml --- - hosts: websrvs remote_user: root tasks: - name: install nginx yum: name=nginx - name: template config to remote hosts template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf notify: restart nginx - name: start service service: name=nginx state=started enabled=yes handlers: - name: restart nginx service: name=nginx state=restarted ansible-playbook templnginx.yml --limit 10.0.0.8
5.4.4.template中使用流程控制 for 和 if
template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能
## for
#temlnginx2.yml --- - hosts: websrvs remote_user: root vars: nginx_vhosts: - 81 - 82 - 83 tasks: - name: template config template: src=nginx.conf.j2 dest=/data/nginx.conf #templates/nginx.conf2.j2 {% for vhost in nginx_vhosts %} server { listen {{ vhost }} } {% endfor %} ansible-playbook -C templnginx2.yml --limit 10.0.0.8 #生成的结果: server { listen 81 } server { listen 82 } server { listen 83 }
#temlnginx3.yml --- - hosts: websrvs remote_user: root vars: nginx_vhosts: - listen: 8080 tasks: - name: config file template: src=nginx.conf3.j2 dest=/data/nginx3.conf #templates/nginx.conf3.j2 {% for vhost in nginx_vhosts %} server { listen {{ vhost.listen }} } {% endfor %} ansible-playbook templnginx3.yml --limit 10.0.0.8 #生成的结果 server { listen 8080 }
#templnginx4.yml - hosts: websrvs remote_user: root vars: nginx_vhosts: - listen: 8080 server_name: "web1.magedu.com" root: "/var/www/nginx/web1/" - listen: 8081 server_name: "web2.magedu.com" root: "/var/www/nginx/web2/" - {listen: 8082, server_name: "web3.magedu.com", root: "/var/www/nginx/web3/"} tasks: - name: template config template: src=nginx.conf4.j2 dest=/data/nginx4.conf # templates/nginx.conf4.j2 {% for vhost in nginx_vhosts %} server { listen {{ vhost.listen }} server_name {{ vhost.server_name }} root {{ vhost.root }} } {% endfor %} ansible-playbook templnginx4.yml --limit 10.0.0.8 #生成结果: server { listen 8080 server_name web1.magedu.com root /var/www/nginx/web1/ } server { listen 8081 server_name web2.magedu.com root /var/www/nginx/web2/ } server { listen 8082 server_name web3.magedu.com root /var/www/nginx/web3/ }
在模版文件中还可以使用 if条件判断,决定是否生成相关的配置信息
## if
#templnginx5.yml - hosts: websrvs remote_user: root vars: nginx_vhosts: - web1: listen: 8080 root: "/var/www/nginx/web1/" - web2: listen: 8080 server_name: "web2.magedu.com" root: "/var/www/nginx/web2/" - web3: listen: 8080 server_name: "web3.magedu.com" root: "/var/www/nginx/web3/" tasks: - name: template config to template: src=nginx.conf5.j2 dest=/data/nginx5.conf #templates/nginx.conf5.j2 {% for vhost in nginx_vhosts %} server { listen {{ vhost.listen }} {% if vhost.server_name is defined %} server_name {{ vhost.server_name }} {% endif %} root {{ vhost.root }} } {% endfor %} #生成的结果 server { listen 8080 root /var/www/nginx/web1/ } server { listen 8080 server_name web2.magedu.com root /var/www/nginx/web2/ } server { listen 8080 server_name web3.magedu.com root /var/www/nginx/web3/ }
6.roles
6.1.使用ansible-galaxy下载共享的roles和collection
ansible-galaxy — Ansible Documentation
ansible-galaxy list ansible-galaxy install geerlingguy.redis ansible-galaxy remove geerlingguy.redis
[root@ansible01 ~]# ansible-galaxy collection install community.postgresql Process install dependency map Starting collection install process Installing 'community.postgresql:1.4.0' to '/root/.ansible/collections/ansible_collections/community/postgresql'
6.2.roles目录结构
playbook.yml roles/ project/ ## 项目名称,有以下子目录 tasks/ ## 定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含 files/ ## 存放由copy或script模块等调用的文件 vars/ ## 定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含 templates/ ## template模块查找所需要模板文件的目录 handlers/ ## 至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含 default/ ## 设定默认变量时使用此目录中的main.yml文件,比vars的优先级低 meta/ ## 定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
6.2.1.创建role的步骤
(1) 创建以roles命名的目录
(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等
(3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建
(4) 在playbook文件中,调用各角色
针对大型项目使用Roles进行编排
nginx-role.yml roles/ └── nginx ├── files │ └── main.yml ├── tasks │ ├── groupadd.yml │ ├── install.yml │ ├── main.yml │ ├── restart.yml │ └── useradd.yml └── vars └── main.yml
6.2.2.playbook调用roles
--- - hosts: websrvs remote_user: root roles: - mysql - memcached - nginx
--- - hosts: all remote_user: root roles: - mysql - { role: nginx, username: nginx } ## 键role用于指定角色名称,后续的k/v用于传递变量给角色
--- - hosts: all remote_user: root roles: - { role: nginx, username: nginx, when: ansible_distribution_major_version == ‘7’ } ## 基于条件测试实现角色调用
--- - hosts: websrvs remote_user: root roles: - { role: nginx ,tags: [ 'nginx', 'web' ] ,when: ansible_distribution_major_version == "6“ } - { role: httpd ,tags: [ 'httpd', 'web' ] } - { role: mysql ,tags: [ 'mysql', 'db' ] } - { role: mariadb ,tags: [ 'mariadb', 'db' ] } ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml ## roles中使用tags