1.环境准备 (自动化工具,批量操作)



6台 2cpu,1.5G以上内存,20G硬盘,1网卡




ansible批量修改配置 ansible 批量配置ip_vim


1.1 基础环境准备


1)启动6台虚拟机,ansible.sh


 


2)真机配置yum仓库


]# tar -xf ansible_soft.tar.xz 


]# cd ansible_soft/


soft]# mkdir /var/ftp/ansible


soft]# cp * /var/ftp/ansible


soft]# createrepo /var/ftp/ansible


 


3)修改主机名(容易区分,6台机器都需要修改)这里以ansible主机为例子


]# echo ansible > /etc/hostname 


]# hostname ansible


 


4)配置ip(6台机器都需要配置),这里以ansible主机为例子


]# vim /etc/sysconfig/network-scripts/ifcfg-eth0 


# Generated by dracut initrd


DEVICE="eth0"


ONBOOT="yes"


IPV6INIT="no"


IPV4_FAILURE_FATAL="no"


NM_CONTROLLED="no"


TYPE="Ethernet"


BOOTPROTO="static"


IPADDR=192.168.1.51


PREFIX=24


GATEWAY=192.168.1.254


]# systemctl restart network


[root@localhost ~]# ifconfig 


...inet 192.168.1.51...


 


5)配置yum客户端,在管理节点ansible上面配置


ansible ~]# vim /etc/yum.repos.d/local.repo 


[local_repo]


name=CentOS-$releasever - Base


baseurl=" ftp://192.168.1.254/system"


enabled=1


gpgcheck=1


[local]


name=local


baseurl=" ftp://192.168.1.254/ansible"


enabled=1


gpgcheck=0


 


ansible ~]# yum clean all


ansible ~]# yum repolist


ansible ~]# yum -y install ansible


ansible ~]# ansible --version


ansible 2.4.2.0        //显示版本说明安装成功


  


6)请在6台主机上面配置/etc/hosts,这里以ansible主机为例子


ansible]# cat /etc/hosts


192.168.1.51 ansible


192.168.1.52 web1


192.168.1.53 web2


192.168.1.54 db1


192.168.1.55 db2

192.168.1.56 cache


 


2. 主机定义与分组


 


熟悉ansible配置文件


定义主机,分组和子组练习


自定义文件,多配置路径练习


 


2.1 ansible.cfg配置文件


 


ansible]# cd /etc/ansible/


ansible ansible]# ls


ansible.cfg  hosts  roles


ansible ansible]# vim ansible.cfg


 


//指定分组文件路径,主机的分组文件hosts


14 inventory = /etc/ansible/hosts


//ssh首次连接的时候,需要取消输入yes


61 host_key_checking = False 


[selinux]  //组名称,selinux的相关选项在这个下面配置


...


[colors]   //组名称,colors的相关选项在这个下面配置


...


 


2.2 定义主机,分组和子组练习


 


1)静态主机的定义


ansible]# vim /etc/ansible/hosts 


[web]


web1


web2


[db]


db[1:2]


[other]


cache


//1:2为db1到db2两台主机,1:20为db1到db20多台主机


 


ansible]# ansible web --list-host   //显示web组的主机


  hosts (2):


    web1


    web2


 


ansible]# ansible db --list-host


  hosts (2):


    db1


    db2


 


ansible]# ansible other --list-host


  hosts (1):


    cache


 


[ansible]# ansible all --list-host  //显示所有组的主机


  hosts (5):


    web1


    web2


    cache


    db1


    db2


 


2)直接测试


-m(module) ping(模块)


ansible]# ansible cache -m ping        


//测试是否可以连接,若失败颜色为红色


cache | UNREACHABLE! => {


    "changed": false, 


    "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname cache: Name or service not known\r\n", 


    "unreachable": true


}


 


3)修改后测试


ansible]# vim /etc/ansible/hosts 


[other]


cache ansible_ssh_user="root" ansible_ssh_pass="123456"


