# ansible ## Ansible简介 当下有许多的运维自动化工具(配置管理),例如:ansible、SaltStack、Puppet、Fabric等。Ansible是一种集成IT系统的配置管理、应用部署、执行特定任务的开源平台,是ansibleWorks公司名下的项目。 Ansible是基于python语言实现的。有Paramiko和PyYaml、jinja2三个关键模块构建。 ### 特性 1. 模块化: 调用特定的模块,完成特定的任务 2. 有Paramiko、PyYaml、Jinja2(模块语言)三个关键模块 3. 支持自定义模块 4. 基于python语言实现 5. 部署简单,基于python和ssh(默认已安装) 6. 安全,基于openssh 7. 支持playbook编排任务 8. 冥等性:一个任务执行1遍和执行n遍效果一样,不会因为重复执行带来意外情况 9. 无需代理不依赖PKI(无需SSL) 10. 可使用任何编程语言写模块 11. YAML格式,编排任务,支持丰富的数据结构 12. 较强大的多层解决方案 13. 提供一个功能强大、操作性强的web管理界面和RESTAPI接口 - AWX平台 ### ansible架构 ![image-20210616145747869](https://xieys.club/images/posts/image-20210616145747869.png) ### 工作原理 ![image-20210616145835259](https://xieys.club/images/posts/image-20210616145835259.png) ### 主要组成部分 1. Ansible playbooks:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是JSON格式的YAML文件 2. Inventory:ansible管理主机的清单 /etc/ansible/hosts 3. Modules:Ansible执行命令的功能模块,多数为内置核心模块,也可以自定义 4. Plugins:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用 5. API:供第三方程序调用的应用程序编程接口 6. Ansible:组合Inventory、API、Modules、Plugins的绿框,可以理解为是ansible命令工具,其为核心执行工具 ### ansible命令执行来源 1. User,普通用户,即System Administrator 2. CMDB(配置管理数据库)API调用 3. Public/Private Cloud Api调用 ### 利用ansible实现管理的方式 1. Ad-Hoc 即ansible命令,主要用于临时命令使用场景 2. Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有提前的规划 ### Ansible-playbook(剧本)执行过程 1. 将已有编排好的任务集写入Ansible-Playbook 2. 通过ansible-playbook命令拆分任务集至逐条ansible命令,按预定规则逐条执行 ### ansible主要操作对象 1. Hosts主机 2. Networking网络设备 ### 注意事项 1. 执行ansible的主机一般称为主控端,中控、master或堡垒机 2. 主控端python版本需要2.6或以上 3. 被控端python版本小于2.4需要安装python-simplejson 4. 被控端如开启SELinux需要安装libselinux-python 5. Windows不能作为主控端 ### ansible与SaltStack的区别 最大区别是Ansible无需在被监控主机部署任何客户端代理,默认通过ssh通道进行远程命令执行或下发配置(相对而言,Saltstack有自己的agent端,速度会比ansible更快) 相同点是都具备功能强大、灵活的系统管理、状态配置,都使用YAML格式来描述配置,两者都提供丰富的模板及API,对云计算平台、大数据都有很好的支持 ## Ansible安装与配置 ### 安装ansible ``` #安装wget [root@ansible ~]# yum -y install wget #添加阿里云yum源以及epel源 [root@ansible ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo [root@ansible ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo #重新建立yum缓存 [root@ansible ~]# yum clean all && yum makecache fast #安装ansible [root@ansible ~]# yum -y install ansible ``` ### 相关文件 > 配置文件 | 文件 | 作用 | | ------------------------ | ------------------------------- | | /etc/ansible/ansible.cfg | 主配置文件,配置ansible工作特性 | | /etc/ansible/hosts | 主机清单 | | /etc/ansible/roles | 存放角色的目录 | > 程序 | 文件 | 作用 | | ------------------------- | -------------------------------------- | | /usr/bin/ansible | 主程序,临时命令执行工具 | | /usr/bin/ansible-doc | 查看配置文档,模块功能查看工具 | | /usr/bin/ansible-galaxy | 下载/上传优秀代码或Roles模块的官网平台 | | /usr/bin/ansible-playbook | 定制自动化任务,编排剧本工具 | | /usr/bin/ansible-pull | 远程执行命令的工具 | | /usr/bin/ansible-vault | 文件加密工具 | | /usr/bin/ansible-console | 基于console界面与用户交互的执行工具 | ### 主机清单 1. Inventory 主机清单,ansible的主要功能用于批量主机操作,为了便捷地使用其中的部分主机,可以再inventory file中将其分组命名 2. 默认的inventory file为/etc/ansible/hosts 3. Inventory file文件可以有多个,且也可以通过Dynamic Inventory来动态生成 > /etc/ansible/hosts文件格式 Inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中;此外,当如若目标主机使用了非默认的ssh端口,还可以在主机名称之后使用冒号加端口号来标明 ``` [webservers] www1.lingcb.com:222 www2.lingcb.com [dbservers] db1.lingcb.com db2.lingcb.com db3.lingcb.com ``` 如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机 ``` [webservs] www[01:100].example.com [dbservs] db-[a:f].example.com ``` ### Ansible配置文件 ``` Ansible配置文件/etc/ansible/ansible.cfg(一般保持默认) [default] #inventory = /etc/ansible/hosts #主机列表配置文件 #library = /usr/share/my_modules/ #库文件存放目录 #remote_tmp = $HOME/.ansible/tmp #临时py命令文件存放在远程主机目录 #local_tmp = $HOME/.ansible/tmp #本机的临时命令执行目录 #forks = 5 #默认并发数 #sudo_user = root #默认sudo用户 #ask_sudo_pass = True #每次执行ansible命令是否询问sudo密码 #ask_pass = True #每次执行ansible命令是否询问ssh密码 #remote_port = 22 #远程主机默认端口 #host_key_checking = False #检查对应服务器的host_key,建议取消注释 #log_path = /var/log/ansible.log #日志文件 建议修改host_key_checking以及log_path ``` ### Ansible系列命令 #### ansible ``` ansible [-m module_name] [-a args] --version 显示版本 -m module 指定模块,默认为command -v 详细过程 -vv -vvv 更详细 --list-hosts 显示主机列表,可简写 --list -k,--ask-pass 提示输入ssh连接密码,默认key验证 -K,--ask-become-pass 提示输入sudo时口令 -C,--check 检查,并不执行 -T,--timeout=TIMEOUT 执行命令的超时时间,默认10s -u,--user=REMOTE_USER 远程执行命令的用户 -b,--become 代替旧版sudo切换 ``` #### ansible的Host-pattern > 匹配主机的列表 ``` ALL : 表示所有Inventory中的所有主机 [root@ansible ~]# ansible all -m ping * : 通配符 [root@ansible ~]# ansible "*" -m ping [root@ansible ~]# ansible 192.168.116.* -m ping [root@ansible ~]# ansible *serv -m ping ``` > 逻辑或 ``` [root@ansible ~]# ansible webserv:dbserv -m ping 在webserv组中或者在dbserv组中 ``` > 逻辑与 ``` [root@ansible ~]# ansible 'webserv:&dbserv' -m ping 在webserv组并且在dbserv组中的主机,注意因为&在shell中有特殊意义,所以这里需要用引号引起来 ``` > 逻辑非 ``` [root@ansible ~]# ansible 'webserv:!dbserv' -m ping 在webserv组中,但是不在dbserv组中的主机,注意需要使用引号引起来 ``` > 综合逻辑 ``` [root@ansible ~]# ansible 'webserv:dbserv:&appserv:!ftpserv' -m ping 在webserv组中或者在dbserv组中并且在appserv组中但不在ftpserv组中的主机 ``` > 正则表达式 ``` [root@ansible ~]# ansible 'webserv:dbserv' -m ping 等同于 [root@ansible ~]# ansible '~(web|db)serv' -m ping ``` > Ansible inventory内置变量 可以再hosts文件中进行配置的内置变量,如下: 1. ansible_ssh_host:定义host ssh地址 2. ansible_ssh_port:定义host ssh端口 3. ansible_ssh_user:定义host ssh 认证用户 4. ansible_ssh_pass:定义ssh认证密码 5. ansible_sudo:定义sudo用户 6. ansible_sudo_pass:定义sudu密码 7. ansible_ssh_connection 目标主机连接类型,可以是local/ssh或者paramiko 8. ansible_ssh_private_key_file 连接目标主机的ssh私钥 ansible_*_interpreter 指定采用非python的其他语言脚本,如ruby/perl解释器 ``` 示例: [root@ansible ~]# cat /etc/ansible/hosts [webserv] 192.168.116.2[0:1] ansible_ssh_user='root' ansible_ssh_pass='123456' [dbserv] 192.168.116.2[1:2] #给dbserv组定义内置变量 [dbserv:vars] ansible_ssh_user='root' ansible_ssh_pass='123456' 测试: [root@ansible ~]# ansible webserv -m ping 192.168.116.20 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } 192.168.116.21 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } [root@ansible ~]# ansible dbserv -m ping 192.168.116.21 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } 192.168.116.22 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } ``` #### ansible-doc ``` ansible-doc [options] [module...] -a 显示所有模块的文档 -l,--list 列出可用模块 -s,--snippet 显示指定模块的playbook片段 示例: [root@ansible ~]# ansible-doc -l 列出所有模块 [root@ansible ~]# ansible-doc ping 查看指定ping模块的帮助用法 [root@ansible ~]# ansible-doc -s ping 查看指定模块的帮助用法 Ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible端能基于秘钥认证的方式联系各被管理节点。 ``` #### Ansible执行命令过程 1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg 2. 加载自己对应的模板文件,如command 3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/xxx.py文件 4. 给文件+x执行权限 5. 执行并返回结果 6. 删除临时py文件,sleep 0 退出 执行状态: 1. 绿色:执行成功并且不需要做改变的操作 2. 黄色:执行成功并且对目标主机做出了变更 3. 红色:执行失败 #### ansible-galaxy 连接https://galaxy.ansible.com下载相应的roles > 列出所有已安装的galaxy `ansible-galaxy list` > 安装galaxy `ansible-galaxy install geerlingguy.redis` > 刪除galaxy `ansible-galaxy remove geerlingguy.redis` #### ansible-pull 推送命令至远程,效率无限提升,对运维要求较高 #### ansible-playbook ansible-playbook hello.yml 运行定制好的ansible-playbook剧本 #### ansible-console 2.0+新增,可交互执行命令,支持tab ``` [root@ansible ~]# ansible-console Welcome to the ansible console. Type help or ? to list commands. root@all (3)[f:5]$ 执行用户@当前操作的主机组(当前组的主机数量)[f:并发数]$ root@all (3)[f:5]$ forks 10 设置并发数为10 root@all (3)[f:10]$ cd webserv 切换至webserv组 root@webserv (2)[f:10]$ list 192.168.116.20 192.168.116.21 列出当前组主机列表 root@webserv (2)[f:10]$ ? 列出所有内置命令 root@webserv (2)[f:10]$ yum name=httpd 安装httpd包 root@webserv (2)[f:10]$ yum name=httpd state=absent 卸载httpd包 ``` #### 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 hello.yml 创建新文件 ### Ansible常用模块 #### Command模块 在远程主机执行命令,默认模块,可以忽略-m选项 ``` [root@ansible ~]# ansible webserv -m command -a 'ls /root' 需要注意的是,command模块不支持特殊符号,比如重定向以及管道,如果需要用到这些,可以使用shell模块实现 ``` #### shell模块 ```` 和command相似,用shell执行命令 [root@ansible ~]# ansible webserv -m shell -a 'findmnt | grep /dev' 调用bash执行命令 ,但是一些复杂命令,即使使用shell也可能会失败,解决办法:写到脚本,使用script模块 ```` #### script模块 ``` 运行脚本 [root@ansible ~]# cat a.sh #!/bin/bash hostname [root@ansible ~]# ansible webserv -m script -a a.sh ``` #### Copy模块 ``` 从服务器复制文件到客户端 [root@ansible ~]# ansible webserv -m copy -a 'src=/root/a.sh dest=/tmp/f1.sh owner=root mode=600 backup=yes' 将/root/a.sh拷贝到被控端的/tmp/f1.sh 所有者、所属组为root,权限为600,如果目标存在,默认覆盖,此处指定先备份 [root@ansible ~]# ansible webserv -m copy -a 'content="test content\n" dest=/tmp/f1.txt' 利用content内容,直接生成目标文件 ``` #### fetch模块 ``` 从客户端取文件到服务器端,与copy相反 [root@ansible ~]# ansible webserv -m fetch -a 'src=/tmp/f1.txt dest=/mnt' [root@ansible ~]# ll /mnt/ total 0 drwxr-xr-x. 3 root root 17 Feb 1 15:06 192.168.116.20 drwxr-xr-x. 3 root root 17 Feb 1 15:06 192.168.116.21 ``` #### file模块 ``` 设置文件属性 [root@ansible ~]# ansible webserv -u root -m file -a 'path=/data mode=755 state=directory' 创建/data目录,权限为755 [root@ansible ~]# ansible webserv -u root -m file -a 'path=/data/f1.txt mode=644 owner=root state=touch' 创建一个/data/f1.txt,所有者所属组为root,文件权限为644 [root@ansible ~]# ansible webserv -m file -a 'src=/etc/fstab path=/data/fstab state=link' 创建一个/etc/fstab的软连接到/data目录下。 [root@ansible ~]# ansible webserv -m file -a 'path=/data state=absent' 删除/data目录 ``` #### stat模块 ``` 获取在远程文件状态信息,atime/ctime/mtime/MD5/uid/gid等信息 [root@ansible ~]# ansible webserv -m stat -a 'path=/tmp/f1.sh' ``` #### yum模块 ``` 软件包管理模块 安装 [root@ansible ~]# ansible webserv -m yum -a 'name=curl' 卸载 [root@ansible ~]# ansible webserv -m yum -a 'name=httpd state=absent' ``` #### get_url模块 ``` 实现在远程主机下载指定url到本地,支持sha256sum文件校验 [root@ansible ~]# ansible webserv -m get_url -a 'url=http://www.baidu.com dest=/tmp/index.html mode=0440 force=yes' ``` #### cron模块 ``` 远程主机crontab配置,支持时间:minute、hour、day、month、weekday [root@ansible ~]# ansible webserv -m cron -a 'name="check dirs" hour="5,2" job="ls -alh > /dev/null"' 效果如下: [root@node1 ~]# crontab -l #Ansible: check dirs * 5,2 * * * ls -alh > /dev/null 关闭上面定时任务: [root@ansible ~]# ansible webserv -m cron -a 'name="check dirs" hour="5,2" job="ls -alh > /dev/null" disabled=yes' 效果如下: [root@node1 ~]# crontab -l #Ansible: check dirs #* 5,2 * * * ls -alh > /dev/null 彻底删除上面定时任务 [root@ansible ~]# ansible webserv -m cron -a 'name="check dirs" state=absent' ``` #### mount模块 ``` 远程主机分区挂载模块 [root@ansible ~]# ansible webserv -m mount -a 'name=/mnt src=/dev/sd0 fstype=ext4 opts=ro state=mounted' 具体其他参数参考 ansible-doc -s mount ``` #### service模块 ``` 远程主机系统服务管理 ansible node -m service -a "name=httpd state=restarted" ansible node -m service -a "name=httpd state=reloaded" ansible node -m service -a "name=httpd state=stopped" ansible node -m service -a "name=httpd state=started" ``` #### group模块 ``` 远程主机用户组管理 [root@ansible ~]# ansible webserv -m group -a 'name=nginx gid=88 system=yes' ``` #### user模块 ``` 远程主机用户管理 添加用户 [root@ansible ~]# ansible webserv -m user -a 'name=nginx uid=88 group=nginx shell=/sbin/nologin system=yes' 递归删除用户以及用户组以及家目录等数据 [root@ansible ~]# ansible webserv -m user -a 'name=nginx state=absent remove=yes' ``` #### hostname模块 ``` 管理主机名 [root@ansible ~]# ansible 192.168.116.22 -m hostname -a 'name=a-node3' ``` #### setup模块 ``` 查看ansible所有的内置变量 [root@ansible ~]# ansible webserv -m setup -a 'filter=*process*' ``` ## Playbook 1. Playbook是由一个或多个“play”组成的列表 2. Play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制同唱一台大戏 3. Playbook采用yaml语言编写 ### 核心元素 1. Hosts 执行的远程主机列表 2. Tasks 任务集 3. Varniables 内置变量或自定义变量在playbook中调用 4. Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件 5. Handlers 和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行 6. Tags 标签,指定某条任务执行,用于选择运行playbook中的部分代码。Ansible具有幂等性。因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片段。 ansible-playbook -t tagsname useradd.yml ### playbook基础组件 #### hosts Hosts:playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。Hosts用于指定要执行指定任务的主机列表,须事先定义在主机清单中 可以是如下形式: ``` One.example.com One.example.com:two.example.com 192.168.150 192.168.1.* 两个组的并集: webserv :dbserv 两个组的交集: webserv:&dbserv 两个组的非集: webserv:!dbserv ``` #### remote_user 用于hosts和task中,也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某个任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户 #### tasks列表和action 1. Play的主体部分是task list。Task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自上而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此在更正playbook后重新执行一次即可 2. Task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行时幂等的,这意味着多次执行时安全的,因为其结果一致 3. 每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤,如果未提供name,则action的结果将用于输出。 ``` tasks: 任务列表 格式: 1、action: module arguments 2、module: arguments 建议使用 注意:shell和command模块后面跟命令,而非key=value 某任务的状态在运行后为changed时,可以通过notify 通知给相应的handlers。 任务可以通过tags打标签,而后可以再ansible-playbook 命令上使用 -t 指定标签进行调用 示例: [root@ansible ~]# cat test.yaml --- - hosts: all remote_user: root tasks: - name: disable selinux command: /sbin/setenforce 0 - name: replace selinux config replace: path=/etc/selinux/config regexp=^(SELINUX=).* replace=\1disabled backup=yes 如果让遇到某个task错误后不停止,继续往后执行,可以使用如下方式: [root@ansible ~]# cat test.yaml --- - hosts: all remote_user: root tasks: - name: disable selinux shell: sss || /bin/true 或者使用ignore_errors来忽略错误信息 [root@ansible ~]# cat test.yaml --- - hosts: all remote_user: root tasks: - name: disable selinux shell: sss ignore_errors: True ``` ### 运行palybook 1. 运行playbook的方式 ansible-playbook ... [options] 2. 常见选项 -C , --check 只检测可能会发生的改变,但不真正执行操作 --list-hosts , --list 列出运行任务的主机列表 --limit 主机列表,只针对主机列表中的主机执行 -v 显示过程 -vv -vvv更详细 #### handlers和notify结合使用触发条件 Handlers 是task列表,这些task与前述的task并没有本质上的不同,同于当关注的资源发生变化时,才会采取一定的操作 Notify此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify列出的操作称为handler,也即notify中调用handler中定义的操作。 > 比如,nginx服务,当配置文件发生改变后,触发重新加载操作 ``` [root@ansible ~]# cat nginx.yml --- - hosts: webserv remote_user: root tasks: - name: copy repo config copy: src=/etc/yum.repos.d/nginx.repo dest=/etc/yum.repos.d/ - name: install nginx yum: name=nginx - name: copy nginx config copy: src=/etc/nginx/nginx.conf dest=/etc/nginx/ notify: reload nginx - name: start nginx service: name=nginx state=started enabled=yes handlers: - name: reload nginx service: name=nginx state=reloaded 检查语法 [root@ansible ~]# ansible-playbook -C nginx.yml 执行playbook [root@ansible ~]# ansible-playbook nginx.yml ``` #### playbook中tags的使用 比如上面示例,我只想运行copy nginx config这个task,这时候就可以使用tag来做(不同task中的标签可以相同),首先添加在task中添加tag ``` [root@ansible ~]# cat nginx.yml --- - hosts: webserv remote_user: root tasks: - name: copy repo config copy: src=/etc/yum.repos.d/nginx.repo dest=/etc/yum.repos.d/ - name: install nginx yum: name=nginx - name: copy nginx config copy: src=/etc/nginx/nginx.conf dest=/etc/nginx/ tags: [nginx,copyconfig] notify: reload nginx - name: start nginx service: name=nginx state=started enabled=yes tags: [nginx,startservice] handlers: - name: reload nginx service: name=nginx state=reloaded 查看此playbook中存在的标签 [root@ansible ~]# ansible-playbook nginx.yml --list-tags 或者 用查看所有的任务也能看到标签信息 [root@ansible ~]# ansible-playbook nginx.yml --list-tasks 指定标签执行playbook [root@ansible ~]# ansible-playbook -t copyconfig nginx.yml ``` #### playbook中变量的使用 变量名:仅能由字母、数字和下划线组成,且只能以字母开头 变量来源: 1. ansible setup facts远程主机的所有变量都可直接调用 2. 在/etc/ansible/hosts中定义 普通变量:主机组中主机单独定义,优先级高于公共变量 公共(组)变量:针对主机组中所有主机定义统一变量 3. 在playbook中定义 vars: \- var1: value1 \- var2: value2 4. 通过命令行指定变量,优先级最高 5. 在role中定义 > 变量优先级 **命令行 > playbook(role) > /etc/ansible/hosts(普通变量) > /etc/ansible/hosts(公共变量)** > 变量定义 key = value 示例: http_port = 80 > 变量调用方式 通过{{ variable_name }}调用变量,且变量名前后必须有空格,有时需要用引号”{{ variable_name }}”才生效 #### templates templates功能:根据模块文件动态生成对应的配置文件,使用的是jinja2模板语法 1、templates文件必须存放于templates目录下,且命名为.j2结尾 2、Yaml/yml文件需和templates目录平级 例如: [root@ansible ansible]# tree . ├── templates │ └── nginx.conf.j2 └── template.yml ``` [root@ansible ansible]# grep worker_pro templates/nginx.conf.j2 worker_processes {{ ansible_processor_vcpus*2 }}; [root@ansible ansible]# cat template.yml --- - hosts: webserv remote_user: root tasks: - name: copy template template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf backup=yes notify: reload nginx handlers: - name: reload nginx service: name=nginx state=reloaded 此时会根据变量ansible_processor_vcpus 动态替换模板的值 此外在template中还可以使用for循环或者if判断 例如:我想根据模板生成类似于这样的配置文件 #官网 server { listen 80; server_name www.lingcb1.com; location / { root /data/web/www.lingcb.com; index index.html index.htm; try_files $uri $uri/ /index.html; proxy_cache lingcb; proxy_cache_valid 200 302 10m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } #收银台升级包 server { listen 80; server_name upg.lingcb1.com; location / { root /data/web/upg.lingcb.com; index index.html index.htm; proxy_cache lingcb; proxy_cache_valid 200 302 10m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } 第一步 编写template模板文件 [root@ansible ansible]# cat templates/www.conf.j2 {% for item in items %} server { listen {{ item.listen | default('80') }}; {% if item.server_name is defined %} server_name {{ item.server_name }}; {% endif %} location / { {% if item.root is defined %} root /data/web/{{ item.root }}; {% endif %} index index.html index.htm; try_files $uri $uri/ /index.html; proxy_cache lingcb; proxy_cache_valid 200 302 10m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } {% endfor %} 第二步编写playbook文件 [root@ansible ansible]# cat template1.yml --- - hosts: webserv remote_user: root vars: items: - listen: 80 server_name: "www.lingcb1.com" root: "www.lingcb.com" - listen: 80 server_name: "upg.lingcb1.com" root: "upg.lingcb.com" tasks: - name: copy nginx conf template template: src=www.conf.j2 dest=/tmp/www.conf backup=yes [root@ansible ansible]# ansible-playbook template1.yml 生成文件如下: [root@node1 ~]# cat /tmp/www.conf #官网 server { listen 80; server_name www.lingcb1.com; location / { root /data/web/www.lingcb.com; index index.html index.htm; try_files $uri $uri/ /index.html; proxy_cache lingcb; proxy_cache_valid 200 302 10m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 80; server_name upg.lingcb1.com; location / { root /data/web/upg.lingcb.com; index index.html index.htm; try_files $uri $uri/ /index.html; proxy_cache lingcb; proxy_cache_valid 200 302 10m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } ``` #### when 条件判断 条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法格式 在task后添加when子句即可使用条件测试 例如: 只有4核cpu的机器,我才把nginx.conf这个文件拷贝过去 ``` [root@ansible ansible]# cat when.yml --- - hosts: webserv remote_user: root tasks: - name: test when copy: src=/etc/nginx/nginx.conf dest=/tmp when: ansible_processor_vcpus == 4 ``` #### with_items 循环 迭代:当有需要重复性执行的任务时,可以使用迭代机制 1、对迭代项的引用,固定变量名为 “item” 2、要在task中使用with_items给定要迭代的元素列表 3、列表格式: ​ 字符串 ​ 字典 例如: 示例1:拷贝多个文件 ``` [root@ansible ansible]# cat items1.yml --- - hosts: webserv remote_user: root tasks: - name: copy files copy: src={{ item }} dest=/tmp with_items: - /etc/fstab - /etc/passwd - /etc/shadow ``` 示例2:添加多个用户组,并把用户添加到对应的用户组中 ``` [root@ansible ansible]# cat items2.yml --- - hosts: webserv remote_user: root tasks: - name: add groups group: name={{ item }} state=present with_items: - group1 - group2 - group3 - name: add user user: name={{ item.name }} group={{ item.group }} with_items: - {name: 'user1',group: 'group1'} - {name: 'user2',group: 'group2'} - {name: 'user3',group: 'group3'} ``` ## roles Ansible自1.2版本引入的新特性,用于层次性,结构化地组织playbook。Roles能根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景 复杂场景:建议使用roles,代码复用度高 1. 变更指定主机或主机组 2. 如命名不规范维护和传参成本大 3. 某些功能需要多个playbook,通过includes即可实现 ### Roles目录结构 1. 每个角色,以特定的层级目录结构进行组织 2. Roles目录结构 Playbook.yml (playbook文件,要跟roles根在同级目录) roles/ (roles根目录) project/ (roles项目) tasks/ (任务目录,定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过include进行包含) files/ (文件目录,存放由copy或script模块等调用的文件) vars/ (变量目录,不常用,定义变量,至少应该包含一个名为main.yml文件,其他的文件需要在此文件中通过include进行包含) default (不常用,设定默认变量时使用此目录中的main.yml文件) templates/ (模板目录,template模块查找所需要模板文件的目录) handlers/ (handlers目录,至少应该包含一个名为main.yml文件,其他的文件需要在此文件中通过include进行包含) meta/ (不常用,定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml文件,其他的文件需要在此文件中通过include进行包含) ### playbook 调用角色 ``` 方法1 --- - hosts: webserv remote_user: root roles: - role: nginx #- role: http #可以多个role同时执行 方法2 传递变量给角色 - hosts: webserv remote_user: root roles: - {role: nginx,username:nginx} 键role用于指定角色名称 后续的k/v用于传递变量给角色 方法3 还可以基于条件测试实现角色调用,比如 roles: - {role: nginx,username:nginx,when: ansible_distribution_major_version == 7} ``` ### roles playbook tags使用 ``` - hosts: webserv remote_user: root roles: - {role: nginx,tags: [‘nginx’,’web’]} - {role: nginx,tags: [‘httpd,’web’]} ``` > 示例 创建一个简单的nginx的roles ``` [root@ansible ansible]# mkdir roles [root@ansible ansible]# mkdir roles/nginx [root@ansible ansible]# cd !$ [root@ansible nginx]# mkdir {tasks,templates,handlers,files} [root@ansible nginx]# cp /etc/yum.repos.d/nginx.repo files/ [root@ansible nginx]# cat tasks/copy_repofile.yml - name: copy yum repo file copy: src=nginx.repo dest=/etc/yum.repos.d/ backup=yes [root@ansible nginx]# cat tasks/install.yml - name: install nginx package yum: name=nginx [root@ansible nginx]# cp /etc/nginx/nginx.conf templates/nginx.conf.j2 [root@ansible nginx]# cat templates/nginx.conf.j2 user nginx; worker_processes {{ ansible_processor_vcpus*2 }}; ... [root@ansible nginx]# cat tasks/template.yml - name: template nginx.conf template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf backup=yes notify: reload nginx service [root@ansible nginx]# cat tasks/cron.yml - name: delete repos backup file cron: name='delete repo backup file' hour=2 minute=0 job='rm -rf /etc/yum.repos.d/nginx.repo.*' - name: delete nginx config backup file cron: name='delete nginx conf backup file' hour=2 minute=0 job='rm -rf /etc/nginx/nginx.conf.*' [root@ansible nginx]# cat tasks/start.yml - name: start nginx service service: name=nginx state=started enabled=yes [root@ansible nginx]# cat tasks/main.yml - include: copy_repofile.yml - include: install.yml - include: template.yml - include: cron.yml - include: start.yml [root@ansible nginx]# cat handlers/reload.yml - name: reload nginx service service: name=nginx state=reloaded [root@ansible nginx]# cat handlers/main.yml - include: reload.yml [root@ansible nginx]# cd .. [root@ansible roles]# cd .. [root@ansible ansible]# cat nginx.yml --- - hosts: webserv remote_user: root roles: - role: nginx #- role: http #可以多个role同时执行 ```