基于python语言实现,有paramiko,Pyyaml和jinjia2 三个关键模块
部署简单,agegtlees,默认使用SSH协议
基于密钥认证
在inventory 文件中指定账号和密码
# install the epel-release RPM if needed on CentOS, RHEL, or Scientific Linux $ sudo yum install ansible
配置文件:/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
[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 <host-pattern> [-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
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
变量命名:变量名仅能由字母、数字和下划线组成、且只能以字母开头
facts 信息被保存在ansible变量中,可以引用使用
register:把任务的输出定义为变量,
实例如下
task: shell:/usr/bin/foo register:foo_result ignore_error:True
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
Inventor
Modules
Ad hot commands
Playbooks
Tasks:任务,及调佣模块完成基础操作
variables:变量
tempalates:模板
handlers:处理器。由某事件触发执行的操作
roles:角色
playbook 中的每一个 play,个别地选择操作的目标机器是哪些,以哪个用户身份去完成要执行的步骤。hosts 行的内容是一个或多个组或主机的 patterns,以逗号为分隔符,
实例:
- hosts: webservers remote_user: root
每一个 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
用于当关注的资源发生变化时采取一定的操作。'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
自定变量引用
调用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
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' }
要求为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
如果你有一个大型的 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'
创建role的步骤
创建以roles命名的目录
在roles目录中分别创建以各个角色名称的目录,如webserver
在每个角色命名的目录中分别创建files、handlers]meta、tasks、templates、vars目录;用不到的目录可以创建,也可以不创建。
在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