Ansible使用入门

思维导图:

1. 运维工作简介

1.1 运维简述

1.1.1 运维工作

  • 运维工作的核心任务:
    • 发布、变更、故障处理
  • 系统安装(物理机、虚拟机)--> 程序包安装、配置、服务启动 --> 批量操作 --> 程序发布 --> 监控
    • 系统安装(物理机、虚拟机)
    • 程序安装、配置、服务启动
    • 批量操作(批量运行命令)
    • 程序发布
    • 监控

预发布验证:

  • 新版本的代码先发布到服务器(跟线上环境配置完全相同,只是未接入到调度器)

程序发布:

  • 不能影响用户体验
  • 系统不能停机
  • 不能导致系统故障或造成系统完全不可用

1.1.2 灰度发布

发布路径:

  • /webapp/tuangou-1.1
  • /web/app/tuangou
  • /webapp/tuangou-1.2

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

  1. 通过调度器将线上的一批服务器标记为down模式(软关闭,比如将权重调为0)(maintanance)
  2. 关闭相应服务
  3. 部署新版本的应用程序至目标位置
  4. 启动相关应用
  5. 调度主机上线

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

  • 灰度发布:
    • 基于主机
    • 基于用户

一些专业名词:

  • CI:持续集成
  • CD:持续交付
  • CD:持续部署
  • 以上三个过程如果能够串联起来自动执行,就叫:DevOps

1.1.3 运维工具的分类

  • agent:
    • puppet、func
  • agentless:
    • ansible、fabric
    • ssh

1.1.4 监控工具

不允许没有被监控的系统上线

  • 监控数据采集:
    • 用户行为日志
    • 服务器性能
    • 运行数据报告
  • 监控管理:
    • 异常报警
    • 失效转移
    • 自动优雅降级

1.1.5 运维工具的层次

  1. OS Provisioning:系统安装
    • 物理机:PXE、Cobbler
    • 虚拟机(云环境下):Image、Templates
  2. Configuration:
    • puppet(ruby)
    • saltstack(python)
    • chef
    • cfengine
  3. Command and Control:
    • func
    • ansible(python)
    • fabric

1.1.6 运维工具图示

1.2 持续集成、持续交付、持续部署

1.2.1 集成、部署、交付

集成:

  • 指软件个人研发的部分向软件整体部分交付,以便尽早发现个人开发部分的问题

部署:

  • 代码尽快向可运行的开发/测试环节交付,以便尽早测试

交付:

  • 指研发尽快向客户交付,以便尽早发现生产环节中存在的问题
  • 如果等到所有东西都完成了才向下个环节交付,导致所有的问题只能在最后才爆发出来,解决成本巨大

持续:

  • 每完成一个完整的部分,就向下个环节交付,发现问题可以马上调整,问题不会放大到其他部分和后面的环节

1.2.2 CI、CD

持续集成(CI):

  • 开发人员提交了新代码之后,立刻进行构建、(单元)测试
  • 根据测试结果,我们可以确定新代码和原有代码能否正确的集成在一起

持续交付(CD):

  • 在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境中(类生产环境)
  • 如果代码没问题,可以继续手动部署到生产环境中

持续部署(CD):

  • 在持续交付的基础上,把部署到生产环境的过程自动化

2. Ansible简介&模块详解

2.1 Ansible的安装&基本结构

2.1.1 ansible简介

  • 模块化,调用特定的模块,完成特定的任务
  • 基于python语言实现,由Paramiko、PyYAML和Jinja2三个关键模块
  • 部署简单,agentless
  • 主从模式
  • 支持自定义模块
  • 支持Playbook
  • 幂等性

2.1.2 ansible的安装

  • 安装:直接yum安装(epel、ansible)
  • 配置文件:
    • 配置文件:/etc/ansible/ansible.cfg
    • 主机清单:/etc/ansible/hosts
      • 在这个文件中定义要控制的主机
  • 主程序:
    • ansible
    • ansible-playbook
    • ansible-doc

