Ansible介绍及安装

一:Ansible介绍及安装

一:Ansible基本概述

1.1 什么是ansible

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

1.2 同类型管理工具对比

1.puppet 学习难,安装ruby环境难,没有远程执行功能

2.ansible 轻量级,大规模环境下只通过ssh会很慢,串行的

3.saltstack 一般选择salt会使用C/S结构的模式,salt-master和salt-minion,并行的,大规模批量操作的情况下,会比Ansible速度快一些,底层使用的是zero-MQ消协队列

1.3 应用:

img

优势:

img

1.4 ansible 功能及优点:

1.远程执行(看100台服务器的内存信息)

批量执行远程命令,可以对多台主机进行远程操作

2.配置管理(管理机安装playbook,统一管理主机配置文件,批量下发)

批量配置软件服务,可以进行自动化方式配置,服务的统一配置管理,和启停

3.事件驱动

通过Ansible的模块,对服务进行不同的事件驱动

比如:

1)修改配置后重启

2)只修改配置文件,不重启

3)修改配置文件后,重新加载

4)远程启停服务管理

4.管理公有云

通过API接口的方式管理公有云,不过这方面做的不如saltstack.

saltstack本身可以通过saltcloud管理各大云厂商的云平台。

5.二次开发

因为语法是Python,所以便于运维进行二次开发。

6.任务编排

可以通过playbook的方式来统一管理服务,并且可以使用一条命令,实现一套架构的部署

7.跨平台,跨系统

几乎不受到平台和系统的限制,比如安装apache和启动服务

在Ubuntu上安装apache服务名字叫apache2

在CentOS上安装apache服务名字叫httpd

在CentOS6上启动服务器使用命令:/etc/init.d/nginx start

在CentOS7上启动服务器使用命令:systemctl start nginx

1.5 ansible执行流程

1.Ansible读取playbook剧本,剧本中会记录对哪些主机执行哪些任务。

2.首先Ansible通过主机清单找到要执行的主机,然后调用具体的模块。

3.其次Ansible会通过连接插件连接对应的主机并推送对应的任务列表。

4.最后被管理的主机会将Ansible发送过来的任务解析为本地Shell命令执行。

二:Ansible安装

环境准备:

主机名 wanIP lanIP 角色
m01 10.0.0.61 172.16.1.61 Ansible控制端
web01 10.0.0.7 172.16.1.7 Ansible被控端
web02 10.0.0.8 172.16.1.8 Ansible被控端

2.1 安装ansible

#1.安装epel源
[root@m01 ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

#2.安装Ansible
[root@m01 ~]# yum install -y ansible

# ansible <host-pattern> [options]
--version   #ansible版本信息
-v          #显示详细信息
-i          #主机清单文件路径,默认是在/etc/ansible/hosts     
-m          #使用的模块名称,默认使用command模块
-a          #使用的模块参数,模块的具体动作
-k          #提示输入ssh密码,而不使用基于ssh的密钥认证
-C          #模拟执行测试,但不会真的执行
-T          #执行命令的超时

#3.查看Ansible版本及模块路径
[root@m01 ~]# ansible --version
ansible 2.7.1
  #配置文件路径
  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)]

2.2 ansible配置文件读取顺序

[root@m01 ~]# rpm -ql ansible
[root@m01 ~]# zcat /usr/share/man/man1/ansible-config.1.gz

#要查看完整列表,请访问https://docs.ansibe.com/或使用ansibe-config命令。
For a full list check \fI\%https://docs.ansible.com/\fP\&. or use the \fIansible\-config\fP command.

#/etc/ansible/ansible.cfg 配置文件,如果存在则使用
/etc/ansible/ansible.cfg \-\- Config file, used if present

#~/.ansible.cfg 用户配置文件,覆盖默认配置(如果存在)
~/.ansible.cfg \-\- User config file, overrides the default config if present

#\&/ansible.cfg 本地配置文件(在当前工作目录中)假定为(aqproject-specific)(aq,如果存在,则重写其余文件)。
\&./ansible.cfg \-\- Local config file (in current working directory) assumed to be \(aqproject specific\(aq and overrides the rest if present.

#如上所述,ANSIBLE_CONFIG环境变量将覆盖所有其他环境变量。
As mentioned above, the ANSIBLE_CONFIG environment variable will override all others.

正常读取顺序:

ansible.cfg-----~/.ansible.cfg------&/ansible.cfg(工作目录)如果上述都没有就会找环境变量ANSIBLE_CONFIG添加

但是:

~/.ansible.cfg的内容会覆盖ansible.cfg,就是如果配置冲突的情况下,以~/.ansible.cfg为准。

企业中,有时候改完ansible.cfg配置文件,但没有生效,因为可能有其他配置文件存在,会覆盖ansible.cfg,企业中一旦没有生效,需要找到是否有其他配置文件存在。

优先级:

1、$ANSIBLE_CONFIG

2、./ansible.cfg

3、~/.ansible.cfg

4、/etc/ansible/ansible.cfg

2.3 ansible 配置文件详解:

[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 

打开:host_key_checking = False #跳过检查主机指纹

目的:跳过下图的yes/no认证。直接进入系统

img

三:Ansible Inventory(主机清单)

/etc/ansible/hosts是ansible默认主机资产清单文件,用于定义被管理主机的认证信息, 例如ssh登录用户名、密码以及key相关信息。Inventory文件中填写需要被管理的主机与主机组信息。还可以自定义Inventory主机清单的位置,使用-i指定文件位置即可。

3.1 基于密码连接

#方式一:
[root@m01 ~]# vim /etc/ansible/hosts
[web_group]
10.0.0.7 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='1'
10.0.0.8 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='1'

#第一条命令
[root@m01 ~]# ansible web_group -m ping

#方式二:
[root@m01 ~]# vim /etc/ansible/hosts
[webs]
web0[1:3] ansible_ssh_pass='1'

[root@m01 ~]# vim /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.7 web01
10.0.0.8 web02
10.0.0.9 web03


#方式三、主机+端口+密码
[webs]
web0[1:3]
[webs:vars]
ansible_ssh_pass='1'
ansible_ssh_port=22

[root@m01 ~]# ansible webs -m ping -i ./hosts
10.0.0.8 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
10.0.0.7 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

3.2 基于密钥连接,分发公钥私钥

场景一:
#创建秘钥对
[root@m01 ~]# ssh-keygen

#推送公钥
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
[root@m01 ~]# vim /etc/ansible/hosts
[webs]
10.0.0.7
10.0.0.8
10.0.0.9


场景二:
[root@m01 ~]# vim /etc/ansible/hosts
[webs]
web01 ansible_ssh_host=10.0.0.7 
web02 ansible_ssh_host=10.0.0.8
web03 ansible_ssh_host=10.0.0.9

#查看主机组中分别有哪些机器
[root@m01 ~]# ansible web_group --list-host

3.3 分组

[root@m01 ~]# vim /etc/ansible/hosts
[lnmp:children]
web_group
db_group

二:Ansible常用模块

一:Ansible命令模块

1.1 command

# 默认模块, 执行命令 [root@m01 ~]# ansible web_group -a "hostname" 

1.2 shell

# 如果需要一些管道操作,则使用shell [root@m01 ~]# ansible web_group -m shell -a "ps -ef|grep nginx" -f 50 

注意:command不识别管道符之类的操作

1.3 script

# 编写脚本

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

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

二:Ansible 软件管理模块

2.1 yum

#查看使用方法
[root@m01 ~]# ansible-doc yum
state:
present  安装软件包   默认是present,可以不写
absent   移除软件包
latest   安装最新软件包

name                            
     (包名httpd)     #本地yum源
    file://   #指定本地安装路径(yum localinstall 本地rpm包)
    http://   #指定yum源(从远程仓库获取rpm包)

[root@m01 ~]# ansible web_group -m yum -a "name=httpd state=present"

2.2 cron:定时任务

ansible web_group -m cron -a 'name="aaaaaaa" minute=0 hour=5,2 day=2 month=1 weekday=1-7 state=present job="/bin/sh /root/a.sh > /dev/null"'

name:注释
state:
    present
    absent
job:crontab要执行的命令


删除:
ansible web_group -m cron -a 'name="aaaaaaa state=absent"

分时日月周不写就直接*号

2.3 yum_repository:建YUM仓

[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx description='zls_nginx' baseurl=http://nginx.org/packages/centos/7/$basearch/"


    name: 指定repo文件名
    description:描述(repo文件中name的值)
    baseurl: 指定yum源
    file:如果定义了file那么文件名以file为准,如果没有定义file文件名以name为准
    state:
        present  #创建(默认)
        absent   #删除

[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx_new file='zls_nginx_new' description='zls_nginx' baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=no"

#删除
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx state=absent"
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx_new file=zls_nginx_new state=absent"
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx123 file=zls_nginx_new state=absent"

# 在已有的仓库文件中添加一个仓库
[root@m01 ~]# ansible 'web_group' -m yum_repository -a "name=nginx123 file='zls_nginx_new' description='zls_nginx' baseurl=http://download.driverzeng.com gpgcheck=no"

三:Ansible文件管理模块

3.1 file

[root@m01 ~]# ansible web_group -m file -a 'path=/tmp/zls state=directory owner=root group=root mode=0644'
    path: 指定创建的路径
    state:
        touch:创建文件
        directory:创建目录
        file:修改文件属性(默认)
        link:软连接
        absent:删除指定的文件或目录
    owner:指定属主
    group:指定属组
    mode:指定权限

3.2 get_url:下载

[root@m01 ~]# ansible web01 -m get_url -a 'url=https://mirrors.aliyun.com/zabbix/zabbix/4.4/rhel/7/x86_64/zabbix-agent-4.4.0-1.el7.x86_64.rpm dest=/tmp mode=0644'

[root@m01 ~]# ansible web01 -m get_url -a 'url=http://test.driverzeng.com/Zabbix_File/percona-release-0.1-3.noarch.rpm dest=/tmp mode=0644 checksum=md5:ea13c36cf79e131bded48bac4f7e88c2'

url:指定软件包地址
dest:指定下载的路径
mode:指定文件的权限
checksum:
    md5:
    sha256:

3.3 unarchive:解压缩

[root@m01 ~]# ansible web02 -m unarchive -a 'src=/root/wordpress-5.0.3-zh_CN.tar.gz dest=/tmp'

src:指定压缩包的路径
dest:指定解压的位置
remote_src:
    yes:
    no:(默认)

四:Ansible服务管理模块

systemd

[root@m01 ~]# ansible web01 -m systemd -a 'name=nginx state=started'
name:指定服务名
state:
    started
    stopped
    restarted
    reloaded
enabled:
    true
    false

五:Ansible用户管理模块

user

group

[root@m01 ~]# ansible web_group -m group -a 'name=qls state=present gid=250'
    name:指定组名
    state:
        present:创建
        absent:删除
    gid:指定组的id

六:Ansible磁盘挂载模块

mount:挂载

[root@m01 ~]# ansible web01 -m mount -a 'path=/data src=172.16.1.31:/data fstype=nfs state=mounted'
path:挂载的路径
src:挂载点
fstype:挂载类型
state:
    present      # 开机挂载,仅将挂载配置写入/etc/fstab
    absent       # 卸载,并清除/etc/fstab
    mounted      # 挂载并写入/etc/fstab
    unmounted    # 卸载,不清除 /etc/fstab

七:Ansible主机信息模块

setup

八:Ansible防火墙模块

selinux

[root@m01 ~]# ansible web01 -m selinux -a 'state=disabled'

firewalld

[root@m01 ~]# ansible web01 -m firewalld -a 'port=80/tcp state=enabled'

九:Ansible 数据库模块

9.1 mysql_db:创建数据库

- name: Create a new database with name 'jiangwei'
  mysql_db:
    name: jiangwei
    state: present
此时,遇到一个问题,playbook建库时,需要先登陆到数据库,登陆到数据库这个动作必须要自动完成,此时引入:
- login_host
        Host running the database.
        [Default: localhost]
        type: str

- login_password
        The password used to authenticate with.
        [Default: (null)]
        type: str

- login_port
        Port of the MySQL server. Requires `login_host' be defined as
        other than localhost if login_port is used.
        [Default: 3306]
        type: int

- login_user
        The username used to authenticate with.
        [Default: (null)]
        type: str

EX:
- name: Create a new database with name 'jiangwei'
  mysql_db:
    login_user: root
    login_password: '123'
    login_host: localhost
    name: jiangwei
    state: present

9.2 mysql_user:创建数据库用户

- name: Create database user with password and all database privileges =
  mysql_user:
    name: bob
    password: 12345
    priv: '*.*:ALL'
    state: present

EX:
- name: Create MySQL User
       mysql_user:
         name: wordpress
         password: '123456'
         priv: '*.*:ALL'
         host: '%'
         state: present

三:Ansible变量

一:变量概述

​ 变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如nginx-1.6.3这个软件包的版本,在其它地方或许会反复使用,那么如果讲此值设置为变量,然后再在其他的playbook中调用,会方便许多。如此一来还方便维护,减少维护的成本。

1.1 定义变量的方式

1.通过命令行进行变量定义
[root@m01 ~]# vim test.yml
- hosts: web_group
  tasks:
  - name: Install httpd Server
    yum:
      name: "{{ web_server }}"

#定义阶段
[root@m01 ~]# ansible-playbook test.yml -e "web_server=vsftpd"
2.在play文件中进行变量定义
- name: ensure a list of packages installed
  yum:
    name: "{{ packages }}"
  vars:
    packages:
    - httpd
    - httpd-tools

#方法一
- hosts: web_group
  vars:
    packages:
      - samba
      - vsftpd
  tasks:
  - name: Install httpd  mariadb php Server
    yum:
      name: "{{ packages }}"

#方法二
- hosts: web_group
  vars:
      - web_server: lsof
      - db_server: htop
      - php_server: iftop,sysstat        #这边注意多个软件包的写法
  tasks:
  - name: Install httpd  mariadb php Server
    yum:
      name:
        - "{{ web_server }}"
        - "{{ db_server }}"
        - "{{ php_server }}"
3.通过Inventory主机信息文件中进行变量定义(不推荐使用,容易使环境混乱)
#定义阶段
[root@m01 ~]# vim /etc/ansible/hosts
[web_group]
web01 ansible_ssh_host=10.0.0.7
web02 ansible_ssh_host=10.0.0.8
[web_group:vars]
web_server=httpd
index_file=index.html

#调用阶段
- hosts: web_group
  tasks:
  - name: Install httpd Server
    yum:
      name: "{{ web_server }}"
  - name: Create Index File
    file:
      path: /tmp/{{ index_file }}
      state: touch 
4.在一个模板文件中定义变量
EX1:
#定义变量
[root@m01 ~]#vim vars_file.yml 
filename: vars_file

#调用变量
[root@m01 bianliang]# vim file.yml 
- hosts: web_group
  vars_files: ./vars_file.yml
  tasks:
    - name: Create {{ filename }} DIR
      file:
        path: /root/{{ filename }}
        state: directory
        
EX2:
#定义变量
[root@m01 ~]# vim vars_file.yml
mysql_ip: localhost
mysql_user: root
mysql_password: '123'

#调用变量
- hosts: db01
  vars_files: ./vars_file1.yml
  tasks:
    - name: Create a new database with name 'jiangwei'
      mysql_db:
            login_user: {{ mysql_user }}
            login_password: {{ mysql_password }}
            login_host: {{ mysql_ip }}
            name: jiangwei
            state: present  
此变量目的:以后创建用户只需要在vars_file1.yml文件中修改即可,无须修改配置文件


#获取Ansible内置变量(利用setup模块)
- hosts: web_group
  tasks:
    - name: Touch IP File
      file:
        path: /root/{{ ansible_default_ipv4['address'] }}
        state: touch

    - name: Touch Hostname File
      file:
        path: /root/{{ ansible_fqdn }}
        state: touch
#创建分别以地址和主机名命令的文件       
[root@web01 ~]# ll
total 48
-rw-r--r--  1 root root     0 Nov 19 21:03 10.0.0.7
-rw-r--r--  1 root root     0 Nov 19 21:03 web01
5.官方推荐变量定义

之前的几种变量定义都不是很好用,比较好用的是在Ansible项目目录下创建两个变量目录:
host_vars
group_vars
切记,目录名字一定要一致,不能做任何修改。

注意:playbook创建在哪里,这两个文件就创建在哪里。
EX1:
#创建出组变量目录和主机变量目录
[root@m01 bianliang]# mkdir host_vars

#想给哪个主机定义变量,就在host_vars目录下创建该主机的名字文件
例如:web01
[root@m01 bianliang]# vim host_vars/web01   #注意web01必须和主机名对应,
web_server: nginx

[root@m01 bianliang]# vim host_vars/web02
web_server: samba

- hosts: web_group
  tasks:
    - name: Install
      yum:
        name: "{{ web_server }}"
此变量目的:当需求为web01只安装nginx,web02只安装samba时。



EX2:
#定义阶段
[root@m01 ~]# mkdir group_vars

#切记定义变量的文件必须以组名为文件名
[root@m01 ~]# vim /root/group_vars/web_group
web_server: httpd

#调用阶段
- hosts: web_group
  tasks:
  - name: Install httpd Server
    yum:
      name: "{{ web_server }}" 

1.2 变量的优先级

1.命令行

2.vars_files

3.vars

4.host_vars

5.group_vars

#官方推荐
host_vars
group_vars

二:变量注册

absible的模块在运行之后,其实都会返回一些result结果,就像是执行脚本,我们有的时候需要脚本给我们一些return返回值,我们才知道,上一步是否可以执行成功,但是默认情况下,ansibleresult并不会显示出来,所以,我们可以把这些返回值'存储'到变量中,这样我们就能通过'调用'对应的变量名,从而获取到这些result,这种将模块的返回值,写入到变量中的方法被称为变量注册

如下一个playbook示例:

#编辑剧本
[root@m01 ~]# vim register.yml
- hosts: web_group
  tasks:
    - name: Test Register Vars
      shell: "ls -l /"

#查看执行结果
[root@m01 ~]# ansible-playbook register.yml

PLAY [web_group] *****************************************************************************************************************************************************************************************************************************

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

TASK [Test Register Vars] ********************************************************************************************************************************************************************************************************************
changed: [web01]
changed: [web02]

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

如上执行结果可见,当我们使用shell模块执行ls -l /时,ansible给我们返回的只有changed我们无法看到执行之后的结果,所以此时我们需要使用到变量注册

playbook如下:

#编辑playbook
[root@m01 ~]# vim register.yml
- hosts: web_group
  tasks:
    - name: Test Register Vars
      shell: "ls -l /"
      register: list_dir     ####

    - name: Return Result
      debug:
        msg: "{{ list_dir }}"

#查看执行结果
[root@m01 ~]# ansible-playbook register.yml

PLAY [web_group] *****************************************************************************************************************************************************************************************************************************

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

TASK [Test Register Vars] ********************************************************************************************************************************************************************************************************************
changed: [web01]
changed: [web02]

TASK [Return Result] *************************************************************************************************************************************************************************************************************************
ok: [web01] => {
    "msg": {
        "changed": true,
        "cmd": "ls -l /",
        "delta": "0:00:00.005536",
        "end": "2019-09-16 11:52:16.492946",
        "failed": false,
        "rc": 0,
        "start": "2019-09-16 11:52:16.487410",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "总用量 28\nlrwxrwxrwx.   1 root root    7 3月   9 2019 bin -> usr/bin\ndr-xr-xr-x.   5 root root 4096 3月   9 2019 boot\ndrwxr-xr-x.  20 root root 3280 9月   8 12:25 dev\ndrwxr-xr-x.  80 root root 8192 9月  10 20:52 etc\ndrwxr-xr-x.   5 root root   41 9月   8 16:22 home\nlrwxrwxrwx.   1 root root    7 3月   9 2019 lib -> usr/lib\nlrwxrwxrwx.   1 root root    9 3月   9 2019 lib64 -> usr/lib64\ndrwxr-xr-x.   2 root root    6 4月  11 2018 media\ndrwxr-xr-x.   2 root root    6 4月  11 2018 mnt\ndrwxr-xr-x.   2 www  www     6 9月  10 15:31 opt\ndr-xr-xr-x. 128 root root    0 9月   8 12:25 proc\ndr-xr-x---.   9 root root 4096 9月  10 21:16 root\ndrwxr-xr-x.  25 root root  740 9月  10 20:52 run\nlrwxrwxrwx.   1 root root    8 3月   9 2019 sbin -> usr/sbin\ndrwxr-xr-x.   2 root root    6 4月  11 2018 srv\ndr-xr-xr-x.  13 root root    0 9月   8 12:25 sys\ndrwxrwxrwt.  15 root root 4096 9月  16 11:52 tmp\ndrwxr-xr-x.  13 root root  155 3月   9 2019 usr\ndrwxr-xr-x.  21 root root 4096 9月  10 20:52 var",
        "stdout_lines": [
            "总用量 28",
            "lrwxrwxrwx.   1 root root    7 3月   9 2019 bin -> usr/bin",
            "dr-xr-xr-x.   5 root root 4096 3月   9 2019 boot",
            "drwxr-xr-x.  20 root root 3280 9月   8 12:25 dev",
            "drwxr-xr-x.  80 root root 8192 9月  10 20:52 etc",
            "drwxr-xr-x.   5 root root   41 9月   8 16:22 home",
            "lrwxrwxrwx.   1 root root    7 3月   9 2019 lib -> usr/lib",
            "lrwxrwxrwx.   1 root root    9 3月   9 2019 lib64 -> usr/lib64",
            "drwxr-xr-x.   2 root root    6 4月  11 2018 media",
            "drwxr-xr-x.   2 root root    6 4月  11 2018 mnt",
            "drwxr-xr-x.   2 www  www     6 9月  10 15:31 opt",
            "dr-xr-xr-x. 128 root root    0 9月   8 12:25 proc",
            "dr-xr-x---.   9 root root 4096 9月  10 21:16 root",
            "drwxr-xr-x.  25 root root  740 9月  10 20:52 run",
            "lrwxrwxrwx.   1 root root    8 3月   9 2019 sbin -> usr/sbin",
            "drwxr-xr-x.   2 root root    6 4月  11 2018 srv",
            "dr-xr-xr-x.  13 root root    0 9月   8 12:25 sys",
            "drwxrwxrwt.  15 root root 4096 9月  16 11:52 tmp",
            "drwxr-xr-x.  13 root root  155 3月   9 2019 usr",
            "drwxr-xr-x.  21 root root 4096 9月  10 20:52 var"
        ]
    }
}
ok: [web02] => {
    "msg": {
        "changed": true,
        "cmd": "ls -l /",
        "delta": "0:00:00.005813",
        "end": "2019-09-16 11:52:16.495422",
        "failed": false,
        "rc": 0,
        "start": "2019-09-16 11:52:16.489609",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "总用量 24\nlrwxrwxrwx.   1 root root    7 3月   9 2019 bin -> usr/bin\ndr-xr-xr-x.   5 root root 4096 3月   9 2019 boot\ndrwxr-xr-x.  20 root root 3260 9月  10 09:47 dev\ndrwxr-xr-x.  80 root root 8192 9月  10 20:52 etc\ndrwxr-xr-x.   5 root root   41 9月   8 16:22 home\nlrwxrwxrwx.   1 root root    7 3月   9 2019 lib -> usr/lib\nlrwxrwxrwx.   1 root root    9 3月   9 2019 lib64 -> usr/lib64\ndrwxr-xr-x.   2 root root    6 4月  11 2018 media\ndrwxr-xr-x.   2 root root    6 4月  11 2018 mnt\ndrwxr-xr-x.   2 www  www     6 9月  10 15:31 opt\ndr-xr-xr-x. 128 root root    0 8月  15 15:10 proc\ndr-xr-x---.   6 root root  180 9月  10 21:16 root\ndrwxr-xr-x.  25 root root  740 9月  10 20:52 run\nlrwxrwxrwx.   1 root root    8 3月   9 2019 sbin -> usr/sbin\ndrwxr-xr-x.   2 root root    6 4月  11 2018 srv\ndr-xr-xr-x.  13 root root    0 8月  15 15:10 sys\ndrwxrwxrwt.  14 root root 4096 9月  16 11:52 tmp\ndrwxr-xr-x.  13 root root  155 3月   9 2019 usr\ndrwxr-xr-x.  21 root root 4096 9月  10 20:52 var",
        "stdout_lines": [
            "总用量 24",
            "lrwxrwxrwx.   1 root root    7 3月   9 2019 bin -> usr/bin",
            "dr-xr-xr-x.   5 root root 4096 3月   9 2019 boot",
            "drwxr-xr-x.  20 root root 3260 9月  10 09:47 dev",
            "drwxr-xr-x.  80 root root 8192 9月  10 20:52 etc",
            "drwxr-xr-x.   5 root root   41 9月   8 16:22 home",
            "lrwxrwxrwx.   1 root root    7 3月   9 2019 lib -> usr/lib",
            "lrwxrwxrwx.   1 root root    9 3月   9 2019 lib64 -> usr/lib64",
            "drwxr-xr-x.   2 root root    6 4月  11 2018 media",
            "drwxr-xr-x.   2 root root    6 4月  11 2018 mnt",
            "drwxr-xr-x.   2 www  www     6 9月  10 15:31 opt",
            "dr-xr-xr-x. 128 root root    0 8月  15 15:10 proc",
            "dr-xr-x---.   6 root root  180 9月  10 21:16 root",
            "drwxr-xr-x.  25 root root  740 9月  10 20:52 run",
            "lrwxrwxrwx.   1 root root    8 3月   9 2019 sbin -> usr/sbin",
            "drwxr-xr-x.   2 root root    6 4月  11 2018 srv",
            "dr-xr-xr-x.  13 root root    0 8月  15 15:10 sys",
            "drwxrwxrwt.  14 root root 4096 9月  16 11:52 tmp",
            "drwxr-xr-x.  13 root root  155 3月   9 2019 usr",
            "drwxr-xr-x.  21 root root 4096 9月  10 20:52 var"
        ]
    }
}

PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
web01                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web02                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

#只输出自己想要的内容
[root@m01 ~]# vim register.yml
- hosts: web_group
  tasks:
    - name: Test Register Vars
      shell: "ls -l /"
      register: list_dir

    - name: Return Result
      debug:
        msg: "{{ list_dir.stdout_lines }}"

#查看结果
[root@m01 ~]# ansible-playbook register.yml

PLAY [web_group] *****************************************************************************************************************************************************************************************************************************

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

TASK [Test Register Vars] ********************************************************************************************************************************************************************************************************************
changed: [web01]
changed: [web02]

TASK [Return Result] *************************************************************************************************************************************************************************************************************************
ok: [web01] => {
    "msg": [
        "总用量 28",
        "lrwxrwxrwx.   1 root root    7 3月   9 2019 bin -> usr/bin",
        "dr-xr-xr-x.   5 root root 4096 3月   9 2019 boot",
        "drwxr-xr-x.  20 root root 3280 9月   8 12:25 dev",
        "drwxr-xr-x.  80 root root 8192 9月  10 20:52 etc",
        "drwxr-xr-x.   5 root root   41 9月   8 16:22 home",
        "lrwxrwxrwx.   1 root root    7 3月   9 2019 lib -> usr/lib",
        "lrwxrwxrwx.   1 root root    9 3月   9 2019 lib64 -> usr/lib64",
        "drwxr-xr-x.   2 root root    6 4月  11 2018 media",
        "drwxr-xr-x.   2 root root    6 4月  11 2018 mnt",
        "drwxr-xr-x.   2 www  www     6 9月  10 15:31 opt",
        "dr-xr-xr-x. 128 root root    0 9月   8 12:25 proc",
        "dr-xr-x---.   9 root root 4096 9月  10 21:16 root",
        "drwxr-xr-x.  25 root root  740 9月  10 20:52 run",
        "lrwxrwxrwx.   1 root root    8 3月   9 2019 sbin -> usr/sbin",
        "drwxr-xr-x.   2 root root    6 4月  11 2018 srv",
        "dr-xr-xr-x.  13 root root    0 9月   8 12:25 sys",
        "drwxrwxrwt.  15 root root 4096 9月  16 11:54 tmp",
        "drwxr-xr-x.  13 root root  155 3月   9 2019 usr",
        "drwxr-xr-x.  21 root root 4096 9月  10 20:52 var"
    ]
}
ok: [web02] => {
    "msg": [
        "总用量 24",
        "lrwxrwxrwx.   1 root root    7 3月   9 2019 bin -> usr/bin",
        "dr-xr-xr-x.   5 root root 4096 3月   9 2019 boot",
        "drwxr-xr-x.  20 root root 3260 9月  10 09:47 dev",
        "drwxr-xr-x.  80 root root 8192 9月  10 20:52 etc",
        "drwxr-xr-x.   5 root root   41 9月   8 16:22 home",
        "lrwxrwxrwx.   1 root root    7 3月   9 2019 lib -> usr/lib",
        "lrwxrwxrwx.   1 root root    9 3月   9 2019 lib64 -> usr/lib64",
        "drwxr-xr-x.   2 root root    6 4月  11 2018 media",
        "drwxr-xr-x.   2 root root    6 4月  11 2018 mnt",
        "drwxr-xr-x.   2 www  www     6 9月  10 15:31 opt",
        "dr-xr-xr-x. 128 root root    0 8月  15 15:10 proc",
        "dr-xr-x---.   6 root root  180 9月  10 21:16 root",
        "drwxr-xr-x.  25 root root  740 9月  10 20:52 run",
        "lrwxrwxrwx.   1 root root    8 3月   9 2019 sbin -> usr/sbin",
        "drwxr-xr-x.   2 root root    6 4月  11 2018 srv",
        "dr-xr-xr-x.  13 root root    0 8月  15 15:10 sys",
        "drwxrwxrwt.  14 root root 4096 9月  16 11:54 tmp",
        "drwxr-xr-x.  13 root root  155 3月   9 2019 usr",
        "drwxr-xr-x.  21 root root 4096 9月  10 20:52 var"
    ]
}

PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
web01                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web02                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

#debug模块常用参数
msg:            #调试输出的消息
var:            #将某个任务执行的输出作为变量传递给debug模块,debug会直接将其打印输出
verbosity:      #debug的级别(默认是0级,全部显示)       

四:Ansible流程控制

一:playbook条件语句---when判断

1.1 根据不同的操作系统安装nginx

#官方示例:
tasks:
  - name: "shut down Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_facts['os_family'] == "Debian"
    # note that all variables can be used directly in conditionals without double curly braces
- hosts: web_group
  tasks:
    - name: Install CentOS nginx
      yum:
        name: nginx
        state: present
    #官方
      when: ansible_facts['os_family'] == "CentOS"
    #非官方
      when: ansible_distribution == "CentOS"

    - name: Install Ubuntu nginx
      yum:
        name: apache2
        state: present
      when: ansible_facts['os_family'] == "Ubuntu"

1.2 使用括号对条件分组

tasks:
  - name: "shut down CentOS 6 and Debian 7 systems"
    command: /sbin/shutdown -t now
    when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
          (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")

1.3 指定多条件为列表

tasks:
  - name: "shut down CentOS 6 systems"
    command: /sbin/shutdown -t now
    when:
      - ansible_facts['distribution'] == "CentOS"
      - ansible_facts['distribution_major_version'] == "6"

案例:rsync推送配置文件

#服务端:
[root@m01 ~]# cat rsyncd/rsyncd.yml
- hosts: rsync_server
  tasks:
    - name: Install Rsyncd Server
      yum:
        name: rsync
        state: present

    - name: Create www Group
      group:
        name: www
        gid: 666
        
    - name: Create www User
      user:
        name: www
        group: www
        uid: 666
        create_home: false
        shell: /sbin/nologin

    - name: Scp Rsync Config
      copy:
        src: ./rsyncd.j2
        dest: /etc/rsyncd.conf
        owner: root
        group: root
        mode: 0644
      when: ansible_hostname == "backup"
           #ansible_fqdn == "backup"

    - name: Create Passwd File
      copy:
        content: 'rsync_backup:123'
        dest: /etc/rsync.passwd
        owner: root
        group: root
        mode: 0600
      when: ansible_hostname == "backup"

    - name: Create backup Directory
      file:
        path: /backup
        state: directory
        mode: 0755
        owner: www
        group: www
        recurse: yes
      when: ansible_hostname == "backup"

    - name: Start Rsyncd Server
      systemd:
        name: rsyncd
        state: started
      when: ansible_hostname == "backup"
      
#客户端
[root@m01 ~]# vim rsync.yml
- hosts: rsync_server
  tasks:
    - name: SCP Backup Shell
      copy:
        src: ./backup.sh
        dest: /root/backup.sh
      when: ansible_hostname is match "web*"

注意点:1.when需要和模块对齐

2.如果用正则需要用“is match”来匹配

3.正常情况下判断是“==” 如果不等于“!=”

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

- hosts: web_group
  tasks:
    - name: Check Httpd Server
      command: systemctl is-active httpd
      ignore_errors: yes     #忽略错误,方便下一步继续执行
      register: check_httpd

    - name: Httpd Restart
      service:
        name: httpd
        state: started
      when: check_httpd.rc != 0
      
说明:
1.systemctl is-active httpd 查看httpd是否启动,没有启动会报错rc=3(0为正常)
2.register设置变量check_httpd
3.when判断check_httpd.rc是否等于0
4.如果不等于0,将开启nginx服务
      

二:playbook循环语句

如:同时启动多个服务或同时创建多个mysql用户

2.1 定义变量循环

EX1:启动多个服务
- hosts: web_group
  tasks:
    - name: start service
      systemd:
        name: "{{ item }}"
        state: started
      with_items:
        - httpd
        - php-fpm
        - mariadb
        
EX2:安装多个服务
- hosts: web_group
  tasks:
    - name: ensure a list of packages installed
      yum: name= "{{ item }}" state=present
      with_items:
        - httpd
        - httpd-tools

2.2 字典循环

EX1:创建多个用户
[root@m01 ~]# cat loop.yml
- hosts: web_group
  tasks:
    - name: Add Users
      user:
        name: "{{ item.name }}"
        groups: "{{ item.groups }}"
        state: present
      with_items:
        - { name: 'zls', groups: 'linux' }
        - { name: 'egon', groups: 'python' }
        
EX2:拷贝多个文件
- hosts: web_group
  tasks:
    - name: Configure Nginx Websit PHP Conf
      copy:
        src: "{{ item.src }}"
        dest: "{{ item.dest }}"
        mode: "{{ item.mode }}"
      with_items:
        - {src: './nginx.j2',dest: '/etc/nginx/nginx.conf',mode: '0644'}
        - {src: './php.drz.com.j2',dest: '/etc/nginx/conf.d/php.drz.com.conf',mode: '0755'}
        - {src: './php.j2',dest: '/etc/php-fpm.d/www.conf',mode: '0000'}

三:playbook handlers

handler用来执行某些条件下的任务,比如当配置文件发生变化的时候,通过notify触发handler去重启服务。

在saltstack中也有类似的触发器,写法相对Ansible简单,只需要watch,配置文件即可。

案例

[root@m01 ~]# cat handler.yml 
- hosts: web_group
  vars:
    - http_port: 8080
  tasks:
    - name: Install Http Server
      yum:
        name: httpd
        state: present

    - name: config httpd server
      template:
        src: ./httpd.j2
        dest: /etc/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

注意:
1.无论多少个task通知了相同的handlers,handlers仅会在所有tasks结束后运行一次。

2.Handlers只有在其所在的任务被执行时,才会被运行;如果一个任务中定义了notify调用Handlers,但是由于条件判断等原因,该任务未被执行,那么Handlers同样不会被执行。

3.Handlers只会在每一个play的末尾运行一次;如果想在一个playbook中间运行Handlers,则需要使用meta模块来实现。例如: -meta: flush_handlers。

4.如果一个play在运行到调用Handlers的语句之前失败了,那么这个Handlers将不会被执行。我们可以使用meta模块的--force-handlers选项来强制执行Handlers,即使Handlers所在的play中途运行失败也能执行。

5.不能使用handlers替代tasks

五:Ansible Roles

一:Ansible Roles目录结构

1.1 官方推荐最佳实践目录结构定义方式

roles/
    common/               # this hierarchy represents a "role"
        tasks/            #
            main.yml      #  <-- tasks file can include smaller files if warranted
        handlers/         #
            main.yml      #  <-- handlers file
        templates/        #  <-- files for use with the template resource
            ntp.conf.j2   #  <------- templates end in .j2
        files/            #
            bar.txt       #  <-- files for use with the copy resource
            foo.sh        #  <-- script files for use with the script resource
        vars/             #
            main.yml      #  <-- variables associated with this role
            
            
#不常用
        defaults/         #
            main.yml      #  <-- default lower priority variables for this role
        meta/             #
            main.yml      #  <-- role dependencies
             library/          # roles can also include custom modules
        module_utils/     # roles can also include custom module_utils
        lookup_plugins/   # or other types of plugins, like lookup in this case

    webtier/              # same kind of structure as "common" was above, done for the webtier role
    monitoring/           # ""
    fooapp/               # ""

1.2 roles目录结构使用galaxy创建

[root@m01 ~]# cd /etc/ansible/roles/

[root@m01 roles]# tree wordpress/
nfs/                #项目名称
├── defaults        #低优先级变量
├── files           #存放文件
├── handlers        #触发器文件
├── meta            #依赖关系文件
├── tasks           #工作任务文件
├── templates       #jinja2模板文件
├── tests           #测试文件
└── vars            #变量文件

备注:只需要这些目录,ansible的roles会自动识别里面的main.yml

二:Ansible Roles依赖关系

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

例如:推送wordpress并解压,前提条件,必须要安装nginx和php,把服务跑起来,才能运行wordpress的页面,此时我们就可以在wordpress的roles中定义依赖nginx和php的roles

[root@m01 roles]# vim /etc/ansible/roles/wordpress/meta/main.yml
dependencies:
  - { role: nginx }
  - { role: php }

如果编写了meta目录下的main.yml文件,那么Ansible会自动先执行meta目录中main.yml文件中的dependencies文件,如上所示,就会先执行nginx和php的安装。

如果安装wordpress,main.yml里有nginx和php
流程:
1.当你执行worepress的playbook,会先在meta的main.yml里找nginx
2.找到后,会在roles目录里找nginx,再去nginx目录的meta找依赖,如果无,会在tasks目录里找到安装、配置、启动等
3.装完nginx后再同理执行php
4.最后再执行wordpress的tasks

三:Ansible Roles创建目录

ansible-galaxy init 服务名 roles
[root@m01 ~]# cd /etc/ansible/roles/
[root@m01 /etc/ansible/roles]# ansible-galaxy init rsync roles

- rsync was created successfully
  [root@m01 /etc/ansible/roles]# tree 
  .
  └── rsync
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml

9 directories, 8 files

猜你喜欢

转载自www.cnblogs.com/captain-jiang/p/12058729.html