【体系】Ansible自动运维

01.发展

  • On-Premises(本地部署):项目从零开始一切都自行负责
  • Iaas(基础设施即服务):以电信行业发展为例,2008年联想风头正盛,营业额达到顶峰,硬件收入高(硬件)
  • PaaS(平台即服务):之后微软到达顶峰,营业额达到顶峰(操作系统)
  • SaaS(软件即服务):现在互联网走到风口,利润不断攀升(软件)

02.灰度发布

环境分类:开发环境(dev)、测试环境(test)、发布环境、生产环境(prod)、灰度环境

  • 开发环境:程序员个人的办公电脑或项目的开发测试环境,部署开发软件,测试个人或项目整体的BUG的环境,管理者是程序员;
  • 测试环境:测试经过开发环境测试通过的软件的功能和性能,判断是否达到项目的预期目标,生成测试报告,管理者是运维。测试环境往往有多套,测试环境满足测试功能即可,不宜过多。通常测试环境有多少套和产品线数量保持一样
  • 预发布环境:使用和生产环境一样的数据库,缓存服务等配置,测试是否正常
  • 发布环境:包括代码发布机,有些公司为堡垒机(安全屏障),往往需要有两台(主备)
  • 生产环境:少数情况开放权限给核心开发,极少数公司将权限完全开放给开发人员并其运维
  • 灰度环境:在全量发布代码前将代码的功能面向少数精准用户发布的环境,可基于主机或用户执行灰度发布。往往该版本功能变更大,为保险起见特意让一部分用户优先体验该功能,待这部分用户使用没有重大问题的时候,再全量发布至所有服务器(灰度发布,也成为金丝雀发布)

案例:共100台生产服务器,先发布其中的10台服务器(将10台服务器下线),这10台服务器就是灰度服务器。然后将这10台服务器更新服务后再上线。这时90台服务提供的是旧服务,另外10台提供的是新服务。若有重大BUG则将10台新服务还原成旧服务,否则则将剩余90台服务逐步10台/次更新。或者基于用户,先优先于付费用户进行更新,没问题后再全部用户更新。


03.程序发布

  • 预发布验证:新版本的代码先发布到服务器(跟线上环境配置完全相同,只有未接入到调度器)
  • 发布过程:在调度器上下线一批主机(标记为maintanance状态) --> 关闭服务 --> 部署新版本的应用程序 --> 启动服务 --> 在调度器上启用这一批服务器

04.自动运维工具

  • Ansible:python便于二次开发,无需代理(SSH),中小型应用环境(300-500服务器,再多性能可能跟不上)
  • Saltstack:python便于二次开发,需部署agent(有代理性能和功能更加强大),执行效率高,使用更大应用环境(1000+服务器)
  • Puppet:ruby,功能强大,配置复杂,重型,适合大型环境(例如:Google)

05.Ansible工具引入

注意:ansible只能安装在linux上(主控端),但是可以控制windows机器(被控端)