//cache虚拟机的用户名和密码


 


ansible]# ansible other -m ping   //测试成功,颜色为绿色


cache | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


ansible]# vim /etc/ansible/hosts 


[web]


web1


web2


[web:vars]    //web组:变量(vars不改),web组的多台机器共用一个用户名和密码


ansible_ssh_user="root"


ansible_ssh_pass="123456"


 


ansible]# ansible web -m ping


web2 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


web1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


2.3 定义子组(集合)


 


ansible]# vim /etc/ansible/hosts 


//指定子分组(app可改:children不改),web,db是提前分好的组


[app:children]


web


db


[app:vars](vars 集合内所有成员的公共属性)


ansible_ssh_user="root"


ansible_ssh_pass="123456"


 


ansible]# ansible app --list-host  //查看


  hosts (4):


    web1


    web2


    db1


    db2


 


ansible]# ansible app -m ping      //测试


web1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


web2 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


db1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


db2 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


2.4 多路径练习


 


自定义的ansible文件只在当前路径生效


 


1)多路径


ansible ~]# mkdir aaa


ansible ~]# cd aaa/


aaa]# vim myhost


[app1]


web1


db1


[app2]


web2


db2


[app:children]


app1


app2


[other]


cache


[app:vars]


ansible_ssh_user="root"


ansible_ssh_pass="123456"


 


aaa]# touch ansible.cfg


aaa]# grep -Ev "^#|^$" /etc/ansible/ansible.cfg 


[defaults]


roles_path    = /etc/ansible/roles:/usr/share/ansible/roles


host_key_checking = False


[inventory]


[privilege_escalation]


[paramiko_connection]


[ssh_connection]


[persistent_connection]


[accelerate]


[selinux]


[colors]


[diff]


 


aaa]# vim ansible.cfg 


[defaults]


inventory = myhost


host_key_checking = False


 


2)测试结果


aaa]# ansible app1 -m ping


web1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


db1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


aaa]# ansible app -m ping


web1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


db1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


db2 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


web2 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


aaa]# ansible app --list-host


  hosts (4):


    web1


    db1


    web2


    db2


 


aaa]# cd 


ansible ~]# ansible  app1 --list-host   //切换到别的目录,测试失败


 [WARNING]: Could not match supplied host pattern, ignoring: app1


 [WARNING]: No hosts matched, nothing to do


  hosts (0):


 


3.动态主机


 


3.1 脚本输出主机列表


 


ansible ~]# cd aaa


aaa]# ls


ansible.cfg  myhost


 


aaa]# vim host.py


#!/usr/bin/python (这行也要!)


import json


hostlist = {} //定义主机列表


hostlist["bb"] = ["192.168.1.52", "192.168.1.53"]


hostlist["192.168.1.54"] = {


         "ansible_ssh_user":"root","ansible_ssh_pass":"pwd"


        }


hostlist["aa"] = {


         "hosts" : ["192.168.1.55", "192.168.1.56"],


         "vars"  : {


              "ansible_ssh_user":"root","ansible_ssh_pass":"pwd"


         }


}


print(json.dumps(hostlist))


aaa]# chmod 755 ./host.py


 


2) 脚本输出样例(这样写输出的结果有些乱)


aaa]# ./host.py 


{"aa": {"hosts": ["192.168.1.55", "192.168.1.56"], "vars": {"ansible_ssh_user": "root", "ansible_ssh_pass": "a"}}, "192.168.1.54": {"ansible_ssh_user": "root", "ansible_ssh_pass": "a"}, "bb": ["192.168.1.52", "192.168.1.53"]}


 


3) 可以用shell脚本输出


aaa]# vim my.sh


#!/bin/bash


echo '


{  "aa": {


        "hosts": 


                ["192.168.1.55", "192.168.1.56"], 


       "vars": {


                "ansible_ssh_user": "root", 


                "ansible_ssh_pass": "123456"}


 },


}' 


 


