欢迎来到李洋的博客

回首境界: 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。

Ansible自动化管理工具

一、Ansible 基础

1.Ansible基础概述

1.1 什么是Ansible

Ansible是一个IT自动化的配置管理工具,自动化主要体现在Ansible集成了丰富模块,丰富的功能组件,可以
通过一个命令行完成一系列的操作。进而能减少我们重复性的工作和维护成本,以提高工作的效率。

1.2 Ansible可以完成哪些功能呢

1)批量执行远程命令,可以对N多台主机同时进行命令的执行
2)批量配置软件服务,可以进行自动化的方式配置和管理服务。
3)实现软件开发功能,jumpserver底层使用ansble来实现的自动化管理0
4)编排高级的IT任务,Ansible的playbook是一门编程语言,可以用来描绘一套IT架构。

1.3 Ansible的特点

1.容易学习,无代理模式,不像saltstack既要学服务端又要学习客户端,还要学习服务端与客户端之间的通讯协议
2.操作灵活,体现在Ansible有较多的模块,提供了丰富的功能,playbook则提供了类似于编程语言的复杂功能
3.简单易用,体现在Ansible —个命令可以完成很多事情
4.安全可靠,因为Ansible使用了SSH协议进行通汛,既稳定又安全
5.可移植性高,可以将写好的playbook拷贝至任意机器进行执行
4.Ansible架构中的控制节点、被控制节点、inventroy, ad-hoc、playbook、连接协议是什么?

2.Ansible的安全配置

2.1.Ansible安装

外网地址 内网地址 角色
10.0.0.61 172.16.1.61 Ansible控制端
10.0.0.7 172.16.1.7 Ansible被控端
10.0.0.8 172.16.1.8 Ansible被控端

1.先安装epel源(提供最新的ansible)

wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

2.安装Ansible

yum install ansible -y

查看ansible的版本
[root@m01 ~]# ansible --version
ansible 2.7.7
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]

3.Ansible的配置文件,配置文件可以随意放,但有查找顺序

$ANSIBLE_CONFIG
ansible.cfg				#当前目录下面查找
.ansible.cfg 				#当前用户的家目录下查找
/etc/ansible/ansible.cfg

[root@m01 ~]# cat /etc/ansible/ansible.cfg 
#inventory      = /etc/ansible/hosts      #主机列表配置文件
#library        = /usr/share/my_modules/  #库文件存放目录
#remote_tmp     = ~/.ansible/tmp          #临时py文件存放在远程主机目录
#local_tmp      = ~/.ansible/tmp          #本机的临时执行目录
#forks          = 5                       #默认并发数
#sudo_user      = root                    #默认sudo用户
#ask_sudo_pass = True                     #每次执行是否询问sudo的ssh密码
#ask_pass      = True                     #每次执行是否询问ssh密码
#remote_port    = 22                      #远程主机端口
host_key_checking = False                 #跳过检查主机指纹
log_path = /var/log/ansible.log           #ansible日志

[privilege_escalation]					#如果是普通用户则需要配置提权
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False

二、Ineventory主机清单

1.场景一、基于密码连接

[root@oldboy.com ~]# cat /etc/ansible/hosts
#方式一、主机+端口+密码
[webservers]
172.16.1.7 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123456'
172.16.1.8 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123456'

#方式二、主机+端口+密码
[webservers]
web[1:2].oldboy.com ansible_ssh_pass='123456'

#方式三、主机+端口+密码
[webservers]
web[1:2].oldboy.com
[webservers:vars]
ansible_ssh_pass='123456'

2.场景二、基于密钥连接,需要先创建公钥和私钥,并下发公钥至被控端

[root@m01 ~]# ssh-keygen
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@172.16.1.7
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@172.16.1.8

-----------------------------------------------------------
[root@m01 ~]# cat hosts 
#方式一、主机+端口+密钥
[webservers]
172.16.1.7
172.16.1.8

[root@m01 ~]# ansible webservers -m ping -i ./hosts 
172.16.1.8 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
172.16.1.7 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

-----------------------------------------------------------
[root@m01 ~]# cat hosts 
#方式二、别名+主机+端口+密钥
[webservers]
web01 ansible_ssh_host=172.16.1.7 ansible_ssh_port=22
web02 ansible_ssh_host=172.16.1.8


[root@m01 ~]# ansible webservers -m ping -i ./hosts 
web02 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
web01 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

3.场景三、主机组使用方式

#1.定义两个组
[lbservers]
172.16.1.5
172.16.1.6

[webservers]
172.16.1.7
172.16.1.8

#2.servers组包括两个子组[lbservers,webserver]
[servers:children]
[lbservers]
[webserver]


#列出当前某个组有多少台主机
[root@m01 ~]# ansible lbservers -m ping -i ./hosts --list-hosts
  hosts (1):
    web01
[root@m01 ~]# ansible webservers -m ping -i ./hosts --list-hosts
  hosts (1):
    web02
[root@m01 ~]# ansible servers -m ping -i ./hosts --list-hosts
  hosts (2):
    web01
    web02
[root@m01 ~]# ansible all -m ping -i ./hosts --list-hosts
  hosts (3):
	web03
    web02
    web01

注意:
如果控制端和被控制端第一次通讯,需要先添加指纹信息,那如果机器特别多少的情况下怎么办?
仅需开启ansible中的 host_key_checking = False

三、Ad-Hoc

1.常用模块

command                 执行shell命令(不支持管道等特殊字符)
shell                         执行shell命令
scripts                      执行shell脚本
yum_repository        配置yum仓库
get_url                     联网下载		
yum                         安装			
copy                        配置			
service、systemd   启动			
user、group            创建用户与组	
file                           授权			
crond                       定时任务		
mount                      挂载			
firewalld		        firewall
selinux			selinux

2..使用过程中需要先了解ansible-doc帮助手册

[root@m01 ~]# ansible-doc -l        # 查看所有模块说明
[root@m01 ~]# ansible-doc copy      # 表示指定模块方法
[root@m01 ~]# ansible-doc -s copy   # 表示指定模块参数

