跳到主要内容
版本:1.0

进阶

Ansible 是一个易读非常好的自动化运维开发语言以及技术体系,它基于 Python,提供数千个管理基础设施的模块,用户无需深厚的技术背景,也可以完成服务器部署、网络配置、云资源管理等相关的工作。它自动化能力,可大大降低技术复杂性,帮助企业减少重复劳动,让聪明的人专注于核心业务。

ansible

安装

安装

主控端

安装之前,需了解是否具备安装条件:

操作系统要求:Red Hat, Debian, CentOS, macOS, any of the BSDs等,不支持Windows Python要求:Python 2 (version 2.7) or Python 3 (versions 3.5 and higher) installed

条件具备之后,只需要一条命令即可安装:

pip install ansible

yum install ansible

apt install ansible
受控端
  • 采用 SSH(默认为SFTP)与 Control Node 通信,如果SSH不可用,通过修改 ansible.cfg 更改通信协议
  • Python支持:Python 2 (version 2.6 or later) or Python 3 (version 3.5 or later).

配置项

Ansible 作为一个自动化解决方案包,与其他成熟的软件系统一样,支持自定义各种环境参数。

配置项不仅可通过 ansible.cfg 文件进行定义,大多数参数也可通过 ANSIBLE_ 开头的环境变量进行配置:

export ANSIBLE_SUDO_USER=root

运行 cat /etc/ansible/ansible.cfg 文件,便可以查看几乎所有的配置项。

# config file for ansible -- https://ansible.com/
# ===============================================

# nearly all parameters can be overridden in ansible-playbook
# or with command line flags. ansible will read ANSIBLE_CONFIG,
# ansible.cfg in the current working directory, .ansible.cfg in
# the home directory or /etc/ansible/ansible.cfg, whichever it
# finds first

[defaults]

# some basic default values...

#inventory = /etc/ansible/hosts
#library = /usr/share/my_modules/
#module_utils = /usr/share/my_module_utils/
#remote_tmp = ~/.ansible/tmp
#local_tmp = ~/.ansible/tmp
#plugin_filters_cfg = /etc/ansible/plugin_filters.yml
#forks = 5
#poll_interval = 15
#sudo_user = root
#ask_sudo_pass = True
#ask_pass = True
#transport = smart
#remote_port = 22
#module_lang = C
#module_set_locale = False

# plays will gather facts by default, which contain information about
# the remote system.
#
# smart - gather by default, but don't regather if already gathered
# implicit - gather by default, turn off with gather_facts: False
# explicit - do not gather by default, must say gather_facts: True
#gathering = implicit

# This only affects the gathering done by a play's gather_facts directive,
# by default gathering retrieves all facts subsets
# all - gather all subsets
# network - gather min and network facts
# hardware - gather hardware facts (longest facts to retrieve)
# virtual - gather min and virtual facts
# facter - import facts from facter
# ohai - import facts from ohai
# You can combine them using comma (ex: network,virtual)
# You can negate them using ! (ex: !hardware,!facter,!ohai)
# A minimal set of facts is always gathered.
#gather_subset = all

# some hardware related facts are collected
# with a maximum timeout of 10 seconds. This
# option lets you increase or decrease that
# timeout to something more suitable for the
# environment.
# gather_timeout = 10

# Ansible facts are available inside the ansible_facts.* dictionary
# namespace. This setting maintains the behaviour which was the default prior
# to 2.5, duplicating these variables into the main namespace, each with a
# prefix of 'ansible_'.
# This variable is set to True by default for backwards compatibility. It
# will be changed to a default of 'False' in a future release.
# ansible_facts.
# inject_facts_as_vars = True

# additional paths to search for roles in, colon separated
#roles_path = /etc/ansible/roles

# uncomment this to disable SSH key host checking
#host_key_checking = False

# change the default callback, you can only have one 'stdout' type enabled at a time.
#stdout_callback = skippy


## Ansible ships with some plugins that require whitelisting,
## this is done to avoid running all of a type by default.
## These setting lists those that you want enabled for your system.
## Custom plugins should not need this unless plugin author specifies it.

# enable callback plugins, they can output to stdout but cannot be 'stdout' type.
#callback_whitelist = timer, mail

# Determine whether includes in tasks and handlers are "static" by
# default. As of 2.0, includes are dynamic by default. Setting these
# values to True will make includes behave more like they did in the
# 1.x versions.
#task_includes_static = False
#handler_includes_static = False

# Controls if a missing handler for a notification event is an error or a warning
#error_on_missing_handler = True

# change this for alternative sudo implementations
#sudo_exe = sudo

# What flags to pass to sudo
# WARNING: leaving out the defaults might create unexpected behaviours
#sudo_flags = -H -S -n

# SSH timeout
#timeout = 10