2.1.3 ansible的使用

准备操作:

  1. ansible在使用前要先在/etc/ansible/hosts中定义要控制的主机
  2. 还要将Ansible Server的ssh公钥分发到各被管控节点上:
    • ssh-keygen  -t  rsa  -f  ~/.ssh/id_rsa  -N ""
    • ssh-copy-id  root@10.0.0.205
    • ssh-copy-id  root@10.0.0.206
    • ssh-copy-id  root@10.0.0.207
    • ssh-copy-id  root@10.0.0.208
  3. 然后就可以在主控server上进行控制了

ansible的简单使用格式:

  • ansible  HOST-PATTERN  -m  MOD_NAME  -a  MOD_ARGS    -f   FORKS  -C  -u   USERNAME 
    • -m:指明模块
    • -a:指明调用的模块参数
    • -f:一批管控多少主机,这里的FORKS也可以在/etc/ansible/ansible.cfg文件中定义,可以将这个值改大点
    • -C:--check,干跑,而不真正执行
    • -u:指明用户名
    • -c:指明连接方式,默认是smart,自动选择
  • 使用示例:
    • ansible 10.0.0.207 -m ping
      • 测试10.0.0.207主机的连通性
    • ansible all -m ping
      • 测试在/etc/ansible/hosts中定义的所有主机的连通性

ansible的工作图示:

2.2 Ansible常用模块详解

2.2.1 获取模块列表

  • ansible-doc -l
    • 列出ansible所有支持的模块
  • ansible-doc -s GROUP_NAME
    • 查看对应模块的用法说明,例如ansible-doc -s group 查看group模块的用法说明
  • ansible使用要点:
    • 定义所期望的目标状态
    • 操作必须是幂等的(所谓幂等就是指重复数次的结果是相同的)

2.2.2 group

  • 作用:
    • 管理用户组
  • 模块参数:
    • name=指定该用户组的组名
    • gid=指定该用户组的gid
    • system=指定该组是否为系统组,yes表示是,no表示不是系统组
    • state=指定目标状态,present表示要创建出来,absent就表示要删除它
  • 使用示例:
    • 创建一个gid为3000的名叫mygrp的非系统组
      • ansible all -m group -a "gid=3000 name=mygrp state=present system=no"
    • 删除刚刚创建的那个组:
      • ansible all -m group -a "gid=3000 name=mygrp state=absent system=no"

2.2.3 user

  • 作用:
    • 管理用户账号
  • 模块参数:
    • name=指定用户名
    • uid=指定用户uid
    • group=指定用户的主组
    • groups=指定用户的附加组
    • home=指定用户家目录
    • shell=指定用户登录的shell
    • comment=指定对该用户的描述
    • system=指定用户是否为系统用户yes或者no
    • state=present或者absent
  • 使用示例:
    • ansible all -m user -a "uid=5000 name=mytestuser state=present groups=mygrp shell=/bin/bash"

2.2.4 copy

  • 作用:
    • 复制文件
    • 从本机到目标主机,或者从远程主机到目标主机
  • 模块参数:
    • dest=指定的目标路径,如果源是一个目录,则目标必须是目录
    • src=指定的源路径,如果源是目录,则默认就会做递归复制,这里如果结尾带了/ 则表示只复制目录中的内容,不带斜线则表示复制所有
    • remote_src=可以指定远程的源路径
    • owner=指定目标文件的属主
    • group=指定目标文件的属组
    • mode=指定目标文件的权限
    • content=不使用src拷贝文件时,使用content直接指定文件内容(src和content必须有其一)
  • 注意:
    • 如果不指定属主属组,它是默认不变的,以哪个用户复制就以哪个用户来生成,
    • 如果自己指明用户,要确保目标主机存在那个用户
  • 使用示例:
    • ansible all -m copy -a "src=/etc/fstab dest=/tmp/fstab mode=600"
    • 也可以使用content生成文件:
      • ansible all -m copy -a "content='hello world\n' dest=/tmp/hello.txt"

2.2.5 fetch

  • 作用:
    • 从远程主机上复制文件到本地
  • 使用参数:
    • dest=指定目标路径
    • src=指定源路径
    • fail_on_missing 远程主机如果没有文件则报错退出(在ansible2.4中已经默认就是yes了)
  • 拉取过来之后会在本地保存成一个嵌套目录:
    • ansible 10.0.0.205 -m fetch -a "src=~/test.txt dest=/tmp/"
    • 在本地存储为:/tmp/10.0.0.205/root/test.txt

2.2.6 command

  • 作用:
    • 直接在远程主机上执行命令
  • 注意:
    • 对于这个模块,-a中的命令不用写成键值对形式,直接指定命令即可
    • command模块使用时,-a中引号内的内容不使用shell来解析,所以要指明shell来解析(貌似指明了executable也没用)
  • 使用参数:
    • chdir=切换到指定的目录下去执行命令
      • 注意:chdir不是幂等的,也就是说执行成功之后再执行就会失败
    • executable=由哪个shell命令发起执行程序,可以指明一个新的shell
  • 使用示例:
    • 在每个远程主机上执行ifconfig命令:
      • ansible all -m command -a "ifconfig"
    • 切换目录后执行命令:
      • ansible all -m command -a "chdir=/tmp mkdir hello.dir"

2.2.7 shell

  • 作用:
    • 真正的执行shell命令的模块,可以识别命令行中的众多字符
  • 注意:
    • 这个模块可以实现众多真正shell命令行中的功能
    • 使用参数及用法与command相同
  • 识别shell命令行中的元字符的两种方法:
    • ansible 10.0.0.205 -m shell -a "/bin/bash -c  'ls -alh /tmp/wzhhg'"
    • ansible 10.0.0.205 -m shell -a "executable=/bin/bash  ls -alh /tmp/wzhhg"

2.2.8 file

  • 作用:
    • 创建文件,真正意义上来说是修改文件属性的
  • 使用示例:
    • 在指定的路径下创建一个目录:
      • ansible all -m file -a "path=/tmp/testhello.dir state=directory"
    • 在指定的路径下创建一个文件:
      • ansible all -m file -a "path=/tmp/testhello.txt state=file"
    • 创建一个符号链接文件:
      • ansible all -m file -a "src=/tmp/fstab path=/tmp/fstab.link state=link"

2.2.9 cron

  • 作用:
    • 定义任务计划
  • 使用参数:
    • day=、hour=、minute=、month=、weekday= 指定的间隔时间,默认使用的是*,为空表示是*
    • name=指明任务的名称,如果不指定名字,默认为None,删除的时候要指定名字,否则删不掉
    • user=任务为哪个用户的
    • state=任务是添加还是删除,present表示添加,absent表示删除,如果不写,默认就是present
    • job=指明任务
  • 使用示例:
    • 每隔3分钟同步一次时间:(这里虽好指定name,以便以后方便调用)
      • ansible all -m cron -a "minute=*/3  job='/usr/sbin/update 10.0.0.203 &> /dev/null'"
    • 删除刚刚添加的任务:
      • ansible all -m cron -a "minute=*/3 job='/usr/sbin/update 10.0.0.203 &> /dev/null' name=None state=absent"

2.2.10 yum

  • 作用:
    • 安装程序包
  • 使用参数:
    • name=指明程序包名
    • state=安装还是卸载,present、installed、latest都表示安装,absent、removed表示卸载
    • disable_gpg_check:安装的过程中禁用密钥检测
    • disablerepo=指明安装过程中禁用的某个仓库
    • enablerepo=指明安装过程中开启的某个仓库
  • 使用示例:
    • 安装httpd包:ansible all -m yum -a "name=httpd  state=installed"

