20171118 Ansible

  • ansible介绍
  • ansible常用模块使用
  • playbook
  • templates,模板
  • 条件测试和循环迭代
  • roles,角色

一、ansible介绍

  • ansible:自动化运维工具,实现了批量系统配置、批量程序部署、批量运行命令

  • 特性:
    模块化:调用特定的模块,完成特定任务
    基于Python语言实现:包含Paramiko, PyYAML和Jinja2三个关键模块
    部署简单:agentless,不需在被配置主机安装客户端
    支持自定义模块
    支持playbook
    幂等性:任意多次执行所产生的影响均与一次执行的影响相同

  • 文件结构:
    配置文件:/etc/ansible/ansible.cfg
    主机清单:/etc/ansible/hosts

    • 主机清单配置文件格式:
    [webservers]      // 主机组名,包含下面的主机
    alpha.example.org
    beta.example.org
    192.168.1.100
    192.168.1.110
    
  • 主程序:
    /usr/bin/ansible
    /usr/bin/ansible-playbook
    /usr/bin/ansible-doc

二、ansible常用模块使用

(一)ansible使用语法:

// 调用模块执行操作
ansible  HOST-PATTERN  -m MOD_NAME  -a  MOD_ARGS -f FORKS -C -u USERNAME -c CONNECTION
// 列出所有可以调用的模块
ansible-doc  -l
// 列出指定模块的使用方法
ansible-doc -s MOD_NAME
  • 测试1:ping模块,测试管理的主机的网络连接状态,连接成功返回pong
    ansible all -m ping
    20171118 Ansible_第1张图片

(二)command模块:在远程主机运行命令

  • chdir=/PATH/TO/DIR:
    执行命令前切换工作目录至指定的位置
  • creates=/PATH/TO/SOMEFILE_OR_DIR:
    如果此处给定的文件或目录存在,则不执行命令
  • removes=/PATH/TO/SOMEFILE_OR_DIR:
    如果此处给定的文件或目录不存在,则不执行命令;即此处给定的文件或目录存在时方执行命令
  • 测试2:查询管理主机指定网卡状态
    ansible all -m command -a 'ip a show ens33'
    20171118 Ansible_第2张图片
  • 测试3:chdir的作用为在执行命令前切换至相应目录
    ansible 192.168.136.230 -m command -a 'pwd chdir=/tmp'
    ansible 192.168.136.230 -m command -a 'pwd'
    20171118 Ansible_第3张图片
  • 省略-m MOD_NAME时,则代表command模块

(三)shell模块:在远程主机的shell进程下运行命令,支持shell特性,如管道等

  • chdir=:
    执行命令前切换工作目录至指定的位置
  • creates=/PATH/TO/SOMEFILE_OR_DIR:
    如果此处给定的文件或目录存在,则不执行命令
  • removes=/PATH/TO/SOMEFILE_OR_DIR:
    如果此处给定的文件或目录不存在,则不执行命令;即此处给定的文件或目录存在时方执行命令
  • executable=/PATH/TO/SHELL:指定运行命令使用的shell解释器
  • 测试4:管理远程主机——修改账号密码
    ansible websrvs -m shell -a 'echo centos | passwd --stdin user1 '
    20171118 Ansible_第4张图片

(四)group模块:管理组账号

  • name=:必须参数,组账号名
  • state=present | absent:建立/删除组账号
  • system=yes | no:是否为系统账号
  • gid=:组ID
  • 测试5:管理远程主机——建立组
    ansible websrvs -m group -a 'name=haproxy system=yes state=present'
    20171118 Ansible_第5张图片

(五)user模块:管理用户账号

  • name=:必须参数,用户账号名
  • system=yes | no:是否为系统账号
  • uid=:用户ID
  • shell=:指定shell类型
  • group=:指定主组
  • groups=:指定附加组
  • comment=:指定说明
  • home=:指定家目录
  • generate_ssh_key=:是否生成ssh密钥
  • 测试6:管理远程主机——建立用户
    ansible websrvs -m user -a 'name=john groups=haproxy state=present shell=/bin/tcsh generate_ssh_key=true'
    20171118 Ansible_第6张图片

(六)copy模块: Copies files to remote locations

  • 用法1:src= dest=:
    将本地的文件复制到管理的主机组中
  • 用法2:content= dest=:
    在管理的主机组中中创建文件,由content关键词指定内容
  • owner=:指定所有者
  • group=:指定所属组
  • mode=:指定权限
  • 测试7:复制文件至远程主机指定目录
    ansible all -m copy -a 'src=test.txt dest=/tmp/ owner=nobody group=daemon mode=664'
    20171118 Ansible_第7张图片
  • 测试8:将内容装入文件复制至远程主机指定目录
    ansible all -m copy -a "content='hello everyone\n' dest=/tmp/test2.txt owner=nobody group=daemon mode=664"
    20171118 Ansible_第8张图片

(七)fetch模块:Fetches a file from remote nodes

从远程节点获取文件

(八)file模块: Sets attributes of files

  • 用法:
    创建链接文件:path= src= state=link
    修改属性:path= owner= mode= group=
    创建目录:path= state=directory

  • 注意:state属性的可用值
    file:仅在修改已经存在文件的属性时使用
    directory:目录
    link:软链接
    hard:硬链接
    touch:创建空白文件
    absent:删除

  • 测试9:在远程主机建立目录
    ansible all -m file -a "path=/tmp/hidir state=directory mode=770"

    20171118 Ansible_第9张图片

  • 测试10:在远程主机建立空文件
    ansible all -m file -a "path=/tmp/hifile state=touch mode=660"

    20171118 Ansible_第10张图片

  • 测试11:在远程主机建立软链接
    ansible all -m file -a "path=/tmp/mytext.txt src=/tmp/test2.txt state=link"

    20171118 Ansible_第11张图片

  • 测试12:在远程主机删除软链接
    ansible all -m file -a "path=/tmp/mytext.txt state=absent"

    20171118 Ansible_第12张图片

(九)get_url模块: Downloads files from HTTP, HTTPS, or FTP to node

  • url=:必须参数
  • dest=:必须参数
  • sha256sum=:校验完整性
  • owner, group, mode:所有者,所属组,权限
  • 测试13:在远程主机上从网络链接下载文件
    ansible all -m get_url -a "url=http://172.16.0.1/centos/7/Packages/ImageMagick-6.7.8.9-15.el7_2.x86_64.rpm dest=/tmp/"
    20171118 Ansible_第13张图片

(十)cron 模块:Manage cron.d and crontab entries.

  • minute=:时间
  • day=:天
  • month=:月
  • weekday=:工作日
  • hour=:消失
  • job=:执行的程序
  • name=:名称,必须参数
  • state=present|absent:创建或删除
  • 测试14:设置远程主机每5分钟向主机172.18.0.1同步时间
    ansible all -m cron -a "name='timesync' job='/usr/sbin/ntpdate 172.18.0.1 &> /dev/null' minute='*/5' "
    20171118 Ansible_第14张图片

(十一)hostname模块:Manage hostname

  • name=:主机名

(十二)包管理相关模块

(1)yum模块:Manages packages with the 'yum' package manager
  • name=:程序包名称,可以带版本号
  • state=
    present, latest, installed:安装
    absent, removed:卸载
  • 测试15:远程安装软件包
    ansible websrvs -m yum -a "name=nginx state=latest"
    20171118 Ansible_第15张图片
  • 查看远程主机指定软件包的安装状态
    ansible websrvs -m yum -a "list=nginx"
    20171118 Ansible_第16张图片
(2)pip模块:Manages Python library dependencies
  • name=
  • state=
  • version=
(3)npm模块:Manage node.js packages with npm
  • name=
  • state=
  • version=

(十三)service模块:管理服务

  • name=:服务名称,必备参数
  • state=started | stopped | restarted:服务启动,关闭,重启
  • enabled=:是否开机启动
  • runlevel=:运行级别,适用于init脚本启动
  • 测试16:远程启动指定服务,并设置为开机启动服务
    ansible websrvs -m service -a "name=nginx enabled=true state=started"
    20171118 Ansible_第17张图片

(十四)其他模块

(1)git模块:Deploy software (or files) from git checkouts
  • repo=:git源
  • dest=:存储的本地路径
  • version=
(2)deploy_helper模块:Manages some of the steps common in deploying projects
(3)haproxy模块:Enable, disable, and set weights for HAProxy backend servers using socket commands.
  • backend=:后端主机
  • host=:必备参数,后端主机名称
  • state=:必备参数,后端主机状态
  • weight=:后端主机权重

三、playbook

  • playbook:一种简单的配置管理系统与多机器部署系统的基础,可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤,并且可以同步或异步的发起任务

(一)YAML介绍:

  • playbook采用YAML格式
  • YAML:Yet Another Markup Language,一个可读性高,用来表达数据序列的格式
  • YAML能表达的基本数据结构:标量、数组、关联数组

(二)playbook的运用:

(1)playbook的核心元素:
  • hosts:主机
  • tasks:任务列表
  • variables:变量
  • templates:包含了模板语法的文本文件
  • handlers:由特定条件触发的任务
(2)playbook的基础组件:
  • hosts:运行指定任务的目标主机

  • remoute_user:在远程主机上执行任务的用户,权限提升时可能要用到sudo_user

  • tasks:任务列表

    • 格式:
      (1) action: module arguments
      (2) module: arguments
      注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;
    • 某任务的状态在运行后为changed时,可通过notify通知给相应的handlers;
    • 任务可以通过tags打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
  • handlers:处理器,在特定条件下触发任务
    接收到其它任务的通知时被触发
    notify: HANDLER TASK NAME

(三)变量:variables

(1)直接调用
  • 注意:可使用setup模块直接获取目标主机的facters
(2)用户自定义变量:
  • 方法一:ansible-playbook命令行中指定
    -e VARS, --extra-vars=VARS

  • 方法二:在playbook中定义变量
    - var1: value1
    变量引用:{{ variable }},注意变量名前后均有空格

  • 方法三:通过roles传递变量

  • 方法四:Host Inventory,主机清单

    • 用户自定义变量

      • 向不同的主机传递不同的变量
        IP/HOSTNAME varaiable=value var2=value2
      • 向组中的主机传递相同的变量
        [groupname:vars]
        variable=value
      • 注意:优先级低于playbook中的定义
    • invertory参数
      用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量
      IP/HOSTNAME [ ansible_ssh_host | ansible_ssh_port | ansible_ssh_user | ansible_ssh_pass | ansbile_sudo_pass],危险不建议使用

(3)测试playbook:
  • ansible-playbook --check|-C
    只检测可能会发生的改变,但不真正执行操作
  • ansible-playbook --list-hosts
    列出运行任务的主机
  • ansible-playbook --list-tasks
    列出要运行的任务列表
  • ansible-playbook --syntax-check
    语法检查

(四)实验1:playbook实现基本的远程配置

  • 实验环境:
    web服务器:192.168.136.230, 192.168.136.130
    数据库服务器:192.168.136.131

  • 实现目标:
    web服务器:自动安装并启动nginx服务
    数据库服务器:自动安装redis,统一配置文件内容,最后启动redis服务

(1)实现过程:
  • 准备步骤:在ansible主机上使用ssh-keygen -t rsa生成公钥和私钥,使用ssh-copy-id ip_address将公钥复制到需要管理的每台主机上

  • 步骤1:配置/etc/ansible/hosts文件,将服务器归类称为不同的组,方便管理

[websrvs]     // web服务器组,命名为websrvs
192.168.136.230
192.168.136.130

[dbsrvs]     // web服务器组,命名为dbsrvs
192.168.136.131
  • 步骤2:配置playbook文件
- hosts: websrvs
  remote_user: root
  tasks:
  - name: install nginx package     // 安装nginx服务
    yum: name=nginx state=latest
  - name: start nginx service       // 启动nginx服务
    service: name=nginx enabled=true state=started

- hosts: dbsrvs
  remote_user: root
  tasks:
  - name: install redis package     // 安装redis服务
    yum: name=redis state=latest
  - name: install conf file         // 复制redis配置文件至远程主机
    copy: src=/root/redis.conf dest=/etc/redis.conf owner=redis group=root mode=644     
    // 提前准备好redis配置文件
  - name: start redis service       // 启动redis服务
    service: name=redis state=started
  • 步骤3:测试并运行
ansible-playbook --list-hosts nginx.yaml    // 列出playbook中的主机
ansible-playbook --list-tasks nginx.yaml    // 列出playbook中的任务
ansible-playbook --syntax-check nginx.yaml  // 检查YAML文件的语法
ansible-playbook -C nginx.yaml              // 预测执行playbook可能发生的变化,但实际不执行
ansible-playbook nginx.yaml                 // 执行playbook
ansible websrvs -m setup                    // 查看执行playbook时收集的信息

列出playbook中的主机

20171118 Ansible_第18张图片

列出playbook中的任务

20171118 Ansible_第19张图片

预测执行playbook可能发生的变化

20171118 Ansible_第20张图片
(2)缺陷分析:
  • 问题1:当配置文件修改后,执行playbook会重复执行所有任务,而大部分任务没有修改
  • 问题2:虽然配置得到了更新,但是服务已经开启,故服务不会重启载入配置
  • 解决:问题1可以通过定义标签,指定只执行标签处的任务;问题2可以通过定义重新启动服务的任务,并声明只在配置更改时执行:
  • 实现步骤1:修改playbook文件
