Ansible 学习笔记(一)

1、ansible的基本命令格式
    ansible [options]
    #host 必选项,表示Inventory文件中指定的主机或者主机组,可以为ip、hostname、Iventory中的group组名,还可以使用.*等通配符
    #option可选项,常见可选项如下
    -m name 或 --module=name :       指定执行使用的模块名
    -u username 或 --user=username : 指定远程主机以什么用户执行命令
    -s  或 --sudo :                  相当于linux中切换到root用户执行命令
    -U sudo_username 或 --sudo-user=sudo_username : 表示切换到指定的用户sudo_username执行命令
    -b 或 --become :                                替换旧版中的-s和--sudo命令
    -become-user  :                                  替换旧版中的--sudo-user命令
    #旧版
    ansible all -m ping -u hadoop                                 #以hadoop用户执行所有主机是否ping得通
    ansible all -m ping -u hadoop --sudo                          #以hadoop用户sudo 切换到root用户执行ping命令
    ansible all -m ping -u hadoop --sudo --sudo-user  master      #以hadoop用户sudo 切换到master用户去执行ping命令
    #新版
    ansible all -m ping -u hadoop -b                           #切换至root用户执行ping命令
    ansible all -m ping -u hadoop -b --become-user master      #以hadoop用户sudo切换到master用户执行ping命令
    ansible web1 -m ping                                      #检查web1服务器组中的所有服务器是否都存活
    ansible web1 -m  copy -a "src=/etc/fstab  dest=/tmp/fstab owner=root group=root mode = 644 backup=yes " #复制本地文件到远程

2、ansible-playbook的基本命令格式
    ansible-playbook test.yml   
    #ansible后面跟事先编辑好的playbook.yml文件
    其实可以看成将一系列ansible命令按照一定的条件组织好,形成一个命令集,存放到yml文件中,再使用ansible-playbook命令统一批量执行。
    

3、ansible-galaxy命令格式 
#类似于github和pip功能,可以从galaxy中下载和上传roles 
(1)ansible-galaxy [init|info|install|list|remove]  [--help] [options]
    #init:初始化本地的Roles配置,以备上传到galaxy中
    #info:列出指定Roles的详细信息
    #install:从galax中下载并安装指定的Roles到本地
    #list: 列出本地已下载的所有Roles
    #remove: 删除已经下载的Roles
(2)--help 显示init、info、install……的具体用法
    ansible init  --help
    usage : ansible-galaxy init [options] role_name
    options可选参数如下:
    #-f, --force 强制覆盖本地已经存在的Role
    #-h, --help  显示帮助信息
    #-c, --ignore-certs  忽略SSL授权认证的错误
    #-p init_path , --init-path=init_path 设置Role的下载存放地址,默认为当前目录
    #--offline , 直接离线安装,不需要在线下载
    #-s api_server , --server=api_server , 设置下载服务器的目标地址,默认是http://galaxy.ansible.com
    #-v , --verbose , 详细信息模式
    #--version , 显示版本号
(3) 案例:
    ansible-galaxy --ignore-errors install azavea.git   #默认保存在/etc/ansible/roles目录下
    
4、ansible-pull基本命令格式
    ansible-pull [options] [playbook.yml] 
    通过ansible-pull命令与git、crontab共同使用,可以通过crontab定期拉去指定的git版本到本地,并以指定模式自动运行预先制定好的指令
    */20 * * * *  root /usr/local/bin/ansible-pull -o -C 2.1.0 -d /src/www/king-gw/  -i /etc/ansible/hosts - U git://git.kingifa.com/king-gw-ansiblepull >> /var/log/ansible-pull.log 2>&1

5、ansible-doc基本命令格式
    ansible-doc [options] [module...]
    Ansible模块文档说明,ansible中的每一个模块(ping 就是一个模块)都有详细的介绍
    ansible-doc ping    #显示ping模块的详细说明
    ansible-doc -l         #列出所有模块

6、ansible-vault基本命令格式
    ansible-vault [create|encrypt|decrypt|edit|rekey|view]    [--help]    [options]  filename
    valut:街道,拱顶,保险库 , ansible-vault主要用来加密和解密yml文件,加密后的yml文件里面就是一串乱码,必须解密后才能正常查看
    ansible-vault encrypt a.yml    #加密文件,
    ansible-vault decrypt a.yml    #解密文件

7、ansible-console
    通过该命令可以直接进入ansible的交互式命令行终端模式,类似于shell命令行,常用于集中处理一批临时命令,复杂程度低于使用ansible-playbooks
    提示符:root@all (4)[f:5]   #当前用户名@当前所在Inventory中定义的组 组中主机(ip地址)的数量 f:5 表示fork线程数为5
    cd web1 #可以切换地址组,
    forks 2 #设置线程数  
    list    #列出组中的所有主机ip地址
    
