http://www.ansible.com.cn/:参照中文文档
安装方式:采用epel源安装
a安装epel源:
yum install wget
wget dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
rpm -ivh epel-release-6-8.noarch.rpm
yum -y install ansible
b安装epel源:
rpm -ivh http://mirror.serverbeheren.nl/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum install ansible -y
以上两种epel源都可以使用
ansible是基于ssh通信的,所以需要ssh密码共享,节点服务器192.168.1.155,ansible控制端服务器192.168.1.11
基于ssh与节点通信:
ssh-keygen -t rsa -P ''
ssh-copy-id -i .ssh/id_rsa.pub root@192.168.1.155
ansible命令使用
ansible <pattern_goes_here> -m <module_name> -a <arguments>
-f forks:默认为5个,没有超过可以不用定义
-m command:命令操作(默认模块)
-s:以sudo模式
ansible all -m command -a "date"
ansible all -m command -a "service httpd status"
或者直接省略-m command:
ansible all -a "ls /tmp"
首先定义hosts文件:
vim /etc/ansible/hosts
[web]
192.168.1.155
实例演示:
ansible-doc -s copy
ansible web -m copy -a "src=/root/ansible.tar.gz dest=/tmp/"
ansible web -m command -a "ls /tmp"
ansible-doc -s cron
ansible web -m cron -a 'name="custom job" minute=*/3 hour=* day=* month=* weekday=* job="/usr/sbin/ntpdate 192.168.31.1"'
ansible web -a "crontab -l"
ansible-doc -s group
ansible web -m group -a "gid=306 system=yes name=mysql"
ansible web -a "tail -1 /etc/group"
ansible-doc -s user
ansible all -m user -a "":group:基本组,groups:附加组
ansible-doc -s yum
ansible web -m yum -a "state=present name=corosync"
ansible web -a "rpm -qa corosync"
ansible-doc -s service
ansible web -m service -a "state=started name=httpd enabled=yes"
ansible web -a "chkconfig --list httpd"
ansible web -m file -a "dest=/tmp/test.txt group=root mode=600 state=touch"
更多模块参考:
ansible-doc -l:列出所有的模块
ansible-doc -s module_name:指出指定模块对应的参数
当使用ansible第一次copy时,遇到如下错误:
[root@RS2 log]# ansible web -m copy -a "src=/root/test.sh dest=/tmp"
192.168.31.115 | FAILED! => {
"changed": false,
"checksum": "31d5f2c4016e2081d99dcd52bf1ab19f48db767e",
"failed": true,
"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
}
上述秒数应该是提示libselinux-python没有安装上,于是将它安装:
[root@RS2 log]# ansible web -m yum -a "name=libselinux-python state=present"
再次copy:
[root@RS2 log]# ansible web -m copy -a "src=/root/test.sh dest=/tmp"
192.168.31.115 | SUCCESS => {
"changed": true,
"checksum": "31d5f2c4016e2081d99dcd52bf1ab19f48db767e",
"dest": "/tmp/test.sh",
"gid": 0,
"group": "root",
"md5sum": "7aa31a8e7374035b1869a50b12544605",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 181,
"src": "/root/.ansible/tmp/ansible-tmp-1463435307.96-222484590205418/source",
"state": "file",
"uid": 0
}
于是成功解决错误
简单说几个模块:
模块之一:setup(用来查看远程主机的一些基本信息)
ansible web -m setup
模块之file:
directory:如果目录不存在,就创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件
模块之- template: Templates a file out to a remote server.
ansible web -m template -a "src=/root/ansible/httpd.yaml dest=/tmp":只能复制file,不能复制目录
模块之copy:既能复制文件,也能复制目录
[root@RS2 ansible]# ansible web -m template -a "src=/root/ansible/test dest=/tmp"
192.168.1.155 | FAILED! => {
"changed": false,
"failed": true,
"msg": "IOError: [Errno 21] Is a directory: u'/root/ansible/test'"
}
[root@RS2 ansible]# ansible web -m copy -a "src=/root/ansible/test dest=/tmp"
192.168.1.155 | SUCCESS => {
"changed": false,
"dest": "/tmp/",
"src": "/root/ansible/test"
}
学会模块使用之后就是playbook的编写使用了(基于yaml语言)
playbook:
检测语法错误,并不执行:
[root@RS2 ansible]# ansible-playbook debug.yaml --syntax-check(检测语法)
playbook: debug.yaml
http.yaml
[root@RS2 ansible]# cat httpd.yaml
- hosts: web
remote_user: root
tasks:
- name: install httpd
yum: name=httpd state=present
notify:
- start httpd
handlers:
- name: start httpd
service: name=httpd state=started enabled=yes
[root@RS2 ansible]# ansible-playbook httpd.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.1.155]
TASK [install httpd] ***********************************************************
changed: [192.168.1.155]
RUNNING HANDLER [start httpd] **************************************************
changed: [192.168.1.155]
PLAY RECAP *********************************************************************
192.168.1.155 : ok=3 changed=2 unreachable=0 failed=0
在playbook中使用item及with_items
copy multi files to destination
[root@RS2 ansible]# cat template.yaml
- hosts: web
remote_user: root
tasks:
- name: copy multi file to destination
template: src=/root/ansible/httpd.yaml dest=/tmp/`item`:多个项目同时更新
with_items:
- httpd001.yaml
- httpd002.yaml
- httpd003.yaml
多项目执行:
- name: touch files with an optional mode
file: dest=`item`.`path` state=touch mode={{item.mode|default(omit)}}
with_items:
- path: /tmp/foo
- path: /tmp/bar
- path: /tmp/baz
mode: "0444"
[root@RS2 ansible]# cat loop.yaml
- hosts: web
remote_user: root
tasks:
- name: echo variables
shell: echo ` item `
with_items: [ 2,3 ]
[root@RS2 ansible]# cat loop.yaml.bak
- hosts: web
remote_user: root
tasks:
- name: echo variables
shell: echo ` item `
with_items:
- 2
- 3
when条件使用:
tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_os_family == "Debian"
tasks:
- name: "shutdown CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
(ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
[root@RS2 ansible]# cat delete.yaml
- hosts: web
remote_user: root
tasks:
- name: delete any file
shell: rm -f /tmp/httpd.yaml
when: ansible_os_family == "RedHat":判断节点服务器是否为RedHat系列,是的话就删掉文件
ansible_os_family该值是模块setup中的结果信息
- hosts: web
remote_user: root
tasks:
- name: delete someone file
file: dest=/tmp/httpd/yaml state=absent
fatal: [192.168.1.155]: FAILED! => {"changed": false, "failed": true, "msg":
"value of state must be one of: file,directory,link,hard,touch,absent, got: abent"}
删除文件两种方式,推荐file:
1、file: dest=/tmp/httpd/yaml state=absent
2、shell: rm -f /tmp/httpd.yaml
引用变量加条件when:
[root@RS2 ansible]# cat peci.yaml
- hosts: web
remote_user: root
vars:
peci: true:此处变量可自定义
tasks:
- name: judge peci
shell: echo "hello world"
when: peci
注册变量:
[root@RS2 ansible]# cat variables.yaml
- hosts: web
remote_user: root
tasks:
- name: judge file
shell: ls /root/ansible
register: home_dirs
- name: copy file
template: src=/root/ansible/` item ` dest=/tmp/` item `
with_items: home_dirs.stdout.split()----》注册变量的值
利用变量进行替换,以及when结合register的使用,当register的变量result执行成功,when:result|success就继续安装步骤执行
result|success这也就代表注册变量的返回值是成功的
[root@RS2 ansible]# cat test.yaml
- hosts: web
remote_user: root
vars:
apache: httpd
tasks:
- name: install httpd
yum: name=` apache ` state=present
register: result:将上步骤执行的结果注册到变量result中
- name: start httpd
service: name=httpd state=started enabled=yes
when: result|success:当result变量是成功的话,就执行是service步骤
[root@RS2 ansible]# cat test.yaml
- hosts: web
remote_user: root
vars:
apache: httpd
tasks:
- name: install httpd
yum: name=` apache ` state=present
register: result
- name: start httpd
service: name=httpd state=started enabled=yes
when: result|success
- name: display time:这一步骤并没有执行,退出了,证明了失败了才会执行
shell: date
when: result|failed
TASK [display time] ************************************************************
skipping: [192.168.1.155]
[root@RS2 ansible]# cat test.yaml
- hosts: web
remote_user: root
vars:
apache: httpd
tasks:
- name: install httpd
yum: name=` apache ` state=present
register: result
- name: start httpd
service: name=httpd state=started enabled=yes
when: result|success
- name: display time
shell: date
when: result|failed
[root@RS2 ansible]# vim test.yaml
[root@RS2 ansible]# ansible-playbook test.yaml --syntax-check
playbook: test.yaml
[root@RS2 ansible]# ansible-playbook test.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.1.155]
TASK [install httpd] ***********************************************************
fatal: [192.168.1.155]: FAILED! => {"changed": true, "cmd": "ls /root/ansible", "delta": "0:00:00.021731", "end": "2016-07-30 16:58:19.750658", "failed": true, "rc": 2, "start": "2016-07-30 16:58:19.728927", "stderr": "ls: 无法访问/root/ansible: 没有那个文件或目录", "stdout": "", "stdout_lines": [], "warnings": []}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @test.retry
PLAY RECAP *********************************************************************可以看出并没有执行failed错误的那条date命令,表明错误操作就直接不进行下面操作
192.168.1.155 : ok=1 changed=0 unreachable=0 failed=1
[root@RS2 ansible]# cat test.
test.retry test.yaml
[root@RS2 ansible]# cat test.yaml
- hosts: web
remote_user: root
vars:
apache: httpd
tasks:
- name: install httpd
shell: ls /root/ansible
register: result
ignore_errors: True:接入忽略错误,加入了这行后面failed操作步骤继续运行
- name: start httpd
service: name=httpd state=started enabled=yes
when: result|success
- name: display time
shell: date
when: result|failed
[root@RS2 ansible]# ansible-playbook test.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.1.155]
TASK [install httpd] ***********************************************************
fatal: [192.168.1.155]: FAILED! => {"changed": true, "cmd": "ls /root/ansible", "delta": "0:00:00.009894", "end": "2016-07-30 17:01:51.789377", "failed": true, "rc": 2, "start": "2016-07-30 17:01:51.779483", "stderr": "ls: 无法访问/root/ansible: 没有那个文件或目录", "stdout": "", "stdout_lines": [], "warnings": []}
...ignoring
TASK [start httpd] *************************************************************上述result是错误结果,所以skip
skipping: [192.168.1.155]
TASK [display time] ************************************************************此处命令成功:ignore_errors: True是加入了这一行
changed: [192.168.1.155]
PLAY RECAP *********************************************************************
192.168.1.155 : ok=3 changed=1 unreachable=0 failed=0
定义变量,替换文件名,进行copy
[root@RS2 ansible]# cat test1.
test1.retry test1.yaml
[root@RS2 ansible]# cat test1.yaml
- hosts: web
remote_user: root
vars:
src_file: test.yaml
tasks:
- name: copy test.yaml to destination
copy: src=/root/ansible/` src_file ` dest=/tmp/` src_file `
[root@RS2 ansible]# ansible-playbook test1.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.1.155]
TASK [copy test.yaml to destination] *******************************************
changed: [192.168.1.155]
PLAY RECAP *********************************************************************
192.168.1.155 : ok=2 changed=1 unreachable=0 failed=0
错误样例:
[root@RS2 ansible]# cat test1.yaml
- hosts: web
remote_user: root
vars:
src_file: /root/ansible/test.yaml
tasks:
- name: copy test.yaml to destination
copy: src=` src_file ` dest=/tmp/` src_file `
[root@RS2 ansible]# ansible-playbook test1.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.1.155]
TASK [copy test.yaml to destination] *******************************************
fatal: [192.168.1.155]: FAILED! => {"changed": false, "checksum": "f0f36e6c39f0fdd58399e8cccaa9dcf30e1cef18", "failed": true, "msg": "Destination directory /tmp//root/ansible does not exist"}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @test1.retry
PLAY RECAP *********************************************************************
192.168.1.155 : ok=1 changed=0 unreachable=0 failed=1
安装lamp
[root@RS2 ansible]# cat lamp.yaml
- hosts: web
remote_user: root
tasks:
- name: install php php-mysql httpd
yum: name=` item ` state=present
with_items:
- httpd
- php
- php-mysql
- mysql-server
register: result
- name: start httpd server
service: name=httpd state=started enabled=yes
when: result|success
- name: start mysql server
service: name=mysqld state=started enabled=yes
when: result|success
[root@RS2 ansible]# ansible-playbook lamp.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.1.155]
TASK [install php php-mysql httpd] *********************************************
changed: [192.168.1.155] => (item=[u'httpd', u'php', u'php-mysql', u'mysql-server'])
TASK [start httpd server] ******************************************************
changed: [192.168.1.155]
TASK [start mysql server] ******************************************************
changed: [192.168.1.155]
PLAY RECAP *********************************************************************
192.168.1.155 : ok=4 changed=3 unreachable=0 failed=0
file做文件覆盖到节点目标机:
[root@RS2 tmp]# cat copy.yaml
- hosts: web
remote_user: root
tasks:
- name: copy file to destination
file: src=/tmp/yum.log dest=/tmp/yum.log state=touch
[root@RS2 tmp]# ansible-playbook copy.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.1.155]
TASK [copy file to destination] ************************************************
changed: [192.168.1.155]
PLAY RECAP *********************************************************************
192.168.1.155 : ok=2 changed=1 unreachable=0 failed=0
roles:
roles:在/etc/ansible/roles/下面创建一个role名称(比如nginx为例)
roles内各目录中可用的文件
tasks目录:至少创建一个名为main.yml的文件,其定义了此角色的任务列表:此文件可以使用 include包含其他的位于此目录中的tasks文件:
files目录:存放由copy或者script等模块调用的文件:
templates目录:templates模块会自动在此目录中寻找Jinjia2模板文件:
handlers目录:此目录中应当包含一个main。
yml文件:用于定义此角色用到的各handler:在handler中使用include包含的其他的handler文件也应该位于此目录中:
vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量
meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系:ansible 1.3及其以后的版本才支持
default目录:为当前角色定义默认变量时使用此目录,应该包含一个main.yml文件
handlers:
handler/main.yaml
---
- name: start nginx
service: name=nginx state=started
- name: reload nginx
service: name=nginx state=reloaded
Meta
Meta/main.yaml
---
dependencies:
- { roles: ssl }
templates
templates/serversforhackers.com.conf:一个配置文件就行
variables
vars/main.yml
---
domain: www.my.com
http_port: 80
tasks:
tasks/main.yaml
---
- name: install nginx
yum: name=nginx state=present
register: result
notify:
- start nginx
- name: copy configure file to destination
template: src=/path/to/serversforhackers.com.conf.j2
dest=/path/to/serversforhackers.com.conf owner=root group=root
- name: create web root directory
file: dest=/www/html owner=nginx group=nginx state=directory mode=775 recurse=yes
notify:
- reload nginx
实例验证:
[root@RS2 nginx]# cat handlers/main.yaml
---
- name: start httpd
service: name=httpd state=started
- name: restart httpd
service: name=httpd state=restarted
[root@RS2 nginx]# cat tasks/main.yaml
---
- name: install httpd
yum: name=httpd state=present
notify:
- start httpd
- name: copy the configure file to destination
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
[root@RS2 nginx]# cat templates/httpd.conf.j2 :也就是httpd.conf配置文件后缀加上j2
[root@RS2 nginx]# cat vars/main.yaml
---
http_port: 80
[root@RS2 workflow]# cat install_httpd.yaml
---
- hosts: web
remote_user: root
roles:
- nginx
[root@RS2 ansible]# tree整个目录结果
.
|-- ansible.cfg
|-- hosts
|-- hosts.bak
|-- roles
| `-- nginx----》角色名
| |-- files
| |-- handlers-----》定义后续notify的处理play
| | `-- main.yaml
| |-- meta----》定义依赖
| |-- tasks-----》定义任务执行play
| | `-- main.yaml
| |-- templates----》定义模板文件
| | `-- httpd.conf.j2
| `-- vars:定义变量
| `-- main.yaml
`-- workflow-----》工作目录,存放各种playbook来执行角色
|-- install_httpd.retry
`-- install_httpd.yaml-----playbook来执行整个roles下的nginx
附上目录结构图:
转载于:https://blog.51cto.com/huangsir007/1832725