1. Ansible自动化运维工具
“无主从无架构,开箱即用,用完即走”
简介
- ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、 fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。
- 基于SSH协议实现远程管理,不需要代理
运维自动化应用场景
- 操作系统预备自动化
- 配置自动化
监控自动化
- 系统与应用监控
- 日志监控
- 代码持续集成与持续发布自动化
- 核心组件
- Ansible:核心组件
- Modules:包括Ansible自带的核心模块及自定义模块
- Plugins:完成模块功能的补充,包括连接插件、邮箱插件
- Playbooks:剧本;定义Ansible多任务配置文件,完成对主机批量部署操作
- Inventory:定义Ansible管理主机的清单 /etc/ansibe/hosts
- Connection Plugins:负责和被监控端实现通信
主机清单:
- 仅对主机清单内的主机列表进行操作
- 实现主机分组
- 特点
1. 不需要在被管控主机上安装任何客户端2. 无服务器端,使用时直接运行命令即可3. 基于模块工作,可使用任意语言开发模块4. 使用yaml语言定制剧本playbook,支持playbook编排任务5. 安全,基于SSH工作6. 可实现多级指挥7. 幂等性:一种操作重复多次结果相同8.模块化:调用特定模块,完成特定任务
安装和配置
#需先安装epel扩展源[root@localhost ~]# yum -y install epel-release[root@localhost ~]# yum -y install ansible[root@localhost ~]# ansibl --version #检测版本
- 常用命令集
[root@localhost ~]# rpm ‐ql ansible | grep bin/usr/bin/ansible #主程序/usr/bin/ansible‐config/usr/bin/ansible‐connection/usr/bin/ansible‐console/usr/bin/ansible‐doc #查看配置文档/usr/bin/ansible‐galaxy/usr/bin/ansible‐inventory/usr/bin/ansible‐playbook #定制自动化任务/usr/bin/ansible‐pull/usr/bin/ansible‐vault #文件加密工具######ansible:临时命令执行工具,常用于临时命令的执行ansible-doc:Ansible模块功能查看工具ansible-playbook:Ansible定制自动化的任务集编排工具
配置文件
ansible.cfg:主配置文件hosts:主机清单roles:角色目录[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 生成的临时py命令文件存放在远程主机的目录#local_tmp = ~/.ansible/tmp 本机的临时命令执行目录#forks = 5 默认的并发数#poll_interval = 15 默认的线程池#sudo_user = root 默认sudo用户#ask_sudo_pass = True 在执行sudo之前是否询问sudo密码.默认为False#ask_pass = True 每次执行ansible命令是否询问ssh密码,默认为False#transport = smart#remote_port = 22#module_lang = C#module_set_locale = False#host_ key_checking = False #检查对应服务器的host_ key ,建议取消注释。这样的话控制其他主机相连的时候就不用先ssh连一次#log_path=/var/log/ansible.log #日志文件,建议开启
主机清单
1.直接指明主机地址或主机名(需要能够解析)
2.定义一个主机组,调用的时候指定该组即可
#存储位置/etc/ansible/hosts#定义方式[root@localhost ~]# vi /etc/ansible/hosts...主机ip地址主机名[server1]www.salted1.comwww.salted2.com[server2]www.edison1.comwww.edison2.com[webserver]192.168.244.[101:103]
- ansible系列命令
[root@node1 ~]# ansible ‐doc #显示模块帮助-a #显示所有模块的文档,不建议使用-l , --list #列出可用模块-s #显示指定模块的playbook片段[root@node1 ~]# ansible <host-patern> [-m module_name] [-a args]--version #显示版本-m #指定模块,默认为command--list #显示主机列表-k,--ask-pass #提示输入ssh连接密码-K,--ask-become-pass #提示输入sudo时的口令-C ##检查,并不执行-T, --timeout = TIMEOUT #执行命令的超时时间,默认10s-u, --user = REMOTE _USER #指定远程执行的用户-b, --become #代替旧版的sudo切换
- ansible的Host-pattern
# 匹配主机列表all:表示主机清单中所有主机[root@node1 ~]# ansible all -m p通配符匹配[root@node1 ~]# ansible "*" -m ping[root@node1 ~]# ansible 192.168.244.* -m ping[root@node1 ~]# ansible "*ver" -m ping
- 命令执行过程
加载自己的配置文件 默认/etc/ansible/ansible.cfg加载自己对应的模块文件,如command通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户的家目录的 ~/.ansible/tmp/XXX/XXX.PY文件。给文件+x执行执行并返回结果删除临时py文件,sleep 0 退出
执行状态
- 绿色:执行成功并且不需要做改变的操作
- 黄色:执行成功并且对目标主机做变更
- 红色:执行失败
常用模块
- ping :检测主机间连通性
[root@localhost ~]# ansible 192.168.244.135 -m ping192.168.244.135 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"},"changed": false,"ping": "pong"}
command:默认模块可忽略
- 此命令不支持$、< >、|、;、&等符号,用shell模块
[root@localhost ~]# ansible 192.168.244.135 -m command -a "ls -l /data"[root@localhost ~]# ansible 192.168.244.135 -a "useradd lisi"
- shell:和command相似,用shell执行命令
[root@localhost ~]# ansible 192.168.244.135 -m shell -a "echo 123456 | passwd --stdin lisi"#调用bash执行命令,类似cat /etc/passwd | awk -F '{print $1,$2}' &> /tmp/data 这些复杂命令,即使使用shell也可能失败。解决办法:写到脚本里面然后copy到远程再执行
- script:运行脚本
-m script -a 'PATH/To/script_file'[root@localhost ~]# ansible 192.168.244.135 -m script -a '/root/test1.sh'
- copy:从服务器复制文件到远程客户端
[root@localhost ~]# ansible all -m copy -a 'src=/etc/hosts dest=/etc/hosts '选项owner = #用户mode = #权限backup = yes/no #如果目标文件存在,默认覆盖然后备份利用内容直接生成目标文件[root@localhost ~]# ansible all -m copy -a 'content="test content\n" dest=/data/test1.txt '
fetch:从客户端取文件至服务端,与copy相反,目录可先tar再获取
- 只能抓一个文件
[root@localhost ~]# ansible all -m fetch -a "src=/root/test1.sh dest=/data/scripts"打包多个文件[root@localhost ~]# ansible all -m shell -a "tar jcf log.tar.xz /var/log/*.log"[root@localhost ~]# ansible all -m fetch -a "src=/root/log.tar.xz dest=/data"
- file:对文件操作,设置文件属性
[root@localhost ~]# ansible all -m file -a "path=/root/test1.sh owner=lisi mode=777"创建软链接文件[root@localhost ~]# ansible all -m file -a "src=/data/test1 dest=/data/test1.link state=link"state:属性(link软链接)创建空文件[root@localhost ~]# ansible all -m file -a "name=/data/test2 state=touch"删除文件[root@localhost ~]# ansible all -m file -a "name=/data/test1 state=absent"创建目录[root@localhost ~]# ansible all -m file -a "name=/data/dir1 state=directory"删除目录[root@localhost ~]# ansible all -m file -a "name=/data/dir1 state=absent"
hostname:修改主机名
- 但是/etc/hosts的主机名没修改成功
[root@localhost ~]# ansible 192.168.244.101 -m hostname -a "name=node1"
cron:计划任务
- 支持分时日月周
创建任务#每周1,3,5的每分钟警告一次[root@localhost ~]# ansible all -m cron -a "minute=* weekday=1,3,5 job='/usr/bin/wall FBI warning' name=warning "删除任务[root@localhost ~]# ansible all -m cron -a "job='/usr/bin/wall FBI warning' name=warning state=absent"注释任务[root@localhost ~]# ansible all -m cron -a "disabled=yes/True job='usr/bin/wall FBI warning' name=warning"取消注释[root@localhost ~]# ansible all -m cron -a "disabled=no/False job='usr/bin/wall FBI warning' name=warning"
- yum:管理包
[root@localhost ~]# ansible 192.168.244.101 -m yum -a "name=httpd update_cache=yes"
- service:管理服务
[root@localhost ~]# ansible all -m service -a "name=httpd state=started enabled=yes "enabled:开机自启动[root@localhost ~]# ansible all -m service -a "name=httpd state=stopped enabled=no "
- user:管理用户
创建用户[root@localhost ~]# ansible 192.168.244.101 -m user -a "name=nginx shell=/sbin/nologin system=yes home=/var/nginx groups=root,bin uid=80 comment='nginx server'"system:是否为系统用户shell:指定shellhome:指定家目录group:主组groups:指定附家组comment:注释删除用户[root@localhost ~]# ansible 192.168.244.101 -m user -a"name=nginx state=absent remove=yes"remove:删除用户的时候删除家目录数据
- group:管理组
创建组[root@localhost ~]# ansible 192.168.244.101 -m group -a "name=testgroup system=yes"删除组[root@localhost ~]# ansible 192.168.244.101 -m group -a "name=testgroup state=absent"
ansible系列命令
ansible-galaxy
- 列出所有已安装的galaxyansible-galaxy list- 安装galaxyansible-galaxy install geerlingguy.redis- 删除galaxyansible-galaxy remove geerlingguy.redis
ansible-pull
推送命令至远程主机,效率无限提升,对运维要求较高
ansible-playbook剧本
ansible-vault
- 管理,加密,解密yml文件
加密yml文件(加密后不能直接运行,得先解密)
[root@localhost ~]#ansible-vault encrypt hello.yml
解密
[root@localhost ~]#ansible-vault decrypt hello.yml
查看加密文件
[root@localhost ~]#ansible-vault view hello.yml
编辑加密文件
[root@localhost ~]#ansible-vault edit hello.yml
修改口令
[root@localhost ~]#ansible-vault rekey hello.yml
创建新的加密yml文件
[root@localhost ~]#ansible-vault rekey new.yml
ansible-console
- 交互式执行命令
- 支持tab
root@test (2)[f:10] $
#执行用户@当前操作的主机组(当前组的主机数量)[f:并发数]$
#设置并发数: forks n 例如: forks 10
#切换组:cd 主机组例如:cd web
#列出当前组主机列表: list
#列出所有的内置命令: ?或help
示例:
root@all (2)[f:5]$ list
root@all (2)[f:5]$ cd webservers
root@appsrvs (2)[f:5]$ forks 10
root@appsrvs (2)[f:5]$ list
root@appsrvs (2)[f:5]$ yum name=httpd state=present
root@appsrvs (2)[f:5]$ service name=httpd state=started
2. playbook剧本
- 由一个或多个”paly”组成的列表,采用YAML语言编写
- 相当于脚本,ansible单条命令的集合(模块的集合)
- 主要功能:将事先归并为一组的主机装扮成task定义好的角色,所谓task不过是调用ansible的一个个module
ansible playbook执行过程:
- 将以编排好的任务集写进playbook
- 通过ansible-playbook命令分拆任务集逐条执行ansible命令,按预定规则逐条执行
格式:
[root@localhost ~]# vi hello.yml
---
- hosts:webservers
remote_user: root #指定远程登录用户
tasks:
- name: hello
command: hostname
[root@localhost ~]#ansible-palybook hello.yml
运行palybook
[root@localhost ~]#ansible-palybook hello.yml
-C --check:只检测,不真正执行
--list-hosts:列出运行任务的主机
--limit:主机列表 只针对主机列表中的主机执行
-v:显示过程 -vv,-vvv 更详细
[root@localhost ~]# ansible-playbook -C file.yml 只检测
[root@localhost ~]# ansible-playbook file.yml
[root@localhost ~]# ansible-playbook file.yml --limit websrvs
YAML语言
YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括: XML、C语言、Python、 Perl以及电子邮件格式RFC2822等。 Clark Evans在2001年在首次发表了这种语言,另外Ingy dot Net与Oren Ben-Kiki也是这语言的共同设计者
YAML Ain’t Markup Language ,即YAML不是XML。不过,在开发的这种语言时, YAML的意思其实是: “Yet Another Markup Language” (仍是一种标记语言)特性:
- YAML的可读性好
- YAML和脚本语言的交互性好
- YAML使用实现语言的数据类型
- YAML有一个致的信息模型
- YAML易于实现
- YAML可以基于流来处理
- YAML表达能力强,扩展性好
更多的内容及规范参见http://www.yaml.org
语法简介
1.在单一档案中,可用连续三个连字号(-)区分多个档案。 另外,还有选择性的连续三个点号( ... )用来表示档案结尾
2.次行开始正常写Playbook的内容, -般建议写明该Playbook的功能
3.使用#号注释代码
4.缩进必须是统一的 ,不能空格和tab混用
5.缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
6.YAML文件内容和Linux系统大小写判断方式保持一致,是区别大小写的, k/v的值均需大小写敏感
7.k/v的值可同行写也可换行写。同行使用:分隔
8.v可是个字符串,也可是另一一个列表
9.一个完整的代码块功能需最少元素需包括name: task
10.一个name只能包括一个task
11.YAML文件扩展名通常为yml或yaml
list:列表,其所有元素均使用"-"打头
dictionar:字典,通常由多个key与value构成
#YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构( Structure )通过空格来展示,序列( Sequence )里的项用"-"来代表, Map里的键值对用":"分隔
核心元素
hosts:执行的远程主机列表
- playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户
身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清
单中
- playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户
tasks:任务列表
解决2: tasks: -name: 忽略错误信息 shell: command ignore_errors: True
-
Varniables内置变量或自定义变量在playbook中调用
-
Templates模板,可替换模板文件中的变量并实现一些简单逻辑的文件
-
Handlers和notity结合使用,由特定条件触发的操作,满足条件方才执行,否<br />
则不执行
-
tags标签指定某条任务执行,用于选择运行playbook中的部分代码。ansible<br />
具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其<br />
确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可<br />
以通过tags跳过此些代码片断<br />
ansible-playbook -t tagsname useradd.yml
```bash
[root@ansible ~]# vim test.yml
---
- hosts: websrvs
remote_ user: root
tasks :
- name: create newfile
file: name=/ data/newfile state=touch
- name: create new user
user: name-test2 system=yes shell=/ sbin/nologin
- name: instal1 httpd service
yum: name=httpd
- name: copy index.html
copy: src=/var/www/htm1/index.html dest=/var/www/htm1/
- name: copy test.html
copy: src=/var/www/htm1/test.html dest=/var/www/htm1/
- name: start service
service: name=httpd state=started enabled=yes
##复制文件一次只能复制一个
[root@ansible ~]# ansible-playbook -C test.yml
[root@ansible ~]# ansible-playbook test.yml
palybook案例
初始化服务端和客户端
- 一台ansible主机,三台受控机node1,node2,node3
安装ansible
[root@ansible ~]# yum install epel-release ##我的主机已经都配备拓展源,不需要下载
[root@ansible ~]# yum install -y ansible
设置主机清单
[root@ansible ~]# vim /etc/ansible/hosts
[webserver]
192.168.244.135
192.168.244.139
192.168.244.141
在ansible管理节点(即安装ansible的节点)上添加目标节点(即需要管理的节点)的ssh认证信息
[root@ansible ~]# ssh-keygen
[root@ansible ~]# ssh-copy-id 192.168.244.135
[root@ansible ~]# ssh-copy-id 192.168.244.139
[root@ansible ~]# ssh-copy-id 192.168.244.141
修改ansible主配置文件,使得第一次连接不用检查密钥
开启日志
[root@ansible ~]# vim /etc/ansible/ansible.cfg
host_key_checking = False
[root@ansible ~]# vim /etc/ansible/ansible.cfg
log_path=/var/log/ansible.log #日志文件,建议开启
验证连通性
[root@ansible ~]# ansible all -m ping
编写剧本
[root@ansible ~]# vim test.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create new directory
file: name=/data state=directory
- name: create new file
file: name=/data/test1 state=touch
- name: create new user
user: name=lisi shell=/sbin/nologin system=yes
- name: install vsftpd
yum: name=vsftpd
- name: start service
service: name=vsftpd state=started enabled=yes
测试并执行
[root@ansible ~]# ansible-playbook -C test.yml
[root@ansible ~]# ansible-playbook test.yml
3. 企业级使用playbook
handlers和notify
- handlers和notify结合使用触发条件
handlers(触发器)
- 是task列表,只有当关注的资源发生变化时,才会采取相应的操作
notify
- 与handlers配套使用。调用handlers中的定义的操作
- 此action可用于在每个paly的最后被触发,可以避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作
触发一个
案例
- 给多台web服务器安装apache服务并将主控机配置文件复制过去
- 主控机配置文件修改过后发送给被控机并让他重启httpd服务使得他配置文件生效
[root@ansible ~]# vim httpd.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd
- name: copy config file
file: src=/etc/httpd/httpd.conf dest=/etc/httpd/ backup=yes
notify: restart service
- name: service start
service: name=httpd state=started enabled=yes
handlers:
- name: restart service
service: name=httpd state=restarted
触发多个
[root@ansible ~]# vim httpd.yml
---
- host: webserver
remote_user: root
tasks:
- name: add group nginx
group: name=nginx
tags: group
- name: add user nginx
user: name=nginx group=nginx
- name: install nginx
yum: name=nginx enabled=yes
- name: copy conf
file: src=/root/conf.txt dest=/etc/nginx/nginx.conf
notify:
- restart nginx
- check nginx process
handlers:
- name: restart nginx
service: name=nginx state=restarted
- name: check nginx process
shell: killall -0 nginx > /tmp/nginx.log
tags
- 标签,可以使我们执行playbook里面指定标签里的内容
- 多个动作可以使用相同的标签
[root@ansible ~]# vim tags.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd
tags: httpdservice
- name: copy config file
flie: src=/etc/httpd/httpd.conf dest=/etc/httpd/httpd.conf
notify: restart httpd service
- name: start service
service: name=httpd state=started enabled=yes
tags: httpdservice
handlers:
- name: restart httpd service
service: name=httpd state=restarted
[root@ansible ~]# ansible-palybook -t httpdservice httpd.yml
变量的使用
变量名:仅由字母,数字和下划线组成,只能以数字开头
变量来源
ansible setup facts 远程主机的所有变量都可以直接调用
在/etc/ansible/hosts定义
- 普通变量:主机组中的主机单独定义,优先级高于公共变量
- 公共变量(组变量):针对主机分组中的所有主机定义统一变量
通过命令行指定变量:ansible-palybook -e varname=value
在palybook中定义 ``` vars:
- var1: value1
- var2: value2 ```
- 在role中定义
命令优先级:命令行变量>普通变量>主机变量
独立的YML文件来专门存放定义的变量,便于维护
##建立存放变量文件
[root@ansible ~]# vim vars.yml
var1: httpd
var2: vsftpd
##调用变量文件
[root@ansible ~]# vim test_var.yml
---
- hosts: werbserver
remote_user: root
vars_files:
- vars.yml
tasks:
- name: install package
yum: name={{ var1 }}
- name: install package
yum: name={{ var2 }}
- 查看远程主机变量
[root@ansible ~]# ansible webserver -m setup -a "filter=ansible_hostname"
filter: 过滤工具,支持通配符
[root@ansible ~]# anisble webserver -m setup -a "filter=*address*"
#将远程变量写进playbook
[root@ansible ansible]# ansible all -m setup -a "filter=ansible_fqdn"
[root@ansible ansible]# vim vars.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: copy file
file: name=/root/{{ ansible_fqdn }}.log state=touch
[root@ansible ansible]# ansible-playbook vars.yml
[root@node1 ~]# ls
anaconda-ks.cfg node1.log
[root@node2 ~]#
[root@node2 ~]# ls
anaconda-ks.cfg auth.smb node2.log
- 在playbook里设置变量
#设置单个变量
[root@ansible ~]# vim test.yml
---
- hosts: werbserver
remote_user: root
tasks:
- name: install package
yum: name={{ varname }}
- name: start service
service: name={{ varname }} state=started
[root@ansible ~]# anisble-palybook webserver -e 'varname=httpd' test.yml
#设置多个变量
[root@ansible ~]# vim test1.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name={{ varname1 }}
- name: install package
yum: name={{ varname2 }}
[root@ansible ~]# anisble-palybook webserver -e 'varname1=httpd varname2=vsftpd' test.yml
#设置变量组
[root@ansible ~]# vim test2.yml
---
- hosts: werbserver
remote_user: root
vars:
- varname1: httpd
- varname2: vsftpd
tasks:
- name: install package
yum: name={{ varname1 }}
- name: install package
yum: name={{ varname2 }}
[root@ansible ~]# anisble-palybook webserver test.yml
- 设置普通变量和公共变量
#普通变量
[root@ansible ~]# vim /etc/ansible/hosts
[webserver]
192.168.244.100 http_port=81
192.168.244.101 http_port=82
[root@ansible ~]# vim test.yml
---
- hosts:webserver
remote_user: root
tasks:
- name: set hostname
hostname: name=www{{ http_port }}.com
#公共变量
[webserver]
192.168.244.100 http_port=81
192.168.244.101 http_port=82
[werserver:vars]
nodenmae=www
domainname=edu.com
[root@ansible ~]# vim test.yml
---
- hosts:webserver
remote_user: root
tasks:
- name: set hostname
hostname: name={{ nodename }}{{ http_port }}.{{ domainname }}
4. template管理nginx配置文件
template 模板
- 文本文件(使用模板编程语言编写)
jinjia2语言
- 数字(int,float)列表,元组,字典,布尔型
- 算数运算
- 比较操作
- 逻辑运算
- 流程控制
特点:
- 只能用于playbook,不能作为单条命令被调用
- 根据被控机当前系统状态来生成对应配置
案例1:
woker进程数量默认是自动,会根据主机cpu数量生成不同的worker进程数。考虑到客户机的cpu数量不一样,如果单纯的用copy模块将服务器的配置文件复制过去是行不通的,我们要用到template模块。
根据不同被控机的cpu数量产生不同的worker数
- 服务器下载nginx
[root@ansible ansible]# yum install -y nginx
[root@ansible ansible]# systemct1 start nginx
[root@ansible ansible]# ps aux | grep nginx
- 服务器创建文件夹(建议与playbook平级)
[root@ansible ansible]# mkdir templates
[root@ansible ansible]# ls
ansible.cfg data hosts roles templates vars.yml
- 将nginx配置文件复制到templates目录下
[root@ansible ansible]# cp /etc/nginx/nginx.conf templates/nginx.conf.j2
##注意后缀名要改为j2
- 编写palybook并执行
#node1节点cpu数量为1
#node2节点cpu数量为2
[root@ansible ansible]# cat test_template.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: install package
yum: name=nginx
- name: copy template
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart service
- name: start service
service: name=nginx state=started enabled=yes
tags: startservice
handlers:
- name: restart service
service: name=nginx state=restarted
[root@ansible ansible]# ansible-playbook test_template.yml
案例2
都是nginx服务,不同主机nginx端口号不同
node1:81
node2:82
定义各自的端口变量(主机变量)
[webserver]
192.168.244.141 http_port=8080
192.168.244.135 http_port=9090
- 修改templates下nginx配置文件
[root@ansible ansible]# vim templates/nginx.conf.j2
....
server {
listen {{ http_port }} default_server;
listen [::]:{{ http_port }} default_server;
....
- 执行playbook
[root@ansible ansible]# ansible-playbook test_template.yml
- 查看不同节点的http端口号
when
- 条件测试条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与
否的前提时要用到条件测试,通过when语句实现,在task中使用, jinja2的语法
格式 when语句
- 在task后添加when子句即可使用条件测试; when语句支持Jinja2表达式语法
示例:
tasks:
name: " shutdown RedHat flavored systems"
command: /sbin/shutdown -h now
when: ansible_ os_ family == "RedHat"
迭代:with_items
- 当有需要重复性执行的任务时,可以使用迭代机制
- 对迭代项的引用,固定变量名为{{ item }}
- 要在task中使用with_ items给定要迭代的元素列表
- 列表格式:
字符串
字典
利用迭代创建多个文件
[root@ansible ansible]# vim test_item.yml
---
- host: webserver
remote_user: root
tasks:
- name: create some files
file: name=/data/{{ item }} state=touch
with_items:
- file1
- file2
- file3
迭代加上when判断
[root@ansible ansible]# vim test_item.yml
---
- host: webserver
remote_user: root
tasks:
- name: create some files
file: name=/data/{{ item }} state=touch
when:ansible_distribution_major_version == '7'
with_items:
- file1
- file2
- file3
迭代安装多个包
[root@ansible ansible]# vim test_item.yml
---
- host: webserver
remote_user: root
tasks:
- name: install package
yum: name={{ item }}
with_items:
- htop
- sl
- hping3
迭代嵌套子变量
迭代创建组创建用户,添加到不同的组中
[root@localhost ansible]# cat test_item.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: create some group
group: name={{ item }}
with_items:
- g1
- g2
- g3
- name: create some user
user: name={{ item.name }} group={{ item.group }}
with_items:
- {name: "user1" , group: "g1"}
- {name: "user2" , group: "g2"}
- {name: "user3" , group: "g3"}
for循环、if语句
for循环 实现创建一个文件里面循环生成配置信息
- yml文件
---
- hosts: webserver
remote_user: root
vars:
ports:
- 81
- 82
- 83
tasks:
- name: copy template conf
template: src=for1.conf.j2 dest=/data/for1.conf
##或者
---
- hosts: webserver
remote_user: root
vars:
ports:
- listen_port: 81
- listen_port: 82
- listen_port: 83
tasks:
- name: copy template conf
template: src=for1.conf.j2 dest=/data/for1.conf
- 实现for循环的文件
[root@ansible templates]# cat for1.conf.j2
{% for p in ports% }
server{
listen {{ p }}
}
{% endfor %}
##或者
{% for p in ports %}
server{
listen {{ p.listen_port }}
}
{% endfor %}
- 多个键值对.yml
---
- hosts: webserver
remote_user: root
vars:
ports:
- web1:
port:81
name:web1.com
- web2:
port:82
name:web2.com
- web3:
port:83
name:web3.com
tasks:
- name: copy template conf
template: src=for1.conf.j2 dest=/data/for1.conf
- 实现for循环的文件
{% for p in ports %}
server{
listen {{ p.port }}
servername {{ p.name }}
}
{% endfor %}
if嵌套在for循环里面用于条件判断
if条件:变量是否已定义
- yml文件
只有web2变量的name定义
---
- hosts: webserver
remote_user: root
vars:
ports:
- web1:
port:81
#name:web1.com
- web2:
port:82
name:web2.com
- web3:
port:83
#name:web3.com
tasks:
- name: copy template conf
template: src=for1.conf.j2 dest=/data/for1.conf
{% for p in ports %}
server{
listen {{ p.port }}
{% if p.name is defined %}
servername {{ p.name }}
{% endif %}
}
{% endfor %}
5. Roles
- 简单来讲,roles就是通过分别将变量、文件、任务、模板及handlers放置于单独的目录中,并可以便捷地include去调用它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
- 复杂场景:建议使用roles ,代码复用度高
特点:
- 变更指定主机或主机组时,建议使用roles
- 如命名不规范维护和传承成本大
- 某些功能需多个Playbook ,通过Include即可实现
- 把不同的内容,分门别类放到不同的文件夹中,需要的时候再逐个调用,方便重复调用
roles目录结构及各自作用
playbook.yml roles
roles/
nginx/
mysql/
project/
tasks/
files/
vars/
default/
templates/
handlers/
Roles各目录作用
- /roles/project/ :项目名称,有以下子目录
- files/ :存放由copy或script模块等调用的文件
- templates/ : template模块查找所需要模板文件的目录
- tasks/ :定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文
件需要在此文件中通过include进行包含 - handlers/ :至少应该包含一个名为main.ym的文件;其它的文件需要在此文件中通过
include进行包含 - vars/ :定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件
中通过include进行包含 - meta/ :定义当前角色的特殊设定及其依赖关系,至少应该包含一 个名为main.yml的文
件,其它文件需在此文件中通过include进行包含 - default/ :设定默认变量时使用此目录中的main.yml文件
先创建一个roles目录(在/etc/ansible/roles也可以)
[root@ansible ansible]# tree roles/
roles/
├── httpd
├── memcache
├── mysql
└── nginx
roles部署一个nginx服务
创建nginx组和用户
安装nginx包
将主机配置文件复制过去
开启服务
重启服务(handler)
创建nginx目录下所需要的文件夹
[root@ansible ansible]# tree
.
├── nginx_roles.yml
└── roles
├── httpd
├── memcache
├── mysql
└── nginx
├── handler
├── tasks
└── template
- tasks下创建任务文件
[root@ansible ansible]# tree
├── tasks
├── group.yml
├── main.yml
├── service.yml
├── templ.yml
├── user.yml
└── yum.yml
#创建组
[root@ansible tasks]# cat group.yml
- name: create group
group: name=nginx gid=80
#创建用户
[root@ansible tasks]# cat user.yml
- name: create user
user: name=nginx uid=80 group=nginx system=yes shell=/sbin/nologin
#安装包
[root@ansible tasks]# cat yum.yml
- name: installl package
yum: name=nginx
#复制配置文件
[root@ansible tasks]# cat templ.yml
- name: copy conf
template: src=template/nginx.conf.j2 dest=/etc/nginx/nginx.conf
#开启服务
[root@ansible tasks]# cat service.yml
- name: start service
service: name=nginx state=started enabled=yes
#创建一个main文件来指定任务顺序
[root@ansible tasks]# cat main.yml
- include: group.yml
- include: user.yml
- include: yum.yml
- include: templ.yml
- include: service.yml
- template下创建要传过去的文件
[root@ansible template]# ls
nginx.conf.j2
- 编写playbook,记得要跟roles同级
[root@ansible ansible]# ls
nginx_roles.yml roles
[root@ansible ansible]# cat nginx_roles.yml
- hosts: webserver
remote_user: root
roles:
- role: nginx
- 执行角色
[root@ansible ansible]# ansible-playbook -C nginx_roles.yml
[root@ansible ansible]# ansible-playbook nginx_roles.yml
roles部署apache服务
定义httpd角色
创建apache用户
复制apache配置文件过去
创建相关目录和文件
[root@localhost ansible]# tree
.
├── httpd_test.yml
└── roles
├── httpd
├── files
└── httpd.conf
└── tasks
├── copyfile.yml
├── main.yml
└── user.yml
#创建apache用户
[root@ansible tasks]# cat user.yml
- name: create user
user: name=apache system=yes shell=/sbin/nologin
#复制apache配置文件过去
[root@ansible tasks]# cat copyfile.yml
- name: copy files
copy: src=httpd.conf dest=/data/ owner=apache
#main
[root@ansible tasks]# cat main.yml
- include: user.yml
- include: copyfile.yml
6. roles企业高级用法
调用多个角色
[root@ansible ansible]# tree
.
├── httpd_test.yml
├── nginx_roles.yml
└── some_role.yml
├── roles
│ ├── httpd
│ │ ├── files
│ │ │ └── httpd.conf
│ │ └── tasks
│ │ ├── copyfile.yml
│ │ ├── main.yml
│ │ └── user.yml
│ ├── memcache
│ ├── mysql
│ └── nginx
│ ├── handler
│ │ └── restart_srvs.yml
│ ├── tasks
│ │ ├── group.yml
│ │ ├── main.yml
│ │ ├── service.yml
│ │ ├── templ.yml
│ │ ├── user.yml
│ │ └── yum.yml
│ └── template
│ └── nginx.conf.j2
[root@ansible ansible]# cp nginx_roles.yml some_role.yml
[root@ansible ansible]# vim some_role.yml
- hosts: webserver
remote_user: root
roles:
- role: httpd
- role: nginx
[root@ansible ansible]# ansible-playbook some_role.yml
调用另一个角色的tasks
- 在nginx角色下调用httpd的某一任务
[root@ansible ansible]# vim roles/nginx/tasks/main.yml
- include: group.yml
- include: user.yml
- include: yum.yml
- include: templ.yml
- include: service.yml
- include: roles/httpd/tasks/copyfile.yml
##注意这个yml文件里面文件路径为绝对路径
[root@ansible tasks]# vim copyfile.yml
- name: copy files
copy: src=/etc/httpd/conf/httpd.conf dest=/data/ owner=apache
在角色里面定义tags
[root@ansible ansible]# vim some_role.yml
- hosts: webserver
remote_user: root
roles:
- { role: httpd, tags: ['web','httpd'] }
- { role: nginx, tags: ['web','nginx'] }
- { role: app, tags: 'app' }
[root@ansible ansible]# ansible-palybook -t web some_role.yml
#加上条件判断
- hosts: webserver
remote_user: root
roles:
- { role: httpd, tags: ['web','httpd'] }
- { role: nginx, tags: ['web','nginx'], when : ansible_distribution_major_version == '7' }
- { role: app, tags: 'app' }
终极案例
创建一个角色app,实现部署http服务
[root@ansible ansible]# tree
.
├── app_roles.yml
├── roles
│ ├── app
│ │ ├── files
│ │ │ └── vhosts.conf
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── copyfile.yml
│ │ │ ├── group.yml
│ │ │ ├── main.yml
│ │ │ ├── start.yml
│ │ │ ├── templ.yml
│ │ │ ├── user.yml
│ │ │ └── yum.yml
│ │ ├── templates
│ │ │ └── httpd.conf.j2
│ │ └── vars
│ │ └── main.yml
- 首先在tasks下创建任务
#创建组
[root@ansible tasks]# cat group.yml
- name: create group
group: name=app system=yes
#创建用户
[root@ansible tasks]# cat user.yml
- name: create user
user: name=app group=app shell=/sbin/nologin system=yes
#安装服务
[root@ansible tasks]# cat yum.yml
- name: install package
yum: name=httpd
#复制模板
[root@ansible tasks]# cat templ.yml
- name: copy conf
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: restart service
#复制文件
[root@ansible tasks]# cat copyfile.yml
- name: copy file
copy: src=vhosts.conf dest=/data/ owner=app
#开启服务
[root@ansible tasks]# cat start.yml
- name: start service
service: name=httpd state=started enabled=yes
#main文件
[root@ansible app]# cat tasks/main.yml
- include: group.yml
- include: user.yml
- include: yum.yml
- include: templ.yml
- include: copyfile.yml
- include: start.yml
- 创建handelers下的触发器
[root@ansible handlers]# cat main.yml
- name: restart service
service: name=httpd state=restarted
- 创建变量,放在模板中
[root@ansible vars]# cat main.yml
username: app
groupname: app
- 创建模板文件
[root@ansible ansible]# cp /etc/httpd/conf/httpd.conf /root/ansible/roles/app/templates/httpd.conf.j2
#在模板文件里面修改使得带上变量名
。。。
Listen {{ ansible_processor_vcpus*10 }}
User {{ username }}
Group {{ groupname }}
。。。
- 创建要复制到远程主机的文件
[root@ansible app]# touch files/vhosts.conf
- 最后指定palybook并运行
[root@ansible ansible]# cat app_roles.yml
- hosts: webserver
remote_user: root
roles:
- app
[root@ansible ansible]# ansible-playbook -C app_roles.yml
[root@ansible ansible]# ansible-playbook app_roles.yml
