目录

  • 一、概述
  • 二、 安装
  • 2.1 控制端
  • 2.2 被控制端
  • 2.3 连接测试(控制端)
  • 三、Inventory管理
  • 3.1 简介
  • 3.2 命令
  • 3.3 服务器匹配
  • 3.4 Inventory行为参数
  • 四、ansible模块
  • 4.1 基础功能
  • 4.1.1 ping模块
  • 4.1.2 远程命令模块
  • 4.2 文件操作
  • 4.2.3 file模块
  • 4.2.4 copy模块
  • 4.2.5 unarchive模块
  • 4.2.6 stat模块
  • 4.3 系统服务
  • 4.3.1 user/group模块
  • 4.3.2 cron模块
  • 4.3.3 yum模块
  • 4.3.4 service模块
  • 4.4 其他
  • 4.4.1 get_url模块
  • 五、剧本playbook
  • 5.1 yaml语法
  • 5.2 playbook写法
  • 5.2.1 常规演示
  • 5.2.2 附加选项
  • 5.3 命令行运行playbook
  • 5.4 role


一、概述

  • ansible:python编写的自动化引擎,实现了批量系统配置、批量程序部署、批量运行命令等
  • 优点:
  • 安装简单:被控端无需安装任何软件
  • 基于SSH配置:加密通信,安全
  • 模块、playbook及role:模块话操作、分享平台、批量命令编辑
  • 命令格式:ansible 服务器匹配 -m 模块名 -a "参数"

二、 安装

2.1 控制端

  • 代码示例
# centos
yum install ansible -y

2.2 被控制端

  • docker模拟被控制端
# 无操作服务权限:避免报错无法获取D总线连接,如果需要用host网络加参数--network host
docker run -itd --name centos7 --privileged centos:7 init 
# 进入docker容器
docker exec -it centos7 bash
# 安装systemctl
yum install initscripts -y
# 安装网络工具:如ping、ifconfig
yum install net-tools -y
# 安装ssh
yum install openssh-server -y
# 安装epel
yum install epel-release

偷懒测试:被控制端为本机,域名为localhost或者IP127.0.0.1,不用输入密码

  • centos系统SSH设置
# /etc/ssh/sshd.conf
# 允许ssh密码登陆:打开此两行
PasswordAuthentication yes
PermitRootLogin yes

>>> systemctl restart sshd
# 修改root密码:两遍,不显示输入
>>> passwd

2.3 连接测试(控制端)

  • /etc/ansible/hosts
# 控制主机列表
[test]
# 密码包含特殊符号,需要使用双引号,第三节详解
172.17.0.4 ansible_user=root ansible_password="xxx"

官方配置文件夹:优先/etc/ansible、次优先/root/.ansible

  • 命令
# 指定主机列表、指定模块(此处ping以ssh连接目标机测试)
# become即权限提升,即Linux中的sudo
>>>  ansible test -m ping -become
172.17.0.4 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

报错:“msg”: "Failed to connect to the host via ssh
解决:删除/root/.ssh/known_host

三、Inventory管理

3.1 简介

  • Inventory:管理的服务器集合
  • hosts文件指定
  • 默认:/etc/ansible/hosts
  • 命令行指定:当前目录下查找ansible test -i hosts -m ping
  • 配置文件指定(常用):/etc/ansible/ansible.cfg中[defaults]标签

3.2 命令

  • /etc/ansible/hosts修改如下
mail.doubi.com
[test]
172.17.0.4

[webservers]
api.doubi.com
doubi.com

[dbservers]
one.doubi.com
two.doubi.com

[common:children]
webservers
dbservers

批量写法:web[1:10].doubi.com,代表 web1.doubi.com到web10.doubi.com

  • 代码示例
# 显示所有的服务器
>>> ansible all --list-hosts
  hosts (6):
    172.17.0.4
    mail.doubi.com
    api.doubi.com
    doubi.com
    one.doubi.com
    two.doubi.com