8、Inventory文件的配置
    Inventory文件是用来管理主机的配置文件,其中记录了很多不同组,每个组中我们可以添加不同的主机IP地址,通过该文件我们就可以批量化地管理多台主机了
    Inventory文件默认存放路径为/etc/ansible/hosts中,在使用ansible命令是可以通过参数-i 或者 --inventory-file来读取指定的inventory文件
    ansible -i /etc/ansible/hosts  webs -m  ping -u hadoop # 读取指定的Inventory文件
    如果系统中只有一个Inventory文件,我们就不需要特别指定,会默认去/etc/ansible/hosts目录中读取。
    另外一台主机可以同时属于多个不同的组
(1)    定义主机和组
    [websevers]             # 定义一个组
    192.168.1.80            #组内可以为ip地址,也可以为主机名
    web1.magedu.com
    web2.mageud.com:2222     #如果目标主机的ssh端口不是默认的22,就需要在主机名或ip地址后面指定SSH端口号
    web[10:20].magedu.com   #[10:20]通配符代表从10~20之间的所有数字, 这一行包含了11台主机
    web[a:f].mageud.com        #[a:f]代表从a~f中所有的字母,这一行包含了6台主机
    
(2)定义主机变量
    为单个主机服务器添加特有的配置,直接在对应的主机后面,添加变量
    [webservers]
    weba.magedu.com http_port=808 maxRequestPerChild=801 #表示这台主机上的http服务的端口不是默认的8080,而是808 ,以及最大链接数为801个

(3)定义组变量
    为某一个组中所有的主机赋予统一变量
    [webservers]
    weba.magedu.com
    webb.magedu.com
    webc.magedu.com
        
    [webservers:vars]    #给webservers组定义主变量
    ntp_server=ntp.magedu.com    #将webservers组中的所有主机ntp_sserver的值为ntp.magedu.com
    nfs_server=nfs.magedu.com    #将webservers组中的所有主机nfs_sserver的值为nfs.magedu.com
(4)    组中还可以嵌套组
    Inventory中,组还可以包含其他组,并且也可以向组中的主机指定变量。

(5)多重变量定义
    变量除了可以在Inventory中定义,还以独立于Inventory文件之外单独到存在yaml格式的配置文件中。

9、正则表达式
    在使用ansible命令,指定作用组或者单个主机时可以使用正则表达式
    ansible webservers -m service -a "name=httpd status=restarted" #重启webservers组中所有主机的httpd服务
    ansible all   -m ping   #检查所有主机是否存活
    ansible "*"   -m ping     #all和*号的功能相同,但是*需要用""号引起来
    ansible 192.168.1.*     -m ping      #检查192.168.1.0/24网络的所有主机是否存活
    ansible web1:web2        -m ping      #同时检查web1和web2两个组的所有主机是否存活,并集,同时对多个主机或多个组执行命令,用":"冒号分割
    ansible web1:!web2         -m ping     #表示表示在web1组中但是不在web2中的所有主机执行命令, 差集
    ansible web1:&web2      -m ping     #即在web1组也在web2组中的主机,交集
    ansbile *.magedu.com     -m ping     #对所有以.magedu.com结尾的主机执行命令
    ansible one*.com:webservers -m ping    #对所有以one开头以com结尾的主机,与webservers组取并集
    ansible webservers[0:1] -m ping     #根据下标取组中对应的主机
    ansible webservers[-1]  -m ping     #取组中倒数第一个主机
    ansible webservers[1:]    -m ping     #取组中第2个到到最后一个主机
    ansible "~(beta|web|green)\.example\.(com|org)" -m ping #支持正则表达式,正则表达式以~开头
    ansible "~192\.168\.[0-9]{\2}.[0-9]\2{,}" -m ping         #检测Inventory中所有以192.168开头的服务器是否存活
    
10、ansible命令详解Ad-Hoc命令集
    ansible命令执行的完整流程:
    ansible webservers -s -m command -a "hostname"  -vvv    #以root用户在每台主机上执行hostname命令,返回webservers组中的每台主机的名字,并显示详细的执行过程。
    (1)首先当前主机与远程主机建立SSH链接,
    (2)然后在远程主机的$HOME/.ansible/tmp/目录下建立临时文件夹用来存放远程执行脚本,
    (3)将/tmp/目录下的临时脚本移动到$HOME/.ansible/tmp/ansible-tmp-数字/command Python脚本中,
    (4)切换成root用户,执行python脚本,并返回结果
    (4)然后再删除临时目录$HOME/.ansible/tmp/ansible-tmp-数字 。
    