aaa]# chmod 755 my.sh


aaa]# ./my.sh 


{  "aa": {


    "hosts": 


        ["192.168.1.55", "192.168.1.56"], 


       "vars": {


        "ansible_ssh_user": "root", 


        "ansible_ssh_pass": "123456"}


 },


}


 


aaa]# vim ansible.cfg


[defaults]


inventory = my.sh


host_key_checking = False


 


aaa]# ansible aa -m ping


192.168.1.55 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


192.168.1.56 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


3.2 批量执行


 


1)查看负载


aaa]# cd /etc/ansible


ansible]# ansible app -m command -a 'uptime'


web2 | SUCCESS | rc=0 >>


 19:55:36 up  4:02,  2 users,  load average: 0.00, 0.01, 0.01


 


db1 | SUCCESS | rc=0 >>


 19:55:36 up  4:01,  2 users,  load average: 0.00, 0.01, 0.02


 


web1 | SUCCESS | rc=0 >>


 19:55:36 up  4:02,  2 users,  load average: 0.00, 0.01, 0.01


 


db2 | SUCCESS | rc=0 >>


 19:55:36 up  4:01,  2 users,  load average: 0.00, 0.01, 0.03


 


2)查看时间


ansible]# ansible app -m command -a 'date +%F\ %T'


web1 | SUCCESS | rc=0 >>


2019-02-26 19:56:12


 


db1 | SUCCESS | rc=0 >>


2019-02-26 19:56:12


 


db2 | SUCCESS | rc=0 >>


2019-02-26 19:56:12


 


web2 | SUCCESS | rc=0 >>


2019-02-26 19:56:12


 


4.批量部署证书文件


创建一对密钥


给所有主机部署密钥


 


4.1 批量部署证书文件,给所有主机部署密钥


 


1)创建密钥


ansible]# cd /root/.ssh/


.ssh]# vim /etc/ansible/hosts


[web]


web1


web2


[db]


db[1:2]


[other]


cache


.ssh]# ansible all -m ping  //直接ping会报错


.ssh]# ssh-keygen -t rsa -b 2048 -N ''  //创建密钥


 


2)给所有主机部署密钥


.ssh]# ansible all -m authorized_key -a "user=root exclusive=true manage_dir=true key='$(< /root/.ssh/id_rsa.pub)'" -k


SSH password:        //输入密码


 


.ssh]# ansible all -m ping  //成功


web2 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


db2 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


web1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


cache | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


db1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


.ssh]# ssh web1


//不需要输入密码,可以直接登陆


 


5. 练习模块


练习使用command , shell , raw, script模块


 


5.1 练习模块


 


ansible-doc //模块的手册,相当于man


ansible-doc -l //列出所有模块


ansible-doc 模块名 //查看指定模块的帮助信息


 


1)ping模块


.ssh]# ansible web1 -m ping


web1 | SUCCESS => {


    "changed": false, 


    "ping": "pong"


}


 


2)command模块


.ssh]# ansible web1 -m command -a 'chdir=/tmp touch f1'  


//创建成功


web1 ~]# cd /tmp/


tmp]# ls        //在web1上面查看


f1


 


3)shell模块


.ssh]# ansible web1 -m shell -a 'chdir=/tmp touch f2'  //创建成功


[root@web1 ~]# cd /tmp/


[root@web1 tmp]# ls    //在web1上面查看


f2


 


4)raw模块


.ssh]# ansible web1 -m raw -a 'chdir=/tmp touch f3'


//文件可以创建,但无法切换目录,文件在用户家目录下生成/root/


web1 ~]# ls //在web1上面查看 


f3


 


5)script模块


对于太复杂的命令,可以写个脚本,然后用script模块执行


在web1主机上创建zhangsan3用户,修改zhangsan3的密码为123456,设置zhangsan3第一次登陆必须修改密码


用命令写:(必须有zhangsan3这个用户)


