自动化运维-3.ansible详解(二)
1. ansible-galaxy
1.1 ansible-galaxy基本使用
1.连接https://galaxy.ansible.com下载相应的roles
2.安装galaxy
ansible-galaxy install geerlingguy.redis
3.列出所有已安装的galaxy
ansible-galaxy list
4.删除galaxy
ansible-galaxy remove geerlingguy.redis
注:要安装其他role,就将geerlingguy.redis改成对应名称

1.2 构建角色架构
用于初始化一个新角色的基本文件结构,节省创建不同的目录和main.yml的时间
ansible-galaxy init rolename
1.3 从一个文件安装多个角色
想安装多个角色,ansible-galaxy 命令行可以通过一个 requirements 文件实现。各种版本的ansible 都允许使用下面的语法从 Ansible galaxy 网站安装角色。
ansible-galaxy install -r requirements.txt
requirements.txt 文件看起来就像这样
username1.foo_role username2.bar_role
想得到指定版本(tag)的role,使用下面的语法
username1.foo_role,version username2.bar_role,version
可用的版本在 Ansible Galaxy 网页上都有列出来。
1.4 Requirements 文件高级用法
一些控制从哪里下载角色,支持远程源的用法,在 Ansible 1.8 之后支持通过 YMAL 语法的 requirements 文件实现,但是必须以 yml为文件扩展名。就像这样
ansible-galaxy install -r requirements.yml
扩展名是很重要的,如果 .yml 扩展忘记写了, ansible-galaxy 命令行会假设这个文件是普通格式的,而且会失败,
这里有个例子展示通过多个源下载一些指定版本。 其中也实现了覆盖下载角色的名字到其它名字。
# from galaxy - src: yatesr.timezone
# from github - src: https://github.com/bennojoy/nginx
# from github installing to a relative path - src: https://github.com/bennojoy/nginx
path: vagrant/roles/# from github, overriding the name and specifying a specific tag - src: https://github.com/bennojoy/nginx
version: master name: nginx_role# from a webserver, where the role is packaged in a tar.gz - src: https://some.webserver.example.com/files/master.tar.gz
name: http-role# from bitbucket, if bitbucket happens to be operational right now :) - src: git+http://bitbucket.org/willthames/git-ansible-galaxy
version: v1.4# from bitbucket, alternative syntax and caveats - src: http://bitbucket.org/willthames/hg-ansible-galaxy
scm: hg
从上面你可以看到,有许多控制命令可以使用去自定义那些角色从哪里获得,保存为什么角色名称。
2. ansible-pull
Ansible远程执行命令的工具,拉取配置而非推送配置
ansible-pull --help 获取详细的帮助信息
注:ansible-pull通常在配置大批量机器的场景下会使用,灵活性稍有欠缺,但效率几乎可以无限提升,对运维人员的技术水平和前瞻性规划有较高要求
3. ansible-vault
Ansible加密解密yaml文件
用法:ansible-vault [create|decrypt|edit|encrypt|rekey|view]
- ansible-vault create test.yaml 创建新文件
- ansible-vault decrypt test.yaml 解密
- ansible-vault edit test.yaml 编辑
- ansible-vault encrypt test.yaml 加密
- ansible-vault rekey test.yaml 修改口令
- ansible-vault view test.yaml 查看
4. ansible-playbook(重点)
4.1 Playbooks 简介
Playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合。
如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.
Playbooks 与 adhoc 相比,是一种完全不同的运用 ansible 的方式,是非常之强大的.
简单来说,playbooks 是一种简单的配置管理系统与多机器部署系统的基础.与现有的其他系统有不同之处,且非常适合于复杂应用的部署.
Playbooks 可用于声明配置,更强大的地方在于,在 playbooks 中可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤.并且可以同步或异步的发起任务.
我们使用 adhoc 时,主要是使用 /usr/bin/ansible 程序执行任务.而使用 playbooks 时,更多是将之放入源码控制之中,用之推送你的配置或是用于确认你的远程系统的配置是否符合配置规范.
4.2 YAML 语法
playbook由YMAL( /ˈjæməl/ )语言编写
playbook常用到的YMAL格式:
1.文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。
2.列表中的所有成员都开始于相同的缩进级别(不能空格和tab混用), 并且使用一个 "- " 作为开头(一个横杠和一个空格):
3.一个字典是由一个简单的 键: 值 的形式组成(这个冒号后面必须是一个空格):
4.Ansible 使用 “{{ var }}” 来引用变量. 如果一个值以 “{” 开头, YAML 将认为它是一个字典, 所以我们必须引用它, 像这样:
foo: "{{ variable }}"
5.需要使用引号来包裹任何包含冒号的哈希值, 像这样:
foo: "somebody said I should put a colon here: so I did"
4.3 主机与用户
hosts 行的内容是一个或多个组或主机的 patterns,以逗号为分隔符
remote_user 就是账户名:
---
- hosts: group1
remote_user: root
4.4 Tasks 列表
每一个 play 包含了一个 task 列表(任务列表).一个 task 在其所对应的所有主机上(通过 host pattern 匹配的所有主机)执行完毕之后,下一个 task 才会执行.有一点需要明白的是(很重要),在一个 play 之中,所有 hosts 会获取相同的任务指令,这是 play 的一个目的所在,也就是将一组选出的 hosts 映射到 task
在运行 playbook 时(从上到下执行),如果一个 host 执行 task 失败,这个 host 将会从整个 playbook 的 rotation 中移除. 如果发生执行失败的情况,请修正 playbook 中的错误,然后重新执行即可.
每个 task 的目标在于执行一个 moudle, 通常是带有特定的参数来执行.在参数中可以使用变量
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 }}
4.5 Handlers: 在发生改变时执行的操作
上面我们曾提到过,module 具有”幂等”性,所以当远端系统被人改动时,可以重放 playbooks 达到恢复的目的. playbooks 本身可以识别这种改动,并且有一个基本的 event system(事件系统),可以响应这种改动.
(当发生改动时)’notify’ actions 会在 playbook 的每一个 task 结束时被触发,而且即使有多个不同的 task 通知改动的发生, ‘notify’ actions 只会被触发一次.
举例来说,比如多个 resources 指出因为一个配置文件被改动,所以 apache 需要重新启动,但是重新启动的操作只会被执行一次.
这里有一个例子,当一个文件的内容被改动时,重启两个 services:
这里有一个例子,当一个文件的内容被改动时,重启两个 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 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了.
注: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’ 部分时,优先执行.这个技巧在有些时候也能派上用场.
4.6 include 语句
一个 task include file 由一个普通的 task 列表所组成,像这样:
---
# possibly saved as tasks/foo.yml
- name: placeholder foo
command: /bin/foo
- name: placeholder bar
command: /bin/bar
Include 指令看起来像下面这样,在一个 playbook 中,Include 指令可以跟普通的 task 混合在一起使用:
tasks:
- include: tasks/foo.yml
你也可以给 include 传递变量。我们称之为 ‘参数化的 include’。
举个例子,如果我们要部署多个 wordpress 实例,我们可将所有的 wordpress task 写在一个 wordpress.yml 文件中, 然后像下面这样使用 wordpress.yml 文件:
tasks:
- include: wordpress.yml wp_user=timmy
- include: wordpress.yml wp_user=alice
- include: wordpress.yml wp_user=bob
如果你运行的是 Ansible 1.4 及以后的版本,include 语法可更为精简,这种写法同样允许传递列表和字典参数:
tasks:
- { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }
使用上述任意一种语法格式传递变量给 include files 之后,这些变量就可以在 include 包含的文件中使用了。变量可以这样去引用:
{{ wp_user }}
(除了显式传递的参数,所有在 vars section 中定义的变量也可在这里使用)
从 1.0 版开始,Ansible 支持另一种传递变量到 include files 的语法,这种语法支持结构化的变量:
tasks:
- include: wordpress.yml
vars:
wp_user: timmy
some_list_variable:
- alpha
- beta
- gamma
Include 语句也可以用在 ‘handlers’ section 中,比如,你希望定义一个重启 apache 的 handler, 你只需要定义一次,然后便可在所有的 playbook 中使用这个 handler。你可以创建一个 handlers.yml 文件如下:
---
# this might be in a file like handlers/handlers.yml
- name: restart apache
service: name=apache state=restarted
然后在你的主 playbook 文件中,在一个 play 的最后使用 include 包含 handlers.yml:
handlers:
- include: handlers/handlers.yml
Include 语句可以和其他非 include 的 tasks 和 handlers 混合使用。
Include 语句也可用来将一个 playbook 文件导入另一个 playbook 文件。这种方式允许你定义一个 顶层的 playbook,这个顶层 playbook 由其他 playbook 所组成。
举个例子:
- name: this is a play at the top level of a file
hosts: all
remote_user: root
tasks:
- name: say hi
tags: foo
shell: echo "hi..."
- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml
注意:当你在 playbook 中引用其他 playbook 时,不能使用变量替换。
4.7 变量的使用
4.7 执行一个 playbook
建议:编写好yaml文件,正式执行前先check一下,没有问题再执行
ansible-playbook -C playbook.yml
在 playbook 执行输出信息的底部,可以找到关于托管节点的信息.也可看到一般的失败信息,和严重的 “unreachable” 信息. 这两个是分开计数的.
如果你想看到执行成功的 modules 的输出信息,使用 --verbose flag(否则只有执行失败的才会有输出信息).这在 0.5 及以后的版本中可用.
如果安装了 cowsay 软件包,ansible playbook 的输出已经进行了广泛的升级.可以尝试一下!
在执行一个 playbook 之前,想看看这个 playbook 的执行会影响到哪些 hosts,你可以这样做:
ansible-playbook playbook.yml --list-hosts
5.roles(重点)
5.1 role使用
怎样组织 playbook 才是最好的方式呢?简单的回答就是:使用 roles ! Roles 基于一个已知的文件结构,去自动的加载某些 vars_files,tasks 以及 handlers。基于 roles 对内容进行分组,使得我们可以容易地与其他用户分享 roles 。
一个项目的结构如下:
site.yml
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
一个 playbook 如下:
---
- hosts: webservers
roles:
- common
- webservers
这个 playbook 为一个角色 ‘x’ 指定了如下的行为:
- 如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中
- 如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
- 如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
- 如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中 (1.3 and later)
- 所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径。
- 所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径。
- 所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径。
- 所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径。
在 Ansible 1.4 及之后版本,你可以为”角色”的搜索设定 roles_path 配置项。使用这个配置项将所有的 common 角色 check out到一个位置,以便在多个 playbook 项目中可方便的共享使用它们。
如果 roles 目录下有文件不存在,这些文件将被忽略。比如 roles 目录下面缺少了 ‘vars/’ 目录,这也没关系。
注意:你仍然可以在 playbook 中松散地列出 tasks,vars_files 以及 handlers,这种方式仍然可用,但 roles 是一种很好的具有组织性的功能特性,我们强烈建议使用它。如果你在 playbook 中同时使用 roles 和 tasks,vars_files 或者 handlers,roles 将优先执行。
而且,如果你愿意,也可以使用参数化的 roles,这种方式通过添加变量来实现,比如:
---
- hosts: webservers
roles:
- common
- { role: foo_app_instance, dir: '/opt/a', port: 5000 }
- { role: foo_app_instance, dir: '/opt/b', port: 5001 }
当一些事情不需要频繁去做时,你也可以为 roles 设置触发条件,像这样:
---
- hosts: webservers
roles:
- { role: some_role, when: "ansible_os_family == 'RedHat'" }
它的工作方式是:将条件子句应用到 role 中的每一个 task 上。关于”条件子句”的讨论参见本文档后面的章节。
最后,你可能希望给 roles 分配指定的 tags。比如:
---
- hosts: webservers
roles:
- { role: foo, tags: ["bar", "baz"] }
如果 play 仍然包含有 ‘tasks’ section,这些 tasks 将在所有 roles 应用完成之后才被执行。
如果你希望定义一些 tasks,让它们在 roles 之前以及之后执行,你可以这样做:
---
- hosts: webservers
pre_tasks:
- shell: echo 'hello'
roles:
- { role: some_role }
tasks:
- shell: echo 'still busy'
post_tasks:
- shell: echo 'goodbye'
5.2角色默认变量(Role Default Variables)
角色默认变量允许你为 included roles 或者 dependent roles(见下) 设置默认变量。要创建默认变量,只需在 roles 目录下添加 defaults/main.yml 文件。这些变量在所有可用变量中拥有最低优先级,可能被其他地方定义的变量(包括 inventory 中的变量)所覆盖。
5.3 角色依赖(Role Dependencies)
“角色依赖” 使你可以自动地将其他 roles 拉取到现在使用的 role 中。”角色依赖” 保存在 roles 目录下的 meta/main.yml 文件中。这个文件应包含一列 roles 和 为之指定的参数,下面是在 roles/myapp/meta/main.yml 文件中的示例:
---
dependencies:
- { role: common, some_parameter: 3 }
- { role: apache, port: 80 }
- { role: postgres, dbname: blarg, other_parameter: 12 }
“角色依赖” 可以通过绝对路径指定,如同顶级角色的设置:
---
dependencies:
- { role: '/path/to/common/roles/foo', x: 1 }
“角色依赖” 也可以通过源码控制仓库或者 tar 文件指定,使用逗号分隔:路径、一个可选的版本(tag, commit, branch 等等)、一个可选友好角色名(尝试从源码仓库名或者归档文件名中派生出角色名):
---
dependencies:
- { role: 'git+http://git.example.com/repos/role-foo,v1.1,foo' }
- { role: '/path/to/tar/file.tgz,,friendly-name' }
“角色依赖” 总是在 role (包含”角色依赖”的role)之前执行,并且是递归地执行。默认情况下,作为 “角色依赖” 被添加的 role 只能被添加一次,如果另一个 role 将一个相同的角色列为 “角色依赖” 的对象,它不会被重复执行。但这种默认的行为可被修改,通过添加 allow_duplicates: yes 到 meta/main.yml 文件中。 比如,一个 role 名为 ‘car’,它可以添加名为 ‘wheel’ 的 role 到它的 “角色依赖” 中:
---
dependencies:
- { role: wheel, n: 1 }
- { role: wheel, n: 2 }
- { role: wheel, n: 3 }
- { role: wheel, n: 4 }
wheel 角色的 meta/main.yml 文件包含如下内容:
---
allow_duplicates: yes
dependencies:
- { role: tire }
- { role: brake }
最终的执行顺序是这样的:
tire(n=1)
brake(n=1)
wheel(n=1)
tire(n=2)
brake(n=2)
wheel(n=2)
...
car
浙公网安备 33010602011771号