# 显示指定组的服务器
>>> ansible webservers --list-hosts
  hosts (2):
    api.doubi.com
    doubi.com

# 显示所有common写法组的服务器
>>> ansible common --list-hosts
  hosts (4):
    api.doubi.com
    doubi.com
    one.doubi.com
    two.doubi.com

3.3 服务器匹配

  • 规则列表

规则

含义

192.168.0.1或web.doubi.com

单服务器匹配,若多个用冒号分隔

webservers

匹配组名,多个用冒号分隔

all或’*’

匹配所有

webservers:!dbservers

在web组不在db组,&替换!表示又在…又在…

192.168.0.*

通配符法

webserver[1:2]

索引号匹配组中服务器

~(web|db).*.doubi.com

以~开头的表示正则表达式匹配

3.4 Inventory行为参数

  • 行为参数列表

名称

默认值

描述

ansible_host

主机的名称

SSH目的主机名或IP

ansible_user

当前用户

SSH连接的用户名

ansible_port

22

SSH连接的端口号

ansible_ssh_private_key_file

none

连接使用的私钥,也可以在ansible.cfg中指定

ansible_python_interpreter

/usr/bin/python

使用哪个python解释器

  • /etc/ansible/hosts
# 定义SSH登陆用户名、登陆密码
172.17.0.6 ansible_user=root  ansible_password="xxx"
  • 定义服务器变量
# 定义单个服务器变量,后续yaml引用
# 当前服务器也可以当作远程服务器来管理
127.0.0.1 mysql_port=3306

[db]
one.doubi.com
two.doubi.com
# 定义组服务器变量
[db:vars]
mysql_port=3306

四、ansible模块

4.1 基础功能

4.1.1 ping模块

  • 功能:测试SSH服务器连通状况,非icmp的ping测试
  • 代码示例
# 如下表示SSH连接服务器正常
>>> ansible localhost -m ping
localhost | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

4.1.2 远程命令模块

  • 功能:在远程Linux服务器上执行命令
  • 代码示例
# command(默认模块):不可使用管道
>>> ansible test -a 'ls'
172.17.0.4 | CHANGED | rc=0 >>
anaconda-ks.cfg

# shell模块(一):可以使用管道,修改root密码
>>> ansible test -m shell -a "echo 123 | passwd --stdin root"
172.17.0.4 | CHANGED | rc=0 >>
Changing password for user root.
passwd: all authentication tokens updated successfully.


# shell模块(二):运行服务器上的脚本(绝对路径)
ansible test -m shell -a '/root/123.sh'
172.17.0.4 | CHANGED | rc=0 >>
123.sh
anaconda-ks.cfg

docker:如果用docker-compose管理docker,可以用copy模块和shell模块进行操作

4.2 文件操作

4.2.3 file模块

  • 功能:操作远程服务器上的文件和目录
  • 参数列表

参数名

解释

path

文件、文件夹路径

recurse

递归设置文件属性,只对文件夹有效,开启recurse=yes

src、dest

创建链接时使用,state=link/hard,源文件或者目录\目标文件或者目录

mode、owner、group、attributes

指定远程主机文件及文件夹的权限、所有者、所有组、特殊属性

state

状态包括:

file:文件,文件若不存在不会创建

link:软链接

directory:文件夹,文件夹不存在则创建

hard:硬链接

touch:创建文件,若存在则更新访问时间和修改时间

absent:删除文件、链接、文件夹

force

强制创建软连接:开启force=yes使用场景:1、源文件不存在之后会建立;2、目标软连接已存在,会先取消旧的后创建新的

  • 用法示例
# 创建软连接
>>> ansible test -m file -a 'src=/root/a.sh dest='/root/b.sh' state=link'
172.17.0.4 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "dest": "/root/b.sh", 
    "gid": 0, 
    "group": "root", 
    "mode": "0777", 
    "owner": "root", 
    "size": 12, 
    "src": "/root/a.sh", 
    "state": "link", 
    "uid": 0
}

# 创建目录
>>> ansible 远程host -m file -a 'path=路径 state=directory'