.ssh]# ansible web1 -m shell -a 'echo 123456 | passwd --stdin zhangsan3'


.ssh]# ssh -l zhangsan3 web1


zhangsan3@web1's password:   //输入zhangsan3的密码


web1 ~]$ whoami


zhangsan3


 


.ssh]# ansible web1 -m shell -a 'chage -d 0 zhangsan3'


(重置zhangsan3的密码)


.ssh]# ssh -l zhangsan3 web1


 


 


用脚本写,script模块执行:


[.ssh]# vim user.sh 


#!/bin/bash


useradd zhangsan3 


echo 123456 | passwd --stdin zhangsan3 


chage -d 0 zhangsan3


echo


 


.ssh]# ansible web1 -m script -a './user.sh'


web1 | SUCCESS => {


    "changed": true, 


    "rc": 0, 


    "stderr": "Shared connection to web1 closed.\r\n", 


    "stdout": "Changing password for user zhangsan3.\r\npasswd: all authentication tokens updated successfully.\r\n\r\n", 


    "stdout_lines": [


        "Changing password for user zhangsan3.", 


        "passwd: all authentication tokens updated successfully.", 


        ""


    ]


}


 


ansible .ssh]# ssh  -l zhangsan3 web1


lisi@web1's password: 


You are required to...(更改密码)


 


6. 模块练习


使用copy模块同步数据


使用lineinfile模块编辑文件


使用replace模块修改文件


 


6.1 模块练习


 


1)使用copy模块同步数据


src:要复制到进程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync


dest:必选项。进程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录


backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no


force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes


 


.ssh]# ansible all -m shell -a 'cat /etc/resolv.conf'


//查看/etc/resolv.conf


 


db1 | SUCCESS | rc=0 >>


; generated by /usr/sbin/dhclient-script


search vbr


nameserver 192.168.1.254


 


web1 | SUCCESS | rc=0 >>


; generated by /usr/sbin/dhclient-script


search vbr


nameserver 192.168.1.254


 


db2 | SUCCESS | rc=0 >>


; generated by /usr/sbin/dhclient-script


search vbr


nameserver 192.168.1.254


 


web2 | SUCCESS | rc=0 >>


; generated by /usr/sbin/dhclient-script


search vbr


nameserver 192.168.1.254


 


cache | SUCCESS | rc=0 >>


; generated by /usr/sbin/dhclient-script


search vbr


nameserver 192.168.1.254


 


.ssh]# cat /etc/resolv.conf


nameserver 176.233.0.227


 


.ssh]# ansible all -m copy -a 'src=/etc/resolv.conf dest=/etc/resolv.conf'


//复制本机的resolv.conf到其他主机


 


.ssh]# ansible all -m shell -a 'cat /etc/resolv.conf'     


//查看都有nameserver 176.233.0.227


 


ansible ~]# mkdir aa


ansible ~]# echo "654321" > aa/1.txt


ansible ~]# ansible all -m copy -a 'src=/root/aa dest=/root/a.log'  


//复制本机的目录/root/aa到其他机器的/root/a.log目录下,复制目录只能少数批量执行同步


 


ansible ~]# ansible all -m shell -a 'ls -ld /root/*''


web2 | SUCCESS | rc=0 >>


drwxr-xr-x 3 root root 16 2月  26 20:30 /root/a.log


 


db1 | SUCCESS | rc=0 >>


drwxr-xr-x 3 root root 16 2月  26 20:30 /root/a.log


 


web1 | SUCCESS | rc=0 >>


drwxr-xr-x 3 root root 16 2月  26 20:30 /root/a.log


 


cache | SUCCESS | rc=0 >>


drwxr-xr-x 3 root root 16 2月  26 20:30 /root/a.log


 


db2 | SUCCESS | rc=0 >>


drwxr-xr-x 3 root root 16 2月  26 20:30 /root/a.log


 


web1 ~]# ls a.log/aa/1.txt 


