Ansible之playbook&&roles

运维:
	手动 --> 标准化-->工具化-->自动化 --> 智能化
	
工具化:
	OS Install:PXE,Cobbler;Virtualization & Cloud Computing
	OS Config:ansible,fabric,puppet,saltstack,chef,cfengine,...
	Deploy:fabric,ansible,...
	Task Exec:fabric,ansible,func,...

YAML语法格式


ansible之Playbook

Playbook的核心元素:
	Hosts:关联到的主机
	Tasks:任务列表,要做哪些事
	Variables:变量
	Templates:包含了模板语法的文本文件;
	Handlers:由特定条件触发的任务;
	Roles:
	
	playbook的基础组件:
		Hosts:运行指定任务的目标主机;
		remoute_user:在远程主机上执行任务的用户;
			sudo_user:
		tasks:任务列表
			模块,模块参数;
			格式:
				(1)action:module arguments
				(2)module:arguments
				
				注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;
		
			(1)某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;
			(2)任务可以通过“tags”打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
			
		运行playbook的方式:
			(1)测试:
				ansible-playbook --check
					只检测可能会发生的改变,但不真正执行操作;
				ansible-playbook --list-hosts
					列出运行任务的主机;
			(2)运行
		
		handlers:
			任务,在特定条件下触发;
			接收到其它任务的通知时被触发;
				notify:HANDLER TASK NAME
		
		variables:
			(1)facts:可直接调用;
				注意:可使用setup模块直接获取目标主机的facters;
				ansible 192.168.0.111 -m setup | less
				
			(2)用户自定义变量:变量引用: {{ variable }}
				(a) ansible-playbook命令的命令行中的:
					-e VARS,--extra-vars=VARS
			
				(b) 在playbook中定义变量的方法:
					vars:
						- var1: value1
						- var2: value2 
			
			(3) 通过roles传递变量;
			(4) Host Inventory;
				(a) 向不同的主机传递不同的变量;
					IP/HOSTNAME variable=value var2=value2
				(b) 向组中的主机传递相同的变量;
                    [groupname:vars]
                    variable=value
			
				注意:invertory参数:
					用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量;
						ansible_ssh_host
						ansible_ssh_port
						ansible_ssh_user
						ansible_ssh_pass
						ansible_sudo_pass
					...
					
			模块:
				template模块:基于模板方式生成一个文件复制到远程主机
	
ansible-playbook --help
	-C
    -D
    -e
    -f FORKS,--forks=FORKS
    -i INVENTORY
    -l SUBNET,--limit=SUBNET
    --list-hosts
    --list-tags
    --list-tasks
    -M MODULE_PATH
	--step:单步执行

	--syntax-check

ansible-playbook --list-hosts --list-tasks first.yaml
ansible-playbook -C first.yaml # 干跑

案例

vim first.yml
- hosts: all
  remote_user: root
  tasks:
  - name: install redis
    yum: name=redis state=latest
  - name: start redis
    service: name=redis state=started
ansible 192.168.0.111 -m fetch -a "src=/etc/redis.conf dest=./"
vim ~/playbooks/redis.conf
	# bind 127.0.0.1
	bind 0.0.0.0
	# requirepass foobared
	requirepass admin123 
vim first.yml
- hosts: all
  remote_user: root
  tasks:
  - name: install redis
    yum: name=redis state=latest
  - name: copy config file
  	copy: "src=/root/playbooks/redis.conf dest=/etc/redis.conf"
  - name: start redis
    service: name=redis state=started
ansible-playbook syntax-check first.yml
ansible-playbook -C first.yml

ansible-playbook  first.yml

再次修改配置文件,如何热加载配置文件?可以通过handlers,在某个任务上添加属性notify,notify和handlers的name对应的名称要一致。如果配置文件没改变,handlers是不会触发的。

vim second.yml
- hosts: all
  remote_user: root
  tasks:
  - name: install redis
    yum: name=redis state=latest
  - name: copy config file
  	copy: "src=/root/playbooks/redis.conf dest=/etc/redis.conf"
    notify: restart redis
  - name: start redis
    service: name=redis state=started
  handlers:
    - name:restart redis  # notify通过其定义的名称,去找handlers的name触发,所以notify的名称要和这里的name一致
      service: name=redis state=restarted