(2)ansible 10.21.40.61 -B 5 -P 2 -T 2  -m command -a "sleep 20" -u root
    对服务器10.21.40.61以root用户执行sleep 20 ,执行最大连接超时时长为2s,设置为后台模式执行命令,没隔2s输出一次进度,如果5s还没有执行完毕就终止改任务
    ansible命令的其他options可选项
    -B num ,--backgroud=num   后台执行命令,超过num秒任务没有执行完毕就自动终止
    -P num ,--poll=num           定期返回后台任务的进度,每隔num秒返回一次任务进度
    -T sec ,--timeout=sec     指定远程链接最长超时时间
    -u name,--user=name       指定远程主机以name用户执行命令
    -k , --ask-pass SSH       认证密码
    -K , --ask-sudo-pass sudo 用户密码 (--sudo时使用)
    -s , --sudo               切换成root用户执行命令
    -a "arguments", --args "arguments" 执行命令command模块的参数
    -m name , --module-name=name 指定执行使用的模块
    -t directory , -tree=directory 输出信息至directory目录下,结果文件以远程主机的主机名命名
    -f num , --forks=num      指定ansible命令执行的并发线程数,默认为5
    -l subset ,--limit=subset 限定运行命令的主机,只有limit指定的主机才会执行命令
    
(3)ansible web1 -m command -a "df -lh"
    ansible web1 -a "df -lh"    #默认使用command模块,查看web1组中的所有主机的磁盘使用情况
    ansible web1 -m shell -a "free -m"  #使用shell模块批量查看web1组中所有主机内存使用情况
    ansible apps -m yum -a "name=redhat-lsb state=present"  #为apps组中所有主机安装redhat-lsb 用来查看每台主机的系统版本号
    ansible apps -m command -a "lsb-release -a"      
    ansible apps -m yum -a "name=ntp state=present"         #为appls组中所有主机按照ntp服务并设置为开机自启动
    ansible apps -m command -a "name=ntpd state=started enable=yes"
    
11、Ad-Hoc组管理和特点主机变更
    架构规划:前端Proxy 、 Web servers 和后端的数据库DB。
    [proxy]
    192.168.37.159
    
    [app]
    192.168.37.130
    192.168.37.160
    
    [nosql]
    192.168.37.142
    
    [db]
    192.168.37.142
(0)构建简单的web服务架构
    proxy组:安装Nginx服务用来转发用户的各种请求到后端的WebServers响应
    app组:  安装Nginx+PHP+Django服务,用来响应用户的request请求
    nosql组:安装redis服务,用来缓冲查询数据库的压力
    db组:   安装MariaDB服务,查询数据库返回结果
    
(1)首先给proxy组安装Nginx服务,并检查服务是否安装成功
    ansible proxy -m yum -a "name=nginx state=present"  #state=present表示新建 
    ansible proxy -m command -a "nginx -v"
    
(2)然后Web Servers组安庄Nginx、PHP、Django服务
    ansible app -m yum -a "name=nginx state=present"        #安装nginx、php服务
    ansible app -m yum -a "name=php  state=present"
    ansible app -m yum -a "name=MySQL-python state=present" #安装MySql-python 和Python-setuptools依赖包
    ansible app -m yum -a "name=python-setuptools state=present"
    ansible app -m pip -a "name=django start=present"        #使用pip安装django服务,django依赖Python 2.7.0+版本
    ansible app -m command -a "python -c 'import django; print django.get_version()'"  #检查django是否安装成功
    
(3)最后配置后端Nosql和Database服务
    ansible nosql -m yum -a "name=redis state=present"     
    ansible nosql -m command -a "redic-cli --version"
        
    安装MariaDB(继Mysql后又一大流行数据库)    
    添加yum源,修改/etc/yum.repos.d/mariadb.repo添加内容
    [mariadb]
    name=MariaDB
    baseurl=http://yum.mariadb.org/10.1/centos6-x86
    gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
    gpgcheck=1
    
    ansible db -m yum -a "name=MariaDB-Server state=present"    #安装MariaDB-Server服务
    ansible db -m yum -a "name=MariaDB-client state=present"    #安装MariaDB-Client服务
    ansible db -m command -a "iptables -A INPUT -s 192.168.37.0/24 -p tcp -m tcp --dport 3306 -j ACCEPT" #开启防火墙3306端口
    
(4)Ad-Hoc限定主机执行命令
    ansible app -m command -a "service ntpd start " --limit "192.168.37.158"  #只启动app组中192.168.37.158这台服务器的ntpd服务
    ansible 192.168.37.158 -m command -a "service ntpd start" 
    ansible "192.168.37.158:192.168.37.161" -m command -a "service ntpd start"    #指定多台主机执行命令,用冒号分割,需要用引号将所有地址引起来
    ansible 192.168.37.*  -m command -a "service ntpd start"    #指定多台主机变更

    
