ansible
1.ansible是什么?
ansible是一个基于Python开发的自动化运维工具 !
其功能实现基于SSH远程连接服务!
ansible可以实现批量系统配置、批量软件部署、批量文件拷贝、批量运行命令等功能
2.ansible软件特性
不需要单独安装客户端(no agents),基于系统自带的sshd服务,sshd就相当于ansible的客户端。
不需要服务端(no servers)。
需要依靠大量的模块实现批量管理。?
配置文件/etc/ansible/ansible.cfg,不用配置
3.ansible软件执行结果
输出内容显示绿色:表示执行成功,当没有任何改变
输出内容显示黄色:表示执行成功,但对被管理主机进行了改变
输出内容显示红色:表示执行失败
ansible模块
command模块
command :作为ansible的默认模块,可以允许远程主机范围内的所有shell命令。
script模块
功能:在远程主机上执行主控端的脚本,相当于scp+shell组合。
shell模块
功能:执行远程主机的shell脚本文件
copy模块
功能: 实现主控端向目标主机copy文件。
stat模块
功能: 获取远程文件的状态信息,包括atime,ctime,mtime,md5,uid,gid等信息。
yum模块
功能: 安装软件包。
cron模块
功能:远程主机crontab配置
template模块
基于模板方式生成一个文件复制到远程主机(template使用Jinjia2格式作为文件模版,进行文档内变量的替换的模块。它的每次使用都会被ansible标记为”changed”状态。)
安装部署ansible
1.安装
[root@server1 ~]# cd ansible/
[root@server1 ansible]# ls
ansible-2.7.8-1.el7.noarch.rpm
ansible-tower-setup-bundle-3.4.2-1.el7.tar.gz
libtomcrypt-1.17-25.el7.x86_64.rpm
libtommath-0.42.0-5.el7.x86_64.rpm
python2-crypto-2.6.1-13.el7.x86_64.rpm
python2-jmespath-0.9.0-1.el7.noarch.rpm
python-httplib2-0.9.2-0.1.el7.noarch.rpm
python-keyczar-0.71c-2.el7.noarch.rpm
python-paramiko-2.1.1-0.9.el7.noarch.rpm
roles
sshpass-1.06-1.el7.x86_64.rpm
[root@server1 ansible]# yum install -y *.rpm
2.创建devops用户,设置ansible服务的组和组里的主机
[root@server1 ansible]# cd /etc/ansible/
[root@server1 ansible]# ls
ansible.cfg hosts roles
[root@server1 ansible]# useradd devops
[root@server1 ansible]# passwd devops
Changing password for user devops.
New password:
BAD PASSWORD: The password is shorter than 8 characters
Retype new password:
passwd: all authentication tokens updated successfully.
[root@server1 ansible]# su - devops
[devops@server1 ~]$ mkdir ansible
[devops@server1 ~]$ cd ansible/
[devops@server1 ansible]$ vim ansible.cfg
[devops@server1 ansible]$ cat ansible.cfg
[defaults]
inventory = inventory
[devops@server1 ansible]$ vim inventory
[devops@server1 ansible]$ cat inventory
[test] ##定义主机组
server2 ##主机名
[db]
server3
[webservers:children]
test
db
3.制作免密连接
server2 server3
[root@server2 ~]# useradd devops
[root@server2 ~]# passwd devops
server1
[devops@server1 ansible]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/devops/.ssh/id_rsa):
Created directory '/home/devops/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/devops/.ssh/id_rsa.
Your public key has been saved in /home/devops/.ssh/id_rsa.pub.
The key fingerprint is:
5c:10:24:a3:75:12:6a:18:7d:ff:0e:29:4e:e8:9e:65 devops@server1
The key's randomart image is:
+--[ RSA 2048]----+
| .. *o=. |
| o.+.= . |
| . +. . . |
| . ... |
| . So |
| . o o . |
| . oE. o |
| .+. . |
| .o |
+-----------------+
[devops@server1 ansible]$ ssh-copy-id server1
[devops@server1 ansible]$ ssh-copy-id server2
[devops@server1 ansible]$ ssh-copy-id server3
4.免密连接测试
[devops@server1 ansible]$ ansible all --list-hosts
hosts (2):
server3
server2
[devops@server1 ansible]$ ansible all -m ping
server2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
server3 | SUCCESS => {
"changed": false,
"ping": "pong"
}
[devops@server1 ansible]$ ansible all -m setup ##查看主机组里面所有主机的配置信息
5.使用copy模块
test表示的是组,在inventory里写了,所以操作的是server2,-m 表示的指定模块 -a指定后面的动作
[devops@server1 ansible]$ ansible test -m copy -a 'src=/etc/passwd dest=/tmp/passwd'
server2 | CHANGED => {
"changed": true,
"checksum": "22dc9c5c3e860a79ca8a2328cd2fb7ab5ebba3d1",
"dest": "/tmp/passwd",
"gid": 1000,
"group": "devops",
"md5sum": "0471aa190bc587c20bffa116275b43c2",
"mode": "0664",
"owner": "devops",
"size": 1003,
"src": "/home/devops/.ansible/tmp/ansible-tmp-1560144902.87-50483023420876/source",
"state": "file",
"uid": 1000
}
server2查看
[root@server2 ~]# su - devops
Last login: Mon Jun 10 13:35:47 CST 2019 on pts/0
[devops@server2 ~]$ ll /tmp/passwd
-rw-rw-r-- 1 devops devops 1003 Jun 10 13:35 /tmp/passwd
[devops@server2 ~]$ cat /tmp/passwd
server1
[devops@server1 ansible]$ ansible test -a 'ls -l /tmp/passwd'
server2 | CHANGED | rc=0 >>
-rw-rw-r-- 1 devops devops 1003 Jun 10 13:35 /tmp/passwd
[devops@server1 ansible]$ ansible test -a 'ls /tmp/passwd'
server2 | CHANGED | rc=0 >>
/tmp/passwd
##使用file模块
[devops@server1 ansible]$ ansible test -m file -a 'dest=/tmp/passwd mode=600'
server2 | CHANGED => {
"changed": true,
"gid": 1000,
"group": "devops",
"mode": "0600",
"owner": "devops",
"path": "/tmp/passwd",
"size": 1003,
"state": "file",
"uid": 1000
}
[devops@server1 ansible]$ ansible test -a 'ls -l /tmp/passwd'
server2 | CHANGED | rc=0 >>
-rw------- 1 devops devops 1003 Jun 10 13:35 /tmp/passwd
6.添加用户授权,让普通用户能够执行超级用户的一些权限
server2 server3
[root@server3 ~]# vim /etc/sudoers
devops ALL=(ALL) NOPASSWD: ALL
ansible自动安装httpd
1.使用yum模块,给test组里的主机安装httpd
[devops@server1 ansible]$ ansible test -m yum -a 'name=httpd state=present' -b
[devops@server1 ansible]$ ansible test -a 'rpm -q httpd' ##查看
2.取消-b参数
[devops@server1 ansible]$ vim ansible.cfg
[devops@server1 ansible]$ cat ansible.cfg
[defaults]
inventory = inventory
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[devops@server1 ansible]$ ansible test -m yum -a 'name=httpd state=present'
3.给webservers包含的组的所有主机安装httpd
[devops@server1 ansible]$ ansible webservers -m yum -a 'name=httpd state=present'
4.卸载test组里所有主机的httpd服务
[devops@server1 ansible]$ ansible test -m yum -a 'name=httpd state=absent'
[devops@server1 ansible]$ ansible test -a 'rpm -q htppd'
5.开启服务
[devops@server1 ansible]$ curl server3
curl: (7) Failed connect to server3:80; Connection refused
[devops@server1 ansible]$ ansible db -m service -a 'name=httpd state=started'
[devops@server1 ansible]$ curl server3
6.发布默认发布页
[devops@server1 ansible]$ ansible db -m copy -a 'content="www.dzh.org\n" dest=/var/www/html/index.html'
server3 | CHANGED => {
"changed": true,
"checksum": "9e463c3c1e487f724201c2062c64f06df14357df",
"dest": "/var/www/html/index.html",
"gid": 0,
"group": "root",
"md5sum": "1f29c821a7f609fc4fc2cc0e65cfbba3",
"mode": "0644",
"owner": "root",
"size": 12,
"src": "/home/devops/.ansible/tmp/ansible-tmp-1560253589.01-78653058950786/source",
"state": "file",
"uid": 0
}
[devops@server1 ansible]$ curl server3
www.dzh.org
7.开启防火墙并设置火墙允许httpd服务通过
[devops@server1 ansible]$ ansible db -m service -a 'name=firewalld state=started enabled=true'
[devops@server1 ansible]$ curl server3
curl: (7) Failed connect to server3:80; No route to host
[devops@server1 ansible]$ ansible db -m firewalld -a 'service=http state=enabled permanent=yes immediate=yes'
server3 | CHANGED => {
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed service http to enabled"
}
[devops@server1 ansible]$ curl server3
www.dzh.org
8.设置tab键的空格数目
[devops@server1 ansible]# cat ~/.vimrc
autocmd filetype yaml setlocal ai ts=2 sw=2 et
自动部署httpd服务
1.创建存放httpd.conf的目录
[devops@server1 ansible]$ mkdir files
[devops@server1 ansible]$ cd files/
[devops@server1 files]$ scp server3:/etc/httpd/conf/httpd.conf .
httpd.conf
2.编写playbook.yml
[devops@server1 ansible]$ vim playbook.yml
---
# deploy apache
- hosts: webservers
tasks:
- name: install httpd
yum:
name: httpd
state: latest
- name: create index.html
copy:
content: "www.westos.org\n"
dest: /var/www/html/index.html
- name: configure httpd
copy:
src: files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: 644
notify: restart httpd ##设置触发器,如果更改了httpd.conf就触发
- name: start httpd
service:
name: httpd
state: started
enabled: true
handlers: ##name一定要和notify后面的一致
- name: restart httpd
service:
name: httpd
state: restarted
3.执行playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml --syntax-check #检查语法
playbook: playbook.yml
执行
[devops@server1 ansible]$ ansible-playbook playbook.yml
4.测试
[devops@server1 ansible]$ curl server2
www.dzh.org
[devops@server1 ansible]$ curl server3
www.dzh.org
5.更改配置文件,将端口设置成8080再测试
[devops@server1 ansible]$ md5sum files/httpd.conf
f5e7449c0f17bc856e86011cb5d152ba files/httpd.conf
[devops@server1 ansible]$ vim files/httpd.conf
Listen 8080
[devops@server1 ansible]$ md5sum files/httpd.conf
04e9239e7bd5d5b9b85864226d60eee5 files/httpd.conf
[devops@server1 ansible]$ ansible-playbook playbook.yml
[devops@server2 ~]$ netstat -ntlp
(No info could be read for "-p": geteuid()=1000 but you should be root.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN -
tcp6 0 0 :::8080 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:25 :::* LISTEN -
6.添加防火墙
[devops@server1 ansible]$ vim playbook.yml
- name: start firewalld ##开启火墙
service:
name: firewalld
state: started
enabled: true
- name: configure firewalld ##允许http服务可以通过火墙
firewalld:
service: http
state: enabled
permanent: yes
immediate: yes
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
[devops@server1 ansible]$ ansible-playbook playbook.yml --syntax-check
[devops@server1 ansible]$ ansible-playbook playbook.yml ##注意files/httpd.conf端口要改回80
[devops@server1 ansible]$ curl server2
www.dzh.org
[devops@server1 ansible]$ curl server3
www.dzh.org
且server2 server3的火墙都开启了
[devops@server2 ~]$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2019-06-11 20:26:44 CST; 2min 21s ago
Docs: man:firewalld(1)
Main PID: 4690 (firewalld)
CGroup: /system.slice/firewalld.service
└─4690 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
7.变量名–主机名
[devops@server1 ansible]$ vim playbook.yml
- name: create index.html
copy:
content: "{{ ansible_facts['hostname'] }}\n" ##或者ansible_facts.hostname
dest: /var/www/html/index.html
[devops@server1 ansible]$ ansible-playbook playbook.yml
[devops@server1 ansible]$ curl server2
server2
[devops@server1 ansible]$ curl server3
server3
8.变量名–ip
[devops@server1 ansible]$ ansible webservers -m setup | less ##查看信息
"ansible_default_ipv4": {
"address": "172.25.68.2",
"alias": "eth0",
"broadcast": "172.25.68.255",
"gateway": "172.25.68.250",
"interface": "eth0",
"macaddress": "52:54:00:1d:0e:a6",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "172.25.68.0",
"type": "ether"
[devops@server1 ansible]$ vim playbook.yml
- name: create index.html
copy:
content: "{{ ansible_facts['hostname'] }} {{ ansible_facts['default_ipv4']['address'] }}\n"
dest: /var/www/html/index.html
[devops@server1 ansible]$ ansible-playbook playbook.yml
[devops@server1 ansible]$ curl server2
server2 172.25.68.2
[devops@server1 ansible]$ curl server3
server3 172.25.68.3
9.标记–只执行那一个模块
[devops@server1 ansible]$ vim playbook.yml
- name: create index.html
copy:
content: "{{ ansible_facts['hostname'] }} {{ ansible_facts['default_ipv4']['address'] }}\n"
dest: /var/www/html/index.html
tags: one
[devops@server1 ansible]$ ansible-playbook playbook.yml -t one
模板j2
1.使用模板模块
[devops@server1 ansible]$ cd files/
[devops@server1 files]$ mv httpd.conf httpd.conf.j2
[devops@server1 ansible]$ vim playbook.yml
- hosts: webservers
vars:
http_port: 80
- name: configure httpd
template: ##模板模块
src: files/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: 644
notify: restart httpd
[devops@server1 ansible]$ vim files/httpd.conf.j2
Listen {{ http_port }}
[devops@server1 ansible]$ ansible-playbook playbook.yml
2.模板
[devops@server1 ansible]$ mkdir templates
[devops@server1 ansible]$ vim playbook.yml
- name: configure httpd
template:
src: templates/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: 644
notify: restart httpd
[devops@server1 ansible]$ cp files/httpd.conf.j2 templates/
3.使用模板创建包含主机一些信息的文件
[devops@server1 ansible]$ vim hostinfo.yml
---
- hosts: all
tasks:
- name: create infofile
template:
src: templates/info.j2
dest: /mnt/hostinfo
[devops@server1 ansible]$ cd templates/
[devops@server1 templates]$ vim info.j2
主机名: {{ ansible_facts['hostname'] }}
主机IP地址: {{ ansible_facts['default_ipv4']['address'] }}
根分区大小: {{ ansible_facts['devices']['dm-0']['size'] }}
系统内核: {{ ansible_facts['distribution_version'] }}
[devops@server1 ansible]$ ansible-playbook hostinfo.yml --syntax-check
playbook: hostinfo.yml
[devops@server1 ansible]$ ansible-playbook hostinfo.yml
4.测试
[devops@server1 ansible]$ ansible all -a 'ls -l /mnt/hostinfo'
server2 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 90 Jun 11 23:34 /mnt/hostinfo
server3 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 90 Jun 11 23:34 /mnt/hostinfo
[devops@server1 ansible]$ ansible all -a 'cat /mnt/hostinfo'
server3 | CHANGED | rc=0 >>
主机名: server3
主机IP地址: 172.25.68.3
根分区大小: 9.79 GB
系统内核: 7.3
server2 | CHANGED | rc=0 >>
主机名: server2
主机IP地址: 172.25.68.2
根分区大小: 9.79 GB
系统内核: 7.3
指定主机安装
[devops@server1 ansible]$ vim install.yml
---
- hosts: all
tasks:
- name: install pkgs
yum:
name: "{{ item }}"
state: present
when: ansible_facts['hostname'] == 'server2' ##指定server2主机
loop:
- httpd
- mariadb
- php
- php-mysql
- name: install mariadb
yum:
name: mariadb
state: present
when: ansible_facts['hostname'] == 'server3' ##指定server3主机
[devops@server1 ansible]$ ansible-playbook install.yml --syntax-check
playbook: install.yml
[devops@server1 ansible]$ ansible-playbook install.yml
循环
/etc/hosts
[devops@server1 ansible]$ vim hostinfo.yml
---
- hosts: all
tasks:
# - name: create infofile
# template:
# src: templates/info.j2
# dest: /mnt/hostinfo
- name: create hosts
template:
src: templates/hosts.j2
dest: /etc/hosts
owner: root
group: root
mode: 0644
[devops@server1 ansible]$ vim templates/hosts.j2
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{% for host in groups['webservers'] %} ##循环
{{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }} {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}
[devops@server1 ansible]$ vim inventory
[devops@server1 ansible]$ cat inventory
[test]
server2
server1
[db]
server3
[webservers:children]
test
db
[root@server1 ansible]# vim /etc/sudoers
devops ALL=(ALL) NOPASSWD: ALL
[devops@server1 ansible]$ ansible-playbook hostinfo.yml
[devops@server1 ansible]$ cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.68.3 server3
172.25.68.2 server2
172.25.68.1 server1
批量添加用户
[devops@server1 ansible]$ vim adduser.yml
---
- hosts: all
vars_files:
- vars/userlist.yml
tasks:
- name: create users
user:
name: "{{ item.user }}"
state: present
password: "{{ item.pass }}"
loop: "{{ userlist }}"
[devops@server1 ansible]$ mkdir vars
[devops@server1 ansible]$ cd vars/
[devops@server1 vars]$ vim userlist.yml
[devops@server1 vars]$ ansible-vault encrypt userlist.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[devops@server1 vars]$ cat userlist.yml
$ANSIBLE_VAULT;1.1;AES256
31633137363733316630303239353338313164373462306434363036646233663963663135646565
3332376232656438393332643363663366636466653661350a623234376334356439616337313738
62643231343066306662353365356263646661333738373031326263393561643830333763303430
3533386433626630630a616338653432373832393030363166653765303362303437633938383662
33303231303937316664373435643731643535666230366638393839323835343266333231646135
37363432313737353565386138326264633430333466346639616537303634373038666234393564
66313263353166623733306661613461343034353365363630326638396339623532313533633632
63383662343462336564366438656339663635643334316437363832306566346230643332366439
6661
[devops@server1 vars]$ ansible-vault view userlist.yml ##此时需要密码才能查看
Vault password:
---
userlist:
- user: user1
pass: westos
- user: user2
pass: redhat
[devops@server1 ansible]$ ansible-playbook adduser.yml --ask-vault-pass
Vault password:
PLAY [all] *****************************************************************************
TASK [Gathering Facts] *****************************************************************
ok: [server3]
ok: [server2]
TASK [create users] ********************************************************************
changed: [server3] => (item={u'user': u'user1', u'pass': u'westos'})
changed: [server2] => (item={u'user': u'user1', u'pass': u'westos'})
changed: [server3] => (item={u'user': u'user2', u'pass': u'redhat'})
[WARNING]: The input password appears not to have been hashed. The 'password' argument
must be encrypted for this module to work properly.
changed: [server2] => (item={u'user': u'user2', u'pass': u'redhat'})
PLAY RECAP *****************************************************************************
server2 : ok=2 changed=1 unreachable=0 failed=0
server3 : ok=2 changed=1 unreachable=0 failed=0
[root@server2 ~]# cat /etc/shadow ##密码还是明文
user1:westos:18060:0:99999:7:::
user2:redhat:18060:0:99999:7:::
[devops@server1 ansible]$ vim adduser.yml
---
- hosts: all
vars_files:
- vars/userlist.yml
tasks:
- name: create users
user:
name: "{{ item.user }}"
state: present
password: "{{ item.pass | password_hash('sha512','mysecretslat') }}"
loop: "{{ userlist }}"
[devops@server1 ansible]$ ansible-playbook adduser.yml --ask-vault-pass
Vault password:
PLAY [all] **********************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [server2]
ok: [server3]
TASK [create users] *************************************************************************************************
changed: [server2] => (item={u'user': u'user1', u'pass': u'westos'})
changed: [server3] => (item={u'user': u'user1', u'pass': u'westos'})
changed: [server3] => (item={u'user': u'user2', u'pass': u'redhat'})
changed: [server2] => (item={u'user': u'user2', u'pass': u'redhat'})
PLAY RECAP **********************************************************************************************************
server2 : ok=2 changed=1 unreachable=0 failed=0
server3 : ok=2 changed=1 unreachable=0 failed=0
[root@server2 ~]# cat /etc/shadow ##密码变成密文
user1:$6$mysecretslat$9BHrNJOamAqTfgPjfgMF67trp.8CVN4CXq/.btQ2lNTq8YNCGZKRBzLiShaGDT.xtXqU.TE/rMPxyBNbnSsjG1:18060:0:99999:7:::
user2:$6$mysecretslat$u1GP1.iBm2lsLHWzzqgSMx7ivazVxB3l3iSSgTkAN.B.PBD1NVvbwzzECjkErIeHpv9jfpczEFTgdUy.xXLyl0:18060:0:99999:7:::
删除用户
状态改为absent
[devops@server1 ansible]$ cat adduser.yml
---
- hosts: all
vars_files:
- vars/userlist.yml
tasks:
- name: create users
user:
name: "{{ item }}"
state: absent
password: westos
loop: "{{ userlist }}"