vim ~/playbooks/redis.conf
	requirepass admin123123

ansible-playbook second.yml

在192.168.0.111机器上:
	redis-cli
	auth admin123123 # 认证成功

如果我们只想跑某个任务,可以使用tags打标签,然后跑任务时加上 -t参数

vim second.yml
- hosts: all
  remote_user: root
  tasks:
  - name: install redis
    yum: name=redis state=latest
  - name: copy config file
  	copy: "src=/root/playbooks/redis.conf dest=/etc/redis.conf"
    notify: restart redis
    tags:configfile
  - name: start redis
    service: name=redis state=started
  handlers:
    - name:restart redis  # notify通过其定义的名称,去找handlers的name触发,所以notify的名称要和这里的name一致
      service: name=redis state=restarted



ansible-playbook -t configfile second.yml

# 再次修改本地redis.conf文件中的密码为admin123
vim ~/playbooks/redis.conf
	requirepass admin123

ansible-playbook -t configfile second.yml # 如下图,通过tags标签copy这个任务,只跑了copy,而我们修改了redis.conf文件,又触发了handlers任务。

yum install facter 
facter -p  # 查看当前主机上的变量
vim third.yml
	- hosts: 192.168.0.111
	  remote_user: root
	  tasks:
	  - name: copy file
        copy: content={{ ansible_env }} dest=/tmp/ansible.env
	  

variables的三种自定义方式

vim var.yml

- hosts: websrvs
  remote_user: root
  vars: # 直接在playbook中定义变量
  - pbvar: playbook variable testing  
  tasks:
  - name: command line variables # 使用ansible-playbook命令行传递变量值
    copy: content={{ cmdvar }} dest=/tmp/cmd.var
  - name: playbook variables
    copy: content={{ pbvar }} dest=/tmp/pb.var
  - name: host iventory variables  # 使用主机清单定义变量,如下图
    copy: content={{ http_port }} dest=/tmp/http_port.var

编辑/etc/ansible/hosts文件传递变量:


补充模块

setup模块:

template模块:基于模板方式生成一个文件复制到远程主机
	
	*src=
	*dest=
	owner=
	group=
	mode=
	
	模板:templates
		ansible-doc -s template
		文本文件,嵌套有脚本 (使用模板编程语言编写)
			Jinja2:	
				字面量:
					字符串:使用单引号或双引号;
					数字:证书,浮点数;
					列表:[item1,item2,...]
					元组:[item1,item2,...]
					字典:{key1:value1,key2:value2,...}
					布尔值:true/false
				
				算数运算:
					+,-,*,/,//,%,**
				比较操作:
					==,!=,>,>=,<,<=
				逻辑运算:
					and,or,not

			示例:
				- hosts: websrvs
				remote_user: root
				tasks:
				  - name: install nginx
				  yum: name=nginx state=present
				  - name: install conf file
				  template: src=files/nginx.conf.j2 dest=/etc/nginx/nginx.conf
				  notify: restart nginx
				  tags: instconf
				  - name: start nginx service
				  service: name=nginx state=started
				  handlers:
				  - name: restart nginx
				  service: name=nginx state=restarted
				  
				  模板配置文件: nginx.conf.j2
				  worker_processes {{ ansible_processor_vcpus }};
				  listen {{ http_port }};

template模板使用案例

ansible 192.168.0.111 -m setup | less  # 通过setup模块查看192.168.0.111虚拟机上的内置变量,得到ansible_default_ipv4有address属性
cp /root/playbooks/redis.conf{,.j2}
vim /root/playbooks/redis.conf.j2
	bind {{ ansible_default_ipv4.address }}

vim template.yml
	- hosts: 192.168.0.111
  remote_user: root
  tasks:
  - name: install config file
    template: src=/root/playbooks/redis.conf.j2 dest=/tmp/redis.conf

ansible-playbook template.yml

在192.168.0.111虚拟机上,查看配置文件/tmp/redis.conf的bind后的变量是否被渲染出来:# 如下图

将template.yml文件中的hosts改成all,再次执行 ansible-playbook template.yml,192.168.0.112的/tmp/redis.conf 中的bind后的变量也被渲染出来,如下图:

案例:使用template在被ansible主机控制的主机上监听一个额外的端口

vim /root/playbooks/mylisten.conf
	Listen {{ http_port }}  # 这个变量在/etc/ansible/hosts文件中

vim /root/playbooks/httpd.yml

- hosts: websrvs
  remote_user: root
  tasks:
  - name: install httpd
    yum: name=httpd state=latest
  - name: install config file
    template: src=/root/playbooks/mylisten.conf dest=/etc/httpd/conf.d/mylisten.conf
    notify: restart httpd
  - name: start httpd
    service: name=httpd state=started
  handlers:
  - name: restart httpd
    service: name=httpd state=restarted

案例:nginx启动的进程数是cpu核心数和cpu个数的乘积减1

cp /etc/nginx/nginx.conf /root/playbooks/nginx.conf.j2

ansible 192.168.0.111 -m setup | less
	   ansible_processor_cores:"2"
       ansible_processor_vcpus:"2"

vim nginx.conf.j2
	worker_processes {{ ansible_processor_cores*ansible_processor_vcpus-1 }};

vim nginx.yml
    - hosts: websrvs
      remote_user: root
      tasks:
      - name: install nginx
        yum: name=nginx state=latest
      - name: change nginx.conf
        template: src=/root/playbooks/nginx.conf.j2 dest=/etc/nginx/nginx.conf
        notify: restart nginx
      - name: start nginx
        service: name=nginx state=started
      handlers:
      - name: restart nginx
        service: name=nginx state=restarted

ansible-playbook -C nginx.yml
ansible-plabook nginx.yml

当再次修改/root/playbooks/nginx.conf.j2,就会触发handlers,重新加载nginx配置文件(nginx.conf)

条件测试(when)和循环(迭代)

条件测试:
	when语句:在task中使用,jinja2的语法格式
		tasks:
		- name: install conf file to centos7
		  template: src=files/nginx.conf.c7.j2
		  when: ansible_distribution_major_version == "7"
		- name: install conf file to cnetos6
		  template: src=files/nginx.conf.c6.j2
		  when: ansible_distribution_major_version == "6"

循环:迭代,需要重复执行的任务;
	对迭代项的引用,固定变量名为“item”,而后,要在task中使用with_items给定要迭代的元素列表;
		列表方法:
			字符串
			字典
			
	- name: install some packages
	  yum: name={{ item }} state=pretent
	  with_items:
	  - nginx
	  - memcached
	  - php-fpm
	  
	- name: add some groups
	  group: name={{ item }} state=present
	  with_items:
	  - group1
	  - group2
	  - group3
	
	- name: add some users
	  user: name={{ item.name }} group={{ item.group }} state=present
	  with_items:
	  - { name: 'user11', group: 'group11' }
	  - { name: 'user12', group: 'group12' }
	  - { name: 'user13', group: 'group13' }
	

案例:根据不同的发行版安装不同的web服务

vim os.yml
    - hosts: websrvs
      remote_user: root
      tasks:
      - name: install httpd
        yum: name=httpd state=latest
        when: ansible_os_family == "Redhat"
      - name: install apache2
        apt: name=apache2 state=latest
        when: ansible_os_family == "Debian"

ansible-playbook -C os.yml

迭代

vim iter.yml
    - hosts: websrvs
      remote_user: root
      tasks:
      - name: install {{ item }} package
        yum: name={{ item }} state=latest
        with_items:
        - tomcat
        - tomcat-webapps
        - tomcat-admin-webapps

角色(roles)

在安装nginx之前,需要配置yum仓库:epel.repo:
	这个仓库是epel-release模块:
		yum info epel-release
		yum intall epel-release
		rpm -ql epel-release