a.log/aa/1.txt


 


 


2)使用lineinfile模块编辑文件


以行为基础,整行修改(整行被替换掉)


ansible ~]# ansible cache -m lineinfile \


-a 'path=/etc/sysconfig/network-scripts/ifcfg-eth0 \


regexp="^ONBOOT=" line="ONBOOT=\"no\""'  (" “ ‘)


 


cache | SUCCESS => {


    "backup": "", 


    "changed": true, 


    "msg": "line replaced"


}


 


3)使用replace模块修改文件


修改文件的某一部分(替换一行中匹配的内容),以正则表达式匹配为基础修改


ansible ~]# ansible cache -m replace -a \


  'path=/etc/sysconfig/network-scripts/ifcfg-eth0 \


regexp="^(ONBOOT=).*" replace="\1\"yes\""'


 


cache | SUCCESS => {


    "changed": true, 


    "msg": "1 replacements made"


}


 


7. 综合练习


安装Apache并修改监听端口为8080


修改ServerName配置,执行apachectl -t命令不报错


设置默认主页hello world


启动服务并设开机自启


 


7.1 步骤一:熟悉模块


 


1)yum模块


ansible ~]# ansible other -m yum -a 'name="lrzsz" state=removed'   


//lrzsz软件包名,removed=absent删除


 


ansible ~]# ansible other -m yum -a 'name="lrzsz,lftp" state=installed'  


//安装多个软件包,不写state默认为安装


 


2)service模块


ansible ~]# ansible other -m service -a 'name="sshd" enabled="yes" state="started"' 


//sshd服务名,开机启动同时启动这个服务


 


3)setup模块


filter 过滤指定的关键字(可以过滤到我们需要的信息)


ansible ~]# ansible cache -m setup -a 'filter=os'


cache | SUCCESS => {


    "ansible_facts": {}, 


    "changed": false


}


 


ansible ~]# ansible cache -m setup -a 'filter=ansible_distribution'


cache | SUCCESS => {


    "ansible_facts": {


        "ansible_distribution": "CentOS"


    }, 


    "changed": false


}


 


7.2 安装Apache


 


1)安装Apache服务设置开机自启


ansible ~]# ansible cache -m yum -a 'name=httpd state=installed'


ansible ~]# ansible cache -m service -a 'name=httpd enabled=yes state=started'


 


2)修改端口号为8080


ansible ~]# ssh cache


cache ~]# cat /etc/httpd/conf/httpd.conf | grep ^Listen


Listen 80


 


ansible ~]# ansible cache -m lineinfile -a 'path="/etc/httpd/conf/httpd.conf" regexp="^Listen " line="Listen 8080"'


 


cache | SUCCESS => {


    "backup": "", 


    "changed": true, 


    "msg": "line replaced"


}


ansible ~]# ssh cache


cache ~]# cat /etc/httpd/conf/httpd.conf | grep ^Listen


Listen 8080


 


7.3 修改ServerName配置,执行apachectl -t命令不报错


 


1)没有修改之前


cache ~]# apachectl -t  //有报错


AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.1.56. Set the 'ServerName' directive globally to suppress this message


Syntax OK


 


2)修改之后


ansible ~]# ansible cache -m lineinfile -a 'path="/etc/httpd/conf/httpd.conf" regexp="^ServerName " line="ServerName 0.0.0.0"'


 


cache | SUCCESS => {


    "backup": "", 


    "changed": true, 


    "msg": "line added"


}


 


ansible ~]# ssh cache


cache ~]# apachectl -t


Syntax OK


 


7.4 设置默认主页为hello world


ansible ~]# echo "Hello World" >  /root/index.html


ansible ~]# ansible cache -m copy -a 'src=/root/index.html dest=/var/www/html/index.html'


 