2.2.11 service

  • 作用:
    • 管理服务
  • 使用参数:
    • name=指明服务命令,如果是CentOS7可以不用加.service
    • enabled=是否设置为开机自启动,yes或者no
    • runlevel=在哪些级别下开机自启动
    • state=服务是启动还是关闭,started表示启动,stopped表示关闭,restarted表示重启,reloaded表示平滑重载
    • pattern=指明的匹配格式,如果匹配到了这里指定的字符串就表示成功
  • 使用示例:
    • 启动nginx服务:ansible all -m service -a "name=nginx state=started"

2.2.12 script

  • 作用:
    • 执行脚本,自动把本地的脚本复制到远程主机上,并在远程主机上执行
  • 使用参数:
    • 直接指明脚本
  • 使用示例:
    • 将脚本复制到远程主机上并执行脚本
      • ansible all -m script -a "/tmp/test.sh"

2.2.13 ping

  • 使用示例:
    • ansible all -m ping --list-hosts
  • 注意:
    • 这里使用all表示ansible的hosts文件中定义的所有主机,这里也可以直接指定主机,或者用正则表达式匹配
    • 这里使用--list-hosts可以列出适配出来的主机,不真正执行

3. Ansible之playbook详解

3.1 playbook简介

3.1.1 YAML格式简介

  • 让每一台主机要执行的任务保存在一个文件中,这个文件组织成YAML格式
  • YAML:是一个可读性高,用来表达数据序列的格式,它其实是一种标记语言
  • Playbook:YAML格式,任务(task)
  • 基本数据结构:
    • 标量、数组、关联数组

3.1.2 Playbook的核心元素

  • Hosts:主机(谁负责来唱这出戏)
  • Tasks:任务列表(要唱哪几出戏)
  • Variables:变量
  • Templates:包含了模板语法的文本文件
  • Handlers:由特定条件触发的任务,要触发handlers,只需要在某个任务上加上notify
  • Roles:角色

3.1.3 playbook的基础组件

  • hosts:运行指定任务的目标主机
  • remote_user:在远程主机上执行任务的用户(在目标主机上以哪种用户的身份执行命令)
    • sudo_user:sudo到哪个用户去执行
  • tasks:任务列表
    • 模块,模块参数
    • 格式:
      • action:module arguments
      • module:arguments
      • 注意:shell和command模块后面直接跟命令,而非键值对的参数列表

3.1.4 运行playbook的方式

测试操作:

  • ansible-playbook --check
    • 只检测可能会发生的改变,但不真正执行操作,干跑
  • ansible-playbook --list-hosts
    • 列出运行任务的主机
  • ansible-playbook --syntax-check:
    • 检查语法,真正的检查语法

ansible-playbook:

  • -C:--check,检查语法,这里是干跑一遍
  • --list-hosts:列出相关主机
  • --list-tasks:列出所有任务
  • --list-tags:列出所有标签
  • --syntax-check:检查语法

特别注意:

  • 如果有一个任务在某一主机上停止了,则所有任务在所有主机上都无法完成
  • 它是按任务分派给所有主机,先执行第一个,再执行第二个,再执行第三个,一次类推

3.2 playbook文件详解

3.2.1 定义playbook文件

- hosts: all
  remote_user: root           # 以什么用户去执行任务
  tasks:                      # 指定任务列表
    - name: install redis
          yum: name=redis state=latest
    - name: copy config file
          copy: src=/root/playbooks/redis.conf dest=/etc/redis.conf
          notify: restart redis   # 触发名称为restart redis的任务,该任务在handlers中定义 
          tags: configfile        # 这里对该任务加上了名为configfile的标签
    - name: start redis
          service: name=redis state=started enabled=true
  handlers:
        - name: restart redis
          service: name=redis state=restarted

注意:

  • handlers只会在所有任务执行完成后执行。而且即使被通知了很多次,它也只会执行一次

后续操作:

  • 然后语法检查:
    • ansible-playbook --syntax-check first.yaml
  • 然后干跑一遍:
    • ansible-playbook -C first.yaml
  • 然后直接执行:
    • ansible-playbook first.yaml

