一、基本概念
1.什么是ansible?
ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于 paramiko 开发的,并且基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远
程主机通讯的。ansible目前已经已经被红帽官方收购,是自动化运维工具中大家认可度最高的,并且上手容易,学习简单。是每位运维工程师必须掌握的技能之一。
2.ansible 任务执行
ansible 任务执行模式
Ansible 系统由控制主机对被管节点的操作方式可分为两类,即adhoc和playbook:
-
ad-hoc模式(点对点模式)
使用单个模块,支持批量执行单条命令。ad-hoc 命令是一种可以快速输入的命令,而且不需要保存起来的命令。就相当于bash中的一句话shell。 -
playbook模式(剧本模式)
是Ansible主要管理方式,也是Ansible功能强大的关键所在。playbook通过多个task集合完成一类功能,如Web服务的安装部署、数据库服务器的批量备份等。可以简单地把playbook理解为通过组合多条ad-hoc操作的配置文件。
二、ansible安装
1.获得资源包安装ansible(此处会有依赖性)
[root@server1 ~]# ls
ansible
[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.查看版本
[root@server1 ansible]# ansible --version
3.建立用户,(ansible不推荐用root进行管理)
[root@server1 ansible]# useradd devops
[root@server1 ansible]# cd /etc/ansible/ #ansible的配置文件目录
[root@server1 ansible]# ls
ansible.cfg hosts roles
在server2、server3、server4上也建立用户,修改密码
[root@server2 ~]# useradd devops
[root@server2 ~]# echo westos | passwd --stdin devops
[root@server3 ~]# useradd devops
[root@server3 ~]# echo westos | passwd --stdin devops
[root@server4 ~]# useradd devops
[root@server4 ~]# echo westos | passwd --stdin devops
4.切换到普通用户,建立新的ansible目录(方便以后修改配置,针对当前用户的)
root@server1 ansible]# su - devops
[devops@server1 ~]$ ls
[devops@server1 ~]$ mkdir ansible
5.编写当前用户的inventory,编写配置文件(读取顺序是先读取当前的配置文件)
[devops@server1 ansible]$ vim inventory
[dev]
server2
[test]
server3
[prod]
server4
[webservers:children]
dev
test
prod
[devops@server1 ansible]$ vim ansible.cfg
[defaults]
inventory=inventory
测试:
[devops@server1 ansible]$ ansible-inventory --list all#查看组的定义(uground表示默认组)
[devops@server1 ansible]$ ansible dev --list-host #显示定义组下的主机
5.测试主机之间网络的连通性
[devops@server1 ansible]$ cat ansible.cfg
[defaults]
inventory=inventory
host_key_checking=False #不要key
[devops@server1 ansible]$ ansible all -m ping
[devops@server1 ansible]$ ansible all -m ping -k #此处输入的密码是普通用户的密码
此时在进行,则成功
[devops@server1 ansible]$ ansible all -m ping
测试:此时可在中控机上查看各目标主机的信息
[devops@server1 ansible]$ ansible all -a “hostname”
[devops@server1 ansible]$ ansible all -m shell -a “df -h”
6.配置免密连接
[devops@server1 ansible]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/devops/.ssh/id_rsa):
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:
cc:c5:66:64:22:60:b2:97:eb:f6:ec:e5:19:be:e2:88 devops@server1
The key's randomart image is:
+--[ RSA 2048]----+
| . o.. . o |
| + . . = |
| . o = |
| . . o + |
| . S |
| . |
| o o |
| o +.+ o |
| E .o=.=. |
+-----------------+
[devops@server1 ~]$ l.
. .. .ansible .bash_logout .bash_profile .bashrc .ssh .viminfo
[devops@server1 ~]$ ssh-copy-id server2
[devops@server1 ~]$ ssh-copy-id server3
[devops@server1 ~]$ ssh-copy-id server4
三、ad-hoc管理
1.安装httpd服务,并测试
帮助文档查看:
[devops@server1 ansible]$ ansible-doc -l #查看模块
[devops@server1 ansible]$ ansible-doc -l | grep ssh
[devops@server1 ansible]$ ansible-doc yum #查看服务使用
安装httpd服务,但是会出现报错
[devops@server1 ansible]$ ansible dev -m yum -a "name=httpd state=present" -b
注意:报错是因为目标主机的普通用户需要密码切换到超户,进行设置
[root@server2 ~]# vim /etc/sudoers
[root@server3 ~]# vim /etc/sudoers
[root@server4 ~]# vim /etc/sudoers
再次进行安装
[devops@server1 ansible]$ ansible dev -m yum -a “name=httpd state=present” -b
在server2上查看是否已经安装
[root@server2 ~]# rpm -q httpd
httpd-2.4.6-45.el7.x86_64
2.设置开机自启:
[devops@server1 ansible]$ ansible dev -m service -a "name=httpd state=started enabled=yes" -b
在server2上查看
[root@server2 ~]# netstat -antlp
3.开启防火墙,开机自启
[devops@server1 ansible]$ ansible dev -m service -a "name=firewalld state=started enabled=yes" -b
在server2上查看
[root@server2 ~]# firewall-cmd --list-services
dhcpv6-client ssh
[root@server2 ~]# systemctl status firewalld
4.编写规则,将httpd写进防火墙策略
[devops@server1 ansible]$ ansible dev -m firewalld -a "service=http permanent=yes immediate=yes state=enabled" -b
在server2上查看
[root@server2 ~]# firewall-cmd --list-services
dhcpv6-client ssh http
[root@server2 ~]# iptables -L
[devops@server1 ansible]$ curl server2 #此时查看的是httpd默认发布页
5.写文件(写默认发布页)
[devops@server1 ansible]$ ansible dev -m copy -a 'content="<h1>www.westos.org</h1>\n" dest=/var/www/html/index.html' -b
测试:
[devops@server1 ansible]$ curl server2
不用加-b操作:
[devops@server1 ansible]$ vim /etc/ansible/ansible.cfg #复制信息
[devops@server1 ansible]$ vim ansible.cfg
[defaults]
inventory=inventory
host_key_checking=False
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[devops@server1 ansible]$ ansible dev -m copy -a 'content="<h1>www.westos.org</h1>\n" dest=/var/www/html/index.html'
四、playbook
playbook是严格按照缩进执行的,因此进行定义:
[devops@server1 ~]$ vim .vimrc
autocmd filetype yaml set ai ts=2 sw=2 et ##写table的缩进,yml类型的文件,一个tab键代表两个空格
1.编写通过playbook执行的内容
[devops@server1 ~]$ cd ansible/
[devops@server1 ansible]$ vim playbook.yml
---
- name: apache playbook
hosts: test ##组,写在inventory 文件下,即针对哪些主机
tasks: ##任务
- name: install httpd ##任务简介
yum:
name: httpd
state: present
- name: start httpd
service:
name: httpd
state: started
enabled: true
- name: enabled firewalld
service:
name: firewalld
state: started
enabled: true
- name: configure firewalld
firewalld:
service: http
state: enabled
permanent: true
immediate: true
- name: copy index.html
copy:
content: "<h1>www.westos.org</h1>\n"
dest: /var/www/html/index.html
2.安装http服务
语法检测:
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml #表示语法正确
执行内容,用ansible进行推送
[devops@server1 ansible]$ ansible-playbook playbook.yml
测试:
[devops@server1 ansible]$ curl server3
- 当对httpd配置文件进行修改时,需要重新加载服务
把httpd服务所需的配置文件复制
[devops@server1 ansible]$ mkdir files
[devops@server1 ansible]$ cd files/
[devops@server1 files]$ scp server2:/etc/httpd/conf/httpd.conf .
[devops@server1 files]$ vim httpd.conf #将端口改为8000
添加任务
[devops@server1 ansible]$ vim playbook.yml
[devops@server1 ansible]$ vim playbook.yml
---
- name: apache playbook
hosts: test
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: configure httpd
copy:
src: files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: '0644'
- name: start httpd
service:
name: httpd
state: started
enabled: true
- name: enabled firewalld
service:
name: firewalld
state: started
enabled: true
- name: configure firewalld
firewalld:
service: http
state: enabled
permanent: true
immediate: true
- name: copy index.html
copy:
content: "<h1>www.westos.org</h1>\n"
dest: /var/www/html/index.html
handlers: #触发器(没遇到notify的时候,触发器不会触发)
- name: restart httpd
service:
name: httpd
state: restarted
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
注意:此时,改变一个地方;
[root@server3 ~]# vim /etc/httpd/conf/httpd.conf #配置文件更改了
[root@server3 ~]# netstat -antlp #但是此时仍然是80
添加动作,让触发器生效
[devops@server1 ansible]$ vim files/httpd.conf #改为80
[devops@server1 ansible]$ vim playbook.yml
---
- name: apache playbook
hosts: test
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: configure httpd
copy:
src: files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: '0644'
notify: restart httpd #仅添加此行
- name: start httpd
service:
name: httpd
state: started
enabled: true
- name: enabled firewalld
service:
name: firewalld
state: started
enabled: true
- name: configure firewalld
firewalld:
service: http
state: enabled
permanent: true
immediate: true
- name: copy index.html
copy:
content: "<h1>www.westos.org</h1>\n"
dest: /var/www/html/index.html
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
注意:此时改变两次信息
[root@server3 ~]# vim /etc/httpd/conf/httpd.conf #配置文件和端口一致
注意:是基于md5码的信息机进行比对,进行推送
[devops@server1 ansible]$ md5sum files/httpd.conf
f5e7449c0f17bc856e86011cb5d152ba files/httpd.conf
[root@server3 ~]# md5sum /etc/httpd/conf/httpd.conf
f5e7449c0f17bc856e86011cb5d152ba /etc/httpd/conf/httpd.conf
此时是一致的,再次进行推送不会有所更改
- 虚拟主机的配置
1.创建虚拟主机配置文档 #模板在/usr/share/doc/httpd-2.4.6(可以rpm -ql httpd)
[devops@server1 ansible]$ cd files/
[devops@server1 files]$ ls
httpd.conf
[devops@server1 files]$ vim vhosts.conf
<VirtualHost *:80>
DocumentRoot /var/www/html
ServerName server3
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /var/www/vhosts/example.com
ServerName server3.example.com
ErrorLog "/var/log/httpd/example.com-error_log"
CustomLog "/var/log/httpd/example.com-access_log" common
</VirtualHost>
<Directory "/var/www/vhosts/example.com">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
2.编写playbook
---
- name: apache playbook
hosts: test
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: configure httpd
copy:
src: files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: '0644'
notify: restart httpd
- name: start httpd
service:
name: httpd
state: started
enabled: true
- name: enabled firewalld
service:
name: firewalld
state: started
enabled: true
- name: configure firewalld
firewalld:
service: http
state: enabled
permanent: true
immediate: true
- name: copy index.html
copy:
content: "<h1>www.westos.org</h1>\n"
dest: /var/www/html/index.html
- name: create /var/www/vhosts/example.com
file:
path: /var/www/vhosts/example.com
state: directory
mode: '0755'
- name: create vhost.html
copy:
content: "server3.example.com-vhosts\n"
dest: /var/www/vhosts/example.com/vhost.html
- name: copy vhosts.conf
copy:
src: files/vhosts.conf
dest: /etc/httpd/conf.d/vhosts.conf
notify: restart httpd
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
测试:
[root@server1 ansible]# vim /etc/hosts
172.25.254.3 server3 server3.example.com
- playbook多个软件的安装
采用定义变量的方法:
1.在playbook文件里定义变量
[devops@server1 ansible]$ vim playbook.yml
---
- name: apache playbook
hosts: test
vars:
web_package: httpd
web_service: httpd
firewalld_service: firewalld
tasks:
- name: install httpd
yum:
name: "{{ web_package }}"
state: present
- name: configure httpd
copy:
src: files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: '0644'
notify: restart httpd
- name: start httpd
service:
name: "{{ web_service }}"
state: started
enabled: true
- name: enabled firewalld
service:
name: "{{ firewalld_service }}"
state: started
enabled: true
- name: configure firewalld
firewalld:
service: http
state: enabled
permanent: true
immediate: true
- name: copy index.html
copy:
content: "<h1>www.westos.org</h1>\n"
dest: /var/www/html/index.html
- name: create /var/www/vhosts/example.com
file:
path: /var/www/vhosts/example.com
state: directory
mode: '0755'
- name: create vhost.html
copy:
content: "server3.example.com-vhosts\n"
dest: /var/www/vhosts/example.com/vhost.html
- name: copy vhosts.conf
copy:
src: files/vhosts.conf
dest: /etc/httpd/conf.d/vhosts.conf
notify: restart httpd
handlers:
- name: restart httpd
service:
name: "{{ web_service }}"
state: restarted
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
注意:此时不会有更改,因为信息没变,只是采用了定义变量的方式
2.局外定义变量
[devops@server1 ansible]$ mkdir vars
[devops@server1 ansible]$ cd vars/
[devops@server1 vars]$ vim web.yml
---
web_package: httpd
web_service: httpd
firewalld_service: firewalld
[devops@server1 ansible]$ vim playbook.yml
1 ---
2 - name: apache playbook
3 hosts: test
4 vars_files:
5 - vars/web.yml
6 tasks:
7 - name: install httpd
8 yum:
9 name: "{{ web_package }}"
10 state: present
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
注意:也不会改变
3.想要在现有基础上添加服务进火墙策略(方法一)
[root@server3 ~]# firewall-cmd --list-service
dhcpv6-client ssh http
[devops@server1 ansible]$ vim playbook.yml
1 ---
2 - name: apache playbook
3 hosts: test
4 vars:
5 firewalld_svc:
6 - http
7 - https
8 vars_files:
9 - vars/web.yml
10 tasks:
11 - name: install httpd
12 yum:
13 name: "{{ web_package }}"
14 state: present
37 - name: configure firewalld
38 firewalld:
39 service: "{{ item }}"
40 state: enabled
41 permanent: true
42 immediate: true
43 loop: "{{ firewalld_svc }}"
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
在server3查看
4.想要在现有基础上添加服务进火墙策略(方法二)
[devops@server1 ansible]$ vim playbook.yml
1 ---
2 - name: apache playbook
3 hosts: test
4 vars:
5 firewalld_svc:
6 - http
7 - https
8 vars_files:
9 - vars/web.yml
10 tasks:
11 - name: install httpd
12 yum:
13 name: "{{ web_package }}"
14 state: present
37 - name: configure firewalld
38 firewalld:
39 service: "{{ item }}"
40 state: enabled
41 permanent: true
42 immediate: true
43 loop:
44 - http
45 - https
46 - ftp
[devops@server1 ansible]$ ansible-playbook --syntax-check playbook.yml
playbook: playbook.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
在server3上查看
- 不同主机安装不同的服务
[devops@server1 ansible]$ vim playbook.yml
37 - name: configure firewalld
38 firewalld:
39 service: "{{ item }}"
40 state: enabled
41 permanent: true
42 immediate: true
43 loop: "{{ firewalld_svc }}"
[devops@server1 vars]$ cp web.yml ftp.yml
[devops@server1 vars]$ vim ftp.yml
---
ftp_package: vsftpd
ftp_service: vsftpd
firewalld_service: firewalld
[devops@server1 ansible]$ cp playbook.yml vsftp.yml
[devops@server1 ansible]$ vim vsftp.yml
---
- name: vsftp playbook
hosts: prod
vars:
firewalld_svc:
- ftp
vars_files:
- vars/ftp.yml
tasks:
- name: install vsftpd
yum:
name: "{{ ftp_package }}"
state: present
- name: configure vsftpd
copy:
src: files/vsftpd.conf
dest: /etc/vsftpd/vsftpd.conf
owner: root
group: root
mode: '0600'
notify: restart vsftpd
- name: start vsftpd
service:
name: "{{ ftp_service }}"
state: started
enabled: true
- name: enabled firewalld
service:
name: "{{ firewalld_service }}"
state: started
enabled: true
- name: configure firewalld
firewalld:
service: "{{ item }}"
state: enabled
permanent: true
immediate: true
loop: "{{ firewalld_svc }}"
handlers:
- name: restart vsftpd
service:
name: "{{ ftp_service }}"
state: restarted
[devops@server1 files]$ ls
httpd.conf vhosts.conf vsftpd.conf
[devops@server1 files]$ ll
total 24
-rw-r--r-- 1 devops devops 11753 May 10 22:57 httpd.conf
-rw-rw-r-- 1 devops devops 474 May 10 23:02 vhosts.conf
-rw-r--r-- 1 root root 5030 May 11 00:03 vsftpd.conf
[root@server1 files]# chown devops.devops vsftpd.conf
[devops@server1 ansible]$ cp playbook.yml apache.yml
[devops@server1 ansible]$ vim playbook.yml
---
- import_playbook: apache.yml
- import_playbook: vsftp.yml
[devops@server1 ansible]$ rm -rf playbook.retry
[devops@server1 ansible]$ ansible-playbook --syntax-check vsftp.yml
playbook: vsftp.yml
[devops@server1 ansible]$ ansible-playbook --syntax-check apache.yml
playbook: apache.yml
[devops@server1 ansible]$ ansible-playbook playbook.yml
- 让按照需求在对应的主机安装对应的服务
[devops@server1 ansible]$ vim test.yml
---
- name: test
hosts:
- prod
- test
tasks:
- name: deploy apache
yum:
name: httpd
state: latest
when: ansible_hostname in groups['test']
- name: deploy vsftpd
yum:
name: vsftpd
state: present
when: ansible_hostname in groups['prod']
[devops@server1 ansible]$ ansible-playbook --syntax-check test.yml
playbook: test.yml
[devops@server1 ansible]$ ansible-playbook test.yml
- 用户的创建针创建不同用户(用户和密码对应)
[devops@server1 ansible]$ cd vars/
[devops@server1 vars]$ vim user.yml
---
userlist:
- name: user1
pass: westos
- name: user2
pass: redhat
[devops@server1 ansible]$ vim test.yml
---
- name: test
hosts:
- test
vars_files:
- vars/user.yml
tasks:
- name: create user
user:
name: "{{ item.name }}"
state: present
password: "{{ item.pass }}"
loop: "{{ userlist }}"
[devops@server1 ansible]$ ansible-playbook --syntax-check test.yml
playbook: test.yml
[devops@server1 ansible]$ ansible-playbook test.yml
注意:此时有警告,是因为密码是明文的
采用加密的方式:
[devops@server1 ansible]$ vim test.yml
---
- name: test
hosts:
- test
vars_files:
- vars/user.yml
tasks:
- name: create user
user:
name: "{{ item.name }}"
state: present
password: "{{ item.pass | password_hash('sha512') }}"
loop: "{{ userlist }}"
[devops@server1 ansible]$ ansible-playbook --syntax-check test.yml
playbook: test.yml
[devops@server1 ansible]$ ansible-playbook test.yml
测试: