Ansible基础介绍,ansible基础


 

Ansible默认通过 SSH 协议管理机器,通过python脚本来实现的,所以管理机和托管机都需要安装python2.6以及更高的版本,除此之外被管理的机器不需要安装任何组件。

Ansible提供了多种安装方式,但是作为python的拥护者果断选择用命令pip install ansible来安装。当然此种安装方式虽然方便,但是在配置上有点微不足道的小麻烦,后面会介绍。

 

Ansible中最亮眼的是集配置,部署,自动化于一身的playbookplaybookansible的核心,本文我们先掌握ansible的基本使用方式,再去掌握playbook

 

Ansible会默认假定你使用 SSH Key(我们推荐这种)但是密码也一样可以.通过在需要的地方添加 –ask-pass选项 来启用密码验证.如果使用了sudo 特性,sudo需要密码时,也同样适当的提供了–ask-sudo-pass选项.

 

 

先简单验证下安装的Ansible,修改/etc/ansible/hosts文件,添加以下三行

192.168.1.50
aserver.example.org
bserver.example.org

执行命令:

$ ansible all -m ping

这就是一个简单的ansible的操作过程,目的就是为了用当前用户名通过ssh协议尝试连接到3台远程机器。

如果是pip安装的ansible,没有/etc/ansible该目录,执行会报错:

大可不必担心,自己mkdirvi一个/etc/ansible/hosts文件即可。包括涉及到ansible的配置文件等,pip安装的同学可以直接在ansible要求的目录里创建即可。

还支持切换为其他用户来ping


$ ansible all -m ping -u otherUser

Ansible是批量操作的,可同时操作属于同一个组的多台主机,组和主机的映射是通过inventory来配置的。我们把hosts文件修改的复杂一些从而来理解组和主机的概念:


mail.example.com

[webservers]
foo.example.com:5123
bar.example.com

[dbservers]
one.example.com
two.example.com
bar.example.com

[databases]
db-[a:f].example.com

[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

[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2

[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

[merge:children]
webservers
dbservers

 

[]中括号引起来的是组名,外面的是主机名或ip

从配置中可以看出以下信息:

1 存在无组织的主机,或者叫游离的主机(mail.example.com

2 一个主机可以同时属于多个组(bar.example.com

3 主机的SSH端口如果不是默认的22,可以通过冒号方式重新指定(foo.example.com

4 可通过[1:50]这种方式来定义一组命名相似的主机(databases

5 连接方式和操作用户可以直接在配置文件中指定(targets

6 可以通过键值对的方式给主机设置变量,被后面的playbooks编排所使用(host1

7 可以直接给组设置变量,对组内的主机批量生效(atlanta

8 组可以继承(merge

 

 

回头再来看inventory的配置,该配置可以被理解为ansible的主文件或者主程序,用它来定义组和主机信息比较合适,如果要把每个主机或组复杂的变量信息也维护进来可读性会很差,所以我们一般把变量配置单独已文件方式来维护,如下:

/etc/ansible/host_vars/mail.example.com
/etc/ansible/group_vars/webservers
/etc/ansible/group_vars/dbservers/db_settings
/etc/ansible/group_vars/dbservers/cluster_settings

1 host_vars配置单个主机,配置文件维护在同名的文件里(mail.example.com

2 group_vars配置组,配置文件维护在同名的文件里(webservers

3 配置文件定义成同名的目录,在目录里再对配置做一次拆分(dbservers

以上无论哪种方式都要保证配置文件在/etc/ansible目录下,也就是说要与inventory在一起。当然这是默认模式,可以通过-i强制指定hosts文件。

 

Ansible Ansible Tower提供了一个数据库来存储 inventory 配置信息, 这个数据库可以通过 web 访问,或通过 REST 访问. Tower 与所有你使用的 Ansible 动态 inventory 源保持同步,并提供了一个图形化的 inventory 编辑器. 有了这个数据库,便可以很容易的关联过去的事件历史,可以看到在上一次 playbook 运行时,哪里出现了运行失败的情况.当然这么好用的一个东西是收费的,所以这里只是点到为止,我的产品没有用到tower

 

 

Inventory中定义了全部的组和主机名列表,但是真正编排时需要精确到具体的组或者部分主机,这就需要用到Pattern这个概念。

如果要处理全部主机,Pattern为:

all

*

我们还可以通过逻辑运算来进行过滤,例如:

webservers:dbservers:&staging:!phoenix

上例的过滤规则是:属于webservers组或dbservers组,而且要属于staging组,并且不能属于phoenix组。

也可以使用通配符:

*.example.com

或者将组看成list集合,取其中一部分主机:

Webservers[0-10]

 

 

Ansible提供两种方式去完成任务,一是 ad-hoc 命令,一是写 Ansible playbook.前者可以解决一些简单的任务, 后者解决较复杂的任务.我们的学习重点时playbookad-hoc我们通过几条简单的命令只做了解即可。

命令1

$ ansible atlanta -a "/sbin/reboot" -f 10

重启atlanta组内的所有主机,每次fork10个进程去执行。

 

命令2

$ ansible raleigh -m shell -a 'echo $TERM'

raleigh组的主机上执行shell,获取TERM变量

 

命令3

$ ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan"

修改webservers组主机上文件的权限和usergroup

 

命令4

$ ansible webservers -m git -a "repo=git://foo.example.org/repo.git dest=/srv/myapp version=HEAD"

使用gitwebservers组的主机上部署项目

 

综上可以发现ad-hoc的核心是要掌握有哪些-m,这些模块怎么使用,当然掌握模块同样是playbook的重点,模块众多参数也众多,需要对linux原理有很深的理解。

 

 

主角登场了!PlaybooksYAML文本格式的编排,可以完成比ad-hoc更复杂的业务编排,是我们学习和掌握Ansible的重中之重。

playbook 由一个或多个 ‘plays’ 组成.它的内容是一个以 ‘plays’ 为元素的列表.

借助以下这个例子先简单了解下playbooks是如何编排的:

---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: pkg=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
    service: name=httpd state=started
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

1 开头的---是固定格式,代表是个playbook文件;

2 2-6行较简单,代表操作哪些主机、变量赋值如何、远程操作用户;

3 tasks内代表一个play-name定义了任务名称,编辑时要注意文本的可读性;notify可以理解为软件开发中的回调函数,里面回调的是handlers中的name,回调函数只有特定条件下才会被执行,后面会解释。

4 task的执行是串行block的,需要执行完一条命令才能开启下一条。

5 如果执行过程中某个host失败,会将该host从本次任务流中剔除,不会影响其他host的编排。

6 编排过程中,每个task目标在于执行一个module,而且是带有幂等性的,moudle 只会执行必要的改动,只会改变需要改变的地方.所以重复多次执行 playbook 也很安全.

7 正因为playbook的幂等性,所以只有当发生改动时notify才会被调用,并不是每次执行都会生效的。

8 handlers的本质也是一个task,只不过默认不执行,只有被nofity回调了才会生效,最佳的应用场景是重启服务等。

9 playbook编排的产出是个YMAL文件,编排的执行通过命令$ansible-playbook playbook.yml -f 10

 

 

当云服务拓扑到达一定规模,同样面对着playbook重用的问题,我们不希望每一次编排都重新写一个又臭又长的YAML文件,于是playbook提出了include的概念。做过页面开发或者js脚本开发的人员很容易理解这种设计,将独立的可重用部分写入yml文件中,然后在上层进行include封装和编排,例如:

tasks:

  - include: wordpress.yml
    vars:
        wp_user: timmy
        some_list_variable:
          - alpha
          - beta
          - gamma

这个play就是引用了wordpress.yml这个task并对其变量进行了赋值。

 

同理,因为前面介绍过handler本质也是待执行的task,所以对handler也可以include

handlers:
  - include: handlers/handlers.yml

Ansible1.2版本开始又提出了Roles概念,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include它们。

Roles的目录结构如下:

site.yml
webservers.yml
fooservers.yml
roles/
   common/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
   webservers/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/

1 前三行是基于roles内的文件在上层编排的文件,供命令调用;

2 roles里定义了2role,一个叫common,一个叫webservers

3 files:用来存放由copy模块或script模块调用的文件。

4 templates:用来存放jinjia2模板,template模块会自动在此目录中寻找jinjia2模板文件。

5 tasks:此目录应当包含一个main.yml文件,用于定义此角色的任务列表,此文件可以使用include包含其它的位于此目录的task文件。

6 handlers:此目录应当包含一个main.yml文件,用于定义此角色中触发条件时执行的动作。

7 vars:此目录应当包含一个main.yml文件,用于定义此角色用到的变量。

8 defaults:此目录应当包含一个main.yml文件,用于为当前角色设定默认变量。

9 meta:此目录应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系。

对于前三行这样的主业务编排,可以如下定义;

---
- hosts: some_group
  roles:
- common
- { role: webservers, when: "ansible_os_family == 'RedHat'" }

对于某组的主机先执行common这个role,然后属于RedHat操作系统的再执行webservers这个role

 

一个完整的业务编排示例如下(建议,非强制):

---

- hosts: webservers

  pre_tasks:
    - shell: echo 'hello'

  roles:
    - { role: some_role }

  tasks:
    - shell: echo 'still busy'

  post_tasks:
- shell: echo 'goodbye'

一般分为自定义预处理taskroles执行、自定义task执行、自定义后处理task四个步骤。

 

 

Playbook中的循环:

1 集合循环:

- name: add several users
  user: name={{ item.name }} state=present groups={{ item.groups }}
  with_items:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }

 

2 Map循环:

变量赋值:

---
users:
  alice:
    name: Alice Appleworth
    telephone: 123-456-7890
  bob:
    name: Bob Bananarama
telephone: 987-654-3210
Map引用:
tasks:
  - name: Print phone records
    debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
    with_dict: "{{users}}"
Do-Until:
- action: shell /usr/bin/foo
  register: result
  until: result.stdout.find("all systems go") != -1
  retries: 5
  delay: 10

 

有了这些基础之后,后续的学习就是深化linux命令与对其原理的理解,不断地掌握更多的ansible模块何其使用方式,ansible-playbook到了后期就是一种用yml和目录结构为载体的变成艺术了,包括对common功能的抽象、对自定义功能的灵活处理等等,也很有意思,喜欢代码设计的同学会发现其别有洞天。我个人称它为基于yml的编程语言~~~


相关内容

    暂无相关文章