Ansible
常用自动化运维工具 Ansible:python,Agentless,中小型应用环境 Saltstack:python,一般需部署agent,执行效率更高 Puppet:ruby, 功能强大,配置复杂,重型,适合大型环境 Fabric:python,agentless Chef:ruby,国内应用少 Cfengine func Ansible:特性 模块化:调用特定的模块,完成特定任务 有Paramiko,PyYAML,Jinja2(模板语言)三个关键模块 支持自定义模块 基于Python语言实现 部署简单,基于python和SSH(默认已安装),agentless 安全,基于OpenSSH 支持playbook编排任务 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况 无需代理不依赖PKI(无需ssl) 可使用任何编程语言写模块 YAML格式,编排任务,支持丰富的数据结构 较强大的多层解决方案 Ansible主要组成部分 playbooks:任务剧本(任务集),编排定义ansible任务集的配置文件,由ansible顺序依次执行,通常是json格式的yml文件 inventory:ansible管理主机的清单/etc/anaible/hosts modules: ansible执行命令的功能模块,多数为内置核心模块,也可自定义 plugins: 模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用 api: 供第三方程序调用的应用程序编程接口 ansible: 组合inventory、api、modules、plugins的绿框,可以理解为是ansible命令工具,其为核心执行工具 Ansible命令执行来源: user,普通用户,即system administrator cmdb(配置管理数据库) api 调用 public/private cloud api调用 user-> ansible playbook -> ansibile 利用ansible实现管理的方式: Ad-Hoc 即ansible命令,主要用于临时命令使用场景 Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有前期的规划过程 Ansible-playbook(剧本)执行过程 将已有编排好的任务集写入Ansible-Playbook 通过ansible-playbook命令分拆任务集至逐条ansible命令,按预定规则逐条执行 Ansible主要操作对象 hosts主机 networking网络设备 注意事项 执行ansible的主机一般称为主控端,中控,master或堡垒机 主控端Python版本需要2.6或以上 被控端Python版本小于2.4需要安装python-simplejson 被控端如开启SELinux需要安装libselinux-python windows不能做为主控端 ansible命令执行过程 1. 加载自己的配置文件 默认/etc/ansible/ansible.cfg 2. 加载自己对应的模块文件,如command 3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件(配置文件中定义了) 4. 给文件+x执行 5. 执行并返回结果 6. 删除临时py文件,退出 执行状态: 绿色:执行成功并且不需要做改变的操作 黄色:执行成功并且对目标主机做变更 红色:执行失败 ----------------------------------------------------------------------------------------------------------- 安装方法 1.rpm包安装: EPEL源 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo yum install ansible 2.编译安装: yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto tar xf ansible-1.5.4.tar.gz cd ansible-1.5.4 python setup.py build python setup.py install mkdir /etc/ansible cp -r examples/* /etc/ansible 3.git方式: git clone git://github.com/ansible/ansible.git --recursive cd ./ansible source ./hacking/env-setup 4.pip安装: pip是安装Python包的管理器,类似yum yum install python-pip python-devel yum install gcc glibc-devel zibl-devel rpm-bulid openssl-devel pip install --upgrade pip pip install ansible --upgrade ----------------------------------------------------------------------------------------------------------- 配置文件 /etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性 /etc/ansible/hosts 主机清单 /etc/ansible/roles/ 存放角色的目录 程序 /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 配置文件/etc/ansible/ansible.cfg (一般保持默认) [defaults] #inventory = /etc/ansible/hosts # 主机列表配置文件 #library = /usr/share/my_modules/ # 库文件存放目录 #remote_tmp = $HOME/.ansible/tmp #临时py命令文件存放在远程主机目录 #local_tmp = $HOME/.ansible/tmp # 本机的临时命令执行目录 #forks = 5 # 默认并发数 #sudo_user = root # 默认sudo 用户 #ask_sudo_pass = True #每次执行ansible命令是否询问ssh密码 #ask_pass = True #remote_port = 22 #host_key_checking = False # 检查对应服务器的host_key,建议取消注释,提示输入yes/no. #log_path=/var/log/ansible.log #日志文件 #module_name = command #默认模块 Ansible 配置文件/etc/ansible/hosts 主机清单inventory ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名 默认的inventory file为/etc/ansible/hosts inventory file可以有多个,且也可以通过Dynamic Inventory来动态生成 inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中;此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明 /etc/ansible/hosts文件格式 www.magedu.com 192.168.80.100 [webservers] www1.magedu.com:2222 www2.magedu.com [websrvs] # 如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机 www[1:100].example.com [dbsrvs] db-[a:f].example.com ------------------------------------------------------------------------------------------------------------------------- Ansible程序命令 ansible 、ansible-doc 、ansible-playbook、ansible-vault 、ansible-console 、ansible-galaxy 、ansible-pull ansible-doc: 显示模块帮助 ansible-doc [options] [module...] -a 显示所有模块的文档 -l, --list 列出可用模块 -s, --snippet显示指定模块的playbook片段 示例: ansible-doc -l 列出所有模块 ansible-doc ping 查看指定模块帮助用法 ansible-doc -s ping 查看指定模块帮助用法 ------------------------------------------------------------------------------------------------------------------------------ ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible端能基于密钥认证的方式联系各被管理节点 ansible <host-pattern> [-m module_name] [-a args] --version 显示版本 -m module 指定模块,默认为command,在配置文件中可以设置module_name 项 -v 详细过程 –vv -vvv更详细 -a 指定执行模块使用的参数 --list-hosts 显示主机列表,可简写 --list(基于密码连接的基本不用,因为每台服务器密码不一样,) -C, --check 检查,并不执行 -T, --timeout=TIMEOUT 执行命令的超时时间,默认10s -u, --user=REMOTE_USER 执行远程执行的用户(默认当前用户) -b, --become 代替旧版的sudo 切换 (使用少,还要设置sudo配置文件) --become-user=USERNAME 指定sudo的runas用户,默认为root -K, --ask-become-pass 提示输入sudo时的口令 -t TREE, --tree=TREE #将日志内容保存在该输出目录,结果保存在一个文件中在每台主机上 {ansible的Host-pattern匹配主机的列表 All :表示所有Inventory中的所有主机 ansible all –m ping * :通配符 ansible “*” -m ping ansible 192.168.1.* -m ping ansible “*srvs” -m ping 或关系 ansible “websrvs:appsrvs” -m ping ansible “192.168.1.10:192.168.1.20” -m ping 逻辑与 ansible “websrvs:&dbsrvs” –m ping 在websrvs组并且在dbsrvs组中的主机 逻辑非 ansible ‘websrvs:!dbsrvs’ –m ping 在websrvs组,但不在dbsrvs组中的主机 注意:此处为单引号 综合逻辑 ansible ‘websrvs:dbsrvs:&appsrvs:!ftpsrvs’ –m ping 正则表达式 ansible “websrvs:&dbsrvs” –m ping ansible “~(web|db).*\.magedu\.com” –m ping } 示例 以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-galaxy 连接 https://galaxy.ansible.com 下载相应的roles ansible-galaxy install geerlingguy.ntp 列出所有已安装的galaxy ansible-galaxy list 安装galaxy ansible-galaxy install geerlingguy.redis 删除galaxy ansible-galaxy remove geerlingguy.redis ------------------------------------------------------------------------------------------------------------------------------ ansible-pull 推送命令至远程,效率无限提升,对运维要求较高 ------------------------------------------------------------------------------------------------------------------------------ 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: 2.0+新增,可交互执行命令,支持tab root@test (2)[f:10] $ 执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$ 设置并发数: forks n 例如: forks 10 切换组: cd 主机组 例如: cd all 列出当前组主机列表: list 列出所有的内置命令: ?或help 示例: root@all (2)[f:5]$ list root@all (2)[f:5]$ cd appsrvs root@appsrvs (2)[f:5]$ list root@appsrvs (2)[f:5]$ yum name=httpd state=present root@appsrvs (2)[f:5]$ service name=httpd state=started ------------------------------------------------------------------------------------------------------------------------------ ansible-playbook playbook是由一个或多个“play”组成的列表(-) play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作 Playbook采用YAML语言编写Yet Another Markup Language"(仍是一种标记语言) 特性 YAML的可读性好 YAML和脚本语言的交互性好 YAML使用实现语言的数据类型 YAML有一个一致的信息模型 YAML易于实现 YAML可以基于流来处理 YAML表达能力强,扩展性好 YAML语法说明 在单一档案中,可用连续三个连字号(——)区分多个档案。另外,还有选择性的连续三个点号( ... )用来表示档案结尾 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能 使用#号注释代码 缩进必须是统一的,不能空格和tab混用 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的 YAML文件内容是区别大小写的,k/v(键值)的值均需大小写敏感 多个k/v(键值)可同行写也可换行写,同行使用,分隔 v(值)可是个字符串,也可是另一个列表 一个完整的代码块功能需最少元素需包括 name 和 task 一个name只能包括一个task YAML文件扩展名通常为yml或yaml Dictionary:字典,通常由多个key与value构成(调用方法:item.name、item.job) name: Example Developer job: Developer skill: Elite 也可以将key:value放置于{}中进行表示,用,分隔多个key:value {name: Example Developer, job: Developer, skill: Elite} YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔 name: John Smith age: 41 gender: 男 spouse: name: Jane Smith age: 37 gender: 女 children: - name: Jimmy Smith age: 17 gender: Male - name: Jenny Smith age 13 gender: Female Playbook核心元素 Hosts 执行的远程主机列表 Tasks 任务集 Variables 内置变量或自定义变量在playbook中调用 Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件 Handlers 和 notity 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行 remote_user 执行或运行的用户,可用于Host和task中,也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户 tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。 此时,如果确信其没有变化,就可以通过tags跳过此些代码片断。ansible-playbook -t tagsname useradd.yml Hosts playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中 可以是如下形式: one.example.com one.example.com:two.example.com 192.168.1.50 192.168.1.* Websrvs:dbsrvs 或者,两个组的并集 Websrvs:&dbsrvs 与,两个组的交集 webservers:!phoenix 在websrvs组,但不在dbsrvs组 示例: - hosts: websrvs:dbsrvs remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户 - hosts: websrvs remote_user: root 默认选项 tasks: - name: test connection ping: 下面三行表示使用 magedu连接,后使用sudo切换,切换到wang,需要sudo配置文件配置。 remote_user: magedu sudo: yes 默认sudo为root sudo_user:wang sudo为wang task列表和action play的主体部分是task list,task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后,再开始第二个任务 task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致 每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出 tasks:任务列表 两种格式: (1) action: module arguments (2) module: arguments 建议使用 注意:shell和command模块后面跟命令,而非key=value 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers 任务可以通过"tags“打标签,可在ansible-playbook命令上使用-t指定进行调用 示例: tasks: - name: disable selinux command: /sbin/setenforce 0 shell和command,如果命令或脚本的退出码不为零,可以使用如下方式替代 tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand || /bin/true 或者使用ignore_errors来忽略错误信息 tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand ignore_errors: True Handlers 是task列表,与tasks同级,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作 Notify此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。 在notify中列出的操作称为handler,也即notify中调用handler中定义的操作 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 #上面配置文件发生变化,notify 调用handler中定义的操作 - name: ensure apache is running service: name=httpd state=started enabled=yes handlers: - name: restart httpd service: name=httpd state=restarted tags: ansible中可以对play、role、include、task打一个tag(标签) 当命令ansible-playbook有-t参数时,只会执行-t指定的tag 当命令ansible-playbook有--skip-tags参数时,则除了--skip-tags指定的tag外,执行其他所有 定义在name中的标签,可以单独执行标签部分的代码。ansible-playbook –t service httpd.yml - name: start httpd service tags: service service: name=httpd state=started enabled=yes ansible-playbook命令说明 ansible-playbook <filename.yml> ... [options] 常见选项 --check -C 只检测可能会发生的改变,但不真正执行操作 --list-hosts 列出运行任务的主机 --list-tags 列出tag标签 --list-tasks 列出task --limit 主机列表 只针对主机列表中的主机执行 -v -vv -vvv 显示过程 -t 执行带”标签“部分的playbook --skip-tags 跳过本tag,执行其他 示例 ansible-playbook file.yml --check 只检测 ansible-playbook file.yml ansible-playbook file.yml --limit websrvs ansible-playbook格式: --- - hosts:all remote_user:root tasks: - name: ping notify: 调用handlers:中的name - name: shell: 模块 tags: 标签 handlers: - name: restart httpd service: name=httpd state=restarted --------------------------------------------------------------------------------------------------------- 实例一,Centos7安装httpd --- - hosts: appsrvs remote_user: root tasks: - name: install yum: name=httpd - name: config copy: src=/data/playbook/httpd.conf dest=/etc/httpd/conf/ notify: restart httpd - name: service service: name=httpd state=started enabled=yes handlers: - name: restart httpd service: name=httpd state=restarted 注意:/data/playbook/httpd.conf已设置好,也可以省略这步,对httpd.conf使用shell或command模块更改配置。 主控和客户端都是Centos7,客户端是Centos6实验失败,因为6与7的版本配置文件不一样。 --------------------------------------------------------------------------------------------------------- 实例二,安装二进制mysql --- - hosts: appsrvs remote_user: root tasks: - name: 1 user: name=mysql system=yes home=/data/mysql create_home=no shell=/sbin/nologin - name: 2 unarchive: src=/data/playbook/mariadb-10.2.32-linux-x86_64.tar.gz dest=/usr/local/ owner=root group=root #src的文件已在ansible控制端中 - name: 3 file: src=/usr/local/mariadb-10.2.32-linux-x86_64 dest=/usr/local/mysql state=link - name: 4 file: path=/data/mysql state=directory - name: 5 file: path=/data/mysql owner=mysql group=mysql - name: 6 shell: chdir=/usr/local/mysql/ scripts/mysql_install_db --datadir=/data/mysql --user=mysql - name: 7 copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh - name: 8 copy: src=/data/playbook/my-huge.cnf dest=/etc/my.cnf #src的文件已在ansible控制端中,并设置{mysqld]数据库路径 datadir=/data/mysql - name: 9 shell: cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld - name: 10 shell: /etc/init.d/mysqld start --------------------------------------------------------------------------------------------------------- 实例三,安装nginx - hosts: websrvs remote_user: root tasks: - name: add group nginx tags: user #标签 gruop: 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 #nginx是否运行。 ======================================================================================= Playbook中变量使用 变量名: 仅能由字母、数字和下划线组成,且只能以字母开头 变量定义:key=value 如:http_port=80 变量调用方式: 1.在playbook文件中通过{{ variable_name }} 调用变量,且变量名前后必须有空格,有时用 “{{ variable_name }}”才生效。 2.ansible-playbook –e 选项指定 ansible-playbook test.yml -e "hosts=www user=magedu" 变量优先级 命令行(命令中-e)最优先、 playbook中定义vars、 inventory 主机清单中hosts 、 系统的 ”setup模块“ facts 变量 角色role定义的默认变量(roles/rolesname/defaults/main.yml) 定义和调用变量方式: 1 ansible ”setup模块“ 远程主机的所有变量都可直接调用,也是ansble内部的变量。 例子:ansible all -m setup -a 'filter=ansible_memtotal_mb' 例子:tasks: - name: create log file file: name=/var/log/{{ ansible_fqdn }} state=touch 2 在/etc/ansible/hosts中定义 普通变量:主机组中主机单独定义,优先级高于公共变量 公共(组)变量:针对主机组中所有主机定义统一变量 [websrvs] www1.magedu.com http_port=80 maxRequestsPerChild=808 www2.magedu.com http_port=8080 maxRequestsPerChild=909 192.168.99.101 http_port=8080 hname=www [websrvs:vars]#公共(组)变量,vars为关键字。 ntp_server=ntp.magedu.com suf=txt 3 通过命令行指定变量,优先级最高 ansible-playbook –e varname=value xxx.yml 例子:tasks: - name: install package yum: name={{ pkname }} state=present ansible-playbook –e pkname=httpd var.yml 4 在playbook中定义,vars为关键字。 vars: - var1: value1 - var2: value2 例子: vars: - username: user1 - groupname: group1 tasks: - name: create group group: name={{ groupname }} state=present - name: create user user: name={{ username }} state=present 5 在独立的变量YAML文件中定义 cat vars.yml var1: httpd var2: nginx vim xxx.yml - hosts: web remote_user: root vars_files: vars.yml #调用独立的变量文件。 6 在role中定义。 roles: - { role: nginx, K: V , when: ansible_distribution_major_version == ‘7’ } ========================================================================================== 模板template 文本文件,嵌套有脚本(使用模板编程语言编写) Jinja2语言,使用字面量,有下面形式 字符串:使用单引号或双引号 数字:整数,浮点数 列表:[item1, item2, ...] 元组:(item1, item2, ...) 只读 字典:{key1:value1, key2:value2, ...} 布尔型:true/false 算术运算:+, -, *, /, //, %, ** 比较操作:==, !=, >, >=, <, <= 逻辑运算:and,or,not 流表达式:For,If,When template功能:根据模块文件动态生成对应的配置文件 template文件必须存放于templates目录下,且命名为 .j2 结尾 yaml/yml 文件需和templates目录平级,目录结构如下: ./ ├── temnginx.yml └── templates └── nginx.conf.j2 例子: [root@localhost7A playbook]# tree ├── mariadb.yml └── templates └── httpd.conf.j2 [root@localhost7A playbook]# cat templates/httpd.conf.j2 模版中使用变量 Listen {{ httpd_port }} [root@localhost7A playbook]# cat /etc/ansible/hosts #主机清单中申明变量 192.168.80.120 httpd_port=8017 192.168.80.120 httpd_port=8027 [root@localhost7A playbook]# cat httpd.yml --- - hosts: appserv remote_user: root tasks: - name: install yum: name=httpd - name: config template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf #templates调用模版。 - name: service service: name=httpd state=started enabled=yes when 条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法 格式 when语句 在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法 如: cat httpd.yml --- - hosts: appserv remote_user: root tasks: - name: install yum: name=httpd - name: config template: src=httpd6.conf.j2 dest=/etc/httpd/conf/httpd.conf when: ansible_distribution_major_version=="6" #此变量为setup模块变量,判断变量值确定是否要运行本段name。 - name: config template: src=httpd7.conf.j2 dest=/etc/httpd/conf/httpd.conf #相对路径,yml 文件需和templates目录平级 when: ansible_distribution_major_version=="7" - name: server service: name=httpd state=started enabled=yes 迭代(循环):(循环)with_items 迭代:当有需要重复性执行的任务时,可以使用迭代机制 对迭代项的引用,固定变量名为”item“ 要在task中使用with_items给定要迭代的元素列表 列表格式: 字符串 字典 示例: - name: add several users user: name={{ item }} state=present groups=wheel #user: name=testuser1 state=present groups=wheel with_items: - user1 - user2 - name: Create rsyncd config copy: src={{ item }} dest=/etc/{{ item }} with_items: - rsyncd.secrets - rsyncd.conf - name: install some packages yum: name={{ item }} state=present with_items: - nginx - memcached - php-fpm 迭代(循环)嵌套子变量 - hosts:websrvs remote_user: root tasks: - name: add some groups group: name={{ item }} state=present with_items: - group_a - group_b - group_c - name: add some users user: name={{ item.name }} group={{ item.group }} state=present with_items: - { name: 'user1', group: 'group_a' } #字典 - { name: 'user2', group: 'group_b' } - { name: 'user3', group: 'group_c' } Playbook中template for if 下面例子主要是学习变量 字典,条件判断等。 [root@localhost7A playbook]# cat for1.yml - hosts: appserv vars: ports_num: - 81 - 82 - 83 tasks: - name: config template: src=server.conf.j2 dest=/data/server.conf [root@localhost7A playbook]# cat templates/server.conf.j2 {% for port in ports_num %} # 定义port变量名,循环遍历ports_num定义的变量值 。 server{ listen {{ port }} } {% endfor %} ----------------------------------------------------------------------- [root@localhost7A playbook]# cat for2.yml #字典使用 - hosts: appserv vars: ports_num: - listen_port: 81 - listen_port: 82 - listen_port: 83 tasks: - name: config template: src=server2.conf.j2 dest=/data/server2.conf [root@localhost7A playbook]# cat templates/server2.conf.j2 {% for port in ports_num %} server{ listen {{ port.listen_port }} } {% endfor %} ----------------------------------------------------------------------- [root@localhost7A playbook]# cat for3.yml - hosts: appserv vars: ports_info: - web1: listen_port: 81 name: web1.magedu.com dir: /data/web1 - web2: listen_port: 82 name: web2.magedu.com dir: /data/web2 - web3: listen_port: 83 name: web3.magedu.com dir: /data/web3 tasks: - name: config template: src=server3.conf.j2 dest=/data/server3.conf [root@localhost7A playbook]# cat templates/server3.conf.j2 {% for port in ports_info %} server{ listen {{ port.listen_port }} server_name {{ port.name }} root {{ port.dir }} } {% endfor %} ------------------------------------------------------------------------ [root@localhost7A playbook]# cat for4.yml - hosts: appserv vars: ports_info: - web1: listen_port: 81 # name: web1.magedu.com #是否定义 dir: /data/web1 - web2: listen_port: 82 name: web2.magedu.com dir: /data/web2 - web3: listen_port: 83 #name: web3.magedu.com dir: /data/web3 tasks: - name: config template: src=server4.conf.j2 dest=/data/server4.conf [root@localhost7A playbook]# cat templates/server4.conf.j2 {% for port in ports_num %} server{ listen {{ port.listen_port }} {% if port.name is defined %} # defined定义。判断name是否定义。定义执行本段。 server_name {{ port.name }} {% endif %} root {{ port.dir }} } {% endfor %} ========================================================================================== roles ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。 要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中, 并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中 复杂场景:建议使用roles,代码复用度高 变更指定主机或主机组 如命名不规范维护和传承成本大 某些功能需多个Playbook,通过includes即可实现 跨roles(项目)调用文件,调用本项目文件,只写文件名,如跨项目,文件路径写:roles/nginx/files/xxx.yaml 每个角色,以特定的层级目录结构进行组织 roles目录结构: playbook.yml roles/ project/ 可以有多个项目,如mysql nginx httpd tasks/ main.yml(调用taskN.yml顺序信息),task1.yml task2.yml files/ 配置文件 vars/ 变量文件 templates/ 模版 handlers/ 调用任务 /roles/project/ :项目名称,有以下子目录,如mysql nginx httpd 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文件 例子: [root@localhost7A playbook]# tree ├── nginx_role.yml #角色文件 ├── roles │ ├── mysql # │ └── nginx │ ├── files │ │ ├── index.html │ │ └── nginx.conf │ ├── handlers │ │ └── main.yml │ └── tasks │ ├── config.yml │ ├── data.yml │ ├── install.yml │ ├── main.yml │ ├── service.yml │ └── user.yml [root@localhost7A playbook]# cat nginx_role.yml #调用名称 - hosts: appserv roles: - role: nginx [root@localhost7A playbook]# cat roles/nginx/handlers/main.yml - name: restart nginx service: name=nginx state=restarted [root@localhost7A playbook]# cat roles/nginx/tasks/main.yml #文件名不能变,调用顺序。 - include: user.yml - include: install.yml - include: config.yml - include: data.yml - include: service.yml [root@localhost7A playbook]# cat roles/nginx/tasks/user.yml - name: create user user: name=nginx shell=/sbin/nologin system=yes create_home=no [root@localhost7A playbook]# cat roles/nginx/tasks/install.yml - name: install nginx yum: name=nginx [root@localhost7A playbook]# cat roles/nginx/tasks/config.yml - name: configa copy: src=nginx.conf dest=/etc/nginx/ notify: restart nginx [root@localhost7A playbook]# cat roles/nginx/tasks/data.yml - name: data file copy: src=index.html dest=/usr/share/nginx/html/ [root@localhost7A playbook]# cat roles/nginx/tasks/service.yml - name: service service: name=nginx state=started enabled=yes [root@localhost7A playbook]# cat roles/nginx/handlers/main.yml - name: restart nginx service: name=nginx state=restarted playbook调用角色 调用角色方法1: - hosts: websrvs remote_user: root roles: - mysql - memcached - nginx 调用角色方法2: 传递变量给角色 - hosts: remote_user: roles: - mysql - { role: nginx, k: v} role用于指定角色名称,后续的k/v用于传递变量给角色 调用角色方法3:还可基于条件测试实现角色调用 - hosts: remote_user: roles: - { role: nginx, k: v, when: ansible_distribution_major_version == ‘7’ } roles playbook tags(标签)使用 ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml // nginx-role.yml --- - hosts: testweb 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: marridb ,tags: [ 'mysql', 'db' ] } - { role: php } ================================================================================================================== ssh-keygen ssh-copy-id 192.168.80.110 目录结构如下: tree ansible/ ├── hosts #主机清单 ├── mysql_role.yml ├── nginx_role.yml #角色文件,调用下面roles下的nginx ├── roles │ ├── mysql #省略 │ └── nginx │ ├── files │ │ ├── index.html │ │ └── nginx.conf │ ├── handlers │ │ └── main.yml │ └── tasks │ ├── config.yml │ ├── data.yml │ ├── install.yml │ ├── main.yml │ ├── service.yml │ └── user.yml
ansible常用模块
Command:在远程主机执行命令,默认模块,可忽略-m选项 creates:一个文件名,当该文件存在,则该命令不执行,不存在,才执行。 free_form:要执行的linux指令 chdir:在执行指令之前,先切换到该指定的目录 removes:一个文件名,当该文件不存在,则该选项不执行 executable:切换shell来执行指令,该执行路径必须是一个绝对路径 ansible all -m command -a "creates=/etc/xxx ls / ; ls /data" ansible srvs -m command -a ‘service vsftpd start’ ansible srvs -m command -a ‘echo magedu |passwd --stdin wang’ 此命令不支持 变量名 $VARNAME < > | ; & 等,用shell模块实现 Shell:和command相似,用shell执行命令 ansible srv -m shell -a ‘echo magedu |passwd –stdin wang’ ansible srv -m shell -a "sed -i s@SELINUX=enforcing@SELINUX=disabled @ /etc/selinux/config" 调用bash执行命令 类似 cat /tmp/stanley.md | awk -F‘|’ ‘{print $1,$2}’ &> /tmp/example.txt 这些复杂命令,即使使用shell也可能会失败,解决办法:写到脚本时,copy到远程,执行,再把需要的结果拉回执行命令的机器 Script:在远程主机上运行ansible服务器上的脚本 -a "/PATH/TO/SCRIPT_FILE“ ansible websrvs -m script -a " /data/f1.sh" Copy:从主控端复制文件到远程主机 注意,当文件存在,复制文件时,只要文件任意属性变了,就会从新复制,文件名没变也会复制。 backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no content:用于替代"src",可以直接设定指定文件的值 directory_mode:递归的设定目录的权限,默认为系统默认权限 force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes others:所有的file模块里的选项都可以在这里使用 src:要复制到远程主机的文件在本地(ansible主控端),可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。 dest:远程主机上的目标路径,绝对路径 (group、mode、owner):定义文件/目录,权限相关设置 如目标存在,默认覆盖,此处指定先备份 ansible srv -m copy -a “src=/root/f1.sh dest=/tmp/f2.sh owner=wang mode=600 backup=yes” 指定内容,直接生成目标文件 ansible srv -m copy -a “content=‘line1\nline2’ dest=/tmp/f1.txt” Fetch:从远程主机提取文件至主控端,copy相反,目前不支持目录 src:远程主机地址,只能是文件。 dest:本机地址, ansible srv -m fetch -a ‘src=/root/a.sh dest=/data/scripts’ File:file模块主要用于远程主机上的文件操作 (group、mode、owner):定义文件/目录 path:定义文件路径 recurse:递归的设置,只对目录有效。 src:要被链接的源文件路径,只应用于state=link的情况 dest:被连接的路径,只应用于state=link的情况 state: directory:如果目录不存在,创建目录 file:即使文件不存在,也不会创建 link:创建软连接 hard:创建硬链接 touch:文件不存在,则会创建。如果存在则会,则更新最后修改的时间。 absent:删除目录、文件或取消链接。 ansible srv -m file -a "path=/root/a.sh state=touch“ 创建文件 ansible srv -m file -a "path=/root/a.sh state=absent“ 删除文件 ansible srv -m file -a "path=/root/b.sh owner=wang mode=755“ ansible web -m file -a ‘src=/app/testfile dest=/app/testfile-link state=link ansible web -m file -a ‘src=/app/testfile path=/app/testfile-link state=link unarchive:解包解压缩,有两种用法: 1、将ansible主机上的压缩包在本地解压缩后传到远程主机上,设置copy=yes. 2、将远程主机上的某个压缩包解压缩到远程主机指定路径下,设置copy=no 常见参数: copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件 src:源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no dest:远程主机上的目标路径 mode:设置解压缩后的文件权限 ansible srv -m unarchive -a 'src=foo.tgz dest=/var/lib/foo' ansible srv -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777' ansible srv -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no' ansible常用模块 Archive:打包压缩 ansible all -m archive -a 'path=/etc/sysconfig dest=/data/sysconfig.tar.bz2 format=bz2 owner=wang mode=0777' Hostname:管理主机名 ansible node1 -m hostname -a “name=websrv” Cron:计划任务 backup:对远程主机上的原任务计划内容修改之前做备份 cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划 day:日(1-31,*,*/2,……) hour:小时(0-23,*,*/2,……) minute:分钟(0-59,*,*/2,……) month:月(1-12,*,*/2,……) weekday:周(0-7,*,……) job:要执行的任务,依赖于state=present name:该任务的描述 special_time:指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly state:确认该任务计划是创建还是删除 user:以哪个用户的身份执行 支持时间:minute,hour,day,month,weekday ansible srv -m cron -a “minute=*/5 job=‘/usr/sbin/ntpdate 172.16.0.1 &>/dev/null’ name=Synctime” 创建任务 ansible srv -m cron -a “minute=*/5 job=‘/usr/sbin/ntpdate 172.16.0.1 &>/dev/null’ name=Synctime disabled=true" 禁用任务 ansible srv -m cron -a ‘state=absent name=Synctime’ 删除任务 Yum:管理包 config_file:yum的配置文件 disable_gpg_check:关闭gpg_check disablerepo:不启用某个源 enablerepo:启用某个源 name:要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径 state:状态(present,absent,latest) ansible srv -m yum -a ‘name=httpd state=present’ 安装 ansible srv -m yum -a ‘name=httpd state=absent’ 删除 Service:管理服务 arguments:给命令行提供一些选项 enabled:是否开机启动 yes|no name:必选项,服务名称 pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行 runlevel:运行级别 sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟 state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded) ansible srv -m service -a 'name=httpd state=stopped' ansible srv -m service -a 'name=httpd state=started enabled=yes' ansible srv -m service -a 'name=httpd state=reloaded’ ansible srv -m service -a 'name=httpd state=restarted' User:管理用户 create_home: 是否创建家目录,默认yes。 home:设置用户的主目录。 shell: shell类型 system:系统账号 uid: 用户ID comment:描述说明 remove:删除家目录等数据 state: 创建或删除 用户(present,absent) ansible srv -m user -a 'name=user1 comment=“test user” uid=2048 home=/app/user1 group=root‘ ansible srv -m user -a 'name=sysuser1 system=yes home=/app/sysuser1 ’ ansible srv -m user -a ‘name=user1 state=absent remove=yes‘ 删除用户及家目录等数据 Group:管理组 ansible srv -m group -a "name=testgroup system=yes“ ansible srv -m group -a "name=testgroup state=absent" Ping 是否在活动 ansible all -m ping setup模块,主要用于获取主机信息,在playbooks里经常会用到的一个参数gather_facts就与该模块相关。setup模块下经常使用的一个参数是filter(滤波器),也是ansible的变量集 ,具体使用示例如下: #查看主机内存信息 ansible host1 -m setup -a 'filter=ansible_memtotal_mb' # 'filter=ansible_*_mb' #查看网卡信息 ansible test1 -m setup -a 'filter=ansible_eth0' template功能:根据模块文件动态生成对应的配置文件 template文件必须存放于templates目录下,且命名为 .j2 结尾 yaml/yml 文件需和templates目录平级,目录结构如下: tasks: - name: template config to remote hosts template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf synchronize 模块 使用rsync同步文件 archive: 归档,相当于同时开启recursive(递归)、links、perms、times、owner、group、-D选项都为yes ,默认该项为开启 checksum: 跳过检测sum值,默认关闭 compress:是否开启压缩 copy_links:复制链接文件,默认为no ,注意后面还有一个links参数 delete: 删除不存在的文件,默认no dest:目录路径 dest_port:默认目录主机上的端口 ,默认是22,走的ssh协议 dirs:传速目录不进行递归,默认为no,即进行目录递归 rsync_opts:rsync参数部分 set_remote_user:主要用于/etc/ansible/hosts中定义或默认使用的用户与rsync使用的用户不同的情况 mode: push或pull 模块,push模的话,一般用于从本机向远程主机上传文件,pull 模式用于从远程主机上取文件 示例:[root@test ansible]# ansible test1 -m synchronize -a 'src=/tmp/helloworld dest=/var/www' mount 模块 dump fstype:必选项,挂载文件的类型 name:必选项,挂载点 opts:传递给mount命令的参数 src:必选项,要挂载的文件 state:必选项 present:只处理fstab中的配置 absent:删除挂载点 mounted:自动创建挂载点并挂载之 umounted:卸载 示例: #创建设备 [root@test ansible]# ansible test1 -a 'dd if=/dev/zero of=/disk.img bs=4k count=1024' #与/dev/loop1关联 [root@test ansible]# ansible test1 -a 'losetup /dev/loop1 /disk.img' #格式化 [root@test ansible]# ansible test1 -m filesystem -a 'fstype=ext3 force=yes opts=-F #挂载 [root@test ansible]# ansible test1 -m mount -a 'name=/mnt src=/dev/loop1 fstype=ext3 state=mounted opts=rw' set_face set_fact模块可以让你在远程受管机器上去执行脚本的过程来计算我们需要的值,这些值可以被用在模板或者变量中。 这些值有点类似setup模块中的参数,只不过setup模块是以单台主机为单位的。 示例: tasks: -name: Calculate InnoDB buffer pool size set facl: innodb_buffer_pool_size_mb=”{{ ansible_mentotal_mb /2 }}” pause 暂停模块可以让我们在playbooks中暂停一段时间,可以知道一个时间段,或者提示用户继续。在命令行中没生么有,但在playbook中,很有用处。 示例: # Pause for 5 minutes to build app cache. - pause: minutes=5 # Pause until you can verify updates to an application were successful. - pause: # A helpful reminder of what to look out for post-update. - pause: prompt="Make sure org.foo.FooOverload exception is not present" wait_for wait_for模块用来检测一个tcp端口是否准备好接收远程连接,这是由远程主机来完成的。 示例: # 10秒后在当前主机开始检查8000端口,直到端口启动后返回 - wait_for: port=8000 delay=10 # 检查path=/tmp/foo直到文件存在后继续 - wait_for: path=/tmp/foo # 直到/var/lock/file.lock移除后继续 - wait_for: path=/var/lock/file.lock state=absent -name: Wait for Tomcat to start wait_for: port=8080 state=started assemble assemble组装模块把多个受管主机的文件合并成一个文件,当配置文件不允许包含的时候,非常有用。特别在设置root用户的authorized_keys文件的时候。 示例: # Example from Ansible Playbooks - assemble: src=/etc/someapp/fragments dest=/etc/someapp/someapp.conf # When a delimiter is specified, it will be inserted in between each fragment - assemble: src=/etc/someapp/fragments dest=/etc/someapp/someapp.conf delimiter='### START FRAGMENT ###' add_host add_host添加主机模块是playbook中一个强大的模块,它可以让你动态的添加受管主机到一个play中。 示例: # add host to group 'just_created' with variable foo=42 - add_host: name={{ ip_from_ec2 }} groups=just_created foo=42 group_by group_by模块可以让我们根据主机的真实特性进行分组,真实特性可以通过add_fact来实现。Group_by模块只接受一个参数,key,同样组名的机器被分到一个组里面。 示例: # Create groups based on the machine architecture - group_by: key=machine_{{ ansible_machine }} # Create groups like 'kvm-host' - group_by: key=virt_{{ ansible_virtualization_type }}_{{ ansible_virtualization_role }} get_url 该模块主要用于从http、ftp、https服务器上下载文件(类似于wget),主要有如下选项: sha256sum:下载完成后进行sha256 check; timeout:下载超时时间,默认10s url:下载的URL url_password、url_username:主要用于需要用户名密码进行验证的情况 use_proxy:是事使用代理,代理需事先在环境变更中定义 示例: - name: download foo.conf get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf mode=0440 - name: download file with sha256 check get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf sha256sum=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c debug 调试模块,用于在调试中输出信息 常用参数: msg:调试输出的消息 var:将某个任务执行的输出作为变量传递给debug模块,debug会直接将其打印输出 verbosity:debug的级别(默认是0级,全部显示) fail 用于终止当前playbook的执行,通常与条件语句组合使用,当满足条件时,终止当前play的运行。可以直接由failed_when取代。 选项只有一个: msg:终止前打印出信息