Ansible基础

介绍

技术 特性 适用场景 说明
Ansible - 基于Python paramiko开发
- 基于ssh 和节点进行通信
- 无需 agent
- 使用YAMLJinja2模板语言进行配置
自动化安装、配置 - 官网
- Doc
- 最新文档
- ansible-examples
- Module Index
Tower - 官网
Ansible Galaxy 是一个免费的用于查找,下载,评论各种社区开发的 Ansible 角色。
ansible-galaxy在 Ansible 1.4.2 就已经被包含了。

基本概念

概念 说明
Ansible Ansible 核心
Modules 包括 Ansible 自带的核心模块及自定义模块
Plugins 完成模块功能的补充,包括连接插件、邮件插件等
Playbooks 定义 Ansible 多任务配置文件,由 Ansible 自动执行
Inventory 定义 Ansible 管理主机的清单
playbook 是有一个或多个 play 组成的列表。
play 的主要功能在于将事先归为一组的主机装扮成事先通过 ansible 中的 task 定义好的角色。

安装 Ansible

CentOS安装Ansible

1
2
3
$ yum install epel-release
$ yum repolist
$ yum install ansible -y

Ubuntu安装Ansible

1
2
3
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible

MacOS安装Ansible

1
$ brew install ansible

运维

查看Ansible版本

1
$ ansible --version

配置主机清单

配置文件路径:/etc/ansible/hosts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 直接在主机清单中写入主机ip或主机名(适用于多主机免密登陆)
192.168.100.101
node2

# 添加主机分组(适用于多主机免密登陆)
[webgroup]
192.168.100.102
node3

# 配置用户名密码(适用于少量主机用户名密码登陆)
## ansible_ssh_port:指定 ssh 端口
## ansible_connection:指定 ansible 的连接方式
## ansible_ssh_user:指定 ssh 用户
## ansible_ssh_pass:ssh 用户登陆是认证密码
## ansible_sudo_pass:指明 sudo 时候的密码
[mons]
192.168.100.11 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=vagrant
192.168.100.12 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=vagrant
192.168.100.13 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=vagrant

[osd]
192.168.100.11 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=vagrant
192.168.100.12 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=vagrant
192.168.100.13 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=vagrant

[webservers]
www[01:50].examples.com

[databases]
db-[a:f].examples.com

# 分组嵌套
[group1]
host1
host2

[group2]
host3
host4

[group3]
host5
host6

## 分组嵌套:group4 包含 group1 和 group2
[group4:children]
group1
group2

## 分组嵌套:group5 包含 group3 和 group4
[group5:children]
group3
group4

配置免密登陆

1
2
3
4
5
6
7
8
9
10
# 生成密钥
$ ssh-keygen -t rsa -f /root/.ssh/id_rsa -N ‘’

# 同步密钥到远程主机
## 语法:
$ ssh-copy-id 远程主机名称
$ ssh-copy-id 192.168.0.11

# 测试
$ ssh 192.168.0.11

取消指纹认证

1
2
3
4
$ vi /etc/ansible/ansible.cfg
##### 修改如下内容 #####
host_key_checking = False
##### 内容结束 #####

ansible.cfg 常用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 资源清单inventory文件的位置
inventory = /root/ansible/hosts

# 存放Ansible模块的目录
library = /usr/share/ansible

# 设置默认情况下Ansible最多能有多少个进程同时工作,默认设置最多5个进程并行处理
forks = 5

# 设置默认执行命令的用户,也可以在playbook中重新设置这个参数
sudo_user = root
## 注意:新版本已经作了修改,如ansible2.4.1下已经为:
default_sudo_user = root

# 指定连接被关节点的管理端口,默认是22
remote_port = 22

# 设置是否检查SSH主机的指纹
host_key_checking = False
## 可选项:True、False

# 设置SSH连接的超时间隔,单位是秒
timeout = 20

# 存储Ansible日志的文件
log_path = /var/log/ansible.log
## Ansible系统默认是不记录日志的
## 需要注意,执行Ansible的用户需要有写入日志的权限,模块将会调用被管节点的syslog来记录,口令是不会出现的日志中的

# 在使用ssh公钥私钥登录系统时候,使用的密钥路径
private_key_file=/path/to/file.pem

开发

变量

引用变量