# 创建文件
>>> ansible 远程host -m file -a 'path=路径 state=touch'

# 创建文件并指定owner,group,mode等
>>> ansible 远程host -m file -a 'path=目录 state=touch owner=拥有者 group=所属组 mode=权限'

# 递归修改owner,group,mode
>>> ansible 远程host -m file -a 'path=目录 recurse=yes owner=拥有者 group=所属组 mode=权限 recurse=yes'

# 删除目录(强制删除其内文件)
>>> ansible 远程host -m file -a 'path=目录 state=absent'
# 删除文件
>>> ansible 远程host -m file -a 'path=路径 state=absent'

4.2.4 copy模块

  • 功能:将管理端文件或目录拷贝到远程服务器上
  • 参数列表

参数名

解释

src

管理端的文件或目录,目录可相对目录dir/test,目录末尾有/表示目录内文件,无/表示文件夹,一级目录若为空则不拷贝

dest

被管理端目标目录或者文件的绝对路径

force

默认yes:若文件md5值不同则强制覆盖被管理端文件或文件夹,no:只有在目标主机不存在此文件时才创建

backup

拷贝动作执行之前,先备份被管理端原始文件,原文件名.backup,默认no

directory_mode

递归设置目录权限,默认为系统默认权限

其他

file模块里所有选项都可以

4.2.5 unarchive模块

  • 功能:拷贝压缩包到远程,再解压缩
  • 参数列表

参数名

解释

src

tar源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需设置copy=no

dest

远程主机上的目标绝对路径

mode

设置解压缩后的文件权限

exec

列出需要排除的目录和文件

remote_src

设置remote_src=yes为解包目标上已经存在的档案

owner

解压后文件或目录的属主

group

解压后的目录或文件的属组

  • 操作示例
# 在远程主机上解压文件并设置权限
ansible test -m unarchive -a 'src=/srv/tomcat8/apache-tomcat.tar.gz \
dest=/usr/local copy=no mode=0755'

# 解压管理机上的压缩文件到远程主机并设置权限
ansible test -m unarchive -a "src=/tmp/install/zabbix.tar.gz \
dest=/tmp/ mode=0755 copy=yes"

4.2.6 stat模块

  • 功能:获取远程服务器文件信息
  • 参数列表

参数名

解释

path

必选项,文件或目录绝对路径

atime/ctime/mtime

访问时间、修改时间、属性修改时间

uid/gid

用户和组ID

checksum

文件的校验和

4.3 系统服务

4.3.1 user/group模块

  • 功能:管理远程服务器上的user和group
  • 参数列表

参数名

解释

参数名

解释

name

操作的用户名或群组名

comment

用户描述信息

createhome

创建家目录,默认yes

home

指定用户的家目录

group

创建用户主组

groups

指定用户组 或 附属组添加,覆盖式添加

system

默认创建普通用户no,系统用户yes

append

添加一个新的组

uid

指定用户id

gid

指定群组id

password

指定用户的密码,此处需转换明文密码

update_password

修改用户密码,配合always使用

shell

设置用户的shell,非登陆用户/sbin/nologin

expire

指定用户过期时间戳,Linux查询date -d2020-12-31 +%s

state

增删用户或群组,默认为present新建,absent删除

force

强制删除

  • 用法示例
# 创建用户
ansible 远程host -m user -a "user=test group=root"
# 创建无登陆权限无home目录的用户
ansible 远程host -m user -a "user=test shell=/sbin/nologin createhome=no"

# 删除用户:1 不删除home文件夹 2 删除文件夹
ansible 远程host -m user -a "name=test state=absent"
ansible 远程host -m user -a 'name=test state=absent remove=yes'

# 用户增组:test用户新增nginx组,默认组test,附加组nginx
ansible 远程host -m user -a "name=test append=yes groups=nginx"
# 修改默认组:默认组nginx,附加组也为nginx
ansible 远程host -m user -a "name=test group=nginx"
# 修改附加组:默认组nginx,附加组也为nginx
ansible 远程host -m user -a "name=test groups=test"

#################################################################
# 设置用户密码:ansible不认明文密码,需设置加密密码
pip3 install passlib
# 将123加密:返回密文
python3 -c "from passlib.hash import sha512_crypt; \
print(sha512_crypt.encrypt('123'))"
# 设置密码
ansible 远程host -m user -a "name=duke password=密文"

# 变更密码
ansible 远程host -m user -a "name=duke password=密文 update_password=always"

#################################################################
# 增组
ansible 远程host -m group -a "name=test"

# 删组
ansible 远程host -m group -a "name=test state=absent"

4.3.2 cron模块

  • 功能:管理远程服务器上的计划任务
  • 参数列表

参数名

解释

name

计划任务名称,会以注释的方式写入文件

cron_file

替换客户端该用户的任务计划的文件

minute

分( 0-59 ,* ,*/5 ),(具体第几分,每分,每5分钟),计划任务的最小单位

hour

时( 0-23 ,* ,*/5 )

day

日( 1-31 ,* ,*/5 )

month

月( 1-12 ,* ,*/5 )

weekday

周( 0-6 或 1-7 ,* )

special_time

reboot(重启后)、yearly(每年)、monthly(每月)、weekly(每周)、daily(每天)、hourly(每时),不写时间是每分

job

任务命令内容,要有state=present

backup

修改删除之前先备份,默认 no,备份位置为 /temp

user

指定操作哪一个用户的 cron

state

指定创建或删除任务:present、absent

计划任务执行时机:crond 命令每分钟检查是否有要执行的工作,有则执行, 新建 cron 任务,不会马上执行,至少要过 2 分钟后才可以,可重启 cron 立即执行

  • 操作示例
# 查看被管理机的计划任务列表
>>> ansible test -a "crontab -l"
# 查看被管理机
>>> ansible test -a "systemctl status crond"

# 管理机上操作如下命令设置计划任务
# 新增计划任务:每三天的1:05和1:15分执行一次
ansible test -m cron -a "name='check fix time' minute=5,15 hour=1 \
day=*/3 job='/root/test.sh'"
# 特殊写法:每天的
ansible test -m cron -a "name='check daily' special_time=daily \
job='/root/test.sh'"

# 删除计划任务
ansible test -m cron -a "name='check reboot' state=absent"

4.3.3 yum模块

  • 功能:管理远程服务器上的软件的安装、升级、卸载,支持红帽.rpm软件的管理
  • 参数列表

参数名

解释

conf_file

设定远程yum执行时所依赖的yum配置文件

disable_gpg_check

安装软件包之前是否坚持gpg key;

name

需要安装的软件名称,支持软件组安装;

update_cache

安装软件前更新缓存;

enablerepo

指定repo源名称;

skip_broken

跳过异常软件节点;

state

软件包状态:安装present、最新latest、卸载absent

  • 代码示例
# 安装软件前先更新缓存
ansible test -m yum -a "name=nmap state=present update_cache=yes"
# 安装rpm
ansible test -m yum -a "name=http://nginx.org/.../na.rpm state=present"

# 卸载软件
ansible test -m yum -a "name=nmap state=absent"

4.3.4 service模块

  • 功能:管理远程服务器的服务
  • 参数列表

参数名

解释

enabled

开机启动,默认no

name

服务名称

state

服务状态:started, stopped, restarted, reloaded

  • 操作示例
# 开启crond服务,并设置开机启动
ansible test -m service -a "name=crond state=started enabled=yes"
# 重新加载配置文件
ansible test -m service -a "name=crond daemon_reload=yes"

4.4 其他

4.4.1 get_url模块

  • 功能:用于从http、ftp、https服务器上下载文件(类似于wget)
  • 参数列表

参数名

解释

url

必选项,下载的URL,url=http://...

dest

必选项,文件绝对路径,若为目录,采用服务器提供的文件名

checksum

文件校验码,checksun=md5:...

backup

如果本地已存在,备份本地文件