定义标签:

  • 可以在playbook的yaml配置文件中的特定任务中加上一个标签,然后在执行时只调用这一个标签
  • 使用:ansible-playbook -t configfile second.yaml 这里是只执行加上了configfile标签的任务

3.2.2 handlers简介

  • 作用:任务,特定条件下触发的任务
  • 说明:收到其他任务的通知时被触发:
    • 如:notify: restart redis , 触发名称为restart redis的任务,该任务在handlers中定义
  • handlers只会在所有任务执行完成后执行,而且即使被通知了很多次,它也只会执行一次

3.2.3 variables详解

1) facts:可直接调用的变量

  • 说明:可以使用setup模块直接获取目标主机的facters
  • setup模块:
    • 作用:用来收集每一个被ansible管控的主机之上相关的环境变量
    • 使用:ansible 10.0.0.206 -m setup
    • 查看用法:ansible-doc -s setup
  • 在yaml文件中调用变量:(将变量置于双花括号内以调用)
    • - hosts: all
        remote_user: root  
        tasks:                  
        - name: copy file
              copy: content={{ ansible_env }} dest=/tmp/ansible.env  # 双花括号以调用变量

2) ansible-playbook命令的命令行中自定义变量

  • 在yaml文件中定义:
    • - hosts: all
        remote_user: root
        tasks:
              - name: install {{ pkgname }}
                yum: name={{ pkgname }} state=latest 
  • 在命令行中使用-e参数进行传递变量:
    • ansible-playbook  -e  pkgname=memcached   forth.yaml    将memcached赋值给变量package

3) Host Inventory

用户自定义变量:

  • 向不同的主机传递不同的变量:(在ansible的hosts文件中定义)
    • 格式:IP/HOSTNAME varaiable=value var2=value2
    • 示例:
      [websrvs]
      172.16.0.67  http_port=8080  my_num=10080 # 添加两个自定义变量
      172.16.0.68
    • 说明:
      • 这里定义的变量在playbook当中(也就是yaml文件中)是可以直接引用的
      • 这里定义的值在模板中也是可以直接变量引用的
  • 向组中的主机传递相同的变量:(在ansible的hosts文件中定义)
    • 格式:
      • [ groupname:vars ]
      • variable=value
    • 示例:
      [websrvs]
      172.16.0.67  
      172.16.0.68
      
      [websrvs:vars]
      http_port=8080  
      my_num=10080  
      # 表示在websrvs组中的所有主机上都定义上这里面所定义的两个变量

invertory参数:用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量

  • 定义的位置:直接写在ansible的hosts文件中远程主机的IP地址后面
    • ansible_ssh_host=使用远程主机另外的地址来连接
    • ansible_ssh_prot=使用其他的端口来连接远程主机
    • ansible_ssh_user=使用其他的用户登录,不写默认是root
    • ansible_ssh_pass
    • ansible_sudo_pass
  • 使用示例:
    • 172.16.0.67 ansible_ssh_port=22122 ansible_ssh_user=hgzero

3.2.4 templates模板

说明:文本文件,嵌套有脚本(使用模板编程语言编写)

Jinja2:

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

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

  • 使用参数:
    • src=模板文件
    • dest=基于模板生成以后的数据流,保存下来生成一个文件
    • owner=属主
    • group=属组
    • mode=权限

在配置文件中内嵌一个变量:

  • vim /root/playbooks/redis.conf.j2
    • bind {{ ansible_eno16777736.ipv4.address }}
    • 说明:可以用点号调用某个变量一个子集下的一个子集...
  • 在yaml文件中定义:
    - hosts: 172.16.0.67
      remote_user: root
      tasks:
            - name: install config file
              template: src=/root/playbooks/redis.conf.j2  dest=/tmp/redis.conf

3.3 playbook高级用法