# default user to use for playbooks if user is not specified
# (/usr/bin/ansible will use current user as default)
#remote_user = root

# logging is off by default unless this path is defined
# if so defined, consider logrotate
#log_path = /var/log/ansible.log

# default module name for /usr/bin/ansible
#module_name = command

# use this shell for commands executed under sudo
# you may need to change this to bin/bash in rare instances
# if sudo is constrained
#executable = /bin/sh

# if inventory variables overlap, does the higher precedence one win
# or are hash values merged together? The default is 'replace' but
# this can also be set to 'merge'.
#hash_behaviour = replace

# by default, variables from roles will be visible in the global variable
# scope. To prevent this, the following option can be enabled, and only
# tasks and handlers within the role will see the variables there
#private_role_vars = yes

# list any Jinja2 extensions to enable here:
#jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n

# if set, always use this private key file for authentication, same as
# if passing --private-key to ansible or ansible-playbook
#private_key_file = /path/to/file

# If set, configures the path to the Vault password file as an alternative to
# specifying --vault-password-file on the command line.
#vault_password_file = /path/to/vault_password_file

# format of string {{ ansible_managed }} available within Jinja2
# templates indicates to users editing templates files will be replaced.
# replacing {file}, {host} and {uid} and strftime codes with proper values.
#ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}
# {file}, {host}, {uid}, and the timestamp can all interfere with idempotence
# in some situations so the default is a static string:
#ansible_managed = Ansible managed

# by default, ansible-playbook will display "Skipping [host]" if it determines a task
# should not be run on a host. Set this to "False" if you don't want to see these "Skipping"
# messages. NOTE: the task header will still be shown regardless of whether or not the
# task is skipped.
#display_skipped_hosts = True

# by default, if a task in a playbook does not include a name: field then
# ansible-playbook will construct a header that includes the task's action but
# not the task's args. This is a security feature because ansible cannot know
# if the *module* considers an argument to be no_log at the time that the
# header is printed. If your environment doesn't have a problem securing
# stdout from ansible-playbook (or you have manually specified no_log in your
# playbook on all of the tasks where you have secret information) then you can
# safely set this to True to get more informative messages.
#display_args_to_stdout = False

# by default (as of 1.3), Ansible will raise errors when attempting to dereference
# Jinja2 variables that are not set in templates or action lines. Uncomment this line
# to revert the behavior to pre-1.3.
#error_on_undefined_vars = False

# by default (as of 1.6), Ansible may display warnings based on the configuration of the
# system running ansible itself. This may include warnings about 3rd party packages or
# other conditions that should be resolved if possible.
# to disable these warnings, set the following value to False:
#system_warnings = True

# by default (as of 1.4), Ansible may display deprecation warnings for language
# features that should no longer be used and will be removed in future versions.
# to disable these warnings, set the following value to False:
#deprecation_warnings = True

# (as of 1.8), Ansible can optionally warn when usage of the shell and
# command module appear to be simplified by using a default Ansible module
# instead. These warnings can be silenced by adjusting the following
# setting or adding warn=yes or warn=no to the end of the command line
# parameter string. This will for example suggest using the git module
# instead of shelling out to the git command.
# command_warnings = False


# set plugin path directories here, separate with colons
#action_plugins = /usr/share/ansible/plugins/action
#become_plugins = /usr/share/ansible/plugins/become
#cache_plugins = /usr/share/ansible/plugins/cache
#callback_plugins = /usr/share/ansible/plugins/callback
#connection_plugins = /usr/share/ansible/plugins/connection
#lookup_plugins = /usr/share/ansible/plugins/lookup
#inventory_plugins = /usr/share/ansible/plugins/inventory
#vars_plugins = /usr/share/ansible/plugins/vars
#filter_plugins = /usr/share/ansible/plugins/filter
#test_plugins = /usr/share/ansible/plugins/test
#terminal_plugins = /usr/share/ansible/plugins/terminal
#strategy_plugins = /usr/share/ansible/plugins/strategy


# by default, ansible will use the 'linear' strategy but you may want to try
# another one
#strategy = free

# by default callbacks are not loaded for /bin/ansible, enable this if you
# want, for example, a notification or logging callback to also apply to
# /bin/ansible runs
#bin_ansible_callbacks = False


# don't like cows? that's unfortunate.
# set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1
#nocows = 1

# set which cowsay stencil you'd like to use by default. When set to 'random',
# a random stencil will be selected for each task. The selection will be filtered
# against the `cow_whitelist` option below.
#cow_selection = default
#cow_selection = random

