• Ansible 基础


    一、介绍

    Ansible 一种集成 IT 系统的配置管理、应用部署、执行特定任务的开源平台,是 AnsibleWorks 公司名下的项目,该公司由 Cobbler 及 Func 的作者于 2012 年创建成立。

    Ansible 基于 Python 语言实现,由 Paramiko 和 PyYAML 两个关键模块构建。

    Ansible 特点:

    >> 部署简单,只需在主控端部署 Ansible 环境,被控端无需做任何操作。
    >> 默认使用 SSH(Secure Shell)协议对设备进行管理。
    >> 主从集中化管理。
    >> 配置简单、功能强大、扩展性强。
    >> 支持 API 及自定义模块,可通过 Python 轻松扩展。
    >> 通过 Playbooks 来定制强大的配置、状态管理。
    >> 对云计算平台、大数据都有很好的支持。

    二、Ansible的安装
    Ansible只需在管理端部署环境即可,默认通过yum安装即可。

    yum install ansible -y
     

    2.1 Ansible配置及测试

        第一步是修改主机与组配置,文件位置/etc/ansible/hosts,格式为ini,添加两台主机ip,同时定义两个IP到webservers组,更新的内容如下:

    【/etc/ansible/hosts】
    [webservers]         #组名 websevers
    ## alpha.example.org
    ## beta.example.org
    172.31.101.51         #主机1    
    172.31.101.52         #主机2
     

      通过ping模块测试主机的连通性,分别对单主机及组进行ping操作

     ansible 172.31.101.52 -m ping -k  #单个主机
     ansible webservers -m ping -k     #单个组
     

    测试主机连通性如下图所示

    image.png

    由于主控端与被控端主机未配置ssh证书信任,需要执行ansible命令添加-k参数,要求提供root(默认)帐号密码,即提示“SSH password:”时输入

    ping模块参数说明

    # -i          指定 hosts 文件位置
    # -u username 指定 SSH 连接的用户名
    # -k          指定远程用户密码
    # -f          指定并发数
    # -s          如需要 root 权限执行时使用 ( 连接用户不是 root 时 )
    # -K          -s 时,-K 输入 root 密码
     

    2.2 配置linux主机ssh无密码访问

        为了避免Ansible下发指令时输入目标主机密码,可以通过证书签名达到ssh无密码访问。

        在主控端创建密钥,执行ssh-keygen -t rsa

    [root@rbtnode1 ~]# ssh-keygen -t rsa              
    Generating public/private rsa key pair.
    Enter file in which to save the key (/root/.ssh/id_rsa): (回车)
    Enter passphrase (empty for no passphrase):                   (回车)
    Enter same passphrase again:                                     (回车)
    Your identification has been saved in /root/.ssh/id_rsa.
    Your public key has been saved in /root/.ssh/id_rsa.pub.
    The key fingerprint is:
    8b:8a:91:2e:04:2e:dd:4d:99:c0:e9:f0:5f:f9:85:bb root@rbtnode1
    The key's randomart image is:
    +--[ RSA 2048]----+
    |   . .           |
    |  . +            |
    |   + . o . .     |
    |.   o + o . .    |
    |o. . + .S. o     |
    |.o... o. .o      |
    |o o   . .  .     |
    |.. o .    E      |
    | .o .            |
    +-----------------+
     

        接下来同步公钥文件id_rsa.pub到目标主机,使用ssh-copy-id公钥拷贝工具,命令格式为/usr/bin/ssh-copy-id [-i[identity-file]][user@]machine

    ssh-copy-id -i /root/.ssh//id_rsa.pub root@172.31.101.51
    ssh-copy-id -i /root/.ssh//id_rsa.pub root@172.31.101.52
     

    image.png

    2.3 定义主机与组规则

        Ansible通过定义好的主机与组规则(Inventory)对匹配的目标主机进行远程操作,配置规则文件默认是/etc/ansible/hosts,以下为举例说明:

    www.abc.com     # 定义域名
    192.168.1.100   # 定义 IP
    192.168.1.150:37268   # 指定端口号
    [WebServer]           # 定义分组
    192.168.1.10
    192.168.1.20
    192.168.1.30
    [DBServer]            # 定义多个分组
    192.168.1.50
    192.168.1.60
    Monitor ansible_ssh_port=12378 ansible_ssh_host=192.168.1.200   # 定义别名
    # ansible_ssh_host 连接目标主机的地址
    # ansible_ssh_port 连接目标主机的端口,默认 22 时无需指定
    # ansible_ssh_user 连接目标主机默认用户
    # ansible_ssh_pass 连接目标主机默认用户密码
    # ansible_ssh_connection 目标主机连接类型,可以是 local 、ssh 或 paramiko
    # ansible_ssh_private_key_file 连接目标主机的 ssh 私钥
    # ansible_*_interpreter 指定采用非 Python 的其他脚本语言,如 Ruby 、Perl 或其他类似 ansible_python_interpreter 解释器
    [webservers]         # 主机名支持正则描述
    www[01:50].example.com
    [dbservers]
    db-[a:f].example.com
     

    2.4 目标匹配

        目标匹配,格式为ansible <pattern_goes_here> -m <module_name> -a <arguments> 举例说明:重启webservers组的所有Apache服务

    ansible webservers -m service -a "name=httpd state=restarted"
     
    规则 含义
    192.198.1.2或one.example.com 匹配目标Ip地址或者主机名,多个ip或主机名使用":"号分隔
    webservers 匹配目标组为webserver,多个组使用":"号分隔
    ALL 或 ‘*’ 匹配目标所有主机
    ~(web|db).*.example.com 或 192.168.1.* 支持正则表达式匹配所有主机或ip地址
    webservers:!192.168.1.22 匹配websevers组且排除192.168.1.22主机ip
    webservers:&dbservers 匹配webservers与dbservers两个群组的交集
    webservers:!{{excluded}}:&{{required}} 支持变量匹配的方式

    2.5查询支持模块及模块说明
    ansible-doc -l    # 列出 Ansible 支持的模块
    ansible-doc ping  # 查看该模块帮助信息
     

    三、常用模块及api

    3.1远程命令模块

        模块包括command、script、shell都可以实现远程shell命令运行。command作为Ansible的默认模块,可以运行远程权限范围内所有的shell命令;script功能是在远程主机上执行主控端存储shell脚本文件,相当于scp+shell组合;shell功能是执行远程主机的shell脚本文件

    ansible webservers -m command -a "free -m"   
    ansible webservers -m script -a "/home/test.sh 12 34"
    ansible webservers -m shell -a "/home/test.sh"
     

    image.png

    3.2copy模块

        实现主控端向目标主机拷贝文件,类似于scp的功能。以下示例实现拷贝/root/pip-10.0.1.tar.gz 文件到webserver组目标主机/tmp/目录下,并更新文件属主及权限

    # ansible webservers -m copy -a "src=/root/pip-10.0.1.tar.gz dest=/tmp/ owner=root group=root mode=0755"
     

    image.png

    3.3 stat模块

        获取远程文件的状态信息,包括atime ,ctime ,md5等信息

    ansible webservers -m stat -a "path=/tmp/pip-10.0.1.tar.gz"
     

    image.png

    4.4 get_url模块

        实现在远程主机下载指定URL到本地,支持sha256sum文件校验

    ansible webservers -m get_url -a  "url=http://www.baidu.com dest=/tmp/index.html mode=0440 force=yes"
     

    image.png

    4.5 yum模块

        linux平台软件包管理操作,常见有yum,apt管理方式

    ansible webservers -m yum -a "name=wget state=latest
     

    image.png

    4.6 cron模块

        远程主机crontab配置

     ansible webservers -m cron -a "name='check dirs' hour='5,2' job='ls -alh > /dev/null'"
     

    image.png

    在远程主机查看计划任务

    image.png

    4.7 mount模块

        远程主机的分区挂载

    ansible webservers -m mount -a "name=/mnt/date src=fstype=exts opts=ro state=present"
     

    4.8 service模块

    远程主机系统服务管理

    ansible webservers -m service -a "name=firewalld state=stopped"
    ansible webservers -m service -a "name=firewalld state=started"
    ansible webservers -m service -a "name=firewalld state="restartd"
    ansible webservers -m service -a "name=firewalld state=reloded"
     

    image.png

    4.8 user服务模块

        远程主机系统用户管理

    ansible webservers -m user -a "name=yangchao comment='yangchao'" #增加用户
    ansible webservers -m user -a "name=yangchao state=absent remove=yes" #删除用户
     

    image.png

    关于ansible其他模块及详细用法,请参照

    http://www.ansible.com.cn/docs/modules_intro.html






    ansible.py
    技术分享图片
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import os
    import tempfile
    from collections import namedtuple
    from ansible.parsing.dataloader import DataLoader
    from ansible.vars.manager import VariableManager
    from ansible.inventory.manager import InventoryManager
    from ansible.playbook.play import Play
    from ansible.executor.playbook_executor import PlaybookExecutor
    from ansible.executor.task_queue_manager import TaskQueueManager
    from ansible.plugins.callback import CallbackBase
    
    
    class AnsibleHost:
        def __init__(self, host, port=None, connection=None, ssh_user=None, ssh_pass=None):
            self.host = host
            self.port = port
            self.ansible_connection = connection
            self.ansible_ssh_user = ssh_user
            self.ansible_ssh_pass = ssh_pass
    
        def __str__(self):
            result = ‘ansible_ssh_host=‘ + str(self.host)
            if self.port:
                result += ‘ ansible_ssh_port=‘ + str(self.port)
            if self.ansible_connection:
                result += ‘ ansible_connection=‘ + str(self.ansible_connection)
            if self.ansible_ssh_user:
                result += ‘ ansible_ssh_user=‘ + str(self.ansible_ssh_user)
            if self.ansible_ssh_pass:
                result += ‘ ansible_ssh_pass=‘ + str(self.ansible_ssh_pass)
            return result
    
    
    class AnsibleTaskResultCallback(CallbackBase):
        def __init__(self, display=None, option=None):
            super().__init__(display, option)
            self.result = None
            self.error_msg = None
    
        def v2_runner_on_ok(self, result):
            res = getattr(result, ‘_result‘)
            self.result = res
            self.error_msg = res.get(‘stderr‘)
    
        def v2_runner_on_failed(self, result, ignore_errors=None):
            if ignore_errors:
                return
            res = getattr(result, ‘_result‘)
            self.error_msg = res.get(‘stderr‘, ‘‘) + res.get(‘msg‘)
    
        def runner_on_unreachable(self, host, result):
            if result.get(‘unreachable‘):
                self.error_msg = host + ‘:‘ + result.get(‘msg‘, ‘‘)
    
        def v2_runner_item_on_failed(self, result):
            res = getattr(result, ‘_result‘)
            self.error_msg = res.get(‘stderr‘, ‘‘) + res.get(‘msg‘)
    
    
    class AnsibleTask:
        def __init__(self, hosts, extra_vars=None):
            self.hosts = hosts
            self._validate()
            self.hosts_file = None
            self._generate_hosts_file()
            Options = namedtuple(‘Options‘,
                                 [‘connection‘, ‘module_path‘, ‘forks‘, ‘become‘, ‘become_method‘, ‘become_user‘, ‘check‘,
                                  ‘diff‘, ‘host_key_checking‘, ‘listhosts‘, ‘listtasks‘, ‘listtags‘, ‘syntax‘])
    
            self.options = Options(connection=‘ssh‘, module_path=None, forks=10,
                                   become=None, become_method=None, become_user=None, check=False, diff=False,
                                   host_key_checking=False, listhosts=None, listtasks=None, listtags=None, syntax=None)
            self.loader = DataLoader()
            self.passwords = dict(vault_pass=‘secret‘)
    
            self.inventory = InventoryManager(loader=self.loader, sources=[self.hosts_file])
            self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory)
            if extra_vars:
                self.variable_manager.extra_vars = extra_vars
    
        def _generate_hosts_file(self):
            self.hosts_file = tempfile.mktemp()
            with open(self.hosts_file, ‘w+‘, encoding=‘utf-8‘) as file:
                hosts = []
                i_temp = 0
                for host in self.hosts:
                    hosts.append(‘server‘ + str(i_temp) + ‘ ‘ + str(host))
                    i_temp += 1
                file.write(‘
    ‘.join(hosts))
    
        def _validate(self):
            if not self.hosts:
                raise Exception(‘hosts不能为空‘)
            if not isinstance(self.hosts, list):
                raise Exception(‘hosts只能为list<AnsibleHost>数组‘)
            for host in self.hosts:
                if not isinstance(host, AnsibleHost):
                    raise Exception(‘host类型必须为AnsibleHost‘)
    
        def exec_shell(self, command):
            source = {‘hosts‘: ‘all‘, ‘gather_facts‘: ‘no‘, ‘tasks‘: [
                {‘action‘: {‘module‘: ‘shell‘, ‘args‘: command}, ‘register‘: ‘shell_out‘}]}
            play = Play().load(source, variable_manager=self.variable_manager, loader=self.loader)
            results_callback = AnsibleTaskResultCallback()
            tqm = None
            try:
                tqm = TaskQueueManager(
                    inventory=self.inventory,
                    variable_manager=self.variable_manager,
                    loader=self.loader,
                    options=self.options,
                    passwords=self.passwords,
                    stdout_callback=results_callback
                )
                tqm.run(play)
                if results_callback.error_msg:
                    raise Exception(results_callback.error_msg)
                return results_callback.result
            except:
                raise
            finally:
                if tqm is not None:
                    tqm.cleanup()
    
        def exec_playbook(self, playbooks):
            results_callback = AnsibleTaskResultCallback()
            playbook = PlaybookExecutor(playbooks=playbooks, inventory=self.inventory,
                                        variable_manager=self.variable_manager,
                                        loader=self.loader, options=self.options, passwords=self.passwords)
            setattr(getattr(playbook, ‘_tqm‘), ‘_stdout_callback‘, results_callback)
            playbook.run()
            if results_callback.error_msg:
                raise Exception(results_callback.error_msg)
            return results_callback.result
    
        def __del__(self):
            if self.hosts_file:
                os.remove(self.hosts_file)
    View Code

    test.py
    技术分享图片
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    from ansible import AnsibleTask, AnsibleHost
    
    if __name__ == "__main__":
        task = AnsibleTask([AnsibleHost(‘127.0.0.1‘, 22, ‘ssh‘, ‘root‘, ‘password)])
        task.exec_playbook([‘/install.yml‘, ‘init.yml‘])
        task.exec_shell(‘echo "abc"‘))
    View Code
     
  • 相关阅读:
    Windows 服务程序(一)
    API---注册表编程
    API---文件操作
    main(argc, char *argv[])
    C 自删除技术---批处理方式
    分治法排序
    TDD尝试:nodejs单元测试
    尝试create tech team
    Yum重装走过的坑
    求生欲很强的数据库
  • 原文地址:https://www.cnblogs.com/hanzeng1993/p/13427923.html
Copyright © 2020-2023  润新知