1.1 ansible安装与配置认证
ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。 ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。 主要包括: (1)、连接插件connection plugins:负责和被监控端实现通信; (2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机; (3)、各种模块核心模块、command模块、自定义模块; (4)、借助于插件完成记录日志邮件等功能; (5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
特点:
- 不需要安装客户端
- 基于模块工作,模块可以以任何语言开发
- 不仅支持命令行使用模块,也可以支持yaml(python)格式的playbook
- 支持sudo
- 有提供UI(浏览器图形化)
安装
只需在服务端安装(IP:192.168.0.106)。
代码语言:javascript复制[root@adailinux ~]# yum install -y epel-release
[root@adailinux ~]# yum install -y ansible
配置密钥
代码语言:javascript复制创建密钥:
[root@adailinux ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
9f:e7:73:61:9e:af:ea:14:f8:af:82:de:c9:50:06:b0 root@adailinux
The key's randomart image is:
--[ RSA 2048]----
| . |
| o |
| E . |
| . . |
| S . |
| o .o |
| ..o o o |
| . .=.. |
| .. o==oo.|
-----------------
将公钥拷贝到客户机:
代码语言:javascript复制[root@adailinux ~]# cat /root/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuoWwgauteoSamitR tMXz90nKQJMHJmknTVctIzkJ5YNTdAdHrKBeNiKP3HoODJVkO0Fj3MnWOFHRZtFfzaJ690y846JzKllGmnDcVeaZC6/1Mg3jNVZ7wmtNhMplj ObJicAOSIoi5bauYPfTQ3F3caCWa/wLBu46pQLu8hCdlKb4TR6t3t DJqTA5aZz0zrx08YqCZFlv92B THWhIp0bOd uJW ivd38u/FdNaY54z7Qr S6cQ9Dir5HrG5oWcrd1HbNcHiBrIXXH8t5aQCWJAy0zrG8hfh5d3PJQjo4q7COtj090CAdWIEtT8euz25asnmNmeDdU8CoZkyoiIw== root@adailinux
客户机:
[root@client ~]# vim .ssh/authorized_keys
#ansible
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuoWwgauteoSamitR tMXz90nKQJMHJmknTVctIzkJ5YNTdAdHrKBeNiKP3HoODJVkO0Fj3MnWOFHRZtFfzaJ690y846JzKllGmnDcVeaZC6/1Mg3jNVZ7wmtNhMplj ObJicAOSIoi5bauYPfTQ3F3caCWa/wLBu46pQLu8hCdlKb4TR6t3t DJqTA5aZz0zrx08YqCZFlv92B THWhIp0bOd uJW ivd38u/FdNaY54z7Qr S6cQ9Dir5HrG5oWcrd1HbNcHiBrIXXH8t5aQCWJAy0zrG8hfh5d3PJQjo4q7COtj090CAdWIEtT8euz25asnmNmeDdU8CoZkyoiIw== root@adailinux
服务端:
[root@adailinux ~]# ssh 192.168.0.109
Address 192.168.0.109 maps to bogon, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!
Last login: Thu Sep 28 00:49:07 2017 from 192.168.0.106
[root@client ~]#
即,106可以登录109机器
ansible远程执行命令
定义主机群组
代码语言:javascript复制更改配置文件:
[root@adailinux ~]# vim /etc/ansible/hosts
# Ex 2: A collection of hosts belonging to the 'webservers' group
[testhosts]
127.0.0.1
192.168.0.109
##创建主机组
注意,如果要使用127.0.0.1连接本地主机(106)需要将密钥写入本机密钥配置文件:
[root@adailinux ~]# vim .ssh/authorized_keys
#本地公钥
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuoWwgauteoSamitR tMXz90nKQJMHJmknTVctIzkJ5YNTdAdHrKBeNiKP3HoODJVkO0Fj3MnWOFHRZtFfzaJ690y846JzKllGmnDcVeaZC6/1Mg3jNVZ7wmtNhMplj ObJicAOSIoi5bauYPfTQ3F3caCWa/wLBu46pQLu8hCdlKb4TR6t3t DJqTA5aZz0zrx08YqCZFlv92B THWhIp0bOd uJW ivd38u/FdNaY54z7Qr S6cQ9Dir5HrG5oWcrd1HbNcHiBrIXXH8t5aQCWJAy0zrG8hfh5d3PJQjo4q7COtj090CAdWIEtT8euz25asnmNmeDdU8CoZkyoiIw== root@adailinux
执行远程命令(ansible模块——command)
执行结果如下:
代码语言:javascript复制单个机器:
[root@adailinux ~]# ansible 192.168.0.109 -m command -a 'hostname'
192.168.0.109 | SUCCESS | rc=0 >>
client
机器组:
[root@adailinux ~]# ansible testhosts -m command -a 'hostname'
192.168.0.109 | SUCCESS | rc=0 >>
client
127.0.0.1 | SUCCESS | rc=0 >>
adailinux
说明: -m:指定ansible要调用的模块;-a:指定具体命令。
报错:
代码语言:javascript复制"msg" Aborting target uses selinux but python bindings (libselinux-python) aren't installed.
解决办法:
代码语言:javascript复制[root@adailinux ~]# yum install -y libselinux-python
ansible模块——shell
代码语言:javascript复制[root@adailinux ~]# ansible 192.168.0.109 -m shell -a 'hostname'
192.168.0.109 | SUCCESS | rc=0 >>
client
[root@adailinux ~]# ansible 192.168.0.109 -m shell -a 'cat /etc/passwd|grep root'
192.168.0.109 | SUCCESS | rc=0 >>
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
注: command模块和shell模块的区别是:shell模块支持“管道符”及脚本。
ansible拷贝文件或目录
使用copy模块。
代码语言:javascript复制[root@adailinux ~]# ansible 192.168.0.109 -m copy -a "src=/tmp/test.txt dest=/tmp/testdir/ owner=root group=root mode=0644"
192.168.0.109 | SUCCESS => {
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/tmp/testdir/test.txt",
"gid": 0,
"group": "root",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"mode": "0644",
"owner": "root",
"size": 0,
"src": "/root/.ansible/tmp/ansible-tmp-1506533297.89-81185506773616/source",
"state": "file",
"uid": 0
}
#此处IP可以换成机器组:testhosts“
客户机:
[root@client ~]# ls /tmp/
testdir
注意: 源文件或目录会放到目标目录下面。src表示源地址,dest表示目标地址
远程执行脚本
服务端:192.168.8.141 客户端:192.168.8.142
代码语言:javascript复制[root@adailinux ~]# vim /etc/ansible/hosts
[testhosts]
127.0.0.1
192.168.8.142
代码语言:javascript复制创建脚本:
[root@adailinux ~]# vim /tmp/test.sh
#!/bin/bash
d=`date`
echo $d > /tmp/an_test.txt
分发脚本;
[root@adailinux ~]# ansible testhosts -m copy -a "src=/tmp/test.sh dest=/tmp/test.sh mode=0755"
远程执行脚本:
[root@adailinux ~]# ansible testhosts -m shell -a "/bin/sh /tmp/test.sh"
192.168.8.142 | SUCCESS | rc=0 >>
127.0.0.1 | SUCCESS | rc=0 >>
在客户机查看:
[root@client ~]# ls /tmp/
an_test.txt test.sh
[root@client ~]# cat /tmp/an_test.txt
2017年 09月 28日 星期四 05:30:25 CST
ansible实现任务计划
创建计划任务:
代码语言:javascript复制[root@adailinux ~]# ansible 192.168.8.142 -m cron -a "name='test cron' job='/bin/touch /tmp/110.txt' weekday=6"
192.168.8.142 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"test cron"
]
}
查看客户机:
[root@client ~]# crontab -l
#Ansible: test cron
* * * * 6 /bin/touch /tmp/110.txt
时间:分钟minute 小时hour 日day 月份month
删除计划任务: 只需加上参数——“state=absent”
代码语言:javascript复制[root@adailinux ~]# ansible 192.168.8.142 -m cron -a "name='test cron' job='/bin/touch /tmp/110.txt' weekday=6 state=absent"
192.168.8.142 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": []
}
客户机:
[root@client ~]# crontab -l
ansible安装rpm包&&管理服务
安装rpm包
代码语言:javascript复制[root@adailinux ~]# ansible 192.168.8.142 -m yum -a "name=zabbix-agent.i686"
注意: name后面需要跟一个准确的包名。
管理服务
代码语言:javascript复制[root@adailinux ~]# ansible 192.168.8.142 -m service -a "name=httpd state=started enable=no"
代码语言:javascript复制列出所有模块:
[root@adailinux ~]# ansible-doc -l
查看指定模块的参数:
[root@adailinux ~]# ansible-doc cron
ansible playbook
相当于把模块写入到配置文件里面,然后单独执行配置文件实现自动化操作。
创建文件
代码语言:javascript复制[root@jumpserver ~]# vim /etc/ansible/test.yml
---
- hosts: 192.168.8.130
remote_user: root
tasks:
- name: test_playbook
shell: touch /tmp/test.txt
说明: hosts参数指定了对哪些主机进行操作;user参数指定了使用什么用户登录远程主机操作;tasks指定了一个任务,其下面的name参数同样是对任务的描述,在执行过程中会打印出来。
定义完成后只需要执行命令:
代码语言:javascript复制[root@jumpserver ~]# ansible-playbook test.yml
PLAY [192.168.8.130] ************************************************************************
TASK [Gathering Facts] **********************************************************************
ok: [192.168.8.130]
TASK [test_playbook] ************************************************************************
[WARNING]: Consider using file module with state=touch rather than running touch
changed: [192.168.8.130]
PLAY RECAP **********************************************************************************
192.168.8.130 : ok=2 changed=1 unreachable=0 failed=0
查看客户机:
[root@localhost ~]# ls /tmp/
test.txt
即可完成所有配置。
创建用户
代码语言:javascript复制[root@jumpserver ansible]# vim create_user.yml
---
- name: create_user
hosts: 192.168.8.130
user: root
gather_facts: false
vars:
- user: "test"
tasks:
- name: create user
user: name="{{ user }}"
说明: name参数对该playbook实现的功能做一个概述,后面执行过程中,会打印 name变量的值 ,可以省略;gather_facts参数指定了在以下任务部分执行前,是否先执行setup模块获取主机相关信息,这在后面的task会使用到setup获取的信息时用到;vars参数,指定了变量,这里指字一个user变量,其值为test ,需要注意的是,变量值一定要用引号引住;user提定了调用user模块,name是user模块里的一个参数,而增加的用户名字调用了上面user变量的值。
循环with_items:
代码语言:javascript复制---
- hosts: testhost
user: root
tasks:
- name: change mod for file
file: path=/tmp/{{ item }} mode=600 owner=root group=root
with_items:
- 1.txt
- 2.txt
说明: with_items 就是循环的关键
条件when:
代码语言:javascript复制---
- hosts: testhost
remote_user: root
gather_facts: True
tasks:
- name: use when
shell: touch /tmp/when.txt
when: facter_ipaddress == "172.7.15.106"
模块handlers:
执行task之后,服务器发生变化之后要执行的一些操作,比如我们修改了配置文件后,需要重启一下服务,具体示例:
代码语言:javascript复制---
- hosts: testhost
remote_user: root
tasks:
- name: test copy
copy: src=/tmp/1.txt dest=/tmp/2.txt
notify: test handlers
handlers:
- name: test handlers
shell: echo "121212" >> /tmp/2.txt
说明,只有copy模块真正执行后,才会去调用下面的handlers相关的操作。也就是说如果1.txt和2.txt内容是一样的,并不会去执行handlers里面的shell相关命令。这种比较适合配置文件发生更改后,重启服务的操作。
实例:安装ansible
因为换了机器,所以重新安装ansible并进行配置。
机器 | IP |
---|---|
server(centos7) | 192.168.8.139 |
client(centos7) | 192.168.8.130 |
server机器上编译安装好nginx。
使用ansible源码安装nginx
思路: 先在一台机器上安装好nginx,然后打包,再利用ansible分发下去;或者直接把/usr/local/nginx目录同步到其他机器。 需要注意的是编译安装的nginx会需要一些库文件,所以再同步之后还要在client机器上yum安装这些包。
准备工作
代码语言:javascript复制[root@jumpserver conf]# cd /usr/local/
打包:
[root@jumpserver local]# tar czf nginx.tar.gz nginx
[root@jumpserver local]# ls
bin etc games include lib lib64 libexec nginx nginx.tar.gz sbin share src
创建一系列目录:
[root@jumpserver local]# cd /etc/ansible/
[root@jumpserver ansible]# ls
ansible.cfg hosts roles
[root@jumpserver ansible]# mkdir nginx_install
[root@jumpserver ansible]# cd nginx_install/
[root@jumpserver nginx_install]# mkdir roles
[root@jumpserver nginx_install]# cd roles/
[root@jumpserver roles]# mkdir common install
#common:用于做前期准备工作(准备一些依赖的包)
定义common内的目录及文件:
代码语言:javascript复制[root@jumpserver roles]# cd common/
[root@jumpserver common]# mkdir tasks
[root@jumpserver common]# cd tasks/
[root@jumpserver tasks]# vim main.yml
- name: Install initializtion require software
yum: name={{ item }} state=installed
with_items:
- zlib-devel
- pcre-devel
- openssl-devel
定义install内的目录及文件:
代码语言:javascript复制[root@jumpserver install]# pwd
/etc/ansible/nginx_install/roles/install
[root@jumpserver install]# mkdir tasks vars files templates
[root@jumpserver install]# cp /usr/local/nginx.tar.gz files/
说明: 我们需要把源码包放到 files目录里面
[root@jumpserver install]# cp /usr/local/nginx/conf/nginx.conf templates/
[root@jumpserver install]# cp /etc/init.d/nginx templates/
[root@jumpserver install]# vim vars/main.yml
nginx_user: www
nginx_basedir: /usr/local/nginx
#指定解压后文件存放目录
说明: 需要再templates下面准备好 默认页、安装nginx的shell脚本、nginx启动脚本、nginx配置文件以及虚拟主机配置文件
代码语言:javascript复制[root@jumpserver install]# cd tasks/
[root@jumpserver tasks]# vim copy.yml
- name: Copy Nginx Software
copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root
- name: Uncompression Nginx Software
shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/
- name: Copy Nginx Start Script
template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755
- name: Copy Nginx Config
template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=0644
说明: 首先把压缩包拷贝到/tmp/目录下,然后解压到/usr/local/下,再拷贝启动脚本到/etc/init.d/下,再拷贝nginx.conf以及vhost.conf
代码语言:javascript复制[root@jumpserver tasks]# vim install.yml
- name: Create Nginx User
user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin
- name: Start Nginx Service
service: name=nginx state=stopped
- name: Add Boot Start Nginx Service
shell: chkconfig --level 345 nginx on
- name: Delete Nginx compression files
shell: rm -rf /tmp/nginx.tar.gz
[root@jumpserver tasks]# vim main.yml
- include: copy.yml
- include: install.yml
说明: roles目录下有三个角色,common为一些准备操作,install为安装nginx的操作;每个角色下面又有几个目录,handlers下面是当发生改变时要执行的操作,通常用在配置文件发生改变,重启服务。files为安装时用到的一些文件,meta为说明信息,说明角色依赖等信息,tasks里面是核心的配置文件,templates通常存一些配置文件,启动脚本等模板文件,vars下为定义的变量。 至此,两个roles:common和install定义完成,接下来定义一个文件入口。
定义入口文件
代码语言:javascript复制[root@jumpserver tasks]# cd /etc/ansible/nginx_install/
[root@jumpserver nginx_install]# vim install.yml
---
- hosts: 192.168.8.130
remote_user: root
gather_facts: True
roles:
- common
- install
执行
代码语言:javascript复制[root@jumpserver nginx_install]# pwd
/etc/ansible/nginx_install
[root@jumpserver nginx_install]# ansible-playbook install.yml
PLAY [192.168.8.130] ************************************************************************
TASK [Gathering Facts] **********************************************************************
ok: [192.168.8.130]
TASK [common : Install initializtion require software] **************************************
ok: [192.168.8.130] => (item=[u'zlib-devel', u'pcre-devel', u'openssl-devel'])
TASK [install : Copy Nginx Software] ********************************************************
changed: [192.168.8.130]
TASK [install : Uncompression Nginx Software] ***********************************************
[WARNING]: Consider using unarchive module rather than running tar
changed: [192.168.8.130]
TASK [install : Copy Nginx Start Script] ****************************************************
ok: [192.168.8.130]
TASK [install : Copy Nginx Config] **********************************************************
ok: [192.168.8.130]
TASK [install : Create Nginx User] **********************************************************
ok: [192.168.8.130]
TASK [install : Start Nginx Service] ********************************************************
ok: [192.168.8.130]
TASK [install : Add Boot Start Nginx Service] ***********************************************
changed: [192.168.8.130]
TASK [install : Delete Nginx compression files] *********************************************
[WARNING]: Consider using file module with state=absent rather than running rm
changed: [192.168.8.130]
PLAY RECAP **********************************************************************************
192.168.8.130 : ok=10 changed=4 unreachable=0 failed=0
查看客户机:
[root@localhost ~]# ps aux |grep nginx
root 10791 0.0 0.1 20488 628 ? Ss 19:41 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody 10794 0.0 0.6 22932 3212 ? S 19:41 0:00 nginx: worker process
nobody 10795 0.0 0.6 22932 3212 ? S 19:41 0:00 nginx: worker process
root 13242 0.0 0.1 112668 968 pts/0 R 19:46 0:00 grep --color=auto nginx
配置成功!!!
参考
官方文档 http://docs.ansible.com/ansible/ 安装配置 http://sofar.blog.51cto.com/353572/1579894 常见错误 http://afewbug.com/article/26 样例库:https://github.com/dl528888/ansible-examples
ansible常用命令及参数
代码语言:javascript复制参数:
-a 'Arguments', --args='Arguments' 命令行参数
-m NAME, --module-name=NAME 执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用 -m参数
-i PATH, --inventory=PATH 指定库存主机文件的路径,默认为/etc/ansible/hosts.
-u Username, --user=Username 执行用户,使用这个远程用户名而不是当前用户
-U --sud-user=SUDO_User sudo到哪个用户,默认为 root
-k --ask-pass 登录密码,提示输入SSH密码而不是假设基于密钥的验证
-K --ask-sudo-pass 提示密码使用sudo
-s --sudo sudo运行
-S --su 用 su 命令
-l --list 显示所支持的所有模块
-s --snippet 指定模块显示剧本片段
-f --forks=NUM 并行任务数。NUM被指定为一个整数,默认是5。 #ansible testhosts -a "/sbin/reboot" -f 10 重启testhosts组的所有机器,每次重启10台
--private-key=PRIVATE_KEY_FILE 私钥路径,使用这个文件来验证连接
-v --verbose 详细信息
all 针对hosts 定义的所有主机执行
-M MODULE_PATH, --module-path=MODULE_PATH 要执行的模块的路径,默认为/usr/share/ansible/
--list-hosts 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook 文件
-o --one-line 压缩输出,摘要输出.尝试一切都在一行上输出。
-t Directory, --tree=Directory 将内容保存在该输出目录,结果保存在一个文件中在每台主机上。
-B 后台运行超时时间
-P 调查后台程序时间
-T Seconds, --timeout=Seconds 时间,单位秒s
-P NUM, --poll=NUM 调查背景工作每隔数秒。需要- b
-c Connection, --connection=Connection 连接类型使用。可能的选项是paramiko(SSH),SSH和地方。当地主要是用于crontab或启动。
--tags=TAGS 只执行指定标签的任务 例子:ansible-playbook test.yml --tags=copy 只执行标签为copy的那个任务
--list-hosts 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook 文件
--list-tasks 列出所有将被执行的任务
-C, --check 只是测试一下会改变什么内容,不会真正去执行;相反,试图预测一些可能发生的变化
--syntax-check 执行语法检查的剧本,但不执行它
-l SUBSET, --limit=SUBSET 进一步限制所选主机/组模式 --limit=192.168.0.15 只对这个ip执行
--skip-tags=SKIP_TAGS 只运行戏剧和任务不匹配这些值的标签 --skip-tags=copy_start
-e EXTRA_VARS, --extra-vars=EXTRA_VARS 额外的变量设置为键=值或YAML / JSON
#cat update.yml
---
- hosts: {{ hosts }}
remote_user: {{ user }}
..............
#ansible-playbook update.yml --extra-vars "hosts=vipers user=admin" 传递{{hosts}}、{{user}}变量,hosts可以是 ip或组名
-l,--limit 对指定的 主机/组 执行任务 --limit=192.168.0.10,192.168.0.11 或 -l 192.168.0.10,192.168.0.11 只对这个2个ip执行任务
配置sudo用户
代码语言:javascript复制---
- hosts: all
vars:
user: test
password: "$6$rounds=100000$O2BHfT2XIF6oDb9w$8Hhv4vOrLN6JF/nRVYDd8zZdnn9TNkQutyYYywIcPF2kRiHgkwAjqHIN7sDUkd1DcjLRABWT9ULHZPBOF2bZS/"
remote_user: root
tasks:
- name: Add user {{ user }}
user: name={{user}} comment="ceph user" password={{ password }}
- name: Config /etc/sudoers
lineinfile: dest=/etc/sudoers state=present line='{{item}}' validate='visudo -cf %s'
with_items:
- "{{ user}} ALL=(ALL) NOPASSWD: ALL"
- "Defaults: {{user}} !requiretty"
此playbook将添加一个具有sudo权限的 test 用户 密码为password
更改用户只用更改vars:中的user 即可
生成密码:
代码语言:javascript复制$ pip install passlib
python -c "from passlib.hash import sha512_crypt; import getpass; print sha512_crypt.encrypt(getpass.getpass())"
输入密码后确认
会生成一长串字符替换playbook中的即可
(adsbygoogle = window.adsbygoogle || []).push({});