# when using the 'random' option for cowsay, stencils will be restricted to this list.
# it should be formatted as a comma-separated list with no spaces between names.
# NOTE: line continuations here are for formatting purposes only, as the INI parser
# in python does not support them.
#cow_whitelist=bud-frogs,bunny,cheese,daemon,default,dragon,elephant-in-snake,elephant,eyes,\
# hellokitty,kitty,luke-koala,meow,milk,moofasa,moose,ren,sheep,small,stegosaurus,\
# stimpy,supermilker,three-eyes,turkey,turtle,tux,udder,vader-koala,vader,www

# don't like colors either?
# set to 1 if you don't want colors, or export ANSIBLE_NOCOLOR=1
#nocolor = 1

# if set to a persistent type (not 'memory', for example 'redis') fact values
# from previous runs in Ansible will be stored. This may be useful when
# wanting to use, for example, IP information from one group of servers
# without having to talk to them in the same playbook run to get their
# current IP information.
#fact_caching = memory

#This option tells Ansible where to cache facts. The value is plugin dependent.
#For the jsonfile plugin, it should be a path to a local directory.
#For the redis plugin, the value is a host:port:database triplet: fact_caching_connection = localhost:6379:0

#fact_caching_connection=/tmp



# retry files
# When a playbook fails a .retry file can be created that will be placed in ~/
# You can enable this feature by setting retry_files_enabled to True
# and you can change the location of the files by setting retry_files_save_path

#retry_files_enabled = False
#retry_files_save_path = ~/.ansible-retry

# squash actions
# Ansible can optimise actions that call modules with list parameters
# when looping. Instead of calling the module once per with_ item, the
# module is called once with all items at once. Currently this only works
# under limited circumstances, and only with parameters named 'name'.
#squash_actions = apk,apt,dnf,homebrew,pacman,pkgng,yum,zypper

# prevents logging of task data, off by default
#no_log = False

# prevents logging of tasks, but only on the targets, data is still logged on the master/controller
#no_target_syslog = False

# controls whether Ansible will raise an error or warning if a task has no
# choice but to create world readable temporary files to execute a module on
# the remote machine. This option is False by default for security. Users may
# turn this on to have behaviour more like Ansible prior to 2.1.x. See
# https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user
# for more secure ways to fix this than enabling this option.
#allow_world_readable_tmpfiles = False

# controls the compression level of variables sent to
# worker processes. At the default of 0, no compression
# is used. This value must be an integer from 0 to 9.
#var_compression_level = 9

# controls what compression method is used for new-style ansible modules when
# they are sent to the remote system. The compression types depend on having
# support compiled into both the controller's python and the client's python.
# The names should match with the python Zipfile compression types:
# * ZIP_STORED (no compression. available everywhere)
# * ZIP_DEFLATED (uses zlib, the default)
# These values may be set per host via the ansible_module_compression inventory
# variable
#module_compression = 'ZIP_DEFLATED'

# This controls the cutoff point (in bytes) on --diff for files
# set to 0 for unlimited (RAM may suffer!).
#max_diff_size = 1048576

# This controls how ansible handles multiple --tags and --skip-tags arguments
# on the CLI. If this is True then multiple arguments are merged together. If
# it is False, then the last specified argument is used and the others are ignored.
# This option will be removed in 2.8.
#merge_multiple_cli_flags = True

# Controls showing custom stats at the end, off by default
#show_custom_stats = True

# Controls which files to ignore when using a directory as inventory with
# possibly multiple sources (both static and dynamic)
#inventory_ignore_extensions = ~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo

# This family of modules use an alternative execution path optimized for network appliances
# only update this setting if you know how this works, otherwise it can break module execution
#network_group_modules=eos, nxos, ios, iosxr, junos, vyos

# When enabled, this option allows lookups (via variables like {{lookup('foo')}} or when used as
# a loop with `with_foo`) to return data that is not marked "unsafe". This means the data may contain
# jinja2 templating language which will be run through the templating engine.
# ENABLING THIS COULD BE A SECURITY RISK
#allow_unsafe_lookups = False

# set default errors for all plays
#any_errors_fatal = False

[inventory]
# enable inventory plugins, default: 'host_list', 'script', 'auto', 'yaml', 'ini', 'toml'
#enable_plugins = host_list, virtualbox, yaml, constructed

# ignore these extensions when parsing a directory as inventory source
#ignore_extensions = .pyc, .pyo, .swp, .bak, ~, .rpm, .md, .txt, ~, .orig, .ini, .cfg, .retry

# ignore files matching these patterns when parsing a directory as inventory source
#ignore_patterns=

# If 'true' unparsed inventory sources become fatal errors, they are warnings otherwise.
#unparsed_is_failed=False

[privilege_escalation]
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False

[paramiko_connection]

# uncomment this line to cause the paramiko connection plugin to not record new host
# keys encountered. Increases performance on new host additions. Setting works independently of the
# host key checking setting above.
#record_host_keys=False

# by default, Ansible requests a pseudo-terminal for commands executed under sudo. Uncomment this
# line to disable this behaviour.
#pty=False