3..command默认执行bash命令模块,模块不支持重定向或管道

[root@m01 ~]# ansible oldboy  -a "hostname"

4..shell模块,如果需要一些管道操作,则使用shell

[root@m01 ~]# ansible oldboy -m shell -a "ifconfig|grep eth0" -f 50

5..script脚本模块

[root@m01 ~]# cat yum.sh
#!/usr/bin/bash
yum install -y iftop

#在本地运行模块,等同于在远程执行,不需要将脚本文件进行推送目标主机执行
[root@m01 ~]# ansible oldboy -m script -a "/server/scripts/yum.sh"

6..yum安装软件模块

[root@m01 ~]# ansible oldboy -m yum -a "name=httpd state=installed"
name        						
	httpd		#指定要安装的软件包名称
	file://		#指定从本地哪个目录安装rpm
	http://		#指定从哪个网站安装rpm包
state       			#指定使用yum的方法
	present   		#安装软件包
	absent      	#移除软件包
	latest		#安装最新软件包 
list=ansible					#列出当前仓库可用的软件包
disablerepo="epel,ol7_latest"		#安装软件时,不从哪些仓库获取
download_only=true			#仅下载软件包,不安装

7.copy文件拷贝模块

#1.拷贝文件文件至被控节点
[root@m01 ~]# ansible oldboy -m copy -a "src=/etc/hosts dest=/tmp/test.txt"
#2.对远端已有文件进行备份,按照时间信息备份
[root@m01 ~]# ansible oldboy -m copy -a "src=/etc/hosts dest=/tmp/test.txt backup=yes"
#3.向被控端主机写入数据,并且会覆盖远端文件内原有数据信息
[root@m01 ~]# ansible oldboy -m copy -a "content='bgx' dest=/tmp/oldboy"

src               #推送数据的源文件信息
dest             #推送数据的目标路径
backup        #对推送传输过去的文件,进行备份
content        #直接批量在被管理端文件中添加内容
group           #将本地文件推送到远端,指定文件属组信息
owner          #将本地文件推送到远端,指定文件属主信息
mode           #将本地文件推送到远端,指定文件权限信息

8..file文件创建模块

1.直接修改被控端的权限
[root@m01 ~]# ansible web01 -m file -a "path=/opt mode=0400" -i ./hosts

2.在被控端创建目录
[root@m01 ~]# ansible oldboy -m file -a "path=/tmp/oldboy state=directory"

3.在被控端创建文件
[root@m01 ~]# ansible oldboy -m file -a "path=/tmp/tt state=touch mode=555 owner=root group=root"

4.递归授权目录权限
[root@m01 ~]# ansible oldboy -m file -a "path=/data owner=bgx group=bgx recurse=yes"
path              #指定远程主机目录或文件
recurse         #递归授权
state             #状态
    directory   #在远端创建目录
    touch        #在远端创建文件
    link            #创建链接文件
    absent      #表示删除文件或目录
    mode        #设置文件或目录权限
    owner       #设置文件或目录属主
    group       #设置文件或目录属组

9..get_url文件下载模块

1.通过get_url下载文件或者软件
[root@m01 ~]# ansible webservers -m get_url -a "url=http,https  dest=/opt mode=0777" -i ./hosts

2.下载一个文件前先进行md5校验,通过则下载,不通过则失败
ansible webservers -m get_url -a "url=http,https  dest=/opt mode=0777 checksum=md5:76eb3af80ffd" -i ./hosts
url			#文件在网络上的具体位置
dest		        #下载到被控端的哪个目录下
checksum	#校验(md5  sha256)

10.ansible管理服务的启动与停止,使用service、systemd

#1.启动crond服务,并加入开机自启
[root@m01 ~]# ansible webservers -m service -a "name=crond state=started enabled=yes"
#2.停止crond服务,并删除开机自启
[root@m01 ~]# ansible webservers -m service -a "name=crond state=stopped enabled=no"
#3.重启crond服务
[root@m01 ~]# ansible webservers -m service -a "name=crond state=restarted"
#4.重载crond服务
[root@m01 ~]# ansible webservers -m service -a "name=crond state=reloaded"

name        # 定义要启动服务的名称
state       # 指定服务状态
    started     #启动服务
    stopped     #停止服务
    restarted   #重启服务
    reloaded    #重载服务
enabled         #开机自启	

11.group组模块

[root@m01 ~]# ansible webservers -m group -a "name=oldgirl gid=888"
name            #指定创建的组名
gid             #指定组的gid
state
    absent      #移除远端主机的组
    present     #创建远端主机的组(默认)

12.user模块

1.创建用户指定uid和gid,不创建家目录也不允许登陆
[root@m01 ~]# ansible oldboy -m user -a "name=oldgirl uid=888 group=888 shell=/sbin/nologin create_home=no"

2.删除用户
[root@m01 ~]# ansible webservers -m user -a "name=tmd state=absent" -i ./hosts 

3.给新创建的用户生成ssh密钥对
[root@m01 ~]# ansible webservers -m user -a "name=oo uid=6677 group=adm generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_rsa" -i ./hosts 

4.将明文密码进行hash加密,然后进行用户创建
[root@m01 ~]# ansible localhost -m debug -a "msg={{ '123456' | password_hash('sha512', 'salt') }}"
localhost | SUCCESS => {
    "msg": "$6$salt$MktMKPZJ6t59GfxcJU20DwcwQzfMvOlHFVZiOVD71w.igcOo1R7vBYR65JquIQ/7siC7VRpmteKvZmfSkNc69."
}
[root@m01 ~]# ansible webservers -m user -a 'name=xlw password=$6$salt$MktMKPZJ6t59GfxcJU20DwcwQzfMvOlHFVZiOVD71w.igcOo1R7vBYR65JquIQ/7siC7VRpmteKvZmfSkNc69. create_home=yes shell=/bin/bash' -i ./hosts 