12、ansible管理系统用户    
(1)linux用户管理
    批量新增用户;新增用户dba , 使用bash shell, 附加组为admins,dbagroup ,家目录为/home/dba/
    ansible db  -m  user -a "name=dba shell=/bin/bash groups=admins,dbagroup append=yes home=/home/dba/  state=present"
    user模块的属性
    name    用户名
    shell      设置用户shell
    groups     设置用户附加组群,使用逗号分隔多个群组,如果参数为空,即groups="" ,则删除用户所有附加组
    append    当为yes表示增量添加group,即用户附加组群变多了,当为no时全量变更,抛弃原来的组群,只设置为groups属性中的组
    state    为present时新建用户 , 为absent时删除用户
    remove  结合state=absent使用,删除用户相当于userdel --remove
    home    设置用户的家目录
    expires    设置用户过期时间
    password 设置用户密码,后面跟的密码必须是加密过后的密码
    update_pssword  当为always:只有密码不同才会更新密码,当为on_create 只为新用户设置密码
    
(2)修改用户属组,将用户dba的所属组质变为dbagroup,删除admins组权限
    ansible db -m user -a "name=bda groups=dbagroup append=no"
    
(3)修改用户属性,将用户dba的过期时间设置为2016/6/1 18:00:00,UNIXTIME=1464775200
    ansible db -m user -a "name=dba expires=1464775200" 
    
(4)删除用户,将用户dba删除
    ansible db -m user -a "name=dba remove=yes state=absent" 

(5)变更用户密码:设置用户tom的密码为redhat123
    ansible db -m user -a "name=tom shell=/bin/bash  password=EKEVWEJRO123 update_pssword=always"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
(6)通过使用mysql_user模块为mysql数据库增加用户xiao,初始密码为xiao123
    ansible db -m mysql_user -a "login_host=localhost login_password=root123 login_user=root name=xiao password="xiao123" priv=zabbox.*:ALL state=present"

13、Playbook基础语法
(1)playbook的正式内容:
    注:缩进空格和tab不能混用,k/v的值可以同行写也可以换行写,同行使用":"隔开,换行写需要以"-"分隔,一个name对应一个task
    创建一个名为hello.yml的文件
    ---                            #必须以三个减号作为首行
    - hosts: webservers            #定义第一个play1,并指定要执行命令的远程主机组或者单个主机
      vars:                        #定义了两个变量,后期可以调用
         http_port: 80
         max_client: 200
      remote_user: root            #设置远程主机以root用户执行命令
      tasks:                    #定义一系列接下来要执行的任务,任务列表
        - name: ensure the apache server is the latest version    #任务1:确保apache服务器的本班时最新的
          yum: name=httpd state=latest                            #       使用yum模块执行任务,后面是yum模块的参数        
        - name: write the apache config file                    #任务2:编辑apache服务器的配置文件
          template: src=/srv/httpd.j2 dest=/etc/httpd.conf        #       使用template模块                            
        - name: ensure apache is running                        #任务3:启动apache服务
          service: name=httpd  state=started                    #        使service模块启动httpd服务
          notify: restart apache                                #调用并执行定义好的handler中的task
      
      handlers:                                                #定义一个handlers,且本质也是一个task的列表,可以通过notify和任务名来调用集合中的某个task,notiy的task才会执行,没有notify的task不会执行
        - name: restart apache server 
          service: name=httpd state=restart 
        - name: stop apache server 
          service: name=httpd state=stop 
    - hosts: app                #定义第二个paly2, 针对app主机组,一个playbook可以包含多个play        
      remote_user: root
      tasks:
        - name:"安装apache server"
          command: yum install --quite -y httpd httpd-devel
        - name: "复制文件"
          command:cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
          command: cp /tmp/httpd-vhosts.conf /etc/httpd/conf/httpd-vhosts.conf
        - name: "启动Apache,并设置为开机自启动"
          command: service httpd start
          command: chkconfig httpd on

    执行hello.yml文件:
    ansible-playbook hello.yml
    
(2)playbook循环语句:
    ---
    - hosts: all
      sudo: yes    #远程主机以root用户执行命令
      tasks:
        - name: "安装Apache server"
          yum: name={{item}} state=present
          with_items:   #wtih_items要与模块名yum左对齐
             - httpd
             - httpd-devel
        - name:"复制配置文件"
          copy: src={{item.src}}  dest={{item.dest}} owner=root group=root mode=644
          with_items:                                                            #该命令是将当前主机上的文件远程拷贝到其他机器的指定路径下
            - {src:"/tmp/httpd.conf", dest:"/etc/httpd/conf/httpd.conf"}        #src表示ansible所在本地服务器上的路径, dest为远程主机的路径
            - {src:"/etc/httpd-vhosts.conf", dest:"/etc/httpd/conf/httpd-vhosts.conf"}
        - name: "检查Apache运行状态,并设置开机自启动"
          service: name=httpd state=started enable=yes