关键字 说明
include 引入 role 中 main.yml 包含的 vars
include_vars 引入 role 中 main.yml 包含的 vars

变量优先级

命令行传递 > roles tasks > roles vars > playbook > group_vars > hosts > roles default

模块

模块说明

常用模块 说明
command - ansible 默认模块
不指定 -m 参数时,使用的就是 command 模块。
- command 模块命令的执行不是通过 shell 执行,所以,像'<'、'>'、'|'、'&' 操作都不可以,也不支持管道。
- 无法批量执行命令
copy 实现主控端向目标主机拷贝文件,类似 scp 功能。
cron 配置远程主机的计划任务。
fetch 将远程主机中的文件拷贝到本机中
file 设置文件属性。
filesystem 块设备上创建文件系统
firewalld 管理防火墙
get_url 实现远程主机下载指定 url 到本地,支持 sha256sum 文件校验。
groups 指定用户的附属组
lineinfile 后端引用的正则表达式来替换
mount 挂载分区
npm Manage node.js packages with npm
ping 测试主机连通性。
replace 通过正则表达式替换文本内容
rpm_key Adds or removes a gpg key from the rpm db
script 使用 script 模块可以在本地写一个脚本,在远程服务器上执行。
selinux 管理 Selinux 状态
service 管理远程主机系统服务。
注意:被启动的服务,必须可以使用 service 命令启动或关闭。
setup 收集远程主机上可用变量,这些变量用于playbooks
shell - 使用 shell 模块,在远程命令通过 /bin/sh 来执行。
在终端输入的各种命令方式,都可以使用。
- 如果待执行的语句少,可以直接写在一句话中。
- 如果在远程待执行的语句比较多,可以写成一个脚本,通过 copy 模块传到远端,然后再执行。但这样涉及两次 ansible 调用,对于这种需求,可以考虑使用 script 模块。
stat 获取远程文件信息。
synchronize 文件、目录同步
sysctl 远程主机 sysctl 配置。
systemd Manage services
template 使用 jinja2模版语言处理
timezone 设置时区
unarchive 解压缩
uri 和 WebServices 交互
user 远程主机用户管理
wait_for Waits for a condition before continuing
yum linux 平台软件包管理。
yum_repository 添加或删除 yum repositories

语法

1
2
3
4
5
6
7
8
9
10
11
12
# 语法
$ ansible <主机清单中的ip或分组名称> -m <模块名称> -a "模块参数"
## -v,-verbose:详细模式,如果命令执行成功,输出详细的结果(-vv -vvv -vvvv)。
## -i PATH,-inventory=PATH:指定 host 文件的路径,默认在/etc/ansible/hosts。
## -f NUM,-forks=NUM:NUM 是一个整数,默认是5,指定 fork 开启同步进程的个数。
## -m Name,-module-name=Name:指定使用的 module 名称,默认使用 command 模块。
## -a,Module_ARGS:指定 module 模块的参数。
## -k,ask-pass:提示输入 ssh 的密码,而不是使用基于 ssh 的密钥认证。
## -sudo:指定使用 sudo 获得 root 权限
## -K,-ask-sudo-pass:提示输入 sudo 密码,与 -sudo 一起使用。
## -u USERNAME,-user=USERNAME:指定移动端的执行用户。
## -C,-check:测试此命令执行会改变什么内容,不会真正的去执行。

ansible-doc 命令

1
2
3
4
5
6
# 列出所有的模块列表
$ ansible-doc -l

# 查看指定模块的参数
$ ansible-doc -s <模块名>
## -s,--snippet:片段

Filter

Filter 说明
ipaddr filter -

Playbook

playbook 中定义任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
- hosts: webservers
user: root
# 定义变量
vars:
## 定义简单变量
http_port: 80
max_clients: 200
## 定义复杂变量
foo:
filed1: one
filed2: two
# 把变量放在单独的文件中
var_files:
- vars/server_vars.yml

tasks:
# 普通任务
- name: task description
module_name: module_args
# 带 notify 的任务
- name: task description
module_name: module_args
notify:
- handler1
- name: insert firewalld rule for httpd
# 使用简单变量(通过 {{变量名}} 引用变量)
firewalld: port={{ http_port }}/tcp permanent=true state=enabled immediate=yes
# handlers
# 使用复杂变量
- name: echo complex vars
command: echo "{{foo.field1}} or {{foo['field1']}}"
# 注册变量(把运行结果当做变量使用)
- name: register var
- shell: ls
## 把执行结果注册到变量中的关键字是 register
register: result
ignore_errors: True
- shell: echo "{{result.stdout}}"
- handlers:
- name: handler1
service:

