Ansible简介
我是在学习部署okd与ansible相遇的,我从来没有特地去学习这么一款工具,只是需要的时候查阅一下官方文档,ansible真的足够简单,可以想使用命令行一样使用ansible,当然ansible也可以做一些不简单的事情。
Ansible是一种IT自动化工具。它可以配置系统,部署软件以及协调更高级的IT任务,例如连续部署或零停机滚动更新。Ansible的主要目标是简单和易用。它还非常关注安全性和可靠性,其特点是活动部件最少,使用OpenSSH进行运输(使用其他运输方式和拉动模式作为替代方案)以及一种围绕人员(即使是不熟悉的人)可审核性设计的语言。
Ansible概念
控制节点(Control node)
任何装有Ansible的机器。可以从任何控制节点调用/usr/bin/ansible或来运行命令和运行playbook /usr/bin/ansible-playbook。可以将任何安装了Python的计算机用作控制节点-笔记本电脑,共享台式机和服务器都可以运行Ansible。但是,不能将Windows计算机用作控制节点。您可以有多个控制节点。
受控节点(Managed nodes)
使用Ansible管理的网络设备(和/或服务器)。受管节点有时也称为“主机”。未在受管节点上安装Ansible。
管理清单(Inventory)
受控节点的列表。清单文件有时也称为“主机文件”。您的清单可以为每个受管节点指定信息,例如IP地址。库存还可以组织受管节点,创建和嵌套组以便于扩展。默认是使用/etc/ansible/hosts
文件作为管理清单文件。在运行时可以通过-i
自定义hosts地址。详细请参考:管理清单
模块(Modules)
将执行代码单元Ansible。从管理特定类型的数据库上的用户到管理特定类型的网络设备上的VLAN接口,每个模块都有特定的用途。您可以通过ansible命令调用单个模块,也可以在playbook中调用多个不同的模块。详细请参考:所有模块
任务(Tasks)
Ansible中的行动单位。您可以使用临时命令一次执行一个任务。
PlayBook
已保存任务的有序列表,因此您可以按此顺序重复运行这些任务。剧本可以包括变量以及任务。剧本采用YAML编写,易于阅读,编写,共享和理解。要了解有关剧本的更多信息,请参阅关于Playbook
安装Ansible
ansible的安装非常简单,CentOS下安装:yum install -y ansible
,Ubantu下安装: sudo apt update && sudo apt install software-properties-common && sudo apt-add-repository --yes --update ppa:ansible/ansible && sudo apt install ansible
更多系统安装ansible请参考Installing Ansible
配置文件
ansible配置文件有两个ansible.cfg
和 hosts
,前者为ansible软件配置,如常见的第一次访问host_key_checking,连接超时时间。后者为批量执行的受控机配置和变量设置。
ansible.cfg
ansible.cfg 配置文件优先级:
- ANSIBLE_CONFIG (环境变量配置)
- ansible.cfg(当前目录,存在风险,不会主动加载)
- ~/.ansible.cfg(当前用户主目录)
- /etc/ansible/ansible.cfg
ansible会安装以上列表并使用第一个找到的配置文件,可以通过ansible-config list
和ansible-config dump --only-changed
查看ansible配置情况
常用的ansible.cfg
文件内容如下:
[defaults]
log_path = /var/log/ansible.log
forks = 20
host_key_checking = False
retry_files_enabled = False
deprecation_warnings = False
nocows = True
remote_user = root
roles_path = roles/
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /etc/ansible/facts
fact_caching_timeout = 600
callback_whitelist = profile_tasks
inventory_ignore_extensions = secrets.py, .pyc, .cfg, .crt, .ini
timeout = 30
[inventory]
unparsed_is_failed=true
[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=600s
timeout = 10
control_path = %(directory)s/%%h-%%r
以上配置文件,主要配置了日志路径、远程用户信息、超时时间等。更多信息请参考:ansible.cfg example和ansible configuration。
hosts
管理清单(host文件)默认在/etc/ansible/hosts
,可以通过命令行 -i <path>
参数进行指定,-i
参数可以多次指定,也就是说,ansible支持多个hosts文件同时使用。host文件支持ini
和yaml
两种格式。
ini文件:
mail.example.com
[webservers]
foo.example.com
bar.example.com
[dbservers]
one.example.com
two.example.com
three.example.com
yaml格式:
all:
hosts:
mail.example.com:
children:
webservers:
hosts:
foo.example.com:
bar.example.com:
two.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
这两个文件的内容是等价的,当你需要多级结构时,推荐使用yaml,否则ini将更加方便。host文件中存在2个默认组all
和ungrouped
。前者包含了每一个主机,后者则是除了all
没有分组的。如示例中的mail.expample.com
,一个host可以存在于多个组里面,如two.example.com:
ansible 支持添加一个范围的host:
在INI文件中:
[webservers]
www[01:50].example.com
在yaml文件中:
webservers:
hosts:
www[01:50].example.com:
表示1-50的主机,此外host文件支持字符顺序如:
[databases]
db-[a:f].example.com
host文件支持添加变量,如:
在INI文件中:
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909
在YAML文件中:
atlanta:
host1:
http_port: 80
maxRequestsPerChild: 808
host2:
http_port: 303
maxRequestsPerChild: 909
对于一些像非标准的ssh端口,可以在hostname后面添加port:
badwolf.example.com:5309
但是ansible可以通过openssh的连接去找到并使用这些端口。
连接的变量也可以通过host变量描述:
localhost ansible_connection=local
other1.example.com ansible_connection=ssh ansible_user=myuser
other2.example.com ansible_connection=ssh ansible_user=myotheruser
host文件支持别名
INI文件:
jumper ansible_port=5555 ansible_host=192.0.2.50
yaml文件
hosts:
jumper:
ansible_port: 5555
ansible_host: 192.0.2.50
在命令行或者playbook文件中可以通过别名使用对应的host,在上面的例子中指定了端口号。
host支持组变量,相当于每一个host都继承了组变量:
INI文件:
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
YAML文件:
atlanta:
hosts:
host1:
host2:
vars:
ntp_server: ntp.atlanta.example.com
proxy: proxy.atlanta.example.com
不过这会导致一个问题:一个host在多个组,且多个组都设置同一个变量。这将引起冲突,ansible将按照字符顺序选择最后一个(尽量避免这种问题出现),ansible支持通过ansible_group_priority
修改优先级,默认值为1。具体规则参考 rules for merging
此外,host文件支持多重组变量集成,通过:children
或children:
分别在INI和YAML来使用:
INI文件:
[atlanta]
host1
host2
[raleigh]
host2
host3
[southeast:children]
atlanta
raleigh
[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2
[usa:children]
southeast
northeast
southwest
northwest
YAML文件:
all:
children:
usa:
children:
southeast:
children:
atlanta:
hosts:
host1:
host2:
raleigh:
hosts:
host2:
host3:
vars:
some_server: foo.southeast.example.com
halon_system_timeout: 30
self_destruct_countdown: 60
escape_pods: 2
northeast:
northwest:
southwest:
hosts文件支持变量文件的添加,分别对应host
变量和group_vars
,hosts的变量文件存放位置可以在/etc/ansible/group_vars/
和/etc/ansible/host_vars/
,如:
/etc/ansible/group_vars/raleigh # can optionally end in '.yml', '.yaml', or '.json'
/etc/ansible/group_vars/webservers
/etc/ansible/host_vars/foosball
同样ansible支持以组名作为目录:
/etc/ansible/group_vars/raleigh/db_settings
/etc/ansible/group_vars/raleigh/cluster_settings
ansible也支持多个hosts文件在指定目录里:
inventory/
openstack.yml # configure inventory plugin to get hosts from Openstack cloud
dynamic-inventory.py # add additional hosts with dynamic inventory script
static-inventory # add static hosts and groups
group_vars/
all.yml # assign variables to all hosts
然后运行:ansible-playbook example.yml -i inventory
ansible 有很多内置变量,如: ssh连接变量,docker,local,详见:inventory parameters
hosts文件支持很多插件:Inventory Plugins
hosts文件同样支持动态功能:dynamic inventory
控制模式
ansible 在运行相关任务的时候,即通过ansible
或者在编写ansible-playbook的文件,指定哪些受控主机需要执行任务的时候。可以通过以下通用模式指定:
描述 | 模式 | 目标主机 |
---|---|---|
所有主机 | all(*) | |
一个主机 | host1 | |
多个主机 | host1:host2(host1,host2) | |
一个分组 | ins | |
分组并集 | ins:nodes | 所有在ins加上所有在nodes的主机 |
分组差集 | ins:!nodes | 所有在ins但不在nodes的主机 |
分组交集 | ins:&nodes | 所有在ins也在nodes的主机 |
可以像这样:ins:nodes:&infra:!master
,表示ins和nodes并且都在infra且不是master的hosts
受控模式同样支持通配符:
192.0.\*
\*.example.com
\*.com
one*.com:dbservers
在模式中使用变量,可以在 ansible-playbook
使用-e
注入变量
webservers:!:&
在模式中使用数组角标,比如存在ins:
[ins]
master
infra
nodes
可以通过数组角标来指定host:
ins[0] # master
ins[-1] # nodes
ins[0:2] # ini[0],ins[1]
ins[1:] # infra nodes
ins[:3] # master,infra,nodes
在模式中使用正则匹配,以~
开头
~(web|db).*\.example\.com
临时命令(命令行)
ansible拥有开箱即用的功能,只要配置好了上面两个文件运行命令行ansible all -m ping
即可以查看各受控主机的状态。
临时命令用于快速批量执行命令:
ansible [模式] -m [模块] -a "[模块参数]"
ansible在不使用-m
指定模块时,默认使用command模块,默认情况下ansible使用5个并发进程,当你想指定进程数时可以通过-f
,通过-u
指定执行用户,通过--become
提升用户权限:
ansible atlanta -a "/sbin/reboot" -f 10 -u username --become 。
常见模块
管理文件
复制文件:
ansible ins -m copy -a "src=/etc/hosts dest=/tmp/hosts`
创建文件:
ansible ins -m file -a "dest=/srv/foo/b.txt mode=600 owner=bryce group=bryce"
创建目录:
ansible ins -m file -a "dest=/path/to/c mode=755 owner=bryce group=bryce state=directory"
删除文件:
ansible ins -m file -a "dest=/path/to/c state=absent"
管理包
- 安装包:
ansible ins -m yum -a "name=java-1.8.0-openjdk state=present"
- 确保包为最新:
ansible ins -m yum -a "name=java state=latest"
- 确保未安装包:
ansible webservers -m yum -a "name=java state=absent"
管理用户和组
- 创建用户:
ansible all -m user -a "name=bryce password=<crypted password here>"
- 删除用户:
ansible all -m user -a "name=bryce state=absent"
管理服务
- 启动服务:
ansible ins -m service -a "name=httpd state=started"
- 停止服务:
ansible ins -m service -a "name=httpd state=stopped"
收集信息
ansible all -m setup
Playbooks
playbooks是ansible的配置,部署和编排语言。真正具有生产力的搬砖工具。
在介绍playbook之前,我们先来看看一个playbook的文档结构
这是我一个安装ElasticSearch的简单例子:
.
├── elasticsearch.yml
├── roles
│ ├── after_install
│ │ └── tasks
│ │ └── main.yml
│ ├── certs
│ │ └── tasks
│ │ └── main.yml
│ ├── elasticsearch
│ │ ├── tasks
│ │ │ ├── config_elasticsearch.yml
│ │ │ ├── install_elasticsearch.yml
│ │ │ ├── main.yml
│ │ │ └── redhat.yml
│ │ └── templates
│ │ ├── elasticsearch
│ │ ├── elasticsearch.yml
│ │ └── jvm.options
│ └── user
│ └── tasks
│ └── main.yml
└── vars
└── elasticsearch.yml
包含了运行主文件elasticsearch.yml、roles文件夹、vars变量文件夹。roles文件包含了多个模块的任务,其中elasticsearch用到了模板。
基础
hosts和users
每一个playbook都需要声明hosts和user,用户可以在每一个task上指定也可以在全局指定。become
用于提升权限
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
become: yes
tasks列表
在上面的tasks:
表示一系列需要执行的任务,如:
tasks:
- name: enable selinux
command: /sbin/setenforce 1
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
- name: Copy ansible inventory file to client
copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
owner=root group=root mode=0644
- name: create a foo.conf file
template:
src: templates/foo.j2
dest: /etc/foo.conf
变量
在playbook任何地方都可以使用两个花括号{{}}
注入变量,但是需要注意yaml语法陷阱,在yaml使用变量时,需要将变量所在位置连续字符用""
包裹。
变量的定义
变量可以定义在hosts文件中定义在playbook中,也可以引用变量文件:
- hosts: ins
vars:
http_port: 80
vars_files:
- /vars/external_vars.yml
也可以在任务中注册变量:
- hosts: ins
tasks:
- shell: /usr/bin/foo
register: foo_result
ignore_errors: True
- shell: /usr/bin/bar
when: foo_result.rc == 5
ansible关键字不能定义为变量,关键字:
add, append, as_integer_ratio, bit_length, capitalize, center, clear, conjugate, copy, count, decode, denominator, difference, difference_update, discard, encode, endswith, expandtabs, extend, find, format, fromhex, fromkeys, get, has_key, hex, imag, index, insert, intersection, intersection_update, isalnum, isalpha, isdecimal, isdigit, isdisjoint, is_integer, islower, isnumeric, isspace, issubset, issuperset, istitle, isupper, items, iteritems, iterkeys, itervalues, join, keys, ljust, lower, lstrip, numerator, partition, pop, popitem, real, remove, replace, reverse, rfind, rindex, rjust, rpartition, rsplit, rstrip, setdefault, sort, split, splitlines, startswith, strip, swapcase, symmetric_difference, symmetric_difference_update, title, translate, union, update, upper, values, viewitems, viewkeys, viewvalues, zfill
系统变量
ansible有一些内置的变量
ansible_facts
可以通过ansible hostname -m setup
查看,引用{{ ansible_facts['devices']['xvda']['model'] }}
hostvars
运行的主机变量groups
是hosts中所有组(和主机)的列表。这可用于枚举组中的所有主机。group_names
是当前主机所在的所有组的列表(数组)。inventory_hostname
Ansible的hosts文件中配置的主机名的名称
模板
ansible的模板使用的是Jinja2,具体可以参考模板(Jinja2)
使用了模板即可以,在使用template模块时,渲染模板文件。使得模板文件符合自己的要求
常见的语法
循环:
[{% for host in groups[elasticsearch_hosts] %}'{{ host }}'{% if not loop.last %},{% endif %}{% endfor %}]
判断:
{% if ip == inventory_hostname %}
echo {{ loop.index - 1 }} > {{install_dir}}/{{data_dir}}/myid
{% endif %}
加减乘除:
{{(groups[elasticsearch_hosts] | length)//2+1 }} # 获取长度除2加1
条件执行
条件执行可以在tasks上使用when
:
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
when 支持多个关键字in
or
==
and
is not defined
!=
循环
用于多次重复执行任务
简单循环列表:
- name: add several users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
# 或者 loop: '{{vars}}'
任务重试:
- shell: /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10
详情参考:loop
阻塞块
块允许对任务进行逻辑分组以及进行中的错误处理。您可以应用于单个任务的大多数内容(循环除外)都可以应用于块级,这也使设置任务通用的数据或指令变得更加容易。这并不意味着该指令会影响块本身,而是被块所包含的任务继承。即,何时将应用于任务,而不是块本身.
tasks:
- name: Install, configure, and start Apache
block:
- name: install httpd and memcached
yum:
name:
- httpd
- memcached
state: present
- name: apply the foo config template
template:
src: templates/src.j2
dest: /etc/foo.conf
- name: start service bar and enable it
service:
name: bar
state: started
enabled: True
when: ansible_facts['distribution'] == 'CentOS'
become: true
become_user: root
ignore_errors: yes
常用技巧及模块
tasks支持很多模块如command
、shell
、copy
、template
等
tasks 还有一个简单的写法:action: template src=templates/foo.j2 dest=/etc/foo.conf
执行playbook:ansible-playbook site.yml --limit datacenter2
命令行工具
ansible 拥有多个命令行工具其中包括ansible
和ansible-playbook
。
ansible
ansible参数:
usage: ansible [-h] [--version] [-v] [-b] [--become-method BECOME_METHOD]
[--become-user BECOME_USER] [-K] [-i INVENTORY] [--list-hosts]
[-l SUBSET] [-P POLL_INTERVAL] [-B SECONDS] [-o] [-t TREE] [-k]
[--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
[-c CONNECTION] [-T TIMEOUT]
[--ssh-common-args SSH_COMMON_ARGS]
[--sftp-extra-args SFTP_EXTRA_ARGS]
[--scp-extra-args SCP_EXTRA_ARGS]
[--ssh-extra-args SSH_EXTRA_ARGS] [-C] [--syntax-check] [-D]
[-e EXTRA_VARS] [--vault-id VAULT_IDS]
[--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
[-f FORKS] [-M MODULE_PATH] [--playbook-dir BASEDIR]
[-a MODULE_ARGS] [-m MODULE_NAME]
pattern
详细信息:ansible 常用选项
ansible-config
详细信息:ansible-config
ansible-console
详细信息:ansible-console
ansible-doc
详细信息:ansible-doc
ansible-galaxy
用于管理共享库
详细信息:ansible-galaxy
ansible-inventory
用于管理hosts文件
详细信息:ansible-inventory
ansible-playbook
用于运行ansible-playbook相关文件
常用参数:
usage: ansible-playbook [-h] [--version] [-v] [-k]
[--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
[-c CONNECTION] [-T TIMEOUT]
[--ssh-common-args SSH_COMMON_ARGS]
[--sftp-extra-args SFTP_EXTRA_ARGS]
[--scp-extra-args SCP_EXTRA_ARGS]
[--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
[--flush-cache] [-b] [--become-method BECOME_METHOD]
[--become-user BECOME_USER] [-K] [-t TAGS]
[--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D]
[-i INVENTORY] [--list-hosts] [-l SUBSET]
[-e EXTRA_VARS] [--vault-id VAULT_IDS]
[--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
[-f FORKS] [-M MODULE_PATH] [--list-tasks]
[--list-tags] [--step] [--start-at-task START_AT_TASK]
playbook [playbook ...]
详细信息:ansible-playbook
ansible-pull
建立远程副本
详细信息:ansible-pull
ansible-vault
加密ansible文件
详细信息:ansible-vault
总结
本文简单介绍了ansible的概念,使用方法以及相关注意事项。
本博客所有文章除特别声明外,均采用: 署名-非商业性使用-禁止演绎 4.0 国际协议,转载请保留原文链接及作者。