(3)ansible-playbook常用的参数 [options]
    --limit          用来限定哪些主机会执行playbook中的命令
    --list-hosts     返回在执行playbook时,哪些主机将会受到影响
    --remote_user   用来执行远程主机以什么用户执行命令
    --ask-sudo-pass 用来传递sudo密码到远程主机,来保证sudo命令可以正常运行,使用--ask-sudo-pass(-K)选项交互式输入sudo密码
    --sudo          可以强制所有play都使用sudo用户执行
    --sudo-user     可以指定sudo可以执行那个用户的权限
    --check         在运行playbook之前,使用该命令--check(-C)来检测playbook都会改变哪些内容,显示的结果跟真正执行时一模一样,但不会真的对被管理的服务器产生实际影响。
    --force-handlers 当playbook中某一个task执行时出现了错误,那么ansible会停止所有任务,而且handlers也不会被触发,如果们需要不管是否出现问题都要触发handlers,那么就可以用该选项来强制触发handlers
    
(4)playbook定义变量,设置Handlers
    在playbook中可以创建一个变量文件vars.yml来存放所有需要的变量。
    不仅变量可以定义在文件中,Handler、Tasks也可以独立定义在文件中.
    ---
    - hosts: all
      vars_files: vars.yml        #通过vars_files关键字来引用文件中的变量
    pre_task和post_task用来指定在主任务运行之前和之后要运行的任务
    例如:在安装其他服务之前,我们需要确保apt缓存始终是最新的,因此我们通过apt模块来更新apt缓存,同时设置有效期为3600s
    pre_tasks:
        - name: update apt cache if needed
          apt: update_cache=yes  cache_valid_time=3600 
            
            
(5)输出打印一行信息:
    ********************************************
    ansible all -m debug -a "msg='hello world'" 
    ansible all -m debug -a msg=hello -u root
    playbook模式
    - name:   打印出环境变量
      debug: msg=" The variable is {{JAVA_HOME}}"
    ********************************************
    
(6)在文件中独立定义变量时,首行时三个减号,变量定义定格写,不需要缩进,
    创建vars.yml 文件用来存放变量
    ---
    name: xiaowei
    age:12
    sex: male
    在playbook中通过vars_files: vars.yml 来引用里面的变量
    创建hello.yml文件
    ---
    - hosts: all
      vars_files: vars.yml
      tasks:
        - name : 打印信息
          debug: msg=" the name is {{name}}, age is {{age}}"
    ansible-playbook  hello.yml

(7)在Inventory文件中定义变量
    Inventory文件默认路径为/etc/ansible/hosts, 可以在主机名的后面或者是组名的下方定义变量,如下:
    [shanghai]           #为某一台主机单独指定变量
    app1.example.com  proxy_state=present
    app2.example.com  proxy_state=present
    
    [shanghai:vars]     #为整个主机组指定变量
    dns_hosts=static.example.com
    version=2.1.0
    
(8)定义变量的另一种方式
    由于ansible在执行命令的时候回默认去/etc/ansible/host_vars/和/etc/ansible/group_vars目录下去读取变量
    因此可以在这两个目录下创建于host主机同名的变量定义文件,或者创建与组同名的变量定义文件
    如果我们需要给主机app1.example.com定义变量文件,那么就可以到/etc/ansible/host_vars/目录下创建一个名为app1.example.com的文件
    在里面以YAML格式定义变量
    如果要给shanghai整个组定义变量文件,那么就可以到/etc/ansible/group_vars/目录下创建一个shanghai的空白文件,
    在里面以YAML格式定义变量:
    ---
    foo: bar
    name: xiaowei 
    
(9)Facts,收集系统信息
    在运行任何一个playbook之前,ansible都会去收集playbook指定的主机的信息,这些信息包括:
    远程主机CPU信息、IP地址、磁盘空间、网络接口、操作系统信息
    这些信息对于运行playbook至关重要,我们可以根据这些信息决定是否要运行playbook,我们也可以将这些信息写入到配置文件中
    ansible localhost -m setup >> setup.txt    #用setup模块获取对应主机上的所有可用的Facts信息
    结果:
    localhost | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.122.128"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::20c:29ff:feff:7eb7"
        ], 
        "ansible_apparmor": {
            "status": "disabled"
        }, 
        "ansible_architecture": "x86_64", 
        "ansible_bios_date": "05/19/2017", 
        "ansible_bios_version": "6.00", 
        "ansible_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-123.el7.x86_64", 
            "LANG": "en_US.UTF-8", 
            "crashkernel": "auto", 
            "quiet": true, 
            "rhgb": true, 
            "ro": true, 
            "root": "UUID=b6943379-8c8a-4dbe-af80-b3f2af2d6fa9", 
            "vconsole.font": "latarcyrheb-sun16", 
            "vconsole.keymap": "us"
        }
        
        常用的Facts变量有: ansible_os_family、ansible_hostname、ansible_memtotal_mb……

