ansible安装配置手册
一、安装
1、Centos系统
1 yum install -y epel-release #更新源 2 yum install -y ansible #安装 3 tree /etc/ansible/ #查看结构
tree /etc/ansible/
/etc/ansible/
├── ansible.cfg #ansible的配置文件
├── hosts #ansible的主仓库,用于存储需要管理的远程主机的相关信息
└── roles #角色
2、Ubuntu系统
1 sudo apt-add-repository ppa:ansible/ansible #更新源 2 sudo apt-get update #更新缓存 3 sudo apt-get install ansible #安装
二、配置
1、配置主机清单
1.1、简单介绍
1 vim /etc/ansible/hosts
例如:
mail.example.com
[webservers]
foo.example.com
bar.example.com
[dbservers]
one.example.com
two.example.com
three.example.com
方括号[]中是组名,用于对系统进行分类,便于对不同系统进行个别的管理.
端口号不是默认设置时,可明确的表示为:
badwolf.example.com:5309
假设你有一些静态IP地址,希望设置一些别名,但不是在系统的 host 文件中设置,又或者你是通过隧道在连接,那么可以设置如下:
jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50
在这个例子中,通过 “jumper” 别名,会连接 192.168.1.50:5555.记住,这是通过 inventory 文件的特性功能设置的变量. 一般而言,这不是设置变量(描述你的系统策略的变量)的最好方式.
一组相似的 hostname , 可简写如下:
[webservers] www[01:50].example.com
数字的简写模式中,01:50 也可写为 1:50,意义相同.你还可以定义字母范围的简写模式:
[databases]
db-[a:f].example.com
对于每一个 host,你还可以选择连接类型和连接用户名:
[targets] localhost ansible_connection=local other1.example.com ansible_connection=ssh ansible_ssh_user=mpdehaan other2.example.com ansible_connection=ssh ansible_ssh_user=mdehaan
所有以上讨论的对于 inventory 文件的设置是一种速记法,后面我们会讨论如何将这些设置保存为 ‘host_vars’ 目录中的独立的文件.
1.2、主机变量
前面已经提到过,分配变量给主机很容易做到,这些变量定义后可在 playbooks 中使用:
[atlanta] host1 http_port=80 maxRequestsPerChild=808 host2 http_port=303 maxRequestsPerChild=909
1.3、组的变量
也可以定义属于整个组的变量:
[atlanta] host1 host2 [atlanta:vars] ntp_server=ntp.atlanta.example.com proxy=proxy.atlanta.example.com
1.4、把一个组作为另一个组的子成员
可以把一个组作为另一个组的子成员,以及分配变量给整个组使用. 这些变量可以给 /usr/bin/ansible-playbook 使用,但不能给 /usr/bin/ansible 使用:
[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
如果你需要存储一个列表或hash值,或者更喜欢把 host 和 group 的变量分开配置,请看下一节的说明.
1.5、分文件定义 Host 和 Group 变量
在 inventory 主文件中保存所有的变量并不是最佳的方式.还可以保存在独立的文件中,这些独立文件与 inventory 文件保持关联. 不同于 inventory 文件(INI 格式),这些独立文件的格式为 YAML.详见 YAML 语法 .
假设 inventory 文件的路径为:
/etc/ansible/hosts
假设有一个主机名为 ‘foosball’, 主机同时属于两个组,一个是 ‘raleigh’, 另一个是 ‘webservers’. 那么以下配置文件(YAML 格式)中的变量可以为 ‘foosball’ 主机所用.依次为 ‘raleigh’ 的组变量,’webservers’ 的组变量,’foosball’ 的主机变量:
/etc/ansible/group_vars/raleigh /etc/ansible/group_vars/webservers /etc/ansible/host_vars/foosball
举例来说,假设你有一些主机,属于不同的数据中心,并依次进行划分.每一个数据中心使用一些不同的服务器.比如 ntp 服务器, database 服务器等等. 那么 ‘raleigh’ 这个组的组变量定义在文件 ‘/etc/ansible/group_vars/raleigh’ 之中,可能类似这样:
---
ntp_server: acme.example.org
database_server: storage.example.org
这些定义变量的文件不是一定要存在,因为这是可选的特性.
还有更进一步的运用,你可以为一个主机,或一个组,创建一个目录,目录名就是主机名或组名.目录中的可以创建多个文件, 文件中的变量都会被读取为主机或组的变量.如下 ‘raleigh’ 组对应于 /etc/ansible/group_vars/raleigh/ 目录,其下有两个文件 db_settings 和 cluster_settings, 其中分别设置不同的变量:
/etc/ansible/group_vars/raleigh/db_settings
/etc/ansible/group_vars/raleigh/cluster_settings
‘raleigh’ 组下的所有主机,都可以使用 ‘raleigh’ 组的变量.当变量变得太多时,分文件定义变量更方便我们进行管理和组织. 还有一个方式也可参考,详见 Ansible Vault 关于组变量的部分. 注意,分文件定义变量的方式只适用于 Ansible 1.4 及以上版本.
Tip: Ansible 1.2 及以上的版本中,group_vars/ 和 host_vars/ 目录可放在 inventory 目录下,或是 playbook 目录下. 如果两个目录下都存在,那么 playbook 目录下的配置会覆盖 inventory 目录的配置.
Tip: 把你的 inventory 文件 和 变量 放入 git repo 中,以便跟踪他们的更新,这是一种非常推荐的方式.
2、Inventory 参数的说明
如同前面提到的,通过设置下面的参数,可以控制 ansible 与远程主机的交互方式,其中一些我们已经讲到过:
ansible_ssh_host 将要连接的远程主机名.与你想要设定的主机的别名不同的话,可通过此变量设置. ansible_ssh_port ssh端口号.如果不是默认的端口号,通过此变量设置. ansible_ssh_user 默认的 ssh 用户名 ansible_ssh_pass ssh 密码(这种方式并不安全,我们强烈建议使用 --ask-pass 或 SSH 密钥) ansible_sudo_pass sudo 密码(这种方式并不安全,我们强烈建议使用 --ask-sudo-pass) ansible_sudo_exe (new in version 1.8) sudo 命令路径(适用于1.8及以上版本) ansible_connection 与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist, 来判断'ssh' 方式是否可行. ansible_ssh_private_key_file ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况. ansible_shell_type 目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为 'csh' 或 'fish'. ansible_python_interpreter 目标主机的 python 路径.适用于的情况: 系统中有多个 Python, 或者命令路径不是"/usr/bin/python",比如 \*BSD, 或者 /usr/bin/python 不是 2.X 版本的 Python.我们不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,且要求 "python" 可执行程序名不可为 python以外的名字(实际有可能名为python26). 与 ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....
一个主机文件的例子:
some_host ansible_ssh_port=2222 ansible_ssh_user=manager aws_host ansible_ssh_private_key_file=/home/example/.ssh/aws.pem freebsd_host ansible_python_interpreter=/usr/local/bin/python ruby_module_host ansible_ruby_interpreter=/usr/bin/ruby.1.9.3
三、操作示例
1、使用 shell 模块
示例如下:
1 ansible raleigh -m shell -a 'echo $TERM'
使用 Ansible ad hoc 命令行接口时(与使用 Playbooks 的情况相反),尤其注意 shell 引号的规则. 比如在上面的例子中,如果使用双引号"echo $TERM",会求出TERM变量在当前系统的值,而我们实际希望的是把这个命令传递 到其它机器执行.
在此我们已经演示了一些简单命令如何去执行,但通常来讲大多数 Ansible 模块的工作方式与简单的脚本不同.They make the remote system look like you state, and run the commands necessary to get it there.这一般被称为 'idempotence', 是 Ansible 设计的核心目标.但我们也认识到,能运行任意命令也是重要的,所以 Ansible 对这两者都做支持.
2、文件传输
这是 /usr/bin/ansible 的另一种用法.Ansible 能够以并行的方式同时 SCP 大量的文件到多台机器. 命令如下
1 ansible atlanta -m copy -a "src=/etc/hosts dest=/tmp/hosts"
若你使用 playbooks, 则可以利用 template
模块来做到更进一步的事情.
使用 file
模块可以做到修改文件的属主和权限,(在这里可替换为 copy
模块,是等效的):
1 nsible webservers -m file -a "dest=/srv/foo/a.txt mode=600" 2 ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan"
使用 file
模块也可以创建目录,与执行 mkdir -p
效果类似:
1 ansible webservers -m file -a "dest=/path/to/c mode=755 owner=mdehaan group=mdehaan state=directory"
删除目录(递归的删除)和删除文件:
1 ansible webservers -m file -a "dest=/path/to/c state=absent"
3、管理软件包
Ansible 提供对 yum 和 apt 的支持.这里是关于 yum 的示例.
确认一个软件包已经安装,但不去升级它:
1 ansible webservers -m yum -a "name=acme state=present"
确认一个软件包的安装版本:
1 ansible webservers -m yum -a "name=acme-1.5 state=present"
确认一个软件包还没有安装:
1 ansible webservers -m yum -a "name=acme state=absent"
对于不同平台的软件包管理工具,Ansible都有对应的模块.如果没有,你也可以使用 command 模块去安装软件. 或者最好是来为那个软件包管理工具贡献一个相应的模块.请在 mailing list 中查看相关的信息和详情.
3、用户和组
使用 ‘user’ 模块可以方便的创建账户,删除账户,或是管理现有的账户:
1 ansible all -m user -a "name=foo password=<crypted password here>" 2 ansible all -m user -a "name=foo state=absent"
更多可用的选项请参考 模块相关 ,包括对组和组成员关系的操作.
4、源码部署
直接使用 git 部署 webapp:
1 ansible webservers -m git -a "repo=git://foo.example.org/repo.git dest=/srv/myapp version=HEAD"
因为Ansible 模块可通知到 change handlers ,所以当源码被更新时,我们可以告知 Ansible 这个信息,并执行指定的任务, 比如直接通过 git 部署 Perl/Python/PHP/Ruby, 部署完成后重启 apache.
5、服务管理
确认某个服务在所有的webservers上都已经启动:
1 ansible webservers -m service -a "name=httpd state=started"
或是在所有的webservers上重启某个服务(译者注:可能是确认已重启的状态?):
1 ansible webservers -m service -a "name=httpd state=restarted"
确认某个服务已经停止:
1 ansible webservers -m service -a "name=httpd state=stopped"
6、让程序运行,不必等待返回结果
需要长时间运行的命令可以放到后台去,在命令开始运行后我们也可以检查运行的状态.如果运行命令后,不想获取返回的信息, 可执行如下命令:
1 ansible all -B 3600 -P 0 -a "/usr/bin/long_running_operation --do-stuff"
如果你确定要在命令运行后检查运行的状态,可以使用 async_status 模块.前面执行后台命令后会返回一个 job id, 将这个 id 传给 async_status 模块:
1 ansible web1.example.com -m async_status -a "jid=488359678239.2844"
获取状态的命令如下:
1 ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"
其中 -B 1800
表示最多运行30分钟, -P 60
表示每隔60秒获取一次状态信息.
Polling 获取状态信息的操作会在后台工作任务启动之后开始.若你希望所有的工作任务快速启动, --forks
这个选项的值 要设置得足够大,这是前面讲过的并发进程的个数.在运行指定的时间(由``-B``选项所指定)后,远程节点上的任务进程便会被终止.
一般你只能在把需要长时间运行的命令或是软件升级这样的任务放到后台去执行.对于 copy 模块来说,即使按照前面的示例想放到 后台执行文件传输,实际上并不会如你所愿.
四、playbook基础
1、主机与用户
你可以为 playbook 中的每一个 play,个别地选择操作的目标机器是哪些,以哪个用户身份去完成要执行的步骤(called tasks).
- hosts 行的内容是一个或多个组或主机的 patterns,以逗号为分隔符.
-
remote_user 就是账户名:
--- - hosts: webservers remote_user: root
Note
参数 remote_user 以前写做 user,在 Ansible 1.4 以后才改为 remote_user.主要为了不跟 user 模块混淆(user 模块用于在远程系统上创建用户).
再者,在每一个 task 中,可以定义自己的远程用户:
--- - hosts: webservers remote_user: root tasks: - name: test connection ping: remote_user: yourname
Note
task 中的 remote_user 参数在 1.4 版本以后添加.
也支持从 sudo 执行命令:
--- - hosts: webservers remote_user: yourname sudo: yes
同样的,你可以仅在一个 task 中,使用 sudo 执行命令,而不是在整个 play 中使用 sudo:
--- - hosts: webservers remote_user: yourname tasks: - service: name=nginx state=started sudo: yes
你也可以登陆后,sudo 到不同的用户身份,而不是使用 root:
--- - hosts: webservers remote_user: yourname sudo: yes sudo_user: postgres
如果你需要在使用 sudo 时指定密码,可在运行 ansible-playbook 命令时加上选项 --ask-sudo-pass
(-K). 如果使用 sudo 时,playbook 疑似被挂起,可能是在 sudo prompt 处被卡住,这时可执行 Control-C杀死卡住的任务,再重新运行一次.
Important
当使用 sudo_user 切换到 非root 用户时,模块的参数会暂时写入 /tmp 目录下的一个随机临时文件. 当命令执行结束后,临时文件立即删除.这种情况发生在普通用户的切换时,比如从 ‘bob’ 切换到 ‘timmy’, 切换到 root 账户时,不会发生,如从 ‘bob’ 切换到 ‘root’,直接以普通用户或root身份登录也不会发生. 如果你不希望这些数据在短暂的时间内可以被读取(不可写),请避免在 sudo_user 中传递未加密的密码. 其他情况下,’/tmp’ 目录不被使用,这种情况不会发生.Ansible 也有意识的在日志中不记录密码参数.
2、Tasks 列表
每一个 play 包含了一个 task 列表(任务列表).一个 task 在其所对应的所有主机上(通过 host pattern 匹配的所有主机)执行完毕之后,下一个 task 才会执行.有一点需要明白的是(很重要),在一个 play 之中,所有 hosts 会获取相同的任务指令,这是 play 的一个目的所在,也就是将一组选出的 hosts 映射到 task.(注:此处翻译未必准确,暂时保留原文)
在运行 playbook 时(从上到下执行),如果一个 host 执行 task 失败,这个 host 将会从整个 playbook 的 rotation 中移除. 如果发生执行失败的情况,请修正 playbook 中的错误,然后重新执行即可.
每个 task 的目标在于执行一个 moudle, 通常是带有特定的参数来执行.在参数中可以使用变量(variables).
modules 具有”幂等”性,意思是如果你再一次地执行 moudle(译者注:比如遇到远端系统被意外改动,需要恢复原状),moudle 只会执行必要的改动,只会改变需要改变的地方.所以重复多次执行 playbook 也很安全.
对于 command module 和 shell module,重复执行 playbook,实际上是重复运行同样的命令.如果执行的命令类似于 ‘chmod’ 或者 ‘setsebool’ 这种命令,这没有任何问题.也可以使用一个叫做 ‘creates’ 的 flag 使得这两个 module 变得具有”幂等”特性 (不是必要的).
每一个 task 必须有一个名称 name,这样在运行 playbook 时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个 task 的. 如果没有定义 name,‘action’ 的值将会用作输出信息中标记特定的 task.
如果要声明一个 task,以前有一种格式: “action: module options” (可能在一些老的 playbooks 中还能见到).现在推荐使用更常见的格式:”module: options” ,本文档使用的就是这种格式.
下面是一种基本的 task 的定义,service moudle 使用 key=value 格式的参数,这也是大多数 module 使用的参数格式:
tasks: - name: make sure apache is running service: name=httpd state=running
比较特别的两个 modudle 是 command 和 shell ,它们不使用 key=value 格式的参数,而是这样:
tasks: - name: disable selinux command: /sbin/setenforce 0
使用 command module 和 shell module 时,我们需要关心返回码信息,如果有一条命令,它的成功执行的返回码不是0, 你或许希望这样做:
tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand || /bin/true
或者是这样:
tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand ignore_errors: True
如果 action 行看起来太长,你可以使用 space(空格) 或者 indent(缩进) 隔开连续的一行:
tasks: - name: Copy ansible inventory file to client copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts owner=root group=root mode=0644
在 action 行中可以使用变量.假设在 ‘vars’ 那里定义了一个变量 ‘vhost’ ,可以这样使用它:
tasks: - name: create a virtual host file for {{ vhost }} template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}
这些变量在 tempates 中也是可用的,稍后会讲到.
在一个基础的 playbook 中,所有的 task 都是在一个 play 中列出,稍后将介绍一种更合理的安排 task 的方式:使用 ‘include:’ 指令.
3、Action Shorthand
New in version 0.8.
在 0.8 及以后的版本中,ansible 更喜欢使用如下的格式列出 modules:
template: src=templates/foo.j2 dest=/etc/foo.conf
在早期的版本中,使用以下的格式:
action: template src=templates/foo.j2 dest=/etc/foo.conf
早期的格式在新版本中仍然可用,并且没有计划将这种旧的格式弃用.
4、Handlers: 在发生改变时执行的操作
上面我们曾提到过,module 具有”幂等”性,所以当远端系统被人改动时,可以重放 playbooks 达到恢复的目的. playbooks 本身可以识别这种改动,并且有一个基本的 event system(事件系统),可以响应这种改动.
(当发生改动时)’notify’ actions 会在 playbook 的每一个 task 结束时被触发,而且即使有多个不同的 task 通知改动的发生, ‘notify’ actions 只会被触发一次.
举例来说,比如多个 resources 指出因为一个配置文件被改动,所以 apache 需要重新启动,但是重新启动的操作只会被执行一次.
这里有一个例子,当一个文件的内容被改动时,重启两个 services:
- name: template configuration file template: src=template.j2 dest=/etc/foo.conf notify: - restart memcached - restart apache
‘notify’ 下列出的即是 handlers.
Handlers 也是一些 task 的列表,通过名字来引用,它们和一般的 task 并没有什么区别.Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行.不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次.
这里是一个 handlers 的示例:
handlers: - name: restart memcached service: name=memcached state=restarted - name: restart apache service: name=apache state=restarted
Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了.
Note
handlers 会按照声明的顺序执行
Roles 将在下一章节讲述.值得指出的是,handlers 会在 ‘pre_tasks’, ‘roles’, ‘tasks’, 和 ‘post_tasks’ 之间自动执行. 如果你想立即执行所有的 handler 命令,在1.2及以后的版本,你可以这样做:
tasks: - shell: some tasks go here - meta: flush_handlers - shell: some other tasks
在以上的例子中,任何在排队等候的 handlers 会在执行到 ‘meta’ 部分时,优先执行.这个技巧在有些时候也能派上用场.
5、执行一个 playbook
既然现在你已经学习了 playbook 的语法,那要如何运行一个 playbook 呢?这很简单,这里的示例是并行的运行 playbook,并行的级别 是10(译者注:是10个并发的进程?):
1 ansible-playbook playbook.yml -f 10
6、Ansible-Pull(拉取配置而非推送配置)
我们可不可以将 ansible 的体系架构颠倒过来,让托管节点从一个 central location 做 check in 获取配置信息,而不是 推送配置信息到所有的托管节点?是可以的.
Ansible-pull 是一个小脚本,它从 git 上 checkout 一个关于配置指令的 repo,然后以这个配置指令来运行 ansible-playbook.
假设你对你的 checkout location 做负载均衡,ansible-pull 基本上可以无限的提升规模.
可执行 ansible-pull --help
获取详细的帮助信息.
也有一个叫做 clever playbook 的东西: clever playbook . 这个可以通过 crontab 来配置 ansible-pull(from push mode).
7、提示与技巧
在 playbook 执行输出信息的底部,可以找到关于托管节点的信息.也可看到一般的失败信息,和严重的 “unreachable” 信息. 这两个是分开计数的.
如果你想看到执行成功的 modules 的输出信息,使用 --verbose
flag(否则只有执行失败的才会有输出信息).这在 0.5 及以后的版本中可用.
如果安装了 cowsay 软件包,ansible playbook 的输出已经进行了广泛的升级.可以尝试一下!
在执行一个 playbook 之前,想看看这个 playbook 的执行会影响到哪些 hosts,你可以这样做:
1 ansible-playbook playbook.yml --list-hosts