ansible介绍
ansible不需要安装客户端,通过sshd去通信
基于模块工作,模块可以由任何语言开发
不仅支持命令行使用模块,也支持编写 yaml 格式的 playbook,易于编写和阅读
安装十分简单,centos上可直接yum安装
有提供UI(浏览器图形化)www.ansible.com/tower,收费的
官方文档 http://docs.ansible.com/ansible/latest/index.html
ansible已经被redhat公司收购,它在github上是一个非常受欢迎的开源软件,github 地址 https://github.com/ansible/ansible
一本不错的入门电子书 https://ansible-book.gitbooks.io/ansible-first-book/
ansible的安装
准备两台机器,前面我们做实验的两台机器 liang-03,liang-04
只需要在 liang-03上安装 ansible
yum list |grep ansible 可以看到自带源里就有2.4版本的 ansible
yum install -y ansible ansible-doc
liang-03上生成密钥对 ssh-keygen -t rsa
把公钥放到 liang-04上,设置密钥认证
在 liang-03 的 vi /etc/ansible/hosts //配置主机组,比如说web组或db组,可以针对不同组做不同操作。
[testhost]
127.0.0.1
192.168.133.132
说明: testhost为主机组名字,自定义的。 下面两个ip为组内的机器ip;也可以写成主机名,但要在/etc/hosts中写上对应的ip。
ansible 批量推送公钥: www.cnblogs.com/amosli/p/6122908.html
ansible远程执行命令
ansible testhost -m command -a 'w'
这样就可以批量执行命令了。这里的testhost 为主机组名,-m后边是模块名字,-a后面是命令。当然我们也可以直接写一个ip,针对某一台机器来执行命令。
ansible 127.0.0.1 -m command -a 'hostname'
错误: "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
解决: yum install -y libselinux-python
还有一个模块就是shell同样也可以实现
ansible testhost -m shell -a 'w'
[root@liang-03 ~]# ansible testhost -m command -a 'w' 127.0.0.1 | CHANGED | rc=0 >> 16:59:21 up 1:40, 2 users, load average: 0.01, 0.05, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.66.1 15:55 9.00s 2.84s 0.01s ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/dac2654951 -tt liang-04 /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1551689960.48-22594798095640/AnsiballZ_command.py && sleep 0' root pts/3 localhost 16:59 0.00s 0.20s 0.01s w liang-04 | CHANGED | rc=0 >> 16:59:21 up 46 min, 2 users, load average: 0.03, 0.02, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.66.1 16:18 7:29 0.28s 0.28s -bash root pts/1 liang-03 16:59 0.00s 0.21s 0.01s w [root@liang-03 ~]# ansible liang-04 -m command -a 'w' liang-04 | CHANGED | rc=0 >> 17:29:20 up 1:16, 2 users, load average: 0.00, 0.01, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.66.1 16:18 16:08 0.45s 0.45s -bash root pts/1 liang-03 17:29 2.00s 2.21s 0.14s w [root@liang-03 ~]# ansible liang-04 -m shell -a 'w' liang-04 | CHANGED | rc=0 >> 17:29:58 up 1:16, 2 users, load average: 0.00, 0.01, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.66.1 16:18 16:46 0.45s 0.45s -bash root pts/1 liang-03 17:29 0.00s 0.24s 0.01s w
ansible拷贝文件或目录
拷贝文件:
ansible liang-04 -m copy -a "src=/etc/ansible dest=/tmp/ansibletest owner=root group=root mode=0755"
注意:源目录会放到目标目录下面去,如果目标指定的目录不存在,它会自动创建。如果拷贝的是文件,dest指定的名字和源如果不同,并且它不是已经存在的目录,相当于拷贝过去后又重命名。但相反,如果desc是目标机器上已经存在的目录,则会直接把文件拷贝到该目录下面。
[root@liang-03 ~]# ansible liang-04 -m copy -a "src=/etc/ansible dest=/tmp/ansible_test owner=root group=root mode=0755" liang-04 | CHANGED => { "changed": true, "dest": "/tmp/ansible_test/", "src": "/etc/ansible" } [root@liang-03 ~]#
拷贝文件:
ansible testhost -m copy -a "src=/etc/passwd dest=/tmp/123.txt"
注意:这里的 /tmp/123.txt 和源机器上的 /etc/passwd 是一致的,但如果跟的是目录,则会在该目录下创建 passwd 文件。
[root@liang-03 ~]# ansible liang-04 -m copy -a "src=/etc/passwd dest=/tmp owner=root group=root mode=0755" liang-04 | CHANGED => { "changed": true, "checksum": "7106394293cad76cf35b09b29e778a014427dcd9", "dest": "/tmp/passwd", "gid": 0, "group": "root", "md5sum": "61facab2a5061e35af5aa73fac80f7eb", "mode": "0755", "owner": "root", "size": 1419, "src": "/root/.ansible/tmp/ansible-tmp-1551692953.86-150166330676828/source", "state": "file", "uid": 0 } [root@liang-03 ~]# ansible liang-04 -m copy -a "src=/etc/passwd dest=/tmp/123.txt owner=root group=root mode=0755" liang-04 | CHANGED => { "changed": true, "checksum": "7106394293cad76cf35b09b29e778a014427dcd9", "dest": "/tmp/123.txt", "gid": 0, "group": "root", "md5sum": "61facab2a5061e35af5aa73fac80f7eb", "mode": "0755", "owner": "root", "size": 1419, "src": "/root/.ansible/tmp/ansible-tmp-1551692976.52-53140664226689/source", "state": "file", "uid": 0 } [root@liang-03 ~]#
ansible远程执行脚本
创建shell脚本:
vim /tmp/test.sh //加入内容 #!/bin/bash echo `date` > /tmp/ansible_test.txt
然后把该脚本分发到各个机器上:
ansible testhost -m copy -a "src=/tmp/test.sh dest=/tmp/1.sh mode=0755"
最后是批量执行该shell脚本:
[root@liang-03 ~]# ansible testhost -m shell -a "/tmp/1.sh" liang-04 | CHANGED | rc=0 >> 127.0.0.1 | CHANGED | rc=0 >> [root@liang-03 ~]# cat /tmp/ansible_test.txt Mon Mar 4 18:01:09 CST 2019 [root@liang-03 ~]#
shell 模块还支持远程执行命令并且带管道,command 则不支持。
[root@liang-03 ~]# ansible testhost -m command -a "cat /etc/passwd |wc -l" 127.0.0.1 | FAILED | rc=1 >> cat: invalid option -- 'l' Try 'cat --help' for more information.non-zero return code liang-04 | FAILED | rc=1 >> cat: invalid option -- 'l' Try 'cat --help' for more information.non-zero return code [root@liang-03 ~]# ansible testhost -m shell -a "cat /etc/passwd |wc -l" 127.0.0.1 | CHANGED | rc=0 >> 29 liang-04 | CHANGED | rc=0 >> 29 [root@liang-03 ~]#
ansible管理任务计划
命令格式:
ansible liang-04 -m cron -a "name='test cron' job='/bin/touch /tmp/1212.txt' weekday=6"
时间格式同样为:分(minute)、时(hour)、日(day)、月(month)、周(weekday),不写默认为 * 。
[root@liang-03 ~]# ansible liang-04 -m cron -a "name='test cron' job='/bin/touch /tmp/111.txt' minute=20 hour=10 weekday=6" liang-04 | CHANGED => { "changed": true, "envs": [], "jobs": [ "test cron" ] } [root@liang-03 ~]#
在 liang-04 上:
[root@liang-04 ~]# crontab -l #Ansible: test cron 20 10 * * 6 /bin/touch /tmp/111.txt [root@liang-04 ~]#
若要删除该 cron,只需要加一个字段 state=absent
[root@liang-03 ~]# ansible liang-04 -m cron -a "name='test cron' state=absent" liang-04 | CHANGED => { "changed": true, "envs": [], "jobs": [] } [root@liang-03 ~]#
ansible安装包和管理服务
安装包:在 name 后面还可以加上 state=installed/removed
[root@liang-03 ~]# ansible liang-04 -m yum -a "name=httpd" liang-04 | CHANGED => { "ansible_facts": { "pkg_mgr": "yum" }, "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * epel: mirrors.tuna.tsinghua.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-88.el7.centos will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n httpd x86_64 2.4.6-88.el7.centos base 2.7 M\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 2.7 M\nInstalled size: 9.4 M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : httpd-2.4.6-88.el7.centos.x86_64 1/1 \n Verifying : httpd-2.4.6-88.el7.centos.x86_64 1/1 \n\nInstalled:\n httpd.x86_64 0:2.4.6-88.el7.centos \n\nComplete!\n" ] } [root@liang-03 ~]#
启动服务:这里的 name 是 centos 系统里的服务名,可以通过 chkconfig --list 查到。
ansible testhost -m service -a "name=httpd state=started enabled=yes"
[root@liang-03 ~]# ansible liang-04 -m service -a "name=httpd state=started enabled=no" liang-04 | CHANGED => { "changed": true, "enabled": false, "name": "httpd", "state": "started", "status": { "ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", "After": "network.target nss-lookup.target basic.target systemd-journald.socket remote-fs.target system.slice tmp.mount -.mount", "AllowIsolate": "no", "AmbientCapabilities": "0", "AssertResult": "no", "AssertTimestampMonotonic": "0", "Before": "shutdown.target", "BlockIOAccounting": "no", "BlockIOWeight": "18446744073709551615", "CPUAccounting": "no", "CPUQuotaPerSecUSec": "infinity", "CPUSchedulingPolicy": "0", "CPUSchedulingPriority": "0", "CPUSchedulingResetOnFork": "no", "CPUShares": "18446744073709551615",
ansible 文档的使用
ansible-doc -l 列出所有的模块
ansible-doc cron 查看指定模块的文档
ansible playbook
相当于把模块写入到配置文件里面,例:
vi /etc/ansible/test.yml //加入如下内容:
--- - hosts: liang-04 remote_user: root tasks: - name: test_playbook shell: touch /tmp/lishiming.txt
说明:第一行需要有三个杠,hosts参数指定了对哪些主机进行参作,如果是多台机器可以用逗号作为分隔,也可以使用主机组,在/etc/ansible/hosts里定义;
user参数指定了使用什么用户登录远程主机操作;
tasks指定了一个任务,其下面的name参数同样是对任务的描述,在执行过程中会打印出来,shell是ansible模块名字
[root@liang-03 ansible]# ansible-playbook test.yml PLAY [liang-04] ********************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************** ok: [liang-04] TASK [test_playbook] **************************************************************************************************** [WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [liang-04] PLAY RECAP ************************************************************************************************************** liang-04 : ok=2 changed=1 unreachable=0 failed=0
playbook里的变量
再来一个创建用户的例子:
vi /etc/ansible/create_user.yml //加入如下内容
--- - name: create_user hosts: liang-04 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 变量的值。
[root@liang-03 ansible]# !ansi ansible-playbook create_user.yml PLAY [create_user] ****************************************************************************************************** TASK [create user] ****************************************************************************************************** changed: [liang-04] PLAY RECAP ************************************************************************************************************** liang-04 : ok=1 changed=1 unreachable=0 failed=0
playbook循环
vi /etc/ansible/while.yml //加入如下内容
---
- hosts: testhost
user: root
tasks:
- name: change mode for files
file: path=/tmp/{{ item }} mode=600
with_items:
- 1.txt
- 2.txt
- 3.txt
说明: with_items为循环的对象
执行 ansible-playbook while.yml
[root@liang-03 ansible]# ansible-playbook while.yml PLAY [liang-04] ********************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************** ok: [liang-04] TASK [change mode for files] ******************************************************************************************** changed: [liang-04] => (item=1.txt) changed: [liang-04] => (item=2.txt) changed: [liang-04] => (item=3.txt) PLAY RECAP ************************************************************************************************************** liang-04 : ok=2 changed=1 unreachable=0 failed=0 [root@liang-03 ansible]#
playbook中的条件判断
vi /etc/ansible/when.yml //加入如下内容
--- - hosts: testhost user: root gather_facts: True #收集hosts信息,来实现下面when的判断 tasks: - name: use when shell: touch /tmp/when.txt when: ansible_ens33.ipv4.address == "192.168.66.139“
说明:ansible aming-02 -m setup 可以查看到所有的facter信息
[root@liang-03 ansible]# ansible-playbook when.yml PLAY [testhost] ********************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************** ok: [127.0.0.1] ok: [liang-04] TASK [use when] ********************************************************************************************************* skipping: [liang-04] [WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [127.0.0.1] PLAY RECAP ************************************************************************************************************** 127.0.0.1 : ok=2 changed=1 unreachable=0 failed=0 liang-04 : ok=1 changed=0 unreachable=0 failed=0
playbook中的handlers
执行tasks之后,服务器发生变化之后要执行的一些操作,比如我们修改了配置文件后,需要重启一下服务。
vi /etc/ansible/handlers.yml//加入如下内容:
--- - name: handlers test hosts: liang-04 user: root tasks: - name: copy file copy: src=/etc/passwd dest=/tmp/aaa.txt notify: test handlers handlers: - name: test handlers shell: echo "111111" >> /tmp/aaa.txt
说明,只有copy模块真正执行成功后,才会去调用下面的 handlers 相关的操作。也就是说如果1.txt 和 2.txt 内容是一样的,并不会去执行 handlers 里面的shell相关命令。 这种比较适合配置文件发生更改后,重启服务的操作。
[root@liang-03 ansible]# ansible-playbook handlers.yml PLAY [handlers test] **************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************** ok: [liang-04] TASK [copy file] ******************************************************************************************************** changed: [liang-04] RUNNING HANDLER [test handlers] ***************************************************************************************** changed: [liang-04] PLAY RECAP ************************************************************************************************************** liang-04 : ok=3 changed=2 unreachable=0 failed=0 [root@liang-03 ansible]#
用playbook安装nginx
思路:先在一台机器上编译安装好nginx、打包,然后再用ansible去下发
准备工作:
cd /etc/ansible 进入ansible配置文件目录
mkdir nginx_install 创建一个nginx_install的目录,方便管理
cd nginx_install
mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}
[root@liang-03 ~]# cd /etc/ansible/ [root@liang-03 ansible]# mkdir nginx_install [root@liang-03 ansible]# cd nginx_install/ [root@liang-03 nginx_install]# mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars} [root@liang-03 nginx_install]#
说明:roles 目录下有两个角色,common 为一些准备操作,install为安装 nginx 的操作。每个角色下面又有几个目录,handlers 下面是当发生改变时要执行的操作,通常用在配置文件发生改变,重启服务。files 为安装时用到的一些文件,meta 为说明信息,说明角色依赖等信息,tasks 里面是核心的配置文件,templates 通常存一些配置文件,启动脚本等模板文件,vars 下为定义的变量。
需要事先准备好安装用到的文件,具体如下:
在一台机器上事先编译安装好 nginx,配置好启动脚本,配置好配置文件
安装好后,我们需要把 nginx 目录打包,并放到 /etc/ansible/nginx_install/roles/install/files/ 下面,名字为 nginx.tar.gz
启动脚本、配置文件都要放到 /etc/ansible/nginx_install/roles/install/templates 下面
playbook脚本:
定义 common 的 tasks:nginx 安装需要的依赖包。
vim ./common/tasks/main.yml //内容如下
- name: Install initializtion require software yum: name="zlib-devel,pcre-devel" state=installed
定义变量:vi .install/var/main.yml
nginx_user: www nginx_port: 80 nginx_basedir: /usr/local/nginx
拷贝nginx目录文件、配置文件、启动脚本到目标机器: vi .install/var/main.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
创建用户、启动服务、删除压缩包:vim /etc/ansible/nginx_install/roles/install/tasks/install.yml
- name: Create Nginx User user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin - name: Start Nginx Service shell: /etc/init.d/nginx start - name: Add Boot Start Nginx Service shell: chkconfig --level 345 nginx on - name: Delete Nginx compression files shell: rm -rf /tmp/nginx.tar.gz
创建main.yml 调用copy.yml和install.yml
vim /etc/ansible/nginx_install/roles/install/tasks/main.yml
- include: copy.yml - include: install.yml
至此,common和install 完成,定义 ansible 入口文件:
--- - hosts: liang-04 remote_user: root gather_facts: True roles: - common - install
执行:ansible-playbook /etc/ansible/nginx_install/install.yml
[root@liang-03 install]# ansible-playbook /etc/ansible/nginx_install/install.yml PLAY [liang-04] ********************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************** ok: [liang-04] TASK [common : Install initializtion require software] ****************************************************************** changed: [liang-04] TASK [install : Copy Nginx Software] ************************************************************************************ ok: [liang-04] TASK [install : Uncompression Nginx Software] *************************************************************************** [WARNING]: Consider using the unarchive module rather than running 'tar'. If you need to use command because unarchive is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [liang-04] TASK [install : Copy Nginx Start Script] ******************************************************************************** ok: [liang-04] TASK [install : Copy Nginx Config] ************************************************************************************** changed: [liang-04] TASK [install : Create Nginx User] ************************************************************************************** changed: [liang-04] TASK [install : Start Nginx Service] ************************************************************************************ changed: [liang-04] TASK [install : Add Boot Start Nginx Service] *************************************************************************** changed: [liang-04] TASK [install : Delete Nginx compression files] ************************************************************************* [WARNING]: Consider using the file module with state=absent rather than running 'rm'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [liang-04] PLAY RECAP ************************************************************************************************************** liang-04 : ok=10 changed=7 unreachable=0 failed=0
playbook管理配置文件
生产环境中大多时候是需要管理配置文件的,安装软件包只是在初始化环境的时候用一下。下面我们来写个管理nginx配置文件的playbook。
准备工作:
mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}
其中new为更新时用到的,old为回滚时用到的,files下面为nginx.conf和vhosts目录,handlers为重启nginx服务的命令。
关于回滚,需要在执行playbook之前先备份一下旧的配置,所以对于老配置文件的管理一定要严格,千万不能随便去修改线上机器的配置,并且要保证new/files下面的配置和线上的配置一致。
先把nginx.conf和vhosts目录放到files目录下面:
cd / usr/local/nginx/conf/
cp -r nginx.conf vhost /etc/ansible/nginx_config/roles/new/files/
vim /etc/ansible/nginx_config/roles/new/vars/main.yml //定义变量
nginx_basedir: /usr/local/nginx
vim /etc/ansible/nginx_config/roles/new/handlers/main.yml //定义重新加载nginx服务
- name: restart nginx shell: /etc/init.d/nginx reload
vim /etc/ansible/nginx_config/roles/new/tasks/main.yml //这是核心的任务
- name: copy conf file copy: src={{ item.src }} dest={{ nginx_basedir }}/{{ item.dest }} backup=yes owner=root group=root mode=0644 with_items: - { src: nginx.conf, dest: conf/nginx.conf } - { src: vhosts, dest: conf/ } notify: restart nginx
vim /etc/ansible/nginx_config/update.yml // 最后是定义总入口配置
--- - hosts: testhost user: root roles: - new
执行: ansible-playbook /etc/ansible/nginx_config/update.yml
[root@liang-03 conf]# !ansi ansible-playbook /etc/ansible/nginx_config/update.yml PLAY [liang-04] ********************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************** ok: [liang-04] TASK [new : copy conf file] ********************************************************************************************* ok: [liang-04] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) changed: [liang-04] => (item={u'dest': u'conf/', u'src': u'vhost'}) RUNNING HANDLER [new : restart nginx] *********************************************************************************** changed: [liang-04] PLAY RECAP ************************************************************************************************************** liang-04 : ok=3 changed=2 unreachable=0 failed=0 [root@liang-03 conf]#
回滚:
而回滚的backup.yml对应的roles为old
rsync -av /etc/ansible/nginx_config/roles/new/ /etc/ansible/nginx_config/roles/old/
先拷贝修改之前的配置到old
回滚操作就是把旧的配置覆盖,然后重新加载nginx服务, 每次改动 nginx 配置文件之前先备份到 old 里,对应目录为/etc/ansible/nginx_config/roles/old/files
vim /etc/ansible/nginx_config/rollback.yml // 最后是定义总入口配置
--- - hosts: liang-04 user: root roles: - old