uid             #指定用户的uid
group           #指定用户组名称
groups          #指定附加组名称
password        #给用户添加密码(记得单引号)
shell           #指定用户登录shell
create_home     #是否创建家目录

13.crond定时任务模块

# 正常使用crond服务(默认没写的时间都算*表示)
[root@m01 ~]# crontab -l
* * * * *  /bin/sh /server/scripts/yum.sh

# 使用ansible添加一条定时任务
[root@m01 ~]# ansible webservers -m cron -a "minute=* hour=* day=* month=* weekday=* job='/bin/sh test.sh'"
[root@m01 ~]# ansible webservers -m cron -a "job='/bin/sh /server/scripts/test.sh'"

# 设置定时任务注释信息,防止重复,name设定
[root@m01 ~]# ansible webservers -m cron -a "name='cron01' job='/bin/sh /server/scripts/test.sh'"

# 删除相应定时任务
[root@m01 ~]# ansible webservers -m cron -a "name='ansible cron02' minute=0 hour=0 job='/bin/sh test.sh' state=absent"

# 注释相应定时任务,使定时任务失效
[root@m01 scripts]# ansible oldboy -m cron -a "name='ansible cron01' minute=0 hour=0 job='/bin/sh test.sh' disabled=yes"

14..mount挂载模块7 nfs 8客户端挂载

[root@m01 ~]# ansible web01 -m yum -a 'name=nfs-utils state=present' -i ./hosts
[root@m01 ~]# ansible web01 -m file -a 'path=/data state=directory' -i ./hosts
[root@m01 ~]# ansible web01 -m copy -a 'content="/data 172.16.1.0/24(rw,sync,no_all_squash)" dest=/etc/exports' -i ./hosts 
[root@m01 ~]# ansible web01 -m systemd -a "name=nfs state=started enabled=yes" -i ./hosts


[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=present"
[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=mounted"
[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=unmounted"
[root@m01 ~]# ansible web02 -m mount -a "src=172.16.1.7:/data path=/data fstype=nfs opts=defaults state=absent"

present     # 开机挂载,仅将挂载配置写入/etc/fstab
mounted     # 挂载设备,并将配置写入/etc/fstab
unmounted   # 卸载设备,不会清除/etc/fstab写入的配置
absent      # 卸载设备,会清理/etc/fstab写入的配置

15.防火墙管理模块

Selinux模块

[root@m01 ~]# ansible webservers -m selinux -a "state=disabled" -i ./hosts

firewalld模块

[root@m01 ~]# ansible webservers -m systemd -a "name=firewalld state=started" -i ./hosts 
[root@m01 ~]# ansible webservers -m firewalld -a "service=http immediate=yes permanent=yes state=enabled" -i ./hosts 
[root@m01 ~]# ansible webservers -m firewalld -a "port=8080-8090/tcp immediate=yes permanent=yes state=enabled" -i ./hosts 

service				#指定开放或关闭的服务名称
port				#指定开放或关闭的端口
masquerade			#开启地址伪装
immediate			#临时生效
permanent			#是否添加永久生效
state				#开启或是关闭

zone				#指定配置某个区域
rich_rule			#配置富规则
source				#指定来源IP

四、Playbook

1.Ansible Playbook基本概述

1.什么是playbook,playbook翻译过来就是“剧本' 那么playbook组成如下

playbook:定义一个文本文件,以yml为后缀结尾(翻译:我有一个剧本)
play:定义的是主机的角色(翻译:找哪个大腕明星)
task:定义的是具体执行的任务(翻译:大腕每一集拍什么)

总结:playbook是由一个或多个play组成,一个play可以包含多个task任务。
可以理解为:使用不同的模块来共同完成一件事情。

2.Ansible playbook与AD-Hoc的关系

  1. playbook是对AD-Hoc的一种编排方式。
  2. playbook可以持久运行,而Ad-Hoc只能临时运行。
  3. playbook适合复杂的任务,而Ad-Hoc适合做快速简单的任务。
  4. playbook能控制任务执行的先后顺序,以及互相依赖的关系。

3.Ansible Playbook书写格式

playbook是由yml语法书写,结构清晰,可读性强,所以必须掌握yml基础语法

语法 描述
缩进 YAML使用固定的缩进风格表示层级结构,每个缩进由两个空格组成,不能使用Tab
冒号 以冒号结尾的除外,其他所有冒号后面所有必须有空格。
短横线 表示列表项,使用一个短横杠加一个空格。多个项使用同样的缩进级别作为同一列表。

3.1.下面我们一起来编写一个playbook文件,playbook起步

host:对哪些主机进行操作
remote_user:我要使用什么用户执行
tasks: 具体执行什么任务

[root@m01 ~]# cat f1.yml 
#play
- hosts: webservers

  tasks:
    - name: Installed Httpd Server
      yum:
        name: httpd
        state: present

    - name: Start Httpd Server
      systemd:
        name: httpd
        state: started
        enabled: yes

2.检查语法,只检查是否是yaml语法格式。并不做逻辑校验。

[root@m01 project1]# ansible-playbook --syntax-check p1.yml 

playbook: p1.yml

3.模拟执行(不是真的执行)

[root@m01 project1]# ansible-playbook -C  p1.yml 

4.真实的描述状态(被控端的状态必须与控制端描述的状态一致)

[root@m01 project1]# ansible-playbook   p1.yml 

3.2.多paly语法示例

ansible安装并配置httpd服务,根据不同的主机配置不同的网站。(多个play的使用方式,但不是生产推荐,了解项,生产推荐使用循环方式)

[root@m01 project1]# cat p1.yml 
---
#play
- hosts: webservers

  tasks:
    - name: Installed Httpd Server
      yum: name=httpd state=present

    - name: Start Httpd Server
      systemd: name=httpd state=started enabled=yes

    - name: Start Firewalld Server
      systemd: name=firewalld state=started enabled=yes

    - name: Configure Firewalld Server
      firewalld: service=http immediate=yes permanent=yes state=enabled

- hosts: web01
  tasks:
    - name: Configure web01 Website
      copy: content='This is Web01' dest=/var/www/html/index.html

- hosts: web02
  tasks:
    - name: Cofnigure webi-2 weisite
      copy: content='This is Web02' dest=/var/www/html/index.html

3.3.安装nfs服务

1.安装
2.配置
	用户
	/data
3.启动
#记得重启你的nfs
[root@m01 project1]# cat nfs.yml 
- hosts: web01

  tasks:
    - name: Install NFS-utils Server
      yum: name=nfs-utils state=present

    - name: Configure Nfs-utils Server
      copy: src=./exports.j2 dest=/etc/exports owner=root group=root mode=0644

    - name: Create NFS Group
      group: name=www gid=666

    - name: Create NFS User
      user: name=www uid=666 group=www create_home=no shell=/sbin/nologin

    - name: Create Data Directory
      file: path=/data state=directory owner=www group=www mode=0755 recurse=yes

    - name: Start NFS Server
      systemd: name=nfs state=started enabled=yes

- hosts: web02
  tasks:
    - name: Mount NFS Server
      mount: path=/opt src=172.16.1.7:/data fstype=nfs opts=defaults state=mounted

3.4.使用AnsiblePlaybook方式构建LAMP架构,具体操作步骤如下:

1.使用yum安装 httpd、php、php-mysql、mariadb、firewalld等
2.启动httpd、firewalld、mariadb等服务
3.添加防火墙规则,放行http的流量,并永久生效
4.使用get_url下载 http://fj.xuliangwei.com/public/index.php 文件

[root@m01 project1]# cat lamp.yml 
#- hosts: webservers
- hosts: otherservers
  tasks:
    - name: Installed Web Packages
      yum: name=httpd,mariadb-server,php,php-mysql,php-pdo state=present

    - name: Start Web Serivce
      service: name=httpd state=started

    - name: Start Mariadb Service
      service: name=mariadb state=started

    - name: Get Wordpress
      unarchive: src=./wordpress-5.0.3-zh_CN.tar.gz dest=/var/www/html/ copy=yes mode=0755


  #  - name: Copy Index.php
  #    copy: src=./index.php.j2 dest=/var/www/html/index.php


 #   - name: Get Url index.php
 #     get_url: url="http://fj.xuliangwei.com/public/index.php" dest=/var/www/html/index.php

4.Ansible Playbook变量解析

1 .变量概述

变量提供了便捷的方式来管理ansible项目中的动态值。比女Ozabbix-3.4.15,可能后期会反复的使用到这个版本的值,那么如果将此值设置扫变量,后续使用和修改都将变得非常方便。这样可以简化项目的创建和维护
定义变量分为如下三种方式
1)通过命令行进行变量定义
2)在play文件中进行定义变量
3)通过inventory在主机组或单个主机中设置变量