# paramiko will default to looking for SSH keys initially when trying to
# authenticate to remote devices. This is a problem for some network devices
# that close the connection after a key failure. Uncomment this line to
# disable the Paramiko look for keys function
#look_for_keys = False

# When using persistent connections with Paramiko, the connection runs in a
# background process. If the host doesn't already have a valid SSH key, by
# default Ansible will prompt to add the host key. This will cause connections
# running in background processes to fail. Uncomment this line to have
# Paramiko automatically add host keys.
#host_key_auto_add = True

[ssh_connection]

# ssh arguments to use
# Leaving off ControlPersist will result in poor performance, so use
# paramiko on older platforms rather than removing it, -C controls compression use
#ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s

# The base directory for the ControlPath sockets.
# This is the "%(directory)s" in the control_path option
#
# Example:
# control_path_dir = /tmp/.ansible/cp
#control_path_dir = ~/.ansible/cp

# The path to use for the ControlPath sockets. This defaults to a hashed string of the hostname,
# port and username (empty string in the config). The hash mitigates a common problem users
# found with long hostnames and the conventional %(directory)s/ansible-ssh-%%h-%%p-%%r format.
# In those cases, a "too long for Unix domain socket" ssh error would occur.
#
# Example:
# control_path = %(directory)s/%%h-%%r
#control_path =

# Enabling pipelining reduces the number of SSH operations required to
# execute a module on the remote server. This can result in a significant
# performance improvement when enabled, however when using "sudo:" you must
# first disable 'requiretty' in /etc/sudoers
#
# By default, this option is disabled to preserve compatibility with
# sudoers configurations that have requiretty (the default on many distros).
#
#pipelining = False

# Control the mechanism for transferring files (old)
# * smart = try sftp and then try scp [default]
# * True = use scp only
# * False = use sftp only
#scp_if_ssh = smart

# Control the mechanism for transferring files (new)
# If set, this will override the scp_if_ssh option
# * sftp = use sftp to transfer files
# * scp = use scp to transfer files
# * piped = use 'dd' over SSH to transfer files
# * smart = try sftp, scp, and piped, in that order [default]
#transfer_method = smart

# if False, sftp will not use batch mode to transfer files. This may cause some
# types of file transfer failures impossible to catch however, and should
# only be disabled if your sftp version has problems with batch mode
#sftp_batch_mode = False

# The -tt argument is passed to ssh when pipelining is not enabled because sudo
# requires a tty by default.
#usetty = True

# Number of times to retry an SSH connection to a host, in case of UNREACHABLE.
# For each retry attempt, there is an exponential backoff,
# so after the first attempt there is 1s wait, then 2s, 4s etc. up to 30s (max).
#retries = 3

[persistent_connection]

# Configures the persistent connection timeout value in seconds. This value is
# how long the persistent connection will remain idle before it is destroyed.
# If the connection doesn't receive a request before the timeout value
# expires, the connection is shutdown. The default value is 30 seconds.
#connect_timeout = 30

# The command timeout value defines the amount of time to wait for a command
# or RPC call before timing out. The value for the command timeout must
# be less than the value of the persistent connection idle timeout (connect_timeout)
# The default value is 30 second.
#command_timeout = 30

[accelerate]
#accelerate_port = 5099
#accelerate_timeout = 30
#accelerate_connect_timeout = 5.0

# The daemon timeout is measured in minutes. This time is measured
# from the last activity to the accelerate daemon.
#accelerate_daemon_timeout = 30

# If set to yes, accelerate_multi_key will allow multiple
# private keys to be uploaded to it, though each user must
# have access to the system via SSH to add a new key. The default
# is "no".
#accelerate_multi_key = yes

[selinux]
# file systems that require special treatment when dealing with security context
# the default behaviour that copies the existing context or uses the user default
# needs to be changed to use the file system dependent context.
#special_context_filesystems=nfs,vboxsf,fuse,ramfs,9p,vfat

# Set this to yes to allow libvirt_lxc connections to work without SELinux.
#libvirt_lxc_noseclabel = yes

[colors]
#highlight = white
#verbose = blue
#warn = bright purple
#error = red
#debug = dark gray
#deprecate = purple
#skip = cyan
#unreachable = red
#ok = green
#changed = yellow
#diff_add = green
#diff_remove = red
#diff_lines = cyan


[diff]
# Always print diff when running ( same as always running with -D/--diff )
# always = no

# Set how many context lines to show in diff
# context = 3

原理

本节尽量全面的介绍 Ansible 的原理,将常用的知识点汇聚在一起,以帮助用户在实践中能够充分准确的用好 Ansible。

Why Ansible?

Ansible 诞生于 2012 年,目前是 RedHat 旗下的产品,是 Github 上受欢迎的自动化运维工具。

