ansible

ansible

介绍

常用运维工具比较

  • Puppet

    • 基于Ruby开发,采用C/S架构,扩展性强,基于SSL,远程命令执行相对较弱
  • SaltStack

    • 基于Python开发,采用C/S架构,相对puppet更轻量级,配置语法使用YAML,配置脚本更简单
  • Ansible

    • 基于Python paramiko开发,分布式,无需客户端,轻量级,配置语法使用YAML及Jinja2模板语言,更强的远程命令执行操作

Ansible简介

  • Ansible基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。

  • ansible是基于模块工作的,本身没有批量部署的能力,通过运行的模块实现,ansible只是提供一种框架

  • 模块

    • connection plugins

      • 连接插件,负责和被管理端实现通信,有SSH,ZEROMQ等,默认使用SSH连接
    • host inventory

      • 主机清单,是一个配置文件里面定义管控的主机
    • modules

      • 核心模块、command模块、自定义模块等
    • plugins

      • modules功能的补充,包括连接插件,邮件插件等
    • playbook

      • 编排、定义Ansible多任务配置文件,非必需

Ansible特性

  • no agents

    • 不需要在被管控主机上安装任何客户端,更新时,只需在操作机上进行一次更新即可
  • no server

    • 无服务器端,使用时直接运行命令即可
  • modules in any languages

    • 基于模块工作,可使用任意语言开发模块
  • yaml,not code

    • 使用yaml语言定制剧本playbook
  • ssh by default

    • 基于SSH工作
  • strong multi-tier solution

    • 可实现多级指挥

Ansible工作原理

  • 在ANSIBLE管理体系中,存在"管理节点" 和 “被管理节点” 两种角色。被管理节点通常被称为"资产"
  • 在管理节点上,Ansible将AdHoc或PlayBook转换为Python脚本,并通过SSH将这些Python脚本传递到资产上
  • 在被管理服务器上依次执行,并实时的将结果返回给管理节点

Ansible执行过程

  • 1). 加载自己的配置文件,默认/etc/ansible/ansible.cfg
  • 2). 查找对应的主机配置文件,找到要执行的主机或者组
  • 3). 加载自己对应的模块文件,如command
  • 4). 通过ansible将模块或命令生成对应的临时py文件(python脚本), 并将该文件传输至远程服务器
  • 5). 给文件添加执行权限
  • 6). 对应执行用户的家目录的.ansible/tmp/XXX/XXX.PY文件
  • 7). 返回执行结果给管理节点
  • 8). 删除临时py文件,sleep 0退出

Ansible中的关键字

  • https://docs.ansible.com/ansible/2.9/reference_appendices/playbooks_keywords.html

Ansible安装

  • yum

    • yum -y install ansible
  • pip

    • yum -y install python-pip
    • pip install ansible

配置文件

配置文件查找顺序

    1. 检查环境变量ANSIBLE_CONFIG指向的路径文件(export ANSIBLE_CONFIG=/etc/ansible.cfg)
    1. ./ansible.cfg,检查当前目录下的ansible.cfg配置文件,即执行ansible命令的目录
    1. ~/.ansible.cfg,检查当前用户家目录下的隐藏.ansible.cfg配置文件
    1. /etc/ansible.cfg检查etc目录的配置文件

主配置文件

  • 路径

    • /etc/ansible/ansible.cfg
  • 参数

    • inventory = /etc/ansible/hosts

      • 资源清单inventory文件的位置
    • library = /usr/share/ansible

      • 指向存放Ansible模块的目录,支持多个目录方式,用冒号(:)隔开
    • sudo_user = root

      • 设置默认执行命令的用户
    • remote_port = 22

      • 指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
    • forks = 5

      • 并发连接数,默认为5
    • host_key_checking = False

      • 设置是否检查SSH主机的密钥,True/False (取消注释)
    • timeout = 60

      • 设置SSH连接的超时时间,单位为秒
    • log_path = /var/log/ansible.log

      • 指定存储ansible日志的文件(默认不记录日志)

Inventory

作用

  • 用于定义要管理主机的认证信息,例如ssh登录用户名、密码以及key相关信息

缺省路径

  • /etc/ansible/hosts

配置

  • 单独定义主机

    • 192.168.10.128

      • 放在主机组前面
  • 定义主机组

    • [webservers]
      192.168.10.128
      Bar.example.com
      up.example.com:5309 #指定SSH端口5309
      web1 ansible_ssh_host=1.1.1.12 #设置主机别名为web1
      www[01:50].example.com #支持通配符匹配www01,…,www50
      db-[a:f].example.com #通配符匹配db-a,db-b,…,db-f
  • 定义变量

    • [atlanta]
      host1 http_port=80 maxRequests=808
      host2 http_port=303 maxRequests=909

      • 为每个主机单独指定一些变量,这些变量可以在playbooks中使用
    • [atlanta]
      host1
      host2

[atlanta:vars] #组名:vars
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

	- 为一个组指定变量,组内每个主机都可以使用该变量
  • 组包含其他组

    • [atlanta]
      host1
      host2

[raleigh]
host3
host4

[southeast:children] #组名:children
atlanta
raleigh

