ansible 核心组件介绍

Architecture Diagram

  • ansible core

  • host iventory

  • core modules

  • custom modules

  • playbook (yaml)

  • connetc plugin ansible 系列教程_第1张图片

ansibles 的特性

  • 基于python语言实现,有paramiko,Pyyaml和jinjia2 三个关键模块

  • 部署简单,agegtlees,默认使用SSH协议

  1. 基于密钥认证

  2. 在inventory 文件中指定账号和密码

支持playbook基于”模块“完成各种任务

ansible install

# install the epel-release RPM if needed on CentOS, RHEL, or Scientific Linux
$ sudo yum install ansible

ansible config

配置文件:/etc/ansible/ansible.cfg

inventory:/etc/ansible/hosts

定制被管理主机:

cat /etc/ansible/host
[webserver]
192.168.0.101
192.168.0.102

管理master 创建ssh密钥

root@node2 ansible]# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
[root@node2 ansible]# ls /root/.ssh/
/root/.ssh/id_rsa  /root/.ssh/id_rsa.pub

将公钥复制给slave节点,并验证ssh证书登录是否成功。

[root@node2 ansible]#ssh-copy-id -i /root/.ssh/id_rsa.pub [email protected]
[root@node2 ansible]# ssh-copy-id -i /root/.ssh/id_rsa.pub [email protected]
[root@node2 ansible]# ssh [email protected] 'date'
Wed Feb  3 19:53:04 CST 2016
[root@node2 ansible]# ssh [email protected] 'date'
Wed Feb  3 19:53:58 CST 2016

ansible-doc - show documentation on Ansible modules

[root@node2 ansible]# ansible-doc -l
cron  Manage cron.d and crontab entries.
crypttab  Encrypted Linux block devices 
datadog_event Posts events to DataDog  service  
debconf   Configure a .deb package  
debug Print statements during execution 
digital_ocean Create/delete a droplet/SSH_key in DigitalOcean   
digital_ocean_domain  Create/delete a DNS record in DigitalOcean

查看模块说明

[root@node2 ansible]# ansible-doc -s cron

ansible命令应用基础

语法: ansible [-f forks] [-m module_name] [-a args]

  • -f forks:启动的并发数

  • -m module_name:使用的模块

  • -args:模块特有参数

EX:使用command模块执行date指令,ansible 默认模块,不支持变量传递。

[root@node2 ansible]# ansible webserver -m command -a "date"
192.168.0.101 | success | rc=0 >>
Wed Feb  3 20:06:50 CST 2016

192.168.0.102 | success | rc=0 >>
Wed Feb  3 20:06:03 CST 2016
[root@node2 ansible]# ansible webserver -a "date"
192.168.0.102 | success | rc=0 >>
Wed Feb  3 20:10:35 CST 2016
192.168.0.101 | success | rc=0 >>
Wed Feb  3 20:11:22 CST 2016

EX:cron模块:每十分钟运行“hello”

  • state

present 添加任务 absent 删除任务

[root@node2 ansible]# ansible webserver -m cron -a 'minute="*/10" job="/bin/echo hello word" name="ansibile cron lession"'

验证结果

[root@node2 ansible]# ansible webserver -a "crontab -l"
192.168.0.101 | success | rc=0 >>
#Ansible: ansibile cron lession
*/10 * * * * /bin/echo hello word    
192.168.0.102 | success | rc=0 >>
#Ansible: ansibile cron lession
*/10 * * * * /bin/echo hello word

删除一个cron任务:

[root@node2 ansible]# ansible webserver -m cron -a 'minute="*/10" job="/bin/echo hello word" name="ansibile cron lession" state=absent'

创建一个mysql 系统用户

home: Check that parent folder is missing and run

[root@node2 ansible]# ansible webserver -m user -a "name=mysql system=yes shell='/sbin/nologin' home='/date/mysql'"
192.168.0.102 | success >> {
"append": false, 
"changed": true, 
"comment": "", 
"group": 497, 
"home": "/date/mysql", 
"move_home": false, 
"name": "mysql", 
"shell": "/sbin/nologin", 
"state": "present", 
"uid": 497
}

192.168.0.101 | success >> {
"append": false, 
"changed": true, 
"comment": "", 
"group": 498, 
"home": "/date/mysql", 
"move_home": false, 
"name": "mysql", 
"shell": "/sbin/nologin", 
"state": "present", 
"uid": 498
}

删除一个mysql用户

[root@node2 ansible]# ansible webserver -m user -a "user=mysql remove='yes' state=absent"
192.168.0.102 | success >> {
"changed": true, 
"force": false, 
"name": "mysql", 
"remove": true, 
"state": "absent"
}

192.168.0.101 | success >> {
"changed": true, 
"force": false, 
"name": "mysql", 
"remove": true, 
"state": "absent"
}

EX:copy 模块:复制文件/etc/fstab 到/tmp/fstab.ansbile,文件所有者为root,所属组为roo并且文件权限为600

[root@node2 ansible]# ansible webserver -m copy -a "src=/etc/fstab dest=/tmp/fstab.ansible owner=root group=root mode=600"
192.168.0.101 | success >> {
"changed": true, 
"checksum": "f24c68dfd84aa1d30c325285d7aedc26a50e7078", 
"dest": "/tmp/fstab.ansible", 
"gid": 0, 
"group": "root", 
"md5sum": "05e29801d839073ed23aa6164e58646f", 
"mode": "0600", 
"owner": "root", 
"secontext": "unconfined_u:object_r:admin_home_t:s0", 
"size": 779, 
"src": "/root/.ansible/tmp/ansible-tmp-1454504173.49-88392224178700/source", 
"state": "file", 
"uid": 0
}

192.168.0.102 | success >> {
"changed": true, 
"checksum": "f24c68dfd84aa1d30c325285d7aedc26a50e7078", 
"dest": "/tmp/fstab.ansible", 
"gid": 0, 
"group": "root", 
"md5sum": "05e29801d839073ed23aa6164e58646f", 
"mode": "0600", 
"owner": "root", 
"secontext": "unconfined_u:object_r:admin_home_t:s0", 
"size": 779, 
"src": "/root/.ansible/tmp/ansible-tmp-1454504173.49-145879281527954/source", 
"state": "file", 
"uid": 0
}

EX:生成文件/tmp/test,内容为"hello word"

[root@node2 ansible]# ansible webserver -m copy -a "content='hello word' dest=/tmp/test "
[root@node2 ansible]# ansible all -m shell -a 'cat /tmp/test'
192.168.0.102 | success | rc=0 >>
hello word

192.168.0.101 | success | rc=0 >>
hello word

EX:文件权限管理

[root@node2 ansible]# ansible all -m file -a 'owner=mysql group=mysql mode=600 path=/tmp/fstab.ansible'

EX:创建软连接文件

[root@node2 ansible]# ansible all -m file -a 'path=/tmp/fstab.link src=/tmp/fstab.ansible state=link'
[root@node2 ~]# ll /tmp/*
lrwxrwxrwx. 1 root  root18 Feb  3 21:21 /tmp/fstab.link -> /tmp/fstab.ansible

EX:service 服务管理模块

enabled: Whether the service should start on boot

[root@node2 ~]# ansible webserver -m service -a 'enabled=true name=nginx state=started'

EX: SHELL 指令模块,可以使用变量及参数传递

[root@node2 ~]# ansible all -m shell -a 'echo redhat| passwd --stdin mysql'
192.168.0.102 | success | rc=0 >>
Changing password for user mysql.
passwd: all authentication tokens updated successfully.

192.168.0.101 | success | rc=0 >>
Changing password for user mysql.
passwd: all authentication tokens updated successfully.

EX:script 在远端执行本地脚本

[root@node2 ~]# ansible all -m script -a '/tmp/test.sh'

EX:YUM 安装软件

[root@node2 ~]# ansible all -m yum -a 'name=nginx'

EX: setup 收集远程主机facts,每个被管理几点在接受并运行管理命令之前,会将自己主机相关信息,如系统版本、IP报告给远程的ansible主机。

[root@node2 ~]# ansible all -m setup

ansible的YAML介绍

YAML是"YAML Ain't a Markup Language"(YAML不是一种置标语言)的递归缩写。 YAML是一个类似GNU的递归式定义。GNU对Unix说“No”,YMAL则是对XML说“No”。而在Ruby的世界里,YAML可以说是Ruby流动的血液。YAML 之于Ruby,犹如XML之于Java。

  • YAML的可读性好。

  • YAML和脚本语言的交互性好。

  • YAML使用宿主语言的数据类型。

  • YAML有一个一致的信息模型。

YAML实例

# MySQL (default setup).  Versions 4.1 and 5.0 are recommended.
# 此处省略一些注释。
development:
  adapter: mysql
  database: demo_development
  username: root
  password:
  host: localhos

ansible的基础元素、变量、组嵌套

变量

  • 变量命名:变量名仅能由字母、数字和下划线组成、且只能以字母开头

  • facts 信息被保存在ansible变量中,可以引用使用

  • register:把任务的输出定义为变量,

实例如下

task:
shell:/usr/bin/foo
register:foo_result
ignore_error:True

ansible playbook 介绍

playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合. 如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划. 在基础层面, playbooks 可以被用来管理用于部署到远程主机的配置文件.在更高的层面上,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

ansible playbook 基础组件

  • Inventor

  • Modules

  • Ad hot commands

  • Playbooks

  • Tasks:任务,及调佣模块完成基础操作

  • variables:变量

  • tempalates:模板

  • handlers:处理器。由某事件触发执行的操作

  • roles:角色

主机与用户

playbook 中的每一个 play,个别地选择操作的目标机器是哪些,以哪个用户身份去完成要执行的步骤。hosts 行的内容是一个或多个组或主机的 patterns,以逗号为分隔符,

实例:

- hosts: webservers
  remote_user: root

Tasks 任务列表

每一个 play 包含了一个 task 列表(任务列表).一个 task 在其所对应的所有主机上(通过 host pattern 匹配的所有主机)执行完毕之后,下一个 task 才会执行.有一点需要明白的是(很重要),在一个 play 之中,所有 hosts 会获取相同的任务指令,这是 play 的一个目的所在,也就是将一组选出的 hosts 映射到 task

每个 task 的目标在于执行一个 moudle, 通常是带有特定的参数来执行.在参数中可以使用变量(variables).

每个task都应该有name,用于playboo的执行结果输出,建议其内容尽可能详细描述任务步骤。如果未提供name,测action 的结果将用于输出

modules 具有”幂等”性,意思是如果你再一次地执行 moudle(译者注:比如遇到远端系统被意外改动,需要恢复原状),moudle 只会执行必要的改动,只会改变需要改变的地方.所以重复多次执行 playbook 也很安全.

对于 command module 和 shell module,重复执行 playbook,实际上是重复运行同样的命令.如果执行的命令类似于 ‘chmod’ 或者 ‘setsebool’ 这种命令,这没有任何问题.也可以使用一个叫做 ‘creates’ 的 flag 使得这两个 module 变得具有”幂等”特性

下面是一种基本的 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

EX:

- hosts: webserver
  remote_user: root
  tasks:
  - name: create nginx group
    group: name=nginx system=yes gid=208
  - name: create nginx user
    user: name=nginx uid=208 group=nginx system=yes
- hosts: dbserver
  remote_user: root
  tasks:
  - name: copy file to dbserver
    copy: src=/etc/inittab dest=/tmp/initab.ans

handlers

用于当关注的资源发生变化时采取一定的操作。'notify'这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之仅在所有的变化发生完成后一次性地执行操作。在‘notify’中列出的操作称之为handler。

EX: 步骤1,写一个playbook 要求如下

  • 自动部署一个httpd服务

  • 提供一个特殊的配置文件端口监听8080

  • 开机自动启动

- hosts: webserver
  remote_user: root
  tasks:
  - name: install httpd package
    yum: name=httpd state=latest
  - name: install congfiguration file for httpd
    copy: src=/root/playboos/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
  - name: start httpd service
    service: enabled=true name=httpd state=started

步骤2 修改配置文件端口监听为80。重新执行playbook查看端口是否被修改!

- hosts: webserver
  remote_user: root
  tasks:
  - name: install httpd package
    yum: name=httpd state=latest
  - name: install congfiguration file for httpd
    copy: src=/root/playboos/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify:
    - restart httpd
  - name: start httpd service
    service: enabled=true name=httpd state=started 
  handlers:
  - name: restart httpd
    service: name=httpd state=restarted

playbooks 变量的使用

  • 自定变量引用

  • 调用ansible系统变量

  • 调用Inventor 定义的变量

EX1:自定变量引用

- hosts: webserver
  remote_user: root
  vars: 
  - package: httpd
  - service: httpd
  tasks:
  - name: install httpd package
    yum: name={{ package }} state=latest
  - name: install congfiguration file for httpd
    copy: src=/root/playboos/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify:
    - restart httpd
  - name: start httpd service
    service: enabled=true name={{ service }} state=started 
  handlers:
  - name: restart httpd
    service: name=httpd state=restarted

EX2:调用ansible系统变量

系统变量查看

[root@node2 conf]# ansible all -m setup

调用ansible系统变量ansibleallipv4_addresses'

- hosts: webserver
  remote_user: root
  tasks:
  - name: copy file
copy: content="{{ ansible_all_ipv4_addresses }}" dest=/tmp/ip.ans

EX3:调用Inventor 定义的变量

# Ex 1: Ungrouped hosts, specify before any group headers.
[webserver] 
192.168.0.101 testvar='0.101' ansible_ssh_user=root ansible_ssh_pass=redhat
192.168.0.102 testvar='0.102'
[dbserver]
192.168.0.102

[root@node2 playboos]# cat vars.yml
- hosts: webserver
  remote_user: root
  tasks:
  - name: copy file
    copy: content="{{ ansible_all_ipv4_addresses }}, {{ testvar }}" dest=/tmp/ip.ans

ansible之条件测试

when语句:在task后添加when子句即可使用条件测试。

EX:

tasks:
  - name: "shutdown Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_os_family == "Debian"

EX:2

[root@node2 playboos]# cat cond.yml 
- hosts: all
  remote_user: root
  vars:
  - username: major 
  tasks: 
  - name: create {{ username }} user
    user: name={{ username }}
    when: ansible_fqdn == "node3.huizhuang.com"

迭代语句 当有需要重复性执行的任务时,可以使用迭代机制。 其使用格式为将需要迭代的内容定义为item变量引用,并通过with_items 语句来指明迭代的元素列表即可。

EX:为了保持简洁,重复的任务可以用以下简写的方式。

` item ` 为固定变量名

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

以上写法与下面是完全等同的

- name: add user testuser1
  user: name=testuser1 state=present groups=wheel
- name: add user testuser2
  user: name=testuser2 state=present groups=wheel

请note使用 ‘with_items’ 用于迭代的条目类型不仅仅支持简单的字符串列表.如果你有一个哈希列表,那么你可以用以下方式来引用子项:

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

ansible之tempalates 使用

要求为webserver两台主机安装httpd 服务要求如下 - 监听端口80 - 0.101主机maxclient 值为100 - 0.102主机maxclient 值为200 - ServerName 为各自主机名 定义 httpd template 模板文件httpd.conf.j2

MaxClients   {{ maxclient }}
Listen {{ http_port }}
ServerName {{ ansible_fqdn}}:80

在Inventor hosts文件定义变量值

[root@node2 templates]# cat /etc/ansible/hosts    
[webserver] 
192.168.0.101 http_port=80 maxclient=100
192.168.0.102 http_port=80 maxclient=200

在http.yml 引用模板变量

- hosts: webserver
  remote_user: root
  vars:
  - package: httpd
  - service: httpd
  tasks:
  - name: install httpd package
    yum: name={{ package }} state=latest
  - name: install congfiguration file for httpd
    template: src=/root/playboos/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
    notify:
    - restart httpd
  - name: start httpd service
    service: enabled=true name={{ service }} state=started 
  handlers:
  - name: restart httpd
    service: name=httpd state=restarted

ansible标签 tags

如果你有一个大型的 playbook,那能够只运行其中特定部分的配置而无需运行整个 playbook 将会很有用.

[root@node2 playboos]# cat httpd.yml 
- hosts: webserver
  remote_user: root
  vars:
  - package: httpd
  - service: httpd
  tasks:
  - name: install httpd package
    yum: name={{ package }} state=latest
  - name: install congfiguration file for httpd
    template: src=/root/playboos/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
    tags:
    - conf
    notify:
    - restart httpd
  - name: start httpd service
    service: enabled=true name={{ service }} state=started 
  handlers:
  - name: restart httpd
    service: name=httpd state=restarted

如果你只想运行一个非常大的 playbook 中的 “conf” 你可以这样做:

# ansible-playbook httpd.yml --tags='conf'

另一方面,如果你只想执行 playbook 中某个特定任务 之外 的所有任务,你可以这样做:

# ansible-playbook httpd.yml --skip-tags='conf'

ansible之role运用

创建role的步骤

  1. 创建以roles命名的目录

  2. 在roles目录中分别创建以各个角色名称的目录,如webserver

  3. 在每个角色命名的目录中分别创建files、handlers]meta、tasks、templates、vars目录;用不到的目录可以创建,也可以不创建。

  4. 在playbook文件中,调用各角色;

创建目录树

[root@node2 ~]# mkdir -pv /root/ansible_playbooks/roles/{webservs,dbservs}/{tasks,files,templates,meta,handlers,vars}

tree /root/ansible_playbooks/
roles/
├── dbservs
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
├── site.yml
└── webservs
├── files
│   └── httpd.conf
├── handlers
│   └── main.yml
├── meta
├── tasks
│   └── main.yml
├── templates
└── vars

复制httpd配置文件到files目录

cp /etc/httpd/conf/httpd.conf files/

定义webservs tasks/main.yml

注意copy src 使用相对路径

[root@node2 ansible_playbooks]# cat /root/ansible_playbooks/roles/webservs/tasks/main.yml 
- name: install httpd package
  yum: name=httpd
- name: install configureation file
  copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
  tags:
  - conf
  notify:
  - restart httpd
- name: start httpd
  service: name=httpd state=started

定义webservs handlers/main.yml

[root@node2 ansible_playbooks]# cat /root/ansible_playbooks/roles/webservs/handlers/main.yml 
- name: restart httpd
  service: name=httpd state=restarted

复制mysql配置文件到files目录

[root@node2 roles]# cp /etc/my.cnf /root/ansible_playbooks/roles/dbservs/files/

定义dbservs tasks/main.yml

[root@node2 roles]# cat dbservs/tasks/main.yml 
- name: install mysql-server package
  yum: name=mysql-server state=latest
- name: install configuration file
  copy: src=my.cnf dest=/etc/my.cnf
  tags:
  - myconf
  notify:
  - restart mysqld
- name: start mysqld service
  service: name=mysqld enabled=true state=started

定义dbservs handlers/main.yml

- name: restart mysqld
  service: name=mysqld state=restarted

定义主机 site.yml

注意角色名等于roles目录下目录名

[root@node2 ansible_playbooks]# cat /root/ansible_playbooks/roles/site.yml 
- hosts: 192.168.0.101
  remote_user: root
  roles:
  - webservs

- hosts: 192.168.0.102
  remote_user: root
  roles:
  - dbservs