ansible-playbook 执行命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ ansible-playbook site.yml
## --list-hosts: 查看该脚本影响哪些主机
## -f: 并行执行脚本的数量
## -C, --check: 并不在远程主机上执行,只是测试。
## -i PATH, --inventory=PATH:资产的文件路径
## --flush-cache: 清除 fact 缓存
## --list-hosts: 列出匹配的远程主机,并不执行任何动作
## -t, TAGS, --tags=TAGS: 运行指定的标签任务
## --skip-tags: 跳过指定的 notify。
## --verbose: 查看输出的细节

# 执行标签为 packages 的任务
$ ansible-playbook example.yml --tags "packages"

# 跳过标签为 configuration 的任务
$ ansible-playbook example.yml --skip-tags "configuration"

流程控制语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 条件判断语句 when
tasks:
- name: "shutdown Debian falvored systems"
command: /sbin/shutdown -t now
when: ansible_os_family == "Debian"
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/something_else
when: result|skipped

# loop 循环
## with_items:用于迭代的 list 类型变量
vars:
somelist: ["testuser1","testuser2"]
tasks:
- name: add several user
user: name={{ item }} state=present groups=wheel
with_items: "{{ somelist }}"

# 对文件列表使用循环
## with_fileglob 可以以非递归的方式来模拟匹配单个目录中的文件
tasks:
- file: dest=/etc/fooapp state=directory
- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
with_fileglob:
- /playbooks/files/fooapp/*

# 使用 block 块

# 使用标签
## always: 如果没有明确指定不执行 always 标签,那么 always 标签对应的任务始终会被执行
## tagged: 执行所有标记了标签的任务,无论标记的标签名字是什么
## untagged: 执行所有没有标记标签的任务,无论标记的标签名字是什么
## all: 执行所有任务
tasks:
- yum: name={{ item }} state=installed
with_items:
- httpd
tags:
- packages

流程控制

Role

Role 的目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# site.yml内容如下:
---
- hosts: webservers
hosts:
roles:
- myrole

# role的目录结构如下
site.yml # site.yml 中调用 role
roles/ # 存放 role
|———— myrole # role 的名称是 myrole
|———— defaults # 存放默认的变量,用于放置一些需要被覆盖的变量,优先级最低
|———— main.yml
|———— files # 存放需要同步到异地服务器的源码文件及配置文件
|———— handlers # 当资源发生变化时需要进行的操作。比如重启服务、重新加载配置文件。
|———— main.yml
|———— meta # 存放角色定义
|———— main.yml
|———— README.md # 说明文件
|———— templates # 存放模板文件
|———— tasks # 存放 playbook 的目录需要执行的任务。
|———— main.yml # 主入口文件,采用import_tasks关键字在main.yml中导入其他yml文件。
|———— tests
|———— inventory.yml
|———— test.yml
|———— vars # 存放一些不想被覆盖的变量,优先级较高
|———— main.yml

role 和 tasks 的执行顺序

pre_tasks > role > task > post_tasks

导入

关键字 说明
include 旧版关键字,不建议使用
include_tasks 建议使用 include_tasks 关键字替代 include 关键字。
只能使用free-form的方式引用任务列表文件。
动态引入
import_tasks 引入任务列表文件。
静态引入
import_playbook 引入整个playbook,建议使用 import_playbook 替代 include 关键字。

Role的依赖

1
2
3
--- 
dependencies:
- { role: common,name :"NameInDb"}

插件

插件类型

插件类型 说明
Action 插件 和模块的使用方法类似,只不过执行目标不是远程主机,而是在 Ansible 的控制节点上
Cache 插件 为 Facts(主机变量)提供缓存,以避免多次执行 Playbook 时在搜集 Facts 上有过度的时间开销
Callback 插件 Ansible 执行 Playbook后,提供额外的行为。例如,将执行结果发送到 Email 中,或者将执行结果写入 log 中,等等。
connection 插件 Ansible 为管理节点和远程主机之间提供了更多的连接方法。默认的连接协议是基于 paramiko 的 SSH协议。paramiko 对于大多数的基本需求已经够用,如果有高级的需求,则可以通过自定义插件来提供 SNMP、Message bug 等传输协议。
filters 插件 为过滤器提供更多的功能
lookup 插件 为 lookup 提供更多的功能
strategy 插件 为执行 Playbook 提供更多的执行策略
shell 插件 通过 shell 插件可以提供远程主机上更多类型的 shell(csh、ksh、tcsh)等的支持。
test 插件 为 Ansible Jinja2 test 提供更多的功能
vars 插件 可以将 inventory/playbook/ 命令行中的变量注入 Ansible 中。通过 vars 插件,可以实现更多方式的变量注入。

ansible-galaxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 初始化一个新角色的基本文件结构
$ ansible-galaxy init rolename

# 从一个文件安装多个角色
$ ansible-galaxy install -r requirements.txt

# requirements.txt示例
##### 内容开始 #####
username1.foo_role username2.bar_role
# 想得到指定版本(tag)的role,使用下面的语法
username1.foo_role,version username2.bar_role,version
##### 内容结束 #####

# Ansible 1.8 之后支持通过 YMAL 语法的 requirements 文件实现,但是必须以 yml为文件扩展名。
$ ansible-galaxy install -r requirements.yml

常用开发示例

安装依赖

1
2
3
4
5
6
7
8
9
10
11
- name: install dependence
yum:
name:
- gcc-c++
- pcre
- pcre-devel
- zlib
- zlib-devel
- openssl
- openssl-devel
state: present

复制、解压

1
2
3
4
5
6
7
8
9
- name: copy erlang binary to the target host
copy:
src: erlang-22.2.5-1.el7.x86_64.rpm
dest: /usr/local/erlang-22.2.5-1.el7.x86_64.rpm

- name: unzip nginx binary to the target host
unarchive:
src: nginx-1.16.1.tar.gz
dest: /usr/local/

安装

1
2
3
4
- name: install erlang
yum:
name: /usr/local/erlang-22.2.5-1.el7.x86_64.rpm
state: present

配置

1
2
3
4
- name: 配置 elasticsearch 
template:
src: elasticsearch.yml.j2
dest: /etc/elasticsearch/elasticsearch.yml

执行 shell

1
2
3
4
- name: make && make install
shell: make && make install
args:
chdir: /usr/local/nginx-1.16.1

启动&开机启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- name: start nginx
shell: 'nohup /usr/local/nginx/sbin/nginx &'

- name: 服务重载
systemd:
daemon-reload: yes

- name: 启动 && 开机启动 elasticsearch
service:
name: elasticsearch
state: started
enabled: yes

- name: 等待 elasticsearch 启动
wait_for:
# host: 0.0.0.0
port: 9200
delay: 10

检查&输出结果

1
2
3
4
5
6
7
8
9
- name: 检查 elasticsarch 
uri:
url: "http://127.0.0.1:{{ http_port }}"
# url: "http://{{ ansible_default_ipv4.address }}:{{ http_port }}"
register: curlOutput

- name: 输出检查结果
debug:
var: curlOutput

开源项目

常见错误

notify 不执行

在 copy 配置文件时,如果源文件和目标文件一样时,copy命令是不执行的。
如果 copy 命令不执行,那么 notify 将不调用 handler。
解决办法是先删除原有配置文件,再拷贝。

环境变量不生效

  • ansible这类远程执行的non-login shell 并不会加载/etc/profile和/.bash_profile下的环境变量,只是加载/.bashrc和/etc/bashrc。
  • 如果需要在ansible中执行需要特定环境变量的命令,可以在执行前source一下~/.bash_profile, 或者将环境变量写在~/.bashrc 。

ansible 调用 shell脚本执行达不到预期

问题描述

1
2
3
4
5
- name: 启动 skywalking 
shell: './startup.sh'
args:
executable: /bin/bash
chdir: '/usr/local/skywalking/bin/'

ansible 中可以正常执行,并且有返回结果。可是实际并没有启动。 到ssh 中是可以正常启动的。

解决办法

1
2
3
4
5
- name: 启动 skywalking 
shell: 'nohup ./startup.sh &'
args:
executable: /bin/bash
chdir: '/usr/local/skywalking/bin/'

参考

坚持原创技术分享,您的支持将鼓励我继续创作!
0%