vim nginx.yaml
- hosts: websrvs
  remote_user: root
  tasks:
  - name: install nginx package
    yum: name=nginx state=latest
  - name: start nginx service
    service: name=nginx enabled=true state=started

- hosts: dbsrvs
  remote_user: root
  tasks:
  - name: install redis package
    yum: name=redis state=latest
  - name: install conf file
    copy: src=/root/redis.conf dest=/etc/redis.conf owner=redis group=root mode=644
    tags: instconf                   // 对install conf file任务打标签
    notify: restart redis service    // 当配置文件变更时,才执行名为restart redis service的handler
  - name: start redis service
    service: name=redis state=started
  handlers:                          // 定义handler,由notify语句在某些情况下被触发
  - name: restart redis service
    service: name=redis state=restarted
  • 实现步骤2:修改/root/redis.conf文件,执行playbook并指定只执行标签instconf处的任务
    ansible-playbook -t instconf nginx.yaml

可以看到执行结果中只执行了tag处的任务,并且触发执行名为restart redis service 的handler

20171118 Ansible_第21张图片
  • 实现步骤3:再次执行上一条命令

可以看到只执行了标签instconf的任务,但由于配置没有改变,故没有触发执行名为restart redis service 的handler

20171118 Ansible_第22张图片

(五)实验2:playbook中定义变量

  • 编辑instalpkg.yml文件,实现:当不指定变量pkgname时,自动安装tree;当指定pkgname的值时,安装指定的软件包
- hosts: websrvs
  remote_user: root
  vars:
  - pkgname: tree
  tasks:
  - name: install package
    yum: name={{ pkgname }} state=latest
20171118 Ansible_第23张图片
  • 可以看到被管理的主机成功安装;变量的引用也可以应用到name中,这样可以看到当前被安装的软件名称,对instalpkg.yml文件做修改后如下:
- hosts: websrvs
  remote_user: root
  vars:
  - pkgname: tree
  tasks:
  - name: install package {{ pkgname }}     // 做修改处
    yum: name={{ pkgname }} state=latest
  • 此时可以看到默认安装tree
20171118 Ansible_第24张图片
  • 指定变量pkgname的值
    ansible-playbook -e "pkgname=memcached" -C instalpkg.yml
    此时可以看到安装软件为memcached
20171118 Ansible_第25张图片

四、templates,模板

(一)template介绍:

  • 定义:基于模板方式生成一个文件复制到远程主机

  • 实质:文本文件,嵌套有脚本(使用模板编程语言编写),类比php嵌入html文件的关系

(二)template配置:

  • template模块的使用:类似copy
    src, dest, owner, group, mode

  • 脚本语言:Jinja2,语法如下

    • 字符串:使用单引号或双引号;
    • 数字:整数,浮点数;
    • 列表:[item1, item2, ...]
    • 元组:(item1, item2, ...)
    • 字典:{key1:value1, key2:value2, ...}
    • 布尔型:true/false
    • 算术运算:+, -, *, /, //, %, **
    • 比较操作:==, !=, >, >=, <, <=
    • 逻辑运算:and, or, not

(三)实验3:实现自动安装redis,之后修改配置文件/etc/redis.conf的maxmemory值为主机总内存大小的一半,并且自动重启服务使配置生效

  • 步骤1:编辑/root/redis_install_and_conf.yml文件,实现实验要求
vim /root/redis_install_and_conf.yml
- hosts: dbsrvs
  remote_user: root
  tasks:
// 安装
  - name: install redis
    yum: name=redis state=latest
// 复制配置文件模板
  - name: install redis conf
    template: src=/root/redis.conf.j2 dest=/etc/redis.conf owner=redis group=root mode=644
    notify: restart redis service
    tags: install_conf
// 启动服务
  - name: start redis service
    service: name=redis state=started
// 条件触发任务
  handlers:
  - name: restart redis service
    service: name=redis state=restarted
  • 步骤2:准备配置文件
cp /etc/redis.conf /root/redis.conf.j2
vim /root/redis.conf.j2
maxmemory {{ ansible_memtotal_mb /2  }}mb     // 添加此行,自动根据安装主机的内存容量设置
  • 步骤3:测试并执行playbook
ansible-playbook -C /root/redis_install_and_conf.yml 
ansible-playbook /root/redis_install_and_conf.yml 

可以看到install redis conf任务成功执行

20171118 Ansible_第26张图片

查看被安装的主机上的/etc/redis.conf文件,maxmemory值根据主机内存情况动态设置

五、条件测试和循环迭代:

