美文网首页
Ansible&实现主/备模式高可用

Ansible&实现主/备模式高可用

作者: Net夜风 | 来源:发表于2018-09-10 19:16 被阅读0次

    运维核心工作:

    操作系统安装(物理机、虚拟机)--> 应用程序包部署(安装、配置、服务启动 )--> 批量操作 --> 业务系统程序部署(安装,运行以及发布) --> 监控

    • 系统安装(OS Provisioning):

      • bare metal:裸机上安装系统,pxe预执行环境;cobbler是二次封装的pxe;
      • virtual machine:在虚拟机上安装系统;
    • Configuration:程序配置

      • puppet(ruby语言研发):学习入门曲线陡峭;早先问世,稳定,重量级;
      • saltstack(python语言研发):与puppet相似,要有强大的二次研发能力才能填坑,重量级;
      • chef:轻量级,使用简单,早期问世;
      • cfengine:
      • ansible:
        注意:puppet和saltstack都是重量级应用在上百台服务器以上的运维环境,需要长时间学习才能灵活运用,如果数量较少,支出会大于收益;
        这就产生了一些较轻量级、简单入门学习的运维工具来负责较少量的服务器运维;如chef、cfengine、ansible等;
    • Command and Control:批量执行命令控制

      • fabric 轻量级,python语言研发;可编写fabric脚本完成强大功能;
      • func 重量级
      • ansible
    • 预发布验正:
      新版本的代码先发布到服务器(跟线上环境配置完全相同,只是未接入到调度器);

    • 程序发布:
      不能影响用户体验;
      系统不能停机;
      不能导致系统故障或造成系统完全不可用;

    • 灰度发布:
      发布路径:
      /webapp/tuangou-1.1
      /web/app/tuangou
      /webapp/tuangou-1.2

    在调度器上下线一批主机(maintanance) --> 关闭服务 --> 部署新版本的应用程序 --> 启动服务 --> 在调度器上启用这一批服务器;

    • 自动化灰度发布:脚本、发布平台;

    轻量级的运维工具:Ansible

    Ansible的特性
    • 模块化:调用特定的模块,完成特定任务
    • 基于Python语言实现,有Paramiko,PyYAML,Jinja2(模板语言)三个关键模块;
    • 部署简单:agentless
    • 支持自定义模块
    • 支持playbook编排任务
    • 有幂等性:一个任务执行一遍和执行n遍效果一样,不因为重复执行带来意外情况
    • 安全,基于OpenSSH
    • 无需代理不依赖PKI(无需ssl)
    • YAML格式编排任务,支持丰富的数据结构
    • 较强大的多层解决方案
    Ansible的架构
    ansible架构.png
    • Core Modules:核心模块
    • Custom Modules:自定义模块
    • Connection Plugins:连接插件
    • Host Inventory:ansible管理主机的清单/etc/ansibe/hosts
    • Plugins:模块功能的补充,如记录日志发送通知等
    • Playbooks 核心组件;任务剧本,编排定义ansible任务集的配置文件,ansible顺序依次执行,通常时json格式的yaml文件
    Ansible的安装使用
    1. ansible是基于epel仓库,因此安装之前先要配置好epel的yum源仓库

      [root@localhost ~]# yum info ansible
      Loaded plugins: fastestmirror
      Loading mirror speeds from cached hostfile
       * extras: ftp.sjtu.edu.cn
      Available Packages
      Name        : ansible
      Arch        : noarch
      Version     : 2.6.3
      Release     : 1.el7
      Size        : 10 M
      Repo        : epel
      Summary     : SSH-based configuration management, deployment, and task execution system
      URL         : http://ansible.com
      License     : GPLv3+
      Description : Ansible is a radically simple model-driven configuration management,
                : multi-node deployment, and remote task execution system. Ansible works
                : over SSH and does not require any software or daemons to be installed
                : on remote nodes. Extension modules can be written in any language and
                : are transferred to managed machines automatically.
      
      [root@localhost ~]# rpm -ql ansible |less
      /etc/ansible/ansible.cfg   #ansible主配置文件
      /etc/ansible/hosts         #主机清单配置文件
      /etc/ansible/roles         #角色配置文件
      
    2. ansible的使用方式:

    • 在命令行中直接给出
    • 在riles中定义好
    1. ansible语法格式:ansible <host-pattern> [options]

    2. ansible的简单使用格式:ansible HOST-PATTERN -m MOD_NAME -a MOD_ARGS -f FORKS -C -u USERNAME -c CONNECTION

    3. 基于密钥的方式连接两台host主机node1和node2

      [root@localhost ~]# ssh-keygen -t rsa -P ""   #生成密钥
      [root@localhost ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.43.143   
          #使用密钥连接node1
      [root@localhost ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.43.129   
          #使用密钥连接node2
      
      [root@localhost ~]# vim /etc/ansible/hosts   #编辑主机清单文件添加主机
       [websrvs]
       192.168.43.129
       192.168.43.143
       
       [dbsrvs]
       192.168.43.129
       [root@localhost ~]# ansible all -m ping -C  #使用ping命令测试两台主机node1,node2;-C:测试模式,干跑;
       192.168.43.129 | SUCCESS => {
           "changed": false, 
           "ping": "pong"
       }
       192.168.43.143 | SUCCESS => {
           "changed": false, 
           "ping": "pong"
       }
      
    4. ansible的常用模块:

    • group 模块

       [root@localhost ~]# ansible-doc -s group   #查看group模块的帮助文档
       示例:
       [root@localhost ~]# ansible all -m group -a "gid=3000 name=mygro state=present system=no"
       192.168.43.143 | SUCCESS => {
           "changed": true, 
           "gid": 3000, 
           "name": "mygro", 
           "state": "present", 
           "system": false
       }
       192.168.43.129 | SUCCESS => {
           "changed": true, 
           "gid": 3000, 
           "name": "mygro", 
           "state": "present", 
           "system": false
       }
       #在node1和node2上查看/etc/group文件确认操作是否成功
       [root@localhost ~]# tail -1 /etc/group
       mygro:x:3000:
      
    • user模块

      • *name= 指定要管理的用户;

      • state= 为present | absent;

      • system= 是否创建系统账号;

      • uid= 指定UID;

      • shell= 默认shell类型;

      • group= 基本组;

      • groups= 额外(附加)组;

      • comment= 注释信息;

      • home= 用户的家目录;

      • move_home= 移动已存在用户的家目录;

      • password 添加密码,应该指定的是openssl加密后的密码;

      • remove 当state=absent时,删除用户时同时删除家目录;

        示例:
        [root@localhost ~]# ansible all -m user -a "uid=5000 name=testuser state=present groups=mygro shell=/bin/tcsh"
        192.168.43.129 | SUCCESS => {
            "changed": true, 
            "comment": "", 
            "create_home": true, 
            "group": 5000, 
            "groups": "mygro", 
            "home": "/home/testuser", 
            "name": "testuser", 
            "shell": "/bin/tcsh", 
            "state": "present", 
            "system": false, 
            "uid": 5000
        }
        192.168.43.143 | SUCCESS => {
            "changed": true, 
            "comment": "", 
            "create_home": true, 
            "group": 5000, 
            "groups": "mygro", 
            "home": "/home/testuser", 
            "name": "testuser", 
            "shell": "/bin/tcsh", 
            "state": "present", 
            "system": false, 
            "uid": 5000
        }
        #在node1和node2上查看用户创建结果
        [root@localhost ~]# tail -1 /etc/passwd
        testuser:x:5000:5000::/home/testuser:/bin/tcsh
        
    • copy模块:`ansible-doc -s copy;用来复制文件到远程主机
      2种用法:

      • 1)src= dest=
      • 2)content= dest=
        owner,group,mode 可同时指明文件的属主、组及权限;
        一般有=号的选项为必有选项;
        src=为本地文件或目录;
        dest=为远程被管理主机文件或目录;
        content=表示把此处的内容直接当做源文件;
    [root@localhost ~]# ansible all -m copy -a "src=/etc/fstab dest=/tmp/fstab.ansible mode=600"
    192.168.43.129 | SUCCESS => {
        "changed": true, 
        "checksum": "413996796bccca42104b6769612d2b57d8085210", 
        "dest": "/tmp/fstab.ansible", 
        "gid": 0, 
        "group": "root", 
        "md5sum": "95b7fa684cc5066d06f284ce029cddb5", 
        "mode": "0600", 
        "owner": "root", 
        "size": 541, 
        "src": "/root/.ansible/tmp/ansible-tmp-1536476031.13-129897102565078/source", 
        "state": "file", 
        "uid": 0
    }
    192.168.43.143 | SUCCESS => {
        "changed": true, 
        "checksum": "413996796bccca42104b6769612d2b57d8085210", 
        "dest": "/tmp/fstab.ansible", 
        "gid": 0, 
        "group": "root", 
        "md5sum": "95b7fa684cc5066d06f284ce029cddb5", 
        "mode": "0600", 
        "owner": "root", 
        "size": 541, 
        "src": "/root/.ansible/tmp/ansible-tmp-1536476031.16-86269165700494/source", 
        "state": "file", 
        "uid": 0
    }
    
    node1:
    [root@node1 ~]# ll -d /tmp/fstab.ansible 
    -rw------- 1 root root 541 Sep  9 02:53 /tmp/fstab.ansible
    
    • command模块:`ansible-doc -s command;在被管理远程主机上执行命令;省略模块时,默认为command模块;

      • chdir:指定在哪个目录下运行命令;

      • creates:命令运行前创建文件;如果文件存在就不执行命令;

      • removes:命令运行后移除文件;如果文件不存在就不执行命令;

      • executable:指定shell程序来运行命令;

        示例:
        [root@localhost ~]# ansible all -m command -a "ifconfig"
        192.168.43.143 | SUCCESS | rc=0 >>
        ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.43.143  netmask 255.255.255.0  broadcast 192.168.43.255
           ...
        lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
           ...
        192.168.43.129 | SUCCESS | rc=0 >>
        ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.43.129  netmask 255.255.255.0  broadcast 192.168.43.255
           ...
        
        lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            ...
        
        注意:command执行时不适用shell解析,是裸执行;比如传递参数`-a "echo mageedu | passwd --stdin testuser"`不能转递密码给testuser,需要使用下面的shell模块
        
    • shell模块:ansible-doc -s shell;在被管理远程主机上执行命令;但是为调用shell进程,然后把命令在子进程中运行;在执行的命令中可使用管道符;

       示例:
       [root@localhost ~]# ansible all -m shell -a "echo mageedu | passwd --stdin testuser"
       192.168.43.143 | SUCCESS | rc=0 >>
       Changing password for user testuser.
       passwd: all authentication tokens updated successfully.
      
       192.168.43.129 | SUCCESS | rc=0 >>
       Changing password for user testuser.
       passwd: all authentication tokens updated successfully.
      
    • file 模块:ansible-doc -s file
      用法:

      • 1)创建链接文件:
        *path= 指明操作的文件
        src= 要链接的源文件;
        state=link

      • 2)修改属性:
        path= owner= mode= group=

      • 3)创建目录:
        path= state=directory

        示例:
        [root@localhost ~]# ansible all -m file -a "path=/var/tmp/hello.dir state=directory"   #创建hello.dir目录
        192.168.43.143 | SUCCESS => {
           "changed": true, 
           "gid": 0, 
           "group": "root", 
           "mode": "0755", 
           "owner": "root", 
           "path": "/var/tmp/hello.dir", 
           "size": 6, 
           "state": "directory", 
           "uid": 0
        }
         192.168.43.129 | SUCCESS => {
           "changed": true, 
           "gid": 0, 
           "group": "root", 
           "mode": "0755", 
           "owner": "root", 
           "path": "/var/tmp/hello.dir", 
           "size": 6, 
           "state": "directory", 
           "uid": 0
        }
        
        node1:
        [root@node1 ~]# ls -d /var/tmp/hello.*
        /var/tmp/hello.dir
        
        #设定文件属性
        [root@localhost ~]# ansible all -m copy -a "src=/etc/fstab dest=/var/tmp/fstab.ansible"
        [root@localhost ~]# ansible all -m file -a "src=/var/tmp/fstab.ansible path=/var/tmp/fstab.link state=link"
        
        node1:
        [root@node1 ~]# ll -d /var/tmp/fstab.*
        -rw-r--r-- 1 root root 541 Sep  9 03:13 /var/tmp/fstab.ansible
        lrwxrwxrwx 1 root root  22 Sep  9 03:15 /var/tmp/fstab.link -> /var/tmp/fstab.ansible
        
    • cron模块:定义任务计划

      • minute= 几分钟,范围0-59;

      • day= 一个月的那一天,范围1-31,例如,1-5,/2等

      • month= 哪个月,范围1-12;

      • hour= 哪个小时,范围0-23;

      • weekday= 星期几,范围0-6;

      • job= 表示state为present时,要执行的命令;

      • *name= 必须指定计划任务条目;

      • state=
        present:创建cron计划任务;默认;
        absent:删除cron计划任务;

        示例:
        
            [root@localhost ~]#  ansible all -m cron -a "minute=*/3 job='/usr/sbin/update 172.16.0.1 &> /dev/null' name=text1"
        192.168.43.129 | SUCCESS => {
            "changed": true, 
            "envs": [], 
            "jobs": [
             "text1"
            ]
        }
        192.168.43.143 | SUCCESS => {
            "changed": true, 
            "envs": [], 
           "jobs": [
             "text1"
            ]
        }
        
        node1:
        [root@node1 ~]# crontab -l
        #Ansible: text1
        */3 * * * * /usr/sbin/update 172.16.0.1 &> /dev/null
        
        [root@localhost ~]#  ansible all -m cron -a "name=text1 state=absent"  #删除定时任务
        192.168.43.129 | SUCCESS => {
            "changed": true, 
            "envs": [], 
            "jobs": []
        }
        192.168.43.143 | SUCCESS => {
            "changed": true, 
            "envs": [], 
            "jobs": []
        }
        
    • yum模块:安装程序模块

        示例:
        [root@localhost ~]# ansible all -m yum -a "name=nginx state=installed"
        192.168.43.129 | SUCCESS => {
            "changed": true, 
            "msg": "", 
            "rc": 0, 
            "results": [
            ...
        192.168.43.143 | SUCCESS => {
            "changed": true, 
            "msg": "", 
            "rc": 0, 
            "results": [
            ...
      
        node1:
        [root@node1 ~]# rpm -q nginx
        nginx-1.12.2-2.el7.x86_64
      
    • service 模块

      • *name= 指明管理的服务

      • state=
        started 启动服务;
        stopped 停止服务;
        restarted 重启服务;

      • enabled= 开机自动启动;1或0;

      • runlevel= 在指定级别下为开机自动启动;默认为2345,或345级别;

      • arguments 向命令行传参数;

        示例:
        [root@localhost ~]# ansible all -m service -a "name=nginx state=started"
        192.168.43.129 | SUCCESS => {
           "changed": true, 
           "name": "nginx", 
           "state": "started", 
           "status": {
           ...
        192.168.43.143 | SUCCESS => {
          "changed": true, 
          "name": "nginx", 
          "state": "started", 
          "status": {
        ...
        
        node1:
        [root@node1 ~]# ss -tnl
        LISTEN     0      128                  *:80                               *:*    
        ...
        

    注意:service有2各选项:enabled设定开机自启,runlevel在那个级别设定开机自启

    • spripts模块:脚本模块

        示例:
        [root@localhost ~]# vim /tmp/text.sh
        #!/bin/bash
        #
        echo "ansible script" > /tmp/ansible.txt
                                           
        [root@localhost ~]# ansible all -m script  -a "/tmp/text.sh"
        192.168.43.143 | SUCCESS => {
        "changed": true, 
        "rc": 0, 
        "stderr": "Shared connection to 192.168.43.143 closed.\r\n", 
        "stderr_lines": [
            "Shared connection to 192.168.43.143 closed."
        ], 
        "stdout": "", 
        "stdout_lines": []
        }
        192.168.43.129 | SUCCESS => {
        "changed": true, 
        "rc": 0, 
        "stderr": "Shared connection to 192.168.43.129 closed.\r\n", 
        "stderr_lines": [
            "Shared connection to 192.168.43.129 closed."
        ], 
        "stdout": "", 
        "stdout_lines": []
        }
      
    1. Playbook的核心元素:
    • hosts:主机(关联到的主机);可以是一个或多个用冒号分隔的主机组;可以是一个主机组,也可以是一个主机;这些主机必须定义在hosts iventory中;
      • remoute_user:在远程主机上执行任务的用户;即以哪个用户的身份运行此任务,可以全局指定,也可以在tasks在中单独指定执行任务的用户;即不同的任务指明不同的用户;
      • sudo_user:在使用sudo方式时执行任务时,指明临时切换哪个用户执行;只是在指明以sudo的方式运行时才使用;
    • tasks:任务列表;定义任务的方式主要就是调用模块和模块参数;
    • variables:变量(多次引用任务使用)
    • templates:模板(包含了模板语法的文本文件)
    • handlers:从处理器(由特定条件触发的任务)任务,在特定条件下触发;在handlers所关注的资源发生改变时才触发任务;一般使用notify机制通知来触发;
      生效方式:接收到其它任务的通知时被触发;
    • roles:角色
    playbook的主要作用:

    就是能够把多个相关联的任务,通过读取YAML格式的配置文件一次编完;要把任务、变量、模板、处理器放在一个YAML格式文件中进行指定,然后任务就可一次批量执行;

    例如:
        playbook的基础组件hosts和tasks演示:
        [root@localhost ~]# mkdir -pv playbook
        [root@localhost ~]# cd playbook/
        [root@localhost playbook]# vim first.yaml
                 - hosts: all
                   remote_user: root
                   tasks:
                   - name: install redis
                     yum: name=redis state=latest
                   - name: start redis
                     service: name=redis state=started
    
        [root@localhost playbook]# ansible-playbook --check first.yaml
        
        PLAY [all] *************************************************************************************
        
        TASK [Gathering Facts] #只要收集参数成功都显示ok;*************************************************************************
        ok: [192.168.43.143]
        ok: [192.168.43.129]
        
        TASK [install redis]  #在playbook中定义的第一个任务***************************************************************************
        changed: [192.168.43.129]
        changed: [192.168.43.143]
        
        TASK [start redis] #在playbook中定义的第二个任务*****************************************************************************
        changed: [192.168.43.129]
        changed: [192.168.43.143]
        
        PLAY RECAP  #返回的报告*************************************************************************************
        192.168.43.129             : ok=3    changed=2    unreachable=0    failed=0   
        192.168.43.143             : ok=3    changed=2    unreachable=0    failed=0 
        
        [root@localhost playbook]# ansible-playbook --list-hosts first.yaml
        #查看这个playbook运行在哪些主机
        playbook: first.yaml
        
          play #1 (all): all    TAGS: []
            pattern: [u'all']
            hosts (2):
              192.168.43.143
              192.168.43.129
      
      [root@localhost playbook]# ansible-playbook -C first.yaml  #干跑一遍测试
      [root@localhost playbook]# ansible-playbook  first.yaml   #真正执行
    
    • 注意:GATHERING FACTS 第一个任务,是默认的,在每一个目标主机上运行之前,需要知道目标主机的状态,例如主机名、ip地址等,这些都是内建变量,叫主机的facts变量,是ansible可调用的变量之一;这个过程就是收集变量的过程,也可手动收集;
    • 如果指明了三个任务,在三台主机上运行,执行次序是,把第一个任务在第三台主机运行,没问题则在三台主机上再运行第二个任务,如果在运行其中某一主机出现故障,后面的任务会终止;
      所以,任务列表,是自上而下,每个任务依次进行的;
      指明任务的格式:2种
      (1)action: module arguments 较新版本支持
      (2)moudule: arguments 所有版本通用
    • shell和command模块参数独特,后面直接跟命令,而非key=value类的参数列表;
      (1)某任务的状态在运行后为changed时,可通过notify通知给相应的handlers处理器;
      (2)任务可以通过tags打标签,而后可在ansibles-playbook命令上使用-t指定进行调用,可调用多个标签;
    • setup模块:手动收集指定远程主机的变量
      ansible 192.168.43.129 -m setup
    示例1:安装httpd,安装配置文件,启动httpd服务
    [root@localhost playbook]# mkdir working
    [root@localhost playbook]# cd working/
    [root@localhost working]# cp /etc/httpd/conf/httpd.conf ./
    [root@localhost working]# vim httpd.conf
        Listen 8080
    [root@localhost playbook]# cd ..
    [root@localhost playbook]# vim web.yaml
            - hosts: websrvs
              remote_user: root
              tasks:
              - name: install httpd package
                yum: name=httpd state=present
              - name: install configure file
                copy: src=working/httpd.conf dest=/etc/httpd/conf/
              - name: start httpd service
                service: name=httpd state=started
              - name: execute ss command
                shell: ss -tnl | grep 8080
    [root@localhost playbook]# ansible-playbook --check web.yaml 测试语法
        PLAY [websrvs] *********************************************************************************
    
        TASK [Gathering Facts] *************************************************************************
        ok: [192.168.43.143]
        ok: [192.168.43.129]
        
        TASK [install httpd package] *******************************************************************
        changed: [192.168.43.143]
        changed: [192.168.43.129]
        
        TASK [install configure file] ******************************************************************
        changed: [192.168.43.129]
        changed: [192.168.43.143]
        
        TASK [start httpd service] *********************************************************************
        changed: [192.168.43.129]
        changed: [192.168.43.143]
        
        TASK [execute ss command] **********************************************************************
        skipping: [192.168.43.129]
        skipping: [192.168.43.143]
        
        PLAY RECAP *************************************************************************************
        192.168.43.129             : ok=4    changed=3    unreachable=0    failed=0   
        192.168.43.143             : ok=4    changed=3    unreachable=0    failed=0 
    [root@localhost playbook]# ansible-playbook web.yaml  #真正执行
    注意:在ansible-playbook中执行ss -tnl | grep :8080,这种查询是不显示结果的,所以,一般不在ansible-playboot里执行有关查询显示的命令;
    

    ...

    示例2:演示使用handlers,触发执行;
    如果把监听端改为808,再执行,则不会生效,因为,服务已经启动了,除非重启服务,这时,就应该用到handlers处理器
    [root@localhost playbook]# vim web-2.yaml 
            - hosts: websrvs
              remote_user: root
              tasks:
              - name: install httpd package
                yum: name=httpd state=present
              - name: install configure file
                copy: src=working/httpd.conf dest=/etc/httpd/conf/
                notify: restart httpd
              - name: start httpd service
                service: name=httpd state=started
              handlers:
              - name: restart httpd
                service: name=httpd state=restarted
            [root@localhost playbook]# vim working/httpd.conf 
                    Listen 808
            [root@localhost playbook]# ansible-playbook --check web-2.yaml
            [root@localhost playbook]# ansible-playbook web-2.yaml
            [root@localhost playbook]# ansible websrvs -m shell -a "ss -tnl | grep 808"
            192.168.1.113 | SUCCESS | rc=0 >>
            LISTEN     0      128         :::808                     :::*                  
            
            192.168.1.114 | SUCCESS | rc=0 >>
            LISTEN     0      128         :::808                     :::*   
    

    ...

     示例3:根据上例,如果仅修改了配置文件,却还要从第一步,执行安装程序包,这样是没必要的,所以,可使用tag,给任务加标签,不指定标签时,执行所有任务,加标签时,只执行标签所在的任务;
     [root@localhost playbook]# vim web-3.yaml   
            - hosts: websrvs
              remote_user: root
              tasks:
              - name: install httpd package
                yum: name=httpd state=present
                tags: insthttpd
              - name: install configure file
                copy: src=working/httpd.conf dest=/etc/httpd/conf/
                tags: instconfig
                notify: restart httpd
              - name: start httpd service
                service: name=httpd state=started
                tags: starthttpd
              handlers:
              - name: restart httpd
                service: name=httpd state=restarted
           [root@localhost playbook]# vim working/httpd.conf
                   Listen 80
          [root@localhost playbook]# ansible-playbook -t insthttpd --check web-3.yaml 
          [root@localhost playbook]# ansible-playbook -t instconf,insthttpd --check web-3.yaml  #调用多个标签;
    

    8.variables:变量

    • 1)facts:任何facts变量都由正在通信的目标主机发回的信息,ansible自动获取变量,可直接调用;在setup模块中查看变量;

    • 2)ansible-playbook命令的命令行中的自定义变量;
      -e VARS, --extra-vars=VARS

    • 3)通过roles传递变量;

    • 4)Host Inventory
      - a)向不同的主机传递不同的变量;
      IP/HOSTNAME varailble=value var2=value2
      - b)向组中的主机传递相同的变量;
      [groupname:vars]
      variable=value

    • 注意:invertory参数:
      用于定义ansible远程路径目标主机时使用的参数,而非传递给playbook的变量;
      ansible_ssh_host ansible_ssh_port ansible_ssh_user ansible_ssh_pass ansible_sudo_pass ...
      通常ansible中的inventory还有专门参数,不叫变量,因为它不是传递给playbook使用的,而是通过ansible连接每个被管理主机时使用的;

        示例1:演示ansible-playbook命令行调用变量
        [root@localhost playbook]# vim forth.yaml
                    - hosts: websrvs
                      remote_user: root
                      tasks:
                      - name: install {{ pkname }}
                        yum: name={{ pkname }} state=present
                  [root@localhost playbook]# ansible-playbook -e pkname=memcached --check forth.yaml 
                  [root@localhost playbook]# ansible-playbook -e pkname=memcached  forth.yaml 
      

    1. playbook的其它组件:
    • 变量:5种
      ansible facts 可使用setup模块获取;收集远程主机变量;
      ansible-playbook -e "var=value" 自定义变量
      host variable:host iventory 主机变量
      group variable(主机组上的变量)
      roles

    • 变量调用方法:{{ variable }}

            在playbook中定义变量的方法:
            vars:
            - var1: value1
            - var2: value2
            注意:这种变量有个缺陷,要想改变变量值时都要改变配置文件,不过可在调用时覆盖其变量的值;
      
    1. templates模块:基于模板方式生成一个文件复制到远程主机;
      *src= 指定本地jinja2的模板文件路径
      *dest= 远程主机路径
      owner=属主
      group=属组
      mode= 权限
    • 模板:templates
      就是文本文件,内部嵌套有脚本(这个脚本使用模板编程语言编写)
      python只有在实现web框架时进行嵌入,将自己基于模板编程语言嵌入到其它文本中的机制,它的模板编程语言叫jinja2嵌入式的编程语言;类似于playbook,在python中叫resource资源和清单facts;在清单中定义资源时或定义使用的模板时会用到rubby的模板编程语言;
      jinja2模板编程语言所实现的功能是,可以在文本文件中,使用一个所谓的嵌入的标记语法,引入一段模板编程语言所编写的脚本;而这种脚本无法就是支持比较简单的编程元素,如条件判断、(迭代)循环、变量;
      • jinja2:模板编程语言
        字面量:是常见的python对象
        字符串:一般使用单引号或双引号;
        数字:整数,浮点数;
        列表:使用[item1,tiem2,..],是可变的数据结构;
        元组:(item1,item2,...),是不可变的数据结构;
        字典:{key1:value1,key2:value2,...},就是键值对的组合;
        key一般为字符串所以要用引号;
        布尔型:true/false
        • 算术运算:
          +,-,,/,//只留商,%只留余数,*
          比较操作:
          ==,!=,>,>=,<,<=
          逻辑运算:
          and,or,not

    演示模板使用:使用ansible在二台主机上,安装nginx,提供配置文件,但其中的worker_processores的值要与主机的cpu核心数相同;此时,就可把配置文件基于模板方式提供,而这个worker_processores的值,放的是jinja2所支持的变量,直接使用变量的方式放在那个位置,而本机的template模块会自动套用这里面变量的值,给ansible facts所报告的结果,并把它生成在这个文件中,而后复制到目标主机上去;这就是模板的作用;

    示例:
    [root@localhost files]# ansible all -m yum --check -a "name=nginx state=latest"  #测试安装nginx
    [root@localhost files]# ansible all -m yum -a "name=nginx state=latest"   #安装nginx
    [root@localhost ~]# mkdir files
    [root@localhost ~]# cp /etc/nginx/nginx.conf /root/files/nginx.conf.j2
    [root@localhost files]# vim nginx.conf.j2
    修改:
    worker_processes {{ ansible_processor_vcpus }};
    
    [root@localhost files]# vim nginx.yaml
            - hosts: websrvs
              remote_user: root
              tasks:
              - name: Install nginx
                yum: name=nginx state=present
              - name: Install config file
                template: src=/root/files/nginx.conf.j2 dest=/etc/nginx/nginx.conf
                notify: restart nginx
              - name: start service
                service: name=nginx state=started
              handlers:
              - name: restart nginx
                service: name=nginx state=restarted
    
    [root@localhost files]# ansible-playbook  nginx.yaml --check
    [root@localhost files]# ansible-playbook  nginx.yaml 
    
    可使用主机变量,让不同主机监听不同端口:
    [root@localhost files]# vim /etc/ansible/hosts
    [websrvs]
    192.168.255.3 http_port=80 定义主机变量
    192.168.255.4 http_port=8080
    [root@localhost files]# vim nginx.conf.j2
    修改:
     listen       {{ http_port }}
     [root@localhost files]# ansible-playbook nginx.yaml --check
     [root@localhost files]# ansible-playbook nginx.yaml 
     
    条件测试:when示例
        ]# scp root@192.168.1.105:/etc/nginx/nginx.conf files/nginx.conf.c6.j2 复制一个centos6上的nginx配置文件;
        ]# vim files/nginx.conf.c6.j2
        worker_processes  {{ ansible_processor_vcpus }};
        
        ]# vim nginx.yaml
        - hosts: all
          remote_user: root
          tasks:
          - name: install nginx
            yum: name=nginx state=present
          - name: install conf file to c7
            template: src=files/nginx.conf.j2 dest=/etc/nginx/nginx.conf
            when: ansible_distribution_major_version == "7"
            notify: restart nginx
            tags: instconf
          - name: install conf file to c6
            template: src=files/nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
            when: ansible_distribution_major_version == "6"
            notify: restart nginx
            tags: instconf
          - name: start nginx service
            service: name=nginx state=started
          handlers: 
          - name: restart nginx
            service: name=nginx state=restarted
    
        示例:
        同时安装nginx、memcached、php-fpm等程序包,使用循环
        ]# vim iter.yaml
        - hosts: all
          remote_user: root
          tasks:
          - name: install some packages
            yum: name={{ item }} state=present
            with_items:
            - nginx
            - memcached
            - php-fpm
    

    1. role 角色
      有3组服务器web、db、ha都用到时间同步服务,当编写三个yaml文件分别适用于这3组服务器时,每个文件都要写一遍时间同步的功能;或另有一种情况,假如第一组服务器即是web又是db,第二组服务器只是db,第三组服务器只是web,此时要写yaml文件,如果要写一个db的,再写一行web的,还要写一个db和web合并的,如果还要memcached服务器,而有些在db上,有些在web上,在这种场景中,代码要在不同的主机角色间灵活组合,而这对于此前固化在yaml中的格式显然是不适用的;
      如果把每一种配置的定义的功能独立化,而且谁用到时谁去调用即可;这种可独立化的配置通常安照功能为基准进行划分的;如果服务器安装了某种功能就扮演成了某种角色;即把db功能的配置定义一个角色,web功能的配置定义一个角色,memcached功能配置定义一个角色等等;需要什么就事先定义好什么,放在特定目录下,
      当主机需要进行配置时,写一个yaml配置文件,在其里面指明用在哪个主机上、使用remote_user基于哪个运行、调用角色即可;
      这就是角色机制,是自包含的,为了让服务器能够调用其中的角色实现某种功能,所需要的一切代码、文件的集合都放在一个特定位置,这个组件就称为角色;
      角色的好处是跟主机是分离的,谁用谁调用;
      对于playbook而言,角色就是在playbook中所应该定义各种组件的集合;但此前是写在playbook一个文件中的,而如果要变成角色,要扮演成一个单独的目录;角色名就是目录名;
      每一个角色一般按固定格式定义,任何角色都不能引用自己目录以外的资源,这样把这个目录复制到任何主机上都可以用,这就是自包含应该指明file子目录;所有的模板放在templates子目录下;所有的任务放在tasks子目录下,所有的处理器放在handlers子目录下;所有变量放在vars子目录下;还有一个补充meta子目录;
      不是所有目录必须得有,一般是用到哪些目录,就给出哪些目录即可;这就是角色的目录组织形式;
      角色(role);/etc/ansible/roles也可在ansible.cfg中定义;
      一般为目录,每一个角色就是一个子目录;
    • 角色集合:
      roles/
      mysql/
      httpd/
      nginx/
      memcached/

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

    • 在playbook调用角色方法1:

            - hosts: websrvs
              remote_user: root
              roles:
              - mysql
              - memcached
              - nginx
      
    • 在playbook调用角色方法2:在角色调用时,传递变量给角色

            - hosts: 
              remote_user:
              roles:
              - { role: nginx, username: nginx }
             #键role用于指定角色名称,后续的k/v用于传递变量给角色;
      
           #还可以基于条件测试实现角色调用;
            roles:
            - { role: nginx, when: "ansible_distribution_major_version == '7'" }
      

    Ansible实现主/备模式高可用

    ansible主备高可用.png
    1. 安装ansible

      [root@localhost ~]# yum -y install ansible keepalive

    2. 编辑主机清单

        [root@localhost ~]# vim /etc/ansible/host
          [websrvs]
          192.168.1.115
          192.168.1.116 
          [hasrvs]
          192.168.1.10
          192.168.1.11
      
    3. 创建固定目录结构

      [root@localhost ~]# mkdir -pv /etc/ansible/roles/{keepalived,nginx}/{files,tasks,templates,handlers,vars,default,meta}
      [root@localhost ~]# tree /etc/ansible/roles/
         /etc/ansible/roles/
       ├── keepalived
       │   ├── default
       │   ├── files
       │   ├── handlers    
       │   ├── meta
       │   ├── tasks
       │   ├── templates
       │   └── vars
       └── nginx
           ├── default
           ├── files
           ├── handlers
           ├── meta
           ├── tasks
           │   └── main.yml
           ├── templates
           │   └── index.html.j2
           └── vars
      

    3 基于秘钥连接node1 node2 r1 r2

    [root@localhost ~]# ssh-keygen -t rsa -P ""
    [root@localhost ~]#  ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.10
    [root@localhost ~]#  ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.11
    [root@localhost ~]#  ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.115
    [root@localhost ~]#  ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.116
    

    4.编辑roles

       [root@localhost ~]#  vim /etc/ansible/roles/keepalived/tasks/main.yml
    #编辑如下内容     
            - name: install keepalived
              yum: name=keepalived state=latest
              when: ansible_os_family == "RedHat"
            - name: install conf
              template: src=kl.conf.j2 dest=/etc/keepalived/keepalived.conf
              tags: conf
              notify: restart keepalived
            - name: start keepalived
              service: name=keepalived state=started enabled=yes
    
        [root@localhost ~]# vim /etc/ansible/roles/keepalived/handlers/main.yml 
            - name: restart keepalived
              service: name=keedpalived state=restarted
    
    1. 编辑keepalived配置文件,并定义变量

       [root@localhost ~]# vim /etc/ansible/roles/keepalived/templates/kl.conf.j2 
       ! Configuration: command not found
       global_defs {
                  notification_email {
                   root@localhost
                  }
                   
              notification_email_from keepalived@localhost
              smtp_server 127.0.0.1
              smtp_connect_timeout 30
              router_id {{ ansible_fqdn }}
              vrrp_mcast_group4 224.1.105.33
           }
           
           vrrp_instance VI_1 {
               state {{ kl_status }}
               interface ens33
               virtual_router_id 33
               priority {{ kl_priority }}
               advert_int 1
               authentication {
                   auth_type PASS
                   auth_pass XXXX1111
               }
               virtual_ipaddress {
                   192.168.1.99 dev ens33 label ens33:0
               }
                notify_master "/etc/keepalived/notify.sh master"
                notify_backup "/etc/keepalived/notify.sh backup"
                notify_fault "/etc/keepalived/notify.sh fault"
           }
           virtual_server 192.168.1.99 80 {
               delay_loop 1
               lb_algo wrr
               lb_kind DR
               protocol TCP
               sorry_server 127.0.0.1 80
           
               real_server 192.168.1.115 80 {
                   weight 1
                   HTTP_GET {
                       url {
                           path /index.html
                           status_code 200
                           }
                       nb_get_retry 3
                       delay_before_retry 2
                       connect_timeout 3
                       }
               }
               real_server 192.168.1.116 80 {
                   weight 1
                   HTTP_GET {
                       url {
                           path /index.html
                           status_code 200
                           }
                       nb_get_retry 3
                       delay_before_retry 2
                       connect_timeout 3
                       }
               }
                   
       }
      
       [root@localhost files]# vim /etc/ansible/hosts 
       [hasrvs]
       192.168.1.10 kl_status=MASTER kl_priority=100
       192.168.1.11 kl_status=BACKUP kl_priority=96
      
    2. 配置nginx的roles

      [root@localhost files]# vim /etc/ansible/roles/nginx/tasks/main.yml
       - name: Install nginx
         yum: name=nginx state=latest
       - name: Install conf
         template: src=index.html.j2 dest=/usr/share/nginx/html/index.html
         notify: reload nginx
       - name: start script
         script: /root/files/setkl.sh start
         notify: reload nginx
       - name: start nginx
         service: name=nginx state=started
       
         [root@localhost files]# vim /etc/ansible/roles/nginx/templates/index.html.j2  
           <h1> {{ ansible_fqdn }} </h1>
           
         [root@localhost files]# vim /etc/ansible/roles/nginx/handlers/main.yml
           - name: reload nginx
             service: name=nginx state=reload
      

    7 .编辑keepalived和nginx的playbook

    [root@localhost ~]# cd files
    [root@localhost files]# vim kl.yml
        - hosts: hasrvs
          remote_user: root
          roles:
          - keepalived
    [root@localhost files]# vim nginx.yml
        - hosts: websrvs
          remote_user: root
          roles:
          - nginx
    
    1. 测试并执行

      [root@localhost files]# ansible-playbook --check kl.yml
      [root@localhost files]# ansible-playbook --check kl.yml
      [root@localhost files]# ansible-playbook --check nginx.yml
      [root@localhost files]# ansible-playbook nginx.yml
      
    2. 访问测试

       [root@localhost files]# curl http://192.168.1.99
       <h1> rs1.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs2.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs1.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs2.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs1.ilinux.com </h1>
      
       node1:规则已生成
       [root@node1 ~]# ipvsadm -ln
       IP Virtual Server version 1.2.1 (size=4096)
       Prot LocalAddress:Port Scheduler Flags
         -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
       TCP  192.168.1.99:80 wrr
         -> 192.168.1.115:80             Route   1      0          3         
         -> 192.168.1.116:80             Route   1      0          2    
      [root@node1 ~]# ifconfig
      ens33: ...   
      ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
           inet 192.168.1.99  netmask 255.255.255.255  broadcast 0.0.0.0
           ether 00:0c:29:6d:e2:f7  txqueuelen 1000  (Ethernet)
           
      
      [root@node1 ~]# systemctl stop keepalived.service  
      
      node2:
      [root@node2 ~]# ipvsadm -ln
      IP Virtual Server version 1.2.1 (size=4096)
      Prot LocalAddress:Port Scheduler Flags
        -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
      TCP  192.168.1.99:80 wrr
        -> 192.168.1.115:80             Route   1      0          0         
        -> 192.168.1.116:80             Route   1      0          0      
      
      #使用客户端访问:
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs2.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs1.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs2.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs1.ilinux.com </h1>
       [root@localhost files]# curl http://192.168.1.99
       <h1> rs2.ilinux.com </h1>
      

    相关文章

      网友评论

          本文标题:Ansible&实现主/备模式高可用

          本文链接:https://www.haomeiwen.com/subject/uzhegftx.html