cache | SUCCESS => {


    "changed": true, 


    "checksum": "22596363b3de40b06f981fb85d82312e8c0ed511", 


    "dest": "/var/www/html/index.html", 


    "gid": 0, 


    "group": "root", 


    "md5sum": "6f5902ac237024bdd0c176cb93063dc4", 


    "mode": "0644", 


    "owner": "root", 


    "size": 12, 


    "src": "/root/.ansible/tmp/ansible-tmp-1536219767.29-30682157793478/source", 


    "state": "file", 


    "uid": 0


}

*****************
ansible.sh


#!/bin/bash


func_zj(){


cd /var/lib/libvirt/images/


for i in ansible web1 web2 db1 db2 cache


do


   qemu-img create -f qcow2 -b node.qcow2 $i.img 20G


   sed "s,node,$i," /etc/libvirt/qemu/node.xml > /etc/libvirt/qemu/$i.xml


   virsh define /etc/libvirt/qemu/$i.xml


   virsh start $i


   for j in {3..0}


   do


      echo $j


      sleep 1


   done


done


}


 


func_spawn(){


expect <<EOF


spawn virsh console $1


   expect " "           {send "\r"}


   expect "login"       {send "root\r"}


   expect "Password"    {send "123456\r"}


   expect "#"           {send "export LANG=en_US\r"}  


   expect "#"           {send "growpart /dev/vda 1\r"}  


   expect "#"           {send "xfs_growfs /\r"}


   expect "#"           {send "lsblk\r"}  


   expect "#"           {send "echo $1 > /etc/hostname\r"}  


   expect "#"           {send "ip a s\r"}


   expect "#"           {send "exit\r"}  


EOF


}


 


func_sj(){


for k in ansible web1 web2 db1 db2 cache


do


  func_spawn $k


done


}


 


echo "开始"


func_zj


   for j in {60..0}


       do


       echo $j


       sleep 1


   done


func_sj


echo "结束"


 


##################################


知识点整理:

01:ansible概述
基于Python开发,IT自动化和DevOps软件,实现了批量操作系统配置,批量程序部署,批量运行命令等功能,只要有SSH和Python即可使用。

02:ad-hoc 主机管理模式/playbook 两种模式
01:主机集合:inventory=/etc/ansible/hosts
host_key_checking=False 首次ssh不输入yes
]# ansible 集合/主机 -m(module) xxx -a(模块的参数) 'xxx' (- k 密码)

常用模块都有哪些:
command --> id(查看用户),uptime,date 默认模块,不支持"|" "<" ">" "&"(bash提供)

authorized_key --> ssh-key-id命令

shell(跟command差不多,可执行任意模块 远程的时候注意转义,否则是本地)

raw(跟shell一样,可执行任意模块,unix,不支持cd 即 -a chdir=/dir touch xxx)

script -a 'xx.sh' --> 执行脚本模块 远程批量执行本地脚本(复杂的任务)

copy -a 'src=xx dest=xx' --> 拷贝文件和文件夹,不适合批量操作(打包校验机制,麻烦)

lineinfile -a 'path=xxx regexp=“^xx"(匹配整行,替换整行) line(修改为)="XXX" -->修改行内容

replace 跟lineinfile一样,但只修改匹配的部分
replace -a 'path=xxx regexp=“^xx"(匹配整行,替换整行) replace(修改为)="^XXX" -->修改行内容

yum -a 'name=aa,bb,.. state=installed' --> yum 装包 (removed 卸载)

service -a 'name=a,b,...state=started(stoppd restarted) enabled=yes' -->启服务

setup | grep os(返回字符串) -->获取主机信息,不写参数获取所有
setup -a 'filter="ansible_os_family"'(返回标准格式) 获取主机名

查看所有模块:]# ansible-doc -l(1300多)

02:动态主机分组(脚本、程序,返回给ansible Json主机数据就行)
(只要哪个程序有主机群组的配置文件+SSH就可以用ansible批量管理,如zabbix)
Json:数组 字典
数组:[ "a","b","c" ]
字典:{ A:a,B:b,...键值对的集合 }

#######################################