14、流程控制if、then、when
(1)flie模块:主要用来
    path参数     :必须参数,用于指定要操作的文件或目录,在之前版本的ansible中,使用dest参数或者name参数指定要操作的文件或目录,为了兼容之前的版本,使用dest或name也可以。
    state参数     :设置path=/testdir/a/b,但是ansible不知道这个路径是代表一个文件还是一个目录,所以要通过state来指定,state=directory(创建目录)、touch(创建文件)、link(创建软连接)、hard(创建硬链接)、absent(删除文件或目录)
    src参数     :当state设置为link或者hard时,表示我们想要创建一个软链或者硬链,所以,我们必须指明软链或硬链链接的哪个文件,通过src参数即可指定链接源。
    force参数     : 当state=link的时候,可配合此参数强制创建链接文件,当force=yes时,表示强制创建链接文件。不过强制创建链接文件分为三种情况。情况一:当要创建的链接文件指向的源文件并不存在时,使用此参数,可以先强制创建出链接文件。情况二:当要创建链接文件的目录中已经存在与链接文件同名的文件时,将force设置为yes,会将同名文件覆盖为链接文件,相当于删除同名文件,创建链接文件。情况三:当要创建链接文件的目录中已经存在与链接文件同名的文件,并且链接文件指向的源文件也不存在,这时会强制替换同名文件为链接文件。
    owner参数     :用于指定被操作文件的属主,属主对应的用户必须在远程主机中存在,否则会报错。
    group参数     :用于指定被操作文件的属组,属组对应的组必须在远程主机中存在,否则会报错。
    mode参数    :用于指定被操作文件的权限,比如,如果想要将文件权限设置为”rw-r-x---“,则可以使用mode=650进行设置,或者使用mode=0650,效果也是相同的。如果想要设置特殊权限,比如为二进制文件设置suid,则可以使用mode=4700。
    recurse参数    :当要操作的文件为目录,将recurse设置为yes,可以递归的修改目录中文件的属性

    - name: 创建文件
      file: path=/home/hadoop/words.txt  state=touch owner=hadoop group=hadoop mode=0650
      
(2)when条件判断
    ansible在进行条件判断时会使用到一些Jinja2的语法、以及Python的一些内置函数
    很多任务只有在特定条件下执行,这就需要用到when条件表达式了
    还以通过注册器保存命令运行的结果,并对其进行判断
    ---
    - hosts: all
      tasks:
        - name: 只为数据库服务器安装mysql
          yum:  name=mysql-server state=present
          when: ({{is_db_server}} is defined) and {{is_db_server}}    #只在一个服务器上设置一个is_db_server的布尔值变量,用来表示这是一台数据库服务器
        - name: 当软件主版本号为4才更新软件
          yum: name=redis state=present
          when: {{redis_version}}.split(".")[0]=='4'
        - name: 查看一个应用的运行状态,
          command: appname --state
          register: appstate_result                 #定义一个注册变量,将该task的任务执行的结果放到这个注册变量appstate_result中
        - name: 根据上app软件运行的状态,决定是否要执行本task
          command: do something else as you like
          when: "ready" in appstate_result.stdout  #只有当上一个task的执行结果中包含有ready时才会执行当前命令
        - name: 如果当前PHP的版本号为7.0,就执行PHP降级任务
          shell: php --version
          register: php_version_result
        - name: PHP降级
          shell: yum -y downgrade php*
          when: '7.0' in php_version_result.stdout
        - name: 如果远程主机中没有host文件,就远程拷贝一个过去
          stat: path=/etc/hosts
          register: host_file_result
        - name: 拷贝host文件
          copy: src=/path/to/local/hosts_file  dest=/path/to/remote/hosts_file
          when: host_file_result.stat.exists =- false
          
(3)changed_when 、failed_when条件判断
    #使用PHP composer来安装项目依赖,无论是否安装或升级的某些软件,ansible任务返回的结果都会是changed,表示主机已经改变。
    #所以我们需要通过changed_when语句来设置,只有当软件被安装成功了或升级成功了,任务才会返回changed
    ---
    - hosts: all
      tasks:
        - name: isntasll dependencies via composer         
          cammand: /user/local/bin/composer global require phpunit/phpunit --prefer-dist
          register: composer_result
          changed_when: "Nothing to install or update" not in composer_result.stdout    #只有当满足这个条件时,才通知Ansible显示主机Changed
        - name: 通过CLI导入Jenkins任务
          shell: java -jar /opt/jenkins-cli.jar  -s htttp://localhost:8080/create-job "my job"
          register: import_result
          failed_when:  import_result and "already exsits" not in import_result            #只有当满足这个条件时,才通知Ansible显示任务执行失败
        - name: 忽略错误
          command: do something as will
          ignore_errors: true        #不管这个任务是否会报错,都算它执行成功
          
(4)delegate_to 任务委托
    在执行任务的时候,如果对于某一个task,我们只想它在某一台服务器上运行,而不是所有的服务器都运行,这时候就需要用到delegate_to了
    ---
    - hosts: webservers
      tasks:
        - name: remove server form load balancer
          command: remove-from-lb
          delegate_to: 127.0.0.1                 #只在本地主机上执行这个task,其他主机上都不执行
          
        - name: remove server form load balancer
          local_action: command remove-from-lb     # local_action 与 delegate_to等价
          
(5) wait_for 任务暂停
    ---
    - hosts: all
      task:
        - name: wait for webserver to start  #等待web1服务器的80端口打开后,才执行本task
          local_action:
            module: wait_for
            host: web1
            port: 80
            delay: 10
            timeout: 300
            state: started
    该任务会每个10s检查一下web1服务器上的80端口是否开启,如果超过300s还没有开启就返回失败信息
    
(6)tags标签
    可以给某一个task、某一个role、某一个play、或者整个playbook都打上标签,然后再执行的时候,使用--tags选项来指定执行哪些task,用--skip-tags来指定不执行哪些tasks
    ansible-playbook hello.yml --tags "helloworld" 
    ansible-playbook hello.yml --skip-tags "helloworld" 
    案例:
    ---
    - hosts: all
      tags: hello
      roles:
        - role: tomcat
        - tags: [tomcat , app]        #第一种添加tags的方式,用一个列表将所有tags包含在里面
      tasks:
        - name: notif on  completion
          local_action:
            module: osx_say
            msg: hi,nihao
            voice: zarvox
          tags:                        #第二种添加tags的方式,换行用"-"分隔tags
            - notification
            - say

(7)block块
    block块将一系列的task形成一个整体,可以对这个整体执行异常处理语句
    ---
    - hosts: all
      tasks:
        # install and configure apache on redhat/centos hosts
        - block:        #把三个task合并成一个整体,如果操作系统是redhat,就执行这些task,而不用逐个判断
            - yum: name=httpd state=present
            - template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
            - service: name=httpd state=started enable=yes
          when: {{ansible_os_family}} == "Redhat"
          sudo: yes
          
        # install and configure apache on debian/ubuntu hosts
        - block:
            - apt: name=apache2 state=present
            - template: src=htttpd.conf.j2 dest=/etc/apache2/apache.conf
            - service: name=apache2 state=started  enable=yes
          when: {{ansible_os_family}} == "Debian"
          sudo: yes 
          
    block块中异常处理:
      tasks:
        - block:
            - name: shell script to connect the app to a monitoring service
              script: monitoring-connect.sh
              rescue:    
                - name: 只有脚本运行出错时,才执行rescue中的语句
                  debug: msg="there was a error in this block"
              always:
                - name: 无论脚本执行结果如何,都要执行always中的语句
                  debug: msg="this always executes"
    #当块中的任意代码出了问题就会执行rescue中的语句,相当于java中的try catch语句,而always相当于finally语句            
            
15、Playbook的高级技巧使用
(1)copy模块的使用:
    copy模块实现复制本地文件到远程主机,copy模块包含如下选项:
    backup:    在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no 
    content:    用于替代"src",可以直接设定指定文件的值 
    dest:        必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录 
    directory_mode:递归的设定目录的权限,默认为系统默认权限
    force:        如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
    others:    所有的file模块里的选项都可以在这里使用
    src:        要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。         
    ansible web1 -m copy -a "src=/etc/ansible/script.sh dest=/tmp/ owner=appuser group=appuser mode=0755"     
    ###复制本地脚本到远程主机server6下并定义用户和组以及权限755 
    
(2)include用法:
    创建一个 install_MysqlAndPhp.yml文件 ,用来存放公共执行模块
    install_MysqlAndPhp.yml:
    ---                              # 这个yml文件可以看做是一个task任务列表,专门用来安装msyql和php
    - yum: name=mysql state=present
    - yum: name=php-fpm state=present
    
    再创建一个install_lamp.yml文件,通过include语句来调用install_MysqlAndPhp.yml文件中的内容
    ---
    - host: all
      remote_user: root
      gather_facts:    no
      tasks:                                # 在tasks关键字中使用include,
        - include: install_MysqlAndPhp.yml    # include语句可以看做是一个task,所以与任务install_httpd左对齐
        
        - name: install_httpd
          yum: name=httpd state=present
        
    在handlers关键字中使用include
    创建test_include.yml文件
    ---
    - hosts: all
      remote_user: root
      gather_facts: no
      tasks:
        - name: create_file
          file: path=/opt/tmp  state=touch 
          notify: test_include_module    #handlers中的任务,要被tasks中的任务调用,所以notify语句要与file模块左对齐,由create_file这个task去notify在handlers中的test_include_moudle这个任务
          
      handlers:        # handlers 也可以看做是一种任务列表,所以与tasks左对齐
        - name: test_include_module
          include: include.yml            #在handlers关键字中调用include语句
          
    创建include.yml
    ---
    - debug: msg="hello world"
    - debug: msg="hello world2"
    - debug: msg="hello world3"
        
(3)Roles角色:    
    roles的默认目录可以在/etc/ansible/ansible.cfg配置文件中找到
    roles_path = /etc/ansible/roles/
    roles目录下用来存放各个角色,每一个角色对应个子文件夹,
    而每个角色文件夹中又包含:files、templates、tasks、handlers、vars、defaults、meta    (7个子文件夹)
    files/         :存放由copy或script模块等调用的文件;
    templates/    :template模块查找所需要模板文件的目录;
    tasks/        :至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含,所有包含在其中的任务将会被执行;
    handlers/    :至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含,所有包含在其中的handlers将会被执行;
    vars/        :至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含,所有包含在其中的变量将在roles中生效;
    meta/        :至少应该包含一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要在此文件中通过include进行包含;注意,角色和角色之间有依赖关系,如安装NT,先装nginx后装tomcat,一般不需定义,执行我们自己定义好安装顺序即可
    default/    :设定默认变量时使用此目录中的main.yml文件;
        
(4)案例:目录结构如下:
    myfile.yml
    myapache.yml
    roles        
        |---- apache
        |        |---- handlers
        |        |        |---- main.yml
        |        |---- tasks
        |                |---- main.yml
        |                |---- restart.yml
        |---- example
                |---- files
                |        |---- Magedu.ppt
                |        |---- Stanley.ppt
                |
                |---- tasks
                        |---- main.yml
                        |---- file.yml
    在roles目录下有两个子目录:apache和example分别对于两个role
    案例一:更新webservers组中的httpd服务的配置文件,然后重启服务
    1)编辑/roles/apache/handlers/main.yml:
    ---
    - name: restart_apache
      service: name=apache state=start
      
    2)编辑/roles/apache/tasks/restart.yml
    ---
    - name: transfer apache config file
      file: src=httpd.conf dest=/opt/apache/httpd.conf  #更新httpd服务的配置文件,然后再重启httpd服务
      notify: restart_apache    #调用handlers中写好的重启apache httpd服务的任务
     
    3)编辑/roles/apache/tasks/main.yml
    ---
    - include: restart.yml
    
    4)编辑与roles目录统计的myapahce.yml
    ---
    - hosts: webservers
      remote_user: root
      roles:
        - role: apache             #所有task、handlers全部都被分解到roles下各个目录的文件中
        
    5)执行apache.yml文件
    ansible-playbook  myapahce.yml
    
    案例二:files文件传输
    1)编辑与roles目录同级的myfile.yml文件
    ---
    - hosts: 192.168.122.128
      remote_user: root
      gather_facts: no
      roles:
        - role: example
    
    2)编辑roles/example/task/file.yml
    ---
    - name:  file change example
      copy: path={{item.src}} dest={{item.dest}} owner=hadoop group=hadoop 
      with_items:
        - src:Magedu.ppt            #由于Magedu.ppt和Stanley.ppt这两个文件存放在roles/files目录,因此传输时只需要指定相对files目录的路径既可,规范用户了存放文件的位置。
          dest:/opt/tmp/magedu.ppt
          
        - src:Stanley.ppt
          dest:/opt/tmp/Stanley.ppt
          
    3)编辑roles/example/task/main.yml
    ---
    - include file.yml
    
    4)执行与roles同级file.yml
    ansible-playbook myfile.yml    #注:这个被执行myfile.yml文件的名字是什么,位置在哪里可以任意指定
    
    
      
      
      
      
      
    
    

    

你可能感兴趣的:(IT)