如果定义的变量出现重复,且造成冲突,优先级如下:
1.命令行定义的变量-高于->play文件定义的变量-高于->inventory文件定义的变量。

2.变量的定义

2.1.playbook变量可以通过多种方式进行定义,最简单的方式就是在playbook的开头通过vars进行定义

#安装两个软件包使用变量方式
[root@m01 project1]# cat  p2.yml 
- hosts: webservers
  vars:
    - web_package: httpd
    - ftp_package: vsftpd
  tasks:
    - name: Installed Packages
      yum: 
        name: 
          - "{{ web_package }}"
          - "{{ ftp_package }}"
        state: present

2.2.也可以在playbook中使用vars_files指定文件作为变量文件,好处就是其他的playbook也可以调

[root@m01 project1]# cat vars.yml 
web_package: httpd
ftp_package: vsftpd

[root@m01 project1]# cat p2.yml 
- hosts: webservers
  vars_files: ./vars.yml
  tasks:
    - name: Installed Packages
      yum: 
        name: 
          - "{{ web_package }}"
          - "{{ ftp_package }}"
        state: present

2.3.在inventory中定义变量,主机变量优先级高于主机组变量(不推荐,容易将环境弄的特别乱)

[root@m01 project1]# vim /etc/ansible/hosts 
[webservers]
web01 ansible_ssh_host=172.16.1.7
web02 ansible_ssh_host=172.16.1.8
[webservers:vars]
filename=group_vars

[root@m01 project1]# cat p3.yml 
- hosts: webservers
  tasks:
    - name: Create File
      file: path=/tmp/{{ filename }} state=touch

2.4.更好的方式是在ansible的项目目录中创建额外的两个变量目录,分别是host_vars和group_vars

group_vars目录下必须存放和inventory清单文件中定义的组名一致,如下
[root@m01 project1]# cat /etc/ansible/hosts 
[webservers]
web01 ansible_ssh_host=172.16.1.7
web02 ansible_ssh_host=172.16.1.8

[root@m01 project1]# cat group_vars/webservers 
web_package: httpd
ftp_package: vsftpd
注意:系统提供了特殊的组,all,也就说在group_vars目录下创建一个all文件,定义变量对所有的主机都生效


[root@m01 project1]# cat host_vars/web01 
web_package: zlib-static
ftp_package: zmap

[root@m01 project1]# cat group_vars/webservers 
web_package: httpd
ftp_package: vsftpd


[root@m01 project1]#  cat p4.yml 
- hosts: webservers
#- hosts: otherservers
  tasks:
    - name: Installed Packages
      yum: 
        name: 
          - "{{ web_package }}"
          - "{{ ftp_package }}"
        state: present


[root@m01 project1]# ansible-playbook p4.yml 

PLAY [webservers] ********************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************
ok: [web02]
ok: [web01]

TASK [Installed Packages] ************************************************************************************************
ok: [web02]
changed: [web01]

PLAY RECAP ***************************************************************************************************************
web01                      : ok=2    changed=1    unreachable=0    failed=0   
web02                      : ok=2    changed=0    unreachable=0    failed=0   

2.5.通过命令行覆盖变量,inventory的变量会被playbook文件中覆盖,这两种方式的变量都会被命