timeout

下载超时时间,默认10s

url_password、url_username

主要用于需要用户名密码进行验证的情况

headers

以格式“key:value,key:value”为请求添加自定义HTTP标头

五、剧本playbook

  • yaml:JSON格式属于YAML的子格式,后端流行配置文件格式
  • 语法特点: 缩进为两个空格,禁tab,大小写敏感,#为注释

5.1 yaml语法

  • 数据类型

写法

注释

name:duke

字符串字典

male:yes

字典布尔值

age:18

字典数字

birthday:2020-01-01

字典日期

time:2018-02-17T15:02:31+08:00

+后面为时区

parent: ~

null写法

- list

列表,首元素为字符串[‘list’]

- auth:yes

列表,首元素为字典[{‘auth’:True}]

5.2 playbook写法

5.2.1 常规演示

  • python解析yaml
# pip3 install pyyaml
import yaml

with open('test.yml','r') as f:
	# 解析yaml文件为字典,loader指定默认加载器,否则报错TypeError
    config= yaml.load(f, Loader=yaml.FullLoader)
    # 输出如下
    print(config)
  • /root/test.yml
# yml文件以三个横杠开篇
---
# - 为列表标识,默认以map格式包住各个元素,即[{},{},{}]
# 列表索引值为0
# hosts\tasks为必选项
- 
  hosts: dbservers
  # yaml附加选项,此处为是否允许权限提升
  become: yes
  tasks:
    # 经测试,-与name同行效果一样
    - 
      name: install nmap
      # 模块名称作为键,参数作为值
  	  # 多参数换行写法
      yum : 
        # 使用变量的写法
        #   针对5.2.2循环name: "{{ item }}"
        name: nmap 
        state: present 
        update_cache: yes
    
# 列表索引值为1
- 
  hosts: webservers
  tasks:
    # 以下为tasks[0]
    - 
      name: change mode
      copy: src=/tmp/data.txt dest=/tmp/data.txt
    # 以下为tasks[1]
    - 
      # 以下为tasks[1]['name']返回'make file'
      name: make file
      file: path=/root/data.txt state=touch
  • python解析后输出
[
	{
	'hosts': 'dbservers', 
	'become': True, 
	'become_method': 'sudo', 
	'tasks': 
		[
			{'name': 'install nmap', 
			'yum': 'name=nmap state=present update_cache=True' }
		]
	}, 
	{
	'hosts': 'webservers', 
    'tasks': 
	    [
		    {'name': 'change mode', 
		    'copy': 'src=/tmp/data.txt dest=/tmp/data.txt'}, 
		    {'name': 'make file', 
		    'file': 'path=/root/data.txt state=touch'}
	    ]
    }
]

5.2.2 附加选项

  • 权限
# 指定执行play的用户,默认用当前用户连接远程服务器
---
- hosts: webservers
  remote_user: duke
###########################################
# 细分特定task用户
---
- hosts: dbservers
  tasks:
    - name: test connection
      ping:
      remote_user: duke
###########################################
# 常用:全局采用一个用户,特定任务用管理员权限
---
- hosts:dbservers
  remote_user: duke
  tasks:
    - service: name=nginx state=started
      become: yes
      become_method: sudo
  • 通知notify
---
- hosts: webservers
  tasks:
    - name: 确定apache已安装且是最新版
      yum: name=httpd state=latest
    
    - name: 拷贝apache配置文件
      copy: src=/root/httpd.conf dest=/etc/httpd.conf
      # 若当前task改变了服务器,则触发通知notify
      notify:
        # 匹配handler中的对应name
        - 重启apache

    - name: 确定apache已经运行
      service: name=httpd state=started 
    
    handlers:
      - name: 重启apache
        service: name=httpd state=restarted

handler触发时机:在playbook所有任务执行完成后再执行,多次触发仅执行一次
功能:官方推荐用来重启服务或服务器

  • 变量var