[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30

Ad-Hoc

作用

  • ansible中需要快速执行、不需要保存、简单的命令

语法

  • ansible -m <module_name> -a

  • pattern

    • inventory文件里定义的主机组名,主机名,IP,别名等。支持通配符,正则

    • all

      • 表示所有的主机,
    • :

      • 多个组,组名之间用冒号隔开
    • web

      • 组名或主机名中含web的
    • webservers[0]

      • webservers组中的第一台主机, -1表示最后一台主机
      • 支持切片(正), [1:2]表示组中的第二台和第三台
  • -m module_name

    • 指定模块,默认为command
  • -a arguments

    • 传递给模块的参数
  • -i file_name

    • 指定inventory文件, 默认为/etc/ansible/hosts
  • -k

    • 询问密码.如果没有传公钥到被管理端,必须要接此选项

配置过程

    1. 在控制节点安装ansible
    1. 编辑主机清单文件,加入被管控节点
    1. 在控制节点生成密钥,把公钥传到所有的被控制节点(建议)

帮助信息

  • ansible-doc -l

    • 查看所有模块信息
  • ansible-doc module_name

    • 查看指定模块帮助信息
  • "="开头的为必选项,示例的格式为列表

Modules

command

  • 作用

    • 默认模块,支持多数shell命令,但不支持某些shell变量及管道
  • 示例

    • ansible 1.1.1.12 -a ‘hostname’

setup

  • 作用

    • 查看远程主机的基本信息

    • Facts - 用于采集被管理主机信息

      • 物理内存容量 ansible_memtotal_mb
        CPU型号 ansible_processor
        CPU核心数 ansible_processor_cores
        操作系统类型 ansible_os_family
        操作系统内核 ansible_kernel
        硬盘挂载名及容量 ansible_mounts
        服务器主机名 ansible_nodename
        服务器ipv4地址 ansible_all_ipv4_addresses
      • 信息内容中{}表示字典,[]表示列表
  • 选项

    • filter

      • 仅列出匹配到的facts, 默认值为*
  • 示例

    • ansible webservers -m setup
    • ansible webservers -m setup -a ‘filter=ansible_mounts’

ping

  • 作用

    • 测试远程主机的运行状态
  • 示例

    • ansible 1.1.1.12 -m ping

file

  • 作用

    • 文件管理
  • 选项

    • path

      • 必选项,定义文件/目录的路径,还可以写成name或dest
    • force

      • 强制创建软链接,源文件不存在或目标软链接已存在时。yes|no(默认no)
      • ansible 1.1.1.12 -m file -a ‘src=/opt/aa.txt dest=/opt/c.txt force=yes’
    • group

      • 定义文件/目录的属组
      • ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt group=tom’
    • mode

      • 定义文件/目录的权限
      • ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt mode=777’
    • owner

      • 定义文件/目录的属主
      • ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt owner=tom’
    • recurse

      • 递归设置文件的属性,只对目录有效。yes|no(默认no)
      • ansible 1.1.1.12 -m file -a ‘dest=/opt/a owner=tom mode=777 recurse=yes’
    • src

      • 被链接的源文件路径,只应用于state=link或state=hard的情况
    • state

      • file

        • 改变文件的属性(默认值)
        • ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt mode=777 state=file’
      • directory

        • 如果目录不存在,就创建目录
        • ansible 1.1.1.12 -m file -a ‘dest=/opt/a state=directory’
      • touch

        • 若文件不存在则创建,若文件已存在则更新其最后修改时间
        • ansible 1.1.1.12 -m file -a ‘dest=/opt/a.txt state=touch’
      • link

        • 创建软链接
        • ansible 1.1.1.12 -m file -a ‘src=/opt/a/b/c.txt dest=/opt/c.txt state=link’
      • hard

        • 创建硬链接
        • ansible 1.1.1.12 -m file -a ‘src=/opt/a/b/c.txt dest=/opt/d.txt state=hard’
      • absent

        • 删除文件
        • ansible 1.1.1.12 -m file -a ‘dest=/opt/d.txt state=absent’

copy

  • 作用

    • 把主控端的文件复制到远程主机
  • 选项

    • dest

      • 必选项。远程主机的目标绝对路径,如果源文件是一个目录,那该路径也必须是个目录
    • src

      • 被复制到远程主机的本地文件,绝对路径或相对路径。如果路径是一个目录,将递归复制
      • 如果src以“/”结尾,则只复制目录里的内容,如果非“/”结尾,则复制目录及目录里的内容
    • content

      • 将指定内容覆盖写入目标文件
      • ansible 1.1.1.12 -m copy -a ‘content=“kkk\n” dest=/opt/a.txt’
    • directory_mode

      • 递归设定目录的权限,默认为系统默认权限
      • ansible 1.1.1.12 -m copy -a ‘src=./a dest=/opt directory_mode=777’
    • force

      • 如果目标主机包含该文件,若内容不同则强制覆盖。yes|no(默认yes)
      • ansible 1.1.1.12 -m copy -a ‘src=./a/ dest=/opt/ force=no’
    • backup

      • 在覆盖之前,将源文件备份,备份文件包含时间信息。yes|no(默认no)
      • ansible 1.1.1.12 -m copy -a ‘src=./a/ dest=/opt/ backup=yes’
    • others

      • 所有的file模块里的选项都可以在这里使用

fetch

  • 作用

    • 从远程某主机获取(复制)文件到本地
  • 选项

    • dest

      • 用来存放文件的目录(本地路径)
    • src

      • 从远程拉取的文件,并且必须是一个file,不能是目录
  • 示例

    • ansible webservers -m fetch -a ‘dest=/opt src=/etc/passwd’

shell

  • 作用

    • 在远程主机上执行shell命令
  • 选项

    • cmd

      • 要运行的命令
    • chdir

      • 运行命令前先切换到的目录
  • 示例

    • ansible 1.1.1.12 -m shell -a ‘cat /etc/passwd |wc -l’

user

  • 作用

    • 远程主机用户管理
  • 选项

    • name

      • 要操作的用户名
    • uid

      • 设置用户的UID
    • group

      • 设置用户的基本组
    • shell

      • 设置用户登录shell
    • groups

      • 设置用户的附加组,如果设置为空,则将用户从所有附加组中退出来
    • home

      • 设置用户家目录
    • create_home

      • 创建家目录,yes|no(默认yes)
    • system

      • 创建为系统用户,yes|no(默认no)
    • state

      • present

        • 创建(默认值)
      • absent

        • 删除
      • remove

        • 当state=absent时,使用remove=yes干净的删除,默认值为no
  • 示例

    • ansible 1.1.1.12 -m user -a ‘name=lili uid=1111 group=tom groups=root shell=/bin/bash home=/root’
    • ansible 1.1.1.12 -m user -a ‘name=lili state=absent remove=yes’

cron

  • 作用

    • 远程主机计划任务管理
  • 选项

    • name

      • 计划任务条目名称
    • minute

    • hour

    • day

    • month

    • weekday

    • job

      • 要执行的命令
    • user

      • 用户
    • state

      • present

        • 创建(默认值)
      • absent

        • 删除, 会列出现有的所有的任务
  • 示例

    • ansible 1.1.1.12 -m cron -a ‘name=“shutdown” minute=0 hour=3 job=“/usr/sbin/shutdown now”’
    • ansible 1.1.1.12 -m cron -a ‘name=“shutdown” state=absent’

script

  • 作用

    • 将本地脚本传输到远程执行
  • 选项

    • chdir

      • 在执行脚本前先cd到此目录下
    • creates

      • 接一个文件名,如果此文件不存在才执行
      • ansible 1.1.1.12 -m script -a ‘./touch.sh chdir=/opt creates=/opt/a.txt’
    • removes

      • 接一个文件名,如果此文件存在才执行
      • ansible 1.1.1.12 -m script -a ‘./touch.sh chdir=/opt removes=/opt/b.txt’

service

  • 作用

    • 远程主机服务管理(el7:systemd)
  • 选项

    • name

      • 服务名称
    • state

      • started

        • 启动服务
      • stopped

        • 停止服务
      • restarted

        • 重启服务
      • reloaded

        • 重新加载配置文件
      • enabled

        • 是否开机启动 yes|no
  • 示例

    • ansible 1.1.1.12 -m systemd -a ‘name=httpd state=started’
    • ansible 1.1.1.12 -m systemd -a ‘name=httpd enabled=yes’

lineinfile

  • 作用

    • 远程主机文件编辑
  • 选项

    • dest

      • 指定要修改的文件
    • regexp

      • 正则匹配模式
    • line

      • 要增加或者修改的内容
    • insertafter

      • 在后面插入。Used with ‘state=present’
    • insertbefore

      • 在前面插入。Used with ’state=present’
    • firstmatch

      • 配合insertbefore或insertafter, 如果设置了,在第一次正则匹配到的行进行插入
    • state

      • present

        • 当匹配到时进行修改,当没有匹配到时在最后增加一行(默认)
      • absent

        • 当匹配到时进行删除
    • backrefs

      • no

        • 表示如果没有匹配到,则增加line;如果匹配成功,则替换line(默认)
      • yes

        • 表示如果没有匹配到,则不变line;如果匹配成功,则替换line
    • backup

      • 备份原文件。yes|no
  • 示例

    • ansible 1.1.1.12 -m lineinfile -a ‘path=/etc/selinux/config regexp=“^SELINUX=” line=“SELINUX=enforcing”’
    • ansible 1.1.1.12 -m lineinfile -a ‘path=/etc/sudoers regexp=“^%wheel” state=absent’

yum

  • 作用

    • 使用yum管理软件包
  • 选项

    • name

      • 要安装软件包的名字,可以带上版本号
    • state

      • present | installd

        • 安装(默认)
      • lastest

        • 安装最新版
      • absent | removed

        • 删除

package

  • 作用

    • 使用操作系统相应的软件包管理工具模块处理,如centos: yum, ubuntu: apt
  • 选项

    • name

      • 要管理的包名,可以带上版本号
    • state

      • present

        • 安装
      • absent

        • 删除
  • 示例

    • ansible 1.1.1.12 -m package -a ‘name=httpd state=present’
    • ansible 1.1.1.12 -m package -a ‘name=httpd state=absent’

unarchive

  • 作用

    • 解压缩
  • 选项

    • src

      • 必选项, 要解压的包名
    • dest

      • 必选项, 解压到哪个目录下
    • remote_src

      • no(默认)

        • 将管理机上的包传到远程主机上解压
      • yes

        • 解压远程主机上的包
  • 示例

    • ansible 1.1.1.12 -m unarchive -a ‘src=./nginx-1.12.2.tar.gz dest=/root’
    • ansible 1.1.1.12 -m unarchive -a ‘src=/opt/nginx-1.12.2.tar.gz dest=/root remote_src=yes’

template

  • 作用

    • 基于jinja2模板创建配置文件
  • 选项

    • src

      • 模板路径,先要定义模板文件
    • dest

      • 目标路径
  • 示例

    • ansbile 1.1.1.12 -m template -a 'src=/tmp/nginx.conf.j2 dest=/etc/nginx/nginx.conf

Variable

facts组件变量

  • 变量值类型

    • 字符串

      • ansible_fqdn = “web1.qf.com”
    • 列表(相当于索引数组)

      • ipv4 = [ ‘192.168.10.11’ , ‘192.168.10.100’ , ‘192.168.10.101’ ]
    • 字典(相当于关联数组)

      • tom = { ‘age’:18 , ‘sex’:‘male’ , ‘class’:‘yunjisuan’ }
  • 常用facts变量

    • 使用setup模块来获取,可直接调用

    • ansible_all_ipv4_addresses

      • 仅显示ipv4的信息 —> [“192.168.95.143”]
    • ansible_eth0[‘ipv4’][‘address’]

      • 仅显示ipv4的信息 —> eth0 的ip地址
    • ansible_devices

      • 仅显示磁盘设备信息
    • ansible_distribution

      • 显示是什么系统,例:centos,suse等
    • ansible_distribution_version

      • 仅显示系统版本
    • ansible_machine

      • 显示系统类型,例:32位,还是64位
    • ansible_eth0

      • 仅显示eth0的信息
    • ansible_hostname

      • 仅显示主机名
    • ansible_kernel

      • 仅显示内核版本
    • ansible_lvm

      • 显示lvm相关信息
    • ansible_memtotal_mb

      • 显示系统总内存
    • ansible_memfree_mb

      • 显示可用系统内存
    • ansible_memory_mb

      • 详细显示内存情况
    • ansible_swapfree_mb

      • 显示swap内存的可用内存
    • ansible_swaptotal_mb

      • 显示总的swap内存
    • ansible_mounts

      • 显示系统磁盘挂载情况
    • ansible_processor

      • 显示cpu个数(具体显示每个cpu的型号)
    • ansible_processor_vcpus

      • 显示cpu个数(只显示总的个数)
    • ansible_python_version

      • 显示python版本

通过命令行传入变量

  • ansible-playbook命令的命令行中接 “-e key=value”
  • ansible-playbook jinjia2-if.yaml -e PORT=‘’

在playbook中定义变量

  • vars:
    
    • var1: value1
    • var2: value2

在Host Inventory中定义变量

  • 向不同的主机传递不同的变量

    • ip/hostname var1=value1 var2=value2
  • 向组中的主机传递相同的变量

    • [groupname:vars]
      var1=value1
      var2=value2

通过roles传递变量

  • cat roles/nginx/defaults/main.yml

user: nginx
pkg: nginx-1.20.2.tar.gz
pkgdir: nginx-1.20.2
basedir: /usr/local/nginx

通过register定义变量

    • name: create user tom
      user:
      name: tom
      register: user_info #主机级变量
  • name: show user_info
    debug:
    var: user_info

优先级

  • 命令行传入 > playbook定义 > host主机变量 > host主机组变量 > default

PlayBook

简介

  • Playbook是ansible用于配置、部署和管理被控节点的剧本
  • 通过playbook的详细描述,执行其中的一系列 tasks ,可以让远端主机达到预期的状态
  • playbook就像Ansible控制器给被控节点列出的的一系列to-do-list ,而被控节点必须要完成
  • 对一些简单的任务,ad-hoc可以方便地解决,但对于过于复杂、需要大量的操作时,最好使用playbook
  • 类似于执行shell命令与写shell脚本,不过playbook有自己的语法格式。使用playbook可以方便的重用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码

组成

  • Target section

    • 定义将要执行 playbook 的远程主机组
  • Variable section

    • 定义 playbook 运行时需要使用的变量
  • Task section

    • 定义将要在远程主机上执行的任务列表
  • Handler section

    • 定义 task 执行完成以后需要调用的任务

YAML语法简介

  • 官方文档

    • https://docs.ansible.com/ansible/2.9/reference_appendices/YAMLSyntax.html
  • 介绍

    • Playbook 采用 YAML 语法。后缀 .yaml或 .yml
    • YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等
    • YAML格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写
  • 常用格式

    • yaml文件以—开始,以…结束,但开始和结束标志都是可选的
    • 在同一行中,#之后的内容表示注释,类似于shell,python和ruby
    • YAML中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容
    • 同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理
    • play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":“分隔表示,”:"后接空格
  • 数据类型

    • 字符串
    • 列表
    • 字典

编写

  • 基本写法


  • hosts: webservers #需执行的主机,值类型为字符串,写法与adhoc一致
    gather_facts: false #关闭Gathering Facts任务,默认开启(需调用变量时要开启)
    tasks: #定义任务列表,值的数据类型为列表

    • name: create user tom #任务描述信息,在执行过程中显示(便于排错)
      user: name=tom state=present #调用user模块,值类型为字典(写法一)
    • name: create file /tmp/tom.txt
      file: #调用file模块,值类型为字典(写法二)
      dest: /tmp/tom.txt #file模块参数
      owner: tom
      mode: 777
      state: touch
  • 变量定义及使用


  • hosts: webservers
    gather_facts: false
    vars: #自定义变量。调用变量必须先自定义或用facts中变量

    • user_name: “tom” #变量值最好使用引号
    • file_name: “tom.txt”
      tasks:
    • name: create user “{{user_name}}”
      user:
      name: “{{user_name}}” #调用变量使用 “{{}}”
    • name: touoch file “/tmp/{{file_name}}”
      file:
      dest: “/tmp/{{file_name}}” #路径调用变量写法
      state: touch
      owner: “{{user_name}}”
  • hosts: 1.1.1.12
    tasks:

    • name: str #facts中字符串变量调用方法
      shell: echo “{{ansible_architecture}}” > /tmp/facts.txt #
    • name: list #facts中列表变量调用方法
      shell: echo “{{ansible_all_ipv4_addresses[1]}}” >> /tmp/facts.txt
    • name: dict1 #facts中字典变量调用方法一
      shell: echo “{{ansible_apparmor.status}}” >> /tmp/facts.txt
    • name: dict2 #facts中字典变量调用方法二
      shell: echo “{{ansible_apparmor[‘status’]}}” >> /tmp/facts.txt
    • name: dict3 #facts中字典列表混合调用一
      shell: echo “{{ansible_mounts[0].block_used}}” > /tmp/facts.txt
    • name: dict4 #facts中字典列表混合调用二
      shell: echo “{{ansible_devices[‘dm-1’].links.uuids[0]}}” >> /tmp/facts.txt
      #若变量名含有‘-’,则改变量必须要用[‘’]调用,如[‘dm-1’]
  • 条件判断


  • hosts: all
    tasks:

    • name: create user tom
      user:
      name: tom
      #when: ansible_hostname == “web03” #写法一:当变量值等于某个字符串
      when: “‘1.1.1.11’ in ansible_all_ipv4_addresses” #写法二:当变量包含某个字符串
      #要求多条件同时满足可用and连接或写成列表的形式
    • name: create file /tmp/a.txt
      file:
      dest: /tmp/a.txt
      state: touch
      when: “‘1.1.1.12’ in ansible_all_ipv4_addresses” #when中变量调用无需“{{}}”
  • handlers


  • hosts: all
    tasks:

    • name: create user tom
      user:
      name: tom
      notify: create file #任务执行结果为changed则通知指定handler
      handlers: #所有tasks执行完后,若收到notify则执行对应handler
    • name: create file
      file:
      dest: /tmp/a.txt
      state: touch
      owner: tom
  • 循环


  • hosts: 1.1.1.12
    gather_facts: false
    tasks:

    • name: install lamp
      yum:
      name: “{{item}}” #固定变量item取值源于loop
      loop: #列表循环,写法一
      • httpd
      • mariadb-server
      • php
      • php-mysql
        #loop: [‘httpd’,‘mariadb-server’,‘php’,‘php-mysql’] #列表循环,写法二

  • hosts: 1.1.1.12
    gather_facts: false
    tasks:

    • name: create hard links
      file:
      dest: “/tmp/{{item.dest}}” #变量取值源于字典
      src: “/opt/{{item.src}}” #变量取值源于字典
      state: hard
      loop: #字典循环
      • {‘src’:‘x’,‘dest’:‘y’}
      • {‘src’:‘z’,‘dest’:‘k’}
  • tags


  • hosts: 1.1.1.12
    gather_facts: false
    tasks:

    • name: task1 #任务可以有1个或多个标签
      file:
      dest: /opt/task1
      state: touch
      #tags: t1 #写法一
      #tags: [‘t2’,‘t3’] #写法二
      #tags: #写法三
      #- t1
      #- t2
    • name: task2
      file:
      dest: /opt/task2
      state: touch
      tags: always #仅–skip-tags=always,tagged可禁止
    • name: task3
      file:
      dest: /opt/task3
      state: touch
      tags: never #仅–tags=never可启用
      • 标签

        • 自定义

        • always

          • 仅–skip-tags=always,tagged可禁止
        • never

          • 仅–tags=never可启用
        • 特殊值

          • tagged

            • 配合–tags,除never外所有带标签的运行
            • 配合–skip-tags,所有带标签的不运行
          • untagged

            • 配合–tags ,always以及所有不带标签的运行
            • 配合–skip-tags,never以及所有不带标签的不运行
          • all

            • 配合–tags ,仅never不运行
            • 配合–skip-tags,仅always运行
      • 运行

        • –tags=tag

          • 运行指定标签,always无需指定
          • ansible-playbook tags.yaml --tags=t1,t2
        • –skip-tags=tag

          • 不运行指定标签,never无需指定
          • ansible-playbook tags.yaml --tags=test --skip-tags=t2
        • 一条指令中,–tags和–skip-tags关系与,–tags或–skip-tags中多个标签关系或

  • register

    • register 是个寄存器,接收任务的返回值或者状态

  • hosts: 1.1.1.12
    tasks:

    • name: create user tom
      user:
      name: tom
      register: user_info #定义变量保存任务执行的状态信息
    • name: show user_info
      debug:
      var: user_info #输出变量内容
  • hosts: 1.1.1.12
    gather_facts: false
    tasks:

    • name: weekday_info
      shell: date +%w
      register: weekday
    • name: show weekday
      debug:
      var: weekday.stdout #状态信息中的stdout字段
    • name: do ceping every wed
      shell: echo ceping > /tmp/a.txt
      when: weekday.stdout == ‘3’ #调用register变量中的字段

执行

  • 语法检测

    • ansible-playbook --syntax-check /path/to/playbook.yaml
  • 测试运行

    • ansible-playbook -C /path/to/playbook.yaml
  • 执行

    • ansible-playbook /path/to/playbook.yaml

    • 执行结果

      • 黄色changed

        • 执行成功,系统状态发生改变
      • 绿色ok

        • 执行成功,系统保持原样
      • 红色fatal

        • 执行失败,显示错误输出(看msg)
      • 紫色WARNING

        • 警告提醒
      • 蓝色skipping

        • 跳过未执行

jinjia2简介

介绍

  • Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity
  • 它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛
  • Jinja2的语法是由variables(变量)和statement(语句)组成

variables

  • 可以替换数据

    • 如: listen {{ nginxport }};

statement

  • 可以用来创建条件和循环等

  • if语句

    • 语法

      • {% if conditional %}

        {% endif %}
      • 涉及变量要提前定义,否则报错变量未定义
      • 对于已定义的变量,其值为0或空值时为假,其他情况为真
      • vim if.yaml


  • hosts: all
    tasks:
    • template:
      src=/tmp/if.j2
      dest=/tmp/if.conf

      	- # vim /tmp/if.j2
      

{% if PORT %}
Listen {{ PORT }}
{% else %}
Listen 80
{% endif %}
- # vim /tmp/if.j2
Listen {{ PORT | default(80) }}

  • for语句

    • 语法

      • {% for item in all_items %}

        {% endfor %}
      • vim for.yaml


  • hosts: all
    tasks:
    • template:
      src=/tmp/for.j2
      dest=/tmp/host.for

      	- # vim /tmp/for.j2
      

{% for id in range(11,15) %}
192.168.10.{{ id }} web{{ id }}.test.com
{% endfor %}

	- 执行结果

		- # cat /tmp/hosts.for

192.168.10.11 web11.test.com
192.168.10.12 web12.test.com
192.168.10.13 web13.test.com
192.168.10.14 web14.test.com
192.168.10.15 web15.test.com

模板支持

  • 字符串

    • 使用单引号或双引号
  • 数字

    • 整数,浮点数
  • 列表

    • [item1, item2, …]
  • 元组

    • (item1, item2, …)
  • 字典

    • {key1:value1, key2:value2, …}
  • 布尔型

    • true/false
  • 算术运算

    • +, -, *, /, //, %, **
  • 比较操作

    • ==, !=, >, >=, <, <=
  • 逻辑运算

    • and, or, not

Templates

介绍

  • 模板是一个文本文件,嵌套有脚本,脚本使用模板编程语言(jinja2)编写
  • 通常来说,模板都是通过引用变量来运用的
  • 用于针对不同主机需要配置不同参数的场景,如配置文件

示例

  • 要求

    • nginx配置文件中工作进程按主机cpu数进行配置,分别配置不同的监听端口

    • 监听端口

      • 1.1.1.12:90
      • 1.1.1.13:8080
        1.1.1.14:8080
      • 1.1.1.15:80
  • 定义模板

    • cp /usr/local/nginx/conf/nginx.conf /tmp/nginx.conf.j2
    • vim /tmp/nginx.conf.j2

work_processes {{ansible_processor_vcpus}}
listen {{nginx_port | default(80)}} #nginx_port若未定义默认80

  • 编写资产文件

    • vim /etc/ansible/hosts

1.1.1.15

[webservers]
web2 ansible_ssh_host=1.1.1.12 nginx_port=90 #定义主机变量
1.1.1.13 #ansible_ssh_host为hosts自带变量
1.1.1.14

[webservers:vars]
nginx_port=8080 #定义主机组变量,优先级低于主机变量

  • 编写playbook

    • vim /etc/ansible/playbooks/nginx.yaml


  • hosts: all
    #vars #playbook中定义的变量优先级高于hosts
    tasks:
    • template:
      src: /tmp/nginx.conf.j2
      dest: /usr/local/nginx/conf/nginx.conf

项目实践

  • 目标

    • 通过ansible实现批量编译安装nginx
  • 环境准备

    • 本机准备安装包

      • /root/nginx-1.20.2.tar.gz
    • 本机准备配置文件模板

      • tar xf /root/nginx-1.20.2.tar.gz
        cp nginx-1.20.2/conf/nginx.conf /tmp/nginx.conf.j2
    • 远程主机卸载原有nginx,关闭80端口服务,删除nginx用户

  • 定义模板

    • # vim /tmp/nginx.conf.j2
      user {{user}}
      work_processes {{ansible_processor_vcpus}}
  • 编写资产文件

    • # vim /etc/ansible/hosts
      [nginx]
      1.1.1.12
      1.1.1.13
      1.1.1.14
  • 编写playbook

    • # vim nginx.yaml

  • hosts: nginx
    vars:

    • user: nginx
    • pkg: nginx-1.20.2.tar.gz
    • pkgdir: /tmp/nginx-1.20.2
    • basedir: /usr/local/nginx
      tasks:
    • name: 拷贝安装包
      unarchive:
      src: “/root/{{package}}”
      dest: /tmp/
    • name: 创建nginx用户
      user:
      name: “{{user}}”
      shell: /sbin/nologin
      create_home: false
      system: true
    • name: 安装依赖包
      yum:
      name: “{{item}}”
      loop:
      • gcc
      • gcc-c++
      • pcre-devel
      • openssl-devel
    • name: 编译安装
      shell:
      cmd: “{{item}}”
      chdir: “{{pkgdir}}”
      loop:
      • ./configure --prefix=“{{basedir}}” --user=“{{user}}” --group=“{{user}}” --with-http_stub_status_module --with-http_ssl_module --sbin-path=/usr/sbin/
      • make
      • make install
    • name: 拷贝配置文件
      template:
      src: /tmp/nginx.conf.j2
      dest: “{{basedir}}/conf/nginx.conf”
    • name: 测试
      shell: nginx -t
      notify: 运行
      handlers:
    • name: 运行
      shell: nginx
  • 运行playbook

    • ansible-playbook nginx.yaml --syntax-check
    • ansible-playbook nginx.yaml

Roles

简介

  • playbook存在弊端即无法实现复用,很难实现灵活的调用
  • ansible提供了一种目录树结构的编排方式,顶层目录对应roles,里面包含子目录,比如defaults、files、tasks、templates等,不同的子目录对应不同的功能
  • roles 能够根据层次型结构自动装载变量文件、tasks以及handlers等
  • 角色中在编写task时本地文件只需写文件名,不需要写路径

角色集合

  • roles目录下,可以创建多个角色目录,每个目录都是一个角色

子目录

  • 每个角色目录可以包含如下子目录,按需配置

  • tasks/

    • 用于定义各task
  • handlers/

    • 用于定义各handler
  • vars/

    • 用于定义各variable
  • defaults/

    • 用于设定默认变量,优先级最低
  • meta/

    • 定义当前角色的特殊设定及其依赖关系
  • files/

    • 存储由copy、script、unarchive模块调用的文件
  • templates/

    • 存储由template模块调用的模板文本

项目一

  • 目标

    • 通过ansible实现一键编译安装redis并部署主从复制及哨兵
  • 创建目录

    • mkdir -p /etc/ansible/playbooks/roles/redis/{defaults,files,tasks,templates}/
  • 配置hosts

    • # vim /etc/ansible/hosts
      [redis]
      1.1.1.12
      1.1.1.13
      1.1.1.14
      1.1.1.15
  • 配置files/

    • 上传redis源码安装包redis-4.0.10.tar.gz
  • 配置defaults/

    • # vim /etc/ansible/playbooks/roles/redis/defaults/main.yml
      redisPort: 6380
      senPort: 26380
      passwd: 123
      master: 1.1.1.12
      pkg: redis-4.0.10.tar.gz
      basedir: /usr/local/redis-4.0.10
  • 配置templates/

    • 准备配置文件

      • tar xf …/files/redis-4.0.10.tar.gz -C ./
      • cp redis-4.0.10/redis.conf redis.conf.j2
      • cp redis-4.0.10/sentinel.conf sentinel.conf.j2
      • rm -rf redis-4.0.10/
    • 定义模板

      • redis

        • # vim redis.conf.j2
          bind 127.0.0.1 {{ansible_ssh_host}}
          protected-mode no
          port {{redisPort}}
          daemonize yes
          pidfile “/var/run/redis_{{redisPort}}.pid”
          logfile “/var/local/redis_{{redisPort}}.log”
          {% if ansible_ssh_host != master %}
          slaveof {{master}} {{redisPort}}
          {% endif %}
          masterauth {{passwd}}
          requirepass {{passwd}}
      • 哨兵

        • vim sentinel.conf.j2

bind {{ansible_ssh_host}}
port {{senPort}}
daemonize yes
logfile “/var/log/sentinel_{{senPort}}.log”
sentinel monitor mymaster {{master}} {{redisPort}} 2
sentinel auth-pass mymaster {{passwd}}
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000

  • 配置tasks/

    • # vim /etc/ansible/playbooks/roles/redis/tasks/main.yml
  • name: 拷贝安装包
    unarchive:
    src: “{{pkg}}”
    dest: /usr/local/

  • name: 安装依赖包
    yum:
    name: “{{item}}”
    loop:

    • gcc
    • gcc-c++
  • name: 编译安装
    shell:
    cmd: make MALLOC=libc
    chdir: “{{basedir}}”

  • name: 制作软链接
    file:
    src: “{{basedir}}/src/{{item}}”
    dest: “/usr/bin/{{item}}”
    state: link
    loop:

    • redis-server
    • redis-cli
    • redis-sentinel
  • name: 拷贝配置文件
    template:
    src: “{{item.src}}”
    dest: “{{basedir}}/{{item.dest}}”
    loop:

    • {‘src’:‘redis.conf.j2’,‘dest’:‘redis.conf’}
    • {‘src’:‘sentinel.conf.j2’,‘dest’:‘sentinel.conf’}
  • name: 启动redis
    shell: redis-server “{{basedir}}/redis.conf”

  • name: 启动哨兵
    shell: redis-sentinel “{{basedir}}/sentinel.conf”
    when: ansible_ssh_host != master

  • 编写playbook

    • # vim /etc/ansible/playbooks/redis.yaml

  • hosts: redis
    roles: #表示选择部署哪个角色

    • redis

      - playbook文件和roles目录放在同一级目录中
      
  • 运行playbook

    • ansible-playbook /etc/ansible/playbooks/redis.yaml --syntax-check
    • ansible-playbook /etc/ansible/playbooks/redis.yaml
  • 目录结构

    • # tree .
      ├── redis.yaml
      └── roles
      └── redis
      ├── defaults
      │ └── main.yml
      ├── files
      │ └── redis-4.0.10.tar.gz
      ├── tasks
      │ └── main.yml
      └── templates
      ├── redis.conf.j2
      └── sentinel.conf.j2

项目二

  • 目标

    • 一键部署MySQL主从复制(传统方式)
  • 创建目录

    • mkdir -p /etc/ansible/playbooks/roles/mysql/{defaults,files,tasks,templates}/
  • 配置hosts

    • # vim /etc/ansible/hosts
      [mysql]
      1.1.1.12
      1.1.1.13
      1.1.1.14
  • 配置files/

    • # vim mysql57.repo
      [mysql57]
      name=mysql5.7
      baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-x86_64/
      enabled=1
      gpgcheck=1
      gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
  • 配置defaults/

    • # vim main.yml
      master: 1.1.1.13
      passwd: Zqs@123456
  • 配置templates/

    • # vim my.cnf.j2
      [mysqld]
      datadir=/var/lib/mysql
      socket=/var/lib/mysql/mysql.sock
      log-error=/var/log/mysqld.log
      pid-file=/var/run/mysqld/mysqld.pid
      log-bin = my-bin
      binlog_format = MIXED
      {% if ansible_ssh_host == master %}
      server-id = 1
      {% else %}
      server-id = 2
      {% endif %}
  • 配置tasks/

    • # vim main.yml
  • name: 拷贝MySQL源
    copy:
    src: mysql57.repo
    dest: /etc/yum.repos.d/

  • name: 安装MySQL
    yum:
    name: mysql-community-server

  • name: 拷贝配置文件
    template:
    src: my.cnf.j2
    dest: /etc/my.cnf

  • name: 启动MySQL
    shell:
    cmd: “{{item}}”
    loop:

    • systemctl start mysqld
    • systemctl enable mysqld
  • name: 获取初始密码
    shell: grep “password” /var/log/mysqld.log |awk ‘{print $NF}’
    register: pass1

  • name: 修改密码
    shell: mysqladmin -u root -p"{{pass1.stdout}}" password “{{passwd}}”
    tags: never

  • name: 创建复制账号
    shell: mysql -u root -p"{{passwd}}" -e “grant replication slave,replication client on . to ‘slave’@‘1.1.1.%’ identified by ‘{{passwd}}’;”
    when: ansible_ssh_host == master
    tags: never

  • name: 获取log_file
    shell: mysql -u slave -p"{{passwd}}" -h “{{master}}” -e “show master status\G” |awk NR==2’{print $2}’
    register: log_file
    when: ansible_ssh_host != master

  • name: 获取log_pos
    shell: mysql -u slave -p"{{passwd}}" -h “{{master}}” -e “show master status\G” |awk NR==3’{print $2}’
    register: log_pos
    when: ansible_ssh_host != master

  • name: slave配置AB
    shell:
    cmd: “{{item}}”
    loop:

    • mysql -u root -p"{{passwd}}" -e “change master to master_host=‘{{master}}’,master_user=‘slave’,master_password=‘{{passwd}}’,master_log_file=‘{{log_file.stdout}}’,master_log_pos={{log_pos.stdout}};”
    • mysql -u root -p"{{passwd}}" -e “start slave;”
      when: ansible_ssh_host != master
  • 编写playbook

    • # vim /etc/ansible/playbooks/mysql.yaml

  • hosts: mysql
    roles:

    • mysql
  • 运行playbook

    • ansible-playbook /etc/ansible/playbooks/mysql.yaml --syntax-check
    • ansible-playbook /etc/ansible/playbooks/mysql.yaml
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值