(一)条件测试:when

  • 适用于根据被管理主机参数的不同采取不同的操作

  • when语句:在task中使用,jinja2的语法格式

tasks: 
- name: install conf file to centos7
  template: src=/etc/nginx.conf.c7.j2 dest=/etc/nginx.conf owner=root group=root
  when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
  template: src=/etc/nginx.conf.c6.j2 dest=/etc/nginx.conf owner=root group=root
  when: ansible_distribution_major_version == "6"

(二)循环:迭代,需要重复执行的任务

  • 对迭代项的引用,固定变量名为"item"

  • 而后,要在task中使用with_items给定要迭代的元素列表

  • 列表方法:字符串,字典

// 字符串列表方法                                  
- name: install some packages
  yum: name={{ item }} state=present
  with_items:
  - nginx
  - memcached
  - php-fpm
              
- name: add some groups
  group: name={{ item }} state=present
  with_items:
  - group11
  - group12
  - group13

// 字典列表方法
- name: add some users
  user: name={{ item.name }} group={{ item.group }} state=present
  with_items:
  - { name: 'user11', group: 'group11' }
  - { name: 'user12', group: 'group12' }
  - { name: 'user13', group: 'group13' }

六、roles,角色

(一)角色的目录结构

  • 角色集合:/etc/ansible/roles/目录下每个角色一个目录

  • 每个角色以特定的层级目录结构进行组织:

    • 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中角色的调用

  • 调用角色的语法:
- hosts: websrvs
  remote_user: root
  roles:
  - mysql
  - nginx
  • 调用角色同时传递变量给角色
- hosts: 
  remote_user: root
  roles:
  - { role: nginx, username: nginx }
  • 基于条件测试实现角色调用
- hosts: 
  remote_user: root
  roles:
  - { role: nginx, when: "ansible_distribution_major_version == '7' " }

(三)实验4:

  • 步骤1:建立目录结构
mkdir /etc/ansible/roles/nginx/{tasks,handlers,vars,files,templates} -pv
cd /etc/ansible/roles
  • 步骤2:编辑task目录,定义需要执行的任务
vim nginx/tasks/main.yml
- name: install nginx package          // 安装nginx
  yum: name=nginx state=latest
- name: install conf file              // 复制配置模板文件
  template: src=web.conf.j2 dest=/etc/nginx/conf.d/web.conf
  notify: reload nginx service         // 触发服务重载
  tags: instconf
- name: create doc root                // 建立网页文件根目录
  file: path={{ ngx_doc_root }} state=directory
  tags: instconf
- name: start nginx service            // 启动nginx服务
  service: name=nginx enabled=true state=started
  • 步骤3:编辑模板配置文件
vim nginx/templates/web.conf.j2
server {
        listen {{ ngx_server_port }};
        server_name {{ ngx_server_name }};
        location / {
                root {{ ngx_doc_root }};
        }
}
  • 步骤4:编辑变量配置文件
vim nginx/vars/main.yml
ngx_server_port: 80
ngx_server_name: www.hellopeiyang.com
ngx_doc_root: /app/webdata
  • 步骤5: 配置handlers配置文件
vim nginx/handlers/main.yml
- name: reload nginx service
  service: name=nginx state=reloaded
  • 步骤6: 编辑playbook
vim /root/mywebsrvs.yml
- hosts: websrvs
  remote_user: root
  roles:
  - nginx
  • 步骤7: 测试并执行playbook
ansible-playbook -C /root/mywebsrvs.yml
ansible-playbook /root/mywebsrvs.yml
  • 测试过程1:成功执行playbook
20171118 Ansible_第27张图片
  • 执行后可以看到配置文件中的信息按照定义的变量值配置
20171118 Ansible_第28张图片
  • 在运行playbook时指定变量值,优先级高于配置文件,同时指定只执行标签instconf处的任务
    ansible-playbook -e "ngx_server_port=1008" -t instconf /root/mywebsrvs.yml
20171118 Ansible_第29张图片
  • 执行后可以看到配置文件中相应的变化
20171118 Ansible_第30张图片
  • 也可以在playbook中直接传递变量给角色
vim /root/mywebsrvs.yml
- hosts: websrvs
  remote_user: root
  roles:
  - { role: nginx, ngx_server_port: 8090 }   // 指定传入的角色,变量名:变量值
ansible-playbook -t instconf /root/mywebsrvs.yml
20171118 Ansible_第31张图片
  • 同样,执行后变量定义处的配置信息也发生了相应的变化
20171118 Ansible_第32张图片

你可能感兴趣的:(20171118 Ansible)