从事过运维相关工作的小伙伴,对 Shell 应该是“有爱有恨”的。一方面我们爱它的无所不能,另外一方面我们恨它的语法晦涩难懂,且难以模块化利用。

Ansible 的作者兼创始人Michael DeHaan 曾经供职于Puppet Labs、RedHat、Michael,在配置管理和架构设计方面有丰富的经验。其在RedHat任职期间主要开发了Cobble,经历了各种系统简化、自动化基础架构操作的失败和痛苦,在尝试了Puppet、Chef、Cfengine、Capistrano、Fabric、Function、Plain SSH等各式工具后,决定自己打造一款能结合众多工具优点的自动化工具,Ansible由此诞生。

Ansible 为何如此火爆?首先是当前云计算的大规模应用所驱动,然后就是它的核心特点决定的:

  • 无需代理也可以控制多台受控机并行管理
  • 采用描述性的语言来使用,非常易读、易编写
  • 兼容 Python 的语法
  • 安装过程简单,学习曲线很平坦

一种解释排版型语言,易读性极强:

- block:
- name: Create credentials Folder
file:
path: /credentials
state: directory

- name: Write Databases Password
template:
src: password.txt.jinja2
dest: /credentials/password.txt
mode: 644

一句话总结:简单易用,功能强大,用途广泛。

应用领域

Ansible 究竟有什么用呢?

我们从运维工程师或开发人员日常工作中最常见的部署来说:为了部署一个应用,我们需要提前安装 Web 服务、应用程序服务、消息队列、缓存系统、数据库、负载均衡等基础软件,与此同时我们还需要通过手工配置,将各个组件连接起来,让它们发挥功效。甚至,站在软件维护的角度,还需要部署日志系统、监控系统、数据库分析系统、数据库审计等维护工具。如果使用手工来完成这些任务,从购买一台云服务器,再到 SSH 登录直至完成所有任务,需要数百个步骤,而且每一个步骤不能出错。

如果有一个自动化程序能够完成上述任务,那一定会收到用户的热烈欢迎。幸运的,Ansible 就是这样的工具,它比 Shell 简单,它可以轻轻松松处理:

配置管理

配置管理即部署部署应用程序环境,包括对 Linux 和 Windows 上进行各种程序安装,系统操作,Web服务管理、应用服务管理、数据库配置等

管理云资源

Ansible 提供包括 AWS,Azure等数十个云资源的创建、操作。即无需用户了解每个云平台的 API,也可以轻松管理云资源。

监控告警

Ansible 支持对 Grafana、Nagios、Zabbix、Datalog 等系统监控软件进行直接操作。

消息发送

Ansible 提供了大量的 Notification modules 用于帮助应用程序发送消息,支持:邮件、Mattermost、RabbitMQ、syslogger等常见的应用。

硬件管理

Ansible 可以对网络设备、存储设备进行直接操作,所支持网络品牌包括 Cisco、Aruba、Check Point等多达几十个,支持的存储品牌包括:IBM、Netapp、EMC等

一句话总结:Ansible 可以完成 DevOps 全过程所需的自动化配置工作:

架构

技术架构

Ansible 技术架构

我们知道,让合适的程序以合适的方式在合适的主机上高效率的运行,是技术架构的出发点。

Ansible 的技术架构同样遵循这个原理,下面我们从如下三个方面阐述 Ansible 的技术架构:

  • 主机:运行 Ansible 程序的服务器,分为主控端和受控端两种类型的主机,主机的在架构中的表现形式为 Host Inventory(主机清单)
  • 程序:官方内置的软件包被成为为模块和插件,用户自己编写的程序被称之为 Playbook (多个 Playbook 以某种形式组合在一起被成为 roles)
  • 连接:主控端和受控端之间的连接与控制,一般采用 SSH 连接,支持认证

为什么主机分为主控端(Control Node)受控端(Managed Node)?

主要是 Ansible 的用途决定的,由于 Ansible 需要考虑同一个程序在同一个时间部署到多个主机上,故在设计上引入的主控端这种角色,用于以集中式的方式向多个受控主机发布配置任务。

如果不考虑这种场景,Ansible 也支持在本机上运行程序,即主控模式并不是必须的。

Ansible 工作原理

用户登录到 Ansible 所在的服务器,便可以使用命令行运行 Ansible 程序。

这里需注意的是前面多次提到过的 Inventory 的概念,Ansible 程序在运行的时候,一定提前准备 Inventory 文件,如果缺少这个文件,Ansible 就只能在本机上运行。

下面就是一个在本机运行 ping 模块的程序,localhost 参数告之 Ansible 目标主机是本机

$ansible localhost -m ping

localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}

如果没有准备好 Inventory,而选用所有主机 (all 参数),系统就会报错

