ansible简介(工作中能使用到的层次)
参考文档
ansible是新出现的自动化运维工具,ansible是一个配置管理和应用部署工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric.SaltStack )的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架,根据官方提供的信息,当前使用ansible的用户有:美国国家航空航天局NASA、evernote(印象笔记)、rackspace(全球三大云计算中心之一)、atlassian、twitter(全球互联网上访问量最大的十个网站之一)等
- ansible在生产环境当中的应用
- 自动化部署应用
- 自动化管理配置
- 自动化持续交付
- 自动化(aws)云服务器管理
- ansible的优点
- ansible糅合了众多老牌运维工具的优点,基本上pubbet和saltstack能实现的功能全部能实现
- 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可
- ansible是一个工具,ansible不需要启动服务,仅仅只是一个工具,可以轻松的实现分布式扩展
- 批量任务执行可以写成脚本,而且不用分发到远程就可以执行
- ansible是一致性,高可靠性,安全性设计的轻量级自动化工具
- 使用python编写,维护更简单,ruby语法过于复杂
- 特性
- no agents:不需要在被管控主机上安装任何客户端
- no server:无服务器端,使用时直接运行命令即可
- modules in any languages:基于模块工作,可使用任意语言开发模块
- yaml,not code:使用yaml语言定制剧本playbook
- ssh by default:基于SSH工作
- strong multi-tier solution:可实现多级指挥(分布式)。
ansible架构以及执行流程
- 连接插件(connectior plugins): 用于连接主机(用来连接被管理端)
- 核心模块(core modules) :连接主机实现操作,它依赖于具体的模块来做具体的事情
- 自定义模块(custom modules): 根据自己的需求编写具体的模块
- 插件(plugins) :完成模块功能的补充
- 剧本(playbooks) :ansible的配置文件,将多个任务定义在剧本中,由ansible自动执行
- 主机清单(host inventory):定义ansible需要操作主机的范围
最重要的一点是ansible是模块化的它所有的操作都依赖于模块
比如需要创建一个文件,那么我就需要调用file模块;需要copy文件,那么我就需要copy模块;需要测试机器的存活率,那么就需要ping模块ansible all -m ping
。
ansible安装与配置
安装
- ansible只是一个进程,不需要添加数据库也不需要启动和运行守护进程,它只是一个进程,你可以轻松使用它安装在任何一台主机上面(除了windows),ansible管理机不能安装到windows上面
- 版本的选择,因为2.0有非常大的改进,一般都会使用2.0以上的版本
- 控制机的要求,因为ansible是python写的,所以需要在安装了python2.6或者2.7以上的python版本才可以安装
- 管理节点的要求,需要安装ssh,python版本在2.5以上
- 安装有3个方式
- yum源安装:
yum -y install ansible
- python模块安装:
pip install ansible
- 从github下载
- yum源安装:
$ git clone git://github.com/ansible/ansible.git --recursive
$ cd ./ansible
$ make rpm
$ sudo rpm -Uvh ./rpm-build/ansible-*.noarch.rpm
任务执行模式
ansible系统由控制主机对被管节点的操作方式有两种ad_hoc和playbook
- ad_hoc单命令模式:可以对多台主机执行单个命令
ansible all -a "/bin/echo hello"
- playbook通过多个tasks的集合完成一类功能如web的安装部署,数据库服务器的批量备份等
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running (and enable it at boot)
service: name=httpd state=started enabled=yes
handlers:
- name: restart apache
service: name=httpd state=restarted
ansible(七个命令)
安装完ansible后,发现ansible一共为我们提供了七个指令:ansible
、ansible-doc
、ansible-galaxy
、ansible-lint
、ansible-playbook
、ansible-pull
、ansible-vault
。这里只查看usage部分,详细部分可以通过 “指令 -h” 的方式获取。
ansible
- 格式:
ansible <host-pattern> [options]
- 说明:ansible是指令核心部分,其主要用于执行ad-hoc命令,即单条命令。默认后面需要跟主机和选项部分,默认不指定模块时,使用的是command模块。
- 举例:
ansible 127.0.0.1 -a 'date'
- 常用参数:
-m:执行模块的名字,默认使用command模块,所以如果是只执行单一命令可以不用-m参数
-a:命令行参数
-u:ssh连接的用户名,默认用root,ansible.cfg中可以配置
-k:提示输入ssh登录密码。当使用密码验证的时候用
-s:sudo运行
-U:sudo到那个用户,默认为root
-K:提示输入sudo密码,当不是NOPASSWD模式时使用
-C:只是测试一下会改变什么内容,不会真正去执行
-c:连接类型(default=smart)
-f:fork多少个进程并发处理,默认为5个
-i:指定hosts文件路径(可以是文件,也可以是目录,也可以动态主机列表获取脚本),默认default=/etc/ansible/hosts
-I: 指定pattern,对<host_pattern>已匹配的主机中再过滤一次
--list-hosts:只打印有哪些主机会执行这个playbook文件,不是实际执行 #ansible --list-hosts all
-M:要执行的模块路径,默认为/usr/share/ansible
-o:压缩输出,摘要输出
--private-key:私钥路径
-T:ssh连接超时时间,默认10秒
-t:日志输出到该目录,日志文件名以主机名命名
-v:详细信息
-vvv: 查看详细信息,调试的时候使用
- 主机清单文件:/etc/ansible/host
ansible-doc
- 格式:
ansible-doc [options] [module...]
- 说明:该指令用于查看模块信息,常用参数有两个-l 和 -s ,具体如下:
- 列出所有已安装的模块
ansible-doc -l
- 查看具体某模块的用法,这里如查看command模块
ansible-doc -s command
- 列出所有已安装的模块
ansible-galaxy
- 格式:
ansible-galaxy [-h] [--version] [-v] TYPE ...
- 说明:用于方便的从<https://galaxy.ansible.com/ >站点下载第三方扩展模块,可以形象的理解其类似于centos下的yum、python下的pip或easy_install。
- 举例:安装了一个aeriscloud.docker组件,前面aeriscloud是galaxy上创建该模块的用户名,后面对应的是其模块。在实际应用中也可以指定txt或yml文件进行多个组件的下载安装。这部分可以参看官方文档。
ansible-galaxy install aeriscloud.docker
ansible-lint
对playbook的语法进行检查的一个工具。用法是ansible-lint playbook.yml
ansible-playbook
该指令是使用最多的指令,其通过读取playbook 文件后,执行相应的动作
ansible-pull
该指令使用需要谈到ansible的另一种模式---pull模式,这和平常经常用的push模式刚好相反,其适用于以下场景:
- 你有数量巨大的机器需要配置,即使使用非常高的线程还是要花费很多时间;
- 你要在一个没有网络连接的机器上运行Anisble,比如在启动之后安装。
ansible-vault
ansible-vault主要应用于配置文件中含有敏感信息,又不希望他能被人看到,vault可以帮你加密/解密这个配置文件,属高级用法。主要对于playbooks里比如涉及到配置密码或其他变量时,可以通过该指令加密,这样我们通过cat看到的会是一个密码串类的文件,编辑的时候需要输入事先设定的密码才能打开。这种playbook文件在执行时,需要加上 –ask-vault-pass参数,同样需要输入密码后才能正常执行。
ansible-inventory
--graph:以结构化的方式显示出受管主机的信息
ansible(配置文件)
- 位置:
/etc/ansible/ansible.cfg
用户可以修改一下配置文件来修改设置,他们的被读取的顺序如下:
* ANSIBLE_CONFIG (一个环境变量)
* ansible.cfg (位于当前目录中)
* .ansible.cfg (位于家目录中)
* /etc/ansible/ansible.cfg
Ansible 将会按以上顺序逐个查询这些文件,直到找到一个为止,并且使用第一个寻找到个配置文件的配置,这些配置将不会被叠加.
获取最新配置文件
如果使用程序包管理器安装ansible,最新的 ansible.cfg 配置文件有可能出现在 /etc/ansible 下并且命名为 ”.rpmnew”, 也可能根据不同的更新命名为其它名称。
如果你是通过 pip 或者其他方式安装,则可能需要自行创建这个文件,以免原配置文件被覆盖。
配置文件不同段详解
通用默认段
在 [defaults] 段中,以下选项是可以调节的:
action_plugins
“行为”是 ansible中的一段代码,用来激活一些事件,例如执行一个模块等。这是一个以开发者为中心的特性,使得一些底层模块可以从外部不同地方加载:
action_plugins = ~/.ansible/plugins/action_plugins/:/usr/share/ansible_plugins/action_plugins
ansible_managed
Ansible-managed 是一个字符串,可以插入到Ansible配置模版系统生成的文件中,如果你使用以下的自字符:{{ ansible_managed }}
例如:默认设置可以哪个用户修改和修改时间:
ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}
这个设置可以告知用户,Ansible修改了一个文件,并且手动写入的内容可能已经被覆盖.需要注意的是,如果使用这一特性,这个字符串中将包含一个日期注释,如果日期更新,模版系统将会在每一次报告文件修改。
ask_pass*
控制Ansible剧本playbook是否会自动弹出输入密码,默认为no。如果使用SSH 密钥匙做身份认证,可能需要修改这一参数
ask_pass=True
ask_sudo_pass*
类似 ask_pass,用来控制Ansible playbook 在执行sudo之前是否询问sudo密码。默认为no。如果用户使用的系统平台开启了sudo 密码的话,应该修改这一参数
ask_sudo_pass=True
bin_ansible_callbacks
用来控制callback插件是否在运行 /usr/bin/ansible 的时候被加载。这个模块将用于命令行的日志系统,发出通知等特性。Callback插件如果存在将会永久性的被 /usr/bin/ansible-playbook 加载,不能被禁用:1.8 版本之前,callbacks 插件不可以被 /usr/bin/ansible加载。
bin_ansible_callbacks=False
callback_plugins
Callbacks 在ansible中是一段代码,在特殊事件时将被调用,并且允许出发通知。这是一个以开发者为中心的特性,可以实现对Ansible的底层拓展,并且拓展模块可以位于任何位置:
callback_plugins = ~/.ansible/plugins/callback_plugins/:/usr/share/ansible_plugins/callback_plugins
deprecation_warnings
允许在ansible-playbook输出结果中禁用“不建议使用”的警告:
“不建议警告”指的是使用一些在新版本中可能会被淘汰的遗留特性。
deprecation_warnings = True
display_skipped_hosts
如果设置为False
,ansible将不会显示任何跳过任务的状态。默认选项是跳过任务的状态:
注意Ansible总是会显示任何任务的头文件, 不管这个任务被跳过与否。
display_skipped_hosts=True
error_on_undefined_vars
这个选项为默认,如果所引用的变量名称错误的话, 将会导致ansible在执行步骤上失败:
error_on_undefined_vars=True
# If set to False, any ‘{{ template_expression }}’ that contains undefined variables will be rendered in a template or ansible action line exactly as written.
executable
这个选项可以在sudo环境下产生一个shell交互接口。用户只在/bin/bash的或者sudo限制的一些场景中需要修改。大部分情况下不需要修改::
executable = /bin/bash
filter_plugins
过滤器是一种特殊的函数,用来拓展模版系统。这是一个开发者核心的特性,允许Ansible从任何地方载入底层拓展模块:
filter_plugins = ~/.ansible/plugins/filter_plugins/:/usr/share/ansible_plugins/filter_plugins
force_color
当没有使用TTY终端的时候,这个选项当用来强制颜色模式:
force_color = 1
force_handlers
即便这个用户崩溃,这个选项仍可以继续运行这个用户:
force_handlers = True
# The default is False, meaning that handlers will not run if a failure has occurred on a host. This can also be set per play or on the command line. See _handlers_and_failure for more details.
# 如果这个选项是False. 如果一个主机崩溃了,handlers将不会再运行这个主机。这个选项也可以通过命令行临时使用。详见:doc:_handlers_and_failure.
forks*
这个选项设置在与主机通信时的默认并行进程数。很多用户把这个设置为50,有些设置为500或者更多,如果你有很多的主机, 高数值将会使得跨主机行为变快。默认值比较保守:
forks=5
hash_behaviour
Ansible默认将会以一种特定的优先级覆盖变量,详见:doc:playbooks_variables
。拥有更高优先级的参数将会覆盖掉其他参数。
有些用户希望被hashed的参数(python 中的数据结构dictionaries)被合并.。这个设置叫做merge
。这不是一个默认设置,而且不影响数组类型的数组。我不建议使用这个设置除非你觉得一定需要这个设置。官方实例中不使用这个选项:
合法的值为replace
(默认值)或者merge
hash_behaviour=replace
host_key_checking*
这个特性详见:doc:intro_getting_started
,在Ansible 1.3或更新版本中将会检测主机密钥。如果你了解怎么使用并且希望禁用这个功能,你可以将这个值设置为False:
host_key_checking=True
inventory*
这个是默认库文件位置,脚本或者存放可通信主机的目录:
inventory = /etc/ansible/hosts
jinja2_extensions
这是一个开发者中心特性,允许开启Jinja2拓展模块:
jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n
library*
这个是Ansible默认搜寻模块的位置:
Ansible会多个用冒号隔开的路径,同时也会搜索在playbook中的“./library”
library = /usr/share/ansible
log_path*
如果出现在ansible.cfg文件中,Ansible将会在选定的位置登陆执行信息。请留意用户运行的Ansible对于logfile有无权限:
这个特性不是默认开启的。如果不设置,ansible将会把模块加载记录在系统日志系统中。不包含用户密码.
对于需要了解更多日志系统的企业及用户,你也许对**:doc:tower**感兴趣。
log_path=/var/log/ansible.log
lookup_plugins
这是一个开发者中心选项,允许模块插件在不同区域被加载:
lookup_plugins = ~/.ansible/plugins/lookup_plugins/:/usr/share/ansible_plugins/lookup_plugins
module_lang
这是默认模块和系统之间通信的计算机语言,默认为C语言
module_lang = C
# 在解决推送日志乱码的时候需要配置
module_lang = C
==> module_lang = zh_CN.UTF-8
module_set_locale = False
==> module_set_locale = True
module_name
这个是/usr/bin/ansible的默认模块名(-m)。默认是command
模块。之前提到过,command模块不支持shell变量、管道、配额,所以也许你希望把这个参数改为shell
:
module_name = command
nocolor
默认ansible会为输出结果加上颜色,用来更好的区分状态信息和失败信息。如果你想关闭这一功能,可以把nocolor
设置为1
:
nocolor=0
nocows
默认ansible可以调用一些cowsay的特性,使得/usr/bin/ansible-playbook运行起来更加愉快。如果你不喜欢cows,你可以通通过将nocows
设置为1
来禁用这一选项:
nocows=0
pattern
如果没有提供“hosts”节点,这是playbook要通信的默认主机组。默认值是对所有主机通信:
注意/usr/bin/ansible 一直需要一个host pattern,并且不使用这个选项。这个选项只作用于/usr/bin/ansible-playbook。
pattern = *
# hosts=*
poll_interval*
对于Ansible中的异步任务,当具体的poll interval 没有定义时,多少时间回查一下这些任务的状态,默认值(15秒)是一个折中选择。这个时间是回查频率、任务完成叫回频率、当任务完成时的回转频率的折中:
poll_interval=15
private_key_file
如果你是用pem密钥文件而不是SSH客户端或密码认证的话,你可以设置这里的默认值,来避免每一次提醒设置密钥文件位置–ansible-private-keyfile
:
private_key_file=/path/to/file.pem
remote_port*
这个设置是你系统默认的远程SSH端口,如果不指定,默认为22号端口:
remote_port = 22
remote_tmp*
Ansible 通过远程传输模块到远程主机,然后远程执行,执行后再清理现场。在有些场景下,你也许想使用默认路径,希望像更换补丁一样使用, 这时候你可以使用这个选项:
默认路径是在用户家目录下的目录.Ansible,会在这个目录中使用一个随机的文件夹名称
remote_tmp = $HOME/.ansible/tmp
remote_user
这是个ansible使用/usr/bin/ansible-playbook
链接的默认用户名。如果不指定,/usr/bin/ansible
默认使用当前用户名称:
remote_user = root
roles_path
roles路径指的是roles/
下的额外目录,用于playbook搜索Ansible roles。比如, 如果我们有个用于common roles源代码控制仓库和一个不同的playbooks仓库,你也许会在 /opt/mysite/roles里面查找roles:
roles_path = /opt/mysite/roles
多余的路径可以用冒号分隔,类似于其他path字符串:
roles_path = /opt/mysite/roles:/opt/othersite/roles
sudo_exe
如果在其他远程主机上使用另一种方式执行sudo操纵, sudo程序的路径可以用这个参数更换,使用命令行标签来拟合标准sudo:
sudo_exe=sudo
sudo_flags
当使用sudo支持的时候,传递给sudo以外的标签. 默认值为-H
, 意思是保留原用户的环境。在有些场景下也许需要添加或者删除标签,大多数用户不需要修改这个选项:
sudo_flags=-H
sudo_user*
这个是sudo使用的默认用户,如果–sudo-user
没有特指或者sudo_user
在Ansible playbooks中没有特指,在大多数的逻辑中 默认为root
sudo_user=root
system_warnings
允许禁用系统运行ansible相关的潜在问题警告(不包括操作主机):
system_warnings = True
timeout*
这个是默认SSH链接尝试超市时间:
timeout = 10
transport*
如果-c <transport_name>
选项没有在使用/usr/bin/ansible
或者 /usr/bin/ansible-playbook
特指的话,这个参数提供了默认通信机制。默认 值为smart
, 如果本地系统支持 ControlPersist技术的话,将会使用(基于OpenSSH)ssh
,如果不支持讲使用paramiko
。其他传输选项包括local
,chroot
,jail
等等。
用户通常可以设置为smart
,让playbook在根据通信条件自己选择connectin:
参数.
transport=smart
vars_plugins
这是一个开发者中心选项,允许底层拓展模块从任何地方加载:
vars_plugins = ~/.ansible/plugins/vars_plugins/:/usr/share/ansible_plugins/vars_plugins
vault_password_file
这个用来设置密码文件,也可以通过命令行指定–vault-password-file
:
vault_password_file = /path/to/vault_password_file
Paramiko Specific Settings
Paramiko是商业版linux 6 的默认SSH链接。但在其他平台上不是默认使用的。请在[paramiko]
头文件下激活它
record_host_keys
默认设置会记录并验证通过在用户hostfile中新发现的的主机(如果host key checking 被激活的话)。这个选项在有很多主机的时候将会性能很差。在这种情况下,建议使用SSH传输代替。当设置为False时, 性能将会提升,在hostkey checking被禁用时候,建议使用:
record_host_keys=True
OpenSSH Specific Settings
在[ssh_connection]
头文件之下,用来调整SSH的通信连接。OpenSSH是Ansible在操作系统上默认的通讯连接。
ssh_args
如果设置了的话,这个选项将会传递一组选项给Ansible,而使用以前的默认值:
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
# 用户可以提高ControlPersist值来提高性能。30分钟通常比较合适.
control_path
这个是保存ControlPath套接字的位置。默认值是:
control_path=%(directory)s/ansible-ssh-%%h-%%p-%%r
在有些系统上面,会遇到很长的主机名或者很长的路径名称(也许因为很长的用户名,或者比较深的家目录),这些都会超出套接字文件名字符上限(对于大多数平台上限为108个字符)。在这种情况下,你也许希望按照以下方式缩短字符串:
control_path = %(directory)s/%%h-%%r
scp_if_ssh
用户操控一个没有开启SFTP协议的远程系统,如果这个设置为True,scp将代替用来为远程主机传输文件:
scp_if_ssh=False
如果没有遇到这样的问题没有必要来修改这个设置。当然修改这个设置也没有什么明显的弊端。大部分的系统环境都默认支持SFTP, 通常情况下不需要修改。
pipelining
在不通过实际文件传输的情况下执行ansible模块来使用管道特性,从而减少执行远程模块SSH操作次数。如果开启这个设置,将显著提高性能.。然而当使用sudo
操作的时候,,你必须在所有管理的主机的/etc/sudoers
中禁用requiretty
。默认这个选项为了保证与sudoers requiretty的设置的兼容性是禁用的.,但是为了提高性能强烈建议开启这个设置。
pipelining=False
Accelerated Mode Settings
在[accelerate]
首部下, 以下设置可以调整。如果你不能在你的环境中开启:ref:pipelining
, Accelertation 是一个很有用的性能特性. 但是如果你可以开启管道,这个选项也许对你无用。
accelerate_port
在急速模式下使用的端口:
accelerate_port = 5099
accelerate_timeout
这个设置时用来控制从客户机获取数据的超时时间。如果在这段时间内没有数据传输,套接字连接会被关闭。一个保持连接(keepalive)数据包通常每15秒回发回给控制台,所以这个超时时间不应该低于15秒(默认值为30秒):
accelerate_timeout = 30
accelerate_connect_timeout
这个设置连接套接字调用的超时时间。这个应该设置相对比较短.这个和accelerate_port
连接在回滚到ssh或者paramiko(受限于你默认的连接设置)连接方式之前会尝试三次开始远程加速daemon守护进程。默认设置为1.0秒:
accelerate_connect_timeout = 1.0
注意,这个选项值可以设置为小于1秒钟,但是除非你拥有一个速度很快而且很可靠的网络,否则也许这样并不是一个很好的选择。如果你使用英特网访问你的系统,最好提高这个值。
accelerate_daemon_timeout
这个控制加速daemon守护进程的超时时间,用分钟来衡量。默认为30分钟:
accelerate_daemon_timeout = 30
accelerate_multi_key
如果这个选项开启,这个设置将允许多个私钥被加载到daemon。任何客户端要想连接daemon都需要开启这个选项:
通过本地套接字文件连接的通过SSH上传密钥文件到目标节点的新客户端,必须在登陆daemon时使用原始的登陆密钥登陆。
accelerate_multi_key = yes
ansible(免密码登录以及排错)
- 生成密钥
ssh-keygen -t rsa
【常用ssh-keygen参数】
-b bits :指定密钥长度。对于RSA密钥,最小要求768位,默认是2048位。DSA密钥必须恰好是1024位(FIPS 186-2 标准的要求)
-t type :指定要创建的密钥类型。可以使用:”rsa1”(SSH-1) “rsa”(SSH-2) “dsa”(SSH-2)
-f filename :指定密钥文件名
-C comment :提供一个新注释
-q :安静模式。用于在 /etc/rc 中创建新密钥的时候
- 将密钥拷贝到预管理的节点(root@192.168.1.203)上
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.1.203
- 测试
ansible all -a "date"
ansible all -a "ping -c 4 192.168.3.1" -vvv
ansible插件ansible-cmdb(实现cmdb功能)
- 安装 ansible-cmdb 插件
wget https://github.com/fboender/ansible-cmdb/releases/download/1.30/ansible-cmdb-1.30.tar.gz
tar -xvf ansible-cmdb-1.30.tar.gz -C /usr/share/ansible/plugins
cd /usr/share/ansible/plugins/ansible-cmdb-1.30/ && make install
- 添加环境变量
vim /etc/profile
source /etc/profile
- 生成所有主机的facts信息
ansible all -m setup --tree out/
# 会在当前目录下生成 out 目录,out目录下都是以主机域名或ip命名的文件。
# 比如,在/usr/local/ 下执行 ansible all -m setup --tree out/ ,则会在 /usr/local/下生成out目录
# 或者,
# 直接指明在哪生成 out目录
ansible all -m setup --tree /usr/local/out
- 通过第3步生成的facts信息生成web页面
cd ~
ansible-cmdb /usr/local/out/ > overview.html
将 ~/overview.html 文件导出可用浏览器直接访问:
ansible组件
inventory(主机清单静态)
所有的机器信息都存放到ansible的inventory组件里面,默认ansible的inventory是一个静态的ini格式的文件/etc/ansible/hosts,当然还可以通过ANSIBLE_HOSTS环境变量指定或者运行ansible和ansible-playbook的时候用-i参数临时设置。
中括号中的名字代表组名,你可以根据你自己的需求将庞大的主机分成具有标识的组,如上面我分了两个组webservers和dbservers组;
主机(hosts)部分可以使用域名、主机名、IP地址表示;当然使用前两者时,也需要主机能反解析到相应的IP地址,一般此类配置中多使用IP地址。
定义主机和主机组
[docker] #定义了一组叫docker
172.16.1.11 #组下面的主机
172.11.11.11 # ansible_ssh_pass='123456'
[docker:vars] #针对docker组使用inventroy内置变量定义了ssh登陆密码
ansible_ssh_pass='123456'
aaa='my name is aaa' # 传入自定义变量
[ansible:children] #定义了ansible组下面包含docker组,即docker组为ansible的子组
docker
主机清单文件在修改后会立即生效,一般使用ansible-inventory --graph
命令以结构化的方式显示出受管主机的信息。因为我们对受管主机进行了分组,因此这种方式非常便于我们的阅读。
[root@linuxprobe ~]# ansible-inventory --graph
@all:
|--@balancers:
| |--192.168.10.24
|--@dev:
| |--192.168.10.20
|--@prod:
| |--192.168.10.22
| |--192.168.10.23
|--@test:
| |--192.168.10.21
|--@ungrouped:
多个inventory列表
配置支持多个inventory,首先需要修改ansible.cfg中hosts的定义改成一个目录比如hostfile = /data/inventory
,然后我们在目录里面放入多个hosts文件
[root@ceshi2 data]# tree inventory
inventory
├── docker
└── hosts
不同的文件可以存放不同的主机:
[root@ceshi2 data] cat hosts
172.16.4.11 ansible_ssh_pass='123456'
[root@ceshi2 data]cat docker
[docker]
172.16.1.11 #组下面的主机
172.11.11.11 # ansible_ssh_pass='123456'
[docker:vars] #针对docker组使用inventroy内置变量定义了ssh登陆密码
ansible_ssh_pass='123456'
[ansible:children]#定义了一个ansible组 下面包含一个docker组
docker
inventory内置参数
- ansible_ssh_host:要连接的主机名
- ansible_ssh_port:端口号默认是22
- ansible_ssh_user:ssh连接时默认使用的用户名
- ansible_ssh_pass:ssh连接时的密码
- ansible_sudo_pass:使用sudo连接用户是的密码
- ansible_ssh_private_key_file:秘钥文件如果不想使用ssh-agent管理时可以使用此选项
- ansible_shell_type:shell的类型默认sh
- ansible_connection:SSH 连接的类型: local , ssh , paramiko。在ansible 1.2之前默认是paramiko,后来智能选择,优先使用基于ControlPersist的ssh
- ansible_python _ interpreter:用来指定 python 解释器的路径,同样可以指定ruby 、perl 的路径
inventory(动态获取主机清单)
动态inventory的意思是所有的变量可以从外部获取,也就是说我们可以从CMDB以及zabbix系统拉取所有的主机信息然后使用ansible进行管理。引用inventory只需要把ansible.cfg文件中的inventory定义值改成一个执行脚本即可。
脚本举例:
#!/usr/bin/env python
# coding=utf-8
# inverti.py
import json
host1ip = ['192.168.1.15']
host2ip = ['192.168.1.110']
group = 'test11'
group2 = 'test22'
hostdata = {group:{"hosts":host1ip},group2:{"hosts":host2ip}} # ansible识别的是json格式,且格式固定为{"组名":{"hosts":ip1}}
print json.dumps(hostdata,indent=4)
执行:
[root@vagrant-centos65 opt]# ansible -i inverti.py all -a 'uptime' -k
SSH password:
192.168.1.15 | SUCCESS | rc=0 >>
07:25:27 up 3:56, 3 users, load average: 0.00, 0.00, 0.00
192.168.1.110 | SUCCESS | rc=0 >>
07:25:27 up 7 min, 3 users, load average: 0.00, 0.02, 0.00
ansible(单命令模式)
ad-hoc是点对点的执行ansible命令,介绍一下日常的Ad-Hoc命令
例如:
# 后台执行(返回ansible_job_id(即jid)等信息)
# -B的意思是异步执行,-o的意思是压缩输出,-P设置轮询间隔
ansible docker -B 120 -P 0 -m shell -a 'sleep 10;hostname' -o #加了-P 0 之后会返回一个job_id 可以通过jobID去查看执行的结果。当-P 大于0的时候会轮询去查询执行结果
# 根据jid查询后台任务状态
# -m要执行的模块,-a模块参数
ansible all -m async_status -a 'jid='5265654654''
其他的命令:
可选参数:
--ask-vault-pass
要求提供保管库密码
--list-hosts
输出匹配主机列表;不执行其他任何操作
--playbook-dir BASEDIR
由于此工具不使用剧本,因此可以将其用作替代剧本目录,从而为许多功能(包括role / group_vars /等)设置相对路径。
--syntax-check
在剧本上执行语法检查,但不执行
--vault-id VAULT_IDS
要使用的库身份
--vault-password-file VAULT_PASSWORD_FILES
保险库密码文件
--version
显示程序的版本号,配置文件位置,配置的模块搜索路径,模块位置,可执行位置和退出
-B SECONDS, --background SECONDS
异步运行,在X秒后失败。(默认值= N / A)
-C, --check
不要做任何改变;相反,尝试预测可能发生的某些变化
-D, --diff
更改(小的)文件和模板时,请显示这些文件中的差异;与--check一起使用效果很好
-M MODULE_PATH, --module-path MODULE_PATH
在模块库前添加用冒号分隔的路径。(默认值=〜/ .ansible / plugins / modules:/ usr / share / ansible / plugins / modules)
-P POLL_INTERVAL, --poll POLL_INTERVAL
如果使用-B,则设置轮询间隔(默认值= 15)
-a MODULE_ARGS, --args MODULE_ARGS
模块参数
-e EXTRA_VARS, --extra-vars EXTRA_VARS
如果文件名以@开头,则将其他变量设置为key = value或YAML / JSON
-f FORKS, --forks FORKS
指定要使用的并行进程数。(默认值= 5)
-h, --help
显示此帮助消息并退出
-i INVENTORY, --inventory INVENTORY, --inventory-file INVENTORY
指定清单主机路径或逗号分隔的主机列表。 --inventory-file已弃用。
-l SUBSET, --limit SUBSET
将所选主机进一步限制为其他模式
-m MODULE_NAME, --module-name MODULE_NAME
要执行的模块名称。(默认=commond)
-o, --one-line
压缩输出
-t TREE, --tree TREE
日志输出到该目录
-v, --verbose
详细模式(-vvv用于更多,-vvvv用于启用连接调试)
--------------------------------------------------------------
--------------------------------------------------------------
特权升级选项:控制您如何以及在目标主机上成为哪个用户
--become-method BECOME_METHOD
要使用的特权升级方法(默认= sudo),请使用“ ansible-doc -t become -l”列出有效的选择。
--become-user BECOME_USER
以该用户身份运行操作(默认= root)
-K, --ask-become-pass
要求特权升级密码
-b, --become
使用变为运行操作(不表示提示输入密码)
--------------------------------------------------------------
--------------------------------------------------------------
连接选项:控制谁以及如何连接到主机
--private-key PRIVATE_KEY_FILE, --key-file PRIVATE_KEY_FILE
使用此文件来验证连接
--scp-extra-args SCP_EXTRA_ARGS
指定额外的参数以仅传递给scp(例如-l)
--sftp-extra-args SFTP_EXTRA_ARGS
指定额外的参数以仅传递给sftp(例如-f,-l)
--ssh-common-args SSH_COMMON_ARGS
指定要传递给sftp / scp / ssh的通用参数(例如ProxyCommand)
--ssh-extra-args SSH_EXTRA_ARGS
指定额外的参数以仅传递给ssh(例如-R)
-T TIMEOUT, --timeout TIMEOUT
覆盖连接超时(以秒为单位)。(默认值为10)
-c CONNECTION, --connection CONNECTION
要使用的连接类型。(默认=智能)
-k, --ask-pass
询问连接密码
-u REMOTE_USER, --user REMOTE_USER
以该用户身份连接。(默认=无)
ansible常用模块
根据官方的分类,将模块按功能分类为:云模块、命令模块、数据库模块、文件模块、资产模块、消息模块、监控模块、网络模块、通知模块、包管理模块、源码控制模块、系统模块、单元模块、web设施模块、window模块等
command
命令模块,适合使用简单的命令 无法支持"<",">","|",";","&"等符号
- chdir:在执行命令前,进入到指定目录中
- creates:判断指定文件是否存在,如果存在,不执行后面的操作
- removes:判断指定文件是否存在,如果存在,执行后面的操作
- free_form:必须要输入一个合理的命令
ansible webservers -m command -a "hostname"
ansible webservers -m command -a "chdir=/data ls -l"
ansible webservers -m command -a "touch /data/lol.txt creates=/data/lol.txt"
ansible webservers -m command -a "rm -f /data/hosts removes=/data/hosts"
shell
类似command模块升级版—万能模块,可以使用"<",">","|",";","&"等符号特殊符号,其它参数参考command模块,使用方法一致
- chdir:在执行命令前,进入到指定目录中
- creates:判断指定文件是否存在,如果存在,不执行后面的操作
- removes:判断指定文件是否存在,如果存在,执行后面的操作
- free_form:必须要输入一个合理的命令
ansible dkaiyun -m shell -a "ps -ef |grep /[s]sh"
ping
主要用于判断远程客户端是否在线,用于ping本身服务器,用法很简单,不涉及参数,返回值是changed、ping
ansible all -m ping
setup
主要用于获取主机信息,不用option的情况会输出所有相关的对象机器的facts,在playbooks里经常会用到的一个参数gather_facts
就与该模块有关。还有一个经常使用的参数是filter
,使用方法如下:
# 查看所有的信息:CPU、内存、IP等,所有的主机信息都会被收集
ansible all -m setup
# filter :过滤关键字
# 查看主机的内存信息
ansible all -m setup -a 'filter="ansible_*_mb"'
# 查看主机eth0-eth2的网卡信息
ansible all -m setup -a 'filter=ansible_eth[0-2]'
# 收集对象机器的环境变量信息
ansible all -m setup -a "filter=ansible_env"
# --tree :将所有主机的输出信息保存到/tmp/目录下,以/etc/ansible/hosts里的主机名为文件名
ansible all -m setup -a 'filter=ansible_distribution_version' --tree /tmp/
# 把所有的主机信息输入到/tmp/inode目录下,每台主机的信息输入到主机文件名的文件中
ansible all -m setup --tree /tmp/inode
# gather_subset:按子集收集信息,值有all, min, hardware, network, virtual, ohai, facter。不包含请使用!号,如,!network
# 其他常用参数如下:
# ansible_all_ipv4_addresses:仅显示ipv4的信息
# ansible_devices:仅显示磁盘设备信息
# ansible_distribution:显示是什么系统,例:centos,suse等
# ansible_distribution_major_version:显示是系统主版本
# 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_swaptotal_mb:显示总的swap内存
# ansible_swapfree_mb:显示swap内存的可用内存
# ansible_mounts:显示系统磁盘挂载情况
# ansible_processor:显示cpu个数(具体显示每个cpu的型号)
# ansible_processor_vcpus:显示cpu个数(只显示总的个数)
file
file模块主要用于远程主机上的文件操作,file模块包含如下选项:
- force:需要在两种情况下强制创建软连接,一是源文件不存在但之后会建立的情况下,二是目标软连接已存在,需要先取消之前的软连接,然后再创建软连接,两个选项:yes|no
- group/mode/owner:定义文件或目录的属组/权限/属主
- path:必选项,定义文件/目录的路径
- recurse:递归的设置文件的属性,只对目录有效
- scr:要被链接的源文件的路径,只应用于state=link的情况
- dest:被链接到的路径,只应用于state=link的情况
- state=
- directory:如果目录不存在,创建目录
- link:创建软连接
- hard:创建硬链接
- touch:如果文件不存在,则创建文件;如果文件或目录已经存在,则更新其最后修改时间
- absent:删除目录、文件、链接文件
- file:查看指定目录信息是否存在
ansible all -m file -a "src=/etc/fstab dest=/tmp/fstab state=link"
ansible all -m file -a "path=/tmp/fstab state=absent"
ansible all -m file -a "path=/tmp/fstab state=touch"
copy
复制文件到远程主机,copy模块包含如下选项:
- backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no。只有当两个文件的内容不同时才生效
- content:用于替代src,可以直接设定指定文件的值
- dest:必选项。要将源文件复制到远程主机的绝对路径,如果源文件是一个目录,那么该路径必须是一个目录
- directory_mode:递归的设定目录的权限,默认为系统默认权限
- force:如果目标主机包含该文件,但内容不同,如果设置为yes(默认值),则强制覆盖;如果为no,则只有当目标主机的目标位置不存在该文件时才复制
- others:所有的file模块里的选项都可以在这里使用
- src:要复制到远程主机的文件在本地的地址,可以是绝对路径也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"结尾,则只复制目录中的内容,否则,包含整个目录在内的全部内容均被复制,类似rsync
- validate:验证命令在复制到位之前运行。 要验证的文件的路径通过“%s”传递,该路径必须如下面的visudo示例中所示。
ansible all -m copy -a "src=/etc/fstab dest=/data owner=foo group=foo mode=0644" # mode权限之前需要添加一位0。如果想要在user对应的权限位上添加执行权限,则可以使用mode=u+x表示
ansible all -m copy -a "src=/root/anaconda-ks.cfg dest=/data"
echo ansible >>/root/anaconda-ks.cfg
ansible all -m copy -a "src=/root/anaconda-ks.cfg dest=/data backup=yes"
ansible all -m copy -a "src=/etc/sudoers dest=/data validate='visudo -cf %s'" # -cf的意思是检查配置文件是否正常
fetch
抓取文件到管理机上
- src:要获取的远程系统上的文件,必须是文件,而不是目录
- dest:用于保存文件的目录
ansible all -m fetch -a "src=/root/lol.txt dest=/root"
service
用于管理服务,该模块包含如下选项:
- arguments:给命令行提供一些选项
- enabled:是否开机启动yes|no
- name:必选项,服务名称
- pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行
- runlevel:运行级别
- sleep:如果执行了restarted,则在stop和start之间沉睡几秒钟
- status=:对当前服务执行
- started:启动
- stopped:停止
- restarted:重启
- reloaded:重新加载
ansible all -m service -a "name=crond state=started enabled=yes"
ansible all -m service -a "name=nginx state=restarted sleep=10"
ansible all -m service -a "name=foo pattern=/usr/bin/foo state=started"
ansible all -m service -a "name=network state=restarted args=ens32" # centos6
cron
用于管理计划任务,包含如下选项:
- backup:对远程主机上的原任务计划内容修改之前做备份
- cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划
- day/hour/minute/month/weekday:日/小时/分钟/月/周
- job:要这行的任务,依赖于state=present
- name:该任务的描述
- special_time:指定什么时候执行,参数reboot/yearly/annually/monthly/weekly/daily/hourly
- state:确认该任务计划是创建还是删除
- user:以哪个用户的身份执行
- diasbled=yes:将指定的任务注释掉,取消注释使用no。注释和取消注释时必须填写 job和时间参数
# 添加任务计划
ansible all -m cron -a 'name="a job for reboot" special_time=reboot job="/some/job.sh"'
ansible all -m cron -a "name='testx' weekday='2' minute='0' hour=12 user='root' job='cat /etc/passwd >/root/111' cron_file='test ansible'"
ansible all -m cron -a 'backup="True" name="test" minute=0 hour=2 job="ls -alh >/dev/null"'
ansible all -m cron -a "name='ntpdate time' minute=*/5 job='/usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null' "
# 删除任务计划
ansible all -m cron -a "name='a job for reboot' state=absent"
ansible all -m cron -a "name='test' state=absent"
ansible all -m cron -a "name='testx' state=absent"
ansible all -m cron -a 'cron_file=ansible_yum-autoupdate state=absent'
# 注释和取消注释任务
ansible all -m cron -a "name='ntpdate time' minute=*/5 job='/usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null' disabled=yes"
ansible all -m cron -a "name='ntpdate time' minute=*/5 job='/usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null' disabled=no"
yum
使用yum包管理器来管理软件包,其选项有:
- config_file:yum的配置文件
- diasble_gpg_check:关闭gpg_check校验
- disablerepo/enablerepo:启用/关闭某个源
- name:要进行操作的软件包的名字,也可以传递一个url或者笨的的rpm包的路径
- state=
- absent:卸载软件(常用)
- removed:卸载软件
- present:安装软件(常用)
- installed:安装软件
- latest:安装最新版本软件,更新软件
ansible all -m yum -a "name=httpd state=latest"
ansible all -m yum -a "name='@Development tools' state=present"
ansible all-m yum -a 'name=nginx state=installed disable_gpg_check=yes'
get_url
该模块主要用于从http\ftp\https服务器上下载文件,类似于wget。
- sha256sum:下载完成后进行sha 256校验
- timeout:下载超时时间,默认10秒
- url:下载的url
- url_password\url_username:主要用于需要用户名和密码进行验证的情况
- use_proxy:使用代理,代理需要先在环境变量中定义
ansible all -m get_url -a "url=https://www.baidu.com dest=/tmp/baidu.html"
mount
用于批量管理主机进行挂载卸载操作
- fstype:指定挂载的文件系统类型
- opts:指定挂载的参数信息
- path:定义一个挂载点信息
- src:定义设备文件信息
- state=
- absent:会进行卸载,也会修改fstab文件信息
- unmounted:会进行卸载,不会修改fstab文件
- present:不会挂载,只会修改fstab文件
- mounted:会进行挂载,会修改fstab文件
# 只是在/etc/fstab文件中添加了配置信息,不会真正进行挂载(mount -a)
ansible all -m mount -a "src=172.16.1.31:/data/ path=/mnt fstype=nfs state=present"
# 在/etc/fstab文件中添加了配置信息,并且也会真正进行挂载
ansible web01 -m mount -a "src=172.16.1.31:/data/ path=/mnt fstype=nfs state=mounted"
# 在进行挂载的时候,使用state=mounted
# 在进行卸载的时候,使用state=absent
group
远程批量创建用户组信息。
- gid:指创建的组ID信息
- name:指创建组名称信息
- state=
- absent:删除指定的用户组
- present:创建指定的用户组
ansible all -m group -a "name=test gid=1055"
ansible all -m group -a "name=test gid=1055 state=absent"
user
远程批量创建用户信息。
- password:请输入密码信息。password设置密码时不能使用明文方式,只能使用密文方式,可以给用户设置密码,还可以给用户修改密码
- name:指定用户名信息
- uid:指定用户uid信息
- group:指定用户主要属于哪个组
- groups:指定用户属于哪个附加组信息
- shell /bin/bash或/sbin/nologin:指定是否能够登录
- create_home:yes/no,是否创建家目录信息
- home:指定家目录创建在什么路径 默认/home
template
可以将带有参数的配置文件传递到目标地址,可以对文件进行属组属主的修改以及备份(类似copy模块)。
- backup:建立个包括timestamp在内的文件备份,以备不时之需.
- dest:远程节点上的绝对路径,用于放置template文件。
- group:设置远程节点上的的template文件的所属用户组
- mode:设置远程节点上的template文件权限。类似Linux中chmod的用法
- owner:设置远程节点上的template文件所属用户
- src:本地Jinjia2模版的template文件位置。
# 在playbook中的使用方法
# 把/mytemplates/foo.j2文件经过填写参数后,复制到远程节点的/etc/file.conf,文件权限相关略过
- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode=0644
# 跟上面一样的效果,不一样的文件权限设置方式
- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode="u=rw,g=r,o=r"
ansible-playbook
playbook基本语法
playbook使用yaml语法,yaml语法可以通过https://yaml.org/spec/1.2/spec.html或https://www.runoob.com/w3cnote/yaml-intro.html进行详细的学习。
下面是简单的例子:
例子1:简单说明playbook的书写方式
- playbook文件-nginx.yml
---
- hosts: all
tasks:
- name: Install nginx
yum: name=nginx state=present
- name: template nginx.conf
template: src=./nginxbak.conf dest=/etc/nginx/nginx.conf owner=root group=root mode=0644 validate='nginx -t -c %s'
notify:
- Restart Nginx Service
handlers:
- name: Restart Nginx Service # name的值必须与notify的值相同,否则无法触发handle
service: name=nginx state=restarted
- 第1行:表示该文件是YAML文件,非必须
- 第2行:定义了该playbook针对的目标主机,all表示针对所有主机,这个参数支持ansible Ad-Hoc模式的所有参数,也就是可以定义组
- 第3行:定义了该playbook所有的tasks集合,比如下面的3个tasks
- 第4行:定义了一个task的名称,非必须,建议根据task实际任务命名
- 第5行:定义了一个状态的action,这里使用的是yum模块安装nginx软件包
- 第6-9行:使用template模板去管理/etc/nginx/nginx.conf文件;owner和group定义改文件的属主和属组;使用validate参数指定文件产生后使用
nginx -t -c %s
命令去做nginx文件的语法验证;notify是触发handle,如果同步后,文件的MD5值有变化会触发Restart Nginx Service
这个handle - 第10-12行:定义一个handle状态让nginx服务重启,handle的名称是
Restart Nginx Service
- hosts文件
[nginx]
192.168.1.201
192.168.1.203
- 进行语法检查
ansible-playbook nginx.yml --syntax-check
- 查看运行的主机和任务
ansible-playbook nginx.yml --list-task
ansible-playbook nginx.yml --list-hosts
- 执行
ansible-playbook nginx.yml
例子2:任务形式
任务目标
服务器:3台
任务1:安装redis
任务2:修改redis.conf配置文件,指定bind绑定各自的局域网ip(用到template模板)
任务3:启动redis服务
####目录结构
p.yml文件内容
- hosts: web #web组三台服务器,hosts文件配置
remote_user: root #远端服务器以root权限执行
tasks:
- name: install_redis #任务1,下载redis
yum: name=redis
tags: install #指定标签,暂时不用
- name: copy_file #任务2,将本地的redis.conf文件复制到远端服务器
template: dest=/etc/redis.conf src=redis.conf.j2 #这个j2文件内下一步再看
tags: copy
- name: start_redis #任务3,启动redis
service: name=redis state=started
tags: start #指定标签,暂时不用
redis.conf.j2文件内容
首先复制/etc/redis.conf文件到当前文件夹下的templates目录下且命名为 redis.conf.j2。然后编辑改文件内容,文件部分内容看截图。
mkdir templates #新建一个templates文件夹
copy /etc/redis.conf ./templates/redis.conf.j2 #复制配置文件
vim ./templates/redis.conf.j2
ansible_default_ipv4.address 获取每个远程服务器的ipv4内网ip(使用setup模块)
执行文件
ansible-plyabook p.yml
常用的一些复杂变量
playbook中的一些复杂变量
---
# 目标主机支持所有的ad-hoc模式的所有的patterns
- hosts: 172.16.102.109:172.16.102.119
# 远程ssh认证用户
remote_user: root
# 设置playbook的sudo操作
sudo: yes
# 设置playbook的sudo操作
sudo_user: admin
# 设置facts信息收集
gather_facts: no
# 设置accelerate模式(守护进程)
accelarate: no
# 设置accelerate端口
accelerate_port: 5099
# 设置playbook的tasks失败的百分比
max_fail_percentage: 30
# 远程连接的方式
connection: local
# 设置并发数目
serial: 15
# 设置额外的变量
vars:
nginx_port: 80
# 引入变量文件
vars_files:
- "vars.yml"
- ["one.yml","two.yml"]
# 设置引入角色
roles:
- docker
# 设置引入tasks
tasks:
- include: tasks.yml
# 设置运行之后的tasks
post_tasks:
- name: post_tasks
# 设置playbook的handlers
handlers:
- include: handlers.yml
角色roles
ansible_playbook是ansible进行配置管理的组件,由于ad-hoc命令无法支撑复杂的配置管理工作,在我们实际使用ansible的工作中,大部分时间都是在编写playbook。
简单的安装nginx的脚本
# mkdir -p /data/nginx_install/roles/nginx/tasks
# vim /data/nginx_install/site.yml
---
- hosts: all
gather_facts: no
roles:
- nginx # 与文件同级的目录roles下面的目录
# - mysql
# - php
# - java
# vim /data/nginx_install/roles/nginx/tasks/main.yml
---
- name: install nginx
yum: name=nginx state=present
- name: start service nginx
service: name=nginx state=started
# vim /data/nginx_install/hosts
[nginx]
192.168.1.201
目录架构:
roles/
-- nginx # 角色目录
-- files # 角色的file目录
-- index.html # 你的file资源
-- handler
-- main.yml
-- tasks
-- main.yml #nginx这个角色的入口文件
-- templates
-- nginx.conf.j2
site.yml # playbook统一入口文件
引入自定义变量
通过inventory文件来定义变量
# vim hosts
[nginx]
192.168.1.201
192.168.1.203
[nginx:vars]
key1= "i am key1"
# vim var.yml
---
key3: "i am key3"
value3: "i am value"
# vim vars.yml
---
- hosts: all
gather_facts: no
vars:
key2: "i am key2"
vars_files:
- var.yml
tasks:
# 方式一:在hosts文件中引入自定义变量
- name: display key1
debug: msg="{{key1}}"
# 方式二:在playbook文件中引入自定义变量
- name: display key2
debug: msg="{{key2}}"
# 方式三:通过yml文件引入自定义变量
- name: display keys
debug: msg="{{key3}}----->{value3{}}"
# 执行
ansible-playbook -i hosts vars.yml
# 通过命令传入需要加参数-e,这种方法很少用
# 在playbook文件里面使用var_files来传变量
变量传递
使用register变量,在playbook中的task之间进行变量的传递,比如两个tasks,第二个task需要第一个task运行后的结果
---
- hosts: all
gather_facts: no
tasks:
# 第一个task:将命令hostname运行结果赋值给变量info
- name: register var
shell: hostname
register: info
# 第二个task:将变量info的内容打印出来,同时打印字典中的key=stdout的值
- name: display var
debug: msg="{{info}}"
- name: display hostname
debug: msg="{{info.stdout}}"
基本的循环loops
使用with_items这个关键字就可以完成迭代一个列表,列表中的每个变量都叫做item
# 标准的loops(循环列表)
---
- hosts: all
gather_facts: no
tasks:
- name: debug loops
debug: msg="{{item}}" # 等同于"for item in with_items:",其中item、with_items是固定写法
with_items:
- one
- two
- three
- four
# 批量安装软件
---
- hosts: all
gather_facts: no
tasks:
- name: debug loops
yum: name="{{item}}" state=present
with_items:
- nginx
- php
- mariadb
- zabbix
# 循环字典
---
- hosts: all
gather_facts: no
tasks:
- name: debug dic
debug: msg="name-->{{item.key}} val-->{{item.value}}"
with_items:
- {key: "one",value: "value_one"}
- {key: "two",value: "value_two"}
嵌套循环
嵌套loops主要用于一对多或者多对多的合并
---
- hosts: all
gather_facts: no
tasks:
- name: loops in loops
debug: msg="List1-->{{item[0]}} List2-->{{item[1]}}"
with_nested:
- ["a","b","c"]
- [1,2,3,4,5]
文件循环和散列循环
散列loops相比标准的loops,变量支持的数据结构更丰富,例如标准的最外层数据必须是python的list数据类型,而散列loops直接支持yaml格式的数据变量
---
- hosts: all
gather_facts: False
vars:
user:
shan:
name: shan
shell: bash
ceshi:
name: ceshi
shell: ssh
tasks:
- name: debug loops
debug: msg="{{item.key}}:{{item.value}}"
with_dict: "{{user}}"
# 而python实现的方法
# user={'shan':{'name':'shan','shell':bash'},'ceshi':{'name':'ceshi','shell':'ssh'}}
# for i,x in user.items():
# print i,x[name],x[shell]
文件匹配循环
---
- hosts: all
gather_facts: False
tasks:
- name: debug loops
debug: msg="{{item}}"
with_fileglob:
- /etc/*.conf # 输出/etc目录下的所有conf文件
条件判断循环以及组合使用
有时候执行一个tasks之后,我们需要检测这个tasks的结果是否达到了预想状态,如果没有达到我们预想的状态时,就需要退出整个playbook执行,这时候需要对这个task结果一直循环检测。
例如:5秒执行一次cat /root/ansible
,将结果赋值给变量hosts,然后判断hosts.stdout.startswitch
的内容是否以Master字符串开头,如果条件成立,此task运行完成,否则5秒后重试,5次后还不成立,此task运行失败。
---
- hosts: all
gather_facts: False
tasks:
- name: debug IF
shell: cat /root/ansible
register: hosts
until: hosts.stdout.startswith("Master")
retries: 5
delay: 5
例如:要么循环5次,要么5次循环还没跑完间隔10s, 但是result.stdout中找到 “all systems go”这几个字母,然后这个task就不跑了(默认的retries=3, delay=5)
---
- hosts: all
gather_facts: False
tasks:
- action: shell /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10
For循环的使用
---
- hosts: all
gather_facts: no
tasks:
- name: debug loops
shell: "{{item}}"
with_items:
- hostname
- uname
register: ret
- name: display ret
debug: msg="{% for i in ret.results %} {{ i.stdout }} {% endfor %}"
when语句逻辑判断
ansible支持从外部拉取信息,比如可以从数据库里面读取信息然后定义给一个变量的形式,这就是ansible的lookups插件。ansible中所有的conditionals都是使用when来判断的,when值是一个条件表达式,如果天剑判断成立,这个task就执行某个操作,否则不执行或者跳过。
---
- hosts: all
tasks:
# 判断IP是否为192.168.1.201
- name: IP192.168.1.201 run this task
debug: msg="{{ansible_default_ipv4.address}}"
when: ansible_default_ipv4.address=="192.168.1.201"
# 判断主机名是否为inode203
- name: all host run this task
shell: hostname
register: info
- name: Hostname is inode203 run this task
debug: msg="{{ansible_fqdn}}"
when: info['stdout']=="inode203"
# 判断主机名中是否包含特定字符207
- name: Hostname is startswith M run this task
debug: msg="{{ansible_fqdn}}"
when: info['stdout'].find("207") != -1
Centos系统,版本号为7,满足这两个条件会在 /home/创建123.test 文件
- name: touch centos
command: touch /home/123.test
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"
tags:
- touch_Cent
组条件判断:
# 使用括号对条件进行分组
---
- hosts: localhost
gather_facts: yes
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: ls -a
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
# 所有需要为true的多条件判读(逻辑“and”) 也可以指定为列表
---
- hosts: localhost
gather_facts: yes
tasks:
- name: "shut down CentOS 7 systems"
command: ls -a
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "7"
when判断是centos还是Ubuntu系统后在安装http
- hosts: all
tasks:
- name: "update apache version - yum"
yum: name=httpd state=present
when:
- ansible_pkg_mgr == 'yum'
notify: restart httpd
- name: "Update apache version - apt"
apt: name=apache2 state=present update_cache=yes
when:
- ansible_pkg_mgr == 'apt'
notify: restart apache2
handlers:
- name: restart apache2
service: name=apache2 state=restarted
- name: restart httpd
service: name=httpd state=restarted
在when
语句中也可以使用过滤器。如,我们想跳过一个语句执行中的错误,但是后续的任务的执行需要由该任务是否成功执行决定:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
更多内容参考https://www.cnblogs.com/gzxbkk/p/7608055.html
ansible(自动部署lnmp+hdwiki)
- 架构与流程
在做一个比较复杂的事情的时候,需要理清思路,通过画图将思路理清楚,可以使用思维导图
- 写代码
cd /data
mkdir hdwiki
cd hdwiki
vim site.yml #编辑site.yml
mkdir roles
cd roles
mkdir nginx mysql hdwiki base -p
# 角色base:配置yum源
cd /data/roles/base
mkdir tasks files
cd /data/roles/base/files # 将yum源的配置文件development.repo放在此目录下
cd /data/roles/base/tasks
vim main.yml
# 设置主机清单
cd /data/roles/hdwiki
vim hosts
[hdwiki]
192.168.1.201
192.168.1.203
[hdwiki:vars]
nginx=nginx-1.4.4-1.x86_64.rpm
php=php-5.3.10-1.x86_64.rpm
user=hdwiki
password=wiki123456
database=wiki
# 角色nginx
cd /data/roles/nginx
mkdir tasks files
cd /data/roles/nginx/tasks
vim main.yml
# 角色mysql
cd /data/roles/mysql
mkdir tasks files
cd /data/roles/mysql/tasks
vim main.yml
# 角色hdwiki
cd /data/roles/hdwiki
mkdir tasks files
cd /data/roles/hdwiki/tasks
vim main.yml
# 执行
cd /data/roles/hdwiki
ansible-playbook -i hosts site.yml
playbook文件
# 总入口文件site.yml
---
- hosts: all
roles:
- base
- nginx
- mysql
- hdwiki
# base的入口文件main.yml
---
- copy: scr=development.repo dest=/etc/yum.repos.d/development.repo
- shell: yum makecache
# nginx的入口
---
- yum: name={{item}} state=present
with_items:
- libtool-libs
- libXpm-devel
- fontconfig-devel
- libpng
- libjpeg-turbo
- shell: mkdir -p /usr/local/services
- name: copy nginx rpm
copy: src={{nginx}} dest=opt/{{nginx}}
- shell: rpm-qa| grep nginx || rpm -ivh /opt/{{nginx}} # 已经安装了的机器不需要再安装
- service: name=nginx state=restarted
- copy: src={{php}} dest=opt/{{php}}
- shell: rpm-qa| grep php || rpm -ivh /opt/{{php}}
- service: name=php-fpm state=restarted
# mysql的入口
---
- yum: name={{item}} state=present
with_items:
- mysql-server
- mysql-python
- service: name=mysqld state=started
- mysql_db: name={{database}} state=present
- mysql_user: name={{user}} password={{password}} priv=*.*:ALL host="%" state=present
- mysql_user: name={{user}} password={{password}} priv=*.*:ALL host="localhost" state=present
# hdwiki的入口
---
- unarchive: src=wiki.tar.gz dest=/data/htdocs/www
- shell: chown -R www:www /data/htdocs/www
ansible-jinja2
jinja2是ansible的默认的模板语音,jinjia2是目前比较流行的一款模板语音,ansible默认支持jinja2语言内的filter,jinja2也提供了很多filter。
字符串过滤器:
- safe:禁止转义,渲染时不会转义特殊字符
- capitallize:把首字母转大写,其他的字母转小写
- lower:把所有的字母转小写
- upper:把所有字母转大写
- title:把每个单词的首字母转大写
- trim:去掉首尾空格
- striptags:去掉所有的HTML标签
- replace:替换字符串的值
- round:对数字四舍五入
- int:转换成int类型
- default:定义变量的默认值
- reverse:字符串反转
- format:格式化输出,例如{{ '%s is %d' | format("Number", 2) }},返回值"Number is 2"
- abs:绝对值
列表过滤器: - first:获取列表的第一个元素
- last:获取列表的最后一个
- sort:排序
- sum:列表求和
- length:求列表长度
- join:将多个值拼接成字符串,类似python的join()函数
- max:最大值
- min:最小值
- random:获取随机值
列表中所有元素都全大写。这里可以用upper,lower,但capitalize无效
更多内容参考
https://jinja.palletsprojects.com/en/2.10.x/
https://www.cnblogs.com/mauricewei/p/10056379.html
---
- hosts: all
gather_facts: False
vars:
list: [1,2,3,4,5]
one: "1"
str: "string"
tasks:
# 执行命令,并将结果赋值给变量info
- name: run commands
shell: df -h
register: info
# 对变量info使用pprint进行格式化,debug时使用可以打印变量的详细信息
- name: debug pprint filter
debug: msg="{{info.stdout|pprint}}"
- name: debug info
debug: msg="{{info}}"
# 判断info[changed]值,如果为true,则执行debug
- name: debug conditionals filter
debug: msg="the run commands status is changed"
when: info.changed
# 对变量one的值进行int转变,对变量str的值进行首字母大写操作
- name: debug int capitalize filter
debug: msg="The int value {{one|int}}. The lower value is {{str|capitalize}}"
# 如果ansible变量定义了就引用其值,否则就定义其默认值为"ansible is not define"
- name: debug default filter
debug: msg="The variable value is {{ansible|default('ansible is not define')}}"
# 获取变量列表list中的最大值和最小值
- name: debug list max and min filter
debug: msg="The list max value is {{list|max}} and min value is {{list|min}}"
# 随意选取一个list内的值,然后随机生成一个1000以内的数据,以1开始且步长为10
- name: debug random filter
debug: msg="The list random value is {{list|random}} and generate a random value is {{1000|random(1,10)}}"
# 将list内的值连接在一起形成字符串
- name: debug join filter
debug: msg="The join filter value is {{list| join("+")}}"
# 将变量str中的字母t替换为T
- name: debug replace filter
debug: msg="The replace value is {{str|replace('t','T')}}"
# string==>strawen,将string变量ri以及之后的所有字符替换为awen
- name: debug regex_replace filter
debug: msg="The regex_replace value is {{str|regex_replace(('ri(.*)$'),'awen')}}"
循环与判断:
---
- hosts: all
gather_facts: no
tasks:
# 解析之后执行,执行结果写入被控端/tmp/f2
- template: src=f2.j2 dest=/tmp/f2
f2.j2文件
{% set list=['one','two','three'] %}
{% set dict={'1':'one','2':'two','3':'three'} %}
{% set dict1={'1':{'1.1':{'1.2':'one point two'}} %}
# 循环
{% for i in list %}
{{i}}
{% endfor %}
{% for key,value in dict.iteritems() %}
{{key}}--->{{value}}
{% endfor %}
# 判断
{% for i in list %}
{% if i=='one' %} # 值为one则打印
--->{{i}}
{% elif loop.index==2 %} # 索引为2(two)则打印
--->>{{i}}
{% else %}
--->>>{{i}}
{% endif %}
{% endfor %}
# 多层嵌套字典取值
{{dict1['1']['1.1']['1.2']}}
jinja2中可以使用set定义临时变量也可以直接使用ansible其他地方定义的变量,关于jinja2变量的引用都是采用{{变量名}}
的方式,当然里面还可以根据变量名数据类型选择你想要的信息,比如dict={'key':'value'}
,直接{{dict}}
会返回一个python的字典数据,如果只需要key对应的值,则需要{{dict['key']}}
或{{dict.get('key')}}
。
ansible-一键部署haproxy+lnmp
首先需要知道我们需要什么样的架构,然后我们了解整个架构每个组件之间是如何衔接和交互的,当然我们还要清除架构中每一个组件的原理和流程。
haproxy是一款提供高可用、负载均衡以及基于TCP和HTTP应用的代理软件,目前很多大公司也在使用其做web集群和cache集群的负载均衡以及代理
整个架构的数据流向:
- haproxy代理以及负载的nginx+php
- nginx+php的web功能
- mysql功能
架构
目录结构及角色
haproxy_lnmp
├── group_vars
│ ├── all
│ ├── haproxy
│ └── mysql
├── hosts
├── roles
│ ├── base
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ ├── CentOS-Base.repo
│ │ └── epel.repo
│ ├── haproxy
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ └── haproxy.cfg.j2
│ ├── mysql
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ └── my.cnf.j2
│ ├── nginx
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ ├── index.php.j2
│ │ └── nginx.conf.j2
│ └── php
│ └── tasks
│ └── main.yml
└── site.yml
变量
全局变量
# cat group_vars/all
---
ansible_ssh_pass: P@ssw0rd
mysql变量
# cat group_vars/mysql
---
user: ansible
password: ansible
database: ansible
mysql_port: 3306
haprxoy变量
# cat group_vars/haproxy
---
mode: http
listenport: 80
hosts列表
# cat hosts
[nginx]
192.168.1.201
192.168.1.203
[php]
192.168.1.201
192.168.1.203
[mysql]
192.168.1.203
[haproxy]
192.168.1.207
入口文件site.yml
---
- name: Modify the yum
gather_facts: no
hosts: all
remote_user: root
roles:
- base
- name: Install the nginx
hosts: nginx
remote_user: root
roles:
- nginx
- name: Install the mysql
gather_facts: no
hosts: mysql
remote_user: root
roles:
- mysql
- name: Install the php
gather_facts: no
hosts: php
remote_user: root
roles:
- php
- name: Install the haproxy
gather_facts: no
hosts: haproxy
remote_user: root
roles:
- haproxy
角色
base
入口文件
# cat roles/base/tasks/main.yml
---
- name: Copy the yum repo to the remote hosts
template: src={{item}} dest=/etc/yum.repos.d/{{item}}
with_items:
- CentOS-Base.repo
- epel.repo
yum源文件
yum源文件,可以使用阿里、163或清华大学等源
# ll roles/base/templates/
total 8
-rw-r--r-- 1 root root 1663 Jul 21 17:50 CentOS-Base.repo
-rw-r--r-- 1 root root 970 Jul 21 17:50 epel.repo
# more roles/base/templates/CentOS-Base.repo
[base]
name=CentOS-$releasever - Base - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
enabled=1
gpgcheck=0
[updates]
name=CentOS-$releasever - Updates - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/
enabled=1
gpgcheck=0
[extras]
name=CentOS-$releasever - Extras - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/
enabled=1
gpgcheck=0
[centosplus]
name=CentOS-$releasever - Plus - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/
enabled=1
gpgcheck=0
[contrib]
name=CentOS-$releasever - Contrib - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/$releasever/contrib/$basearch/
enabled=1
gpgcheck=0
# epel.repo
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
enabled=1
gpgcheck=0
[epel-debuginfo]
name=Extra Packages for Enterprise Linux 7 - $basearch - Debug
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch
enabled=1
gpgcheck=0
[epel-source]
name=Extra Packages for Enterprise Linux 7 - $basearch - Source
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=$basearch
enabled=1
gpgcheck=0
nginx
入口文件
# cat roles/nginx/tasks/main.yml
---
- name: Install Nginx Package
yum: name=nginx state=present
- name: Copy Nginx.conf
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=0644 validate='nginx -t -c %s'
- name: restart nginx
service: name=nginx state=restarted enabled=yes
- name: Copy php file to nginx web root
template: src=index.php.j2 dest=/usr/share/nginx/html/index.php
配置文件
nginx配置文件是同版本的配置文件
# ll roles/nginx/templates/
total 8
-rw-r--r-- 1 root root 34 Jul 21 19:21 index.php.j2
-rw-r--r-- 1 root root 2491 Jul 21 17:50 nginx.conf.j2
# cat roles/nginx/templates/index.php.j2
# 网页文件,获取nginx主机的IP
{{ansible_default_ipv4.address}}
# cat roles/nginx/templates/nginx.conf.j2
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
php
# cat roles/php/tasks/main.yml
---
- name: Install php
yum: name={{item}} state=installed
with_items:
- php-fpm
- php-mysql
- name: start php service
service: name=php-fpm state=started enabled=yes
mysql
入口文件
# cat roles/mysql/tasks/main.yml
---
- name: Install mysql
yum: name={{item}} state=installed
with_items:
- mariadb-server
- MySQL-python
- name: Configure the mysql cnf file with hosts
template: src=my.cnf.j2 dest=/etc/my.cnf owner=root group=root mode=0644
- name: Start mariadb service
service: name=mariadb state=started enabled=yes
- name: Create database
mysql_db: name={{database}} state=present
- name: Create user
mysql_user: name={{user}} password={{password}} priv={{database}}.*:ALL host='%' state=present
配置文件
# cat roles/mysql/templates/my.cnf.j2
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
port={{ mysql_port }}
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mariadb/mysqld.pid
haproxy
入口文件
# cat roles/haproxy/tasks/main.yml
- name: Install haproxy
yum: name=haproxy state=present
- name: Configure the haproxy cnf file with hosts
template: src=haproxy.cfg.j2 dest=/etc/haproxy/haproxy.cfg
- name: restart haproxy
service: name=haproxy state=restarted enabled=yes
配置文件
# cat roles/haproxy/templates/haproxy.cfg.j2
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
defaults
mode {{mode}}
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend main *:{{listenport}}
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .gif .png .css .js
use_backend static if url_static
default_backend app
backend static
balance roundrobin
server static 127.0.0.1:8080 check
backend app
balance roundrobin
{% for host in groups['nginx'] %}
server {{hostvars[host]['inventory_hostname']}} {{host}}:80}
# server {{hostvars[host]['ansible_hostname']}} {{hostvars[host]['inventory_hostname']}}:80 check inter 3000 rise 3 fall 2
{% endfor %}
语法检查
只检查site.yml入口文件,不能检查各个角色下的main.yml
ansible-playbook site.yml --syntax-check
playbook: site.yml
执行
ansible-playbook -i hosts site.yml
测试
curl 192.168.1.201
curl 192.168.1.203
curl 192.168.1.207
curl 192.168.1.207
curl 192.168.1.207
curl 192.168.1.207
排错
在入口文件site.yml中的nginx角色没有使用gather_facts: no选项,是因为index.php中要获取主机的信息得到IP地址。
ansible优化执行速度
开启ssh长连接
ansible模式是使用ssh和被管理机器进行通信的,所以ansible对ssh的依赖非常强。
ansible在openssh5.6版本以后可以支持multiplexing,在ansible.cfg
文件中设置ssh长连接,设置参数如下:
# vim /etc/ansible/ansible.cfg
sh_args = -C -o ControlMaster=auto ControlPersist=5d
# ControlPersist=5d :设置整个长连接保持时间为5天,如果开启后通过ssh连接过的设备都会在当前ansible/cp目录下产生一个socket文件,也可以通过netstat命令查看,会发现有一个状态为ESTABLISHED的连接一直与被控端进行TCP连接
开启pipelining
pipelining也是openssh的一个特性,之前的流程是在本地产生一个py的文件,然后put到被控端上面再执行这个py脚本。如果开启pipelining,这个过程将会在ssh的会话中进行。
如果需要开启pipelining,则需要在被控端/etc/sudoers文件编辑当前ansible ssh用户的配置为requirety。
# vim /etc/ansible/ansible.cfg
pipelining = True
开启accelerate
和前面的ssh的长连接有点类似,因为都依赖ansible控制端和被控端有一个长连接,但是accelerate是使用python在被控端运行一个守护进行,然后ansible会通过这个守护进行监听的端口进行通信,开启accelarate模式,则需要在ansible控制端和被控端都安装python-keyczar软件包
# vim /etc/ansible/ansible.cfg
[accelerate]
accelerate_port=5099
accelerate_timeout=30
accelerate_connect_timeout=5.0
设置facts缓存
在playbook里面有一个gather_facts:yes
选项,用来收集远端机器的信息,比较浪费时间,执行一次之后,将结果保存一定时间可以节省后面执行playbook的时间,从而提高效率
# vim /etc/ansible/ansible.cfg
gathering = smart
fact_caching_timeout = 86400
fact_caching = jsonfile
fact_cashing_connection = /dev/shm/ansible_fact_cache
# ansible支持将数据放到redis里面,读取速度会更快
gathering = smart
fact_caching_timeout = 86400
fact_caching = redis
ansible目录标准化
参考https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html
官网最佳实践中推荐使用的ansible工作目录的结构,统一工作目录如下:
Project
├── hosts # 主机清单
├── site.yml # playbook统一入口文件
├── webservers.yml # 特殊任务playbook文件【一般不用】
├── java # java环境的inventory文件
├── web # web环境的inventory文件
├── library # 自定义模块存放的目录
├── filter_plugins # 自定义filter插件存放的目录
├── group_vars # 自定义变量存放文件夹
│ ├── all # 全局变量
│ ├── role1 # role1使用的变量
│ └── role2
├── host_vars # 自定义变量存放文件夹,功能同group_vars【一般不用】
│ ├── all # 全局变量
│ ├── host1 # role1使用的变量
├── roles #角色存放的目录
│ ├── role1 # 角色1目录
│ │ ├── tasks # 存放playbook的目录,其中main.yml是主入口文件
│ │ │ └── main.yml # 在main.yml中导入其他yml文件,要采用import_tasks关键字
│ │ | └── install.yml
│ │ ├── handles # 存放tasks中的notify指定的内容
│ │ │ └── main.yml
│ │ ├── files # unarchive、copy等模块会来这找文件,不必写绝对路径,只需写文件名
│ │ | ├── mysql.tar.gz
│ │ | └── nginx.tar.gz
│ │ └── templates # template模块需要用的文件存放目录,存放的是软件的配置文件
│ │ ├── index.php.j2 # 使用jinja2格式作为文件模板,进行文档内变量替换的模块
│ │ └── nginx.conf.j2
# 举例:
haproxy_lnmp
├── group_vars
│ ├── all
│ ├── haproxy
│ └── mysql
├── hosts
├── roles
│ ├── base
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ ├── CentOS-Base.repo
│ │ └── epel.repo
│ ├── haproxy
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ └── haproxy.cfg.j2
│ ├── mysql
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ └── my.cnf.j2
│ ├── nginx
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── templates
│ │ ├── index.php.j2
│ │ └── nginx.conf.j2
│ └── php
│ └── tasks
│ └── main.yml
└── site.yml
ansible-项目实战-批量部署
需求和目的
通过ansible制作一个初始化脚本,采用标准化半自动化流程,可移植、可复用、步骤明确、操作简便、低故障、责任明确。
初始化操作
- 配置yum源
- 安装常用软件和机器所需软件:wget、vim、unzip、net-tools、gcc、ntpdate等
- 配置防火墙
- 配置SeLinux(关闭)
- 生成秘钥,发送公钥
- 修改ssh配置文件,修改ssh连接的默认端口
- 配置DNS、hostname、IP等
- 配置时间同步服务器,添加到crontab
- 调优,优化内核参数:提高打开文件数量、配置nginx最大连接数等等
- IO测试,磁盘性能
- ......
创建所有的角色
- base,替换yum源
- public,秘钥
- yum,安装依赖
- crontab,配置时间服务器等
- iptables,关闭selinux、NetworkManager和iptables配置
- init,调优初始化
- install,安装软件
- ssh_config,修改ssh的配置
mkdir -p setup_init/roles/{base,public,yum,crontab,iptables,init,install,ssh_config}/{tasks,templates,files}
开发
目录结构
/root/
└── setup_init
└── roles
├── base
│ ├── files
│ │ ├── CentOS-Base.repo
│ │ └── epel.repo
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── crontab
│ ├── files
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── init
│ ├── files
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── install
│ ├── files
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── iptables
│ ├── files
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── public
│ ├── files
│ │ └── id_rsa.pub
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── ssh_config
│ ├── files
│ ├── tasks
│ │ └── main.yml
│ └── templates
└── yum
├── files
├── tasks
│ └── main.yml
└── templates
入口文件
base/tasks/main.yml
---
- copy: src=CentOS-Base.repo dest=/etc/yum.repos.d/CentOS-Base.repo
- copy: src=epel.repo dest=/etc/yum.repos.d/epel.repo
- shell: yum makecache
public/tasks/main.yml
---
- shell: mkdir -p ~/.ssh
- copy: src=id_rsa.pub dest='~/.ssh/id_rsa.pub_tmp' force=yes
- shell: cat '~/.ssh/id_rsa.pub_tmp' >>'~/.ssh/zuthorized_keys'
yum/tasks/main.yml
---
- yum: name={{item}} state=present
with_items:
- vim
- unzip
- wget
- gcc
- net-tools
- tree
- ntpdate
crontab/tasks/main.yml
---
- cron: minute */2 hour=* day=* month=* name=uptime job='ntpdate time.windows.com >/dev/null' state=present
iptables/tasks/main.yml
---
- serivce: name=NetworkManager state=stopped enabled=no
- shell: setenforce 0
# 防火墙根据要求进行配置
init/tasks/main.yml
---
# 根据实际情况进行优化
install/tasks/main.yml
---
# 根据实际情况进行安装