1 playbook基础组件
1.1 yaml语言介绍
YAML: #将所有的需要执行的命令放置在一个文件中,在每台主机都将这个文件执行一遍,所有任务都可以执行完成。就像脚本来完成多个任务一样
YAML is a data serialization format designed for human readability and interaction with scripting languages.
安装:[root@localhost ~]#yum info PyYAML 数据结构: key:value - item1 - item2 - item3 {name:jerry, age:21}
1.2 Hosts和Users
playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分隔主机组;remote_user则用于指定远程主机上的执行任务的用户。如上面示例中的
-hosts: webnodes remote_user: root
不过,remote_user也可用于各task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户。
- hosts: webnodes remote_user: andy tasks: - name: test connection ping: remote_user: andy sudo: yes
1.3 任务列表和action
play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自下而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,在更正playbook后重新执行一次即可。
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。
每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。
定义task的可以使用“action: module options”或“module: options”的格式,推荐使用后者以实现向后兼容。如果action一行的内容过多,也中使用在行首使用几个空白字符进行换行。
tasks: - name: make sure apache is running service: name=httpd state=running 在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式,例如: tasks: - name: disable selinux command: /sbin/setenforce 0 如果命令或脚本的退出码不为零,可以使用如下方式替代: tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand || /bin/true 或者使用ignore_errors来忽略错误信息: tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand ignore_errors: True
1.4 handlers
用于当关注的资源发生变化时采取一定的操作。
“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。 在notify中列出的操作称为handler,即notify中调用handler中定义的操作。 - name: template configuration file template: src=template.j2 dest=/etc/foo.conf notify: - restart memcached - restart apache handler是task列表,这些task与前述的task并没有本质上的不同。 handlers: - name: restart memcached service: name=memcached state=restarted - name: restart apache service: name=apache state=restarted
案例:当 /etc/httpd/conf/httpd.conf 文件改变的时候,即源文件和目标文件不同,重启 httpd 服务
httpd.yaml - hosts: hbhosts remote_user: root tasks: - name: ensure httpd latest version yum: name=httpd state=present - name: authkeys configure file copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf force=yes notify: - restart httpd - name: ha.cf configure file copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/ha.cf notify: - restart abc handlers: - name: restart httpd service: name=httpd state=restarted - name: restart abc service: name=abc state=restarted
PlayBook的核心元素:
Tasks:任务,由模块定义的操作的列表; Variables:变量 Templates:模板,即使用了模板语法的文本文件; Handlers:由特定条件触发的Tasks; Roles:角色; playbook的基础组件: Hosts:运行指定任务的目标主机; remote_user:在远程主机以哪个用户身份执行; sudo_user:非管理员需要拥有sudo权限; tasks:任务列表 模块,模块参数: 格式: (1) action: module arguments (2) module: arguments 示例1: - hosts: all remote_user: root #以哪个用户身份运行 tasks: - name: install a group #每个任务要起一个名字 group: name=mygrp system=true #模块名:参数 - name: install a user user: name=user1 group=mygrp system=true #模块名:参数 - hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name=httpd - name: start httpd service service: name=httpd state=started
运行playbook,使用ansible-playbook命令
(1) 检测语法 ansible-playbook --syntax-check /path/to/playbook.yaml (2) 测试运行,干跑 ansible-playbook -C /path/to/playbook.yaml #干跑的时候有的服务因为前面没有实际安装会执行不成功,实际运行的时候可以运行 --list-hosts #影响的主机 --list-tasks --list-tags (3) 运行 ansible-playbook /path/to/playbook.yaml -t TAGS, --tags=TAGS #只执行某个标签 --skip-tags=SKIP_TAGS #跳过指定的标签任务 --start-at-task=START_AT #从指定的某个任务开始运行 主机:192.168.170.21 [root@localhost ~]#cat test.yaml #注意缩进,好像很严格 - hosts: all remote_user: root tasks: - name: install a group group: name=mygrp system=true - name: install a user user: name=user1 group=mygrp system=true - hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name=httpd - name: start httpd service service: name=httpd state=started [root@localhost ~]#ansible-playbook ./test.yaml #执行操作 主机:192.168.170.21 [root@localhost ~]#cat test.yaml #在root目录下面有一个httpd.conf文件,里面监听的端口是8080, #让远程的主机安装好httpd服务,并将ansible主机的配置文件拷贝过去,启动服务 - hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name=httpd - name: cp a conf file copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf - name: start httpd service service: name=httpd state=started 在其他主机看到,监听端口是8080
handlers:由特定条件触发的Tasks;
调用及定义方式:
tasks: - name: TASK_NAME #当确实执行这个命令的时候,会执行notify,只有当文件改变的时候才会复制文件, 才会执行notify。当两边的文件相同,文件不变,不会执行复制命令,那么notify就不会执行,还要再看 module: arguments notify: HANDLER_NAME handlers: - name: HANDLER_NAME module: arguments 示例: [root@localhost ~]#cat test.yaml - hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name=httpd - name: cp a conf file copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf notify: reload httpd service - name: start httpd service service: name=httpd state=started handlers: - name: reload httpd service shell: systemctl reload httpd.service
tags:给指定的任务定义一个调用标识;
格式 - name: NAME module: arguments tags: TAG_ID [root@localhost ~]#cat test.yaml - hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name=httpd - name: cp a conf file copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf notify: reload httpd service tags: abc #调用标签前要先指定标签名字 - name: start httpd service service: name=httpd state=started [root@localhost ~]#ansible-playbook -t abc ./test.yaml #只执行abc标签的命令 [root@localhost ~]#ansible-playbook -skip-tags=abc ./test.yaml #跳过abc标签的命令
变量Variables:
类型: 内建: (1) facts 自定义: (1) 命令行传递; -e VAR=VALUE (2) 在playbook中定义 vars: - var_name: value - var_name: value (3) 在hosts Inventory中为每个主机定义专用变量值;在hosts文件中添加 (a) 向不同的主机传递不同的变量 ; IP/HOSTNAME variable_name=value (b) 向组内的所有主机传递相同的变量 ; [groupname:vars] variable_name=value (4) Inventory还可以使用参数: 用于定义ansible远程连接目标主机时使用的属性,而非传递给playbook的变量;连接ssh的时候的属性 ansible_ssh_host ansible_ssh_port ansible_ssh_user ansible_ssh_pass ansible_sudo_pass ... (5) 在角色调用时传递 roles: - { role: ROLE_NAME, var: value, ...} 变量调用: {{ var_name }} 主机:192.168.170.21 [root@localhost ~]#cat test.yaml - hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name={{ pkgname }} [root@localhost ~]#ansible-playbook -e pkgname=vsftpd ./test.yaml #在命令行中指定变量的值就可以执行 或者这样配置,将变量定义在内部也可以 主机:192.168.170.21 [root@localhost ~]#cat test.yaml - hosts: websrvs remote_user: root vars: - pkgname: memcached tasks: - name: install httpd package yum: name={{ pkgname }} [root@localhost ~]#ansible-playbook ./test.yaml #在命令行中指定变量的值就可以执行
Templates:模板,配置每个主机的时候的配置文件不一定相同,具体的参数跟主机的某些属性有关系
文本文件,内部嵌套有模板语言脚本(使用模板语言编写),这是一个配置文件,里面的内容就像php嵌套在html中,只有变量才会被替换,然后将配置文件传递给ansible去配置主机,
Jinja2 is a template engine written in pure Python. It provides a Django inspired non-XML syntax but supports inline expressions and an optional sandboxed environment.
语法: 字面量: 字符串:使用单引号或双引号; 数字:整数、浮点数; 列表:[item1, item2, ...] 元组:(item1, item2, ...) 字典:{key1:value1, key2:value2, ...} 布尔型:true/false 算术运算: +, -, *, /, //, %, ** 比较操作: ==, !=, >, <, >=, <= 逻辑运算:and, or, not 执行模板文件中的脚本,并生成结果数据流,需要使用template模块; template: -a ”“ src= dest= mode= onwer= group= 注意:此模板不能在命令行使用,而只能用于playbook; 示例:根据模板,不同核心数开启不同数量的进程 主机:192.168.170.21 [root@localhost ~]#ansible all -m setup | grep cpu #为了测试,将其中一个虚拟机的核心数调整为4 "ansible_processor_vcpus": 4, "ansible_processor_vcpus": 1, "ansible_processor_vcpus": 1, 将一个nginx的配置文件放在root目录下面,修改 [root@localhost ~]#mv nginx.conf nginx.conf.j2 #为了便于区别,将配置文件后缀名改为:j2 [root@localhost ~]#cat nginx.conf.j2 user nginx; worker_processes {{ ansible_processor_vcpus }}; #cpu的数量修改为变量,这个变量就是上面setup输出的变量名称 ... [root@localhost ~]#cat test.yaml - hosts: websrvs remote_user: root tasks: - name: install nginx package yum: name=nginx state=latest - name: cp a conf file template: src=/root/nginx.conf.j2 dest=/etc/nginx/nginx.conf #使用template复制过去的配置文件,里面的变量会被自动其值替换。用copy命令复制过去不能替换变量 - name: start nginx service: name=nginx state=started enabled=true 主机:12.18.1.21 [root@localhost ~]#cat /etc/nginx/nginx.conf user nginx; worker_processes 4; #自动替换为其变量的值 并且也开启了四个进程,测试成功 root 4106 0.0 0.2 122220 2216 ? Ss 20:36 0:00 nginx: master process /usr/sbin/nginx nginx 4107 0.0 0.4 124732 3492 ? S 20:36 0:00 nginx: worker process nginx 4108 0.0 0.4 124732 3492 ? S 20:36 0:00 nginx: worker process nginx 4109 0.0 0.4 124732 3492 ? S 20:36 0:00 nginx: worker process nginx 4110 0.0 0.4 124732 3492 ? S 20:36 0:00 nginx: worker process
条件判断,循环:
when语句:在tasks中使用,Jinja2的语法格式;在条件满足的情况下会执行 - hosts: all remote_user: root tasks: - name: install nginx package yum: name=nginx state=latest - name: start nginx service on CentOS6 shell: service nginx start when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" #变量为centos6执行 - name: start nginx service shell: systemctl start nginx.service when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7" #变量为centos7执行 循环:迭代,需要重复执行的任务; 对迭代项的引用,固定变量名为"item”,只能使用item;使用with_item属性给定要迭代的元素; 元素:列表 字符串 字典 基于字符串列表给出元素示例:用循环来安装多个程序包 主机:192.168.170.21 [root@localhost ~]#cat test.yaml #这样,所有的主机都会安装上下面的的rpm包,提高效率 - hosts: websrvs remote_user: root tasks: - name: install package yum: name={{ item }} state=latest with_items: - httpd - php - php-mysql - php-gd 基于字典列表给元素示例: 主机:192.168.170.21 [root@localhost ~]#cat test.yaml - hosts: websrvs remote_user: root tasks: - name: create groups group: name={{ item }} state=present with_items: - groupx1 - groupx2 - groupx3 - name: create users user: name={{ item.name }} group={{ item.group }} state=present #这里的这个item和上面创建组的item不一样,是两个变量名,没有关系。这里有三个item,每个item有两个元素, #创建用户的时候看需要item中的哪个元素,放上去,就可以,这里的元素多个应该都可以 with_items: - {name: 'userx1', group: 'groupx1'} - {name: 'userx2', group: 'groupx2'} - {name: 'userx3', group: 'groupx3'}
ansible以任务为中心,所有主机跑完第一个任务,然后所有的任务才跑第二个主机
角色:roles
以特定的层级目录结构进行组织的tasks、variables、handlers、templates、files等; role_name/ files/:存储由copy或script等模块调用的文件; tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行“包含”调用; handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;其它的文件需要由main.yml进行“包含”调用; vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable;其它的文件需要由main.yml进行“包含”调用; templates/:存储由template模块调用的模板文本; meta/:此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行“包含”调用; default/:此目录中至少应该有一个名为main.yml的文件,用于设定默认变量; 在playbook中调用角色的方法: - hosts: HOSTS remote_user: USERNAME roles: - ROLE1 - ROLE2 - { role: ROLE3, VARIABLE: VALUE, ...} - { role: ROLE4, when: CONDITION } [root@localhost /etc/ansible/roles]#mkdir ./{nginx,memcached,httpd,mysql}/{files,templates,vars,handlers,meta,default,tasks} -pv [root@localhost /etc/ansible/roles]#tree nginx nginx ├── default ├── files │ └── nginx-1.10.0-1.el7.ngx.x86_64.rpm #这个rpm包是从ftp上面下载的,以这个rpm包和对应的配置文件为例子。用yum上面的rpm包也可以, ├── handlers │ └── main.yml ├── meta ├── tasks │ └── main.yml ├── templates │ ├── default.conf.j2 │ └── nginx.conf.j2 └── vars └── main.yml 7 directories, 6 files [root@localhost /etc/ansible/roles/nginx/tasks]#cat main.yml - name: copy nginx package to remote file copy: src=nginx-1.10.0-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.10.0-1.el7.ngx.x86_64.rpm #文件默认去files目录下面去找 tags: cprpm - name: install nginx packages yum: name=/tmp/nginx-1.10.0-1.el7.ngx.x86_64.rpm state=present - name: install conf file template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf #这里的template文件不用指明目录位置,以.j2结尾的文件会自动去template目录中查找,只用写文件名就可以,修改了cpu数量 tags: ngxconf notify: reload nginx service - name: install default file #将default.conf配置文件修改后也传递过去,修改了监听的端口,由自己定义变量来赋值 template: src=default.conf.j2 dest=/etc/nginx/conf.d/default.conf tags: ngxconf notify: reload nginx service - name: start nginx service service: name=nginx enabled=true state=started [root@localhost /etc/ansible/roles/nginx/templates]#cat nginx.conf.j2 user nginx; worker_processes {{ ansible_processor_vcpus }}; [root@localhost /etc/ansible/roles/nginx/templates]#cat default.conf.j2 server { listen {{ ngxport }}; #这个变量自己定义 [root@localhost /etc/ansible/roles/nginx/handlers]#cat main.yml - name: reload nginx service service: name=nginx state=restarted [root@localhost /etc/ansible/roles/nginx/vars]#cat main.yml ngxport: 8090 ----------------------------------------------------------- [root@localhost /etc/ansible]#vim ansible.cfg #查看ansible默认去哪里找roles文件,将文件放置在定义的路径中 roles_path = /etc/ansible/roles [root@localhost ~]#cat nginx.yml #这里是剧本,来调用上面的所有文件,放到下面定义的路径中 - hosts: ngxsrvs remote_user: root roles: - nginx [root@localhost ~]#ansible-playbook --syntax-check nginx.yml #显示没有语法错误 playbook: nginx.yml [root@localhost ~]#ansible-playbook -t cprpm ./nginx.yml #先执行复制rpm命令,成功 [root@localhost ~]#ansible-playbook ./nginx.yml #执行成功,监听的端口,进程的数量都正确
这里有很多示例值得参考
https://github.com/ansible/ansible-examples
https://my.oschina.net/jastme/blog/510707
–
–
–
评论前必须登录!
注册