安装:由于内网环境限制,笔者这里使用手动安装配置,操作系统为麒麟操作系统(其步骤大致为先挂载本地yum源,用于安装基本环境,然后手动安装所需模块)

  • 首先确保虚拟机已经挂载ios文件,若重新挂载,挂载完成后需要重启虚拟机在这里插入图片描述

  • 将iso源挂载到麒麟操作系统并配置指定yum下载源:新建/mnt/cdrom/目录mkdir /mnt/cdrom/,之后挂载CDROM[root@server0 yum.repos.d]# mount -o loop /dev/cdrom /mnt/cdrom/,然后配置yum源在这里插入图片描述在这里插入图片描述

  • 安装基本环境:安装gccyum install gcc.x86_64;安装zlibyum install zlib zlib-devel -y;安装opensslyum install openssl openssl-devel

  • 安装python:python2.7下载地址

    # 手动安装python包
    tar xvzf Python-2.7.8.tgz
    cd Python-2.7.8
    ./configure --prefix=/usr/local
    make
    make install
    
    # 将python头文件拷贝到标准目录,以避免编译ansible时,找不到所需的头文件
    cd /usr/local/include/python2.7
    cp -a ./* /usr/local/include/
    
    ## 备份旧版本的python,并符号链接新版本的python
    cd /usr/local/bin
    mv python python.old
    ln -s /usr/local/bin/python2.7 /usr/local/bin/python
    rm -f /usr/bin/python && cp /usr/local/bin/python2.7 /usr/bin/python
    
  • 模块安装:由于服务器在内网环境,没法用pip安装,所以需要把python模块从官网上逐个下载下来安装。pycrypto模块地址setuptools模块地址yaml模块地址PyYAML模块地址MarkupSafe模块地址Jinja2模块地址ecdsa模块地址paramiko模块地址simplejson模块地址ansible地址

    # pycrypto模块安装
    tar xvzf pycrypto-2.6.1.tar.gz
    cd pycrypto-2.6.1
    python setup.py install
     
    # setuptools模块安装
    tar zxvf setuptools-0.6c11.tar.gz
    cd setuptools-0.6c11
    python setup.py install
    
    # PyYAML模块安装
    tar xvzf yaml-0.1.5.tar.gz
    cd yaml-0.1.5
    ./configure --prefix=/usr/local
    make --jobs=`grep processor/proc/cpuinfo | wc -l`
    make install
    
    tar xvzf PyYAML-3.11.tar.gz
    cd PyYAML-3.11
    python setup.py install
    
    # Jinja2模块安装
    tar xvzf MarkupSafe-0.9.3.tar.gz
    cd MarkupSafe-0.9.3
    python setup.py install
    
    tar xvzf Jinja2-2.7.3.tar.gz
    cd Jinja2-2.7.3
    python setup.py install
    
    # paramiko模块安装
    tar xvzf ecdsa-0.11.tar.gz
    cd ecdsa-0.11
    python setup.py install
    
    tar xvzf paramiko-1.15.1.tar.gz
    cd paramiko-1.15.1
    python setup.py install
    
    # simplejson模块安装
    tar xvzf simplejson-3.6.5.tar.gz
    cd simplejson-3.6.5
    python setup.py install
    
    # ansible安装
    tar xvzf ansible-1.7.2.tar.gz
    cd ansible-1.7.2
    python setup.py install
    
  • Ansible配置:安装ansible后发现找不到ansible.cfg,配置文件的路径如下图,并将配置文件拷贝过去在这里插入图片描述

  • 默认配置文件位置为/etc/ansible/ansilble.cfg,配置文件位置可以修改。Ansible 按照如下位置和顺序来查找ansible.cfg 文件:

    • ANSIBLE_CONFIG 环境变量所指定的文件。
    • ./ansible.cfg(当前目录下的ansible.cfg)。
    • ~/.ansible.cfg(家目录下的.ansible.cfg)。
    • /etc/ansible/ansible.cfg。
  • Ansible配置详解:
    在这里插入图片描述
    在这里插入图片描述

配置SSH免密登录:由于ansible使用的登陆方式是ssh,在主机需要配置ssh秘钥对,这样ansible才能正常使用。

# 服务端:192.168.2.121 客户端:192.168.2.250
# 一键生成非交互式秘钥对
ssh-keygen -t rsa -f /root/.ssh/id_rsa -P ""
# 公钥(id_rsa.pub)拷贝到客户端上:
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.2.250
# 本机也要拷贝:
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys      # 必须是600, 否则用ansible连接本机报错
# 在服务端测试ssh是否可以登录
ssh 192.168.2.250

06.Ansible相关工具介绍

Ansible相关工具:

  • /usr/bin/ansible 主程序,临时命令执行工具 /usr/bin/ansible-doc 查看配置文档,模块功能查看工具
  • /usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台
  • /usr/bin/ansible-playbook 定制自动化任务,编排剧本工具
  • /usr/bin/ansible-pull 远程执行命令的工具
  • /usr/bin/ansible-vault 文件加密工具
  • /usr/bin/ansible-console
  • 基于Console界面与用户交互的执行工具

ansible-doc:此工具用来显示模块帮助,格式

ansible-doc [options] [module...]
-l, --list          #列出可用模块
-s, --snippet       #显示指定模块的playbook片段
# 范例
# 列出所有模块
ansible-doc -l  
# 查看指定模块帮助用法
ansible-doc ping  
# 查看指定模块帮助用法
ansible-doc -s  ping

# 模块使用格式
ansible <host-pattern> [-m module_name] [-a args]
# 选项说明
--version           #显示版本
-m module           #指定模块,默认为command
-v                  #详细过程 –vv  -vvv更详细
--list-hosts        #显示主机列表,可简写 --list
-k, --ask-pass      #提示输入ssh连接密码,默认Key验证    
-C, --check         #检查,并不执行
-T, --timeout=TIMEOUT #执行命令的超时时间,默认10s
-u, --user=REMOTE_USER #执行远程执行的用户
-b, --become        #代替旧版的sudo 切换
--become-user=USERNAME  #指定sudo的runas用户,默认为root
-K, --ask-become-pass  #提示输入sudo时的口令
# 范例
ansible all -k -m ping

利用sshpass批量实现基于key验证:Ansible此工具通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能。建议:使用此工具前,先配置ansible主控端能基于密钥认证的方式联系各个被管理节点

# 利用sshpass批量实现基于key验证
#!/bin/bash
ssh-keygen -f /root/.ssh/id_rsa  -P ''
NET=192.168.100
export SSHPASS=magedu
for IP in {1..200};do 
    sshpass -e ssh-copy-id  NET.IP 
done

# 手动实现原理
[root@9019-kylin ~]# ssh-keygen
[root@9019-kylin ~]# ssh-copy-id 172.16.91.21

# 查看本机所有用户,ansible建议用root远程连接
[root@9019-kylin ~]#getent passwd 
# 亦可用grep命令找文件看是否有指定用户
[root@9019-kylin ~]# grep secadm /etc/passwd
secadm:x:1001:1001::/secadm:/bin/bash

通配符:用于匹配被控制的主机的列表

# All :表示所有Inventory中的所有主机
ansible all -m ping

# *:通配符
ansible "*" -m ping 
ansible 192.168.1.* -m ping
ansible "srvs" -m ping

# 或关系
ansible "webservers:appservers" -m ping 
ansible "172.16.91.21:172.16.91.22" -m ping

# 逻辑与
# 在websrvs组并且在dbsrvs组中的主机
ansible “websrvs:&dbsrvs” -m ping 

# 逻辑非
#在websrvs组,但不在dbsrvs组中的主机
#注意:此处为单引号
ansible 'websrvs:!dbsrvs' -m ping 

# 综合逻辑
ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' -m ping

# 正则表达式
ansible "websrvs:dbsrvs" -m ping 
ansible "~(web|db).*\.magedu\.com" -m ping 

ansible命令执行过程

  1. 加载自己的配置文件 默认/etc/ansible/ansible.cfg
  2. 加载自己对应的模块文件,如:command
  3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
  4. 给文件+x执行
  5. 执行并返回结果
  6. 删除临时py文件,退出

ansible使用范例

#以wang用户执行ping存活检测
ansible all -m ping -u wang  -k
#以wang sudo至root执行ping存活检测
ansible all -m ping -u wang -k -b
#以wang sudo至mage用户执行ping存活检测
ansible all -m ping -u wang -k -b --become-user=mage
#以wang sudo至root用户执行ls 
ansible all -m command  -u wang -a 'ls /root' -b --become-user=root   -k -K

ansible-playbook:此工具用于执行编写好的 playbook 任务

ansible-playbook hello.yml
cat  hello.yml
---
#hello world yml file
- hosts: websrvs
  remote_user: root  
  tasks:
    - name: hello world
      command: /usr/bin/wall hello world

ansible-vault:此工具可以用于加密解密yml文件

# 格式:ansible-vault [create|decrypt|edit|encrypt|rekey|view]

# 范例:
ansible-vault encrypt hello.yml     #加密
ansible-vault decrypt hello.yml     #解密
ansible-vault view hello.yml        #查看
ansible-vault edit  hello.yml       #编辑加密文件
ansible-vault rekey  hello.yml      #修改口令
ansible-vault create new.yml        #创建新文件

ansible-console:此工具可交互执行命令,支持tab,ansible 2.0+新增

# 提示符格式:执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$
# 常用子命令:设置并发数(forks n 例如: forks 10)、切换组(cd 主机组 例如: cd web)、列出当前组主机列表(list)、列出所有的内置命令(?或help)
#范例:
[root@ansible ~]#ansible-console
Welcome to the ansible console.
Type help or ? to list commands.

root@all (3)[f:5]list
10.0.0.8
10.0.0.7
10.0.0.6
root@all (3)[f:5] cd websrvs
root@websrvs (2)[f:5]list
10.0.0.7
10.0.0.8
root@websrvs (2)[f:5] forks 10
root@websrvs (2)[f:10]cd appsrvs
root@appsrvs (2)[f:5] yum name=httpd state=present
root@appsrvs (2)[f:5]$ service name=httpd state=started

ansible-galaxy:此工具会连接 https://galaxy.ansible.com 下载相应的roles

#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy
ansible-galaxy install geerlingguy.mysql
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis

07.Ansible常用模块详解

command模块:在远程主机执行命令,此为默认模块,可忽略-m选项(注意:此命令不支持 $VARNAME < > | ; & 等,用shell模块实现)

# 查看命令参数
[root@9019-kylin ~]# ansible-doc -s command
- name: Executes a command on a remote node
  action: command
      chdir                  # cd into this directory before running the command
      creates                # a filename, when it already exists, this step will *not* be run.
      executable             # change the shell used to execute the command. Should be an absolute path to the executable.
      free_form=             # the command module takes a free form command to run.  There is no parameter actually named 'f
      removes                # a filename, when it does not exist, this step will *not* be run.

# 直接执行命令
[root@9019-kylin ansible]# ansible webservers -m command -a 'cat /etc/centos-release'
172.16.91.22 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core) 

172.16.91.21 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core) 

# chdir参数
[root@9019-kylin ansible]# ansible webservers -m command -a 'chdir=/etc cat centos-release'
172.16.91.21 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core) 

172.16.91.22 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core) 

# creates参数
[root@9019-kylin ~]# ansible webservers -m command -a 'chdir=/etc creates=/data/f1.txt cat centos-release'
172.16.91.21 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core) 

172.16.91.22 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core) 

# 有些shell通配符并不支持
[root@9019-kylin ~]# ansible webservers -m command -a 'rm -rf /data/*'
[root@9019-kylin ~]# ansible webservers -m command -a 'echo hello > /data/hello.log'
[root@9019-kylin ~]# ansible webservers -m command -a 'echo centos | passwd --stdin ansible' #修改密码
[root@9019-kylin ~]# ansible webservers -m command -a "echo $HOSTNAME"

shell模块:和command相似,用shell执行命令,支持大部分符号

[root@9019-kylin ~]# ansible webservers -m command -a 'echo $HOSTNAME'
# 修改默认执行的模块
[root@9019-kylin ~]# vim /etc/ansible/ansible.cfg
# 设置 module_name = shell

script模块:在远程主机上运行ansible服务器上的脚本

[root@9019-kylin ~]# vim test.sh
#!/bin/bash
echo My hostname is `hostname`
[root@9019-kylin ~]# chmod +x test.sh
[root@9019-kylin ~]# ./test.sh 
My hostname is 9019-kylin

[root@9019-kylin ~]# ansible webservers -m script -a './test.sh'
172.16.91.21 | success >> {
    "changed": true, 
    "rc": 0, 
    "stderr": "", 
    "stdout": "My hostname is 21-cent74\r\n"
}

172.16.91.22 | success >> {
    "changed": true, 
    "rc": 0, 
    "stderr": "", 
    "stdout": "My hostname is 22-centos\r\n"
}
# 复制的远程文件在远程机器的./ansible/tmp/目录下

Copy模块:从ansible服务器主控端复制文件到远程主机

#如目标存在,默认覆盖,此处指定先备份
ansible webservers -m copy -a "src=/root/test.sh dest=/tmp/test.sh    owner=ansible  mode=600 backup=yes"
#指定内容,直接生成目标文件    
ansible webservers -m copy -a "content='test line1\ntest line2' dest=/tmp/test.txt"
#复制/etc/下的文件,不包括/etc/目录自身
ansible webservers -m copy -a "src=/etc/ dest=/backup"

Fetch模块:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录(不支持目录提取,同时目标必须是指定的目录而不是文件)

ansible all -m fetch -a 'src=/etc/redhat-release dest=/data/'

File模块:设置文件属性

# 创建空文件
ansible all -m file -a 'path=/data/test.txt state=touch'
ansible all -m file -a 'path=/data/test.txt state=absent'
ansible all -m file -a "path=/root/test.sh owner=user mode=755"

# 循环修改目录中文件权限
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"

# 创建软链接
ansible all -m file -a 'src=/data/testfile  dest=/data/testfile-link state=link'

unarchive模块:解包解压缩。常见参数:copy(默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件)、remote_src(和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible主机上)、src(源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no)、dest(远程主机上的目标路径)、mode(设置解压缩后的文件权限)

# 压缩包在ansible机器上
ansible webservers -m unarchive -a 'src=/data/etc.tar.gz dest=/data/ owner=user'

# 压缩包在远程主机上
ansible webservers -m unarchive -a 'src=/data/etc.tar.gz dest=/data/ mode=700 copy=no'

Archive模块:打包压缩。(dest为目标主机)

ansible webservers -m archive  -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2  owner=user mode=600'

Hostname模块:管理主机名

ansible webservers -m hostname -a "webservers" 
ansible 172.16.91.20 -m hostname -a 'name=manager-module'

Cron模块:计划任务(支持时间:minute,hour,day,month,weekday)

# 备份数据库脚本
[root@9019-kylin ~]# cat mysql_backup.sh
# 创建定时任务
ansible dbservers -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'

# 远程主机查看是否存在任务
[root@21-cent74 etc]# crontab -l
[root@21-cent74 etc]# cat /var/spool/cron/root

# 暂停定时任务
ansible dbservers -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disable=yes'

# 启用定时任务
ansible dbservers -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disable=no'

# 删除定时任务
ansible dbservers -m cron -a 'name="backup mysql" state=absent'

Yum模块:管理软件包,只支持RHEL,CentOS,fedora,不支持Ubuntu其它版本

ansible websrvs -m yum -a 'name=httpd state=present'  #安装
ansible websrvs -m yum -a 'name=httpd state=absent'   #删除

Service模块:管理服务

# 开启服务
ansible all -m service -a 'name=httpd state=started'

# 停止服务
ansible all -m service -a 'name=httpd state=stopped'

# 查看启动情况
ansible all -a "ss -ntl"

# 设置开机启动
ansible all -m service -a 'name=httpd state=started enabled=yes'

# 修改监听端口
ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf"

User模块:管理用户

# 创建用户
ansible all -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'
ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx groups="root,daemon" shell=/sbin/nologin system=yes create_home=no  home=/data/nginx non_unique=yes'

# 删除用户及家目录等数据
ansible all -m user -a 'name=nginx state=absent remove=yes'

Group模块:管理组

# 创建组
ansible webservers -m group  -a 'name=nginx gid=88 system=yes'
# 删除组
ansible webservers -m group  -a 'name=nginx state=absent'

Lineinfile模块:相当于sed,可以修改文件内容。ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换。

ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=enforcing'"
ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'

Replace模块:该模块有点类似于sed命令,主要也是基于正则进行匹配和替换

ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"  
ansible all -m replace -a "path=/etc/fstab regexp='^#(.*)' replace='\1'"

Setup模块: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度,可以使用。gather_facts: no来禁止 Ansible 收集 facts 信息。

ansible all -m setup
ansible all -m setup -a "filter=ansible_nodename"
ansible all -m setup -a "filter=ansible_hostname"
ansible all -m setup -a "filter=ansible_domain"
ansible all -m setup -a "filter=ansible_memtotal_mb"
ansible all -m setup -a "filter=ansible_memory_mb"
ansible all -m setup -a "filter=ansible_memfree_mb"
ansible all -m setup -a "filter=ansible_os_family"
ansible all -m setup -a "filter=ansible_distribution_major_version"
ansible all -m setup -a "filter=ansible_distribution_version"
ansible all -m setup -a "filter=ansible_processor_vcpus"
ansible all -m setup -a "filter=ansible_all_ipv4_addresses"
ansible all -m setup -a "filter=ansible_architecture"
ansible all -m setup -a "filter=ansible_processor*"

[root@ansible ~]#ansible all  -m  setup -a 'filter=ansible_python_version'
10.0.0.7 | SUCCESS => {
    "ansible_facts": {
        "ansible_python_version": "2.7.5",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
10.0.0.6 | SUCCESS => {
    "ansible_facts": {
        "ansible_python_version": "2.6.6",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
10.0.0.8 | SUCCESS => {
    "ansible_facts": {
        "ansible_python_version": "3.6.8",
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false
}

08.Ansible-Playbook详解

yaml语法:YAML是一个可读性高的用来表达资料序列的格式,目前很多软件中采有此格式的文件,如:ubuntu,anisble,docker,k8s等,YAML官方网站地址。语法简介:

  • 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾
  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
  • 使用#号注释代码
  • 缩进必须是统一的,不能空格和tab混用
  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
  • YAML文件内容是区别大小写的,key/value的值均需大小写敏感
  • 多个key/value可同行写也可换行写,同行使用,分隔
  • v可是个字符串,也可是另一个列表
  • 一个完整的代码块功能需最少元素需包括 name 和 task
  • 一个name只能包括一个task
  • YAML文件扩展名通常为yml或yaml

YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-“来代表,Map里的键值对用”:"分隔,下面介绍常见的数据结构。

# List列表:列表由多个元素组成,每个元素放在不同行,且元素前均使用“-”打头,或者将所有元素用 [ ] 括起来放在同一行
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango

[Apple,Orange,Strawberry,Mango]

# Dictionary字典:字典由多个key与value构成,key和value之间用 :分隔,所有k/v可以放在一行,或者每个 k/v 分别放在不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite
# 也可以将key:value放置于{}中进行表示,用,分隔多个key:value

# An employee record
{name: "Example Developer", job: "Developer", skill: "Elite"}

# 范例
name: John Smith
age: 41
gender: Male
spouse:
  name: Jane Smith
  age: 37
  gender: Female
children:
  - name: Jimmy Smith
    age: 17
    gender: Male
  - name: Jenny Smith
    age 13
    gender: Female

三种常见的数据格式:XML(可扩展标记语言,可用于数据交换和配置);JSON(JavaScript 对象表记法,主要用来数据交换或配置,不支持注释);YAML(不是一种标记语言, 主要用来配置,大小写敏感,不支持tab)
在这里插入图片描述
可以用工具互相转换,参考网站:json2yamlbejson

playbook核心元素:Hosts(执行的远程主机列表)、Tasks(任务集)、Variables(内置变量或自定义变量在playbook中调用)、Templates(模板,可替换模板文件中的变量并实现一些简单逻辑的文件)、Handlers和notify(结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行)、tags( 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断)

  • hosts组件:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
  • remote_user 组件:可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
    - hosts: webservers
      remote_user: root
    
      tasks:
        - name: test connection
          ping:
          remote_user: user
          sudo: yes                 #默认sudo为root
          sudo_user:Chang           #sudo为Chang
    
  • task列表和action组件:play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task。task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。task两种格式:(1) action: module arguments (2) module: arguments 建议使用。注意:shell和command模块后面跟命令,而非key=value
    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: install httpd
          yum: name=httpd 
        - name: start httpd
          service: name=httpd state=started enabled=yes
    
  • 其它组件:某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers。任务可以通过"tags“打标签,可在ansible-playbook命令上使用-t指定进行调用
    # ShellScripts VS Playbook 案例
    #SHELL脚本实现
    #!/bin/bash
    # 安装Apache
    yum install --quiet -y httpd 
    # 复制配置文件
    cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
    cp/tmp/vhosts.conf /etc/httpd/conf.d/
    # 启动Apache,并设置开机启动
    systemctl enable --now httpd 
    
    #Playbook实现
    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: "安装Apache"
          yum: name=httpd
        - name: "复制配置文件"
          copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
        - name: "复制配置文件"
          copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
        - name: "启动Apache,并设置开机启动"
          service: name=httpd state=started enabled=yes
    

playbook 命令ansible-playbook <filename.yml> ... [options],有以下常见选项

-C --check          #只检测可能会发生的改变,但不真正执行操作
--list-hosts        #列出运行任务的主机
--list-tags         #列出tag
--list-tasks        #列出task
--limit 主机列表      #只针对主机列表中的主机执行
-v -vv  -vvv        #显示过程

# 范例
ansible-playbook  file.yml  --check #只检测
ansible-playbook  file.yml  
ansible-playbook  file.yml  --limit websrvs

09.Ansible-Playbook使用

利用 playbook 创建 mysql 用户:mysql_user.yml

[root@9019-kylin ansible]# vim create_mysql.yml
#create mysql user and group
- hosts: dbservers
  remote_user: root
  #gather_facts: no 不用收集主机信息,提升执行速度

  tasks:
    - {name: create group, group: name=mysql system=yes gid=306}
    - name: create user
      user: name=mysql system=yes group=mysql shell=/sbin/nologin createhome=no home=/data/mysql uid=306

# 检查语法
[root@9019-kylin ansible]# ansible-playbook -C create_mysql.yml

PLAY [dbservers] ************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [172.16.90.160]

TASK: [create group] ********************************************************** 
changed: [172.16.90.160]

TASK: [create user] *********************************************************** 
changed: [172.16.90.160]

PLAY RECAP ******************************************************************** 
172.16.90.160              : ok=3    changed=2    unreachable=0    failed=0 

# 执行
[root@9019-kylin ansible]# ansible-playbook create_mysql.yml

PLAY [dbservers] ************************************************************** 

TASK: [create group] ********************************************************** 
changed: [172.16.90.160]

TASK: [create user] *********************************************************** 
changed: [172.16.90.160]

PLAY RECAP ******************************************************************** 
172.16.90.160              : ok=2    changed=2    unreachable=0    failed=0 

# 查看结果
[root@9019-kylin ansible]# ansible dbservers -a 'getent passwd mysql'
172.16.90.160 | success | rc=0 >>
mysql:x:306:306::/data/mysql:/sbin/nologin

利用playbook安装nginx:install_nginx.yml

[root@9019-kylin ansible]# vim install_nginx.yml
---
# install nginx
- hosts: webservers
  remote_user: root
  gather_facts: no
  tasks:
    - name: add group nginx
      user: name=nginx state=present
    - name: add user nginx
      user: name=nginx state=present group=nginx
    - name: Install Nginx
      yum: name=nginx state=present
    - name: web page
      copy: src=files/index.html dest=/usr/share/nginx/html/index.html
    - name: Start Nginx
      service: name=nginx state=started enabled=yes

# 看远程端口是否启用
[root@9019-kylin ansible]# ansible webservers -a 'ss -ntl'

# 检查yml文件语法
[root@9019-kylin ansible]# ansible-playbook -C install_nginx.yml

# 执行yml文件
[root@9019-kylin ansible]# ansible-playbook install_nginx.yml

# 查看用户和组
[root@9019-kylin ~]# ansible webservers -a 'ls -l /etc/passwd'
172.16.91.22 | success | rc=0 >>
-rw-r--r--. 1 root root 2114 Feb 20 09:21 /etc/passwd

[root@9019-kylin ~]# ansible webservers -a 'ls -l /etc/group'
172.16.91.22 | success | rc=0 >>
-rw-r--r--. 1 root root 925 Feb 20 09:21 /etc/group

更多案例,请点击链接


10.Ansible-Playbook高级用法

handlers和notify:Handlers本质是task list,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在每个play的最后被触发,这样可避免多次有改变发生时,每次都执行指定的操作,仅在所有的变化发生完成后一次性的执行指定操作,在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。(可以理解为当被触发语句标识色为黄色则触发触发器)

---
- hosts: webservers
  remote_user: root
  gather_facts: no

  tasks:
    - name: add group nginx
      user: name=nginx state=present
    - name: add user nginx
      user: name=nginx state=present group=nginx
    - name: Install Nginx
      yum: name=nginx state=present
    - name: config
      copy:src=/root/config.txt dest=/etc/nginx/nginx.conf
      notify:
        - Restart Nginx
        - Check Nginx Process
      
      handlers:
        - name: Restart Nginx
          service: name=nginx state=restarted enabled=yes
        - name:check Nginx process
          shell: killall -0 nginx &> /tmp/nginx.log

tags组件:在playbook文件中,可以利用tags组件,为特定task指定标签,当在执行playbook时,可以只执行tags的task而非整个playbook文件。

---
- hosts: webservers
  remote_user: root
  tasks:
    - name: Install httpd
      yum: name=httpd state=present
    - name: Install configure file
      copy: src=files/httpd.conf dest/etc/httpd/conf/
      notify: restart httpd
      tags: config
    - name: ensure apache is running
      service: name=httpd state=started enable=yes

  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

# 查看有哪些标签
[root@9019-kylin ~]# ansible-playbook --list-tags httpd.yml

# 针对标签进行执行
[root@9019-kylin ~]# ansible-playbook -t config httpd.yml

变量:仅能由字母、数字和下划线组成,且只能以字母开头。例如:http_port=80,,通过{{ http_port }}调用变量(建议变量名前后加空格),有时用"{{ http_port }}"才生效。来源:

  • .ansible 的 setup facts 远程主机的所有变量都可直接调用
    # 范例
    # 执行错误,变量只能在playbook中使用
    [root@9019-kylin ~]# ansible all -m file -a 'path=/data/{{ ansible_nodename }}.log state=touch'
    
    # 执行成功
    [root@9019-kylin ~]# vim var.yml
    ---
    # var.yml
    - host: all
      remote_user: root
    
      tasks:
        - name: create log file
          file: name=/data/{{ ansible_nodename }}.log state=touch owner=user mode=600
    [root@9019-kylin ~]# ansible-playbook var.yml
    
  • 通过命令行指定变量(优先级最高)
    ---
    - hosts: webservers
      remote_user: root
      tasks:
        - name: install package
          yum: name={{ pkname }} state=present
    
    # 给变量赋值      
    [root@9019-kylin ~]# ansible-playbook -e pkname=memcached
    
  • 在playbook文件中定义变量
    ---
    - hosts: webservers
      remote_user: root
      vars:
        - username: user1
        - groupname: group1
    
      tasks:
        - name: create group
          group: name={{ groupname }} state=present
        - name: create user
          user: name={{ username }} group={{ groupname }} state=present
    
    # 验证是否创建成功
    [root@21-cent74 ~]# id user1
    
  • 使用变量文件(可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比playbook中定义的变量优化级高)
    vim vars1.yml
    ---
    # variables file
    package_name: vsftpd
    service_name: vsftpd
    
    vim  var2.yml
    ---
    #install package and start service
    - hosts: webservers
      remote_user: root
      vars_files:
        - vars1.yml
    
      tasks:
        - name: install package
          yum: name={{ package_name }}
          tags: install
        - name: start service
          service: name={{ service_name }} state=started enabled=yes
    
  • 主机清单文件中定义变量
    # 主机变量:在inventory主机清单文件中为指定的主机定义变量以便在playbook中使用
    # 组(公共)变量:在inventory主机清单文件中赋予给指定组内的所有主机上的paybook中可用的变量,如果和主机变量是同名,优先级地域主机变量
    [root@9019-kylin ansible]# vim hosts 
    [appservers]
    
    [webservers]
    172.16.91.21 host=node1
    172.16.91.22 host=node2
    
    [webservers:vars]
    domain=example.org
    
    [root@9019-kylin ansible]# ansible webservers -m hostname -a 'name={{host}}.{{domain}}'
    

11.Ansible-Playbook模板用法

简介:模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja语法(语法详解地址)。可以根据和参考模块文件,动态生成相类似的配置文件,template文件必须存放于templates目录下,且命名为.j2结尾且yaml/yml 文件需和templates目录平级

[root@9019-kylin ansible]# vim templnginx.yml
---
- hosts: webservers
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: template config to remote hosts
      template: src=nginx.conf.js dest=/etc/nginx/nginx.conf
    - name: start service
      service: name=nginx state=started enabled=yes
[root@9019-kylin ansible]# mkdir templates
[root@9019-kylin ansible]# cd templates/
[root@9019-kylin templates]# vim nginx.conf.j2

# Jinja 允许用计算值
[root@9019-kylin ansible]# vim nginx.conf.j2 
worker_processes {{ ansible_processor_vcpus**2 }};    

template中使用流程控制 for 和 if:template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

[root@9019-kylin templates]# vim nginx.conf2.j2

{% for vhost in nginx_vhosts %}
server {
   listen {{ vhost }}
}
{% endfor %}

[root@9019-kylin ansible]# vim templnginx2.yml
---
- hosts: webservers
  remote_user: root
  vars:
    nginx_vhosts:
      - 81
      - 82
      - 83
  tasks:
    - name: template config
      template: src=nginx.conf.j2 dest=/data/nginx.conf

[root@9019-kylin ansible]# ansible-playbook -C templnginx2.yml
[root@9019-kylin ansible]# ansible-playbook templnginx2.yml
[root@9019-kylin ansible]# vim templnginx3.yml
- hosts: webservers
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8080
        root: "/var/www/nginx/web1/"
      - web2:
        listen: 8080
        server_name: "web2.magedu.com"
        root: "/var/www/nginx/web2/"
      - web3:
        listen: 8080
        server_name: "web3.magedu.com"
        root: "/var/www/nginx/web3/"
  tasks:
    - name: template config to 
      template: src=nginx.conf3.j2 dest=/data/nginx3.conf
      
[root@9019-kylin templates]# vim nginx.conf3.j2
{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost.listen }}
   {% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
   {% endif %}
root  {{ vhost.root }}
}
{% endfor %}

# 生成结果
server {
   listen 8080
   root  /var/www/nginx/web1/
}
server {
   listen 8080
   server_name web2.magedu.com
   root  /var/www/nginx/web2/
}
server {
   listen 8080
   server_name web3.magedu.com
   root  /var/www/nginx/web3/
}

playbook中使用流程控制 when 和 with_items:when语句,可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式。 with_items语句,可以实现迭代(当有需要重复性执行的任务时,可以使用迭代机制)。对迭代项的引用,固定变量名为”item“,要在task中使用with_items给定要迭代的元素列表。(列表元素格式:字符串、字典)

[root@9019-kylin ansible]# vim templnginx3.yml
---
- hosts: webservers
  remote_user: root
  tasks: 
    - name: install conf file to centos7
      template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
      when: ansible_distribution_major_version == "7"
    - name: install conf file to centos6
      template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
      when: ansible_distribution_major_version == "6"
---
#remove mariadb server
- hosts: appsrvs:!192.168.38.8
  remote_user: root

  tasks:
    - name: stop service
      shell: /etc/init.d/mysqld stop
    - name:  delete files and dir
      file: path={{ item }} state=absent
      with_items:
        - /usr/local/mysql
        - /usr/local/mariadb-10.2.27-linux-x86_64
        - /etc/init.d/mysqld
        - /etc/profile.d/mysql.sh
        - /etc/my.cnf
        - /data/mysql
    - name: delete user
      user: name=mysql state=absent remove=yes 

---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: add some groups
      group: name={{ item }} state=present
      with_items:
        - nginx
        - mysql
        - apache
    - name: add some users
      user: name={{ item.name }} group={{ item.group }} state=present
      with_items:
        - { name: 'nginx', group: 'nginx' }
        - { name: 'mysql', group: 'mysql' }
        - { name: 'apache', group: 'apache' }

更多案例,请点击链接


12.Ansible-Playbook高级用法role

角色role,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。运维复杂的场景:建议使用roles,代码复用度高。roles:多个角色的集合, 可以将多个的role,分别放至roles目录下的独立子目录中。

Roles各目录作用:roles/project/ :项目名称,有以下子目录

  • files/ :存放由copy或script模块等调用的文件
  • templates/:template模块查找所需要模板文件的目录
  • tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
  • handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
  • vars/:定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
  • meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
  • default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低

创建role:创建role的步骤如下

  • 创建以roles命名的目录
  • 在roles目录中分别创建以各角色名称命名的目录,如webservers等
  • 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建
  • 在playbook文件中,调用各角色

roles的目录结构:针对大型项目使用Roles进行编排

nginx-role.yml 
roles/
└── nginx 
     ├── files
     │    └── main.yml 
     ├── tasks
     │    ├── groupadd.yml 
     │    ├── install.yml 
     │    ├── main.yml 
     │    ├── restart.yml 
     │    └── useradd.yml 
     └── vars 
          └── main.yml 

playbook调用角色

# 调用角色方法1:
---
- hosts: websrvs
  remote_user: root
  roles:
    - mysql
    - memcached
    - nginx   

# 调用角色方法2:键role用于指定角色名称,后续的k/v用于传递变量给角色
---
- hosts: all
  remote_user: root
  roles:
    - mysql
    - { role: nginx, username: nginx }

# 调用角色方法3:还可基于条件测试实现角色调用
---
- hosts: all
  remote_user: root
  roles:
    - { role: nginx, username: nginx, when: ansible_distribution_major_version == ‘7’  }

# roles 中 tags 使用
#nginx-role.yml
---
- hosts: websrvs
  remote_user: root
  roles:
    - { role: nginx ,tags: [ 'nginx', 'web' ] ,when: ansible_distribution_major_version == "6“ }
    - { role: httpd ,tags: [ 'httpd', 'web' ]  }
    - { role: mysql ,tags: [ 'mysql', 'db' ] }
    - { role: mariadb ,tags: [ 'mariadb', 'db' ] }

ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml

案例详解:更多案例请点击链接

# 案例:实现 httpd 角色
# 规划:1、安装软件 2、修改配置文件 3、部署网页 4、启动服务
[root@9019-kylin roles]# pwd
/root/ansible/roles
[root@9019-kylin roles]# mkdir httpd/{tasks,files,handles} -pv
mkdir: 已创建目录 "httpd"
mkdir: 已创建目录 "httpd/tasks"
mkdir: 已创建目录 "httpd/files"
mkdir: 已创建目录 "httpd/handles"
[root@9019-kylin ansible]# vim roles/httpd/tasks/install.yml
- name: install httpd package
  yum: name=httpd
[root@9019-kylin ansible]# vim roles/httpd/tasks/config.yml
- name: config file
  copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes
  notify: restart
[root@9019-kylin ansible]# cd roles/httpd/files/
[root@9019-kylin files]# ls
httpd.conf
[root@9019-kylin ansible]# vim roles/httpd/tasks/index.yml
- name: index.html
  copy: src=index.html dest=/var/www/html/
[root@9019-kylin ansible]# vim roles/httpd/files/index.html
<h1>Welcome to ansible!</h1>
[root@9019-kylin ansible]# vim roles/httpd/tasks/service.yml
- name: start service
  service: name=httpd state=started enabled=yes
[root@9019-kylin ansible]# vim roles/httpd/tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
[root@9019-kylin roles]# vim roles/httpd/handlers/main.yml
- name: restart
  service: name=httpd state=restarted
[root@9019-kylin roles]# tree httpd/
├── files
│   ├── httpd.conf
│   └── index.html
├── handlers
│   └── main.yml
└── tasks
    ├── config.yml
    ├── index.yml
    ├── install.yml
    ├── main.yml
    └── service.yml
[root@9019-kylin ansible]# vim role_httpd.yml
---
# httpd role
- hosts: webservers
  remote_user: root

  roles:
    - httpd
[root@9019-kylin ansible]ansible-playbook role_httpd.yml
# 注意:centos7安装软件的时候会自动创建账号;而centos8不会自动创建账号,直接安装会报错。建议在ansible脚本中配置添加账号

推荐资料
http://galaxy.ansible.com
https://galaxy.ansible.com/explore
http://github.com
http://ansible.com.cn
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples
https://www.zsythink.net
http://www.wangxiaochun.com
https://www.junmajinlong.com

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值