角色(roles):
	角色集合:
		roles/
			mysql/
			httpd/
			nginx/
			memcached/
	每个角色,以特定的层级目录结构进行组织:
		mysql/
			files/:存放由copy或script模块等调用的文件;
			templates/:template模块查找所需要模板文件的目录;
			tasks/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
			handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
			vars/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
			meta/:至少应该包含一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要在此文件中通过include进行包含;
			default/:设定默认变量时使用此目录中的main.yml文件;
	
	在playbook调用角色方法1:
		- hosts: websrvs
		  remote_user: root
		  roles:
		  - mysql
		  - memcached
		
	在playbook调用角色方法2:传递变量给角色
		- hosts:
		  remote_user:
		  roles:
		  - { role: nginx,username: nginx }
		    键role用于指定角色名称;后续的k/v用于传递变量给角色;
		 
		还可以基于条件测试实现角色调用;
		roles:
		- { role: nginx, when: "ansible_distribution_major_version == '7'" }
ansible-vcs:可实现ansible-pull机制
	https://github.com/andrewrothstein/ansible-vcs

实战项目:
	主/备模式高可用keepalived+nginx(proxy)
	两台主机:httpd+php
	一台主机:mysql-server或mariadb-server;

http://www.ansible.com.cn


ansible在配置文件(/etc/ansible/ansible.cfg)中已经说明,它的角色应该放在 /etc/ansible/roles或/usr/share/ansible/roles目录下,才能默认被找到,不然自己修改配置文件的role_path定义路径。。。。。。# 如下图1
			

图1:

mkdir -pv /etc/ansible/roles/nginx/{files,templates,tasks,vars,handlers,meta,default}
vim /etc/ansible/roles/nginx/tasks/main.yml
    - name: install nginx
      yum: name=nginx state=latest
      when: ansible_os_family == "RedHat"
      
vim ~/playbooks/nginx_roles.yml
	- hosts: websrvs
  	remote_user: root
  	roles:
 	- nginx


ansible-playbook --syntax-check nginx_roles.yml 
ansible-playbook -C nginx_roles.yml # 如图2

图2:

(1)
cd /etc/ansible
vim roles/nginx/templates/vhost1.conf.j2
	server {
		listen 80;
		server_name {{ ansible_fqdn }};
		location / {
				root "/ngxdata/vhost1";
		}
	}
	
(2)
vim roles/nginx/tasks/main.yml
    - name: install nginx
      yum: name=nginx state=latest
      when: ansible_os_family == "RedHat"
	- name: install config file
  	  template: src=vhost1.conf.j2 dest=/etc/nginx/conf.d/vhost1.conf  # 自动去../templates中找vhost1.conf.j2文件

ansible-playbook -C nginx_roles.yml # 如下图3 

======================================================================================================

vim roles/nginx/tasks/main.yml
单独执行某个任务,添加如下两行:
	tags: conf
	notify: restart nginx
	
vim roles/nginx/handlers/main.yml
	- name: restart nginx
	  service: name=nginx state=restarted

vim roles/nginx/tasks/main.yml
	nginx没有start,也就没有restart,所以添加第三个任务:
		- name: start nginx
		  service: name=nginx state=started

vim roles/nginx/tasks/main.yml
	还需要给nginx提供一个测试页和家目录,因此还需要添加一个创建家目录的任务:
		- name: install site home directory
		  file: path={{ ngxroot }} state=directory
		- name: install index page
		  copy: src=index.html dest={{ ngxroot }}/ 

vim roles/nginx/vars/main.yml
	ngxroot: /ngxdata/vhost1 # 这是定义成的字典格式,前面不需要加'-'

vim roles/nginx/files/index.html
	<h1>Vhost1<h1>

ansible-playbook -C nginx_roles.yml # 如下图4

# 停掉192.168.0.111和192.168.0.112虚拟机上监听在80端口的服务:
ansible websrvs -m service -a "name=nginx state=stopped"

ansible-playbook  nginx_roles.yml

图3:

图4:

被管控的两台虚拟机nginx已经启动,在浏览器中能正常访问。。。

但这不是我们设定的测试页,因为我们templates中定义的变量访问的是主机名,可以更改监听端口为8080;修改roles/nginx/templates/vhost1.conf.j2 中的 listen:8080;

ansible-playbook -t conf /root/playbooks/nginx_roles.yml # 按照我们定义的tags,只跑修改nginx配置文件的这个任务,又触发handlers重载nginx。

在浏览器中访问8080端口,可以看到我们的测试页了。。。。。如下图

posted on 2021-09-03 20:05  jueyuanfengsheng  阅读(362)  评论(0编辑  收藏  举报