---
- hosts: webservers
  # 变量写法一:变量较少
  vars:
    mysql_port: 80
  # 变量写法二:变量较多
  vars_files:
    - /vars/external_vars.yml
  tasks:  
    - name: 生成apache配置文件
      # 模版模块:前者是jinja2模版,后者是目标服务器文件位置
      # jinjia2模版可以直接使用vars中的变量
      template: src=/root/httpd.j2 dest=/etc/httpd.conf
  • external_vars.yml内容:

--- password: 123 somevar: somevar ...

  • jinja2语法:详见Python运维(五)
  • facts变量:自动获取远程服务器参数,不需设置直接可使用,可由ansible all -m setup查看,嵌套数据获取ansible_eth0.ipv4.address
  • 循环
---
- hosts: webservers
  tasks: 
    - name: 批量安装软件
      # item会从下面的loop中依次读取
      yum: name={{ item }} state=latest update_cache=yes
      loop:
        - python3 
        - net-tools
  • 条件判断
---
- hosts: webservers
  tasks:
    - command: /usr/bin/ls
      # 将此task的返回值保存到result变量中
      register: result
      # 如果遇到报错,忽略,继续执行后续task,否则直接跳出
      ignore_errors: yes

    - ping:
      when: 
        # 提取变量result中的返回码
        - result.rc==0
        # facts变量可直接使用,见上变量注释
        - ansible_os_family=="RedHat"

    # debug模块:会在控制端终端打印变量
    # 以下语句效果相同
    #   - debug: msg={{ result }} 或
    #   - debug:
    #.      msg: "{{result}}"
    - debug: var=result

5.3 命令行运行playbook

  • 命令写法及注释
# 执行yml文件,远程主机目录默认/etc/ansible/hosts
# 参数随后添加,见下表
ansible-playbook test.yml 
# 每进行一个任务等待用户确认继续
ansible-playbook test.yml --step
  • 参数列表

写法

注释

- T 或–timeout

设置建立SSH超时时间

–private-key 密钥路径

设置SSH连接的私钥文件

-i host文件路径

指定host文件位置,默认/etc/ansible/hosts

–list-hosts

列出playbook的匹配服务器列表

–list-tasks

列出playbook的任务列表

–syntax-check

检查playbook语法

–check

检查当前playbook是否会修改远程服务器

5.4 role

  • 概述:roles是将playbook各项进行拆分,并形成模块化目录组织结构,还可以从线上社区仓库下载最受欢迎的role
  • 特点
  • 专一性:一个role只包含一个单一、明确的操作
  • 非必需性:role的每个文件夹都不是必须的,按需删除
  • 简洁性:编写playbook时可以引用role大幅简化配置
  • role管理命令
# 初始化一个roles的目录结构:默认在当前文件夹创建
ansible-galaxy init /root/.ansible/roles/websrvs

# 安装线上nginx的roles:https://galaxy.ansible.com
ansible-galaxy install geerlingguy.nginx

# 列出已安装的roles
ansible-galaxy list

# 卸载roles
ansible-galaxy remove geerlingguy.nginx
  • 新建的role目录结构
# galayx默认下载到/root/.ansible/roles目录下
# 在此roles目录下运行init命令
/root/.ansible/roles/websrvs/
├── defaults			# 默认可被覆盖的变量
│   └── main.yml
├── files				# 静态文件,可拷贝进目标服务器
├── handlers			# 所有handler
│   └── main.yml
├── meta				# role依赖
│   └── main.yml
├── README.md			# 说明文件
├── tasks				# 任务列表
│   └── main.yml
├── templates			# jinja2模版
├── tests				# 测试区域
│   ├── inventory
│   └── test.yml
└── vars				# 不可被覆盖的变量
  • 所有main.yml
# main将当前文件夹的a.yml和b.yml按顺序插入进来
---
- include: a.yml
- include: b.yml
  • playbook的role写法
# /root/.ansible/site.yml
---
- hosts: webservers
# 直接写文件夹名称 
- roles:
    - geerlingguy.nginx
    - websrvs
  • 运行:ansible-playbook site.yml