3.3.1 条件测试

  • when语句:在task中使用,jinja2的语法格式
  • 示例:
    - hosts: websrvs
      remote_user: root
      tasks:
      - name: install httpd
        yum: name=httpd state=latest
            when: ansible_os_family == "RedHat"  # 可以用when关键字对变量进行判断
      - name: install apache2
        apt: name=apache2 state=latest
            when: ansible_os_family == "Debian"

3.3.2 循环、迭代操作

  • 使用:
    • 需要重复执行的任务,对迭代项的应用,固定变量名为"item"
    • 而后,要在task中使用with_items给定要迭代的元素列表
  • 列表方法:
    • 字符串迭代:
      - name: install {{ item}} package
        yum: name={{ itme }} state=present # 迭代with_items中的每个字符串
        with_items:
        - nginx
        - memcached
        - php-fpm
    • 字典迭代:
      - name: add some users
        user: name={{ item.name }} group={{ item.group }} state=present # 迭代with_items中的每个字典
        with_items:
        - { name: 'user11', group: 'group11' }
        - { name: 'user12', group: 'group12' }
        - { name: 'user13', group: 'group13' }

4. Ansible之role角色详解

4.1 角色(roles)简介

1) 描述:自包含的所需要的各种文件的集合

2) 角色的集合

roles/
        mysql/
        httpd/
        nginx/
        memcached/

3) 每个角色,以特定的层级目录结构进行组织(至少要有一个task,其他都是可选的)

mysql/
        files/:存放由copy或script模块等调用的文件
        templates/:template模块查找所需要模板文件的目录
        tasks/:至少应该包含一个名为main.yml的文件,其他的文件需要在此文件中通过include进行包含
        vars/:至少应该包含一个名为main.yml的文件,其他的文件需要在此文件中通过include进行包含
        meta/:至少应该包含一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系
                             其他的文件需要在此文件中通过include进行包含
        default/:设定默认变量时使用此目录中的main.yml文件
  • 注意:ansible的role的存放位置:应该放在/etc/ansible/ansible.cfg中指定的路径中

4.2 创建角色

1) 创建基本角色目录集:

  • mkdir  -pv  /etc/ansible/roles/nginx/{files,templates,tasks,vars,handlers,meta,default}

2) 编辑创建工作任务tasks文件:

vim  /etc/ansible/roles/nginx/tasks/main.yml
        - name: install nginx
          yum: name=nginx state=latest
          when: ansible_os_family == "RedHat"
        - name: install conf
          template: src=vhost1.conf.j2  dest=/etc/nginx/conf.d/vhost1.conf
          tags: conf                # 为配置任务打个标签
          notify: restart nginx     # 触发handlers中定义的restart nginx
        - name: install site home directory
          file: path={{ ngxroot }} state=directory   # 这里调用的变量被定义在了vars目录下
        - name: install index page
          copy: src=index.html  dest={{ ngxroot }}/
        - name: start nginx
          service: name=nginx state=started

3) 编辑创建模板templates文件:

vim roles/nginx/templates/vhost1.conf.j2
        server {
                listen 8080;
                server_name {{ ansible_fqdn }};
                location  /  {
                        root  "/ngin"
                }
        }

4) 编辑创建handlers文件:

vim roles/nginx/handlers/main.yml   
        - name: restart nginx      # 这里定义的内容会被notify触发
        service: name=nginx state=restarted

5) 编辑创建变量vars文件:

vim roles/nginx/vars/main.yml
        ngxroot: /ngxdata/vhost1   # 定义变量要用字典的格式,是yaml格式的字典

6) 编辑创建files文件:

vim  roles/nginx/files/index.html
        <h1>Vhost1</h1>

7) 编辑创建主执行文件:

vim  nginx.yml
        - hosts: websrvs
          remote_user: root
          roles:
          - nginx

8) 执行:

  • 直接执行:
    • ansible-playbook nginx.yml
  • 只修改配置文件:
    • ansible-playbook -t conf nginx.yml

 

posted @ 2020-06-22 13:45  Praywu  阅读(591)  评论(0编辑  收藏  举报