令行直接指定变量所覆盖。使用--extra-vars或-e设定变量。

[root@m01 project1]# ansible-playbook p4.yml -e "web_package=zarafa-devel" -e "ftp_package=zarafa-utils"

2.6.变量优先级测试

命令行变量--->play中的vars_files--->play中的vars变量-->host_vars中定义的变量--->group_vars/组--->group_vars/all

[root@m01 project1]# cat p5.yml 
- hosts: webservers
#  vars:
#    filename: play_vars
#  vars_files:
#    - ./vars.yml
  tasks:

    - name: Create 
      shell: mkdir -pv /tmp/{{ filename }}
      register: mk_test

    - name: debug
      debug: msg={{ mk_test }}

2.7.变量注册register

- hosts: webservers
  tasks:
    - name: Get Network Port Status
      shell: netstat -lntp
      register: net_port

    - name: OutPut Network Port Status
      debug:
        msg: "{{ net_port.stdout_lines }}"

2.8.变量也支持层级定义,使用"."可能会有问题,建议使用"[]"代替。

[root@m01 project1]# cat vars1.yml 
rainbow:
  web:
    web_package: httpd
    db_package: mariadb

code:
  web:
    filename: code_web_filename

	
[root@m01 project1]# cat p8.yml 
- hosts: webservers
  vars_files: ./vars1.yml
  tasks:
    - name: Install Package
      yum: name= "{{ rainbow['web']['web_package'] }}"

    - name: create filename
      file: 
        path: /tmp/{{ code.web.filename }}
        state: touch

2.9.facts变量 (setup模块)

Ansible facts是在被管理主机上通过ansible自动采集发现的变量。facts包含每台特定的主机信息。比如:被控端主机的主机名、IP地址、系统版本、CPU数量、内存状态、磁盘状态等等。
facts使用场景
1.通过facts检查CPU,来生成对应的Nginx配置文件
2.通过facts检查主机名信息,来生成不同的Zabbix配置文件
3.通过fact检索的内存情况来自定义mysql的配置文件

1.facts基本用法,比如获取被控端的主机名与IP地址

[root@m01 〜]# cat facts.yml
-hosts: web
  tasks:
    -name: Output variables ansible facts
      debug:
        msg: >
           this default IPv4 address "{{ ansible_fqdn}}" is "{{ ansible_default_ipv4.address}}"

2.使用facts模拟批量修改zabbix配置文件,template和copy用法差不多,但template支持解析变量

[root@m01 project1]# cat p10.yml 
- hosts: webservers
  #gather_facts: no   关闭facts采集
  vars: 
    - zabbix_server: 172.16.1.71
  tasks:
    - name: Copy Zabbix Agent Configure
      template: src=./zabbix_agentd.conf dest=/tmp/zabbix_agent.conf
  1. facts开启后会影响Ansible主机的性能,如果没有采集被控端主机需求可选择关闭
[root@m01 project1]# cat p10.yml 
- hosts: webservers
  #gather_facts: no   关闭facts采集
  vars: 
    - zabbix_server: 172.16.1.71
  tasks:
    - name: Copy Zabbix Agent Configure
      template: src=./zabbix_agentd.conf dest=/tmp/zabbix_agent.conf

4.使用setup模块获取采集的值

ansible web01 -m setup -i ./hosts

5.playbook安装一个memcached,利用了facts变量

[root@m01 project1]# cat memcached.j2 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb //2 }}"
OPTIONS=""

[root@m01 project1]# cat p11.yml 
- hosts: webservers
  tasks:
    - name: Installed Memcached
      yum: name=memcached state=present

    - name: Configure Memcached
      template: src=./memcached.j2 dest=/etc/sysconfig/memcached

    - name: Start Memcached
      service: name=memcached state=started enabled=yes

2.10.批量修改主机名

解法一、web_随机数的解法

[root@m01 ~]# cat te.yaml
- hosts: all
  tasks:
  - name: 打印facts变量的内容
    debug: msg={{ ansible_default_ipv4.address }}
  - name: 使用hostname模块将主机名修改为web_ip
    hostname: name=web_{{ ansible_default_ipv4.address }}

解法二、web_随机数的解法

[root@m01 ~]# cat te_2.yaml
- hosts: all
  tasks:
    - name: 定义一个随机数,设定为变量,然后后续调用
      shell: echo $((RANDOM%200))
      register: System_SJ

    - name: 使用debug输出变量结果,这样好知道需要提取的关键值
      debug: msg={{ System_SJ }}

    - name: 使用hostname模块将主机名修改为web_随机数
      hostname: name=web_{{ System_SJ.stdout }}

解法三、随机数+时间戳的解法

[root@m01 project1]# cat vars_14.yml 
- hosts: oldboy
  tasks:

    - name: SHell
      shell: echo $RANDOM|md5sum |cut -c 5-10
      register: get_random

    - name: Get Facts
      debug:
        msg: "{{ ansible_date_time.epoch }}"

    - name: Hostname
      hostname: name={{ get_random.stdout }}_{{ ansible_date_time.epoch }}

5.Playbook条件语句

判断在Ansible任务中_吏用频率非常高。比如yum模块可以检测软件包是否已被安装,而在这个过程中我们不用做太多的人工干预。

但是也有部分任务需要进行判断,比如:web服务器角色都需要安装nginx仓库,但其他的服务器角色并不需要,此时就会用到when判断。

比如:Centos与Ubuntu系统都需要安装httpd服务,那么就需要使用when判断主机系统,然后调用不同的模块执行。

实践案例一、根据不同操作系统,安装相同的软件包
Centos:httpd
Ubuntu:httpd2

[root@m01 project2]# cat when.yml 
- hosts: webservers
  tasks:

    - name: Install httpd Server
      yum: name=httpd state=present
      when: ansible_distribution == "CentOS"

    - name: Install httpd Server
      apt: name=httpd2 state=present
      when: ansible_distribution == "Ubuntu"

实践案例二、所有为web主机名的添加nginx仓库,其余的都跳过添加
1.如何添加yum仓库
2.如何判断,判断什么内容

---
- hosts: all
  tasks:
    - name: Add Nginx Repos
      yum_repository:
        name: nginx_tet
        description: Nginx YUM repo
        baseurl: http://nginx.org/packages/centos/7/$basearch/
        gpgcheck: no
      when: (ansible_hostname is match ("web*")) or (ansible_hostname is match ("lb*"))

1.通过register将命令执行结果保存至变量,然后通过when语句进行判断

- hosts: webservers
  tasks:
    - name: Check Httpd Server
      command: systemctl is-active httpd
      ignore_errors: yes
      register: check_httpd

    #- name: debug outprint			#仅仅只是输出结果
    #  debug: var=check_httpd

    - name: Httpd Restart
      service: name=httpd state=restarted
      when: check_httpd.rc == 0

6.Playbook循环语句

有时候我们写playbook的时候发现了很多task都要重复引用某个模块,比如一次启动10个服务,或者一次拷贝10个文件,如果按照传统的写法最少要写10次,这样会显得playbook很臃肿。如果使用循环的方式来编写playbook,这样可以减少重复使用某个模块。

实践案例一、使用循环启动多个服务

[root@m01 project2]# cat with.yml 
- hosts: webservers
  tasks:
    - name: Start httpd mariadb
      systemd: name={{ item }} state=started
      with_items:
        - httpd
        - mariadb

案例二、使用定义变量方式循环安装软件包。

- hosts: webservers
  tasks:
    - name: ensure a list of packages installed
      yum: name= "{{ packages }}" state=present
      vars:
        packages:
         - httpd
         - httpd-tools

#弃用的方式
- hosts: webservers
  tasks:
    - name: ensure a list of packages installed
      yum: name= "{{ item }}" state=present
      with_items:
        - httpd
        - httpd-tools

实践案例三、使用字典循环方式创建用户和批量拷贝文件

1.批量创建用户,使用字典的key value的方式
[root@manager ~]# cat loop-user.yml
- hosts: webservers
  tasks:
    - name: Add Users
      user: name={{ item.name }} groups={{ item.groups }} state=present
      with_items:
        - { name: 'testuser1', groups: 'bin' }
        - { name: 'testuser2', groups: 'root' }
		

2.使用字典循环批量拷贝文件
[root@m01 project2]# cat with4.yml 
- hosts: webservers
  tasks:
    - name: Copy Rsync configure and Rsync passwd
      copy: src={{ item.src }} dest={{ item.dest }} mode={{ item.mode }}
      with_items:
        - { src: "./rsyncd.conf", dest: "/etc/rsyncd.conf", mode: "0644" }
        - { src: "./rsync.passwd", dest: "/tmp/rsync.passwd", mode: "0600" }

7.handlers触发器

1.当配置发生改变,重启服务

[root@m01 project2]# cat han.yml 
- hosts: webservers
  vars:
    - http_port: 8083
  tasks:

    - name: Install Http Server
      yum: name=httpd state=present

    - name: configure httpd server
      template: src=./httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
      notify: 
        - Restart Httpd Server
        - Restart PHP Server

    - name: start httpd server
      service: name=httpd state=started enabled=yes

  handlers:
    - name: Restart Httpd Server
      systemd: name=httpd state=restarted 

    - name: Restart PHP Server
      systemd: name=php-fpm state=restarted

2.handlers注意事项

  • 1.无论多少个task通知了相同的handlers,handlers仅会在所有tasks结束后运行一次。
  • 2.只有task发生改变了才会通知handlers,没有改变则不会触发handlers
  • 3.不能使用handlers替代tasks

8.Playbook tag标记(用于调试的场景下)

默认情况下,Ansible在执行一个playbook时,会执行playbook中定义的所有任务。Ansible的标签(Tags)功能可以给单独任务甚至整个playbook打上标签,然后利用这些标签来指定要运行playbook中的个别任务,或不执行指定的任务。
1.打标签的方式有几种,比如:
对一个task打一个标签、对一个task打多个标签、对多个task打一个标签

2、对task打完标签应该如何使用

-t:执行指定的tag标签任务
-skip-tags:执行-skip-tags之外的标签任务

[root@m01 project2]# cat tag.yml 
- hosts: webservers
  vars:
    - http_port: 8083
  tasks:

    - name: Install Http Server
      yum: name=httpd state=present
      tags: 
        - install_httpd
        - httpd_server

    - name: configure httpd server
      template: src=./httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
      notify: Restart Httpd Server
      tags: 
        - confiure_httpd
        - httpd_server

    - name: start httpd server
      service: name=httpd state=started enabled=yes
      tags: service_httpd

  handlers:
    - name: Restart Httpd Server
      systemd: name=httpd state=restarted 

[root@m01 project2]# ansible-playbook tag.yml --list-tags                                    #查看所有标签
[root@m01 project2]# ansible-playbook tag.yml -t httpd_server                            #运行指定的标签
[root@m01 project2]# ansible-playbook tag.yml -t install_httpd,confiure_httpd    #运行指定的多个标签
[root@m01 project2]# ansible-playbook tag.yml --skip-tags httpd_server            #跳过指定的标签

9.Playbook 文件复用(include)

include用来动态的包含tasks任务列表include_tasks新版/include老版

include包含
include(import_playbook)此为包含完整的文件
include_tasks 此为包含任务

#主入口文件
[root@m01 project2]# cat task.yml 
- hosts: webservers
  vars:
    - http_port: 801

  tasks:
    - include_tasks: task_install.yml
    - include_tasks: task_configure.yml
    - include_tasks: task_start.yml

  handlers:
    - name: Restart Httpd Server
      systemd: name=httpd state=restarted

#任务文件
[root@m01 project2]# cat task_install.yml 
- name: Install Http Server
  yum: name=httpd state=present

[root@m01 project2]# cat task_configure.yml 
- name: configure httpd server
  template: src=./httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
  notify: Restart Httpd Server

[root@m01 project2]# cat task_start.yml 
- name: start httpd server
  service: name=httpd state=started enabled=yes

10.Playbook忽略错误(ignore_errors)

默认Playbook会偷asks执行的返囪状态,如遇到锗误则会立即终止playbook的后续的tasks执行。然而有些时候palybook即使执行锗误了也要让其继续执行

加入参数:ignore_errors: yes忽略错误

编写playbook,当有task执行失败则会立即终止后续task运行

[root@manager ~]# cat f9.yml
---
- hosts: webservers
  tasks:
    - name: Ignore False
      command: /bin/false
      ignore_errors: yes
	  
    - name: touch new file
      file: path=/tmp/bgx_ignore state=touch

11.Playbook异常处理

通常情况下,当task失败后,play将会终止,任何在前面已经被tasks notify的handlers都不会被执行。如果你在play中设置了force_handlers: yes参数,被通知的handlers就会被强制执行。(有些特殊场景可能会使用到)

force_handlers: yes 强制调用handlers (写到play里)
changed_when: false 被管理主机没有发生变化,可以使用参数将change状态改为ok
changed_when: httpd_check.stdout.find('OK') #查看变量中的某个字符串

[root@m01 project2]# cat changed_when.yml 
- hosts: webservers
  vars:
    - http_port: 8083
  tasks:

    - name: configure httpd server
      template: src=./httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
      notify: Restart Httpd Server

    - name: Check HTTPD
      shell: /usr/sbin/httpd -t
      register: httpd_check
      changed_when: 
	    - httpd_check.stdout.find('OK')
		- false

    - name: start httpd server
      service: name=httpd state=started enabled=yes

  handlers:
    - name: Restart Httpd Server
      systemd: name=httpd state=restarted 

failed_when
命令不依赖返回状态码来判定是否执行失败,而是要查看命令返回内容来决定,比如返回内容中包括 failed 字符串,则判定为失败。示例如下:

- name: this command prints FAILED when it fails 
  command: /usr/bin/example-command -x -y -z 
  register: command_result 
  failed_when: "'FAILED' in command_result.stderr"

五、Ansible加密模块

1.Ansible Vault 概述

Ansible Vault作为ansible的一项新功能可将例如passwords,keys等感数据文件逬行加密,而非存放在明文的playbooks或roles中。

2.Ansible Vault实践

ansible加密使用的是ansible-vault命令进行加密,语法示例

[root@m01 project2]# ansible-vault --help
Usage: ansible-vault [create|decrypt(解密)|edit|encrypt(加密)|encrypt_string|rekey(修改密码)|view(查看)] [options] [vaultfile.yml]

加密一个文件

ansible-vault encrypt include.yml

查看一个文件

[root@m01 project2]# ansible-vault view include.yml 
Vault password: 
- import_playbook: han.yml
- import_playbook: when2.yml 

修改加密的文件内容

[root@m01 project2]# ansible-vault edit include.yml

rekey 修改密码

[root@m01 project2]# ansible-vault rekey include.yml 
Vault password: 
New Vault password: 
Confirm New Vault password: 
Rekey successful

执行加密的playbook

echo "1" >pass
chmod 600 pass 
ansible-playbook include.yml  --vault-password-file=pass

六、jinja模板

1.Ansible Jinja2模板概述

1.1.什么是Jinja2

Jinja2是Python的全功能模板引擎

1.2.Jinja2横板与Anslble有什么关系

Ansible通常会使用Jinja2模板来修改被管理主机的配置文件。例如给10台远程主机都装上httpd服务,但是要求每个服务器的端口不一样,如何解决?

1.3.Anslble如何使用Jinja2模板

使用ansible的jinja2模板,也就是template模板。该模块和copy模块一样,都是将文件复制到远端主机上去,但是区别在于template模板可以获取要复制的文件中变量的值,而copy则是原封不动的把文件内容复制过去,比如:针对不同的主机定义不同的变量, template会在将配置文件分发出去前读取变量到iinja2模板.然后分发到不同的被管理主机上。

Ansible 使用Jinja2模板注意事项:
Ansible允许Jinja2模板中使用条件判断和循环.但是不允许在playbook中使用。
注悤:不是每个管理员都需要这个特性,但屋有些时候jinja2模板能大大提高效率。

2.Ansible Jinja2的基本使用

2.1.jinja模板基本语法

{{EXPR}}输出变量的值(会输出自定义变量的值或fact}
1)playbook文件使用template 参数
2)模板文件里面变量使用{{名称}},比如{{PORT}}或使用facts.

2.2.Jinja模板逻辑关系

{% for i in EXPR %}...{% endfor%}作为循环表达式
{% if EXPR %}...{% elif EXPR %}...{% endif%}作为条件判断
{# COMMENT #}表示注释

2.3.jinja模板使用示例,使用fact变量的示例

1)使用Playbook推送文件

[root@m01 playbook ]# cat jinja2.yml
- hosts: web
  tasks:
    - name: Copy Template File /etc/motd
      template: src=./motd.j2 dest=/etc.motd

2)准备motd.j2文件

[root@m01 playbook]# cat motd.j2
Welcome to {{ ansible_hostname }}
This system total Memory is: {{ ansible_memtotal_mb }} MB
This system free Memory is: {{ ansible_memfree_mb }} MB

3)执行Playbook

[root@m01 playbook]# ansible-playbook -i hosts jinja2.yml

3.Ansible Jinja2管理Nginx

ansible 使用jinja2的for循环表达式渲染出nginx负载均衡的配置文件

1)使用Playbook推送nginx配置文件
[root@m01 project2]# cat jinja_nginx.yml 
- hosts: webservers
  vars:
    - http_port: 80
    - server_name: www.oldboyedu.com
  tasks:
    - name: Copy Nginx COnfigure
      template: src=./oldboyedu.conf.j2 dest=/etc/nginx/conf.d/oldboyedu_proxy.conf

2)准备proxy.conf.j2配置文件
[root@m01 project2]# cat proxy.conf.j2 
upstream {{ server_name }} {
{% for i in range(1,20) %}
  server 172.16.1.{{i}}:{{http_port}};
{%endfor%}
}
server {
	listen {{ http_port }};
	server_name {{ server_name }};
	location / {
		proxy_pass http://{{ server_name }};
		proxy_set_header Host $http_host;
	}
}

循环的高级用法:
读取主机清单中的组(inventory)

upstream {{ server_name }} {
{% for i in groups['webserver'] %}
    server {{i}}:{{http_port}} weight=2;
{% endfor %}

4.Ansible Jinja2管理Keepalived

ansible 使用jinja2的if判断表达式渲染出Keepalived高可用配置文件,并推送到lb组

1)使用Playbook推送Keepalived配置文件
[root@m01 project2]# cat jinja_keepalived.yml 
- hosts: webservers
  tasks:
    - name: Copy Keepalived Configure
      template: src=./kee.conf.j2 dest=/tmp/keepalived.conf

2)准备kee.conf.j2 配置文件
[root@m01 project2]# cat kee.conf.j2 
global_defs {     
    router_id {{ ansible_hostname }}
}

vrrp_instance VI_1 {
{%if ansible_hostname =="web01" %}
    state MASTER
    priority 150
{%elif ansible_hostname == "web02" %}
    state BACKUP
    priority 100
{%endif%}

    interface eth0
    virtual_router_id 50
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
}
    virtual_ipaddress {
        10.0.0.3
    }
}

5.Ansible Jinja2 IF 管理mysql

1)使用Playbook推送mysql配置文件
[root@m01 project2]# cat jinja_mysql.yml 
- hosts: webservers
  gather_facts: no
  vars:
    PORT: 13306
   # PORT: false  #相当于开关
  tasks:
    - name: Copy MySQL Configure
      template: src=./my.cnf.j2 dest=/tmp/my.cnf

2)准备my.cnf.j2 配置文件
[root@m01 project2]# cat my.cnf.j2 
{% if PORT %}
bind-address=0.0.0.0:{{ PORT }}
{% else %}
bind-address=0.0.0.0:3306
{%endif%}

七、Ansible Rose角色

1.Ansible Rose基本概述

前面已经学过tasks和handles,那怎样组织playbook才是最好的方式呢?简单的回答就是:使用Roles! Roles基于一个已知的文件结构,去自动的加载某些vars_files, tasks以及handlers。

以便pkaybook更好的调用。相比playbook, roles的结构更加的清晰有层次。

例如:我们无论安装什么软件都会安装时间同步服务,那么每个playbook都要编写时间同步服务的task。此时我们可以将时间同步服务task写好,等到用的时候再调用就行了。

Ansible注意事项:在编写roles的时候,最好能够将一个task拆分为一个文件,方便后续复用。(彻底的打散)

2.Ansible Rose目录结构

1.rose官方目录的结构,必须那么定义

[root@m01 ~]# cd /etc/ansible/roles/
[root@m01 roles]# mkdir -p {nfs,rsync,web}/{vars,tasks,templates,handlers,files,meta}
[root@m01 roles]# tree
.
├── nfs
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
├── rsync
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
└── web
    ├── files
    ├── handlers
    ├── meta
    ├── tasks
    ├── templates
    └── vars

21 directories, 0 files

3.Ansible Rose依赖关系

roles允许您在使用role时自动引入其他role。role依赖关系存储在role目录中meta/main.yml文件中。

例如:安装wordpress需要先确保nginx与php都能正常运行,此时可以在wordpress的role中定义,依赖nginx与php-fpm的roles

[root@m01 playbook]# cat /root/roles/wordpress/meta/main.yml
---
dependencies:
  - { role: nginx }
  - { role: php-fpm }

此时wordpress的role会先执行nginx的role,然后再执行php-fpm的role,最后再执行wordpress本身的role。

4.Ansible Rose案例实战

Roles小技巧:
1.创建role 目录结构,手动或使用ansible-galaxy init test roles
2.编写role功能内容。
3.在playbook中引用

案例一、Ansible Roles重构NFS服务

1.安装nfs的task任务
[root@m01 roles]# cat nfs/tasks/install.yml 
- name: Install NFS-utils Server
  yum: name=nfs-utils state=present

2.配置nfs的task任务
[root@m01 roles]# cat nfs/tasks/config.yml 
- name: Configure Nfs-utils Server
  template: src=./exports.j2 dest=/etc/exports owner=root group=root mode=0644
  notify: Restart NFS Server

3.启动fs的task任务
[root@m01 roles]# cat nfs/tasks/start.yml 
- name: Start NFS Server
  systemd: name=nfs state=started enabled=yes

4.包含nfs的安装、配置、启动的task任务
[root@m01 roles]# cat nfs/tasks/main.yml 
- include_tasks: install.yml
- include_tasks: config.yml
- include_tasks: start.yml

5.客户端挂载nfs的task任务
[root@m01 roles]# cat nfs-client/tasks/main.yml 
- name: Mount NFS Server
  mount: path=/opt src=172.16.1.7:/data fstype=nfs opts=defaults state=mounted

6.执行所有tasks的roles主配置文件
[root@m01 roles]# cat site.yml 
- hosts: web01
  roles:
    - nfs

- hosts: web02
  roles:
    - nfs-client

5.Ansible Galaxy

Galaxy是一个免费网站,类似于github网站,网站上基本都是共享的roles角色。从Galaxy下载roles角色是快速启动自动化项目方式之一。galaxy官网

Ansible提供了一个ansible-galaxy 命令行工具,可以用来init(初始化)、search(查找)、install(安装)、remove(移除)等操作。

1.如何使用ansible-galaxy 搜索一个项目

2.查看详细信息

3.客户端搜索项目,直接安装

posted on 2019-06-13 15:20  miss_xxy  阅读(917)  评论(0编辑  收藏  举报

导航

levels of contents