$ansible all -m ping
43.128.22.14 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}

Ansible 代码执行过程

生态架构

Ansible 是一个卓越的技术产品,也是一个成功的商业软件,它的成功与其商业生态布局有密切关系。

生态架构的技术基础:

  • 模块
  • 插件
  • Python 语法语法兼容性
  • Roles

生态商业整合:

  • Ansible Galaxy:开发者共享的代码库(role库) Ansible Galaxy

  • Ansible Collection:开发者共享的应用程序库(完整的 Ansible 应用程序) Ansible Galaxy

  • Ansible Tower:企业级可视化 Ansible 管理工具,支持 API。 Ansible Tower

  • Ansible Automation Platform:由 RedHat 托管的 Ansible 项目,包含 Ansible Tower 以及自动化资源、自动化分析等企业级功能。 Ansible Automation Platform

主机清单

Ansible 经常用于管理大量的服务器,如果企业有数千台服务器,那么一定需要对这些服务器进行分门别类。与此同时,服务器的用户账号信息等也各不相同。

Ansible Inventory (主机清单) 就是为了灵活的管理主机信息的技术标准。

格式

静态文件是相对于动态文件来说,Ansible 的静态主机文件是指提前准备好并有完整内容的主机清单

默认的文件是:/etc/ansible/hosts

下面先展示一个包含丰富信息的 hosts 文件示例:

[webservers]
86.21.14.177
web1.websoft9.com
we2.websoft9.com
192.165.2.50

[database]
86.21.14.172
host1.websoft9.com
host2.websoft9.com
192.165.2.51

[monitor]
86.21.14.173 ansible_user=root ansible_ssh_pass=123456 proxy=proxy.websoft9.com
86.21.14.174 ansible_user=root ansible_ssh_private_key_file=/root/mykey
host1.websoft9.com
www[01:50].example.com

[monitor:vars]
proxy=proxy.websoft9.com

从以上文件可得知 Inventory 的特点:

  • 可分组(分组还可以嵌套)
  • 可存放用户账号和密码
  • 可以为主机和分组指定变量
  • 同一个主机可以归属多个组
  • 主机名称支持范表达式 www[01:50] 表示:www01,www02...

另外,Ansible 还支持多个 inventory 文件。只需在 ansible.cfg 文件中让 inventory 配置项指向一个目录即可。不过,多个 inventory 文件与单个并没有区别,毕竟可以单个文件由于支持分组,已经完全可以满足各种分类场景了。

参数

ansible_ssh_host远程主机
ansible_ssh_port指定原创主机ssh端口
ansible_ssh_rootssh连接远程主机的用户
ansible_ssh_passssh连接远程主机的密码
ansible_sudo_passsudo密码
ansible_connection指定连接类型:local、ssh、paramiko
ansible_ssh_private_key_filessh连接使用的私钥
ansible_shell_type指定连接端的shell类型,sh、csh、fish
ansible_python_interpreter指定远程主机使用的python路径

变量

Ansible 支持向 inventory 文件中添加变量,变量适用范围可以是单个主机,也可以是分组。

清单插件

参考

Playbook

本章我们讲解 Ansible 最核心的组件 playbook。

playbook 是什么?

如果把 Ansible 比作开发语言,那么 playbook 就是一个程序文件。程序代码在程序文件中按顺序执行,最终完成所需处理的任务。

为什么称之 playbook 而不是程序文件呢?

playbook 翻译过来就是剧本的意思。如果你是文艺爱好者,可能阅读过电影/舞台剧的剧本(下图)

电影剧本

剧本是个导演组织演员、道具、拍摄等资源一种编排叙述性的文字说明。

Ansible 的程序代码与电影具备具有类似性,故被作者命名为 playbook

格式

playbook 有着规范化的格式,下面就是一个典型的可以被直接运行的 playbook 范例:

- hosts: localhost
remote_user:root
vars:
https_port: 443
tasks:
- name: Create file1
ansible.builtin.file:
state: touch
path: /tmp/file1

- name: Create file2
ansible.builtin.file:
state: touch
path: /tmp/file2

- name: Create file3
ansible.builtin.file:
state: touch
path: /tmp/file3

playbook 包含几个关键字,每个关键字的含义如下:

  • hosts: 主机IP 或 主机组名 或 all
  • remote_user: 以某个用户身份运行,通常设置为 root
  • vars: 变量

Ansible playbook 关系图
图:playbook, paly, task 三者关系

模块

模块 Ansible 官方已经编写好了的软件包,是 Ansible 的功能核心。

正是由于 Ansible 提供了大量的模块,才大大简化运维工作,可以让运维人员只需要少量的 Shell 知识便可以完成复杂的运维任务。

有两种使用模块的方式:

在 Playbook 中使用模块:

- name: restart webserver
service:
name: httpd
state: restarted

在 命令行中使用模块:

ansible localhost -m service -a "name=httpd state=started"

查看所有模块

插件

插件是对模块功能的一种补充。

变量

循环

条件

Ansible 中使用 when 作为条件判断的关键词,条件判断注意事项:

  • 变量名不需要双大括号“{{}}”
  • 运算符兼容 jinja2 格式:==, !=, >, >=
  • 支持逻辑运算符:and, or, not
  • 支持变量的定义判断:defined, undefined, none

详情参考:Ansible条件判断详解

过滤

模板

查询

交互

- name: Create file1
ansible.builtin.file:
state: touch
path: /tmp/file1

Role

Ansible role 是用于规范化管理 playbook 程序文件以及附带的其他文件的一种软件包组织机制。

结构

运行 ansible-galaxy init myrole 可以创建名称为 myrole 的 role。

使用 tree 命令查看包的结构:

$ tree myrole
myrole
|-- defaults
| `-- main.yml
|-- files
|-- handlers
| `-- main.yml
|-- meta
| `-- main.yml
|-- README.md
|-- tasks
| `-- main.yml
|-- templates
|-- tests
| |-- inventory
| `-- test.yml
`-- vars
`-- main.yml

8 directories, 8 files

  • tasks/main.yml 存放项目的主文件
  • templates 存放 jinjia2 模板文件
  • files 存放程序所需的文件
  • defaults/vars 存放变量文件,vars 下的变量优先级更高
  • tests 存放本 role 入口 playbook
  • handlers 存放 task 的 handler
  • meta 存放 role 的元数据,包括系统兼容性、role 依赖等
运行

以上创建的 role 模板也可以使用 ansible-playbook 运行。

ansible-playbook myrole/tests/test.yml

这种运行方式是很多初学者可能会忽视的

Ansible Galaxy

Ansible Galaxy 是官方提供的帮助用户分享 role 的网站平台。

同时官方也提供了一套 cli 命令:

$ ansible-galaxy role -h
usage: ansible-galaxy role [-h] ROLE_ACTION ...

positional arguments:
ROLE_ACTION
init Initialize new role with the base structure of a role.
remove Delete roles from roles_path.
delete Removes the role from Galaxy. It does not remove or alter the
actual GitHub repository.
list Show the name and version of each role installed in the
roles_path.
search Search the Galaxy database by tags, platforms, author and
multiple keywords.
import Import a role
setup Manage the integration between Galaxy and the given source.
info View more details about a specific role.
install Install role(s) from file(s), URL(s) or Ansible Galaxy

optional arguments:
-h, --help show this help message and exit

Collection

Ansible Collection 是完整的 Ansible 应用,它包含了 role 以及各种其他所需的配置,可以 role 编排后处理更为复杂的任务。

Websoft9 提供了包括 WordPress, GitLab, Odoo, LAMP 等数十个常见应用的开源自动化 Ansible Collection,可免费使用。

Ansible Tower

Ansible Tower 是 Ansible 可视化工具,它由一个上游的开源版本 AWX 可供用户免费使用。

问题解答

Ansible 是否有可视化工具?

有,Ansible Tower 即可视化工具

Ansible 可以管理远程服务器吗?

可以管理远程主机,也可以管理本机

Ansible 是否有系统服务?

没有,Ansible 是一套开发语言工具,主要提供 CLI 供用户使用

如何成为Ansible程序高手?

Shell命令是根本,夯实基础稳步走;
晦涩理论看一遍,动手实验是正道。
经典教材床头放,官方文档经常看;
闲时看书有收获,勤动笔来总结多。
三人成行有我师,学会提问收获多;
疑难问题要会诊,切莫独钻死胡同。
稳定简约见功底,数据结构来撑腰;
软件没有终结日,长久迭代价值高。

学会驾驭Ansible,用通用的软件方法论去理解Ansible,千万不要被Ansible的技术术语所牵制。

如何成为 Ansible 应用高手?

多想场景,多看官方文档,多看官方博客,多想想生态

系统变量 ansible_os_family 支持哪些值?

OS_FAMILY = dict(
RedHat = 'RedHat',
Fedora = 'RedHat',
CentOS = 'RedHat',
Scientific = 'RedHat',
SLC = 'RedHat',
Ascendos = 'RedHat',
CloudLinux = 'RedHat',
PSBM = 'RedHat',
OracleLinux = 'RedHat',
OVS = 'RedHat',
OEL = 'RedHat',
Amazon = 'RedHat',
XenServer = 'RedHat',
Ubuntu = 'Debian',
Debian = 'Debian',
SLES = 'Suse',
SLED = 'Suse',
OpenSuSE = 'Suse',
SuSE = 'Suse',
Gentoo = 'Gentoo',
Archlinux = 'Archlinux',
Mandriva = 'Mandrake',
Mandrake = 'Mandrake',
Solaris = 'Solaris',
Nexenta = 'Solaris',
OmniOS = 'Solaris',
OpenIndiana = 'Solaris',
SmartOS = 'Solaris',
AIX = 'AIX',
Alpine = 'Alpine',
MacOSX = 'Darwin',
FreeBSD = 'FreeBSD',
HPUX = 'HP-UX'
)

Ansible 是否支持动态主机清单?

支持。由于在实际生产场景中,如果清单采用手动维护这些列表将是一个非常繁琐的任务。

Ansible 支持动态生产主机清单,即 ansible.cfg 指向一个生产主机清单的程序,再由程序产生符合格式的清单列表。

Ansible 有没有默认分组?

有。默认有包含文件所有主机的 all 组,同时还有没有归属的 ungrouped 组。

Ansible受控端是否必须提前安装Python?

不是。Ansible的raw模块和script模块不依赖于客户端安装的Python来运行。从技术上讲,您可以使用Ansible使用raw模块安装兼容版本的Python ,然后使用该模块使用其他所有模块。例如,如果需要将Python 2引导到基于RHEL的系统上,则可以按以下方式安装它:

ansible myhost --become -m raw -a "yum install -y python2"

主控端如何安装Ansible最方便?

推荐采用 pip install ansible

Ansible 的应用模块好用吗?例如:Docker, MySQL等

建议弃用,直接使用命令更为稳定可靠,这样可以避免这边模块的版本兼容性问题

Ansible中的变量优先级有哪些?

有高到低:ansible命令带入的变量 > cfg配置文件的变量 > 主项目的var变量 > role中的var变量 > role default 变量

Ansible有全局变量的概念吗?

没有,但我们可以将:ansible命令带入的变量 | cfg配置文件的变量 | 主项目的var变量 视为全局变量。但特别需要注意的是:Ansible项目中即使有同名变量,它们不会共享一个内存区域,而是各自独占内存(区别于Java等语言变量指针的概念)。

Ansible 如何实现模块化?

Ansible Galaxy 就是模块化唯一的方案

Ansible 中的条件判断有哪些可能性?

True, not False, !=none, !="",

Ansbile 中Python Pip apt/yum 总结

  1. 客户端和服务端 python版本可以不一致
  2. 升级最新pip版本会导致 pip 命令无法使用 官方解释使用 python3 -m pip install xxx
  3. apt lock 问题可以在脚本中预处理

Ansbile 客户端和服务端 Python版本是否可以不一致?

可以

pip和pip3共存吗?

可以共存。但建议通过:python3 -m pip install xxx 这样的方式使用Python3下的pip,启用pip3这种表达方式

为什么Ansible中apt升级容易导致 lock?

AWS上非常容易出错,建议在脚本中预处理

Ansible 之PIP模块是否可以制定Python版本?

可以,参考如下

# Install (Bottle) for Python 3.3 specifically,using the 'pip3.3' executable.
- pip:
name: bottle
executable: pip3.3

dnf 模块现在可以用吗?

现在不建议使用dnf模块

一个Ansible项目中,主入口文件中 vars_filesvars 哪个变量优先级高?

vars_files的优先级更高。需要注意的是Ansible的变量是无法覆盖的,即同名变量在内存中都有单独的存储区域,而Ansible只是通过优先级的方式使用。

如何从一个裸机快速运行Ansible项目?

下面以 CentOS 为例列出运行 Ansible 项目的步骤:

yum install ansible git -y
git clone https://github.com/Websoft9/ansible-activemq.git
cd ansible-activemq
ansible-galaxy install -r requirements.yml -f
ansible-playbook activemq.yml -c local

条件判断中变量 none,null.undefined 有什么区别?

  • undefined 代表变量未定义,即变量不存在
  • null 即空字符,varA="" 就代表定义个 null 变量 varA
  • none 空值是Python里一个特殊的值,varA=None 就代表定义了一个 None 的变量 varA。None不能理解为0,因为0是有意义的,而None是一个特殊的空值。

jinja2 模板中如何判断一个变量 varA 是否未定义,为空或 false:

使用 {% if varA %} 即可,等同于{% if varA is defined and varA is not none %}

本项目中 Ansible 采用何种安装方式?

采用 rpm/deb 包的安装方式

如何以调试模式启动Ansible服务?

systemctl stop ansible-server
ansible-server console

python_interpreter=auto 时的选择逻辑?

Ansible 主控端有一个 Python interpreter 解析器的选择表,Ansible 会维护不同的操作系统发行版对应的选择。具体参考:Interpreter Discovery

可以通过 Ansible 的 ansible_python_interpreter 变量修改默认值。

Ansible 有哪些内置变量?

Ansible 有三种类型的内置变量: