Linux基础篇
Linux基础篇总共包含8个章节,第1章到第8章学习内容分别包括:Linux快速入门、Linux发展及系统安装、CentOS Linux系统管理、Linux必备命令、Linux用户和组、Linux软件包管理、磁盘管理、Linux文件共享管理等。
读者通过对基础篇8个章节的深入学习,可以更加了解Linux发展历程,了解Linux发行版之间的特性以及Linux内核命名规范,基于虚拟机环境手动安装CentOS操作系统,能够快速上手,快速的入门Linux。
同时能够熟练掌握Linux操作系统完整的流程,掌握Linux操作系统用户和组管理的机制,对Linux系统文件及目录进行权限定制和分配,从而提升Linux操作系统使用安全,更加保证系统的稳定性。
对Linux必备命令的掌握程度,直接决定后期对Linux系统能否进行娴熟的操作,同时掌握Linux高效学习大绝招,养成学习Linux的习惯和方法,对后期的Linux学习能起到事半功倍的效果。
俗话说“基础不牢,地动山摇”,熟练掌握Linux基础必备篇的相关内容,能够独立维护和管理企业Linux操作系统,为后期维护企业生产环境服务器打下坚实的基础。
Linux进阶篇
Linux进阶篇总共包含6个章节,第9章到第14章学习内容分别包括:HTTP协议详解、Apache WEB服务器企业实战、MySQL数据库服务器企业实战、LAMP企业架构实战、Zabbix分布式监控系统实战、Nginx高性能WEB服务器实战等。
读者通过对进阶篇6个章节的深入学习,可以基于基础篇学习的Linux操作系统管理,快速上手独立维护和管理企业各种服务,例如主流的Apache、Nginx WEB服务器,深入学习HTTP协议,掌握HTTP底层通信原理等。
同时能熟练构建企业级数据库管理集群,MySQL主从复制,一主多从、读写分离实战保证网站数据的完整,对数据库配置文件进行调优、增加索引提供数据查询效率,如果数据库异常或者缓慢,可以基于MySQL慢查询日志定位慢SQL。
进阶篇引入Redis高性能缓存服务器,互联网各大公司都在使用Redis,熟练掌握Redis对升职加薪及网站性能有巨大的帮助,Redis缓存还可以提高用户访问WEB网站的效率,增强用户体验。同时随着企业服务器不断增加,基于Zabbix分布式监控系统能够实时监控服务器CPU、内存、硬盘、网卡及服务器上各种应用的监控,做到有故障第一时间给相关人员发送微信报警,第一时间处理问题。
互联网主流WEB服务器软件Nginx,得到各大企业的SA的青睐,应用也非常的广泛,对Nginx深入掌握,对运维能力的提升是非常大的,通过进阶篇的对Nginx的深入学习,能够熟练掌握Nginx工作原理、安装配置、管理升级、负载均衡及动静分离、虚拟主机、参数调优、Nginx Location、Nginx Rewrite、日志切割、防盗链、HTTPS等核心技术,能更好的维护生产环境Nginx高性能 WEB服务器。
Linux高级篇
Linux进阶篇总共包含9个章节,第15章到第23章学习内容分别包括:Linux性能优化、大数据量备份、Shell企业实战基础、Shell实战高级编程、自动化运维趋势、Puppet自动化运维实战、Ansible自动化运维实战、Jenkins企业级自动化实战、企业级高并发网站集群等。
读者通过对进阶篇9个章节的深入学习,可以能够独立维护和管理企业上百台、千台服务器,能够在企业中独当一面,打造企业级千万PV门户网站架构。
同时能够掌握对MYSQL 2T+大数量的备份,Linux服务器内核进行优化、对内核故障排错,服务器异常能够快速解决,编写企业生产环境各种Shell脚本工具,实现网站自动化维护和部署、Shell高级实战编程章讲述了11个高级实战脚本案例满足企业各种场景使用,基于Shell编程独立开发各种脚本,例如:构建网站服务器数据备份、LAMP、LNMP一键安装部署、服务器硬件信息收集存入DB、MYSQL主从实战、自动修改千台服务器IP、Zabbix自动部署客户端、Nginx、Tomcat自动部署、Docker虚拟化管理平台、Bind高级管理等脚本等。
对Linux高级篇的学习能够完全胜任万台服务器的维护和管理,基于Puppet各种案例实现主动部署管理、客户端自动获取配置、批量管理服务器等,通过轻量级Ansible自动化部署工具,实现至少1000台服务器的运维和管理,通过各种资源模块对服务器进行管理,同时可以编写Playbook剧本实现对服务器流程化管理,减轻人工干预,实现对服务器和web网站高效维护。
高级篇引入Jenkins自动化部署平台,讲述传统网站部署、主流网站部署的方法,基于Jenkins构建企业级自动化平台,支持SVN、GIT仓库,结合Ansible自动化运维工具打造企业级自动化部署平台,让运维工作更加的轻松。
本篇最后一个章节以9个企业级高级实战集群部署,例如Nginx+keepalived、Redis+keepalived、LVS+Keepalived、Haproxy+keepalived满足企业各个应用环境的部署,真正学以致用,满足企业高速的发展!
第1章 Linux快速入门

Linux是一套免费使用和自由传播的类UNIX操作系统,是一个基于POSIX移植操作系统接口(Portable Operating System Interface of UNIX,POSIX)和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。
目前被广泛使用于企业服务器、WEB网站平台、大数据、虚拟化、Android、超级计算机等领域,未来Linux将应用各行各业,例如云计算、物联网、人工智能等。
本章向读者介绍Linux发展简介、Linux发行版特点、32位及64位CPU特性及Linux内核命名规则。
1.1 为什么要学习Linux
我们为什么要学习Linux?我们目前的处境是什么?我们想达到什么样的目标?在谈到这三个问题时,相信每个人都有自己的答案,我们来自不同的家庭,各种经历也都不一样,但最终的目标都是希望通过学习技术,提升自己的专业技术。真正做一个对社会有贡献的人。
想想我们刚步入学堂的那一刻起,心里就狠狠下决心,以后不管做什么,都要一番出息,可是20年、30年过去了,我们收获了什么,得到了什么,到底是在追求什么?方向又在哪里呢?
在生活中各种挫折、感情、生活以及很多零碎的事情,让我们很难静下心来学习,当我们某天突然惊醒,年少已不在。所以今天就下定决心,现在就要学习,去行动,去改变。
人生最可怕的是在自以为舒适的地方待得太久,等到外界改变来的时候,已经晚了,我们不能像温水煮青蛙一样,待在温水里,没有觉察到周围事物的变化,最终被社会所淘汰,如图1-1所示。

图1-1 温水煮青蛙
1.2 Linux操作系统简介
Linux操作系统是基于UNIX以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统,Linux能运行各种工具软件、应用程序及网络协议,它支持安装在32位和64位CPU硬件上。
通常的讲,Linux这个词本身只表示Linux内核,但是人们已经习惯用Linux来形容整个基于Linux内核的操作系统,并且是一种使用GNU通用公共许可证(GNU General Public License,GPL)工程各种工具和数据库的操作系统。
GNU是“GNU is Not Unix”,UNIX是一种广泛使用的商业操作系统,由于GNU将要实现以UNIX系统的接口标准,因此GNU计划可以分别开发不同的操作系统部件,并且采用了部分当时已经可自由使用的软件。
为了保证GNU软件可以自由地“使用、复制、修改和发布”,所有的GNU软件都在一份禁止其他人添加任何限制的情况下授权所有权利给任何人的协议条款里,我们把这个条款称之为GNU通用公共许可证(GNU General Public License,GPL)。
1991年的10月5日,Linux创始人Linus Torvalds在comp.os.minix新闻组上发布消息,正式向外宣布Linux内核的诞生,1994年3月Linux 1.0发布,代码量17万行,当时是完全按照自由免费的协议发布,随后正式采用GPL协议,目前GPL协议版本包括:GPLv1、GPLv2、GPLv3以及未来的GPLv4、GPLv5等。
1.3 Linux操作系统优点
随着IT产业的不断发展,Linux操作系统应用领域越来越广泛,尤其是近年来Linux在服务器领域飞速的发展,主要得益于Linux操作系统具备的如下优点:
开源免费;
系统迭代更新;
系统性能稳定;
安全性高;
多任务,多用户;
耗资源少;
内核小;
应用领域广泛;
使用及入门容易。
1.4 Linux操作系统发行版
学习Linux操作系统,需要选择不同的发行版本,Linux操作系统是一个大类别,Linux操作系统主流发行版本包括:Red Hat Linux、CentOS、Ubuntu、SUSE Linux、Fedora Linux等,具体发行版本区别如下:
1.Red Hat Linux
Red Hat Linux是最早的Linux发行版本之一,同时也是最著名的Linux版本,Red Hat Linux已经创造了自己的品牌,也是读者经常听到的“红帽操作系统”。Red Hat 1994年创立,目前公司全世界有3000多人,一直致力于开放的源代码体系,向用户提供一套完整的服务,这使得它特别适合在公共网络中使用。这个版本的Linux也使用最新的内核,还拥有大多数人都需要使用的主体软件包。
Red Hat Linux发行版操作系统的安装过程非常简单,图形安装过程提供简易设置服务器的全部信息,磁盘分区过程可以自动完成,还可以通过图形界面(Graphical User Interface,GUI)完成安装,即使对于Linux新手来说这些都非常简单。后期如果想批量安装Red Hat Linux系统,可以通过批量的工具来实现快速安装。
2.CentOS
社区企业版操作系统(Community Enterprise Operating System,CentOS)是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定性的服务器以CentOS替代商业版的Red Hat Enterprise Linux使用。
CentOS于Red Hat Linux不同之处在于CentOS并不包含封闭的源代码软件,可以开源免费使用,得到运维人员、企业、程序员的青睐,CentOS发行版操作系统是目前企业使用最多的系统之一,2016年12月12日,CentOS基于 Red Hat Enterprise Linux 的 CentOS Linux 7 (1611) 系统正式对外发布。
3.Ubuntu 
Ubuntu是一个以桌面应用为主的Linux操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词(译为吾帮托或乌班图),意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观。
Ubuntu基于Debian发行版和GNOME桌面环境, Ubuntu发行版操作系统的目标在于为一般用户提供一个最新的、同时稳定的以开放自由软件构建而成的操作系统,目前Ubuntu具有庞大的社区力量,用户可以方便地从社区获得帮助。
4.SUSE Linux
SUSE(发音 /ˈsuːsə/),SUSE Linux 出自德国,SuSE Linux AG公司发行维护的Linux发行版,是属于此公司的注册商标2003年11月4日,Novell表示将会对SUSE提出收购。收购的工作于2004年1月完成。
Novell也向大家保证SUSE的开发工作仍会继续下去,Novell更把公司内全线电脑的系统换成SUSE LINUX,并同时表示将会把SUSE特有而优秀的系统管理程序 - YaST2以GPL授权释出。
5.Fedora Linux
Fedora是一个知名的Linux发行版,是一款由全球社区爱好者构建的面向日常应用的快速、稳定、强大的操作系统。它允许任何人自由地使用、修改和重发布,无论现在还是将来。它由一个强大的社群开发,这个社群的成员以自己的不懈努力,提供并维护自由、开放源码的软件和开放的标准。
Fedora 约每六个月会发布新版本,美国当地时间2015年11月3日,北京时间2015年11月4日,Fedora Project 宣布 Fedora 23 正式对外发布,2017年6月发布Fedora 26版本。
1.5 32位与64位操作系统的区别
学习Linux操作系统之前,需要理解计算机基本的常识,计算机内部对数据的传输和储存都是使用二进制,二进制是计算技术中广泛采用的一种数制,而Bit(比特)则表示二进制位,二进制数是用0和1两个数码来表示的数。基数为2,进位规则是“逢二进一”,0或者1分别表示一个Bit二进制位。
Bit位是计算机最小单位,而字节是计算机中数据处理的基本单位,转换单位为:1Byte=8Bit,4Byte=32Bit。
随着计算机技术的发展,尤其是中央处理器(Central Processing Unit,CPU)技术的变革,CPU的位数指的是通用寄存器(General-Purpose Registers, GPRs)的数据宽度,也就是处理器一次可以处理的数据量多少。
目前主流CPU处理器分为32位CPU处理器和64位CPU处理器,32位CPU处理器可以一次性处理4个字节的数据量。而64位处理器一次性处理8个字节的数据量(1Byte=8bit),64位CPU处理器对计算机处理器在RAM里(随机存取储存器)处理信息的效率比32位CPU做了很多优化,效率更高。
X86_32位操作系统和X86_64操作系统也是基于CPU位数的支持,具体区别如下:
32位操作系统表示32位CPU对内存寻址的能力;
64位操作系统表示64位CPU对内存寻址的能力;
32位的操作系统安装在32位CPU处理器和64位CPU处理器上;
64位操作系统只能安装64位CPU处理器上;
32位操作系统对内存寻址不能超过4GB;
64位操作系统对内存寻址可以超过4GB,企业服务器更多安装64位操作系统,支持更多内存资源的利用;
64位操作系统是为高性能处理需求设计,数据处理、图片处理、实时计算等领域需求;
32位操作系统是为普通用户设计,普通办公、上网冲浪等需求。
1.6 Linux内核命名规则
Linux内核是Linux操作系统的核心,一个完整的Linux发行版包括进程管理、内存管理、文件系统、系统管理、网络操作等部分。
Linux内核官网可以下载Linux内核版本、现行版本,历史版本,可以了解版本与版本之间的特性。
Linux内核版本命名在不同的时期有其不同的命名规范,其中在2.X版本中,X如果为奇数表示开发版、X如果为偶数表示稳定版,从2.6.X以及3.X,内核版本命名就没有严格的约定规范。
从Linux内核1994年发布1.0发布到目前主流2.6、3.X版本,4.X属于开发调试阶段,查看Linux操作系统内核如图1-2所示:

图1-2操作系统内核
Linux内核命名格式为 “R.X.Y-Z”,其中R、X、Y、Z命名意义如下:
数字R表示内核版本号,版本号只有在代码和内核有重大改变的时候才会改变,到目前为止有4个大版本更新。
数字X表示内核主版本号,主版本号根据传统的奇偶系统版本编号来分配,奇数为开发版,偶数为稳定版。
数字Y表示内核次版本号,次版本号是无论在内核增加安全补丁、修复Bug、实现新的特性或者驱动时都会改变。
数字Z表示内核小版本号,小版本号会随着内核功能的修改、Bug修复而发生变化。
官网内核版本如图1-3所示,Mainline表示主线开发版本,Stable表示稳定版本,稳定版本主要由mainline测试通过而发布。Longterm表示长期支持版,会持续更新及Bug修复,如果长期版本被标记为EOL(End of Life),则表示不再提供更新。

图1-3官网内核版本
第2章 Linux发展及系统安装
互联网飞速发展,用户对网站体验要求也越来越高,目前主流WEB网站后端承载系统均为Linux操作系统,Android手机也是基于Linux内核而研发,企业大数据、云存储、虚拟化等先进技术也均是基于Linux操作系统为载体,满足企业的高速发展。
本章向读者介绍Linux发展前景、Windows与Linux操作系统区别、硬盘分区介绍、CentOS 7 Linux操作系统安装图解及菜鸟学好Linux必备大绝招。
2.1 Linux发展前景及就业形势
权威部门统计,未来几年内我国软件行业的从业机会十分庞大,中国每年对IT软件人才的需求将达到200万人左右。而对于Linux专业人才的就业前景,更是广阔;据悉在未来5-10年内Linux专业人才的需求将达到150万,尤其是有Linux行业经验的,资深的Linux工程师非常缺乏,薪资也非常诱人,平均月薪15000-25000,甚至更高,Linux行业薪资如图2-1所示:

图2-1 Linux行业薪资
2.2 Windows操作系统简介
为什么要学习Windows操作系统呢,了解Windows系统结构,可以让我们快速学习Linux操作系统,通过对比学习的方法,我们可以更快的学会Linux。
计算机硬件组成包括:CPU、内存、网卡、硬盘、DVD光驱、电源、主板、显示器、鼠标等设备,计算机硬件是不能直接被人使用的,需要在其上安装各种操作系统,安装完操作系统,并安装驱动程序,方可进行操作、办公、上网冲浪等。
驱动程序主要指的是设备驱动程序(Device Driver),是一种可以使计算机系统和设备通信的特殊程序,相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备,进行资源调度。
Windows操作系统主要以窗口形式对用户展示,操作系统须安装在硬盘上,安装系统之前需对硬盘进行分区并格式化,默认Windows操作系统安装在C盘分区,D盘分区用于存放数据文件。
通俗的讲,安装操作系统时,需要对磁盘进行格式化,格式化需要指定格式化的类型,告诉操作系统如何去管理磁盘空间,文件如何存放,如何查找及调用。操作系统不知道怎么存放文件以及文件结构,文件系统概念就诞生了。
文件系统是操作系统用于明确磁盘或分区上文件的方法和数据存储结构,文件系统由三部分组成:与文件管理有关软件、被管理文件以及实施文件管理所需数据结构。
Windows操作系统,文件系统类型一般有FAT、FAT16、FAT32、NTFS等,不同的文件系统类型,有不同的特性,例如NTFS文件系统类型支持文件及文件夹安全设置,而FAT32文件系统类型不支持,NTFS支持单文件最多为单个磁盘分区的容量大小2T,而FAT32单个最大文件不能超过4GB。
Windows操作系统从设计层面来讲,主要用来管理电脑硬件与软件资源的程序,大致包括五个方面的管理功能:进程与处理机管理、作业管理、存储管理、设备管理、文件管理。Windwos操作系统从个人使用角度来讲,主要用于个人电脑办公、软件安装、上网冲浪、游戏、数据分析、数据存储等功能。
2.3 硬盘分区简介
学习Windows、Linux操作系统,必然要了解硬盘设备,硬盘是电脑主要的存储媒介之一,硬盘要能够安装系统或者存放数据,必须进行分区和格式化,Windows系统常见分区有三种:主磁盘分区、扩展磁盘分区、逻辑磁盘分区。
一块硬盘设备,主分区至少有1个,最多4个,扩展分区可以为0,最多1个,且主分区+扩展分区总数不能超过4个,逻辑分区可以有若干个。在Windows下激活的主分区是硬盘的启动分区,他是独立的,也是硬盘的第一个分区,通常就是我们所说的C盘系统分区。
扩展分区是不能直接用的,他是以逻辑分区的方式来使用的,扩展分区可分成若干逻辑分区。他们的关系是包含的关系,所有的逻辑分区都是扩展分区的一部分。
在Windows系统安装时,硬盘驱动器是通过磁盘0,磁盘1来显示,其中磁盘0表示第一块硬盘,磁盘1表示第二块硬盘,然后在第一块硬盘磁盘0上进行分区,最多不能超过4个主分区,分区为C、D、E、F。
硬盘接口是硬盘与主机系统间的连接部件,作用是在硬盘缓存和主机内存之间传输数据。不同的硬盘接口决定着硬盘与计算机之间的连接速度,在整个系统中,硬盘接口的优劣直接影响着程序运行快慢和系统性能好坏,常见的硬盘接口类型为:IDE(Integrated Drive Electronics)、SATA(Serial Advanced Technology Attachment)、SCSI(Small Computer System Interface)、SAS(Serial Attached SCSI)和光纤通道等。
IDE接口硬盘多用于家用,部分也应用于传统服务器,SCSI、SAS接口的硬盘则主要应用于服务器市场,而光纤通道用于高端服务器上,SATA主要用于个人家庭办公电脑及低端服务器。
在Linux操作系统中,读者可以看到硬盘驱动器的第一块IDE硬盘接口的硬盘设备为hda,或者SATA硬盘接口的硬盘设备为sda,主分区编号为hda1-4或者sda1-4,逻辑分区从5开始。如果有第二块硬盘,主分区编号为hdb1-4或者sdb1-4。
不管是Windows还是Linux操作系统,硬盘的总容量=主分区的容量+扩展分区的容量,而扩展分区的容量=各个逻辑分区的容量之和。主分区也可成为“引导分区”,会被操作系统和主板认定为这个硬盘的第一个分区,所以C盘永远都是排在所有磁盘分区的第一的位置上。
MBR(Master Boot Record)和GPT(GUID Partition Table)是在磁盘上存储分区信息的两种不同方式。这些分区信息包含了分区从哪里开始的信息,这样操作系统才知道哪个扇区是属于哪个分区的,以及哪个分区是可以启动操作系统的。
在磁盘上创建分区时,必须选择MBR或者GPT,默认是MBR,也可以通过其他方式修改为GPT方式。MBR分区的硬盘最多支持4个主分区,如果想支持更多主分区,可以考虑使用GPT格式分区。
2.4 Linux安装环境准备
要学好Linux这门技术,首先需安装Linux操作系统,Linux操作系统安装是每个初学者的门槛。而安装Linux操作系统,最大的困惑莫过于给操作系统进行磁盘分区。
虽然目前各种发行版本的 Linux 已经提供了友好的图形交互界面,但很多初学者还是感觉无从下手,这其中原因主要是不清楚Linux 的分区规定。
Linux 系统安装中规定,同样每块硬盘设备最多只能分 4个主分区(其中包含扩展分区)构成,任何一个扩展分区都要占用一个主分区号码,也就是在一个硬盘中,主分区和扩展分区一共最多是 4 个。
为了让读者能将本书所有Linux技术应用于企业,本书案例以企业里主流Linux操作系统CentOS为蓝本,目前主流CentOS发行版本为CentOS7.2。
读者在安装CentOS操作系统时,如果没有多余的计算机裸机设备,可以基于Windows主机上安装Vmware workstation工具,该工具的用途可以在Windows主机上创建多个计算机裸机设备资源,包括:CPU、内存、硬盘、网卡、DVD光驱、USB接口、声卡,创建的多个计算机裸机设备共享Windows主机的所有资源。
读者在安装CentOS操作系统时,如果有多余的计算机裸机设备或者企业服务器,可以将CentOS系统直接安装在多余的设备上,安装之前需要下载CentOS7.2操作系统镜像文件(International Organization for Standardization,ISO 9660标准),通过刻录工具,将ISO镜像文件刻录至DVD光盘或者U盘里,通过DVD或者U盘启动然后安装系统。
如下为在Windwos主机上安装VMware workstation虚拟机软件,虚拟机软件的用途是可以在真实机上模拟一个新的计算机完整的资源设备,进而可以在计算机裸设备上安装CentOS7.2操作系统步骤:
(1)安装环境准备
VMware workstation 10.0
CentOS 7.2 x86_64
(2)Vmware Workstation 10.0下载
http://download3.vmware.com/software/wkst/file/VMware-workstation-full-10.0.1-1379776.exe
(3)CentOS7.2操作系统ISO镜像下载
http://124.205.69.165/files/706900000291EB25/mirror.math.princeton.edu/pub/CentOS/7/isos/x86_64/CentOS-7-x86_64-DVD-1511.iso
(4)将VMware workstation 10.0和CentOS7 ISO镜像文件下载至Windows系统,双击VMware-workstation-full-10.0.1-1379776.exe,根据提示完成安装,会在Windows桌面显示VMware Workstation图标,如图2-2所示:

图2-2 VMware Workstation图标
(5)双击桌面VMware Workstation图标打开虚拟机软件,单击“创建新的虚拟机”,如图2-3所示:

图2-3 VMware Workstation创建虚拟机

(6)新建虚拟机向导,选择自定义(高级)(C)选项,如图2-4所示:

图2-4 创建虚拟机向导
(7)安装客户机操作系统,选择“稍后安装操作系统(S)”,如图2-5所示:

图2-5 安装客户机操作系统
(8)选择客户机操作系统,由于我们即将安装CentOS7.2操作系统,所以需要勾选“Linux(L)”,同时版本(V)选择“CentOS64位”,如图2-6所示:

图2-6 操作系统版本
(9)虚拟机内存设置,默认为1024MB,如图2-7所示:

图2-7 虚拟机内存分配
(10)选择虚拟机网络类型,此处选择-网络连接为-“使用桥接模式”,如图2-8所示:

图2-8 虚拟机网络类型
(11)指定磁盘容量,设置虚拟机硬盘大小为40GB,将虚拟磁盘拆分成多个文件,如下图2-9所示:

图2-9设置虚拟机磁盘容量
(12)虚拟机硬件资源创建完成,设备详情里面包括计算机常用设备,例如内存、处理器、硬盘、CD/DVD、网络适配器等,如图2-10所示:

图2-10虚拟机裸机设备
(13)将CentOS7.2 ISO系统镜像文件添加至虚拟机CD/DVD中,双击虚拟机“CD/DVD(IDE)自动检测”选项,选择CentOS-7-x86_64-DVD-1511.iso镜像文件,如图2-11所示:

图2-11选择系统安装镜像
2.5 Linux系统安装图解
如果直接在硬件设备上安装CentOS系统,不需要安装虚拟机等步骤,直接将U盘或者光盘插入DVD光驱即可,打开电源设备。
(1)如图2-12所示,光标选择Install CentOS 7,直接按Enter键进行系统安装。

图2-12选择安装菜单
(2)继续按Enter键启动安装进程,进入光盘检测,按Esc键跳过检测,如图2-13所示:

图2-13跳过ISO镜像检测
(3)CentOS7欢迎界面,选择安装过程中界面显示的语言,初学者可以选择“简体中文”或者默认English,如图2-14所示:

图2-14选择安装过程语言
(4)CentOS7 Installation Summary安装总览界面,如图2-15所示:

图2-15 Installation Summary界面
(5)选择“I will configure partioning.”,单击Done,如图2-16所示:

图2-16 磁盘分区方式选择
(6)下拉框选择“Standard Partition”,选择+号,创建分区,如图2-17所示:

图2-17 磁盘分区类型选择
(7)Linux操作系统分区与Windows操作系统分区C盘、D盘有很大区别,Liunx操作系统是采用树形的文件系统管理方式,所有的文件存储以/(根)开始,如图2-18所示。

图2-18 Linux文件系统目录结构
Linux是以文件的方式存储,例如/dev/sda代表整块硬盘,/dev/sda1表示硬盘第一分区,/dev/sda2表示硬盘第二分区,为了能将目录和硬盘分区关联,所以Linux采用挂载点的方式来关联磁盘分区,/boot目录、/根目录、/data目录跟磁盘管理后,称之为分区,每个分区功能如下:
/boot分区用于存放Linux内核及系统启动过程所需文件;
Swap分区又称为交换分区,类似Windows系统的虚拟内存,物理内存不够用时,以供程序使用Swap内存;
/分区用于系统安装核心分区及所有文件存放的根系统;
/data分区为自定义分区,企业服务器中用于作应用数据存放。
如图2-19所示,创建/boot分区并挂载,分区大小为200MB:

图2-19 创建/boot分区
单击“Add mount point”即可,磁盘分区默认文件系统类型为XFS,根据如上方法,依次创建swap分区,大小为2048MB,创建/分区,大小为剩余所有空间,最终如图2-20所示:

图2-20 磁盘完整分区
(8)选择SOFTWARE SELECTION,设置为Minimal Install最小化安装,如果后期需要开发包、开发库等软件,可以在系统安装完后,根据需求安装即可,如图2-21所示:

图2-21 选择安装的软件
(9)操作系统时区选择,选择Asia-Shanghai,关闭Network Time,如图2-22所示:

图2-22 操作系统时区选择
(10)以上配置完毕后,单击“Begin Installation”,单击“Root PASSWORD”设置Root用户密码,如图2-23所示,如果需要新增普通用户,可以单击“USER CREATEION”进行创建即可。

图2-23 设置ROOT用户密码
(11)安装进程完毕,单击“Reboot”重启系统,如图2-24所示:

图2-24 系统安装完毕
(12)重启CentOS 7 Linux操作系统,进入Login登录界面,“localhost login:”处输入root,按Enter键,然后“Password:”处输入系统安装时设定的密码,输入密码时不会提示,密码输入完按Enter键,即可登录CentOS 7 Linux操作系统,默认登录的终端称为Shell终端,所有的后续操作指令均在Shell终端上执行,默认显示字符提示[root@localhost ~]#,其中#代表当前是root用户登录,如果是$表示当前为普通用户。如图2-25所示:

图2-25 Login登录系统界面
2.6 菜鸟学好Linux大绝招
系统安装是初学者的门槛,系统安装完毕后,很多初学者不知道该如何学习,不知道如何快速进阶,下面作者总结了菜鸟学好Linux技能的大绝招:
初学者完成Linux系统分区及安装之后,需熟练掌握Linux系统管理必备命令,命令包括:cd、ls、pwd、clear、chmod、chown、chattr、useradd、userdel、groupadd、vi、vim、cat、more、less、mv、cp、rm、rmdir、touch、ifconfig、ip addr、ping、route、echo、wc、expr、bc、ln、head、tail、who、hostname、top、df、du、netstat、ss、kill、alias、man、tar、zip、unzip、jar、fdisk、free、uptime、lsof、lsmod、lsattr、dd、date、crontab、ps、find、awk、sed、grep、sort、uniq等,每个命令至少练习30遍,逐步掌握每个命令的用法及应用场景;
初学者进阶之路,需熟练构建Linux下常见服务(DHCP、SAMBA、DNS、Apache、MySQL、Nginx、Zabbix、Squid、Varnish、LVS、Keepalived、ELK、MQ、Zookeeper、Docker、Openstack、Hbase、Mongodb、Redis等,遇到问题先思考,没有头绪可以借助百度、Google搜索引擎,问题解决后,将解决问题的步骤总结并形成文档;
理解操作系统的每个命令,每个服务的用途,为什么要配置这个服务,为什么需要调整该参数,只有带着目标去学习才能更快的成长,才能让你去发掘更多新知识;
熟练搭建Linux系统上各种服务之后,需要理解每个服务的完整配置和优化,可以拓展思维。例如LAMP所有服务放在一台机器上,能否分开放在多台服务器以平衡压力呢,该如何去构建和部署呢?一台物理机构建Docker虚拟化,如果是100台、1000台如何去实施呢,会遇到哪些问题呢;
Shell是Linux最经典的命令解释器,Shell脚本可以实现自动化运维,平时多练习Shell脚本编程,每个Shell脚本多练习几遍,从中吸取关键的参数、语法,不断的练习,不断的提高;
建立个人学习博客,把平时工作、学习中的知识都记录到博客,一方面可以供别人参考,另一方面可以提高自己文档编写及总结的能力;
学习Linux技术是一个长期的过程,一定要坚持,遇到各种错误、问题可以借助百度、Google搜索引擎,如果解决不了,可以请教同学、朋友及你的老师;
通过以上步骤的学习方法,不断进步,如果想达到高级、资深大牛级别,还需要进一步深入学习WEB集群架构、网站负载均衡、网站架构优化、自动化运维、运维开发、虚拟化等知识;
多练习才是硬道理,实践出真知。
2.7 本章小结
通过对本章内容的学习,读者对Linux系统有了一个初步的理解,了解Linux行业的发展前景,学会了如何在企业中或者虚拟机中安装Linux系统。
对32位、64位CPU处理器以及对Linux内核版本命名也有进一步的认识,同时掌握了学习Linux的大绝招。
2.8 同步作业
1.企业中服务器品牌DELL R730,其硬盘总量为300G,现需安装CentOS 7 Linux操作系统,请问如何进行分区?
2.GNU与GPL的区别是什么?
3.企业一台Linux服务器,查看该Linux内核显示:3.10.0-327.36.3.el7.x86_64,请分别说出点号分割的每个数字及字母的含义?
4.CentOS Linux至今发布了多少个系统版本?
5.如果Linux系统采用光盘安装,如何将ISO镜像文件刻录成光盘,请写出具体实现流程?
第3章 CentOS系统管理
Linux系统安装完毕,需要对Linux系统进行管理和维护,让Linux服务器能真正应用于企业中。
本章向读者介绍Linux系统引导原理、启动流程、系统目录、权限、命令及CentOS7和CentOS6在系统管理、命令方面有什么区别,让我们一起来遨游在Linux的海洋里。
3.1 操作系统启动概念
不管是Windows还是Linux操作系统,底层设备一般均为物理硬件,操作系统启动之前会对硬件进行检测,然后硬盘引导启动操作系统,如下为操作系统启动相关的各个概念:
3.1.1 BIOS
基本输入输出系统(Basic Input Output System,BIOS)是一组固化到计算机主板上的只读内存镜像(Read Only Memory image,ROM)芯片上的程序,它保存着计算机最重要的基本输入输出的程序、系统设置信息、开机后自检程序和系统自启动程序。主要功能是为计算机提供最底层的、最直接的硬件设置和控制。
3.1.2 MBR
全新硬盘在使用之前必须进行分区格式化,硬盘分区初始化的格式主要由两种,分别是:MBR格式和GPT格式。
如果使用MBR格式,操作系统将创建主引导记录扇区(Main Boot Record,MBR),MBR位于整块硬盘的0磁道0柱面1扇区,主要功能是操作系统对磁盘进行读写时,判断分区的合法性以及分区引导信息的定位。
主引导扇区总共为512字节,MBR只占用了其中的446个字节,另外的64个字节为硬盘分区表 (Disk Partition Table,DPT),最后两个字节“55,AA”是分区的结束标志。
在MBR硬盘中,硬盘分区信息直接存储于主引导记录(MBR)中,同时主引导记录还存储着系统的引导程序,如图3-1所示:
图3-1 MBR分区表内容
MBR是计算机启动最先执行的硬盘上的程序,只有512字节大小,所以不能载入操作系统的核心,只能先载入一个可以载入计算机核心的程序,我们称之为引导程序。
因为MBR分区标准决定了MBR只支持在2TB以下的硬盘,对于后面的多余空间只能浪费。为了支持能使用大于2T硬盘空间,微软和英特尔公司在可扩展固件接口(Extensible Firmware Interface,EFI)方案中开发了全局唯一的标识符(Globally unique identifier,GUID),进而全面支持大于2T硬盘空间在企业中使用。
3.1.3 GPT
全局唯一的标识符(Globally unique identifier,GUID),正逐渐取代MBR成为新标准。它和统一的可扩展固件接口 (Unified Extensible Firmware Interface,UEFI)相辅相成。
UEFI用于取代老旧的BIOS,而GPT则取代老旧的MBR。之所以称为“GUID分区表”,是因为驱动器上的每个分区都有一个全局唯一的标识符。
在GPT硬盘中,分区表的位置信息储存在GPT头中。出于兼容性考虑,第一个扇区同样有一个与MBR类似的标记,叫做受保护的主引导记录(Protected Main Boot Record,PMBR)。
PMBR的作用是当使用不支持GPT的分区工具时,整个硬盘将显示为一个受保护的分区,以防止分区表及硬盘数据遭到破坏,而其中存储的内容和MBR一样,之后才是GPT头。
GPT优点支持2T以上磁盘,如果使用Fdisk分区,最大只能建立2TB大小的分区,创建大于2TB的分区,需使用parted,同时必须使用64位操作系统,Mac、Linux系统都能支持GPT分区格式,Windows 7/8 64bit、Windows Server 2008 64bit支持GPT。图3-2所示,为GPT硬盘分区表内容:

图3-2 GPT分区表内容
3.1.4 GRUB
GNU项目的多操作系统启动程序(GRand Unified Bootloader,GRUB),可以支持多操作系统的引导,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。
GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。它是一个多重操作系统启动管理器。用来引导不同系统,如Windows,Linux。Linux常见的引导程序包括:LILO、GRUB、GRUB2,CentOS 7 Linux默认使用GRUB2引导程序,引导系统启动。如图3-3所示为GRUB加载引导流程:

图3-3 GRUB引导流程
GRUB2是基于GRUB开发成更加安全强大的多系统引导程序,最新Linux发行版都是使用GRUB2作为引导程序。同时GRUB2采用了模块化设计,使得GRUB2核心更加精炼,使用更加灵活,同时也就不需要像GRUB分为stage1,stage1.5,stage2三个阶段。
3.2 Linux操作系统启动流程
初学者对Linux操作系统启动流程的理解,能有助于后期在企业中更好的维护Linux服务器,能快速定位系统问题,进而解决问题。Linux操作系统启动流程如图3-4所示:

图3-4 系统启动流程
(1)加载BIOS
计算机电源加电质检,首先加载基本输入输出系统(Basic Input Output System,BIOS),BIOS中包含硬件CPU、内存、硬盘等相关信息,包含设备启动顺序信息、硬盘信息、内存信息、时钟信息、即插即用(Plug-and-Play,PNP)特性等。加载完BIOS信息,计算机将根据顺序进行启动。
(2)读取MBR
读取完BIOS信息,计算机将会查找BIOS所指定的硬盘MBR引导扇区,将其内容复制到0x7c00地址所在的物理内存中。被复制到物理内存的内容是Boot Loader,然后进行引导。
(3)GRUB引导
GRUB启动引导器是计算机启动过程中运行的第一个软件程序,当计算机读取内存中的GRUB配置信息后,会根据其配置信息来启动硬盘中不同的操作系统。
(4)加载Kernel
计算机读取内存映像,并进行解压缩操作,屏幕一般会输出“Uncompressing Linux”的提示,当解压缩内核完成后,屏幕输出“OK, booting the kernel”。系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。
(5)设定Inittab运行等级
内核加载完毕,会启动Linux操作系统第一个守护进程init,然后通过该进程读取/etc/inittab文件,/etc/inittab文件的作用是设定Linux的运行等级,Linux常见运行级别如下:
0:关机模式;
1:单用户模式;
2:无网络支持的多用户模式;
3:字符界面多用户模式;
4:保留,未使用模式;
5:图像界面多用户模式;
6:重新引导系统,重启模式。
(6)加载rc.sysinit
读取完运行级别,Linux系统执行的第一个用户层文件/etc/rc.d/rc.sysinit,该文件功能包括:设定PATH运行变量、设定网络配置、启动swap分区、设定/proc、系统函数、配置Selinux等。
(7)加载内核模块
读取/etc/modules.conf文件及/etc/modules.d目录下的文件来加载系统内核模块。该模块文件,可以后期添加或者修改及删除。
(8)启动运行级别程序
根据之前读取的运行级别,操作系统会运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。其中以S开头表示系统即将启动的程序,如果以K开头,则代表停止该服务。S和K后紧跟的数字为启动顺序编号。如图3-5所示:图3-5 运行级别服务
(9)读取rc.local文件
操作系统启动完相应服务之后,会读取执行/etc/rc.d/rc.local文件,可以将需要开机启动的任务加入到该文件末尾,系统会逐行去执行并启动相应命令,如图3-6所示:

图3-6 开机运行加载文件
(10)执行/bin/login程序
执行/bin/login程序,启动到系统登录界面,操作系统等待用户输入用户名和密码,即可登录到Shell终端,如图3-7所示,输入用户名、密码即可登录Linux操作系统,至此Linux操作系统完整流程启动完毕。

图3-7 系统登录界面
3.3 CentOS6与CentOS7区别
CentOS6默认采用Sysvinit风格,Sysvinit就是system V风格的init系统,Sysvinit用术语runlevel 来定义"预订的运行模式"。Sysvinit 检查 '/etc/inittab' 文件中是否含有'initdefault' 项,该选项指定init的默认运行模式。Sysvinit 使用脚本,文件命名规则和软链接来实现不同的Runlevel,串行启动各个进程及服务。
CentOS7默认采用Systemd风格,Systemd是Linux系统中最新的初始化系统(init),它主要的设计目标是克服 Sysvinit 固有的缺点,提高系统的启动速度。
Systemd 和 Ubuntu 的 Upstart 是竞争对手,预计会取代 UpStart。Systemd的目标是尽可能启动更少的进程,尽可能将更多进程并行启动。如图3-8所示为CentOS6与CentOS7操作系统的区别:
图3-8 CentOS6与CentOS7操作系统区别
Linux操作系统文件系统类型主要由EXT3、EXT4、XFS等,其中CentOS6普遍采用EXT3和EXT4文件系统格式,而CentOS7默认采用XFS格式。如下为EXT3、EXT4、XFS区别:
EXT4是第四代扩展文件系统(Fourth EXtended filesystem,EXT4)是Linux系统下的日志文件系统,是EXT3文件系统的后继版本;
EXT3类型文件系统支持最大16TB文件系统和最大2TB文件;
EXT4分别支持1EB(1EB=1024PB,1PB=1024TB)的文件系统,以及16TB的单个文件;
EXT3只支持32,000个子目录,而EXT4支持无限数量的子目录;
EXT4磁盘结构的inode个数支持40亿,而且EXT4的单个文件大小支持到16T(4K block size)  ;
XFS是一个64位文件系统,最大支持8EB减1字节的单个文件系统,实际部署时取决于宿主操作系统的最大块限制,常用语64位操作系统,发挥更好的性能;
XFS一种高性能的日志文件系统,最早于1993年,由Silicon Graphics为他们的IRIX操作系统而开发,是IRIX 5.3版的默认文件系统;
XFS于2000年5月,Silicon Graphics以GPL发布这套系统的源代码,之后被移植到Linux内核上,XFS特别擅长处理大文件,同时提供平滑的数据传输。
3.4 TCP/IP协议概述
要学好Linux,对网络协议也要有充分的了解和掌握,例如传输控制协议/因特网互联协议(Transmission Control Protocol/Internet Protocol,TCP/IP),TCP/IP名为网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。
TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地,而IP是给因特网的每台联网设备规定一个地址。
基于TCP/IP的参考模型将协议分成四个层次,它们分别是网络接口层、网际互连层(IP层)、传输层(TCP层)和应用层。如图3-9为TCP/IP跟OSI参考模型层次的对比:

图3-9 ISO7层模型与TCP/IP四层对比
  OSI模型与TCP/IP模型协议功能实现对照表,如图3-10所示:

图3-10 ISO7层模型与TCP/IP层次功能对比
3.5 IP地址及网络常识
互联网协议地址(Internet Protocol Address,IP),IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。IP地址被用来给Internet上的每个通信设备的一个编号,每台联网的PC上都需要有IP地址,这样才能正常通信。
IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(即4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。
常见的IP地址,分为IPv4与IPv6两大类。IP地址编址方案将IP地址空间划分为A、B、C、D、E五类,其中A、B、C是基本类,D、E类作为多播和保留使用。
IPV4有4段数字,每一段最大不超过255。由于互联网的蓬勃发展,IP位址的需求量愈来愈大,使得IP位址的发放愈趋严格,各项资料显示全球IPv4位址在2011年已经全部分发完毕。
地址空间的不足必将妨碍互联网的进一步发展。为了扩大地址空间,拟通过IPv6重新定义地址空间。IPv6采用128位地址长度。在IPv6的设计过程中除了一劳永逸地解决了地址短缺问题以外,IPV6的诞生可以给全球每一粒沙子配置一个IP地址,还考虑了在IPv4中解决不好的其它问题,如图3-11所示:

图3-11 IPV4与IPV6地址
3.5.1IP地址分类
IPV4地址编址方案有A、B、C、D、E五类,其中A、B、C是基本类,D、E类作为多播和保留使用,如下为分类详解:
1.A类IP地址
一个A类IP地址是指,在IP地址的四段号码中,第一段号码为网络号码,剩下的三段号码为本地计算机的号码。如果用二进制表示IP地址的话,A类IP地址就由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”。A类IP地址中网络的标识长度为8位,主机标识的长度为24位,A类网络地址数量较少,有126个网络,每个网络可以容纳主机数达1600万台。
A类IP地址 地址范围1.0.0.0到127.255.255.255 (二进制表示为:00000001 00000000 00000000 00000000 - 01111110 11111111 11111111 11111111),最后一个为广播地址,A类IP地址的子网掩码为255.0.0.0,每个网络支持的最大主机数为256的3次方-2=16777214台。
2.B类IP地址
一个B类IP地址是指在IP地址的四段号码中,前两段号码为网络号码。如果用二进制表示IP地址的话,B类IP地址就由2字节的网络地址和2字节主机地址组成,网络地址的最高位必须是“10”。
B类IP地址中网络的标识长度为16位,主机标识的长度为16位,B类网络地址适用于中等规模的网络,有16384个网络,每个网络所能容纳的计算机数为6万多台。
B类IP地址地址范围128.0.0.0-191.255.255.255(二进制表示为:10000000 00000000 00000000 00000000----10111111 11111111 11111111 11111111)。
最后一个是广播地址,B类IP地址的子网掩码为255.255.0.0,每个网络支持的最大主机数为256的2次方-2=65534台。
3.C类IP地址
一个C类IP地址是指在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码。如果用二进制表示IP地址的话,C类IP地址就由3字节的网络地址和1字节主机地址组成,网络地址的最高位必须是“110”。C类IP地址中网络的标识长度为24位,主机标识的长度为8位,C类网络地址数量较多,有209万余个网络。适用于小规模的局域网络,每个网络最多只能包含254台计算机。
C类IP地址范围192.0.0.0-223.255.255.255[3] (二进制表示为: 11000000 00000000 00000000 00000000 - 11011111 11111111 11111111 11111111)。C类IP地址的子网掩码为255.255.255.0,每个网络支持的最大主机数为256-2=254台。
4.D类IP地址
D类IP地址又称之为多播地址(Multicast Address),即组播地址。在以太网中,多播地址命名了一组应该在这个网络中应用接收到一个分组的站点。多播地址的最高位必须是“1110”,范围从224.0.0.0到239.255.255.255。
5.特殊的地址
每一个字节都为0的地址(“0.0.0.0”)表示当前主机,IP地址中的每一个字节都为1的IP地址(“255.255.255.255”)是当前子网的广播地址,IP地址中凡是以“11110”开头的E类IP地址都保留用于将来和实验使用。
IP地址中不能以十进制“127”作为开头,而以数字127.0.0.1到127.255.255.255段的IP地址称为回环地址,用于回路测试,如:127.0.0.1可以代表本机IP地址,网络ID的第一个8位组也不能全置为“0”,全“0”表示本地网络。
3.5.2子网掩码
子网掩码(Subnet Mask)又名网络掩码、地址掩码,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。
通常的讲,子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。
子网掩码是一个32位地址,用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址是在局域网上,还是在远程网上。
对于A类地址,默认的子网掩码是255.0.0.0,而对于B类地址来说默认的子网掩码是255.255.0.0;对于C类地址来说默认的子网掩码是255.255.255.0。
互联网是由各种小型网络构成的,每个网络上都有许多主机,这样便构成了一个有层次的结构。IP地址在设计时就考虑到地址分配的层次特点,将每个IP地址都分割成网络号和主机号两部分,以便于IP地址的寻址操作。
子网掩码的设定必须遵循一定的规则。与二进制IP地址相同,子网掩码由1和0组成,且1和0分别连续。子网掩码的长度也是32位,左边是网络位,用二进制数字“1”表示,1的数目等于网络位的长度;右边是主机位,用二进制数字“0”表示,0的数目等于主机位的长度。
3.5.3网关地址
网关(Gateway)是一个网络连接到另一个网络的“关口”, 网关实质上是一个网络通向其他网络的IP地址。主要用于不同网络传输数据。
例如我们电脑设备上网,如果是接入到同一个交换机,在交换机内部传输数据是不需要经过网关的,但是如果两台设备不在一个交换机网络,则需要在本机配置网关,内网服务器的数据通过网关,网关把数据转发到其他的网络的网关,直至找到对方的主机网络,然后返回数据。
3.5.4MAC地址
媒体访问控制(Media Access Control或者Medium Access Control,MAC),也即是物理地址、硬件地址,用来定义网络设备的位置。
在OSI模型中,第三层网络层负责 IP地址,第二层数据链路层则负责 MAC地址。因此一个主机会有一个MAC地址,而每个网络位置会有一个专属于它的IP地址。
IP地址工作在OSI参考模型的第三层网络层。两者之间分工明确,默契合作,完成通信过程。IP地址专注于网络层,将数据包从一个网络转发到另外一个网络;而MAC地址则专注于数据链路层,将一个数据帧从一个节点传送到相同链路的另一个节点。
IP地址和MAC地址一般是成对出现。如果一台计算机要和网络中另一外计算机通信,那么这两台设备必须配置IP地址和MAC地址,而MAC地址是网卡出厂时设定的,这样配置的IP地址就和MAC地址形成了一种对应关系。
在数据通信时,IP地址负责表示计算机的网络层地址,网络层设备(如路由器)根据IP地址来进行操作;MAC地址负责表示计算机的数据链路层地址,数据链路层设备,根据MAC地址来进行操作。IP和MAC地址这种映射关系是通过地址解析协议(Address Resolution Protocol,ARP)来实现的。
3.6 Linux系统配置IP
Linux操作系统安装完毕,那接下来如何让Linux操作系统能上外网呢?如下为Linux服务器配置IP的方法。
Linux服务器网卡默认配置文件在/etc/sysconfig/network-scripts/下,命名的名称一般为:ifcfg-eth0 ifcfg-eth1 ,eth0表示第一块网卡,eth1表示第二块网卡,依次类推,例如DELL R720标配有4块千兆网卡,在系统显示的名称依次为:eth0、eth1、eth2、eth3。
修改服务器网卡IP地址命令为vi /etc/sysconfig/network-scripts/ifcfg-eth0 (注CentOS7网卡名ifcfg-eno16777736)。vi命令打开网卡配置文件,默认为DHCP方式,配置如下:
DEVICE=eth0
BOOTPROTO=dhcp
HWADDR=00:0c:29:52:c7:4e
ONBOOT=yes
TYPE=Ethernet
vi命令打开网卡配置文件,修改BOOTPROTO为DHCP方式,同时添加IPADDR、NETMASK、GATEWAY信息如下:
DEVICE=eth0
BOOTPROTO=static
HWADDR=00:0c:29:52:c7:4e
ONBOOT=yes
TYPE=Ethernet
IPADDR=192.168.1.103
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
服务器网卡配置文件,详细参数如下:
DEVICE=eth0 #物理设备名
ONBOOT=yes # [yes|no](重启网卡是否激活网卡设备)
BOOTPROTO=static #[none|static|bootp|dhcp](不使用协议|静态分配|BOOTP协议|DHCP协议)
TYPE=Ethernet #网卡类型
IPADDR=192.168.1.103 #IP地址
NETMASK=255.255.255.0 #子网掩码
GATEWAY=192.168.1.1 #网关地址
服务器网卡配置完毕后,重启网卡服务:/etc/init.d/network restart 即可。
然后查看ip地址,命令为:ifconfig或者ip addr show 查看当前服务器所有网卡的IP地址。
CentOS 7 Linux中,如果没有ifconfig命令,可以用ip addr list/show查看,也可以安装ifconfig命令,需安装软件包net-tools,命令如图3-12所示:
yum install net-tools -y

图3-12 YUM安装net-tools工具
3.7 Linux系统配置DNS
如上网卡IP地址配置完毕,如果服务器需上外网,还需配置域名解析地址(Domain Name System,DNS),DNS主要用于将请求的域名转换为IP地址,DNS地址配置方法如下:
修改vi /etc/resolv.conf 文件,在文件中加入如下两条:
nameserver 202.106.0.20
nameserver 8.8.8.8
如上分别表示主DNS于备DNS,DNS配置完毕后,无需重启网络服务,DNS是立即生效。
可以ping -c 6 www.baidu.com 查看返回结果,如果有IP返回,则表示服务器DNS配置正确,如图3-13所示:

图3-13 ping命令返回值
3.8 Linux网卡名称命名
CentOS7服务器,默认网卡名为ifcfg-eno16777736,如果我们想改成ifcfg-eth0,使用如下步骤即可:
(1)编辑/etc/sysconfig/grub文件,命令为vi /etc/sysconfig/grub,在倒数第二行quiet后加入如下代码,并如图3-14所示:
net.ifnames=0 biosdevname=0

图3-14 网卡配置ifnames设置
(2)执行命令grub2-mkconfig -o /boot/grub2/grub.cfg,生成新的grub.cfg文件,如图3-15所示:
grub2-mkconfig -o /boot/grub2/grub.cfg

图3-15 生成新的grub.cnf文件
(3)重命名网卡名称,执行命令mv ifcfg-eno16777736 ifcfg-eth0,修改ifcfg-eth0文件中DEVICE= eno16777736为DEVICE= eth0,如图3-16所示:
图3-16 重命名网卡名称
(4)重启服务器,并验证网卡名称是否为eth0,Reboot完后,如图3-17所示:
图3-17 验证网卡设备名称
3.9 CentOS7密码重置
修改CentOS7 ROOT密码非常简单,只需登录系统,执行命令passwd回车即可,但是如果忘记ROOT,无法登录系统,该如何去重置ROOT用户的密码呢?如下为重置ROOT用户的密码的方法:
(1)Reboot重启系统,系统启动进入欢迎界面,加载内核步骤时,按e,然后选中“CentOS Linux (3.10.0-327.e17.x86_64)7 (Core)”,如图3-18所示:

图3-18 内核菜单选择界面
(2)继续按e进入编辑模式,找到ro crashkernel=auto xxx项,将ro改成rw init=/sysroot/bin/sh,如图3-19所示:

图3-19 内核编辑界面
(3)修改为后如图3-20所示:

图3-20 内核编辑界面
(4)按ctrl+x按钮进入单用户模式,如图3-21所示:

图3-21 进入系统单用户模式
(5)执行命令chroot /sysroot访问系统,并使用passwd修改root密码,如图3-22所示:

图3-22 修改ROOT用户密码
(6)更新系统信息,touch /.autorelabel,执行命令touch /.autorelabel,在/目录下创建一个.autorelabel文件,如果该文件存在,系统在重启时就会对整个文件系统进行relabeling重新标记,可以理解为对文件进行底层权限的控制和标记,如果seLinux属于disabled关闭状态则不需要执行这条命令,如图3-23所示:

图3-23 创建autorelabel文件
3.10 远程管理Linux服务器
系统安装完毕后,可以通过远程工具来连接到Linux服务器,远程连接服务器管理的好处在于可以跨地区管理服务器,例如读者在北京,想管理的服务器在上海某IDC机房,通过远程管理后,不需要到IDC机房现场去操作,直接通过远程工具即可管理,与在现场的管理是一模一样。
远程管理Linux服务器要满足如下三个步骤:
(1)服务器配置IP地址,如果服务器在公网,需配置公网IP,如果服务器在内部局域网,可以直接配置内部私有IP即可;
(2)服务器安装SSHD软件服务并启动该服务,几乎所有的Linux服务器系统安装完毕均会自动安装并启动SSHD服务,SSHD服务监听22端口,关于SSHD服务、OpenSSH及SSH协议后面章节会讲解;
(3)在服务器中防火墙服务需要允许22端口对外开放,初学者可以临时关闭防火墙,CentOS6 Linux关闭防火墙的命令:service iptables stop,而CentOS7 Linux关闭防火墙的命令:systemctl stop firewalld.service。
常见的Linux远程管理工具包括:SecureCRT、Xshell、Putty、Xmanger等工具。目前主流的远程管理Linux服务器工具为SecureCRT,官网https://www.vandyke.com 下载并安装SecureCRT,打开工具,点击左上角quick connect快速连接,弹出界面如图3-24所示,连接配置具体步骤如下:
协议(P):选择SSH2
主机名(H):输入Linux服务器IP地址
端口(o): 22
防火墙(F):None
用户名(U):root
单击下方的“连接”,会提示输入密码,输入root用户对应密码即可。

图3-24 SecureCRT远程Linux服务器
通过SecureCRT远程连接Linux服务器之后,会发现如图3-25所示界面,与服务器本地操作界面一样,在命令行可以执行命令,操作结果与在服务器现场操作是一样。

图3-25 SecureCRT远程Linux服务器
3.11 Linux系统目录功能
通过以上知识的学习,读者已经能够独立安装并配置Linux服务器IP并远程连接,为了进一步学习Linux,需熟练掌握Linux系统各个目录的功能。
Linux主要树结构目录包括:/、/root、/home、/usr、/bin、/tmp、/sbin、/proc、/boot等,如图3-26所示,为典型的Linux目录结构如下:

图3-26 Linux目录树形结构
Linux系统中常见目录功能如下:
/ 根目录;
/bin 存放必要的命令;
/boot 存放内核以及启动所需的文件;
/dev 存放硬件设备文件;
/etc 存放系统配置文件;
/home 普通用户的宿主目录,用户数据存放在其主目录中; 
/lib|lib64 存放必要的运行库;
/mnt 存放临时的映射文件系统,通常用来挂载使用;
/proc 存放存储进程和系统信息;
/root 超级用户的主目录;
/sbin 存放系统管理程序;
/tmp 存放临时文件;
/usr 存放应用程序,命令程序文件、程序库、手册和其它文档;
/var 系统默认日志存放目录。
第4章 Linux必备命令
Linux系统启动默认为字符界面,一般不会启动图形界面,所以对命令行的熟练程度能更加方便、高效的管理Linux系统。
本章向读者介绍Linux系统必备命令各项参数及功能场景,Linux常见命令包括:cd、ls、pwd、mkdir、rm、cp、mv、touch、cat、head、tail、chmod、vim等。
4.1 cd命令详解
cd命令主要用于目录切换,例如:cd /home切换至/home目录,cd /root表示切换至/root目录 ;cd ../切换至上一级目录;cd ./切换至当前目录。
其中.和..可以理解为相对路径,例如cd ./test表示以当前目录为参考,表示相对于当前,而cd /home/test表示完整的路径,理解为绝对路径),如图4-1所示:

图4-1 Linux cd命令操作
4.2 ls命令详解
ls命令主要用于浏览目录下的文件或者文件夹,使用方法参考:ls ./ 查看当前目录所有的文件和目录,ls -a 查看所有的文件,包括隐藏文件,以.开头的文件,常用参数详解如下:
-a, --all 不隐藏任何以. 开始的项目;
-A, --almost-all 列出除. 及.. 以外的任何项目;
--author 与-l 同时使用时列出每个文件的作者;
-b, --escape 以八进制溢出序列表示不可打印的字符;
--block-size=大小 块以指定大小的字节为单位;
-B, --ignore-backups 不列出任何以"~"字符结束的项目;
-d, --directory 当遇到目录时列出目录本身而非目录内的文件;
-D, --dired 产生适合Emacs 的dired 模式使用的结果;
-f 不进行排序,-aU 选项生效,-lst 选项失效;
-i, --inode 显示每个文件的inode 号;
-I, --ignore=PATTERN 不显示任何符合指定shell PATTERN 的项目;
-k 即--block-size=1K;
-l 使用较长格式列出信息;
-n, --numeric-uid-gid 类似 -l,但列出UID 及GID 号;
-N, --literal 输出未经处理的项目名称 (如不特别处理控制字符) ;
-r, --reverse 排序时保留顺序;
-R, --recursive 递归显示子目录;
-s, --size 以块数形式显示每个文件分配的尺寸;
-S 根据文件大小排序;
-t 根据修改时间排序;
-u 同-lt 一起使用:按照访问时间排序并显示;
同-l一起使用:显示访问时间并按文件名排序;
其他:按照访问时间排序;
-U 不进行排序;按照目录顺序列出项目;
-v 在文本中进行数字(版本)的自然排序。
4.3 pwd命令详解
pwd命令主要用于显示或者查看当前所在的目录路径,如图4-2所示:

图4-2 pwd命令查看当前目录
4.4 mkdir命令详解
mkdir命令主要用于创建目录,用法mkdir dirname,命令后接目录的名称,常用参数详解如下:
用法:mkdir [选项]... 目录;若指定目录不存在则创建目录;
长选项必须使用的参数对于短选项时也是必需使用的;
-m, --mode=模式 设置权限模式(类似chmod),而不是rwxrwxrwx 减umask;
-p, --parents 需要时创建目标目录的上层目录,但即使这些目录已存在也不当作错误处理;
-v, --verbose 每次创建新目录都显示信息;
-Z, --context=CTX 将每个创建的目录的SELinux 安全环境设置为CTX;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出。
4.5 rm命令详解
rm 命令主要用于删除文件或者目录,用法 rm –rf test.txt (-r表示递归,-f表示强制),常用参数详解如下:
用法:rm [选项]... 文件...删除 (unlink) 文件。
-f, --force 强制删除。忽略不存在的文件,不提示确认;
-i 在删除前需要确认;
-I 在删除超过三个文件或者递归删除前要求确认。此选项比-i 提示内容更少,但同样可以阻止大多数错误发生;
-r, -R, --recursive 递归删除目录及其内容;
-v, --verbose 详细显示进行的步骤;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出;
默认时,rm 不会删除目录,使用--recursive(-r 或-R)选项可删除每个给定的目录,以及其下所有的内容;
要删除第一个字符为"-"的文件 (例如"-foo"),请使用以下方法之一:
rm -- -foo
rm ./-foo
4.6 cp命令详解
cp 命令主要用于拷贝文件,用法,cp old.txt /tmp/new.txt ,常用来备份,如果拷贝目录需要加-r参数,常用参数详解如下:
用法:cp [选项]... [-T] 源文件 目标文件
 或:cp [选项]... 源文件... 目录
 或:cp [选项]... -t 目录 源文件...
将源文件复制至目标文件,或将多个源文件复制至目标目录。
长选项必须使用的参数对于短选项时也是必需使用的。
-a, --archive 等于-dR --preserve=all;
--backup[=CONTROL 为每个已存在的目标文件创建备份;
-b 类似--backup 但不接受参数;
--copy-contents 在递归处理是复制特殊文件内容;
-d 等于--no-dereference --preserve=links;
-f, --force 如果目标文件无法打开则将其移除并重试(当 -n 选项;
存在时则不需再选此项);
-i, --interactive 覆盖前询问(使前面的 -n 选项失效);
-H 跟随源文件中的命令行符号链接;
-l, --link 链接文件而不复制;
-L, --dereference 总是跟随符号链接;
-n, --no-clobber 不要覆盖已存在的文件(使前面的 -i 选项失效);
-P, --no-dereference 不跟随源文件中的符号链接;
-p 等于--preserve=模式,所有权,时间戳;
--preserve[=属性列表 保持指定的属性(默认:模式,所有权,时间戳),如果;
可能保持附加属性:环境、链接、xattr 等;
-c same as --preserve=context;
--sno-preserve=属性列表 不保留指定的文件属性;
--parents 复制前在目标目录创建来源文件路径中的所有目录;
-R, -r, --recursive 递归复制目录及其子目录内的所有内容。
4.7 mv命令详解
mv 命令主要用于重命名或者移动文件或者目录,用法, mv old.txt new.txt,常用参数详解如下:
用法:mv [选项]... [-T] 源文件 目标文件;
或:mv [选项]... 源文件... 目录;
或:mv [选项]... -t 目录 源文件;
将源文件重命名为目标文件,或将源文件移动至指定目录。长选项必须使用的参数对于短选项时也是必需使用的。
--backup[=CONTROL] 为每个已存在的目标文件创建备份;
-b 类似--backup 但不接受参数;
-f, --force 覆盖前不询问;
-i, --interactive 覆盖前询问;
-n, --no-clobber 不覆盖已存在文件,如果您指定了-i、-f、-n 中的多个,仅最后一个生效;
--strip-trailing-slashes 去掉每个源文件参数尾部的斜线;
-S, --suffix=SUFFIX 替换常用的备份文件后缀;
-t, --target-directory=DIRECTORY 将所有参数指定的源文件或目录;
移动至 指定目录;
-T, --no-target-directory 将目标文件视作普通文件处理;
-u, --update 只在源文件文件比目标文件新,或目标文件;
不存在时才进行移动;
-v, --verbose 详细显示进行的步骤;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出。
4.8 touch命令详解
touch 命令主要用于创建普通文件,用法为touch test.txt,如果文件存在,则表示修改当前文件时间,常用参数详解如下:
用法:touch [选项]... 文件...
将每个文件的访问时间和修改时间改为当前时间;
不存在的文件将会被创建为空文件,除非使用-c 或-h 选项;
如果文件名为"-"则特殊处理,更改与标准输出相关的文件的访问时间;
长选项必须使用的参数对于短选项时也是必需使用的;
-a 只更改访问时间;
-c, --no-create 不创建任何文件;
-d, --date=字符串 使用指定字符串表示时间而非当前时间;
-f (忽略);
-h, --no-dereference 会影响符号链接本身,而非符号链接所指示的目的地;
(当系统支持更改符号链接的所有者时,此选项才有用);
-m 只更改修改时间;
-r, --reference=文件 使用指定文件的时间属性而非当前时间;
-t STAMP 使用[[CC]YY]MMDDhhmm[.ss] 格式的时间而非当前时间;
--time=WORD 使用WORD 指定的时间:access、atime、use 都等于-a;
选项的效果,而modify、mtime 等于-m 选项的效果;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出。
4.9 cat命令详解
cat 命令主要用于查看文件内容,用法 cat test.txt 可以查看test.txt内容,常用参数详解如下:
用法:cat [选项]... [文件]...
将[文件]或标准输入组合输出到标准输出。
-A, --show-all 等于-vET;
-b, --number-nonblank 对非空输出行编号;
-e 等于-vE;
-E, --show-ends 在每行结束处显示"$";
-n, --number 对输出的所有行编号;
-s, --squeeze-blank 不输出多行空行;
-t 与-vT 等价;
-T, --show-tabs 将跳格字符显示为^I;
-u (被忽略);
-v, --show-nonprinting 使用^ 和M- 引用,除了LFD和 TAB 之外;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出。
cat还有一种用法,cat …EOF…EOF,表示追加内容至/tmp/test.txt文件中,如下:
cat >>/tmp/test.txt<<EOF
My Name is JFEDU.NET
I am From Bei jing.
EOF
cat test.txt |more 分页显示text内容,|符号是管道符,用于把|前的输出作为后面命令的输入。More命令常用于分页查看某文件或者内容。
4.10 head命令详解
head命令主要用于查看文件内容,通常查看文件前10行,head -10 /var/log/messages可以查看该文件前10行的内容,常用参数详解如下:
用法:head [选项]... [文件]...
将每个指定文件的头10 行显示到标准输出。
如果指定了多于一个文件,在每一段输出前会给出文件名作为文件头。
如果不指定文件,或者文件为"-",则从标准输入读取数据,长选项必须使用的参数对于短选项时也是必需使用的;
-q, --quiet, --silent 不显示包含给定文件名的文件头;
-v, --verbose 总是显示包含给定文件名的文件头;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出;
-c, --bytes=[-]K 显示每个文件的前K 字节内容,如果附加"-"参数,则除了每个文件的最后K字节数据外显示剩余全部内容;
-n, --lines=[-]K 显示每个文件的前K 行内容,如果附加"-"参数,则除了每个文件的最后K 行外显示剩余全部内容。
4.11 tail命令详解
tail命令主要用于查看文件内容,通常查看末尾10行,tail –fn 100 /var/log/messages可以实时查看该文件末尾100行的内容,常用参数详解如下:
用法:tail [选项]... [文件]...
显示每个指定文件的最后10 行到标准输出。
若指定了多于一个文件,程序会在每段输出的开始添加相应文件名作为头。
如果不指定文件或文件为"-" ,则从标准输入读取数据。
长选项必须使用的参数对于短选项时也是必需使用的。
-n, --lines=K 输出的总行数,默认为10行;
-q, --quiet, --silent 不输出给出文件名的头;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出;
-f, --follow[={name|descriptor}] 即时输出文件变化后追加的数据;
-f, --follow 等于--follow=descriptor
-F 即--follow=name –retry
-c, --bytes=K 输出最后K字节;另外,使用-c +K 从每个文件的第K字节输出。
4.12 chmod命令详解
chmod命令主要用于修改文件或者目录的权限,例如chmod o+w test.txt,赋予test.txt其他人w写权限,常用参数详解如下:
用法:chmod [选项]... 模式[,模式]... 文件...
 或:chmod [选项]... 八进制模式 文件...
 或:chmod [选项]... --reference=参考文件 文件,将每个文件的模式更改为指定值。
-c, --changes 类似 --verbose,但只在有更改时才显示结果
--no-preserve-root 不特殊对待根目录(默认);
--preserve-root 禁止对根目录进行递归操作;
-f, --silent, --quiet 去除大部份的错误信息;
-R, --recursive 以递归方式更改所有的文件及子目录;
--help 显示此帮助信息并退出;
--version 显示版本信息并退出;
-v, --verbose 为处理的所有文件显示诊断信息;
--reference=参考文件 使用指定参考文件的模式,而非自行指定权限模式。
4.13 chown命令详解
chown命令主要用于文件或者文件夹宿主及属组的修改,命令格式例如chown –R root.root /tmp/test.txt,表示修改test.txt文件的用户和组均为root,常用参数详解如下:
用法:chown [选项]... [所有者][:[组]] 文件...
 或:chown [选项]... --reference=参考文件 文件...
更改每个文件的所有者和/或所属组。
当使用 --referebce 参数时,将文件的所有者和所属组更改为与指定参考文件相同。
-f, --silent, --quiet 去除大部份的错误信息
--reference=参考文件 使用参考文件的所属组,而非指定值;
-R, --recursive 递归处理所有的文件及子目录;
-v, --verbose 为处理的所有文件显示诊断信息;
-H 命令行参数是一个通到目录的符号链接,则遍历符号链接;
-L 历每一个遇到的通到目录的符号链接;
-P 历任何符号链接(默认);
--help 显示帮助信息并退出;
--version 显示版本信息并退出。
4.14 echo命令详解
echo命令主要用于打印字符或者回显,例如输入echo ok,会显示ok, echo ok > test.txt 则会把ok字符覆盖test.txt内容。>表示覆盖,原内容被覆盖,>>表示追加,原内容不变。
例如echo ok >> test.txt,表示向test.txt文件追加OK字符,不覆盖原文件里的内容,常用参数详解如下:
使用-e扩展参数选项时,与如下参数一起使用,有不同含义,例如:
\a 发出警告声
\b 删除前一个字符
\c 最后不加上换行符号;
\f 换行但光标仍旧停留在原来的位置;
\n 换行且光标移至行首;
\r 光标移至行首,但不换行;
\t 插入tab; \v 与\f相同;
\\ 插入\字符;
\033[30m 黑色字 \033[0m
\033[31m 红色字 \033[0m
\033[32m 绿色字 \033[0m
\033[33m 黄色字 \033[0m
\033[34m 蓝色字 \033[0m
\033[35m 紫色字 \033[0m
\033[36m 天蓝字 \033[0m
\033[37m 白色字 \033[0m
\033[40;37m 黑底白字 \033[0m
\033[41;37m 红底白字 \033[0m
\033[42;37m 绿底白字 \033[0m
\033[43;37m 黄底白字 \033[0m
\033[44;37m 蓝底白字 \033[0m
\033[45;37m 紫底白字 \033[0m
\033[46;37m 天蓝底白字 \033[0m
\033[47;30m 白底黑字 \033[0m
echo颜色打印扩展,auto_lamp_v2.sh内容如下:
echo -e "\033[36mPlease Select Install Menu follow:\033[0m"
echo -e "\033[32m1)Install Apache Server\033[1m"
echo "2)Install MySQL Server"
echo "3)Install PHP Server"
echo "4)Configuration index.php and start LAMP server"
echo -e "\033[31mUsage: { /bin/sh $0 1|2|3|4|help}\033[0m"
执行结果如图4-3所示:
图4-3 echo –e颜色打印
4.15 df命令详解
df命令常用于磁盘分区查询,常用命令df –h,查看磁盘分区信息,常用参数详解如下:
用法:df [选项]... [文件]...
显示每个文件所在的文件系统的信息,默认是显示所有文件系统。
长选项必须使用的参数对于短选项时也是必需使用的。
-a, --all include dummy file systems
-B, --block-size=SIZE use SIZE-byte blocks
--direct show statistics for a file instead of mount point
--total produce a grand total
-h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)
-H, --si likewise, but use powers of 1000 not 1024
-i, --inodes 显示inode 信息而非块使用量;
-k 即--block-size=1K;
-l, --local 只显示本机的文件系统;
--no-sync 取得使用量数据前不进行同步动作(默认);
-P, --portability 使用POSIX 兼容的输出格式;
--sync 取得使用量数据前先进行同步动作;
-t, --type=类型 只显示指定文件系统为指定类型的信息;
-T, --print-type 显示文件系统类型;
-x, --exclude-type=类型 只显示文件系统不是指定类型信息;
--help 显示帮助信息并退出;
--version 显示版本信息并退出。
4.16 du命令详解
du命令常用于查看文件在磁盘中的使用量,常用命令du -sh,查看当前目录所有文件及文件及的大小,常用参数详解如下:
用法:du [选项]... [文件]...
 或:du [选项]... --files0-from=F
计算每个文件的磁盘用量,目录则取总用量。
长选项必须使用的参数对于短选项时也是必需使用的。
-a, --all 输出所有文件的磁盘用量,不仅仅是目录; --apparent-size 显示表面用量,而并非是磁盘用量;虽然表面用量通常会小一些,但有时它会因为稀疏文件间的"洞"、内部碎片、非直接引用的块等原因而变大;
-B, --block-size=大小 使用指定字节数的块;
-b, --bytes 等于--apparent-size --block-size=1;
-c, --total 显示总计信息;
-H 等于--dereference-args (-D);
-h, --human-readable 以可读性较好的方式显示尺寸(例如:1K 234M 2G);
--si 类似-h,但在计算时使用1000 为基底而非1024;
-k 等于--block-size=1K;
-l, --count-links 如果是硬连接,就多次计算其尺寸;
-m 等于--block-size=1M;
-L, --dereference 找出任何符号链接指示的真正目的地;
-P, --no-dereference 不跟随任何符号链接(默认);
-0, --null 将每个空行视作0 字节而非换行符;
-S, --separate-dirs 不包括子目录的占用量;
-s, --summarize 只分别计算命令列中每个参数所占的总用量;
-x, --one-file-system 跳过处于不同文件系统之上的目录;
-X, --exclude-from=文件 排除与指定文件中描述的模式相符的文件;
-D, --dereference-args 解除命令行中列出的符号连接;
--files0-from=F 计算文件F中以NUL结尾的文件名对应占用的磁盘空间,如果F 的值是"-",则从标准输入读入文件名。
如上为Linux初学者必备命令,当然Linux命令还有很多,后面章节会随时学习新的命令。
4.17 vi|vim编辑器实战
VI是一个命令行界面下的文本编辑工具,最早在1976年由Bill Joy开发,当时名字叫做ex。vi支持绝大多数操作系统(最早在BSD上发布),并且功能已经十分强大
1991年Bram Moolenaar基于vi进行改进,发布了vim,加入了对GUI的支持。
随着VIM更新发展,VIM已经不是普通意义上的文本编辑器,而是被广泛的作为在文本编辑、方本处理、代码开发等用途,Linux中主流的文本编辑器包括:VI、Vim、Sublime、Emacs、Light Table、Eclipse、Gedit等。
Vim强大的编辑能力中很大部分是来自于其普通模式命令。vim的设计理念是命令的组合。
“5dd”5表示总共5行,删除光标所在后的5行,包含光标行;
“d$” $"代表行尾,删除到行尾的内容,包含光标;
“2yy”表示复制光标及后2行,包括光标行;
“%d” %代表全部或者全局,%d表示删除文本所有的内容,也即是清空文档所有的内容。
VIM是一个主流开源的编辑器,其默认执行vim命令,会显示帮助乌干达贫困的孩子,如图4-4为vim与键盘键位功能对应关系:
图4-4 vim与键盘位置对应关系
4.18 VIM编辑器模式
Vim编辑器模式常用有三种,分别是:
命令行模式;
文本输入模式;
末行模式。
vim是vi的升级版本,它是安装在Linux操作系统中的一个软件,官网为:www.vim.org
在Linux Shell终端下默认执行vim命令,按Enter键后:
默认进入命令行模式;
在命令行模式按i进入文本输入模式;
按ESC进入命令行模式;
按:进入末行模式。
4.19 VIM编辑器必备
VIM编辑器最强大的功能,就在于内部命令及规则使用,如下为VIM编辑器最常用的语法及规则:
命令行模式:可以删除、复制、粘贴、撤销,可以切换到输入模式,输入模式跳转至命令行模式:按ESC键。
yy 复制光标所在行;
nyy 复制n行;
3yy 复制3行;
p,P 粘贴;
yw 复制光标所在的词组,不会复制标点符号;
3yw 复制三个词组;
u 撤消上一次;
U 撤消当前所有;
dd 删除整行;
ndd 删除n行;
x 删除一个字符;
u 逐行撤销;
dw 删除一个词组;
a 从光标所在字符后一个位置开始录入;
A 从光标所在行的行尾开始录入;
i 从光标所在字符前一个位置开始录入;
I 从光标所在行的行首开始录入;
o 跳至光标所在行的下一行行首开始录入;
O 跳至光标所在行的上一行行首开始录入;
R 从光标所在位置开始替换;
末行模式主要功能包括:查找、替换、末行保存、退出等;
:w 保存;
:q 退出;
:s/x/y 替换1行;
:wq 保存退出;
1,5s/x/y 替换1,5行;
:wq! 强制保存退出;
1,$sx/y 从第一行到最后一行;
:q! 强制退出;
:x 保存;
/word 从前往后找,正向搜索;
?word 从后往前走,反向搜索;
:s/old/new/g 将old替换为new,前提是光标一定要移到那一行;
:s/old/new 将这一行中的第一次出现的old替换为new,只替换第一个;
:1,$s/old/new/g 第一行到最后一行中的old替换为new;
:1,2,3s/old/new/g 第一行第二行第三行中的old改为new;
vim +2 jfedu.txt 打开jfedu.txt文件,并将光标定位在第二行;
vim +/string jfedu.txt 打开jfedu.txt文件,并搜索关键词。
4.20 本章小结
通过对本章内容的学习,读者对Linux操作系统引导有了进一步的理解,能够快速解决Linux启动过程中的故障,同时学习了CentOS6与CentOS7系统的区别,理解了TCP/IP协议及IP地址相关基础内容。
学会了Linux初学必备的16个Linux命令,能使用命令熟练的操作Linux系统,通过对VIM编辑器的深入学习,能够熟练编辑、修改系统中任意的文本及配置文件。对Linux系统的认识及操作有了更进一步的飞跃。
4.21 同步作业
1.请写出DELL R730服务器启动Linux操作系统的完整流程。
2.请写出CentOS6与CentOS7的区别,至少8种区别。
3.企业中一台CentOS6 Linux服务器,密码忘记了,如何破解,请写出方法?
4.CentOS Linux至今发布了多少个系统版本?
5.如果Linux系统采用光盘安装,如何将ISO镜像文件刻录成光盘,请写出具体实现流程?
第5章 Linux用户及权限管理
Linux是一个多用户的操作系统,引入用户,可以更加方便管理Linux服务器,系统默认需要以一个用户的身份登入,而且在系统上启动进程也需要以一个用户身份器运行,用户可以限制某些进程对特定资源的权限控制。
本章向读者介绍Linux系统如何管理创建、删除、修改用户角色、用户权限配置、组权限配置及特殊权限深入剖析。
5.1 Linux用户及组
Linux操作系统对多用户的管理,是非常繁琐的,所以用组的概念来管理用户就变得简单,每个用户可以在一个独立的组,每个组也可以有零个用户或者多个用户。
Linux系统用户是根据用户ID来识别的,默认ID长度为32位,从默认ID编号从0开始,但是为了和老式系统兼容,用户ID限制在60000以下,Linux用户分总共分为三种,分别如下:
root用户 (ID 0)
系统用户 (ID 1-499)
普通用户 (ID 500以上)
Linux系统中的每个文件或者文件夹,都有一个所属用户及所属组,使用id命令可以显示当前用户的信息,使用passwd命令可以修改当前用户密码。Linux操作系统用户的特点如下:
每个用户拥有一个UserID,操作系统实际读取的是UID,而非用户名;
每个用户属于一个主组,属于一个或多个附属组,一个用户最多有31个附属组;
每个组拥有一个GroupID;
每个进程以一个用户身份运行,该用户可对进程拥有资源控制权限;
每个可登陆用户拥有一个指定的Shell环境。
5.2 Linux用户管理
Linux用户在操作系统可以进行日常管理和维护,涉及到的相关配置文件如下:
/etc/passwd 保存用户信息
/etc/shdaow 保存用户密码(以加密形式保存)
/etc/group 保存组信息
/etc/login.defs 用户属性限制,密码过期时间,密码最大长度等限制
/etc/default/useradd 显示或更改默认的useradd配置文件
如需创建新用户,可以使用命令useradd,执行命令useradd jfedu1即可创建jfedu1用户,同时会创建一个同名的组jfedu1,默认该用户属于jfedu1主组。
Useradd jfedu1命令默认创建用户jfedu1,会根据如下步骤进行操作:
在/etc/passwd文件中添加用户信息;
如使用passwd命令创建密码,密码会被加密保存在/etc/shdaow中;
为jfedu1创建家目录:/home/jfedu1;
将/etc/skel中的.bash开头的文件复制至/home/jfedu1家目录;
创建与用户名相同的jfedu1组,jfedu1用户默认属于jfeud1同名组;
Jfedu1组信息保存在/etc/group配置文件中。
在使用useradd命令创建用户时,可以支持如下参数:
用法:useradd [选项] 登录
useradd -D
useradd -D [选项]
选项:
-b, --base-dir BASE_DIR 指定新账户的家目录;
-c, --comment COMMENT 新账户的 GECOS 字段;
-d, --home-dir HOME_DIR 新账户的主目录;
-D, --defaults 显示或更改默认的 useradd 配置;
-e, --expiredate EXPIRE_DATE 新账户的过期日期;
-f, --inactive INACTIVE 新账户的密码不活动期;
-g, --gid GROUP 新账户主组的名称或ID;
-G, --groups GROUPS 新账户的附加组列表;
-h, --help 显示此帮助信息并推出;
-k, --skel SKEL_DIR 使用此目录作为骨架目录;
-K, --key KEY=VALUE 不使用 /etc/login.defs 中的默认值;
-l, --no-log-init 不要将此用户添加到最近登录和登录失败数据库;
-m, --create-home 创建用户的主目录;
-M, --no-create-home 不创建用户的主目录;
-N, --no-user-group 不创建同名的组;
-o, --non-unique 允许使用重复的 UID 创建用户;
-p, --password PASSWORD 加密后的新账户密码;
-r, --system 创建一个系统账户;
-R, --root CHROOT_DIR chroot 到的目录;
-s, --shell SHELL 新账户的登录 shell;
-u, --uid UID 新账户的用户 ID;
-U, --user-group 创建与用户同名的组;
-Z, --selinux-user SEUSER 为SELinux 用户映射使用指定 SEUSER。
Useradd案例演示:
(1)新建jfedu用户,并加入到jfedu1,jfedu2附属组;
useradd -G jfedu1,jfedu2 jfedu
(2)新建jfedu3用户,并指定新的家目录,同时指定其登陆的SHELL;
useradd jfedu3 -d /tmp/ -s /bin/sh
5.3 Linux组管理
所有的Linux或者Windows系统都有组的概念,通过组可以更加方便的管理用户,组的概念应用于各行行业,例如企业会使用部门、职能或地理区域的分类方式来管理成员,映射在Linux系统,同样可以创建用户,并用组的概念对其管理。
Linux组有如下特点:
每个组有一个组ID;
组信息保存在/etc/group中;
每个用户至少拥有一个主组,同时还可以拥有31个附属组。
通过命令groupadd、groupdel、groupmod来对组进行管理,详细参数使用如下:
groupadd用法
-f, --force 如果组已经存在则成功退出;
并且如果 GID 已经存在则取消 –g;
-g, --gid GID 为新组使用 GID;
-h, --help 显示此帮助信息并推出;
-K, --key KEY=VALUE 不使用 /etc/login.defs 中的默认值;
-o, --non-unique 允许创建有重复 GID 的组;
-p, --password PASSWORD 为新组使用此加密过的密码;
-r, --system 创建一个系统账户;
groupmod用法
-g, --gid GID 将组 ID 改为 GID;
-h, --help 显示此帮助信息并推出;
-n, --new-name NEW_GROUP 改名为 NEW_GROUP;
-o, --non-unique 允许使用重复的 GID;
-p, --password PASSWORD 将密码更改为(加密过的) PASSWORD;
groupdel用法
groupdel jfedu 删除jfedu组;
Groupadd案例演示:
(1)groupadd创建jingfeng组
groupadd jingfeng
(2)groupadd创建jingfeng组,并指定GID为1000;
groupadd -g 1000 jingfeng
(3)groupadd创建一个system组,名为jingfeng组
groupadd -r jingfeng
Groupmod案例演示:
(4)groupmod修改组名称,将jingfeng组名,改成jingfeng1;
groupmod -n jingfeng1 jingfeng
(5)groupmod修改组GID号,将原jingfeng1组gid改成gid 1000;
groupmod –g 1000 jingfeng1
5.4 Linux用户及组案例
Useradd主要用于新建用户,而用户新建完毕,可以使用usermod来修改用户及组的属性,如下为usermod详细参数:
用法:usermod [选项] 登录
选项:
-c, --comment 注释 GECOS 字段的新值;
-d, --home HOME_DIR 用户的新主目录;
-e, --expiredate EXPIRE_DATE 设定帐户过期的日期为 EXPIRE_DATE;
-f, --inactive INACTIVE 过期 INACTIVE 天数后,设定密码为失效状态;
-g, --gid GROUP 强制使用 GROUP 为新主组;
-G, --groups GROUPS 新的附加组列表 GROUPS;
-a, --append GROUP 将用户追加至上边 -G 中提到的附加组中,
并不从其它组中删除此用户;
-h, --help 显示此帮助信息并推出;
-l, --login LOGIN 新的登录名称;
-L, --lock 锁定用户帐号;
-m, --move-home 将家目录内容移至新位置 (仅于 -d 一起使用);
-o, --non-unique 允许使用重复的(非唯一的) UID;
-p, --password PASSWORD 将加密过的密码 (PASSWORD) 设为新密码;
-R, --root CHROOT_DIR chroot 到的目录;
-s, --shell SHELL 该用户帐号的新登录shell环境;
-u, --uid UID 用户帐号的新UID;
-U, --unlock 解锁用户帐号;
-Z, --selinux-user SEUSER 用户账户的新SELinux 用户映射。
Usermod案例演示:
(1)将jfedu用户属组修改为jfedu1,jfedu2附属组;
usermod -G jfedu1,jfedu2 jfedu
(2)将jfedu用户加入到jfedu3,jfedu4附属组,-a为添加新组,原组保留;
usermod –a -G jfedu3,jfedu4 jfedu
(3)修改jfedu用户,并指定新的家目录,同时指定其登陆的SHELL;
usermod -d /tmp/ -s /bin/sh jfedu
(4)将jfedu用户名修改为jfedu1;
usermod –l jfedu1 jfedu
(5)锁定jfedu1用户及解锁jfedu1用户方法;
usermod –L jfedu1;usermod -U jfedu1
Userdel案例演示:
使用userdel可以删除指定用户及其用户的邮箱目录或者Selinux映射环境:
userdel jfedu1 保留用户的家目录;
userdel –r jfedu1 删除用户及用户家目录,用户login系统无法删除;
userdel –rf jfedu1 强制删除用户及该用户家目录,不论是否login系统。
5.5 Linux权限管理
Linux权限是操作系统用来限制对资源访问的机制,权限一般分为读、写、执行。系统中每个文件都拥有特定的权限、所属用户及所属组,通过这样的机制来限制哪些用户或用户组可以对特定文件进行相应的操作。
Linux每个进程都是以某个用户身份运行,进程的权限与该用户的权限一样,用户的权限越大,则进程拥有的权限就越大。
Lnux中有的文件及文件夹都有至少权限三种权限,常见的权限如表5-1所示:
权限 对文件的影响 对目录的影响
r(读取) 可读取文件内容 可列出目录内容
w(写入) 可修改文件内容 可在目录中创建删除内容
x(执行) 可作为命令执行 可访问目录内容
目录必须拥有x权限,否则无法查看其内容
表5-1 Linux 文件及文件及权限
Linux权限授权,默认是授权给三种角色,分别是user、group、other,Linux权限与用户之间的关联如下:
U代表User,G代表Group,O代表Other;
每个文件的权限基于UGO进行设置;
权限三位一组(rwx),同时需授权给三种角色,UGO;
每个文件拥有一个所属用户和所属组,对应UGO,不属于该文件所属用户或所属组使用O来表示;
在Linux系统中,可以通过ls –l查看jfedu.net目录的详细属性,如图5-1所示:
drwxrwxr-x 2 jfedu1 jfedu1 4096 Dec 10 01:36 jfedu.net
图5-1 Linux jfedu.net目录详细属性
jfedu.net目录属性参数详解如下:
d 表示目录,同一位置如果为-则表示普通文件;
rwxrwxr-x 表示三种角色的权限,每三位为一种角色,依次为u,g,o权限,如上则表示user的权限为rwx,group的权限为rwx,other的权限为r-x;
2表示文件夹的链接数量,可理解为该目录下子目录的数量;
从左到右,第一个jfedu1表示该用户名,第二个jfedu1则为组名,其他人角色默认不显示;
4096表示该文件夹占据的字节数;
Dec 10 01:36 表示文件创建或者修改的时间;
Jfedu.net 为目录的名,或者文件名。
5.6 Chown属主及属组
修改某个用户、组对文件夹的属主及属组,用命令chown实现,案例演示如下:
(1)修改jfedu.net文件夹所属的用户为root,其中-R参数表示递归处理所有的文件及子目录。
chown -R root jfedu.net
(2)修改jfedu.net文件夹所属的组为root。
chown -R :root jfedu.net或者chgrp –R root jfedu.net
(3)修改jfedu.net文件夹所属的用户为root,组也为root。
chown -R root:root jfedu.net
5.7 Chmod用户及组权限
修改某个用户、组对文件夹的权限,用命令chmod实现,其中以代指ugo,、-、=代表加入、删除和等于对应权限,具体案例如下:
(1)授予用户对jfedu.net目录拥有rwx权限
chmod –R u+rwx jfedu.net
(2)授予组对jfedu.net目录拥有rwx权限
chmod –R g+rwx jfedu.net
(3)授予用户、组、其他人对jfedu.net目录拥有rwx权限
chmod –R u+rwx,g+rwx,o+rwx jfedu.net
(4)撤销用户对jfedu.net目录拥有w权限
chmod –R u-w jfedu.net
(5)撤销用户、组、其他人对jfedu.net目录拥有x权限
chmod –R u-x,g-x,o-x jfedu.net
(6)授予用户、组、其他人对jfedu.net目录只有rx权限
chmod –R u=rx,g=rx,o=rx jfedu.net
5.8 Chmod二进制权限
Linux权限默认使用rwx来表示,为了更简化在系统中对权限进行配置和修改,Linux权限引入二进制表示方法,如下代码:
Linux权限可以将rwx用二进制来表示,其中有权限用1表示,没有权限用0表示;
Linux权限用二进制显示如下:
rwx=111
r-x=101
rw-=110
r--=100
依次类推,转化为十进制,对应十进制结果显示如下:
rwx=111=4+2+1=7
r-x=101=4+0+1=5
rw-=110=4+4+0=6
r--=100=4+0+0=4
得出结论,用r=4,w=2,x=1来表示权限。
使用二进制方式来修改权限案例演示如下,其中默认jfedu.net目录权限为755:
(1)授予用户对jfedu.net目录拥有rwx权限
chmod –R 755 jfedu.net
(2)授予组对jfedu.net目录拥有rwx权限
chmod –R 775 jfedu.net
(3)授予用户、组、其他人对jfedu.net目录拥有rwx权限
chmod –R 777 jfedu.net
(4)撤销用户对jfedu.net目录拥有w权限
chmod –R 555 jfedu.net
(5)撤销用户、组、其他人对jfedu.net目录拥有x权限
chmod –R 644 jfedu.net
(6)授予用户、组、其他人对jfedu.net目录只有rx权限
chmod –R 555 jfedu.net
5.9 Linux特殊权限及掩码
Linux权限除了常见的rwx权限之外,还有很多特殊的权限,细心的读者会发现,为什么Linux目录默认权限755,而文件默认权限为644呢,这是因为Linux权限掩码umask导致。
每个Linux终端都拥有一个umask属性,umaks熟悉可以用来确定新建文件、目录的默认权限,默认系统权限掩码为022。在系统中每创建一个文件或者目录,文件默认权限是666,而目录权限则为777,权限对外开放比较大,所以设置了权限掩码之后,默认的文件和目录权限减去umask值才是真实的文件和目录的权限。
对应目录权限为:777-022=755;
对应文件权限为:666-022=644;
执行umask命令可以查看当前默认的掩码,umask -S 023可以设置默认的权限掩码。
在Linux权限中,除了普通权限外,还有如下表5-2所示,三个特殊权限:
权限 对文件的影响 对目录的影响
Suid 以文件的所属用户身份执行,而非执行文件的用户 无

sgid
以文件所属组身份去执行 在该目录中创建任意新文件的所属组与该目录的所属组相同

sticky
无 对目录拥有写入权限的用户仅可以删除其拥有的文件,无法删除其他用户所拥有的文件
表5-2 Linux三种特殊权限
Linux中设置特殊权限方法如下:
设置suid: chmod u+s jfedu.net
设置sgid: chmod g+s jfedu.net
设置sticky: chmod o+t jfedu.net
特殊权限与设置普通权限一样,可以使用数字方式表示:
SUID = 4
SGID = 2
Sticky = 1
可以通过chmod 4755 jfedu.net对该目录授予特殊权限为s的权限,Linux系统中s权限的应用常见包括:su、passwd、sudo,如图5-2所示:
图5-2 Linux特殊权限s应用
5.10 本章小结
通过对本章内容的学习,读者可以了解Linux用户和组的系统知识,同时账号Linux用户和组在系统中各种案例操作。读者可以熟练新建用户、删除用户、修改用户属性、添加组、修改组以及删除组。
5.11 同步作业
1.某互联网公司职能及员工信息表,如表5-3所示,请在Linux系统中创建相关员工,并把员工加入到部门。
部门 职能
讲师部(teacher) jfwu,jfcai
市场部(market) jfxin,jfqi
管理部(manage) jfedu,jfteach
运维部(operater) jfhao,jfyang
表5-3 Linux用户和组管理
2.批量创建1-100个用户,用户名以jfedu开头,后面紧跟1,2,3,例如jfedu1,jfedu2,jfedu3。
3.使用useradd创建用户并通过-p参数指定密码,设定完密码需通过系统能正常验证并登陆。
4.小王公司服务器,使用Root用户通过SecureCRT远程登陆后,如图5-3所示,发现登录终端变成bash-4.1#,是什么原因导致?以及如何修复为正常的登录SHELL环境,请写出答案。
图5-3 SecureCRT登录Linux系统界面
第6章 Linux软件包企业实战
通过前几章的学习,读者掌握了Linux系统基本命令、用户及权限等知识,Linux整个体系的关键不在于系统本身,而是在于可以基于Linux系统去安装和配置企业中相关的软件、数据及应用程序,所以对软件的维护是运维工程师的重中之重。
本章向读者介绍Linux系统软件的安装、卸载、配置、维护以及如何构建企业本地YUM光盘源及HTTP本地源。
6.1 RPM软件包管理
Linux软件包管理大致可分为二进制包、源码包,使用的工具也各不相同。Linux常见软件包分为两种,分别是源代码包(Source Code)、二进制包(Binary Code),源代码包是没有经过编译的包,需要经过GCC、C++编译器环境编译才能运行,二进制包无需编译,可以直接安装使用。
通常而言,可以通过后缀简单区别源码包和二进制包,例如.tar.gz、.zip、.rar结尾的包通常称之为源码包,以.rpm结尾的软件包称之为二进制包。真正区分是否为源码还是二进制还得基于代码里面的文件来判断,例如包含.h、.c、.cpp、.cc等结尾的源码文件,称之为源码包,而代码代码里面存在bin目可以执行文件,称之为二进制包。
CentOS操作系统中有一款默认软件管理的工具,红帽包管理工具(Red Hat Package Manager,RPM)。
使用RPM工具可以对软件包实现快速安装、管理及维护。RPM管理工具适用的操作系统包括:CentOS,RedHat,Fedora,SUSE等,RPM工具常用于管理.rpm后缀结尾的软件包。
RPM软件包命令规则详解如下:
RPM包命名格式为:
name-version.rpm
name-version-noarch.rpm
name-version-arch.src.rpm
如下软件包格式:
epel-release-6-8.noarch.rpm
perl-Pod-Plainer-1.03-1.el6.noarch.rpm
yasm-1.2.0-4.el7.x86_64.rpm
RPM包格式解析如下:
name 软件名称,例如yasm、perl-pod-Plainer;
version 版本号,1.2.0通用格式:“主版本号.次版本号.修正号”;
4表示是发布版本号,该RPM包是第几次编译生成的;
arch 适用的硬件平台,RPM支持的平台有:i386、i586、i686、x86_64、sparc、alpha等。
.rpm 后缀包表示编译好的二进制包,可用rpm命令直接安装;
.src.rpm 源代码包,源码编译生成.rpm格式的RPM包方可使用;
el 软件包发行版本,el6表示该软件包适用于RHEL 6.x/CentOS 6.x;
devel: 开发包;
noarch: 软件包可以在任何平台上安装。
RPM工具命令详解如下:
RPM 选项 PACKAGE_NAME
-a, --all 查询所有已安装软件包;
-q,--query 表示询问用户,输出信息;
-l, --list 打印软件包的列表;
-f, --file FILE 查询包含 FILE 的软件包;
-i, --info 显示软件包信息,包括名称,版本,描述;
-v, --verbose 打印输出详细信息;
-U, --upgrade 升级RPM软件包;
-h,--hash 软件安装,可以打印安装进度条;
--last 列出软件包时,以安装时间排序,最新的在上面;
-e, --erase 卸载rpm软件包
--force 表示强制,强制安装或者卸载;
--nodeps RPM包不依赖
-l, --list 列出软件包中的文件;
--provides 列出软件包提供的特性;
-R, --requires 列出软件包依赖的其他软件包;
--scripts 列出软件包自定义的小程序。
RPM企业案例演示:
rpm -q httpd 检查httpd包是否安装;
rpm -ql httpd 查看软件安装的路径;
rpm -qi httpd 查看软件安装的版本信息;
rpm -e httpd 卸载httpd软件;
rpm -e --nodeps httpd 强制卸载httpd;
rpm -qa|grep httpd 检查httpd相关的软件包是否安装。
rpm -ivh httpd-2.4.10-el7.x86_64.rpm 安装httpd软件包;
rpm -Uvh httpd-2.4.10-el7.x86_64.rpm 升级httpd软件;
rpm -ivh --nodeps httpd-2.4.10-el7.x86_64.rpm 不依赖其他软件包;
6.2 Tar软件包管理
Linux操作系统除了使用RPM管理工具对软件包管理之外,还可以通过tar、zip、jar等工具进行源码包的管理。
6.2.1 Tar命令参数详解
-A, --catenate, --concatenate 将存档与已有的存档合并
-c, --create 建立新的存档
-d, --diff, --compare 比较存档与当前文件的不同之处
--delete 从存档中删除
-r, --append 附加到存档结尾
-t, --list 列出存档中文件的目录
-u, --update 仅将较新的文件附加到存档中
-x, --extract, --get 解压文件
-j, --bzip2, --bunzip2 有bz2属性的软件包;
-z, --gzip, --ungzip 有gz属性的软件包;
-b, --block-size N 指定块大小为 Nx512 字节(缺省时 N=20);
-B, --read-full-blocks 读取时重组块;
-C, --directory DIR 指定新的目录;
--checkpoint 读取存档时显示目录名;
-f, --file [HOSTNAME:]F 指定存档或设备,后接文件名称;
--force-local 强制使用本地存档,即使存在克隆;
-G, --incremental 建立老 GNU 格式的备份;
-g, --listed-incremental 建立新 GNU 格式的备份;
-h, --dereference 不转储动态链接,转储动态链接指向的文件;
-i, --ignore-zeros 忽略存档中的 0 字节块(通常意味着文件结束);
--ignore-failed-read 在不可读文件中作 0 标记后再退出;
-k, --keep-old-files 保存现有文件;从存档中展开时不进行覆盖;
-K, --starting-file F 从存档文件 F 开始;
-l, --one-file-system 在本地文件系统中创建存档;
-L, --tape-length N 在写入 N
1024 个字节后暂停,等待更换磁盘;
-m, --modification-time 当从一个档案中恢复文件时,不使用新的时间标签;
-M, --multi-volume 建立多卷存档,以便在几个磁盘中存放;
-O, --to-stdout 将文件展开到标准输出;
-P, --absolute-paths 不要从文件名中去除 '/';
-v, --verbose 详细显示处理的文件;
--version 显示tar 程序的版本号;
--exclude FILE不把指定文件包含在内;
-X, --exclude-from FILE 从指定文件中读入不想包含的文件的列表。
6.2.2 TAR企业案例演示
tar -cvf jfedu.tar.gz jfedu 打包jfedu文件或者目录,打包后名称jfedu.tar.gz;
tar -tf jfedu.tar.gz 查看jfedu.tar.gz包中内容;
tar -rf jfedu.tar.gz jfedu.txt 将jfedu.txt文件追加到jfedu.tar.gz中
tar -xvf jfedu.tar.gz 解压jfedu.tar.gz程序包;
tar -czvf jfedu.tar.gz jfedu 使用gzip格式打包并压缩jfedu目录;
tar -cjvf jfedu.tar.bz2 jfedu 使用bzip2格式打包并压缩jfedu目录;
tar -czf jfedu.tar.gz -X list.txt 使用gzip格式打包并压当前目录所有文件,排除list.txt中记录的文件;
tar -czf jfedu.tar.gz
--exclude=zabbix-3.2.4.tar.gz --exclude=nginx-1.12.0.tar.gz 使用gzip格式打包并压当前目录所有文件及目录,排除zabbix-3.2.4.tar.gz和nginx-1.12.0.tar.gz软件包。
6.2.3 TAR实现Linux操作系统备份
Tar命令工具除了用于日常打包、解压源码包或者压缩包之外,最大的亮点是还可以用于Linux操作系统文件及目录的备份,使用tar –g可以基于GNU 格式的增量备份,备份原理是基于检查目录或者文件的atime、mtime、ctime属性是否被修改。文件及目录时间属性详解如下:
文件被访问的时间(Access time,atime);
文件内容被改变的时间(Modified time,mtime);
文件写入、权限更改的时间(Change time,ctime)。
总结,更改文件内容mtime和ctime都会改变,但ctime可以在mtime未发生变化时被更改,例如修改文件权限,文件mtime时间不变,而ctime时间改变。TAR增量备份案例演示步骤如下:
(1)/root目录创建jingfeng文件夹,同时在jingfeng文件夹中,新建jf1.txt,jf2.txt文件,如图6-1所示:
图6-1 创建jingfeng目录及文件
(2)使用tar命令第一次完整备份jingfeng文件夹中的内容,-g指定快照snapshot文件,第一次没有该文件则会自动创建,如图6-2所示:
cd /root/jingfeng/
tar -g /data/backup/snapshot -czvf /data/backup/2017jingfeng.tar.gz

图6-2 tar备份jingfeng目录中文件
(3)使用tar命令第一次完整备份jingfeng文件夹中之后,会生成快照文件:/data/backup/snapshot,后期增量备份会以snapshot文件为参考,在jingfeng文件夹中再创建jf3.txt jf4.txt文件,然后通过tar命令增量备份jingfeng目录所有内容,如图6-3所示:
cd /root/jingfeng/
touch jf3.txt jf4.txt
tar -g /data/backup/snapshot -czvf /data/backup/2017jingfeng_add1.tar.gz *

图6-3 tar增量备份jingfeng目录中文件
如上图6-3所示,增量备份时,需-g指定第一次完整备份的快照snapshot文件,同时增量打包的文件名不能跟第一次备份后的文件名重复,通过tar –tf可以查看打包后的文件内容。
6.2.4 Shell+TAR实现增量备份
企业中日常备份的数据包括/boot、/etc、/root、/data目录等,备份的策略参考:每周1-6执行增量备份,每周日执行全备份。同时在企业中备份操作系统数据均使用Shell脚本完成,此处auto_backup_system.sh脚本供参考,后面章节会系统讲解Shell脚本,脚本内容如下:

!/bin/bash

Automatic Backup Linux System Files

By Author www.jfedu.net

Define Variables

SOURCE_DIR=(
$?
if
[ -z $DIR=/data/backup/
YEAR=date +%Y
MONTH=date +%m
DAY=date +%d
WEEK=date +%u
FILES=system_backup.tgz
CODE=$?
if
[ -z $SOURCE_DIR ];then
echo -e "Please Enter a File or Directory You Need to Backup:\n--------------------------------------------\nExample $0 /boot /etc ......"
exit
fi

Determine Whether the Target Directory Exists

if
[ ! -d $TARGET_DIR/$YEAR/$MONTH/$DAY ];then
mkdir -p $TARGET_DIR/$YEAR/$MONTH/$DAY
echo "This $TARGET_DIR Created Successfully !"
fi

EXEC Full_Backup Function Command

Full_Backup()
{
if
[ "$WEEK" -eq "7" ];then
rm -rf $TARGET_DIR/snapshot
cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;tar -g $TARGET_DIR/snapshot -czvf $FILES echo ${SOURCE_DIR[@]}
[ "$CODE" == "0" ]&&echo -e "--------------------------------------------\nFull_Backup System Files Backup Successfully !"
fi
}

Perform incremental BACKUP Function Command

Add_Backup()
{
cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;
if
[ -f $TARGET_DIR/$YEAR/$MONTH/$DAY/$FILES ];then
read -p "$FILES Already Exists, overwrite confirmation yes or no ? : " SURE
if [ $SURE == "no" -o $SURE == "n" ];then
sleep 1 ;exit 0
fi

Add_Backup Files System

if
    [ $WEEK -ne "7" ];then
    cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;tar -g $TARGET_DIR/snapshot -czvf $$_$FILES `echo ${SOURCE_DIR[@]}`
    [ "$CODE" == "0" ]&&echo -e  "-----------------------------------------\nAdd_Backup System Files Backup Successfully !"

fi
else
if
[ $WEEK -ne "7" ];then
cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;tar -g $TARGET_DIR/snapshot -czvf $FILES echo ${SOURCE_DIR[@]}
[ "$CODE" == "0" ]&&echo -e "-------------------------------------------\nAdd_Backup System Files Backup Successfully !"
fi
fi
}
Full_Backup;Add_Backup
6.3 ZIP软件包管理
ZIP也是计算机文件的压缩的算法,原名Deflate(真空),发明者为菲利普·卡兹(Phil Katz)),他于1989年1月公布了该格式的资料。ZIP通常使用后缀名“.zip”。
主流的压缩格式包括tar、rar、zip、war、gzip、bz2、iso等。从性能上比较,TAR、WAR、RAR格式较ZIP格式压缩率较高,但压缩时间远远高于ZIP,Zip命令行工具可以实现对zip属性的包进行管理,也可以将文件及文件及打包成zip格式。如下为ZIP工具打包常见参数详解:
-f freshen:只更改文件;
-u update:只更改或新文件;
-d 从压缩文件删除文件;
-m 中的条目移动到zipfile(删除OS文件);
-r 递归到目录;
-j junk(不记录)目录名;
-l 将LF转换为CR LF(-11 CR LF至LF);
-1 压缩更快1-9压缩更好;
-q 安静操作,不输出执行的过程;
-v verbose操作/打印版本信息;
-c 添加一行注释;
-z 添加zipfile注释;
-o 读取名称使zip文件与最新条目一样旧;
-x 不包括以下名称;
-F 修复zipfile(-FF尝试更难);
-D 不要添加目录条目;
-T 测试zip文件完整性;
-X eXclude eXtra文件属性;
-e 加密 - 不要压缩这些后缀;
-h2 显示更多的帮助。
ZIP企业案例演示:
(1)通过zip工具打包jingfeng文件夹中所有内容,如图6-4所示:
zip -rv jingfeng.zip /root/jingfeng/
图6-4 zip对jingfeng目录打包备份
(2)通过zip工具打包jingfeng文件夹中所有内容,排除部分文件,如图6-5所示:
zip -rv jingfeng.zip -x jf1.txt
zip -rv jingfeng.zip
-x jf2.txt -x jf3.txt
图6-5 zip对jingfeng目录打包备份,排除部分文件
(3)通过zip工具删除jingfeng.zip中jf3.txt文件,如图6-6所示
zip jingfeng.zip -d jf3.txt
(4)通过unzip工具解压jingfeng.zip文件夹中所有内容,如图6-6所示:
unzip jingfeng.zip
unzip jingfeng.zip -d /data/backup/ 可以-d指定解压后的目录

图6-6 unzip对jingfeng目录解压
6.4 源码包软件安装
通常使用RPM工具管理.rpm结尾的二进制包,而标准的.zip、tar结尾的源代码包则不能使用RPM工具去安装、卸载及升级,源码包安装有三个步骤,如下:
./configure 预编译,主要用于检测系统基准环境库是否满足,生成MakeFile文件;
make 编译,基于第一步生成的makefile文件,进行源代码的编译;
make install 安装,编译完毕之后,将相关的可运行文件安装至系统中;
使用make编译时,Linux操作系统必须有GCC编译器,用于编译源码。
源码包安装通常需要./configure、make、make install三个步骤,某些特殊源码可以只有三步中的其中一个步骤,或者两个步骤。
以CentOS 7 Linux系统为基准,在其上安装Nginx源码包,企业中源码安装的详细步骤如下:
(1)Nginx.org官网下载Nginx-1.13.0.tar.gz包
wget http://nginx.org/download/nginx-1.13.0.tar.gz
(2)Nginx源码包解压
tar -xvf nginx-1.13.0.tar.gz
(3)源码Configure预编译,需进入解压后的目录执行./configure指令,分号“;”表示连接多个命令。
cd nginx-1.13.0;./configure
(4)make编译
make
(5)make install安装
make install
通过以上五个步骤,源码包软件安装成功,源码包在编译及安装时,可能会遇到各种错误,需要把错误解决之后,然后再进行下一步安装即可,后面章节会重点针对企业使用的软件进行案例演练。
6.5 YUM软件包管理
前端软件包管理器(Yellow Updater Modified,YUM)适用于CentOS、Fedora、RedHat及SUSE中的Shell命令行,主要用于管理RPM包,于RPM工具使用范围类似,YUM工具能够从指定的服务器自动下载RPM包并且安装,还可以自动处理依赖性关系。
使用RPM工具管理和安装软件时,会发现rpm包有依赖,需要逐个手动下载安装,而YUM工具的最大便利就是可以自动安装所有依赖的软件包,从而提升效率,节省时间。
6.5.1 YUM工作原理
学习YUM,一定要理解YUM工作原理,YUM正常运行,需要依赖两个部分,一是YUM源端,二是YUM客户端,也即用户使用端。
YUM客户端安装的所有RPM包都是来自YUM服务端,YUM源端通过HTTP或者FTP服务器发布。而YUM客户端能够从YUM源端下载依赖的RPM包是由于在YUM源端生成了RPM包的基准信息,包括RPM包版本号、配置文件、二进制信息、依赖关系等。
YUM客户端需要安装软件或者搜索软件,会查找/etc/yum.repos.d下以.repo结尾文件,CentOS Linux默认的.repo文件名为CentOS-Base.repo,该文件中配置了YUM源端的镜像地址,所以每次安装、升级RPM包,YUM客户端均会查找.repo文件。
YUM客户端如果配置了CentOS官方repo源,客户端操作系统必须能联外网,满足网络条件,才能下载软件并安装,如果没有网络,也可以构建光盘源或者内部YUM源。在只要YUM客户端时,YUM客户端安装软件,默认会把YUM源地址、Header信息、软件包、数据库信息、缓存文件存储在/var/cache/yum中,每次使用YUM工具,YUM优先通过Cache查找相关软件包,Cache中不存在,然后在访问外网YUM源。
6.5.2 YUM企业案例演练
由于YUM工具的使用简便、快捷、高效,在企业中得到广泛的使用,得到众多IT运维、程序人员的青睐,要能熟练使用YUM工具,需要先掌握YUM命令行参数的使用,如下为YUM命令工具的参数详解及实战步骤:
YUM命令工具指南,YUM格式为:
YUM [command] [package] -y|-q 其中的[options]是可选。-y安装或者卸载出现YES时,自动确认yes;-q不显示安装的过程。
yum install httpd 安装httpd软件包;
yum search YUM搜索软件包;
yum list httpd 显示指定程序包安装情况httpd;
yum list 显示所有已安装及可安装的软件包;
yum remove httpd 删除程序包httpd;
yum erase httpd 删除程序包httpd;
yum update 内核升级或者软件更新;
yum update httpd 更新httpd软件;
yum check-update 检查可更新的程序;
yum info httpd 显示安装包信息httpd;
yum provides 列出软件包提供哪些文件;
yum provides "*/rz" 列出rz命令由哪个软件包提供;
yum grouplist 查询可以用groupinstall安装的组名称;
yum groupinstall "Chinese Support" 安装中文支持;
yum groupremove "Chinese Support" 删除程序组Chinese Support;
yum deplist httpd 查看程序httpd依赖情况;
yum clean packages 清除缓存目录下的软件包;
yum clean headers 清除缓存目录下的headers;
yum clean all 清除缓存目录下的软件包及旧的headers。
(1)基于CentOS 7 Linux,执行命令yum install httpd -y,安装httpd服务,如图6-7所示:
图6-7 YUM 安装httpd软件
(2)执行命令yum grouplist,检查groupinstall的软件组名,如图6-8所示:
图6-8 YUM Grouplist显示组安装名称
(3)执行命令yum groupinstall "GNOME Desktop" -y,安装Linux图像界面,如图6-9所示:

图6-9 GNOME Desktop图像界面安装
(4)执行命令yum install httpd php php-devel php-mysql mariadb mariadb-server -y,安装中小企业LAMP架构环境,如图6-10所示:

图6-10 LAMP中小企业架构安装
(5)执行命令yum remove ntpdate -y,卸载ntpdate软件包,如图6-11所示:
图6-11 卸载NTPDATE软件
(6)执行命令yum provides rz或者yum provides "*/rz",查找rz命令的提供者,如图6-12所示:
图6-12 查找RZ命令的提供者
(7)执行命令yum update -y,升级Linux所有可更新的软件包或Linux内核升级,如图6-13所示:
图6-13 软件包升级或内核升级
6.6 基于ISO镜像构建YUM本地源
通常而言,YUM客户端使用前提是必须联外网,YUM安装软件时,检查repo配置文件查找相应的YUM源仓库,企业IDC机房很多服务器为了安全起见,是禁止服务器上外网的,所以不能使用默认的官方YUM源仓库。
构建本地YUM光盘源,其原理是通过查找光盘中的软件包,实现YUM安装,配置步骤如下:
(1)将CentOS-7-x86_64-DVD-1511.iso镜像加载至虚拟机CD/DVD或者放入服务器CD/DVD光驱中,并将镜像文件挂载至服务器/mnt目录,如图6-14所示,挂载命令:
mount /dev/cdrom /mnt/

图6-14 CentOS ISO镜像文件挂载
(2)备份/etc/yum.repos.d/CentOS-Base.repo文件为CentOS-Base.repo.bak,同时在/etc/yum.repos.d目录下创建media.repo文件,并写入如下内容:
[yum]
name=CentOS7
baseurl=file:///mnt
enabled=1
gpgcheck=1
gpgkey=file:///mnt/RPM-GPG-KEY-CentOS-7
Media.repo配置文件详解:
name=CentOS7 YUM源显示名称;
baseurl=file:///mnt ISO镜像挂载目录;
gpgcheck=1 是否检查GPG-KEY;
enabled=1 是否启用YUM源;
gpgkey=file:///mnt/RPM-GPG-KEY-CentOS-7 指定载目录下的GPG-KEY文件验证。
(3)运行命令yum clean all清空YUM Cache,执行yum install screen –y安装screen软件如图6-15所示:
图6-15 YUM 安装Screen软件
(4)至此YUM光盘源构建完毕,在使用YUM源时,会遇到部分软件无法安装,原因是因为光盘中软件包不完整导致,同时光盘源只能本机使用,其他局域网服务器无法使用。
6.7 基于HTTP构建YUM网络源
YUM光盘源默认只能本机使用,局域网其他服务器无法使用YUM光盘源,如果想使用的话,需要在每台服务器上构建YUM本地源,该方案在企业中不可取,所以需要构建HTTP局域网YUM源解决,可以通过CreateRepo创建本地YUM源端,repo即为Repository。
构建HTTP局域网YUM源方法及步骤如下:
(1)挂载光盘镜像文件至/mnt
mount /dev/cdrom /mnt/
(2)拷贝/mnt/Packages目录下所有软件包至/var/www/html/centos/
mkdir -p /var/www/html/centos/
cp -R /mnt/Packages/ /var/www/html/centos/
(3)使用Createrepo创建本地源,执行如下命令会在Centos目录生成repodata目录,目录内容如图6-16所示:
yum install createrepo
-y
cd /var/www/html
createrepo centos/
图6-16 Createrepo生成repodata目录
(4)利用HTTP发布YUM本地源
本地YUM源通过CreateRepo搭建完毕,需要借助HTTP WEB服务器发布/var/www/html/centos/中所有软件,YUM或者RPM安装HTTP WEB服务器,并启动httpd服务。
yum install httpd httpd-devel -y 安装HTTP WEB服务;
useradd apache -g apache 创建apache用户和组;
systemctl restart httpd.service 重启HTTPD服务;
setenforce 0 临时关闭SeLinux应用级安全策略;
systemctl stop firewalld.service 停止防火墙;
ps -ef |grep httpd 查看HTTPD进程是否启动。
(5)在YUM客户端,创建/etc/yum.repos.d/http.repo文件,写入如下内容:
[base]
name="CentOS7 HTTP YUM"
baseurl=http://192.168.1.115/centos/
gpgcheck=0
enabled=1
[updates]
name="CentOS7 HTTP YUM"
baseurl=http://192.168.1.115/centos
gpgcheck=0
enabled=1
(6)至此在YUM客户端上执行如下命令,如图6-17所示:
yum clean all 清空YUM Cache;
yum install ntpdate -y 安装NTPDATE软件。
图6-17 HTTP YUM源客户端验证
6.8 YUM源端软件包扩展
默认使用ISO镜像文件中的软件包构建的HTTP YUM源,会发现缺少很多软件包,如果服务器需要挂载移动硬盘,Mount挂载移动硬盘需要ntfs-3g软件包支持,而本地光盘镜像中没有该软件包,此时需要往YUM源端添加ntfs-3g软件包,添加方法如下:
(1)切换至/var/www/html/centos目录,官网下载NTFS-3G软件包。
cd /var/www/html/centos/
wget http://dl.fedoraproject.org/pub/epel/7/x86_64/n/ntfs-3g-2016.2.22-3.el7.x86_64.rpm
http://dl.fedoraproject.org/pub/epel/7/x86_64/n/ntfs-3g-devel-2016.2.22-3.el7.x86_64.rpm
(2)Createrepo命令更新软件包,同理,如需新增其他软件包,同样把软件下载至本地,然后通过createrepo更新即可,如图6-18所示:
createrepo --update centos/

图6-18 CreateRepo update更新软件包
(3)客户端YUM验证,安装NTFS-3G软件包,如图6-19所示:
图6-19 YUM INSTALL NTFS-3G软件包
6.9 同步外网YUM源
在企业实际应用场景中,仅仅靠光盘里面的RPM软件包是不能满足需要,我们可以把外网的YUM源中的所有软件包同步至本地,可以完善本地YUM源的软件包数量及完整性。
获取外网YUM源软件常见方法包括Rsync、Wget、Reposync,三种同步方法的区别Rsync方式需要外网YUM源支持RSYNC协议,Wget可以直接获取,而Reposync可以同步几乎所有的YUM源,下面以Reporsync为案例,同步外网YUM源软件至本地,步骤如下:
(1)下载CentOS7 REPO文件至/etc/yum.repos.d/,并安装reposync命令工具:
wget http://mirrors.163.com/.help/CentOS7-Base-163.repo
mv CentOS7-Base-163.repo /etc/yum.repos.d/centos.repo
yum clean all
yum install yum-utils createrepo –y
yum repolist
(2)通过reposync命令工具获取外网YUM源所有软件包,-r指定repolist id,默认不加-r表示获取外网所有YUM软件包,-p参数表示指定下载软件的路径,如图6-20(a)、图6-20(b)所示:
reposync -r base -p /var/www/html/centos/
reposync -r updates -p /var/www/html/centos/

图6-20(a) Reposync获取外网YUM源软件包

图6-20(b) Reposync获取外网YUM源软件包
(3)通过reposync工具下载完所有的软件包之后,需要执行createrepo更新本地YUM仓库:
createrepo /var/www/html/centos/
6.10 本章小结
通过对本章内容的学习,读者掌握了Linux安装不同包的工具及命令,使用RPM及YUM管理.RPM结尾的二进制包,基于configure、make、make install实现源码包安装,并能够对软件进行安装、卸载及维护。
能够独立构建企业光盘源、HTTP网络YUM源,实现无外网网络使用YUM安装各种软件包及工具,同时能随时添加新的软件包至本地Yum源中。
6.11 同步作业
1.RPM及YUM管理工具的区别是什么?
2.企业中安装软件,何时选择YUM安装或者源码编译安装?
3.将Linux系统中PHP5.3版本升级至PHP5.5版本,升级方法有几种,分别写出升级步骤?
4.使用源码编译安装httpd-2.4.25.tar.bz2,写出安装的流程及注意事项。
5.如何将CentOS 7 Linux字符界面升级为图形界面,并设置系统启动默认为图形界面?
第7章 Linux磁盘管理
Linux系统一切以文件的方式存储于硬盘,应用程序数据需要时刻读写硬盘,所以企业生产环境中对硬盘的操作变得尤为重要,对硬盘的维护和管理也是每个运维工程师必备工作之一。
本章向读者介绍硬盘简介、硬盘数据存储方式、如何在企业生产服务器添加硬盘、对硬盘进行分区、初始化以及对硬盘进行故障修复等。
7.1 计算机硬盘简介
硬盘是计算机主要存储媒介之一,由一个或者多个铝制或者玻璃制的碟片组成,碟片外覆盖有铁磁性材料,硬盘内部由磁道、柱面、扇区、磁头等部件组成,如图7-1所示:

图7-1 硬盘内部结构组成
Linux系统中硬件设备相关配置文件存放在/dev/下,常见硬盘命名:/dev/hda、/dev/sda、/dev/sdb、/dev/sdc、/dev/vda。不同硬盘接口,在系统中识别的设备名称不一样。
IDE硬盘接口在Linux中设备名为/dev/hda,SAS、SCSI、SATA硬盘接口在Linux中设备名为sda,高效云盘硬盘接口会识别为/dev/vda等。
文件储存在硬盘上,硬盘的最小存储单位叫做Sector(扇区),每个Sector储存512字节。操作系统在读取硬盘的时候,不会逐个Sector的去读取,这样效率非常低,为了提升读取效率,操作系统会一次性连续读取多个Sector,即一次性读取多个Sector称为一个Block(块)。
由多个Sector组成的Block是文件存取的最小单位。Block的大小常见的有1KB、2KB、4KB,Block在Linux中常设置为4KB,即连续八个Sector组成一个Block。
/boot分区Block一般为1KB,而/data/分区或者/分区的Block为4K。可以通过如下三种方法查看Linux分区的Block大小:
dumpe2fs /dev/sda1 |grep "Block size"
tune2fs -l /dev/sda1 |grep "Block size"
stat /boot/|grep "IO Block"
例如创建一个普通文件,文件大小为10Bytes,而默认设置Block为4K,如果有1万个小文件,由于每个Block只能存放一个文件,如果文件的大小比Block大,会申请更多的Block,相反如果文件的大小比默认Block小,仍会占用一个Block,这样剩余的空间会被浪费掉。
1万个文件理论只占用空间大小:10000x10=100000Bytes=97.65625MBytes;
1万个文件真实占用空间大小:10000x4096Bytes=40960000Bytes=40000MBytes=40GB。
根据企业实际需求,此时可以将Block设置为1K,从而节省更多的空间。
7.2 硬盘Block及Inode详解
通常而言,操作系统对于文件数据的存放包括两个部分:文件内容、权限及文件属性。操作系统文件存放是基于文件系统,文件系统会将文件的实际内容存储到Block中,而将权限与属性等信息存放至Inode中。
在硬盘分区中,还有一个超级区块 (SuperBlock) ,SuperBlock会记录整个文件系统的整体信息,包括 Inode、Block 总量、使用大小、剩余大小等信息,每个 inode 与 block 都有编号对应,方便Linux系统快速定位查找文件。
Superblock:记录文件系统的整体信息,包括inode与block的总量、使用大小、剩余大小, 以及文件系统的格式与相关信息等;
Inode:记录文件的属性,权限,同时会记录该文件的数据所在的block编号;
Block:存储文件的内容,如果文件超过默认Block大小,会自动占用多个Block。
因为每个 inode 与 block 都有编号,而每个文件都会占用一个 inode ,inode 内则有文件数据放置的 block 号码。如果能够找到文件的 inode,就可以找到该文件所放置数据的block号码,从而读取该文件内容。
操作系统进行格式化分区时,操作系统自动将硬盘分成两个区域。一个是数据Block区,用于存放文件数据;另一个是Inode Table区,用于存放inode包含的元信息。
每个inode节点的大小,可以在格式化时指定,默认为128Bytes或256Bytes,/boot分区Inode默认为128Bytes,其他分区默认为256Bytes,查看Linux系统Inode方法如下:
dumpe2fs /dev/sda1 |grep " Inode size "
tune2fs -l /dev/sda1 |grep " Inode size"
stat /boot/|grep "Inode"
格式化磁盘时,可以指定默认Inode和Block的大小,-b指定默认Block值,-I指定默认Inode值,如图7-2所示,命令如下:
mkfs.ext4 -b 4096 -I 256 /dev/sdb
图7-2 格式化硬盘指定Inode和Block
7.3 硬链接介绍
一般情况下,文件名和inode编号是一一对应的关系,每个inode号码对应一个文件名。但UNIX/Linux系统多个文件名也可以指向同一个inode号码。这意味着可以用不同的文件名访问同样的内容,对文件内容进行修改,会影响到所有文件名。但删除一个文件名,不影响另一个文件名的访问。这种情况就被称为硬链接(hard link)。
创建硬链接的命令为:ln jf1.txt jf2.txt,其中jf1.txt为源文件,jf2.txt为目标文件。如上命令源文件与目标文件的inode号码相同,都指向同一个inode。inode信息中有一项叫做"链接数",记录指向该inode的文件名总数,这时会增加1,变成2,如图7-3所示:
图7-3 jf1.txt jf2.txt硬链接inode值变化
同样删除一个jf2.txt文件,就会使得jf1.txt inode节点中的"链接数"减1。如果该inode值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域,如图7-4所示:
图7-4 删除jf2.txt硬链接inode值变化
实用小技巧:硬链接不能跨分区链接,硬链接只能对文件生效,对目录无效,也即是目录不能创建硬链接。硬链接源文件与目标文件共用一个inode值,从某种意义上来,节省inode空间。不管是单独删除源文件还是删除目标文件,文件内容始终存在。同时链接后的文件不占用系统多余的空间。
7.4 软链接介绍
除了硬链接以外,还有一种链接-软链接。文件jf1.txt和文件jf2.txt的inode号码虽然不一样,但是文件jf2.txt的内容是文件jf1.txt的路径。读取文件jf2.txt时,系统会自动将访问者导向文件jf1.txt。
无论打开哪一个文件,最终读取的都是文件jf1.txt。这时,文件jf2.txt就称为文件jf1.txt的"软链接"(soft link)或者"符号链接(symbolic link)。
文件jf2.txt依赖于文件jf1.txt而存在,如果删除了文件jf1.txt,打开文件jf2.txt就会报错:"No such file or directory"。
软链接与硬链接最大的不同是文件jf2.txt指向文件jf1.txt的文件名,而不是文件jf1.txt的inode号码,因此文件jf1.txt的inode链接数不会发生变化,如图7-5所示:

图7-5 删除jf1.txt源文件链接数不变
实用小技巧:软链接可以跨分区链接,软链接支持目录同时也支持文件的链接。软链接源文件与目标文件Inode不相同,从某种意义上来,会消耗省inode空间。不管是删除源文件还是重启系统,该软链接还存在,但是文件内容会丢失,一旦新建源同名文件名,软链接文件恢复正常。
7.5 Linux下磁盘实战操作命令
企业真实场景由于硬盘常年大量读写,经常会出现坏盘,需要更换硬盘。或者由于磁盘空间不足,需添加新硬盘,新添加的硬盘需要经过格式化、分区才能被Linux系统所使用,虚拟机CentOS 7 Linux模拟DELL R730真实服务器添加一块新硬盘,不需要关机,直接插入用硬盘即可,一般硬盘均支持热插拔功能。企业中添加新硬盘的操作流程如下:
(1)检测Linux系统识别的硬盘设备,新添加硬盘被识别为/dev/sdb,如果有多块硬盘,会依次识别成/dev/sdc、/dev/sdd等设备名称,如图7-6所示:
fdisk -l

图7-6 Fdisk查看Linux系统硬盘设备
(2)基于新硬盘/dev/sdb设备,创建磁盘分区/dev/sdb1,如图7-7所示:
fdisk /dev/sdb
图7-7 Fdisk /dev/sdb分区
(3)fdisk分区命令参数如下,常用参数包括m、n、p、e、d、w。
b 编辑bsd disklabel;
c 切换dos兼容性标志;
d 删除一个分区;
g 创建一个新的空GPT分区表;
G 创建一个IRIX(SGI)分区表;
l 列出已知的分区类型;
m 打印帮助菜单;
n 添加一个新分区;
o 创建一个新空DOS分区表;
p 打印分区表信息;
q 退出而不保存更改;
s 创建一个新的空的Sun磁盘标签;
t 更改分区的系统ID;
u 更改显示/输入单位;
v 验证分区表;
w 将分区表写入磁盘并退出;
x 额外功能。
(4)创建/dev/sdb1分区方法,fdisk /dev/sdb,然后按n-p-1-Enter键- +20G-Enter键-w,最后执行fdisk –l|tail -10,如图7-8(a)、图7-8(b)所示:

图7-8(a) Fdisk /dev/sdb创建/dev/sdb1分区
图7-8(b) Fdisk –l查看/dev/sdb1分区
(5)mkfs.ext4 /dev/sdb1格式化磁盘分区,如图7-9所示:
图7-9 mkfs.ext4格式化磁盘分区
(6)/dev/sdb1分区格式化,使用mount命令挂载到/data/目录,如图7-10所示:
mkdir -p /data/ 创建/data/数据目录
mount /dev/sdb1 /data 挂载/dev/sdb1分区至/data/目录
df -h 查看磁盘分区详情
echo "mount /dev/sdb1 /data" >>/etc/rc.local 将挂载分区命令加入/etc/rc.local开机启动
图7-10 MOUNT挂载/dev/sdb1磁盘分区
(7)自动挂载分区除了可以加入到/etc/rc.local开机启动之外,还可以加入到/etc/fstab文件中,如图7-11所示:
/dev/sdb1 /data/ ext4 defaults 0 0
mount -o rw,remount / 重新挂载/系统,检测/etc/fstab是否有误。

图7-11 /dev/sdb1磁盘分区加入/etc/fstab文件
7.6 基于GPT格式磁盘分区
MBR分区标准决定了MBR只支持在2TB以下的硬盘,为了支持能使用大于2T硬盘空间,需使用GPT格式进行分区。创建大于2TB的分区,需使用parted工具。
在企业真实环境中,通常一台服务器有多块硬盘,整个硬盘容量为10T,需要基于GTP格式对10T硬盘进行分区,操作步骤如下:
parted -s /dev/sdb mklabel gpt 设置分区类型为gpt格式;
mkfs.ext3 /dev/sdb 基于Ext3文件系统类型格式化;
mount /dev/sdb /data/ 挂载/dev/sdb设备至/data/目录。
(1)如图7-12所示,假设/dev/sdb 为10T硬盘,使用GPT格式来格式化磁盘:
图7-12 假设/dev/sdb为10T设备
(2)执行命令:parted -s /dev/sdb mklabel gpt,如图7-13所示:
图7-13 设置/dev/sdb为GPT格式磁盘
(3)基于mkfs.ext3 /dev/sdb格式化磁盘,如图7-14所示:
图7-14 格式/dev/sdb磁盘
parted命令行也可以进行分区,如图7-15(a)、7-15(b)、7-15(c)所示:
partedselect /dev/sdbmklabel gptmkpart primary 0 -1print
mkfs.ext3 /dev/sdb1
mount /dev/sdb1 /data/
图7-15(a)parted工具执行GPT格式分区

图7-15(b)parted工具执行GPT格式分区

图7-15(c) parted工具执行GPT格式分区
7.7 MOUNT命令工具
Mount命令工具主要用于将设备或者分区挂载至Linux系统目录下,Linux系统在分区时,也是基于mount机制将/dev/sda分区挂载至系统目录,将设备与目录挂载之后,Linux操作系统方可进行文件的存储。
7.7.1 Mount命令参数详解
如下为企业中Mount命令常用参数详解:
mount [-Vh]
mount -a [-fFnrsvw] [-t vfstype]
mount [-fnrsvw] [-o options [,...]] device | dir
mount [-fnrsvw] [-t vfstype] [-o options] device dir
-V: 显示mount工具版本号;
-l: 显示已加载的文件系统列表;
-h: 显示帮助信息并退出;
-v: 输出指令执行的详细信息;
-n: 加载没有写入文件/etc/mtab中的文件系统;
-r: 将文件系统加载为只读模式;
-a: 加载文件/etc/fstab中配置的所有文件系统;
-o: 指定mount挂载扩展参数,常见扩展指令:rw、remount、loop等,其中-o相关指令如下:
-o atime: 系统会在每次读取文档时更新文档时间;
-o noatime: 系统会在每次读取文档时不更新文档时间;
-o defaults: 使用预设的选项 rw,suid,dev,exec,auto,nouser等;
-o exec 允许执行档被执行;
-o user、-o nouser: 使用者可以执行 mount/umount的动作;
-o remount: 将已挂载的系统分区重新以其他再次模式挂载;
-o ro: 只读模式挂载;
-o rw: 可读可写模式挂载;
-o loop 使用loop模式,把文件当成设备挂载至系统目录。
-t: 指定mount挂载设备类型,常见类型nfs、ntfs-3g、vfat、iso9660等,其中-t相关指令如下:
iso9660 光盘或光盘镜像;
msdos Fat16文件系统;
vfat Fat32文件系统;
ntfs NTFS文件系统;
ntfs-3g 识别移动硬盘格式;
smbfs 挂载Windows文件网络共享;
nfs Unix/Linux文件网络共享。
7.7.2 企业常用Mount案例
Mount常用案例演示如下:
mount /dev/sdb1 /data 挂载/dev/sdb1分区至/data/目录
mount /dev/cdrom /mnt 挂载Cdrom光盘至/mnt目录;
mount -t ntfs-3g /dev/sdc /data1 挂载/dev/sdc移动硬盘至/data1目录;
mount -o remount,rw / 重新以读写模式挂载/系统;
mount -t iso9660 -o loop centos7.iso /mnt 将centos7.iso镜像文件挂载至/mnt目录;
mount -t fat32 /dev/sdd1 /mnt 将U盘/dev/sdd1挂载至/mnt/目录;
mount -t nfs 192.168.1.11:/data/ /mnt 将远程192.168.1.11:/data目录挂载至本地/mnt目录。
7.8 Linux硬盘故障修复
企业服务器运维中,经常会发现操作系统的分区变成只读文件系统,错误提示信息为
“Read-only file system”,出现只读文件系统,会导致只能读取,而无法写入新文件、新数据等操作。
造成该问题的原因包括:磁盘老旧长期大量的读写、文件系统文件被破坏、磁盘碎片文件、异常断电、读写中断等等。
以企业CentOS 7 Linux为案例,来修复文件系统,步骤如下:
(1)远程备份本地其他重要数据,出现只读文件系统,需先备份其他重要数据,基于rsync|scp远程备份,其中/data为源目录,/data/backup/2017/为目标备份目录。
rsync -av /data/ root@192.168.111.188:/data/backup/2017/
(2)可以重新挂载/系统,挂载命令如下,测试文件系统是否可以写入文件。
mount -o remount,rw /
(3)如果重新挂载/系统无法解决问题,则需重启服务器,以CD/DVD光盘引导进入Linux Rescue修复模式,如图7-16(a)、7-16(b)所示,光标选择“Troubleshooting”,按Enter键,然后选择“Rescue a CentOS system”,按Enter键。
图7-16(a) 光盘引导进入修复模式
图7-16(b) 光盘引导进入修复模式
(4)选择“1)Continue”继续操作,如图7-17所示:

图7-17 选择Continue继续进入系统
(5)登录修复模式,执行如下命令,df –h显示原来的文件系统,如图7-18所示:
chroot /mnt/sysimage
df -h
图7-18 切换原分区目录
(6)对有异常的分区进行检测并修复,根据文件系统类型,执行相应的命令如下:
umount /dev/sda3
fsck.ext4 /dev/sda3 –y
(7)修复完成之后,重启系统即可
reboot
7.9 本章小结
通过对本章内容的学习,读者掌握了Linux硬盘内部结构、Block及Inode特性,能够对企业硬盘进行分区、格式化等操作,满足企业的日常需求。
基于mount工具,能对硬盘、各类文件系统进行挂载操作,同时对只读文件系统能快速修复并投入使用。
7.10 同步作业
1.软链接与硬链接的区别是什么?
2.有一块4T的移动硬盘,如何将数据拷贝至服务器/data/目录,服务器空间为10T,请写出详细步骤?
3.运维部小刘发现公司IDC机房一台DELL R730服务器,/data/目录不可写,而/boot目录可读可写,请问原因是什么导致,如何修复/data/目录?
4.公司一台DELL R730服务器/data/images目录存放了大量的小文件,运维人员向该目录写入1M测试文件,提示磁盘空间不足,而通过df –h显示剩余可用空间为500G,请问是什么原因导致,如何解决该问题?
5.机房一台DELL R730服务器,由于业务需求,临时重启,重启完,20分钟后还无法登陆系统,检查控制台输出,一直卡在MySQL服务启动项,请问如何快速解决让系统正常启动,请写出解决步骤。
第8章 Linux文件服务器企业实战
运维和管理企业Linux服务器,除了要熟练Linux系统本身的维护和管理之外,最重要的是熟练甚至精通基于Linux系统安装配置各种应用软件,对软件进行调优以及软件在使用中遇到各类问题,能够快速定位并解决问题。
本章向读者介绍进程、线程、企业Vsftpd服务器实战、匿名用户访问、系统用户访问及虚拟用户实战等。
8.1 进程与线程概念及区别
Linux系统各种软件和服务,存在于系统,必然会占用系统各种资源,系统资源是如何分配及调度的呢,本节将给读者展示系统进程、资源及调度相关的内容。
进程(Process)是计算机中的软件程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
在早期面向进程设计的计算机结构中,进程是程序的基本执行实体,在当代面向线程设计的计算机结构中,进程是线程的容器。软件程序是对指令、数据及其组织形式的描述,而进程是程序的实体,通常而言,把运行在系统中的软件程序称之为进程。
除了进程,读者通常会听到线程的概念,线程也被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有操作系统资源,但是该线程可与同属进程的其它线程共享该进程所拥有的全部资源。
程序、进程、线程三者区别如下:
程序:程序并不能单独执行,是静止的,只有将程序加载到内存中,系统为其分配资源后才能够执行;
进程:程序对一个数据集的动态执行过程,一个进程包含一个或者更多的线程,一个线程同时只能被一个进程所拥有,进程是分配资源的基本单位。进程拥有独立的内存单元,而多个线程共享内存,从而提高了应用程序的运行效率。
线程:线程是进程内的基本调度单位,线程的划分尺度小于进程,并发性更高,线程本身不拥有系统资源, 但是该线程可与同属进程的其它线程共享该进程所拥有的全部资源。每一个独立的线程,都有一个程序运行的入口、顺序执行序列、和程序的出口。
如图8-1所示,程序、进程、线程三者的关系拓扑图:
图8-1 程序、进程、线程关系图
如上图8-1所示,多进程、多线程的区别如下:
多进程,每个进程互相独立,不影响主程序的稳定性,某个子进程崩溃对其他进程没有影响,通过增加CPU可以扩充软件的性能,可以减少线程加锁/解锁的影响,极大提高性能。缺点是多进程逻辑控制复杂,需要和主程序交互,需要跨进程边界,进程之间上下文切换比线程之间上下文切换代价大。
多线程,无需跨进程,程序逻辑和控制方式简单,所有线程共享该进程的内存和变量等。缺点是每个线程与主程序共用地址空间,线程之间的同步和加锁控制比较麻烦,一个线程的崩溃会影响到整个进程或者程序的稳定性。
8.2 Vsftpd服务器企业实战
文件传输协议(File Transfer Protocol,FTP),基于该协议FTP客户端与服务端可以实现共享文件、上传文件、下载文件。 FTP 基于TCP协议生成一个虚拟的连接,主要用于控制FTP连接信息,同时再生成一个单独的TCP连接用于FTP数据传输。用户可以通过客户端向FTP服务器端上传、下载、删除文件,FTP服务器端可以同时提供给多人共享使用。
FTP服务是Client/Server(简称C/S)模式,基于FTP协议实现FTP文件对外共享及传输的软件称之为FTP服务器源端,客户端程序基于FTP协议,则称之为FTP客户端,FTP客户端可以向FTP服务器上传、下载文件。
8.2.1 FTP传输模式
FTP基于C/S模式,FTP客户端与服务器端有两种传输模式,分别是FTP主动模式、FTP被动模式,主被动模式均是以FTP服务器端为参照。主被动模式如图8-2(a)、8-2(b)所示,主被动模式详细区别如下:
FTP主动模式:客户端从一个任意的端口N(N>1024)连接到FTP服务器的port 21命令端口,客户端开始监听端口N+1,并发送FTP命令“port N+1”到FTP服务器,FTP服务器以数据端口(20)连接到客户端指定的数据端口(N+1)。
FTP被动模式:客户端从一个任意的端口N(N>1024)连接到FTP服务器的port 21命令端口,客户端开始监听端口N+1,客户端提交 PASV命令,服务器会开启一个任意的端口(P >1024),并发送PORT P命令给客户端。客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据。
在企业实际环境中,如果FTP客户端与FTP服务端均开放防火墙,FTP需以主动模式工作,这样只需要在FTP服务器端防火墙规则中,开放20、21端口即可。关于防火墙配置后面章节会讲解。

图8-2(a) FTP主动模式
图8-2(b) FTP被动模式
8.2.2 Vsftpd服务器简介
目前主流的FTP服务器端软件包括:Vsftpd、ProFTPD、PureFTPd、Wuftpd、Server-U FTP、 FileZilla Server等软件,其中Unix/Linux使用较为广泛的FTP服务器端软件为Vsftpd 。
非常安全的FTP服务进程(Very Secure FTP daemon,Vsftpd),Vsftpd在Unix/Linux发行版中最主流的FTP服务器程序,优点小巧轻快,安全易用、稳定高效、满足企业跨部门、多用户的使用等。
Vsftpd基于GPL开源协议发布,在中小企业中得到广泛的应用,Vsftpd可以快速上手,基于Vsftpd虚拟用户方式,访问验证更加安全。Vsftpd还可以基于MYSQL数据库做安全验证,多重安全防护。
8.2.3 Vsftpd服务器安装配置
Vsftpd服务器端安装有两种方法,一是基于YUM方式安装,而是基于源码编译安装,最终实现效果完全一致,本文采用YUM安装Vsftpd,步骤如下:
(1)在命令行执行如下命令,如图8-3所示:
yum install vsftpd* -y
图8-3 YUM安装Vsftpd服务端
(2)打印vsftpd安装后的配置文件路径、启动Vsftpd服务及查看进程是否启动,如图8-4所示:
rpm -ql vsftpd|more
systemctl restart vsftpd.service
ps -ef |grep vsftpd
图8-4 打印Vsftpd软件安装后路径
(3)Vsftpd.conf默认配置文件详解如下:
anonymous_enable=YES 开启匿名用户访问;
local_enable=YES 启用本地系统用户访问;
write_enable=YES 本地系统用户写入权限;
local_umask=022 本地用户创建文件及目录默认权限掩码;
dirmessage_enable=YES 打印目录显示信息,通常用于用户第一次访问目录时,信息提示;
xferlog_enable=YES 启用上传/下载日志记录;
connect_from_port_20=YES FTP使用20端口进行数据传输;
xferlog_std_format=YES 日志文件将根据xferlog的标准格式写入;
listen=NO Vsftpd不以独立的服务启动,通过Xinetd服务管理,建议改成YES;
listen_ipv6=YES 启用IPV6监听;
pam_service_name=vsftpd 登录FTP服务器,依据/etc/pam.d/vsftpd中内容进行认证;
userlist_enable=YES vsftpd.user_list和ftpusers配置文件里用户禁止访问FTP;
tcp_wrappers=YES 设置vsftpd与tcp wrapper结合进行主机的访问控制,Vsftpd服务器检查/etc/hosts.allow 和/etc/hosts.deny中的设置,来决定请求连接的主机,是否允许访问该FTP服务器。
(4)启动Vsftpd服务后,通过Windows客户端资源管理器访问Vsftp服务器端,如图8-5所示:
ftp://192.168.111.131/
图8-5 匿名用户访问FTP默认目录
FTP主被动模式,默认为被动模式,设置为被动模式使用端口方法如下:
pasv_enable=YES
pasv_min_port=60000
pasv_max_port=60100
8.2.4 Vsftpd匿名用户配置
Vsftpd默认以匿名用户访问,匿名用户默认访问的FTP服务器端路径为:/var/ftp/pub,匿名用户只有查看权限,无法创建、删除、修改。如需关闭FTP匿名用户访问,需修改配置文件/etc/vsftpd/vsftpd.conf,将anonymous_enable=YES修改为anonymous_enable=NO,重启Vsftpd服务即可。
如果允许匿名用户能够上传、下载、删除文件,需在/etc/vsftpd/vsftpd.conf配置文件中加入如下代码:
anon_upload_enable=YES 允许匿名用户上传文件;
anon_mkdir_write_enable=YES 允许匿名用户创建目录;
anon_other_write_enable=YES 允许匿名用户其他写入权限。
匿名用户完整vsftpd.conf配置文件代码如下:
anonymous_enable=YES
local_enable=YES
write_enable=YES
local_umask=022
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
listen=NO
listen_ipv6=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES
由于默认Vsftpd匿名用户有两种:anonymous、ftp,所以匿名用户如果需要上传文件、删除及修改等权限,需要ftp用户对/var/ftp/pub目录有写入权限,使用如下chown和chmod任意一种即可,设置命令如下:
chown -R ftp pub/
chmod o+w pub/
如上Vsftpd.conf配置文件配置完毕,同时权限设置完,重启vsftpd服务即可,通过Windows客户端访问,能够上传文件、删除文件、创建目录等操作,如图8-6所示:

图8-6 匿名用户访问上传文件
8.2.5 Vsftpd系统用户配置
Vsftpd匿名用户设置完毕,匿名用户,任何人都可以查看FTP服务器端的文件、目录,甚至可以修改、删除,此方案如适合存放私密文件在FTP服务器端,如何保证文件或者目录专属拥有者呢,Vsftpd系统用户可以实现该需求。
实现Vsftpd系统用户方式验证,只需在Linux系统中创建多个用户即可,创建用户使用useradd,同时给用户设置密码,即可通过用户和密码登录FTP,进行文件上传、下载、删除等操作。Vsftpd系统用户实现方法步骤如下:
(1)Linux系统中创建系统用户jfedu1、jfedu2,分别设置密码为123456:
useradd jfedu1
useradd jfedu2
echo 123456|passwd --stdin jfedu1
echo 123456|passwd --stdin jfedu2
(2)修改vsftpd.conf配置文件代码如下:
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
listen=NO
listen_ipv6=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES
(3)通过Windows资源客户端验证,使用jfedu1、jfedu2用户登录FTP服务器,即可上传文件、删除文件、下载文件,jfedu1、jfedu2系统用户上传文件的家目录在/home/jfedu1、/home/jfedu2下,如图8-7(a)、8-7(b)所示:
图8-7(a) jfedu1用户登录FTP服务器
图8-7(b) jfedu1登录FTP服务器上传文件
8.2.6 Vsftpd虚拟用户配置
如果基于Vsftpd系统用户访问FTP服务器,系统用户越多越不利于管理,而且不利于系统安全管理,鉴于此,为了能更加的安全使用VSFTPD,需使用Vsftpd虚拟用户方式。
Vsftpd虚拟用户原理:虚拟用户就是没有实际的真实系统用户,而是通过映射到其中一个真实用户以及设置相应的权限来实现访问验证,虚拟用户不能登录Linux系统,从而让系统更加的安全可靠。
Vsftpd虚拟用户企业案例配置步骤如下:
(1)安装Vsftpd虚拟用户需用到的软件及认证模块:
yum install pam libdb-utils libdb --skip-broken -y
(2)创建虚拟用户临时文件/etc/vsftpd/ftpusers.txt,新建虚拟用户和密码,其中jfedu001、jfedu002为虚拟用户名,123456为密码,如果有多个用户,依次格式填写即可:
jfedu001
123456
jfedu002
123456
(3)生成Vsftpd虚拟用户数据库认证文件,设置权限700:
db_load -T -t hash -f /etc/vsftpd/ftpusers.txt /etc/vsftpd/vsftpd_login.db
chmod 700 /etc/vsftpd/vsftpd_login.db
(4)配置PAM认证文件,/etc/pam.d/vsftpd行首加入如下两行:
auth required pam_userdb.so db=/etc/vsftpd/vsftpd_login
account required pam_userdb.so db=/etc/vsftpd/vsftpd_login
(5)所有Vsftpd虚拟用户需要映射到一个系统用户,该系统用户不需要密码,也不需要登录,主要用于虚拟用户映射使用,创建命令如下:
useradd -s /sbin/nologin ftpuser
(6)完整vsftpd.conf配置文件代码如下:

global config Vsftpd 2017

anonymous_enable=YES
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
listen=NO
listen_ipv6=YES
userlist_enable=YES
tcp_wrappers=YES

config virtual user FTP

pam_service_name=vsftpd
guest_enable=YES
guest_username=ftpuser
user_config_dir=/etc/vsftpd/vsftpd_user_conf
virtual_use_local_privs=YES
如上Vsftpd虚拟用户配置文件参数详解:

config virtual user FTP

pam_service_name=vsftpd 虚拟用户启用pam认证;
guest_enable=YES 启用虚拟用户;
guest_username=ftpuser 映射虚拟用户至系统用户ftpuser;
user_config_dir=/etc/vsftpd/vsftpd_user_conf 设置虚拟用户配置文件所在的目录;
virtual_use_local_privs=YES 虚拟用户使用与本地用户相同的权限。
(7)至此,所有虚拟用户共同基于/home/ftpuser主目录实现文件上传与下载,可以在/etc/vsftpd/vsftpd_user_conf目录创建虚拟用户各自的配置文件,创建虚拟用户配置文件主目录:
mkdir -p /etc/vsftpd/vsftpd_user_conf/
(8)如下分别为虚拟用户jfedu001、jfedu002用户创建配置文件:
vim /etc/vsftpd/vsftpd_user_conf/jfedu001,同时创建私有的虚拟目录,代码如下:
local_root=/home/ftpuser/jfedu001
write_enable=YES
anon_world_readable_only=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
vim /etc/vsftpd/vsftpd_user_conf/jfedu002,同时创建私有的虚拟目录,代码如下:
local_root=/home/ftpuser/jfedu002
write_enable=YES
anon_world_readable_only=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
虚拟用户配置文件内容详解:
local_root=/home/ftpuser/jfedu002 jfedu002虚拟用户配置文件路径;
write_enable=YES 允许登陆用户有写权限;
anon_world_readable_only=YES 允许匿名用户下载,然后读取文件;
anon_upload_enable=YES 允许匿名用户上传文件权限,只有在write_enable=YES时该参数才生效;
anon_mkdir_write_enable=YES 允许匿名用户创建目录,只有在write_enable=YES时该参数才生效;
anon_other_write_enable=YES 允许匿名用户其他权限,例如删除、重命名等。
(9)创建虚拟用户各自虚拟目录:
mkdir -p /home/ftpuser/{jfedu001,jfedu002} ;chown -R ftpuser:ftpuser /home/ftpuser
重启Vsftpd服务,通过Windows客户端资源管理器登录Vsftpd服务端,测试结果如图8-8(a)、8-8(b)所示:
图8-8(a) jfedu001虚拟用户登录FTP服务器
图8-8(b) jfedu001虚拟用户上传下载文件
第9章 HTTP协议详解
超文本传输协议(HyperText Transfer Protocol,HTTP)是互联网上应用最为广泛的一种网络协议。所有的WWW服务器都基于该协议。HTTP设计最初的目的是为了提供一种发布WEB页面和接收WEB页面的方法。
本章向读者介绍TCP、HTTP协议、HTTP资源定位、HTTP请求及响应头详细信息、HTTP状态码及MIME类型详解等。
9.1 TCP协议与HTTP协议
1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),为HTTP超文本传输协议标准架构的发展奠定了根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。
很多读者对TCP协议与HTTP协议存在疑问,这两者有什么区别呢,从应用领域来说,TCP协议主要用于数据传输控制,而HTTP协议主要用于应用层面的数据交互,本质上两者没有可比性。
HTTP协议属于应用层协议,是建立在TCP协议基础之上,HTTP协议以客户端请求和服务器端应答为标准,浏览器通常称为客户端,而WEB服务器称之为服务器端。客户端打开任意一个端口向服务端的指定端口(默认为80)发起HTTP请求,首先会发起TCP三次握手,TCP三次握手的目的是建立可靠的数据连接通道,TCP三次握手通道建立完毕,进行HTTP数据交互,如图9-1(a)、9-1(b)所示:
图9-1(a) HTTP与TCP关系结构图
图9-1(b) HTTP客户端与服务器
当客户端请求的数据接收完毕后,HTTP服务器端会断开TCP连接,整个HTTP连接过程非常短。HTTP连接也称为无状态的连接,无状态连接是指客户端每次向服务器发起HTTP请求时,每次请求都会建立一个新的HTTP连接,而不是在一个HTTP请求基础上进行所有数据的交互。
9.2 资源定位标识符
发起HTTP请求的内容资源由统一资源标示符(Uniform Resource Identifiers,URI)来标识,关于资源定位及标识有三种:URI、URN、URL,三种资源定位详解如下:
统一资源标识符(uniform resource identifier,URI),用来唯一标识一个资源;
统一资源定位器(uniform resource locator,URL),是一种具体的URI。URL可以用来标识一个资源,而且访问或者获取该资源;
统一资源命名(uniform resource name,URN),通过名字来标识或识别资源。
如图9-2所示,可以直观区分URI、URN、URL的区别:
图9-2 URI、URN、URL关联与区别
三种资源标识,其中URL资源标识方式使用最为广泛,完整的URL标识格式如下:
protocol://host[:port]/path/.../[?query-string][#anchor]
protocol 基于某种协议,常见协议:http、https、ftp、rsync等;
host 服务器的IP地址或者域名;
port 服务器的端口号,如果是HTTP 80端口,默认可以省略。
path 访问资源在服务器的路径;
query-string 传递给服务器的参数及字符串;
anchor- 锚定结束;
Http URL案例演示如下:
http://www.jfedu.net/newindex/plus/list.php?tid=2#jfedu
protocol: http协议;
host: www.jfedu.net;
path: /newindex/plus/list.php
Query String: tid=2
Anchor: jfedu
9.3 HTTP与端口通信
HTTP WEB服务器默认在本机会监听80端口,不仅HTTP会开启监听端口,其实每个软件程序在Linux系统中运行,会以进程的方式启动,程序就会启动并监听本地接口的端口,为什么会引入端口这个概念呢?
端口是TCP/IP协议中应用层进程与传输层协议实体间的通信接口,端口是操作系统可分配的一种资源,应用程序通过系统调用与某个端口绑定后,传输层传给该端口的数据会被该进程接收,相应进程发给传输层的数据都通过该端口输出。
在网络通信过程中,需要唯一识别通信两端设备的端点,就是使用端口识别运行于某主机中的应用程序。如果没有引入端口,则只能通过PID进程号进行识别,而PID进程号是系统动态分配的,不同的系统会使用不同的进程标识符,应用程序在运行之前没有明确的进程号,如果需要运行后再广播进程号则很难保证通信的顺利进行。
而引入端口后,就可以利用端口号识别应用程序,同时通过固定端口号来识别和使用某些公共服务,例如如HTTP默认使用80端口,而FTP使用21、20端口,MYSQL则使用3306端口。
使用端口还有一个原因是随着计算机网络技术的发展,物理机器上的硬件接口已不能满足网络通信的要求,而TCP/IP协议模型作为网络通信的标准就解决了这个通信难题。
TCP/IP协议中引入了一种被称为套接字(Socket)的应用程序接口。基于Socket接口技术,一台计算机就可以与任何一台具有Socket接口的计算机进行通信,而监听的端口在服务器端也称之为Socket接口。
9.4 HTTP Request与Response详解
客户端浏览器向WEB服务器发起Request, Web服务器接到Request后进行处理,会生成相应的Response信息返给浏览器,客户端浏览器收到服务器返回的Response信息,会对信息进行解析处理,最终用户看到浏览器展示WEB服务器的网页内容。
客户端发起Request,Request消息分为三个部分,分别包括:Request line、Request header、Body,如图9-3所示:
图9-3 HTTP Request Message组成
Unix/Linux系统中执行CURL -v命令可以打印访问WEB服务器的Request及Response详细处理流程,如图9-4所示:
curl -v http://192.168.111.131/index.html
图9-4 Request及Response请求回应流程
(1)Request信息详解如表9-1所示:
HTTP/1.1 200 OK 请求行

Request Message
User-Agent: curl/7.19.7
Host: 192.168.111.131
Accept: /
……
请求头部

空行
请求Body
第一部分:请求行,指定请求类型,访问的资源及使用的HTTP协议版本。
GET表示Request请求类型为GET;/index.html表示访问的资源;HTTP/1.1表示协议版本。
第二部分:请求头部,请求行下一行起,指定服务器要使用的附加信息;
User-Agent 表示用户使用的代理软件,常指浏览器;HOST表示请求的目的主机。
第三部分:空行,请求头部后面的空行表示请求头发送完毕。
第四部分:请求数据也叫Body,可以添加任意的数据,Get请求的Body内容默认为空。
表9-1 Request请求头详解
(2)Response信息详解如表9-2所示:
HTTP/1.1 200 OK 响应行

Response Message
Server: nginx/1.10.1
Date: Thu, 11 May 2017
Content-Type: text/html
……
响应头部

空行

www.jf1.com Pages

响应Body 第一部分:响应状态行,包括HTTP协议版本号、状态码、状态消息。 HTTP/1.1表示HTTP协议版本号;200表示返回状态码;OK表示状态消息。 第二部分:消息报头,响应头部附加信息。 Date表示生成响应的日期和时间,Content-Type表示指定MIME类型的HTML(text/html),编码类型是UTF-8,记录文件资源的Last-Modified时间。 第三部分:空行,表示消息报头响应完毕。 第四部分:响应正文,服务器返回给客户端的文本信息。 表9-2 Request请求头详解 (3)Request请求方法根据请求的资源不同,有如下请求方法: GET方法,向特定的资源发出请求,获取服务器端数据; POST方法,向WEB服务器提交数据进行处理请求,常指提交新数据; PUT方法,向WEB服务器提交上传最新内容,常指更新数据; DELETE方法,请求删除Request-URL所标识的服务器资源; TRACE方法,回显服务器收到的请求,主要用于测试或诊断; CONNECT方法,HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器; OPTIONS方法,返回服务器针对特定资源所支持的HTTP请求方法; HEAD方法,HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。 9.5 HTTP 1.0/1.1协议区别 HTTP 协议定义服务器端和客户端之间文件传输的沟通方式HTTP1.0运行方式,如图9-5所示:

图9-5 HTTP1.0 客户端、服务器传输模式
基于HTTP协议的客户/服务器模式的信息交换过程,如图所示,它分四个过程,建立连接、发送请求信息、发送响应信息、关闭连接;
浏览器与WEB服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对每一个页面的访问,浏览器与WEB服务器都要建立一次单独的连接;
浏览器到WEB服务器之间的所有通讯都是完全独立分开的请求和响应。
HTTP1.1运行方式,如图9-6所示:

图9-6 HTTP1.1 客户端、服务器传输模式
在一个TCP连接上可以传送多个HTTP请求和响应;
多个请求和响应过程可以重叠;
增加了更多的请求头和响应头,比如Host、If-Unmodified-Since请求头等。
9.6 HTTP状态码详解
HTTP状态码(HTTP Status Code)是用来表示WEB服务器HTTP Response状态的3位数字代码,常见的状态码范围分类:
100-199 用于指定客户端应相应的某些动作;
200-299 用于表示请求成功;
300-399 已移动的文件且被包含在定位头信息中指定新的地址信息;
400-499 用于指出客户端的错误;
500-599 用于支持服务器错误。
HTTP协议Response常用状态码详解表9-3所示:
HTTP状态码 状态码英文含义 状态码中文含义
100 Continue HTTP/1.1新增状态码,表示继续,客户端继续请求HTTP服务器;
101 Switching Protocols 服务器根据客户端的请求切换协议,切换到HTTP的新版本协议;
200 OK HTTP请求完成,常用于GET、POST请求中;
301 Moved Permanently 永久移动,请求的资源已被永久的移动到新URI;
302 Found 临时移动,资源临时被移动,客户端应继续使用原有URI;
304 Not Modified 文件未修改,请求的资源未修改,服务器返回此状态码时,常用于缓存;
400 Bad Request 客户端请求的语法错误,服务器无法解析或者访问;
401 Unauthorized 请求要求用户的身份认证;
402 Payment Required 此状态码保留,为以后使用;
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求;
404 Not Found 服务器没有该资源,请求的文件找不到;
405 Method Not Allowed 客户端请求中的方法被禁止;
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求;
499 Client has closed connection 服务器端处理的时间过长;
500 Internal Server Error 服务器内部错误,无法完成请求;
502 Bad Gateway 服务器返回错误代码或者代理服务器错误的网关;
503 Service Unavailable 服务器无法响应客户端请求,或者后端服务器异常;
504 Gateway Time-out 网关超时或者代理服务器超时;
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理。
表9-3 HTTP常用状态码
9.7 HTTP MIME 类型支持
浏览器接收到WEB服务器的Response信息,浏览器会进行解析,在解析页面之前,浏览器必须启动本地相应的应用程序来处理获取到的文件类型。
基于多用途互联网邮件扩展类型 (Multipurpose Internet Mail Extensions,MIME),可以明确某种文件在客户端用某种应用程序来打开,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开,设计之初是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它使得HTTP传输的不仅是普通的文本,可以支持更多文件类型、多媒体音、视频等。
在HTTP协议中,HTTP Response消息,MIME类型被定义在Content-Type header中,例如:Content-Type: text/html,表示默认指定该文件为html类型,在浏览器端会以HTML格式来处理。
在最早的HTTP协议中,并没有附加的数据类型信息,所有传送的数据都被客户程序解释为超文本标记语言HTML文档,为了支持多媒体数据类型,新版HTTP协议中就使用了附加在文档之前的MIME数据类型信息来标识数据类型,如表9-4所示:
Mime-Types(MIME类型) Dateiendung (扩展名) Bedeutung
application/msexcel .xls .xla Microsoft Excel Dateien
application/mshelp .hlp .chm Microsoft Windows Hilfe Dateien
application/mspowerpoint .ppt .ppz .pps .pot Microsoft Powerpoint Dateien
application/msword .doc .dot Microsoft Word Dateien
application/octet-stream .exe exe
application/pdf
.pdf Adobe PDF-Dateien
application/post** .ai .eps *.ps Adobe Post**-Dateien
application/rtf .rtf Microsoft RTF-Dateien
application/x-httpd-php
.php *.phtml PHP-Dateien
application/x-java** *.js serverseitige Java**-Dateien
application/x-shockwave-flash .swf .cab Flash Shockwave-Dateien
application/zip .zip ZIP-Archivdateien
audio/basic
.au .snd Sound-Dateien
audio/mpeg
.mp3 MPEG-Dateien
audio/x-midi .mid .midi MIDI-Dateien
audio/x-mpeg .mp2 MPEG-Dateien
audio/x-wav
.wav Wav-Dateien
image/gif .gif GIF-Dateien
image/jpeg
.jpeg .jpg .jpe JPEG-Dateien
image/x-windowdump .xwd X-Windows Dump
text/css
.css CSS Stylesheet-Dateien
text/html .htm .html *.shtml -Dateien
text/java** *.js Java**-Dateien
text/plain .txt reine Textdateien
video/mpeg
.mpeg .mpg .mpe MPEG-Dateien
video/vnd.rn-realvideo .rmvb realplay-Dateien
video/quicktime
.qt .mov Quicktime-Dateien
video/vnd.vivo
viv *.vivo Vivo-Dateien
表9-4 HTTP MIME类型详解
第10章 Apache WEB服务器企业实战
万维网 (WORLD WIDE WEB,WWW)服务器,也称之为WEB服务器,主要功能是提供网上信息浏览服务。WWW是 Internet的多媒体信息查询工具,是Internet上飞快发展的服务,也是目前用的最广泛的服务。正是因为有了WWW软件,才使得近年来 Internet 迅速发展。
目前主流的WEB服务器软件包括:Apache、Nginx、Lighttpd、IIS、Resin、Tomcat、WebLogic、Jetty等。
本章向读者介绍Apache WEB服务器发展历史、Apache工作模式深入剖析、Apache虚拟主机、配置文件详解及Apache Rewrite企业实战等。
10.1 Apache WEB服务器入门简介
Apache HTTP Server是Apache软件基金会的一个开源的网页服务器,是世界使用排名第一的Web服务器软件,可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是目前最流行的Web服务器端软件之一。
Apache服务器是一个多模块化的服务器,经过多次修改,成为目前世界使用排名第一的Web服务器软件。Apache取自“A Patchy Server”的读音,即充满补丁的服务器,因为Apache基于GPL发布,大量开发者不断为Apache贡献新的代码、功能、新的特性、修改原来的缺陷。
Apache服务器的特点是使用简单、速度快、性能稳定,可以做负载均衡及代理服务器来使用。
10.2 Prefork MPM工作原理
每辆汽车都有发动机引擎,不同的引擎,对车子运行效率也不一样,同样Apache也有类似工作引擎或者处理请求的模块,亦可称之为多路处理模块(Multi-Processing Modules,MPM),Apache WEB服务器有三种处理模块:Prefork MPM、Worker MPM、Event MPM。
在企业中最常用的处理模块为Prefork MPM和Worker MPM,Event MPM不支持HTTPS方式,官网也给出“This MPM is experimental, so it may or may not work as expected”提示,所以很少被使用。
默认Apache处理模块为Prefork MPM方式,Prefork采用的预派生子进程方式,Prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,所以比较稳定。
      Prefork的工作原理:控制进程Master在最初建立“StartServers”个进程后,为了满足MinSpareServers设置的最小空闲进程,所以需创建第一个空闲进程,等待一秒钟,继续创建两个,再等待一秒钟,继续创建四个,依次按照递增指数级创建进程数,最多每秒同时创建32个空闲进程,直到满足至少有MinSpareServers设置的值为止。
Apache的预派生模式(Prefork),基于预派生模式不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能,不过由于Prefork MPM引擎是基于多进程方式提供对外服务,每个进程占内存也相对较高。
10.3 Worker MPM工作原理
      相对于Prefork MPM,Worker方式是2.0版中全新的支持多线程和多进程混合模型的MPM,由于使用线程来处理,所以可以处理海量的HTTP请求,而系统资源的开销要小于基于Prefork多进程的方式。Worker也是基于多进程,但每个进程又生成多个线程,这样可以保证多线程可以获得进程的稳定性。
      Worker MPM工作原理:控制进程Master在最初建立“StartServers”个进程,每个进程会创建ThreadsPerChild设置的线程数,多个线程共享该进程内存空间,同时每个线程独立地处理用户的HTTP请求。为了不在请求到来时再生成线程,Worker MPM也可以设置最大最小空闲线程。
Worker MPM模式下同时处理的请求总数=进程总数xThreadsPerChild,也即等于MaxClients。如果服务器负载很高,当前进程数不满足需求,Master控制进程会fork新的进程,最大进程数不能超过ServerLimit数,如果需调整的StartServers进程数,需同时调整ServerLimit值。
Prefork MPM与Worker MPM引擎区别小结如下:
Prefork MPM模式:使用多个进程,每个进程只有一个线程,每个进程在某个确定的时间只能维持一个连接,稳定,内存开销较高;
Worker MPM模式:使用多个进程,每个子进程包含多个线程,每个线程在某个确定的时间只能维持一个连接,内存占用量比较小,适合大并发、高流量的WEB服务器。Worker MPM缺点是一个线程崩溃,整个进程就会连同其任何线程一起挂掉。
10.4 Apache WEB服务器安装
从Apache官方分站点下载目前稳定版本httpd-2.2.32版本,目前最新版本为2.4版本,下载地址如下:
http://mirrors.hust.edu.cn/apache/httpd/httpd-2.2.32.tar.bz2
Apache WEB服务器安装步骤如下:
tar -xjvf httpd-2.2.32.tar.bz2 tar工具解压httpd包;
cd httpd-2.2.32/ 进入解压后目录;
yum install apr apr-devel apr-util apr-util-devel -y 安装APR相关优化模块;
./configure --prefix=/usr/local/apache2/ --enable-rewrite --enable-so 预编译Apache,启用rewrite规则、启用动态加载库;
make 编译
make install 安装
Apache2.2.32安装完毕,如图10-1所示:

图10-1 Apache2.2.32安装图解
启动Apache服务,临时关闭selinux、firewalld防火墙:
/usr/local/apache2/bin/apachectl start
setenforce 0
systemctl stop firewalld.service
查看Apache服务进程,通过客户端浏览器访问http://192.168.111.131/,如图10-2(a)、10-2(b)所示:
图10-2(a) Apache启动及查看进程

图10-2(b) 浏览器访问Apache WEB服务器
10.5 Apache虚拟主机企业应用
企业真实环境中,一台WEB服务器发布单个网站会非常浪费资源,所以一台WEB服务器上会发布多个网站,少则3-5个,多则2-30个网站。
在一台服务器上发布多网站,也称之为部署多个虚拟主机,WEB虚拟主机配置方法有三种:
基于单IP多个Socket端口;
基于多IP地址一个端口;
基于单IP一个端口不同域名。
其中基于同一端口不同域名的方式在企业中得到广泛的使用和应用,如下为基于一个端口不同域名,在一台Apache WEB服务器上部署多个网站,步骤如下:
(1)创建虚拟主机配置文件httpd-vhosts.conf,该文件默认已存在,只需去掉httpd.conf配置文件中#号即可,如图10-3所示:
图10-3 httpd.conf配置文件开启虚拟主机
(2)配置文件/usr/local/apache2/conf/extra/httpd-vhosts.conf中代码设置为如下:
NameVirtualHost :80
<VirtualHost
:80>
ServerAdmin support@jfedu.net
DocumentRoot "/usr/local/apache2/htdocs/jf1"
ServerName www.jf1.com
ErrorLog "logs/www.jf1.com_error_log"
CustomLog "logs/www.jf1.com_access_log" common

ServerAdmin support@jfedu.net DocumentRoot "/usr/local/apache2/htdocs/jf2" ServerName www.jf2.com ErrorLog "logs/www.jf2.com_error_log" CustomLog "logs/www.jf2.com_access_log" common Httpd-vhosts.conf参数详解: NameVirtualHost *:80 开启虚拟主机,并且监听本地所有网卡接口的80端口; 虚拟主机配置起始; ServerAdmin support@jfedu.net 管理员邮箱; DocumentRoot "/usr/local/apache2/htdocs/jf1" 该虚拟主机发布目录; ServerName www.jf1.com 虚拟主机完整域名; ErrorLog "logs/www.jf1.com_error_log" 错误日志路径及文件名; CustomLog "logs/www.jf1.com_access_log" common 访问日志路径及文件名; 虚拟主机配置结束。 (3)创建www.jf1.com及www.jf2.com发布目录,重启apache服务,并分别创建index.html页面: mkdir -p /usr/local/apache2/htdocs/{jf1,jf2}/ /usr/local/apache2/bin/apachectl restart echo "

www.jf1.com Pages

" >/usr/local/apache2/htdocs/jf1/index.html echo "

www.jf2.com Pages

" >/usr/local/apache2/htdocs/jf2/index.html (4)Windows客户端设置Hosts映射,将www.jf1.com、www.jf2.com与192.168.111.131 IP进行映射绑定,映射的目的将域名跟IP进行绑定,在浏览器可以输入域名,不需要输入IP地址,绑定方法是在“C:\Windows\System32\drivers\etc”文件夹中,使用记事本编辑hosts文件,加入如下代码,如图10-4所示: 192.168.111.131 www.jf1.com 192.168.111.131 www.jf2.com 图10-4 Windows主机Hosts配置 (5)浏览器访问www.jf1.com、www.jf2.com如图10-5(a)、10-5(b)所示,至此Apache基于多域名虚拟主机配置完毕,如果还需添加虚拟主机,直接拷贝其中一个虚拟主机配置、修改WEB发布目录即可: 图10-5(a) www.jf1.com网站返回内容 图10-5(b) www.jf2.com网站返回内容 10.6 Apache常用目录学习 Apache可以基于源码安装、YUM安装,不同的安装方法,所属的路径特不同,如下为Apache常用路径的功能用途: /usr/lib64/httpd/modules/ Apache模块存放路径; /var/www/html/ YUM安装Apache网站发布目录; /var/www/error/ 服务器设置错误信息,浏览器显示; var/www/icons/ Apache小图标文件存放目录; var/www/cgi-bin/ 可执行的CGI程序存放目录。 /var/log/httpd/ Apache日志目录; /usr/sbin/apachectl Apache启动脚本; /usr/sbin/httpd Apache二进制执行文件; /usr/bin/htpasswd 设置Apache目录密码访问; /usr/local/apache2/bin Apache命令目录; /usr/local/apache2/build Apache构建编译目录; /usr/local/apache2/htdocs/ 源码安装Apache网站发布目录; /usr/local/apache2/cgi-bin 可执行的CGI程序存放目录; /usr/local/apache2/include Apache引用配置文件目录; /usr/local/apache2/logs Apache日志目录; /usr/local/apache2/man Apache帮助文档目录; /usr/local/apache2/manual Apache手册; /usr/local/apache2/modules Apache模块路径。 10.7 Apache配置文件详解 Apache的配置文件是Apache WEB难点,读者需要掌握配置文件中每个参数的含义,才能理解并在日常运维中去解决Apache遇到的故障,如下为Apache配置文件详解: ServerTokens OS 显示服务器的版本和操作系统内核版本; ServerRoot "/usr/local/apache2/" Apache主配置目录; PidFile run/httpd.pid PidFile进程文件; Timeout 60 不论接收或发送,当持续连接等待超过60秒则该次连接就中断; KeepAlive Off 关闭持续性的连接; MaxKeepAliveRequests 100 当KeepAlive设置为On的时候,该数值可以决定此次连接能够传输的最大传输数量; KeepAliveTimeout 65 当KeepAlive设置为On的时候,该连接在最后一次传输后等待延迟的秒数; Prefork MPM引擎配置段; StartServers 8 默认启动Apache工作进程数; MinSpareServers 5 最小空闲进程数; MaxSpareServers 20 最大空闲进程数; ServerLimit 4096 Apache服务器最多进程数; MaxClients 4096 每秒支持的最大客户端并发; MaxRequestsPerChild 4000 每个进程能处理的最大请求数; Worker MPM引擎配置段; StartServers 8 默认启动Apache工作进程数; MaxClients 4000 每秒支持的最大客户端并发; MinSpareThreads 25 最小空闲线程数; MaxSpareThreads 75 最小空闲线程数; ThreadsPerChild 75 每个进程启动的线程数; MaxRequestsPerChild 0 每个进程能处理的最大请求数,0表示无限制; LoadModule mod_version.so 静态加载apache相关模块; ServerAdmin support@jfedu.net 管理员邮箱,网站异常,错误信息会发生至该邮箱; DocumentRoot "/usr/local/apache2/htdocs/" Apache网站默认发布目录; 设置/data/webapps/www1目录权限; AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all AllowOverride 设置为None时,目录中.htaccess 文件将被完全忽略,当指令设置为All时,.htaccess文件生效; Options -Indexes FollowSymLinks 禁止浏览目录,去掉”-“,表示浏览目录,常用于下载站点; Order allow,deny 默认情况下禁止所有客户机访问; Order deny,allow 默认情况下允许所有客户机访问; Allow from all 允许所有客户机访问。 10.8 Apache Rewrite规则实战 Rewirte规则也称为规则重写,主要功能是实现浏览器访问HTTP URL的跳转,其正则表达式是基于Perl语言。通常而言,几乎所有的WEB服务器均可以支持URL重写。Rewrite URL规则重写的用途: 对搜索引擎优化(Search Engine Optimization,SEO)友好,利于搜索引擎抓取网站页面; 隐藏网站URL真实地址,浏览器显示更加美观; 网站变更升级,可以基于Rewrite临时重定向到其他页面。 Apache WEB服务器如需要使用Rewrite功能,须添加Rewrite模块,基于源码安装是指定参数“--enable-rewrite”,还有一种方法可以动态添加模块,以DSO模式安装Apache,利用模块源码和Apache apxs工具完成Rewrite模块的添加。 使用Apache Rewrite,除了安装Rewrite模块之外,还需在httpd.conf中的全局配置段或者虚拟主机配置段设置如下指令来开启Rewrite功能: RewriteEngine on Apache Rewrite规则使用中有三个概念需要理解,分别是:Rewrite结尾标识符、Rewrite规则常用表达式、Apache Rewrite变量,如下为三个概念的详解: (1)Apache Rewrite结尾标识符,用于Rewrite规则末尾,表示规则的执行属性。 R[=code](force redirect) 强制外部重定向; G(force URL to be gone) 强制URL为GONE,返回410HTTP状态码; P(force proxy) 强制使用代理转发; L(last rule) 匹配当前规则为最后一条匹配规则,停止匹配后续规则; N(next round) 重新从第一条规则开始匹配; C(chained with next rule) 与下一条规则关联; T=MIME-type(force MIME type) 强制MIME类型; NC(no case) 不区分大小写。 (2)Apache Rewrite规则常用表达式,主要用于匹配参数、字符串及过滤设置。 . 匹配任何单字符; [word] 匹配字符串:word; [^word] 不匹配字符串:word; jfedu|jfteach 可选择的字符串:jfedu|jfteach; ? 匹配0到1个字符; * 匹配0到多个字符; + 匹配1到多个字符; ^ 字符串开始标志; $ 字符串结束标志; \n 转义符标志。 (3)Apache Rewrite变量,常用于匹配HTTP请求头信息、浏览器主机名、URL等。 HTTP headers:HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_HOST, HTTP_ACCEPT; connection & request: REMOTE_ADDR, QUERY_STRING; server internals: DOCUMENT_ROOT, SERVER_PORT, SERVER_PROTOCOL; system stuff: TIME_YEAR, TIME_MON, TIME_DAY。 详解如下: HTTP_USER_AGENT 用户使用的代理,例如浏览器; HTTP_REFERER 告知服务器,从哪个页面来访问的; HTTP_COOKIE 客户端缓存,主要用于存储用户名和密码等信息; HTTP_HOST 匹配服务器ServerName域名; HTTP_ACCEPT 客户端的浏览器支持的MIME类型; REMOTE_ADDR 客户端的IP地址 QUERY_STRING URL中访问的字符串; DOCUMENT_ROOT 服务器发布目录; SERVER_PORT 服务器端口; SERVER_PROTOCOL 服务器端协议; TIME_YEAR 年; TIME_MON 月; TIME_DAY 日; (4)Rewrite规则实战案例,以下配置均配置在httpd.conf或者vhosts.conf中,企业中常用的Rewrite案例如下: 1.将jfedu.net跳转至www.jfedu.net。 RewriteEngine on 启用rewrite引擎; RewriteCond %{HTTP_HOST} ^jfedu.net [NC] 匹配以jfedu.net开头的域名,NC忽略大小写; RewriteRule ^/(.*)$ http://www.jfedu.net/$1 [L] (.*)表示任意字符串,$1表示引用(.*)的中任意内容。 2.将www.jf1.com www.jf2.com jfedu.net跳转至www.jfedu.net,OR含义表示或者。 RewriteEngine on RewriteCond %{HTTP_HOST} www.jf1.com [NC,OR] RewriteCond %{HTTP_HOST} www.jf2.com [NC,OR] RewriteCond %{HTTP_HOST} ^jfedu.net [NC] RewriteRule ^/(.*)$ http://www.jfedu.net/$1 [L] 3.访问www.jfedu.net首页,跳转至www.jfedu.net/newindex/,R=301表示永久重定向。 RewriteEngine on RewriteRule ^/$ http://www.jfedu.net/newindex/ [L,R=301] 4.访问/newindex/plus/view.php?aid=71跳转至http://www.jfedu.net/linux/。 RewriteEngine on RewriteCond %{QUERY_STRING} ^tid=(.+)$ [NC] RewriteRule ^/forum\.php$ /jfedu/thread-new-%1.html? [R=301,L] 5.访问www.jfedu.net首页,内容访问www.jfedu.net/newindex/,但是浏览器URL地址不改变。 RewriteEngine on RewriteCond %{HTTP_HOST} ^www.jfedu.net [NC] RewriteRule ^/$ /newindex/ [L] 6.访问/forum.php?tid=107258跳转至/jfedu/thread-new-107258.html。 RewriteEngine on RewriteCond %{QUERY_STRING} ^tid=(.+)$ [NC] RewriteRule ^/forum\.php$ /jfedu/thread-new-%1.html? [R=301,L] 7.访问/xxx/123456跳转至/xxx?id=123456。 RewriteEngine on rewriteRule ^/(.+)/(\d+)$ /$1?id=$2 [L,R=301] 8.判断是否使用移动端访问网站,移动端访问跳转至m.jfedu.net。 RewriteEngine on RewriteCond %{HTTP_USER_AGENT} ^iPhone [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^Android [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^WAP [NC] rewriteRule ^/$ http://m.jfedu.net/index.html [L,R=301] rewriteRule ^/(.*)/$ http://m.jfedu.net/$1 [L,R=301] 9.访问/10690/jfedu/123跳转至/index.php?tid/10690/items=123,[0-9]表示任意一个数字,+表示多个,(.+)表示任何多个字符。 RewriteEngine on RewriteRule ^/([0-9]+)/jfedu/(.+)$ /index.php?tid/$1/items=$2 [L,R=301] 第11章 MYSQL服务器企业实战 MySQL是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 旗下公司。MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。 本章向读者介绍关系型数据库特点、MySQL数据库引擎特点、数据库安装配置、SQL案例操作、数据库索引、慢查询、MySQL数据库集群实战等。 11.1 MYSQL数据库入门简介 MySQL 是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL 所使用的 SQL 语言是用于访问数据库的最常用标准化语言。 MySQL数据库主要用于存储各类信息数据,例如:员工姓名、身份证ID、商城订单及金额、销售业绩及报告,学生考试成绩、网站帖子、论坛用户信息、系统报表等等。 MySQL 软件采用了双授权政策,它分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。由于其社区版的性能卓越,搭配 PHP 和 Apache 可组成良好的开发环境。 关系数据库管理系统(Relational Database Management System,RDBMS),是将数据组织为相关的行和列的系统,而管理关系数据库的计算机软件就是关系数据库管理系统,常用的关系型数据库软件有MYSQL、Mariadb、Oracle、SQL Server、PostgreSQL、DB2等。) RDBMS数据库的特点如下: 数据以表格的形式出现; 每行记录数据的真实内容; 每列记录数据真实内容的数据域; 无数的行和列组成一张表; 若干的表组成一个数据库; 目前主流架构LAMP(Linux+Apache+MySQL+PHP),MySQL更是得到各位IT运维、DBA的青睐,虽然MySQL数据库已被Orcacle公司收购,不过好消息是原来MySQL创始人已独立出来自己重新开发了MariaDB数据库,开源免费,目前越来越多的人开始尝试使用。MariaDB数据库兼容MySQL数据库所有的功能和相关参数。 MySQL数据库运行在服务器前,需要选择启动的引擎,好比一辆轿车,性能好的发动机会提升轿车的性能,从而启动、运行更加的高效。同样MYSQL也有类似发动机引擎,这里称之为MYSQL引擎。 MYSQL引擎包括:ISAM、MyISAM、InnoDB 、MEMORY、CSV、BLACKHOLE、ARCHIVE、PERFORMANCE_SCHEMA、Berkeley、Merge、Federated、Cluster/NDB等,其中MyISAM、InnoDB使用最为广泛,如下为Myisam BDB Memory InnoDB Archive引擎功能的对比: 引擎特性 Myisam BDB Memory InnoDB Archive 批量插入的速度 高 高 高 中 非常高 集群索引 不支持 不支持 不支持 支持 不支持 数据缓存 不支持 不支持 支持 支持 不支持 索引缓存 支持 不支持 支持 支持 不支持 数据可压缩 支持 不支持 不支持 不支持 支持 硬盘空间使用 低 低 NULL 高 非常低 内存使用 低 低 中等 高 低 外键支持 不支持 不支持 不支持 支持 不支持 存储限制 没有 没有 有 64TB 没有 事务安全 不支持 支持 不支持 支持 不支持 锁机制 表锁 页锁 表锁 行锁 行锁 B树索引 支持 支持 支持 支持 不支持 哈希索引 不支持 不支持 支持 支持 不支持 全文索引 支持 不支持 不支持 不支持 不支持 性能总结:MyISAM MySQL 5.0 之前的默认数据库引擎,最为常用。拥有较高的插入,查询速度,但不支持事务; InnoDB事务型数据库的首选引擎,支持ACID事务,ACID包括:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),一个支持事务(Transaction)的数据库,必需要具有这四种特性,否则在执行事务过程无法保证数据的正确性。 MYSQL5.5之后默认引擎为InnoDB,Innodb支持行级锁定, 支持事物、外键等功能。 BDB源自 Berkeley DB,事务型数据库的另一种选择,支持Commit 和Rollback 等其他事务特性; Memory所有数据置于内存的存储引擎,拥有极高的插入,更新和查询效率。但是会占用和数据量成正比的内存空间。并且其内容会在 MySQL 重新启动时丢失; Mysql常用的两大引擎有MyISAM和innoDB,那他们有什么明显的区别呢,什么场合使用什么引擎呢? MyISAM类型的数据库表强调的是性能,其执行数度比InnoDB类型更快,但不提供事务支持,不支持外键,如果执行大量的SELECT(查询)操作,MyISAM是更好的选择,支持表锁。 InnoDB提供事务支持事务、外部键、行级锁等高级数据库功能,执行大量的INSERT或UPDATE,出于性能方面的考虑,可以考虑使用InnoDB引擎。 11.2 Mysql数据库安装方式 MySQL数据库安装方法有两种,一种是yum/rpm通过YUM源在线安装,另外一种是通过源码软件编译安装。 (1)YUM方式安装MYSQL方法,执行命令: yum install mysql-server mysql-devel mysql-libs -y CentOS6.x YUM安装 yum install mariadb-server mariadb mariadb-libs -y CentOS7.x YUM安装 (2)源码安装MYSQL5.5.20方法,通过cmake、make、make install三个步骤实现。 wget http://down1.chinaunix.net/distfiles/mysql-5.5.20.tar.gz yum install cmake ncurses-devel ncurses -y cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql55/ \ -DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ -DMYSQL_DATADIR=/data/mysql \ -DSYSCONFDIR=/etc \ -DMYSQL_USER=mysql \ -DMYSQL_TCP_PORT=3306 \ -DWITH_XTRADB_STORAGE_ENGINE=1 \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_PARTITION_STORAGE_ENGINE=1 \ -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \ -DWITH_MYISAM_STORAGE_ENGINE=1 \ -DWITH_READLINE=1 \ -DENABLED_LOCAL_INFILE=1 \ -DWITH_EXTRA_CHARSETS=1 \ -DDEFAULT_CHARSET=utf8 \ -DDEFAULT_COLLATION=utf8_general_ci \ -DEXTRA_CHARSETS=all \ -DWITH_BIG_TABLES=1 \ -DWITH_DEBUG=0 make make install (3)MYSQL源码安装参数详解 cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql55 Cmake预编译;-DMYSQL_UNIX_ADDR=/tmp/mysql.sock MYSQL Socket通信文件位置; -DMYSQL_DATADIR=/data/mysql MYSQL数据存放路径; -DSYSCONFDIR=/etc 配置文件路径; -DMYSQL_USER=mysql MYSQL运行用户; -DMYSQL_TCP_PORT=3306 MYSQL监听端口; -DWITH_XTRADB_STORAGE_ENGINE=1 开启xtradb引擎支持; -DWITH_INNOBASE_STORAGE_ENGINE=1 开启innodb引擎支持; -DWITH_PARTITION_STORAGE_ENGINE=1 开启partition引擎支持; -DWITH_BLACKHOLE_STORAGE_ENGINE=1 开启blackhole引擎支持; -DWITH_MYISAM_STORAGE_ENGINE=1 开启MyISAM引擎支持; -DWITH_READLINE=1 启用快捷键功能; -DENABLED_LOCAL_INFILE=1 允许从本地导入数据; -DWITH_EXTRA_CHARSETS=1 支持额外的字符集; -DDEFAULT_CHARSET=utf8 默认字符集UTF-8; -DDEFAULT_COLLATION=utf8_general_ci 检验字符; -DEXTRA_CHARSETS=all 安装所有扩展字符集; -DWITH_BIG_TABLES=1 将临时表存储在磁盘上; -DWITH_DEBUG=0 禁止调试模式支持; make 编译; make install 安装。 (4)将源码安装的Mysql数据库服务设置为系统服务,可以使用chkconfig管理,并启动MYSQL数据库,如图11-1所示: cd /usr/local/mysql55/ \cp support-files/my-large.cnf /etc/my.cnf \cp support-files/mysql.server /etc/init.d/mysqld chkconfig --add mysqld  chkconfig --level 35 mysqld on mkdir –p /data/mysql useradd mysql /usr/local/mysql55/scripts/mysql_install_db --user=mysql --datadir=/data/mysql/ --basedir=/usr/local/mysql55/ ln -s /usr/local/mysql55/bin/* /usr/bin/ service mysqld restart

图11-1 查看MYSQL启动进程
(5)不设置为系统服务,也可以用源码启动方式。
cd /usr/local/mysql55
mkdir –p /data/mysql
useradd mysql
/usr/local/mysql55/scripts/mysql_install_db --user=mysql --datadir=/data/mysql/ --basedir=/usr/local/mysql55/
ln -s /usr/local/mysql55/bin/ /usr/bin/
/usr/local/mysql55/bin/mysqld_safe --user=mysql &
11.3 Mysql数据库必备命令操作
MySQL数据库安装完毕之后,对MYSQL数据库中各种指令的操作变得尤为重要,熟练掌握MYSQL必备命令是SA、DBA必备工作之一,如下为MYSQL数据库中操作必备命令,所有操作指令均在MYSQL命令行中操作,不能在Linux Shell解释器上直接运行:
直接在Shell终端执行命令:mysql或者/usr/local/mysql55/bin/mysql,按Enter键,进入MYSQL命令行界面如图11-2所示:
图11-2 MYSQL命令行界面
MYSQL命令行常用命令如下,操作结果如图11-3(a)、11-3(b)、11-3(c)所示:
show databases; 查看所有的数据库;
create database jfedu; 创建名为jfedu数据库;
use jfedu; 进入jfedu数据库;
show tables; 查看数据库里有多少张表;
create table t1 (id varchar(20),name varchar(20)); 创建名为t1表,并创建两个字段,id、name,varchar表示设置数据长度,用字符来定义长度单位,其中1汉字=2字符=2Bytes;
insert into t1 values ("1","jfedu"); 向表中插入数据;
select
from t1; 查看t1表数据内容;
Select * from t1 where id=1 and age =’jfedu’; id、age多个条件查询;
desc t1; 查看t1表字段内容;
alter table t1 modify column name varchar(20); 修改name字段的长度;
update t1 set name='jfedu.net' where id=1; 修改name字段的内容;
flush privileges; 刷新权限;
delete from t1 ; 清空表内容;
drop table t1 ; 删除表;
drop database jfedu; 删除jfedu数据库;
show variables like '%char%'; 查看数据库字符集;
show engines; 查看MySQL存储引擎;
show variables like '%storage_engine%'; 查看MySQL默认的存储引擎;
alter table t1 engine=innodb;   修改MySQL t1表存储引擎;

图11-3(a) MYSQL命令操作
图11-3(b) MYSQL命令操作
图11-3(c) MYSQL命令操作
11.4 Mysql数据库字符集设置
计算机中储存的信息都是用二进制数方式来表示的,读者每天看到屏幕显示的英文、汉字等字符是二进制数转换之后的结果。通俗的说,将汉字按照某种字符集编码存储在计算机中,称为"编码"。将存储在计算机中的二进制数解析显示出来,称为"解码",在解码过程中,如果使用了错误的解码规则,会导致显示乱码。
MYSQL数据库在存储数据时,默认编码latin1,存储中文字符时,在显示或者WEB调用时会显示为乱码,为解决该乱码问题,需修改Mysql默认字符集为UTF-8,有两种方法:
(1)编辑vim /etc/my.cnf配置文件,在相应段中加入相应的参数字符集修改完毕,重启MySQL服务即可。
[client]字段里加入: default-character-set=utf8
[mysqld]字段里加入: character-set-server=utf8
[mysql]字段里加入 : default-character-set=utf8
(2)MYSQL命令行中运行如下指令,如图11-4所示:
show variables like '%char%';
SET character_set_client = utf8;
SET character_set_results = utf8;
SET character_set_connection = utf8;
图11-4 设置MYSQL数据库字符集
11.5 Mysql数据库密码管理
MYSQL数据库在使用过程中为了加强安全防范,需要设置密码访问,如何设置密码、及密码忘记如何破解呢,如下为设置密码授权、密码修改及密码破解的方法:
(1)MYSQL创建用户及授权
grant all on jfedu. to test@localhost identified by 'pas';
grant select,insert,update,delete on
. to test@”%” identified by ‘pas’;
grant all on jfedu.
to test@’192.168.111.118’ identified by 'pas';
如上三条grant语句授权参数详解如下:
授权localhost主机通过test用户和pas密码访问本地的jfedu库的所有权限;
授权所有主机通过test用户和pas密码访问本地的jfedu库的查询、插入、更新、删除权限;
授权192.168.111.118主机通过test用户和pas密码访问本地的jfedu库的所有权限;
(2)MYSQL密码破解方法
在使用MYSQL数据库中,偶尔会出现密码忘记,或者被其他人员修改掉数据库权限的,如果需要紧急修改密码,如何破解MYSQL密码呢,首先停止MYSQL数据库服务,以跳过权限方式启动,命令如下:
/etc/init.d/mysqld stop
/usr/bin/mysqld_safe --user=mysql --skip-grant-tables &
MYSQL跳过权限方式启动后,在Shell终端执行mysql命令并按Enter键,进入mysql命令行,如图11-5所示:
图11-5 跳过权限启动并登陆MYSQL
由于MYSQL用户及密码认证信息存放在mysql库中的user表,需进入mysql库,更新相应的密码字段即可,例如将MYSQL中root用户的密码均改为123456,如图11-6所示:
use mysql
update user set password=password(‘123456’) where user=’root’;
图11-6 MYSQL密码破解方法
MYSQL root密码修改完,需停止以Mysql跳过权限表的启动进程,再以正常方式启动MYSQL,再次以新的密码登陆即可进入Mysql数据库,如图11-7所示:
图11-7 MYSQL正常方式启动
11.6 Mysql数据库配置文件详解
理解MYSQL配置文件,可以更快的学习和掌握MYSQL数据库服务器,如下为MYSQL配置文件常用参数详解:
[mysqld] //服务器端配置
datadir=/data/mysql //数据目录
socket=/var/lib/mysql/mysql.sock //socket通信设置
user=mysql //使用mysql用户启动;
symbolic-links=0 //是否支持快捷方式;
log-bin=mysql-bin //开启bin-log日志;
server-id = 1 //mysql服务的ID;
auto_increment_offset=1 //自增长字段从固定数开始;
auto_increment_increment=2 //自增长字段每次递增的量;
socket = /tmp/mysql.sock //为MySQL客户程序与服务器之间的本地通信套接字文件;
port = 3306 //指定MsSQL监听的端口;
key_buffer = 384M //key_buffer是用于索引块的缓冲区大小;
table_cache = 512 //为所有线程打开表的数量;
sort_buffer_size = 2M //每个需要进行排序的线程分配该大小的一个缓冲区;
read_buffer_size = 2M //读查询操作所能使用的缓冲区大小。
query_cache_size = 32M //指定MySQL查询结果缓冲区的大小
read_rnd_buffer_size = 8M //改参数在使用行指针排序之后,随机读;
myisam_sort_buffer_size = 64M //MyISAM表发生变化时重新排序所需的缓冲;
thread_concurrency = 8 //最大并发线程数,取值为服务器逻辑CPU数量×2;
thread_cache = 8 //缓存可重用的线程数;
skip-locking //避免MySQL的外部锁定,减少出错几率增强稳定性。
default-storage-engine=INNODB //设置mysql默认引擎为Innodb;

mysqld_safe config

[mysqld_safe] //mysql服务安全启动配置;
log-error=/var/log/mysqld.log //mysql错误日志路径;
pid-file=/var/run/mysqld/mysqld.pid //mysql PID进程文件;
key_buffer_size = 2048MB //MyISAM表索引缓冲区的大小;
max_connections = 3000 //mysql最大连接数;
innodb_buffer_pool_size = 2048MB //InnoDB内存缓冲数据和索引大小;
basedir = /usr/local/mysql55/ //数据库安装路径;
[mysqldump] //数据库导出段配置;
max_allowed_packet =16M //服务器和客户端发送的最大数据包;
11.7 MySQL数据库索引案例
MySQL索引可以用来快速地寻找某些具有特定值的记录,所有MySQL索引都以B-树的形式保存。例如MYSQL没有索引,执行select时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。如果表中数据有上亿条数据,查询一条数据花费的时间会非常长,索引的目的就类似电子书的目录及页码的对应关系。
如果在需搜索条件的列上创建了索引,MySQL无需扫描全表记录即可快速得到相应的记录行。如果该表有1000000条记录,通过索引查找记录至少要比全表顺序扫描快至少100倍,这就是索引在企业环境中带来的执行速度的提升。
MYSQL数据库常见索引类型包括:普通索引(normal)、唯一索引(unique)、全文索引(full text)、主键索引(primary key)、组合索引等,如下为每个索引的应用场景及区别:
普通索引: normal,使用最广泛;
唯一索引: unique,不允许重复的索引,允许有空值;
全文索引: full text,只能用于MyISAM表,FULLTEXT主要用于大量的内容检索;
主键索引: primary key又称为特殊的唯一索引,不允许有空值;
组合索引: 为提高mysql效率可建立组合索引;
MYSQL数据库表创建各个索引命令,以t1表为案例,操作如下:
主键索引 ALTER TABLE t1 ADD PRIMARY KEY ( column );
唯一索引 ALTER TABLE t1 ADD UNIQUE (column);
普通索引 ALTER TABLE t1 ADD INDEX index_name ( column' ); 全文索引 ALTER TABLE t1 ADD FULLTEXT (column); 组合索引 ALTER TABLE t1 ADD INDEX index_name (column1,column2,column3` );
如图11-8所示,为t1表的id字段创建主键索引,查看索引是否被创建,然后插入相同的id,提示报错:

图11-8 MYSQL主键索引案例演示
MYSQL数据库表删除各个索引命令,以t1表为案例,操作如下:
DROP INDEX index_name ON t1;
ALTER TABLE t1 DROP INDEX index_name;
ALTER TABLE t1 DROP PRIMARY KEY;
MYSQL数据库查看表索引:
show index from t1;
show keys from t1;
MYSQL数据库索引的缺点:
MYSQL数据库索引虽然能够提高数据库查询速度,但同时会降低更新、删除、插入表的速度,例如如对表进行INSERT、UPDATE、DELETE时,update表MySQL不仅要保存数据,还需保存更新索引;
建立索引会占用磁盘空间,大表上创建了多种组合索引,索引文件的会占用大量的空间。
11.8 MySQL数据库慢查询
MYSQL数据库慢查询主要用于跟踪异常的SQL语句,可以分析出当前程序里那些Sql语句比较耗费资源,慢查询日志则用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL语句,会被记录到慢查询日志中。
Mysql数据库默认没有开启慢查询日志功能,需手动在配置文件或者MYSQL命令行中开启,慢查询日志默认写入磁盘中的文件,也可以将慢查询日志写入到数据库表。
查看数据库是否开启慢查询,如图11-9(a)、11-9(b)所示,命令如下:
show variables like "%slow%";
show variables like "%long_query%";

图11-9(a) MYSQL数据库慢查询功能
图11-9(b) MYSQL数据库慢查询功能
MYSQL慢查询参数详解如下:
log_slow_queries 关闭慢查询日志功能;
long_query_time 慢查询超时时间,默认为10s,MYSQL5.5以上可以设置微秒;
slow_query_log 关闭慢查询日志;
slow_query_log_file 慢查询日志文件;
slow_launch_time Thread create时间,单位秒,如果thread create的时间超过了这个值,该变量slow_launch_time的值会加1;
log-queries-not-using-indexes 记录未添加索引的SQL语句。
开启MYSQL慢查询日志方法有两种:
(1)Mysql数据库命令行执行命令:
set global slow_query_log=on;
show variables like "%slow%";
(2)编辑my.cnf配置文件中添加如下代码:
log-slow-queries = /data/mysql/localhost.log
long_query_time = 0.01
log-queries-not-using-indexes
慢查询功能开启之后,数据库会自动将执行时间超过设定时间的SQL语句添加至慢查询日志文件中,可以通过慢查询日志文件定位执行慢的SQL,从而对其优化,可以通过mysqldumpslow命令行工具分析日志,相关参数如下:
执行命令mysqldumpslow -h可以查看命令帮助信息:
主要参数包括:-s和-t
-s 这个是排序参数,可选的有:
l: 查询锁的总时间;
r: 返回记录数;
t: 查询总时间排序;
al: 平均锁定时间;
ar: 平均返回记录数;
at: 平均查询时间;
c: 计数;
-t n 显示头n条记录。
MYSQL慢查询mysqldumpslow按照返回的行数从大到小,查看前2行,如图11-10所,命令如下:
mysqldumpslow -s r -t 2 localhost.log
图11-10 mysqldumpslow以返回记录排序
MYSQL慢查询mysqldumpslow按照查询总时间从大到小,查看前5行,同时过滤select的sql语句,如图11-11所,命令如下:
mysqldumpslow -s t -t 5 -g "select" localhost.log
图11-11 mysqldumpslow以查询总时间排序
11.9 MySQL数据库优化
Mysql数据库优化是一项非常重要的工作,而且是一项长期的工作,MYSQL优化三分靠配置文件及硬件资源的优化,七分靠sql语句的优化。
Mysql数据库具体优化包括:配置文件的优化、sql语句的优化、表结构的优化、索引的优化,而配置的优化包括:系统内核优化、硬件资源、内存、CPU、mysql本身配置文件的优化。
硬件上的优化:增加内存和提高磁盘读写速度,都可以提高MySQL数据库的查询,更新的速度。另一种提高MySQL性能的方式是使用多块磁盘来存储数据。因为可以从多块磁盘上并行读取数据,这样可以提高读取数据的速度。
MySQL参数的优化:内存中会为MySQL保留部分的缓冲区,这些缓冲区可以提高MySQL的速度,缓冲区的大小可以在MySQL的配置文件中进行设置。
附企业级MYSQL百万量级真实环境配置文件my.cnf内容,可以根据实际情况修改:
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
user = mysql
server_id = 10
port = 3306
socket = /tmp/mysql.sock
datadir = /data/mysql/
old_passwords = 1
lower_case_table_names = 1
character-set-server = utf8
default-storage-engine = MYISAM
log-bin = bin.log
log-error = error.log
pid-file = mysql.pid
long_query_time = 2
slow_query_log
slow_query_log_file = slow.log
binlog_cache_size = 4M
binlog_format = mixed
max_binlog_cache_size = 16M
max_binlog_size = 1G
expire_logs_days = 30
ft_min_word_len = 4
back_log = 512
max_allowed_packet = 64M
max_connections = 4096
max_connect_errors = 100
join_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 2M
sort_buffer_size = 2M
query_cache_size = 64M
table_open_cache = 10000
thread_cache_size = 256
max_heap_table_size = 64M
tmp_table_size = 64M
thread_stack = 192K
thread_concurrency = 24
local-infile = 0
skip-show-database
skip-name-resolve
skip-external-locking
connect_timeout = 600
interactive_timeout = 600
wait_timeout = 600

*** MyISAM

key_buffer_size = 512M
bulk_insert_buffer_size = 64M
myisam_sort_buffer_size = 64M
myisam_max_sort_file_size = 1G
myisam_repair_threads = 1
concurrent_insert = 2
myisam_recover

*** INNODB

innodb_buffer_pool_size = 64G
innodb_additional_mem_pool_size = 32M
innodb_data_file_path = ibdata1:1G;ibdata2:1G:autoextend
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_file_per_table = 1
innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 120
innodb_log_buffer_size = 8M
innodb_log_file_size = 256M
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 90
innodb_thread_concurrency = 16
innodb_open_files = 10000

innodb_force_recovery = 4

*** Replication Slave

read-only

skip-slave-start

relay-log = relay.log
log-slave-updates
11.10 MySQL数据库集群实战
随着访问量的不断增加,单台MySQL数据库服务器压力不断增加,需要对MYSQL进行优化和架构改造,MYQSL优化如果不能明显改善压力情况,可以使用高可用、主从复制、读写分离来、拆分库、拆分表来进行优化。
MYSQL主从复制集群在中小企业、大型企业中被广泛使用,MYSQL主从复制的目的是实现数据库冗余备份,将Master数据库数据定时同步至Slave库中,一旦Master数据库宕机,可以将WEB应用数据库配置快速切换至Slave数据库,确保WEB应用较高的可用率,如图11-12所示,为MYSQL主从复制结构图:

图11-12 MYSQL主从原理架构图
Mysql主从复制集群至少需要2台数据库服务器,其中一台为Master库,另外一台为Slave库,MYSQL主从数据同步是一个异步复制的过程,要实现复制首先需要在master上开启bin-log日志功能,bin-log日志用于记录在Master库中执行的增、删、修改、更新操作的sql语句,整个过程需要开启3个线程,分别是Master开启IO线程,Slave开启IO线程和SQL线程,具体主从同步原理详解如下:
Slave上执行slave start,Slave IO线程会通过在Master创建的授权用户连接上至Master,并请求master从指定的文件和位置之后发送bin-log日志内容;
Master接收到来自slave IO线程的请求后,master IO线程根据slave发送的指定bin-log日志position点之后的内容,然后返回给slave的IO线程。
返回的信息中除了bin-log日志内容外,还有master最新的binlog文件名以及在binlog中的下一个指定更新position点;
Slave IO线程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和position点记录到master.info文件中,以便在下一次读取的时候能告知master从响应的bin-log文件名及最后一个position点开始发起请求;
Slave Sql线程检测到relay-log中内容有更新,会立刻解析relay-log的内容成在Master真实执行时候的那些可执行的SQL语句,将解析的SQL语句并在Slave里执行,执行成功后,Master库与Slave库保持数据一致。
11.11 MySQL主从复制实战
MYSQL主从复制环境构建至少需2台服务器,可以配置1主多从,多主多从,如下为1主1从,MYSQL主从复制架构实战步骤:
(1)系统环境准备
Master:192.168.111.128
Slave: 192.168.111.129
(2)Master安装及配置
Master端使用源码安装MySQL-5-5版本软件后,在/etc/my.cnf 配置文件[mysqld]段中加入如下代码,然后重启MYSQL服务即可。如果在安装时cp my-large.cnf /etc/my.cnf,则无需添加如下代码:
server-id = 1
log-bin = mysql-bin
Master端/etc/my.cnf完整配置代码如下:
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
port = 3306
socket = /tmp/mysql.sock
skip-external-locking
key_buffer_size = 256M
max_allowed_packet = 1M
table_open_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size= 16M
thread_concurrency = 8
log-bin=mysql-bin
binlog_format=mixed
server-id = 1
[mysqldump]
quick
max_allowed_packet = 16M
[mysql]
no-auto-rehash
[myisamchk]
key_buffer_size = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M
[mysqlhotcopy]
interactive-timeout
Master数据库服务器命令行中 创建tongbu用户及密码并设置权限,执行如下命令,查看bin-log文件及position点,如图11-13所示:
grant replication slave on . to 'tongbu'@'%' identified by '123456';
show master status;

图11-13 MYSQL Master授权用户
(3)Slave安装及配置
Slave端使用源码安装MySQL-5-5版本软件后,在/etc/my.cnf 配置文件[mysqld]段中加入如下代码,然后重启MYSQL服务即可。如果在安装时cp my-large.cnf /etc/my.cnf,则需修改server-id,MASTER与Slave端server-id不能一样,Slave端也无需开启bin-log功能:
server-id = 2
Slave端/etc/my.cnf完整配置代码如下:
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
port = 3306
socket = /tmp/mysql.sock
skip-external-locking
key_buffer_size = 256M
max_allowed_packet = 1M
table_open_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size= 16M
thread_concurrency = 8
server-id = 2
[mysqldump]
quick
max_allowed_packet = 16M
[mysql]
no-auto-rehash
[myisamchk]
key_buffer_size = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M
[mysqlhotcopy]
interactive-timeout
Slave指定Master IP、用户名、密码、bin-log文件名(mysql-bin.000028)及position(257),代码如下:
change master to
master_host='192.168.111.128',master_user='tongbu',master_password='123456',master_log_file='mysql-bin.000028',master_log_pos=257;
在slave启动slave start,并执行show slave status\G查看Mysql主从状态:
slave start;
show slave status\G
查看Slave端IO线程、SQL线程状态均为YES,代表Slave已正常连接Master实现同步:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
执行Show slave status\G,常见参数含义解析:
Slave_IO_State I/O线程连接Master状态;
Master_User 用于连接Master的用户;
Master_Port Master端监听端口;
Connect_Retry 主从连接失败,重试时间间隔;
Master_Log_File I/O线程读取的Master二进制日志文件的名称。
Read_Master_Log_Pos I/O线程已读取的Master二进制日志文件的位置;
Relay_Log_File SQL线程读取和执行的中继日志文件的名称。
Relay_Log_Pos SQL线程已读取和执行的中继日志文件的位置;
Relay_Master_Log_File SQL线程执行的Master二进制日志文件的名称;
Slave_IO_Running I/O线程是否被启动并成功地连接到主服务器上;
Slave_SQL_Running SQL线程是否被启动;
Replicate_Do_DB 指定的同步的数据库列表;
Skip_Counter SQL_SLAVE_SKIP_COUNTER设置的值;
Seconds_Behind_Master Slave端SQL线程和I/O线程之间的时间差距,单位为秒,常被用于主从延迟检查方法之一。
在Master端创建mysql_db_test数据库和t0表,如图11-14所示,命令如下:
create database mysql_ab_test charset=utf8;
show databases;
use mysql_ab_test;
create table t0 (id varchar(20),name varchar(20));
show tables;
图11-14 MYSQL master创建数据库和表
Slave服务器查看是否有mysql_ab_test数据库和t0的表,如果存在则代表Slave从Master复制数据成功,证明MYSQL主从配置至此已经配置成功,如图11-15所示:
图11-15 MYSQL Slave自动同步数据
在Master服务器的t0表插入两条数据,在slave查看是否已同步,master上执行如下图11-16所示:
insert into t0 values (“001”,”wugk1”);
insert into t0 values (“002”,”wugk2”);
select * from t0;

图11-16 MYSQL Master insert数据
Slave端执行查询命令,如图11-17所示,表示在Master插入的数据已经同步到Slave端:
图11-17 MYSQL Slave数据已同步
11.12 MySQL主从同步排错思路
Mysql主从同步集群在生成环境使用过程中,如果主从服务器之间网络通信条件差或者数据库数据量非常大,容易导致MYSQL主从同步延迟。
MYSQL主从产生延迟之后,一旦主库宕机,会导致部分数据没有及时同步至丛库,重新启动主库,会导致丛库与主库同步错误,如何快速恢复主从同步关系呢,如下有两种方法:
(1)忽略错误后,继续同步:
此种方法适用于主从库数据内容相差不大,或者要求数据可以不完全统一的情况,数据要求不严格的情况。
Master端执行如下命令,将数据库设置全局读锁,不允许写入新数据:
flush tables with read lock;
Slave端停止Slave I/O及sql线程,同时将同步错误的SQL跳过1次,跳过会导致数据不一致,最后启动start slave,同步状态恢复,命令如下:
stop slave;
set global sql_slave_skip_counter =1;
start slave;
(2)重新做主从同步,完全同步:
此种方法适用于主从库数据内容相差很大,或者要求数据完全统一的情况,数据需完全保持一致。
Master端执行如下命令,将数据库设置全局读锁,不允许写入新数据:
flush tables with read lock;
Master端基于mysqldump、xtrabackup工具进行数据库将完整的数据库备份,也可以用shell脚本或python脚本实现定时备份,备份成功之后,将完整的数据导入至丛库,重新配置主从关系,当Slave端的IO线程、SQL线程均为YES之后,最后将Master端读锁解开即可,解锁命令如下:
unlock tables;
第12章 LAMP架构企业实战
Linux下LAMP(Linux+Apache+MySQL/MariaDB+Perl/PHP/Python)是一组用来搭建动态网站的开源软件架构,本身是各自独立的软件服务,放在一起使用,拥有了越来越高的兼容度,共同组成了一个强大的Web应用程序平台。
本章向读者介绍互联网主流企业架构LAMP应用案例、PHP解释性语言详解、LAMP组合通信原理、LAMP企业源码架设、LAMP拓展及使用Redis提升LAMP性能优化等。
12.1 LAMP企业架构简介
随着开源潮流的蓬勃发展,开放源代码的LAMP已经与J2EE和.Net商业软件形成三足鼎立之势,并且该软件开发的项目在软件方面的投资成本较低,因此受到整个IT界的关注。LAMP架构受到大多数中小企业的运维、DBA、程序员的青睐,Apache默认只能发布静态网页,而LAMP组合可以发布静态+PHP动态页面。
静态页面通常指不与数据库发生交互的页面,是一种基于w3c规范的一种网页书写格式,是一种统一协议语言,所以称之为静态网页。静态页面被设计好之后,一般很少去修改,不随着浏览器参数改变而内容改变,需注意的是动态的图片也是属于静态文件。从SEO角度来讲,HTML页面更有利于搜索引擎的爬行和收录。常见的静态页面以.html、.gif、.jpg、
.jpeg、.bmp、.png、.ico、.txt、.js、.css等结尾。
动态页面通常指与数据库发生交互的页面,内容展示丰富,功能非常强大,实用性广。从SEO角度来讲,搜索引擎很难全面的爬行和收录动态网页,因为动态网页会随着数据库的更新、参数的变更而发生改变,常见的动态页面以.jsp、.php、.do、.asp、.cgi、.apsx等结尾。
12.2 Apache与PHP工作原理
LAMP企业主流架构最重要的三个环节,一是Apache WEB服务器,二是PHP(PHP: Hypertext Preprocessor),三是MYSQL数据库。
Apache WEB服务器主要是基于多模块工作,依赖PHP SAPI处理方式中的PHP_MODULE去解析PHP结尾的文件,如图12-1所示:

图12-1 Apache+PHP mod工作原理
PHP是一种适用于web开发的动态语言,PHP语言内核基于C语言实现包含大量组件的软件框架,是一种功能强大的解释型脚本语言。PHP底层运行机制如图12-2所示:
图12-2 PHP底层处理机制
PHP底层工作原理包括4个部分:
Zend引擎,属于PHP内核部分,它负责将PHP代码解析为可执行opcode的处理并实现相应的处理方法、实现基本的数据结构、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕Zend实现。
Extensions,围绕着Zend引擎,Extensions通过组件的方式提供各种基础服务,各种内置函数、标准库等都是通过Extension来实现。
Sapi,服务端应用编程接口(Server Application Programming Interface,Sapi),sapi通过一系列钩子函数,基于SAPI可以让PHP与外部进行数据交互。
常见的SAPI编程接口处理方法包括:apache2handler:以apache作为webserver,采用MOD_PHP模式运行时候的处理方式;cgi:webserver和PHP直接的另一种交互方式,FastCGI协议;cli:命令行调用的应用模式。
APP代码应用,又称之为PHP代码程序,基于sapi接口生成不同的应用模式,从而被PHP引擎解析。
当用户在浏览器地址中输入域名或者域名+PHP页面,向HTTP WEB服务器Apache发起HTTP请求,WEB服务器接受该请求,并根据其后缀判断如果请求的页面是以.php结尾,WEB服务器从硬盘或者内存中取出该PHP文件,将其发送给PHP引擎程序。
PHP引擎程序将会对WEB服务器传送过来的文件进行扫描并根据命令从后台读取、处理数据、并动态地生成相应的HTML页面。然后PHP引擎程序将生成的HTML页面返回给WEB服务器,最终WEB服务器将HTML页面返回给客户端浏览器,浏览器基于MIME类型进行解析展示给用户页面。
12.3 LAMP企业安装配置
构建LAMP架构有两种方法,一是使用YUM在线安装,另外一种是基于LAMP源码编译安装,YUM在线安装方法如下:
yum install httpd httpd-devel mysql mysql-server mysql-devel php php-devel php-mysql -y
service httpd restart
service mysqld restart
YUM方式安装简单、快捷,但如果需要添加扩展的功能和模块,需使用源码包的方式来编译安装LAMP。如下为LAMP源码编译安装的步骤:
(1)Apache WEB安装,先安装apr、apr-utils库包。
yum install apr-devel apr-util-devel -y;
cd /usr/src ;
wget http://mirror.bit.edu.cn/apache/httpd/httpd-2.2.31.tar.gz
tar xzf httpd-2.2.31.tar.gz
cd httpd-2.2.31
./configure --prefix=/usr/local/apache --enable-so --enable-rewrite
make
make install
(2)MYSQL数据库安装,基于MYSQL5.5编译安装,通过cmake、make、make install三个步骤实现。
yum install cmake ncurses-devel ncurses -y
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql55 \
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \
-DMYSQL_DATADIR=/data/mysql \
-DSYSCONFDIR=/etc \
-DMYSQL_USER=mysql \
-DMYSQL_TCP_PORT=3306 \
-DWITH_XTRADB_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_EXTRA_CHARSETS=1 \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=all \
-DWITH_BIG_TABLES=1 \
-DWITH_DEBUG=0
make
make install
将源码安装的Mysql数据库服务设置为系统服务,可以使用chkconfig管理,并启动MYSQL数据库:
cd /usr/local/mysql55/
\cp support-files/my-large.cnf /etc/my.cnf
\cp support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld 
chkconfig --level 35 mysqld on
mkdir -p /data/mysql
useradd mysql
/usr/local/mysql55/scripts/mysql_install_db --user=mysql --datadir=/data/mysql/ --basedir=/usr/local/mysql55/
ln -s /usr/local/mysql55/bin/* /usr/bin/
service mysqld restart
(3)PHP服务安装,PHP需与Apache、MySQL进行整合,如图12-3所示,参数命令如下:
cd /usr/src
wget http://mirrors.sohu.com/php/php-5.3.28.tar.bz2
tar jxf php-5.3.28.tar.bz2
cd php-5.3.28 ;
./configure --prefix=/usr/local/php5 --with-config-file-path=/usr/local/php5/etc --with-apxs2=/usr/local/apache2/bin/apxs --with-mysql=/usr/local/mysql55/

图12-3 LAMP源码编译整合
(4)Apache+PHP源码整合
为了能让Apache发布PHP页面,需要将PHP安装完成后的libphp5.so模块与Apache进行整合,vim httpd.conf编辑配置文件,加入如下代码:
LoadModule      php5_module modules/libphp5.so
AddType application/x-httpd-php .php
DirectoryIndex   index.php index.html index.htm
(5)测试Apache+PHP环境
创建PHP测试页面,在/usr/local/apache/htdocs目录下创建index.php测试页面,执行如下命令自动创建:
cat >/usr/local/apache/htdocs/index.php<<EOF
<?php
phpinfo();
?>
EOF
重新启动Apache服务,浏览器输入 Apache WEB的IP访问,如图12-4所示,即代表LAMP源码环境整合成功。
图12-4 Apache+PHP测试页面
(6)Discuz PHP论坛安装
LAMP源码整合完毕之后,Dicuz官网下载Discuz开源PHP软件包,将软件包解压并发布在Apache Htdocs发布目录,代码如下:
cd /usr/src ;
wget http://download.comsenz.com/DiscuzX/3.1/Discuz_X3.1_SC_UTF8.zip
unzip Discuz_X3.1_SC_UTF8.zip -d /usr/local/apache/htdocs/
cd /usr/local/apache/htdocs/ ;\mv upload/* .
chmod 757 -R data/ uc_server/ config/ uc_client/
通过浏览器访问Apache WEB IP,如图12-5所示,选择“我同意”

图12-5 Discuz安装界面一
进入如图12-6界面,数据库安装,如果不存在则需要新建数据库并授权。

图12-6 Discuz安装界面二
MYSQL数据库命令行中创建PHP连接MYSQL的用户及密码,命令如下:
create database discuz charset=utf8;
grant all on discuz.* to root@'localhost' identified by "123456";
单击下一步,直至安装完成,浏览器自动跳转至如图12-7所示界面:

图12-7 Discuz安装界面三
12.4 LAMP企业架构拓展实战
如上LAMP服务均安装至单台服务器,随着用户访问量不断的增加,单台服务器压力逐渐增加,那如何优化LAMP架构,如何拆分LAMP架构呢,怎么把Apache和MySQL分开放在不同的机器呢。
LAMP架构拆分的目的在于缓解单台服务器的压力,可以将PHP、MYSQL单独安装至多台服务器,本节将实现LAP+MySQL的架构,也即是把MYSQL单独拆分出去。部署方法有两种:
(1)YUM安装LAMP多机方案
在Apache WEB服务器只需只需如下代码:
yum install httpd httpd-devel php-devel php php-mysql -y
在MYSQL数据库服务器只需只需如下代码:
yum install mysql-server mysql mysql-devel mysql-libs -y
(2)源码安装LAMP多机方案
源码安装LAMP多机方式,Apache WEB服务与MYSQL数据库服务分别部署在不同的服务器即可,PHP与Apache服务部署在一台服务器,PHP编译参数时加入如下代码进行LAMP的整合,mysqlnd为PHP远程连接MYSQL数据库服务器的一种方式:
./configure --prefix=/usr/local/php5 \
--with-mysql=mysqlnd  --with-mysqli=mysqlnd  --with-pdo-mysql=mysqlnd \
--with-apxs2=/usr/local/apache2/bin/apxs
make
make install
12.5 LAMP+Redis企业实战
LAMP在企业生产环境中,除了将MYSQL单独部署在其他服务器、由于MYSQL数据库压力会很大,还会对MYSQL实现主从复制及读写分离,同时会对PHP网站进行调优,通常PHP的优化手段包括:PHP代码本身优化、PHP配置文件优化、为PHP添加缓存模块,将PHP网站数据存入缓存等。
12.5.1 Redis入门简介
Redis是一个开源的使用ANSI  C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis是一个key-value存储系统。
和Memcached缓存类似,Redis支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(有序集合)和hash(哈希类型)。
Redis是一种高级key-value数据库,它跟memcached类似,不过Redis的数据可以持久化,而且支持的数据类型很丰富,有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交和补集(difference)等,还支持多种排序功能。Redis也被看成是一个数据结构服务器。
Redis很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。Redis提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,方便易用,得到IT人的青睐。
Redis支持主从同步,数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制,由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录,同步对读取操作的可扩展性和数据冗余很有帮助。
目前使用Redis的互联网企业有:京东、百度、腾讯、阿里巴巴、新浪、图吧、研修网等等,如表12-1所示,为目前主流数据库简单功能对比:
名称 数据库类型 数据存储选项 操作类型 备注
Redis 内存存储,Nosql数据库 支持字符串、列表、集合、散列表、有序集合 增、删、修改、更新 支持分布式集群、主从同步及高可用、单线程
Memcached 内存缓存数据库,键值对 键值之间的映射 增、删、修改、更新 支持多线程
MySQL 典型关系数据库,RDBMS 数据库由多表主成,每张表包含多行 增、删、修改、更新 支持ACID性质
PostgreSQL 典型关系数据库,RDBMS 数据库由多表主成,每张表包含多行 增、删、修改、更新 支持ACID性质
MongoDB 硬盘存储,Nosql数据库 数据库包含多个表 增、删、修改、更新 主从复制,分片,副本集、空间索引
表12-1 常见数据库功能对比
12.5.2 LAMP+Redis工作机制
LAMP+Redis工作机制:用户通过浏览器访问LAMP网站,并以用户名和密码登录到网站,默认Redis缓存中没有该用户名和密码对应列表,PHP程序会读取MYSQL数据库中的用户名和密码,然后将用户名和密码缓存至Redis中,下次用户通过浏览器再次使用同样的用户名和密码登录网站,PHP无需从数据库中读取该用户和密码信息,而是直接优先从Redis缓存中读取并返回,从而减轻MYSQL数据库的压力。
Redis除了可以缓存用户名、密码,还可以换成PHP论坛各种数据,例如用户帖子、用户动态等等,如图12-8所示:
图12-8 LAMP+Redis架构流程图
要实现将LAMP PHP网站相关数据存入Redis,需要一台Redis服务器、PHP-redis连接驱动、PHP代码连接修改等。
12.5.3 LAMP+Redis操作案例
LAMP PHP连接Redis,首先需安装Redis服务器,安装连接驱动,然后修改PHP网站配置文件,具体操作步骤如下:
(1)LAMP+Redis实战环境配置
LAMP服务器: 192.168.149.128
Redis主库: 192.168.149.129
Redis从库: 192.168.149.130
(2)192.168.149.129服务器安装部署Redis服务,代码如下
wget http://download.redis.io/releases/redis-2.8.13.tar.gz
tar zxf redis-2.8.13.tar.gz
cd redis-2.8.13
make PREFIX=/usr/local/redis install
cp redis.conf /usr/local/redis/
将/usr/local/redis/bin/目录加入至环境变量配置文件/etc/profile末尾,然后Shell终端执行source /etc/profile让环境变量生效。
export PATH=/usr/local/redis/bin:$PATH
Nohup后台启动及停止Redis服务命令:
nohup /usr/local/redis/bin/redis-server /usr/local/redis/redis.conf &
/usr/local/redis/bin/redis-cli -p 6379 shutdown
(3)安装PHP-Redis连接驱动
要确保PHP能够连接Redis缓存服务器,需添加PHP Redis扩展程序,也即是添加PHP安ext扩展模块,添加方法如下:
wget https://github.com/phpredis/phpredis/archive/3.1.2.tar.gz
tar xzf 3.1.2.tar.gz
cd phpredis-3.1.2/
./configure --with-php-config=/usr/local/php5/bin/php-config --enable-redis
make
make install
修改vim /usr/local/php/lib/php.ini配置文件,添加redis.so模块,代码如下:
extension_dir = "/usr/local/php5/lib/php/extensions/no-debug-zts-20090626"
extension=redis.so
重启Apache服务,写入phpinfo测试页面,通过浏览器访问,如图12-9所示,检查到存在Redis模块即可:
图12-9 PHP Redis模块添加
(4)LAMP+Redis缓存测试
登录192.168.149.128 WEB服务器,修改Discuz PHP网站发布/usr/local/apache2/htdcos目录全局配置文件config_global.php,查找CONFIG MEMORY段,将redis server后改为Redis主服务器的IP 192.168.149.129即可,如图12-10所示:
图12-10 PHP Redis配置文件修改
通过浏览器访问Apache PHP论坛网站,同时登陆Redis服务器,执行命令redis-cli进入Redis命令行,运行命令KEYS *,如图12-11所示,存在以IOKLAN开头的key,则证明Redis成功缓存LAMP+Discuz网站信息数据。
图12-11 Redis缓存LAMP KEYS数据
(3)测试Redis缓存是否生效
访问LAMP+Discuz网站,创建论坛测试用户jfedu666,密码jfedu666,此时用户数据第一次注册,用户名和密码会写入到MySQL数据库表中,同时会写入该数据也会写入到Redis缓存,如图12-12(a)、12-12(b)、12-12(c)所示:
图12-12(a) 创建论坛用户和密码
图12-12(b) MySQL数据库用户查询
图12-12(c) Redis缓存测试案例
将jfedu666从MySQL Discuz库pre_common_member中删除,通过该用户依然可以正常登录WEB网站,则证明此时数据读取的是Redis缓存服务器,如图12-13(a)、12-13(b)、12-13(c)所示:
图12-13(a) 删除数据库用户和密码
图12-13(b) 用户名和密码登录discuz论坛
图12-13(c) 用户名和密码登录discuz论坛
12.6 Redis配置文件详解
Redis是一个内存数据库,附Redis.conf常用参数的详解,后面章节会继续深入讲解。

daemonize no Linux Shell终端运行redis,改为yes即后台运行Redis服务;

daemonize yes

当运行多个 redis 服务时,需要指定不同的pid文件和端口

pidfile /var/run/redis_6379.pid

指定redis运行的端口,默认是 6379

port 6379

在高并发的环境中,为避免慢客户端的连接问题,需要设置一个高速后台日志

tcp-backlog 511

指定redis只接收来自于该 IP 地址的请求,如果不进行设置,那么将处理所有请求

bind 192.168.1.100 10.0.0.1

bind 127.0.0.1

设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接;

timeout 0

在Linux 上,指定值(秒)用于发送 ACKs 的时间。注意关闭连接需要双倍的时间。默认为 0 。

tcp-keepalive 0

Redis总共支持四个日志级别: debug 、 verbose 、 notice 、 warning ,默认为 verbose

debug 记录很多信息,用于开发和测试

varbose 有用的信息,不像 debug 会记录那么多

notice 普通的 verbose ,常用于生产环境

warning 只有非常重要或者严重的信息会记录到日志

loglevel notice

配置 log 文件地址

默认值为 stdout ,标准输出,若后台模式会输出到 /dev/null 。

logfile /var/log/redis/redis.log

可用数据库数

默认值为16 ,默认数据库为0,数据库范围在 0- ( database-1 )之间

databases 16

数据写入磁盘快照设置

保存数据到磁盘,格式如下 :

save

指出在多长时间内,有多少次更新操作,就将数据同步到数据文件 rdb 。

相当于条件触发抓取快照,这个可以多个条件配合

比如默认配置文件中的设置,就设置了三个条件

save 900 1 900 秒内至少有 1 个 key 被改变

save 300 10 300 秒内至少有 300 个 key 被改变

save 60 10000 60 秒内至少有 10000 个 key 被改变

save 900 1

save 300 10

save 60 10000

后台存储错误停止写。

stop-writes-on-bgsave-error yes

存储至本地数据库时(持久化到 rdb 文件)是否压缩数据,默认为 yes

rdbcompression yes

本地持久化数据库文件名,默认值为 dump.rdb

dbfilename dump.rdb

工作目录

数据库镜像备份的文件放置的路径。

这里的路径跟文件名要分开配置是因为 redis 在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成,

再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。

AOF 文件也会存放在这个目录下面

注意这里必须制定一个目录而不是文件

dir /var/lib/redis/
################################# 复制 #################################

主从复制 . 设置该数据库为其他数据库的从数据库 .

设置当本机为 slav 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步

slaveof

当 master 服务设置了密码保护时 ( 用 requirepass 制定的密码 )

slave 服务连接 master 的密码

masterauth

当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:

1) 如果 slave-serve-stale-data 设置为 yes( 默认设置 ) ,从库会继续响应客户端的请求

2) 如果 slave-serve-stale-data 是指为 no ,出去 INFO 和 SLAVOF 命令之外的任何请求都会返回一个

错误 "SYNC with master in progress"

slave-serve-stale-data yes

配置 slave 实例是否接受写。写 slave 对存储短暂数据(在同 master 数据同步后可以很容易地被删除)是有用的,但未配置的情况下,客户端写可能会发送问题。

从 Redis2.6 后,默认 slave 为 read-only

slaveread-only yes

从库会按照一个时间间隔向主库发送 PINGs. 可以通过 repl-ping-slave-period 设置这个时间间隔,默认是 10 秒

repl-ping-slave-period 10

repl-timeout 设置主库批量数据传输时间或者 ping 回复时间间隔,默认值是 60 秒

一定要确保 repl-timeout 大于 repl-ping-slave-period

repl-timeout 60

在 slave socket 的 SYNC 后禁用 TCP_NODELAY

如果选择“ yes ” ,Redis 将使用一个较小的数字 TCP 数据包和更少的带宽将数据发送到 slave , 但是这可能导致数据发送到 slave 端会有延迟 , 如果是 Linux kernel 的默认配置,会达到 40 毫秒 .

如果选择 "no" ,则发送数据到 slave 端的延迟会降低,但将使用更多的带宽用于复制 .

repl-disable-tcp-nodelay no

设置复制的后台日志大小。

复制的后台日志越大, slave 断开连接及后来可能执行部分复制花的时间就越长。

后台日志在至少有一个 slave 连接时,仅仅分配一次。

repl-backlog-size 1mb

在 master 不再连接 slave 后,后台日志将被释放。下面的配置定义从最后一个 slave 断开连接后需要释放的时间(秒)。

0 意味着从不释放后台日志

repl-backlog-ttl 3600

如果 master 不能再正常工作,那么会在多个 slave 中,选择优先值最小的一个 slave 提升为 master ,优先值为 0 表示不能提升为 master 。

slave-priority 100

如果少于 N 个 slave 连接,且延迟时间 <=M 秒,则 master 可配置停止接受写操作。

例如需要至少 3 个 slave 连接,且延迟 <=10 秒的配置:

min-slaves-to-write 3

min-slaves-max-lag 10

设置 0 为禁用

默认 min-slaves-to-write 为 0 (禁用), min-slaves-max-lag 为 10

################################## 安全 ###################################

设置客户端连接后进行任何其他指定前需要使用的密码。

警告:因为 redis 速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行 150K 次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解

requirepass jfedu

命令重命名 .

在一个共享环境下可以重命名相对危险的命令。比如把 CONFIG 重名为一个不容易猜测的字符。

举例 :

rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52

如果想删除一个命令,直接把它重命名为一个空字符 "" 即可,如下:

rename-command CONFIG ""

###################################约束###################################

设置同一时间最大客户端连接数,默认无限制,

Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,

如果设置 maxclients 0 ,表示不作限制。

当客户端连接数到达限制时, Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息

maxclients 10000

指定 Redis 最大内存限制, Redis 在启动时会把数据加载到内存中,达到最大内存后, Redis 会按照清除策略尝试清除已到期的 Key

如果 Redis 依照策略清除后无法提供足够空间,或者策略设置为 ”noeviction” ,则使用更多空间的命令将会报错,例如 SET, LPUSH 等。但仍然可以进行读取操作

注意: Redis 新的 vm 机制,会把 Key 存放内存, Value 会存放在 swap 区

该选项对 LRU 策略很有用。

maxmemory 的设置比较适合于把 redis 当作于类似 memcached 的缓存来使用,而不适合当做一个真实的 DB 。

当把 Redis 当做一个真实的数据库使用的时候,内存使用将是一个很大的开销

maxmemory

当内存达到最大值的时候 Redis 会选择删除哪些数据?有五种方式可供选择

volatile-lru -> 利用 LRU 算法移除设置过过期时间的 key (LRU: 最近使用 Least RecentlyUsed )

allkeys-lru -> 利用 LRU 算法移除任何 key

volatile-random -> 移除设置过过期时间的随机 key

allkeys->random -> remove a randomkey, any key

volatile-ttl -> 移除即将过期的 key(minor TTL)

noeviction -> 不移除任何可以,只是返回一个写错误

注意:对于上面的策略,如果没有合适的 key 可以移除,当写的时候 Redis 会返回一个错误

默认是 : volatile-lru

maxmemory-policy volatile-lru

LRU 和 minimal TTL 算法都不是精准的算法,但是相对精确的算法 ( 为了节省内存 ) ,随意你可以选择样本大小进行检测。

Redis 默认的灰选择 3 个样本进行检测,你可以通过 maxmemory-samples 进行设置

maxmemory-samples 3

############################## AOF###############################

默认情况下, redis 会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况,那么将造成比较大范围的数据丢失。

所以 redis 提供了另外一种更加高效的数据库备份及灾难恢复方式。

开启 append only 模式之后, redis 会把所接收到的每一次写操作请求都追加到 appendonly.aof 文件中,当 redis 重新启动时,会从该文件恢复出之前的状态。

但是这样会造成 appendonly.aof 文件过大,所以 redis 还支持了 BGREWRITEAOF 指令,对 appendonly.aof 进行重新整理。

你可以同时开启 asynchronous dumps 和 AOF

appendonly no

AOF 文件名称 ( 默认 : "appendonly.aof")

appendfilename appendonly.aof

Redis 支持三种同步 AOF 文件的策略 :

no: 不进行同步,系统去操作 . Faster.

always: always 表示每次有写操作都进行同步 . Slow, Safest.

everysec: 表示对写操作进行累积,每秒同步一次 . Compromise.

默认是 "everysec" ,按照速度和安全折中这是最好的。

如果想让 Redis 能更高效的运行,你也可以设置为 "no" ,让操作系统决定什么时候去执行

或者相反想让数据更安全你也可以设置为 "always"

如果不确定就用 "everysec".

appendfsync always

appendfsync everysec

appendfsync no

AOF 策略设置为 always 或者 everysec 时,后台处理进程 ( 后台保存或者 AOF 日志重写 ) 会执行大量的 I/O 操作

在某些 Linux 配置中会阻止过长的 fsync() 请求。注意现在没有任何修复,即使 fsync 在另外一个线程进行处理

为了减缓这个问题,可以设置下面这个参数 no-appendfsync-on-rewrite

no-appendfsync-on-rewrite no

AOF 自动重写

当 AOF 文件增长到一定大小的时候 Redis 能够调用 BGREWRITEAOF 对日志文件进行重写

它是这样工作的: Redis 会记住上次进行些日志后文件的大小 ( 如果从开机以来还没进行过重写,那日子大小在开机的时候确定 )

基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动

同时需要指定一个最小大小用于 AOF 重写,这个用于阻止即使文件很小但是增长幅度很大也去重写 AOF 文件的情况

设置 percentage 为 0 就关闭这个特性

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
######## # LUA SCRIPTING #########

一个 Lua 脚本最长的执行时间为 5000 毫秒( 5 秒),如果为 0 或负数表示无限执行时间。

lua-time-limit 5000
################################LOW LOG################################

Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括 I/O 计算比如连接客户端,返回结果等,只是命令执行时间

可以通过两个参数设置 slow log :一个是告诉 Redis 执行超过多少时间被记录的参数 slowlog-log-slower-than( 微妙 ) ,

另一个是 slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除

下面的时间以微妙为单位,因此 1000000 代表一秒。

注意指定一个负数将关闭慢日志,而设置为 0 将强制每个命令都会记录

slowlog-log-slower-than 10000

对日志长度没有限制,只是要注意它会消耗内存

可以通过 SLOWLOG RESET 回收被慢日志消耗的内存

推荐使用默认值 128 ,当慢日志超过 128 时,最先进入队列的记录会被踢出

slowlog-max-len 128
12.7 Redis常用配置
Redis缓存服务器命令行中常用命令如下:
Redis CONFIG 命令格式如下:
redis 127.0.0.1:6379> CONFIG GET|SET CONFIG_SETTING_NAME
CONFIG GET 获取Redis服务器所有配置信息;
CONFIG SET loglevel "notice" 设置Redis服务器日志级别;
CONFIG SET requirepass "jfedu"
AUTH jfedu
redis-cli -h host -p port -a password 远程连接redis数据库;
CLIENT GETNAME 获取连接的名称;
CLIENT SETNAME 设置当前连接的名称;
CLUSTER SLOTS 获取集群节点的映射数组;
COMMAND 获取Redis命令详情数组;
COMMAND COUNT 获取 Redis 命令总数;
COMMAND GETKEYS 获取给定命令的所有键;
TIME 返回当前服务器时间;
CONFIG GET parameter 获取指定配置参数的值;
CONFIG SET parameter value 修改redis 配置参数,无需重启;
CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据;
DBSIZE 返回当前数据库的 key 的数量;
DEBUG OBJECT key 获取 key 的调试信息;
DEBUG SEGFAULT 让Redis服务崩溃;
FLUSHALL 删除所有数据库的所有key;
FLUSHDB 删除当前数据库的所有key;
ROLE 返回主从实例所属的角色;
SAVE 异步保存数据到硬盘;
SHUTDOWN 异步保存数据到硬盘,并关闭服务器;
SLOWLOG 管理 redis 的慢日志;
SET keys values 设置key为jfedu,值为123;
DEL jfedu 删除key及值;
INFO CPU 查看服务器CPU占用信息;
KEYS jfedu 查看是存在jfedu的key;
KEYS
查看Redis所有的KEY;
CONFIG REWRITE 启动 Redis时所指定的redis.conf 配置文件进行改写;
INFO [section] 获取Redis服务器的各种信息和统计数值;
SYNC 用于复制功能(replication)的内部命令;
SLAVEOF host port 指定服务器的从属服务器(slave server);
MONITOR 实时打印出Redis服务器接收到的命令,调试用;
LASTSAVE 返回最近一次Redis成功将数据保存到磁盘上的时间;;
CLIENT PAUSE timeout 指定时间内终止运行来自客户端的命令;
BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作;
BGSAVE 后台异步保存当前数据库的数据到磁盘。
12.8 Redis集群主从实战
为了提升redis高可用性,我们除了备份redis dump数据之外,还需要创建redis主从架构,可以利用从将数据库持久化(数据持久化通俗讲就是把数据保存到磁盘上,保证不会因为断电等因素丢失数据。
Redis需要经常将内存中的数据同步到磁盘来保证持久化。redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。)
Redis主从复制,当用户往Master端写入数据时,通过Redis Sync机制将数据文件发送至Slave,Slave也会执行相同的操作确保数据一致;且实现Redis的主从复制非常简单。同时slave上还可以开启二级slave,三级slave从库,跟MySQL的主从类似。
Redis主从配置非常简单,只需要在Redis丛库192.168.149.130配置中设置如下指令,slaveof表示指定主库的IP,192168.149.129为master服务器,6379为master服务器Redis端口,配置方法如下:
(1)192.168.149.129 Redis主库redis.conf配置文件如下:
daemonize no
pidfile /var/run/redis.pid
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel notice
logfile ""
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename redis.rdb
dir /data/redis/
slave-serve-stale-data yes
slave-read-only yes
repl-disable-tcp-nodelay no
slave-priority 100
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
(2)192168.149.130 Redis丛库redis.conf配置文件如下:
daemonize no
pidfile /var/run/redis.pid
port 6379
slaveof 192.168.149.129 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel notice
logfile ""
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename redis.rdb
dir /data/redis/
slave-serve-stale-data yes
slave-read-only yes
repl-disable-tcp-nodelay no
slave-priority 100
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
(3)重启Redis主库、丛库服务,在Redis主库创建key及values,登录Redis丛库查看,如图12-14(a)、12-14(b)所示:
图12-14(a) Redis主库创建key
图12-14(b) Redis从库获取key值
12.9 Redis数据备份与恢复
Redis所有数据都是保存在内存中,Redis数据备份可以定期的通过异步方式保存到磁盘上,该方式称为半持久化模式,如果每一次数据变化都写入aof文件里面,则称为全持久化模式。同时还可以基于Redis主从复制实现Redis备份与恢复。
12.9.1 半持久化RDB模式
半持久化RDB模式也是Redis备份默认方式,是通过快照(snapshotting)完成的,当符合在Redis.conf配置文件中设置的条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上,完成数据备份。
Redis进行RDB快照的条件由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。在配置文件中已经预置了3个条件:
save 900 1 #900秒内有至少1个键被更改则进行快照;
save 300 10 #300秒内有至少10个键被更改则进行快照;
save 60 10000 #60秒内有至少10000个键被更改则进行快照。
默认可以存在多个条件,条件之间是“或”的关系,只要满足其中一个条件,就会进行快照。 如果想要禁用自动快照,只需要将所有的save参数删除即可。Redis默认会将快照文件存储在Redis数据目录,默认文件名为:dump.rdb文件,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。也可以在Redis命令行执行config get dir获取Redis数据保存路径,如图12-15(a)、12-15(b)所示:
图12-15(a) 获取Redis数据目录
图12-15(b) Redis数据目录及dump.rdb文件
Redis实现快照的过程,Redis使用fork函数复制一份当前进程(父进程)的副本(子进程),父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件,当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
执行fork的时操作系统会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时,操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。
Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得我们可以通过定时备份RDB文件来实 现Redis数据库备份。
RDB文件是经过压缩(可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。除了自动快照,还可以手动发送SAVE和BGSAVE命令让Redis执行快照,两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他请求,后者会通过fork子进程进行快照操作。
Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存,根据数据量大小与结构和服务器性能不同,通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需花费20~30秒钟。
通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。此时需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。
12.9.2 半持久化AOF模式
如果数据很重要无法承受任何损失,可以考虑使用AOF方式进行持久化,默认Redis没有开启AOF(append only file)方式的全持久化模式。
在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些,开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改该名称。
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少,可以在redis.conf中通过appendonly参数开启Redis AOF全持久化模式:
appendonly yes
appendfilename appendonly.aof
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
appendfsync always

appendfsync everysec

appendfsync no

Redis AOF持久化参数配置详解:
appendonly yes #开启AOF持久化功能;
appendfilename appendonly.aof #AOF持久化保存文件名;
appendfsync always #每次执行写入都会执行同步,最安全也最慢;

appendfsync everysec #每秒执行一次同步操作;

appendfsync no #不主动进行同步操作,而是完全交由操作系统来做,每30秒一次,最快也最不安全;

auto-aof-rewrite-percentage 100 #当AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据;
auto-aof-rewrite-min-size 64mb #允许重写的最小AOF文件大小配置写入AOF文件后,要求系统刷新硬盘缓存的机制。
12.9.3 Redis主从复制备份
通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。但是由于数据是存储在一台服务器上的,如果这台服务器的硬盘出现故障,也会导致数据丢失。
为了避免单点故障,我们希望将数据库复制多个副本以部署在不同的服务器上,即使只有一台服务器出现故障其他服务器依然可以继续提供服务,这就要求当一台服务器上的数据库更新后,可以自动将更新的数据同步到其他服务器上,Redis提供了复制(replication)功能可以自动实现同步的过程。通过配置文件在Redis从数据库中配置文件中加入slaveof master-ip master-port即可,主数据库无需配置。
Redis主从复制优点及应用场景, WEB应用程序可以基于主从同步实现读写分离以提高服务器的负载能力。在常见的场景中,读的频率一般比较大,当单机Redis无法应付大量的读请求时,可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库负责读操作,还可以基于LVS+keepalived+Redis对Redis实现均和高可用。
从数据库持久化持久化通常相对比较耗时,为了提高性能,可以通过复制功能建立一个(或若干个)从数据库,并在从数据库中启用持久化,同时在主数据库禁用持久化。
当从数据库崩溃时重启后主数据库会自动将数据同步过来,所以无需担心数据丢失。而当主数据库崩溃时,需要在从数据库中使用SLAVEOF NO ONE命令将从数据库提升成主数据库继续服务,并在原来的主数据库启动后使用SLAVE OF命令将其设置成新的主数据库的从数据库,即可将数据同步回来。
12.10 LAMP企业架构读写分离
LAMP+Discuz+Redis缓解了MYSQL的部分压力,但是如果访问量非常大,Redis缓存中第一次没有缓存数据,会导致MYSQL数据库压力增大,此时可以基于分库、分表、分布式集群、或者读写分离来分担MYSQL数据库的压力,以读写分离为案例,来实现分担MYSQL数据库的压力。
MYSQL读写分离的原理其实就是让Master数据库处理事务性增、删除、修改、更新操作(CREATE、INSERT、UPDATE、DELETE),而让Slave数据库处理SELECT操作,MYSQL读写分离前提是基于MYSQL主从复制,这样可以保证在Master上修改数据,Slave同步之后,WEB应用可以读取到Slave端的数据。
实现MYSQL读写分离可以基于第三方插件,也可以通过开发修改代码实现,具体实现的读写分离的常见方式有如下四种:
MySQL-Proxy读写分离
Amoeba读写分离
Mycat读写分离
基于程序读写分离(效率很高,实施难度大,开发改代码)
Amoeba是以MySQL为底层数据存储,并对WEB、APP应用提供MySQL协议接口的proxy。它集中地响应WEB应用的请求,依据用户事先设置的规则,将SQL请求发送到特定的数据库上执行,基于此可以实现负载均衡、读写分离、高可用性等需求。
Amoeba相当于一个SQL请求的路由器,目的是为负载均衡、读写分离、高可用性提供机制,而不是完全实现它们。用户需要结合使用MySQL的 Replication等机制来实现副本同步等功能。
Mysql-Proxy是MySQL官方提供的mysql中间件服务,支持无数客户端连接,同时后端可连接若干台Mysql-Server服务器,MYSQL-Proxy自身基于MySQL协议,连接MYSQL-Proxy的客户端无需修改任何设置, 跟正常连接MYSQL Server没有区别,无需修改程序代码。
MySQL Proxy是App应用(客户端)与MYSQL Server之间的一个连接代理,MySQL Proxy负责将APP应用的SQL请求根据转发规则,转发至相应的后端数据库,基于lua脚本,可以实现复杂的连接控制和过滤,从而实现数据读写分离和负载均衡的需求。
Mysql-Proxy允许用户指定Lua脚本对SQL请求进行拦截,对请求进行分析与修改,还允许用户指定Lua脚本对服务器的返回结果进行修改,加入一些结果集或者去除一些结果集,对SQL的请求通常为读请求、写请求,基于Lua脚本,可以实现将SQL读请求转发至后端Slave服务器,将SQL写请求转发至后端Master服务器。
如图12-16所示,为MYSQL-PROXY读写分离架构图,通过架构图可以清晰看到SQL请求整个流向的过程。

图12-16 MYSQL-Proxy读写分离流程
Mysql-Proxy读写分离架构实战配置,如图12-17所示,两台WEB通过MYSQL-Proxy连接后端1.14和1.15 MYSQL服务器。
图12-17 MYSQL-Proxy实施架构图
构建Mysql读写分离架构首先需要将两台MYSQL服务器配置为主从复制(前文已存在,此处省略配置),配置完毕后,在192.168.1.16服务器上安装Mysql-Proxy服务即可,配置步骤如下:
(1)下载MYSQL-Proxy软件版本,解压并重命名至/usr/local/mysql-proxy,命令如下:
wget http://ftp.ntu.edu.tw/pub/MySQL/Downloads/MySQL-Proxy/mysql-proxy-0.8.4-linux-el6-x86-64bit.tar.gz
useradd -r mysql-proxy
tar zxvf mysql-proxy-0.8.4-linux-el6-x86-64bit.tar.gz -C /usr/local
mv /usr/local/mysql-proxy-0.8.4-linux-el6-x86-64bit /usr/local/mysql-proxy
(2)环境变量配置文件/etc/profile中加入如下代码保存退出,然后执行source /etc/profile使环境变量配置生效即可:
export PATH=$PATH:/usr/local/mysql-proxy/bin/
(3)启动MYSQL-Proxy中间件,命令如下:
mysql-proxy --daemon --log-level=debug --user=mysql-proxy --keepalive --log-file=/var/log/mysql-proxy.log --plugins="proxy" --proxy-backend-addresses="192.168.1.14:3306" --proxy-read-only-backend-addresses="192.168.1.15:3306" --proxy-lua-script="/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua" --plugins=admin --admin-username="admin" --admin-password="admin" --admin-lua-script="/usr/local/mysql-proxy/lib/mysql-proxy/lua/admin.lua"
(4)Mysql-Proxy的相关参数详解如下:
--help-all :获取全部帮助信息;
--proxy-address=host:port :代理服务监听的地址和端口,默认为4040;
--admin-address=host:port :管理模块监听的地址和端口,默认为4041;
--proxy-backend-addresses=host:port :后端mysql服务器的地址和端口;
--proxy-read-only-backend-addresses=host:port :后端只读mysql服务器的地址和端口;
--proxy-lua-script=file_name :完成mysql代理功能的Lua脚本;
--daemon :以守护进程模式启动mysql-proxy;
--keepalive :在mysql-proxy崩溃时尝试重启之;
--log-file=/path/to/log_file_name :日志文件名称;
--log-level=level :日志级别;
--log-use-syslog :基于syslog记录日志;
--plugins=plugin :在mysql-proxy启动时加载的插件;
--user=user_name :运行mysql-proxy进程的用户;
--defaults-file=/path/to/conf_file_name :默认使用的配置文件路径,其配置段使用[mysql-proxy]标识;
--proxy-skip-profiling :禁用profile;
--pid-file=/path/to/pid_file_name :进程文件名;
(5)MYSQL-Proxy启动后,在服务器端查看端口,其中4040为proxy代理端口用于WEB应用连接,4041位管理端口用于SA或者DBA管理,如图12-48所示:

图12-48 MYSQL-Proxy启动端口
(6)基于4041端口MySQL-Proxy查看读写分离状态,登录4041管理端口,命令如下:
mysql -h192.168.1.16 -uadmin -p -P 4041
(7)以4041管理口登录,然后执行select命令,如图12-18所示state均为up状态,type类型为rw、ro,则证明读写分离状态成功。如果状态为unknown未知状态,可以4040端口登录执行:show databases;命令,直到state变成up状态为止。
select * from backends;
图12-18 MYSQL-Proxy读写分离状态
(8)读写分离数据测试,以3306端口登录到从库,进行数据写入和测试,在丛库上创建jfedu_test测试库,并写入内容,如图12-19所示:

图12-19 MYSQL-Proxy读写分离测试
(9)读写分离数据测试,以4040代理端口登录,执行如下命令,可以查看到数据即证明读写分离成功。
mysql -h192.168.1.16 -uroot -p123456 -P4040 -e "select * from jfedu_test.t1;"
(10)登录Apache WEB服务器,修改Discuz PHP网站发布/usr/local/apache2/htdcos目录全局配置文件config_global.php,查找dbhost段,将192.168.1.16 改成192.168.1.16:40404,如图12-20所示:

图12-20 MYSQL-Proxy读写分离测试
第13章 Zabbix分布式监控企业实战
企业服务器对用户提供服务,作为运维工程师最重要的事情就是保证该网站正常稳定的运行,需要实时监控网站、服务器的运行状态,并且有故障及时去处理。
监控网站无需人工时刻去访问WEB网站或者登陆服务器去检查,可以借助开源监控软件例如Zabbix、Cacti、Nagios、Ganglia等来实现对网站的7x24小时的监控,并且做到有故障及时报警通知SA解决。
本章向读者介绍企业级分布式监控Zabbix入门、Zabbix监控原理、最新版本Zabbix安装实战、Zabbix批量监控客户端、监控MYSQL、WEB关键词及微信报警等。
13.1 Zabbix监控系统入门简介
Zabbix是一个基于WEB界面的提供分布式系统监控的企业级的开源解决方案,Zabbix能监视各种网络参数,保证服务器系统的安全稳定的运行,并提供灵活的通知机制以让SA快速定位并解决存在的各种问题。Zabbix分布式监控系统的优点如下:
支持自动发现服务器和网络设备;
支持底层自动发现;
分布式的监控体系和集中式的WEB管理;
支持主动监控和被动监控模式;
服务器端支持多种操作系统:Linux, Solaris, HP-UX, AIX, FreeBSD, OpenBSD, MAC等;
Agent客户端支持多种操作系统:Linux, Solaris, HP-UX, AIX, FreeBSD,Windows等;
基于SNMP、IPMI接口方式也可以监控Agent;
安全的用户认证及权限配置;
基于WEB的管理方法,支持自由的自定义事件和邮件发送;
高水平的业务视图监控资源,支持日志审计,资产管理等功能;
支持高水平API二次开发、脚本监控、自Key定义、自动化运维整合调用。
13.2 Zabbix监控组件及流程
Zabbix监控组件如图13-1所示,主要由三大组件,分别是Zabbix server端、Zabbix Proxy、Agent客户端,其中Zabbix Server端包括:WEB GUI、Database、Zabbix_Server。
图13-1 Zabbix监控组件
Zabbix监控系统具体监控系统流程如图13-2所示:
图13-2 Zabbix监控流程图
Zabbix监控完整流程包括:Agent安装在被监控的主机上,Agent负责定期收集客户端本地各项数据,并发送到Zabbix Server端,Zabbix Server收到数据,将数据存储到数据库中,用户基于Zabbix WEB可以看到数据在前端展现图像。
当Zabbix监控某个具体的项目,该项目会设置一个触发器阀值,当被监控的指标超过该触发器设定的阀值,会进行一些必要的动作,动作包括:邮件、微信报警或者执行命令等操作。如下为Zabbix完整监控系统,各个部分负责的工作:
Zabbix Server:负责接收agent发送的报告信息的核心组件,所有配置,统计数据及操作数据均由其组织进行;
Database Storage:专用于存储所有配置信息,以及存储由Zabbix收集到的数据;
Web interface:Zabbix的GUI接口,通常与Server运行在同一台主机上;
Proxy:常用于分布监控环境中,代理Server收集部分被监控端的监控数据并统一发往Server端;
Zabbix Agent:部署在被监控主机上,负责收集本地数据并发往Server端或Proxy端;
Zabbix监控部署在系统中,会包含常见的四个程序:zabbix_server 、zabbix_get、zabbix_agentd 、zabbix_proxy、zabbix_sender等。四个程序启动后分别对应四个进程,如下为每个进程的功能:
Zabbix_server:Zabbix服务端守护进程,其中zabbix_agentd、zabbix_get、zabbix_sender、zabbix_proxy的数据最终均是提交给Zabbix_Server;
Zabbix_Agentd:客户端守护进程,负责收集客户端数据,例如收集cpu负载、内存、硬盘使用情况等;
Zabbix_get:Zabbix数据获取工具,单独使用的命令,通常在server或者proxy端执行获取远程客户端信息的命令;
Zabbix_sender:zabbix数据发送工具,用于发送数据给server或者proxy,通常用于耗时比较长的检查。很多检查非常耗时间,导致zabbix超时。于是我们在脚本执行完毕之后,使用sender主动提交数据;
Zabbix_proxy:zabbix分布式代理守护进程,分布式监控架构需要部署Zabbix_Proxy。
13.3 Zabbix监控方式及数据采集
Zabbix分布式监控系统监控客户端的方式常见有三种,分别是Agent方式、SNMP、IPMI方式,三种方式特点如下:
Agent:Zabbix可以基于自身zabbix_agent客户端插件监控OS的状态,例如CPU、内存、硬盘、网卡、文件等。
SNMP:Zabbix可以通过简单网络管理协议(Simple Network Management Protocol,SNMP)协议监控网络设备或者windows主机等,通过设定SNMP的参数将相关监控数据传送至服务器端,交换机、防火墙等网络设备一般都支持SNMP协议。
IPMI:智能平台管理接口(Intelligent Platform Management Interface,IPMI)即主要应用于设备的物理特性,包括:温度、电压、电扇工作状态、电源供应以及机箱入侵等。IPMI最大的优势在于无论OS在开机还是关机的状态下,只要接通电源就可以实现对服务器的监控。
Zabbix监控客户端分为主动监控与被动监控,主被动模式以客户端为参照,Zabbix监控客户端默认为被动模式,可以修改为主动模式,只需要在客户端配置文件中添加。可以关闭被动模式的方法:在配置文件中加入 StartAgents=0,即为关闭被动模式。主被动监控模式区别如下:
Zabbix主动模式:Agent主动请求server获取主动的监控项列表,并主动将监控项内需要检测的数据提交给server/proxy,zabbix agent首先向ServerActive配置的IP请求获取active items,获取并提交active tiems数据值server或者proxy;
Zabbix被动模式:Server向agent请求获取监控项的数据,agent返回数据,Server打开一个TCP连接,Server发送请求agent.ping,Agent接收到请求并且响应,Server处理接收到的数据。
13.4 Zabbix监控概念
Zabbix监控系统包括很多监控概念,掌握Zabbix监控概念能对Zabbix监控快速的理解,如下为Zabbix常用术语及解释。
主机(host): 被监控的网络设备,可以写IP或者DNS;
主机组(host group): 主机组用于管理主机,可以批量设置权限;
监控项(item): 具体监控项,items值由独立的keys进行识别;
触发器(trigger): 为某个items设置触发器,达到触发器会执行action动作;
事件(event): 例如达到某个触发器,称之为一个事件;
动作(action): 对于特定事件事先定义的处理方法,默认可以发送信息及发送命令;
报警升级(escalation): 发送警报或执行远程命令的自定义方案,如隔5分钟发送一次警报,共发送5次等。
媒介(media): 发送通知的方式,可以支持Mail、SMS、Scripts等;
通知(notification): 通过设置的媒介向用户发送的有关某事件的信息;
远程命令 达到触发器,可以在被监控端执行命令;
模板(template): 可以快速监控被监控端,模块包含:item、trigger、graph、screen、application;
web场景(web scennario)用于检测web站点可用性,监控HTTP关键词;
web前端(frontend): Zabbix的web接口;
图形(graph) 监控图像;
屏幕(screens) 屏幕显示;
幻灯(slide show) 幻灯显示。
13.5 Zabbix监控平台部署
Zabbix监控平台部署,至少需要安装四个组件,分别是Zabbix_Server、Zabbix_Web、Databases、Zabbix_Agent,如下为Zabbix监控平台安装配置详细步骤:
(1)系统环境
Server端:192.168.149.128
Agent端:192.168.149.129
(2)下载zabbix版本,各个版本之间安装方法相差不大,可以根据实际情况选择安装版本,本文版本为Zabbix-3.2.6.tar.gz。
wget  http://sourceforge.net/projects/zabbix/files/ZABBIX%20Latest%20Stable/3.2.6/zabbix-3.2.6.tar.gz/download
(3)Zabbix Server端和Zabbix Agent执行如下代码:
yum -y install curl curl-devel net-snmp net-snmp-devel perl-DBI
groupadd zabbix
useradd -g zabbix zabbix
usermod -s /sbin/nologin zabbix
(4)Zabbix Server端配置
创建zabbix数据库,执行授权命令:
create database zabbix charset=utf8;
grant all on zabbix. to zabbix@localhost identified by '123456';
flush privileges;
解压zabbix软件包并将Zabbix基础SQL文件导入数据至Zabbix数据库:
tar zxvf zabbix-3.2.6.tar.gz
cd zabbix-3.2.6
mysql -uzabbix -p123456 zabbix <database/mysql/schema.sql
mysql -uzabbix -p123456 zabbix <database/mysql/images.sql
mysql -uzabbix -p123456 zabbix < database/mysql/data.sql
切换至Zabbix解压目录,执行如下代码,安装Zabbixserver:
./configure --prefix=/usr/local/zabbix/ --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl
make
make install
ln -s /usr/local/zabbix/sbin/zabbix
/usr/local/sbin/
Zabbix server安装完毕,cd /usr/local/zabbix/etc/目录,如图13-3所示:
图13-3 Zabbix监控流程图
备份Zabbix server配置文件,代码如下:
cp zabbix_server.conf zabbix_server.conf.bak
将zabbix_server.conf配置文件中代码设置为如下:
LogFile=/tmp/zabbix_server.log
DBHost=localhost
DBName=zabbix
DBUser=zabbix
DBPassword=123456
同时cp zabbix_server启动脚本至/etc/init.d/目录,启动zabbix_server, Zabbix_server默认监听端口为10051。
cd zabbix-3.2.6
cp misc/init.d/tru64/zabbix_server  /etc/init.d/zabbix_server
chmod o+x /etc/init.d/zabbix_server
配置Zabbix interface Web页面,安装HTTP WEB服务器,将Zabbix WEB代码发布至Apache默认发布目录,由于Zabbix3.2+ PHP版本需要使用PHP5.4.0版本,请将本机PHP版本升级至5.4.0+,PHP5.3升级至PHP5.6,代码如下:
rpm -Uvh http://repo.webtatic.com/yum/el6/latest.rpm
yum remove php
yum install php56w.x86_64 php56w-cli.x86_64 php56w-common.x86_64 php56w-gd.x86_64 php56w-ldap.x86_64 php56w-mbstring.x86_64 php56w-mcrypt.x86_64 php56w-mysql.x86_64 php56w-pdo.x86_64 -y
yum install httpd httpd-devel httpd-tools -y
cp -a   /root/zabbix-3.2.6/frontends/php/
  /var/www/html/
sed  -i   '/date.timezone/i date.timezone = PRC'   /etc/php.ini
重新启动Zabbix Server、HTTP、MYSQL服务,代码如下:
/etc/init.d/zabbix_server restart
/etc/init.d/httpd   restart
/etc/init.d/mysqld restart
(5)Zabbix WEB GUI安装配置
通过浏览器Zabbix_WEB验证,通过浏览器访问http://192.168.149.128/,如图13-4所示:
图13-4 Zabbix WEB安装界面
单击下一步,出现如图13-5所示,如果有错误提示,需要把错误依赖解决完,方可进行下一步操作。
图13-5 Zabbix WEB安装错误提示
如上异常错误解决方法代码如下,安装缺失的软包,并修改php.ini对应参数的值即可,如图13-6所示:
yum install php56w-mbstring php56w-bcmath php56w-gd php56w-xml -y
yum install gd gd-devel -y
sed -i '/post_max_size/s/8/16/g;/max_execution_time/s/30/300/g;/max_input_time/s/60/300/g;s/\;date.timezone.*/date.timezone \= PRC/g;s/\;always_populate_raw_post_data/always_populate_raw_post_data/g' /etc/php.ini
/etc/init.d/httpd restart
图13-6 Zabbix WEB测试安装环境
单击下一步,如图13-7所示,配置数据库连接,输入数据库名、用户、密码,单击Test connection,显示OK,单击下一步即可。
图13-7 Zabbix WEB数据库配置
继续单击下一步出现如图13-8所示,填写Zabbix Title显示,可以为空,可以输入自定义的名称。
图13-8 Zabbix WEB详细信息
单击下一步,如图13-9所示,需修创建zabbix.conf.php文件,执行如下命令,或者单击“Download the configuration file”下载zabbix.conf.php文件,并将该文件上传至/var/www/html/conf/,并设置可写权限,刷新WEB页面,zabbix.conf.php内容代码如下,最后单击Finish即可:
<?php
// Zabbix GUI configuration file.
global $DB;
$DB['TYPE'] = 'MYSQL';
$DB['SERVER'] = 'localhost';
$DB['PORT'] = '0';
$DB['DATABASE'] = 'zabbix';
$DB['USER'] = 'zabbix';
$DB['PASSWORD'] = '123456';
// Schema name. Used for IBM DB2 and PostgreSQL.
$DB['SCHEMA'] = '';
$ZBX_SERVER = 'localhost';
$ZBX_SERVER_PORT = '10051';
$ZBX_SERVER_NAME = '京峰教育-分布式监控系统';
$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
图13-9 Zabbix WEB配置文件测试
登录Zabbix WEB界面,默认用户名和密码为:admin/zabbix,如图13-10(a)、13-10(b)所示:
图13-10(a) Zabbix WEB登录界面

图13-10(b) Zabbix WEB后台界面
(6)Agent客户端安装配置
解压zabbix-3.2.6.tar.gz源码文件,切换至解压目录,编译安装Zabbix,命令如下:
./configure  --prefix=/usr/local/zabbix --enable-agent
make
make install
ln -s /usr/local/zabbix/sbin/zabbix_ /usr/local/sbin/
修改zabbix_agentd.conf客户端配置文件,执行如下命令,zabbix_agentd.conf内容,指定server IP,同时设置本地Hostname为本地IP地址或者DNS名称:
CPU、内存、负载、网卡、磁盘、IO、应用服务、端口、登录用户、
LogFile=/tmp/zabbix_agentd.log
Server=192.168.149.128
ServerActive=192.168.149.128
Hostname = 192.168.149.129
同时cp zabbix_agentd启动脚本至/etc/init.d/目录,启动zabbix_agentd服务即可, Zabbix_agentd默认监听端口为10050。
cd zabbix-3.2.6
cp misc/init.d/tru64/zabbix_agentd /etc/init.d/zabbix_agentd
chmod o+x /etc/init.d/zabbix_agentd
/etc/init.d/zabbix_agentd start
(7)Zabbix监控客户端
Zabbix服务端和客户端安装完毕之后,需通过Zabbix Server添加客户端监控,Zabbix WEB界面添加客户端监控的操作步骤如下,如图13-11所示:
Zabbix-WEB configuration hosts Create host Host name和Agent interfaces,同时选择添加templates模板选择Add 勾选Template OS Linux-选择Add提交;
此处Host name名称与Agentd.conf配置文件中Hostname保持一致,否则会报错。

图13-11 Zabbix 添加客户端监控
将客户端主机链接至“Template OS Linux”,启用模板完成主机默认监控,单击Add
,继续单击Update即可,如图13-12所示:

图13-12 Zabbix 为客户端监控添加模板
单击Zabbix WEBMonitoringGraphsGroupHostGraph,监控图像如图13-13(a)、13-13(b)所示:

图13-13(a) Zabbix客户端监控图像

图13-13(b) Zabbix客户端监控图像
如果无法监控到客户端,可以在Zabbix Server端,执行命令获取Agent的items KEY值是否有返回,例如system.uname为返回客户端的uname信息,监测命令如下:
/usr/local/zabbix/bin/zabbix_get -s 192.168.149.130 -k system.uname
13.6 Zabbix配置文件详解
Zabbix监控系统组件分为Server、Proxy、Agentd端,对参数的详细了解,能够更加深入理解Zabbix监控功能,及对Zabbix进行调优,如下为三个组件常用参数详解:
(1)Zabbix_server.conf配置文件参数详解:
DBHost 数据库主机地址;
DBName 数据库名称;
DBPassword 数据库密码;
DBPort 数据库端口,默认为3306;
AlertScriptsPath 告警脚本存放路径;
CacheSize 存储监控数据的缓存;
CacheUpdateFrequency 更新一次缓存时间;
DebugLevel 日志级别;
LogFile 日志文件;
LogFileSize 日志文件大小,超过自动切割;
LogSlowQueries 数据库慢查询记录,单位毫秒;
PidFile PID文件;
ProxyConfigFrequency Proxy被动模式下,Server多少秒同步配置文件至proxy;
ProxyDataFrequency 被动模式下,Server间隔多少秒向proxy请求历史数据;
StartDiscoverers 发现规则线程数;
Timeout 连接Agent超时时间;
TrendCacheSize 历史数据缓存大小;
User Zabbix运行的用户;
HistoryCacheSize 历史记录缓存大小;
ListenIP 监听本机的IP地址;
ListenPort 监听端口;
LoadModule 模块名称;
LoadModulePath 模块路径。
(2)Zabbix_Proxy.conf配置文件参数详解:
ProxyMode Proxy工作模式,默认为主动模式,主动发送数据至Server;
Server 指定Server端地址;
ServerPort Server端PORT;
Hostname Proxy端主机名;
ListenPort Proxy端监听端口;
LogFile Proxy代理端日志路径;
PidFile PID文件的路径;
DBHost Proxy端数据库主机名;
DBName Proxy端数据库名称;
DBUser Proxy端数据库用户;
DBPassword Proxy端数据库密码;
DBSocket Proxy数据库SOCKET路径;
DBPort Proxy数据库端口号;
DataSenderFrequency Proxy向Server发送数据的时间间隔;
StartPollers Proxy程池数量;
StartDiscoverers Proxy端自动发现主机的线程数量;
CacheSize 内存缓存配置;
StartDBSyncers 同步数据线程数;
HistoryCacheSize 历史数据缓存大小;
LogSlowQueries 慢查询日志记录,单位为毫秒;
Timeout 超时时间。
(3)Zabbix_agentd.conf配置文件参数详解:
EnableRemoteCommands 运行服务端远程至客户端执行命令或者脚本;
Hostname 客户端主机名;
ListenIP 监听的IP地址;
ListenPort 客户端监听端口;
LoadModulePath 模块路径;
LogFile 日志文件路径;
PidFile PID文件名;
Server 指定Server IP地址;
ServerActive Zabbix主动监控server的ip地址;
StartAgents Agent启动进程,如果设置为0,表示禁用被动监控;
Timeout 超时时间
User 运行Zabbix的用户;
UserParameter 用户自定义key;
BufferSize 缓冲区大小;
DebugLevel Zabbix日志级别。

13.7 Zabbix自动发现及注册
熟练通过Zabbix监控平台监控单台客户端之后,企业中有成千上万台服务器,如果手工添加会非常耗时间,造成大量的人力成本的浪费,有没有什么好的自动化添加客户端的方法呢?
Zabbix自动发现就是为了解决批量监控而设计的功能之一,什么是自动发现呢,简单来说就是Zabbix Server端可以基于设定的规则,自动批量的去发现局域网若干服务器,并自动把服务器添加至Zabbix监控平台,省去人工手动频繁的添加,节省大量的人力成本。
Zabbix相对于Nagios、Cacti监控来说,如果要想批量监控,Nagios、Cacti需要手动单个添加设备、分组、项目、图像,也可以使用脚本,但是不能实现自发方式添加。
Zabbix最大的特点之一就是可以批量自动主机并监控,利用发现(Discovery)模块,实现自动发现主机、自动将主机添加到主机组、自动加载模板、自动创建项目(Items)、自动创建监控图像,操作步骤如下:
(1)Configurationdiscovery Create discovery rule,如图13-14所示:

图13-14 创建客户端发现规则
Name: 规则名称;
Discovery by proxy : 通过代理探索;
IP range : zabbix_server 探索区域的IP范围;
Delay : 搜索一次的时间间隔;
Checks : 检测方式,如用ping方式去发现主机,zabbix_server需安装fping,此处使用Agent方式发现;
Device uniqueness criteria: 以IP地址作为被发现主机的标识。
(2)Zabbix客户端安装Agent
由于发现规则里选择checks方式为Agent,所以需在所有被监控的服务器安装zabbix Agent,安装的方法可以手动安装,也可以使用Shell脚本,附Zabbix客户端安装脚本,脚本运行方法:sh auto_install_zabbix.sh。

!/bin/bash

auto install zabbix

by jfedu.net 2017

#############
ZABBIX_SOFT="zabbix-3.2.6.tar.gz"
INSTALL_DIR="/usr/local/zabbix/"
SERVER_IP="192.168.149.128"
IP=ifconfig|grep Bcast|awk '{print $2}'|sed 's/addr://g'
AGENT_INSTALL(){
yum -y install curl curl-devel net-snmp net-snmp-devel perl-DBI
groupadd zabbix ;useradd -g zabbix zabbix;usermod -s /sbin/nologin zabbix
tar -xzf $ZABBIX_SOFT;cd echo $ZABBIX_SOFT|sed 's/.tar.*//g'
./configure --prefix=/usr/local/zabbix --enable-agent&&make install
if [ $? -eq 0 ];then
ln -s /usr/local/zabbix/sbin/zabbix_* /usr/local/sbin/
fi
cd - ;cd zabbix-3.2.6
cp misc/init.d/tru64/zabbix_agentd /etc/init.d/zabbix_agentd ;chmod o+x /etc/init.d/zabbix_agentd

config zabbix agentd

cat >$INSTALL_DIR/etc/zabbix_agentd.conf<<EOF
LogFile=/tmp/zabbix_agentd.log
Server=$SERVER_IP
ServerActive=$SERVER_IP
Hostname = $IP
EOF

start zabbix agentd

/etc/init.d/zabbix_agentd restart
/etc/init.d/iptables stop
setenforce 0
}
AGENT_INSTALL
(3)创建发现Action
Zabbix发现规则创建完毕,客户端Agent安装完后,被发现的IP主机不会自动添加至Zabbix监控列表,需要添加发现动作,添加方法如下:
Configuration Actions Event source(选择Discovery) Create action
添加规则时,系统默认存在一条发现规则,可以新建规则,也可以编辑默认规则,如图13-15(a)、13-15(b)、13-15(c)所示,编辑默认发现规则,单击Operations设置发现操作,分别设置Add host、Add to host groups、Link to templates,最后启用规则即可:

图13-15(a) 创建客户端发现动作

图13-15(b) 客户端发现自动添加至Zabbix

图13-15(c) 客户端发现自动添加至Zabbix
MontoringDiscovery,查看通过发现规则找到的服务器IP列表,如图13-16所示:

图13-16 被发现的客户端列表
ConfigurationHosts,查看4台主机是否被自动监控至Zabbix监控平台,如图13-17所示:

图13-17 自动发现的主机被添加至Hosts列表
MonitoringGraphs,监控图像查看,如图13-18(a)、13-18(b)所示,可以选择Host、Graph分别查看各种的监控图像:
图13-18(a) 客户端监控图像

图13-18(b) 客户端监控图像
13.8 Zabbix邮件报警
Zabbix监控服务端、客户端都已经部署完成,被监控主机已经添加,Zabiix监控运行正常,通过查看Zabbix监控服务器,可以了解服务器的运行状态是否正常,运维人员不会时刻登录Zabbix监控平台刷新,查看服务器的状态。
可以在Zabbix服务端设置邮件报警,当被监控主机宕机或者达到设定的触发器预设值时,不管任何时候,会自动发送报警邮件、微信信息到指定的人员,运维人员收到信息有利于第一时间解决故障。Zabbix邮件报警设置步骤如下:
(1)设置邮件模板及邮件服务器
AdministrationMedia typesCreate media type,填写邮件服务器信息,根据提示设置完毕,如图13-19(a)、13-19(b)所示:

图13-19(a) Zabbix邮件报警邮箱设置

图13-19(b) Zabbix邮件报警邮箱设置
(2)配置接收报警的邮箱
Administration-user-Admin (Zabbix Administrator)-user-admin,选择Media,单击Add添加发送邮件的类型“Email”,同时指定接收邮箱地址:wgkgood@163.com,根据实际需求改成自己的接收人,如图13-20所示:

图13-20 Zabbix邮件报警添加接收人
(3)添加报警触发器
ConfigurationActionsAction Event sourceTriggers-Create Action,如图13-21(a)、13-21(b)、13-21(c)所示,分别设置Action、Operations、Recovery operations。
ActionNew condition选择“Trigger serverity>=Warning”;
Operations设置报警间隔为60s,自定义报警信息,报警信息发送至administrators组;
Recovery operations 自定义恢复信息,恢复信息发送至administrators组。

图13-21(a) 邮件报警Action设置

图13-21(b) 邮件报警Operations设置

图13-21(c) 邮件报警Recovery Operations设置
报警邮件标题可以使用默认信息,亦可使用如下中文报警内容:
名称:Action-Email
默认标题:故障{TRIGGER.STATUS},服务器:{HOSTNAME1}发生: {TRIGGER.NAME}故障!
默认信息:
告警主机:{HOSTNAME1}
告警时间:{EVENT.DATE} {EVENT.TIME}
告警等级:{TRIGGER.SEVERITY}
告警信息: {TRIGGER.NAME}
告警项目:{TRIGGER.KEY1}
问题详情:{ITEM.NAME}:{ITEM.VALUE}
当前状态:{TRIGGER.STATUS}:{ITEM.VALUE1}
事件ID:{EVENT.ID}
恢复邮件标题可以使用默认信息,亦可使用如下中文报警恢复内容:
恢复标题:恢复{TRIGGER.STATUS}, 服务器:{HOSTNAME1}: {TRIGGER.NAME}已恢复!
恢复信息:
告警主机:{HOSTNAME1}
告警时间:{EVENT.DATE} {EVENT.TIME}
告警等级:{TRIGGER.SEVERITY}
告警信息: {TRIGGER.NAME}
告警项目:{TRIGGER.KEY1}
问题详情:{ITEM.NAME}:{ITEM.VALUE}
当前状态:{TRIGGER.STATUS}:{ITEM.VALUE1}
事件ID:{EVENT.ID}
MonitoringProblems,检查有问题的Action事件,单击Time下方时间,如图13-22(a)、13-22(b)所示,可以看到邮件是否执行成功或者失败:

图13-22(a) Zabbix查看有问题的事件

图13-22(b) Zabbix有问题的事件执行任务
Zabbix邮件发送失败,报错Support for SMTP authentication was not compiled in,原因是由于Zabbix CURL版本要求至少是7.20+版本,升级CURL,升级方法:
wget http://mirror.city-fan.org/ftp/contrib/yum-repo/city-fan.org-release-1-13.rhel6.noarch.rpm
rpm -ivh city-fan.org-release-1-13.rhel6.noarch.rpm
yum upgrade libcurl –y
curl -V
CURL升级完毕之后,测试邮件发送,还是报同样的错误,原因是因为需要重新将Zabbix_Server服务通过源码编译安装一遍,安装完zabbx_server,重启服务,乱码问题是由于数据库字符集需改成UTF-8格式,同时将数Zabbix库导出,然后修改latin1为utf8,再将SQL导入,重启Zabbix即可,最终如图13-23(a)、13-23(b)、13-23(c)所示:

图13-23(a) Zabbix事情发送邮件进程

图13-23(b) Zabbix监控故障item发送报警邮件

图13-23(c) Zabbix监控故障item恢复发送邮件
13.9 Zabbix监控MYSQL主从
Zabbix监控除了可以使用Agent监控客户端服务器状态、CPU、内存、硬盘、网卡流量,同时Zabbix还可以监控MySQL主从用、监控LAMP、Nginx WEB服务器等等,如下为Zabbix监控MYSQL 主从复制的步骤:
(1)在Zabbix Agent端/data/sh目录创建Shell脚本:mysql_ab_check.sh,写入如下代码:

!/bin/bash

/usr/local/mysql/bin/mysql -uroot -e 'show slave status\G' |grep -E "Slave_IO_Running|Slave_SQL_Running"|awk '{print $2}'|grep -c Yes
(2)在客户端Zabbix_agentd.conf配置文件中加入如下代码:
UserParameter=mysql.replication,sh /data/sh/mysql_ab_check.sh
(3)Zabbix服务器端获取监控数据,如果返回值为2,则证明丛库I/O、SQL线程均为YES,表示主从同步成功:
/usr/local/zabbix/bin/zabbix_get -s 192.168.149.129 -k mysql.replication
(4)Zabbix WEB平台,在192.168.149.129 hosts中创建item监控项,如图13-24(a)、13-24(b)所示,单击右上角create item,Key填写Zabbix Agentd配置文件中的mysql.replication即可:

图13-24(a) Zabbix添加MYSQL主从item

图13-24(b) Zabbix添加MYSQL主从item
MYSQL主从监控项创建Graph图像,如图13-25(a)、13-25(b)所示:

图13-25(a) 创建MYSQL主从监控图像
图13-25(b) 创建MYSQL主从监控图像
MYSQL主从监控项创建触发器,如图13-26(a)、13-26(b)所示,MYSQL主从状态监控,设置触发器条件为key值不等于2即可,不等于2即表示MYSQL主从同步状态异常,匹配触发器,执行Actions:
图13-26(a) 创建MYSQL主从监控触发器

图13-26(b) 创建MYSQL主从监控触发器
如果主从同步状态异常,Key值不等于2,会触发邮件报警,报警信息如图13-27所示:

图13-27 MYSQL主从监控报警邮件
13.10 Zabbix日常问题汇总
Zabbix 可以设置中文汉化,如果出现乱码解决办法,如果访问zabbix出现如下历史记录乱码, WEB界面乱码,原因是因为数据库导入前不是UTF-8字符集,需要修改为UTF-8模式,如图13-28所示:
图13-28 数据库原字符集latin1
MYSQL数据库修改字符集方法,vim /etc/my.cnf在配置段加入如下代码:
[mysqld]
character-set-server= utf8
[client]
default-character-set = utf8
[mysql]
default-character-set = utf8
备份zabbix数据库,并删除原数据库,重新创建,再导入备份的数据库,修改导入的zabbix.sql文件里面的latin1为utf8,然后再导入到zabbix库,乱码问题解决。
sed -i 's/latin1/utf8/g' zabbix.sql
如果在查看graphs监控图像界面的时候时候出现乱码,如图13-29所示:

图13-29 Graphs图像乱码
从windows下控制面板->字体->选择一种中文字库,例如“楷体”,如图13-30所示:

图13-30 上传Windows简体中文字体
将字体文件cp至zabbix服务dauntfonts目录下,/var/www/html/zabbix/fonts,并且将STKAITI.TTF重命名为DejaVuSans.ttf,最好刷新Graph图像,乱码问题解决,如图13-31(a)、13-31(b)所示:

图13-31(a) 上传Windows简体中文字体

图13-31(b) Graph图像乱码问题解决
13.11 Zabbix触发命令及脚本
Zabbix监控在对服务或者设备进行监控的时候,如果被监控客户端服务异常,满足触发器,默认可以发送邮件报警、短信报警及微信报警。Zabbix还可以远程执行命令或者脚本对部分故障实现自动修复。具体可以执行的任务包括:
重启应用程序,例如Apache、Nginx、MySQL、Tomcat服务等;
通过IPMI接口重启服务器;
删除服务器磁盘空间及数据;
执行脚本及资源调度管理;
远程命令最大长度为255字符;
同时支持多个远程命令;
Zabbix代理不支持远程命令。
使用Zabbix远程执行命令,首先需在zabbix客户端配置文件开启对远程命令的支持,在zabbix_agentd.conf行尾加入如下代码,并重启服务,如图13-32所示:
EnableRemoteCommands = 1

图13-32 客户端配置远程命令支持
创建Action,ConfigurationActionsTriggers,如图13-33(a)、13-33(b)所示,类型选择“Remote Command”,steps表示执行命令1-3次, step duration设置每次命令间隔时间的5秒执行一次,执行命令方式选择Zabbix agent,基于sudo执行命令即可:

图13-33(a) 客户端触发器满足条件

图13-33(b) Operations类型选择Remote Command
Zabbix客户端Sudoer配置文件中添加zabbix用户拥有执行权限且无需密码登录:
Defaults:zabbix !requiretty
zabbix ALL=(ALL) NOPASSWD: ALL
Zabbix客户端/data/sh/,创建auto_clean_disk.sh,脚本代码如下:

!/bin/bash

auto clean disk space

2017年6月21日10:12:18

by author jfedu.net

rm -rf /boot/test.img
find /boot/ -name "*.log" -size +100M -exec rm -rf {} \;
将192.168.149.129服务器/boot目录,临时写满,然后满足触发器,实现远程命令执行,查看问题事件命令执行结果,如图13-34(a)、13-34(b)所示:

图13-34(a) Remote Command执行成功

图13-34(b) Remote Command执行磁盘清理成功
如果Zabbix客户端脚本或者命令没有执行成功,http服务没有停止,可以在Zabbix server端执行如下命令,如图13-35所示:
/usr/local/zabbix/bin/zabbix_get -s 192.168.149.129 -k "system.run[sudo /etc/init.d/httpd restart]"

图13-35 测试Remote Command命令
13.12 Zabbix分布式配置
Zabbix是一个分布式监控系统,它可以以一个中心点、多个分节点的模式运行,使用Proxy能大大的降低Zabbix Server的压力,Zabbix Proxy可以运行在独立的服务器上,如图13-36所示:

图13-36 Zabbix Proxy网络拓扑图
安装Zabbix Proxy,基于Zabbix-3.2.6.tar.gz软件包,同时需要导入zabbix基本框架库,具体实现方法如下:
(1)下载Zabbix软件包,代码如下:
wget  http://sourceforge.net/projects/zabbix/files/ZABBIX%20Latest%20Stable/3.2.6/zabbix-3.2.6.tar.gz/download
(2)Zabbix Proxy上执行如下代码:
yum -y install curl curl-devel net-snmp net-snmp-devel perl-DBI
groupadd zabbix ;useradd -g zabbix zabbix;usermod -s /sbin/nologin zabbix
(3)Zabbix Proxy端配置
创建zabbix数据库,执行授权命令:
create database zabbix_proxy charset=utf8;
grant all on zabbix_proxy. to zabbix@localhost identified by '123456';
flush privileges;
解压zabbix软件包并将Zabbix基础SQL文件导入数据至Zabbix数据库:
tar zxvf zabbix-3.2.6.tar.gz
cd zabbix-3.2.6
mysql -uzabbix -p123456 zabbix_proxy <database/mysql/schema.sql
mysql -uzabbix -p123456 zabbix_proxy <database/mysql/images.sql
切换至Zabbix解压目录,执行如下代码,安装Zabbixserver:
./configure --prefix=/usr/local/zabbix/ --enable-proxy --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl
make
make install
ln -s /usr/local/zabbix/sbin/zabbix
/usr/local/sbin/
Zabbix Proxy安装完毕,cd /usr/local/zabbix/etc/目录,如图13-37所示:
图13-37 Zabbix Proxy安装目录
(4)备份Zabbix Proxy配置文件,代码如下:
cp zabbix_proxy.conf zabbix_proxy.conf.bak
(5)将zabbix_proxy.conf配置文件中代码设置为如下:
Server=192.168.149.128
Hostname=192.168.149.130
LogFile=/tmp/zabbix_proxy.log
DBName=zabbix_proxy
DBUser=zabbix
DBPassword=123456
Timeout=4
LogSlowQueries=3000
DataSenderFrequency=30
HistoryCacheSize=128M
CacheSize=128M
(6)Zabbix客户端安装Agent,同时配置Agent端Server设置为Proxy服务器的IP地址或者主机名,zabbix_agentd.conf配置文件代码:
LogFile=/tmp/zabbix_agentd.log
Server=192.168.149.130
ServerActive=192.168.149.130
Hostname = 192.168.149.131
(7)Zabbix Server WEB端添加Proxy,实现集中管理和分布式添加监控,如图13-38(a)、13-38(b)、13-38(c)所示:

图13-38(a) Zabbix Proxy WEB添加

图13-38(b) Zabbix Proxy监控客户端

图13-38(c) Zabbix Proxy监控客户端图像
13.13 Zabbix微信报警
Zabbix除了可以使用邮件报警之外,还可以通过多种方式把告警信息发送到指定人,例如短信报警方式,越来越多的企业开始使用Zabbix结合微信作为主要的告警方式,因为每个人每天都在使用微信,这样可以及时有效的把告警信息推送到接收人,方便告警的及时处理。Zabbix微信报警怎么设置呢,设置的步骤有哪些呢,方法步骤如下:
(1)微信企业号注册
企业号注册地址:https://qy.weixin.qq.com/填写企业注册信息,等待审核完,并且微信扫描登录企业公众号,如图13-39(a)、13-39(b)所示

图13-39(a) 微信企业公众号注册
图13-39(b) 微信企业公众号登录
(2)通讯录添加运维部门及人员
登录新建的企业号,通过提前把企业成员信息添加到组织或者部门,需要填写手机号、微信号或邮箱,通过这样方式让别人扫码关注企业公众号,为了后面企业号推送消息给企业成员,如图13-40(a)、13-40(b)所示:
图13-40(a) 微信企业公众号通讯录图13-40(b) 微信企业公众号通讯录
(3)企业应用-创建应用
除了对个人添加微信报警之外,还可以添加不同管理组,接受同一个应用推送的消息,
成员账号,组织部门ID,应用Agent ID,CorpID和Secret,调用API接口需要用到这些信息,如图13-41(a)、13-41(b)、13-41(c)所示:
图13-41(a) 微信企业公众号创建应用图13-41(b) 微信企业公众号创建应用图13-41(c) 微信企业公众号创建应用
(4)获取企业CorpID,单击企业公众号首页“我的企业”,即可看到,如图13-42所示:

图13-42 微信企业公众号CorpID
(5)微信接口调试,调用微信接口需要一个调用接口的凭证:Access_token通过CorpID和Secret可以获得Access_token,微信企业号接口调试地址: http://qydev.weixin.qq.com/debug,如图 13-43(a)、13-43(b)所示:

图13-43(a) 微信企业公众号调试

图13-43(b) 微信企业公众号调试
(6)获取微信报警工具
mkdir –p /usr/local/zabbix/alertscripts
cd /usr/local/zabbix/alertscripts
wget http://dl.cactifans.org/tools/zabbix_weixin.x86_64.tar.gz
tar zxvf zabbix_weixin.x86_64.tar.gz
mv zabbix_weixin/weixin .
chmod o+x weixin
mv zabbix_weixin/weixincfg.json /etc/
rm -rf zxvf zabbix_weixin.x86_64.tar.gz
rm -rf zabbix_weixin/
修改/etc/ weixincfg.json配置文件中corpid、secret、agentid,并测试脚本发送信息,如图13-44(a)、13-44(b)所示:
cd /usr/local/zabbix/alertscripts
./weixin wuguangke 京峰教育报警测试 Zabbix故障报警
./weixin contact subject body
标准信息格式:
Contact,为你的微信账号,注意不是微信号,不是微信昵称,可以把用户账号设置成微信号或微信昵称,Subject 告警主题,Body 告警详情。

图13-44(a) Zabbix Server端微信配置文件

图13-44(b) Zabbix Server端微信配置文件
(7)脚本调用设置
Zabbix_Server端设置脚本执行路径,编辑zabbix_server.conf文件,添加如下内容:
AlertScriptsPath=/usr/local/zabbix/alertscripts
(8)Zabbix WEB端配置,设置Actions动作,并设置触发微信报警,如图13-45(a)、13-45(b)、13-45(c)所示:

图13-45(a) Zabbix Server Action动作配置
图13-45(b) Zabbix Server Action动作配置
图13-45(c) Zabbix Server Action动作配置
(9)配置Media Type 微信脚本,AdministrationMedia TypesCreate Media Type如图13-46所示,脚本加入三个参数:{ALERT.SENDTO}、{ALERT.SUBJECT}、{ALERT.MESSAGE}:

图13-46 Zabbix Server Media Types配置
(10)配置接收微信信息的用户,AdministrationUsersAdminMedia如图13-47所示:

图13-47 Zabbix Server Users Media
(11)微信报警信息测试,磁盘容量剩余不足20%,会触发微信报警,如图13-48(a)、13-48(b)、13-48(c)所示:

图13-48(a)Zabbix 微信报警信息
图13-48(b)Zabbix 微信报警故障信息

图13-48(c)Zabbix 微信报警恢复信息
13.14 Zabbix监控网站关键词
随着公司网站系统越来越多,不能通过人工每天手动去刷新网站来检查网站代码及页面是否被传该,通过zabbix监控可以实现自动去检查WEB网站是否被串改,例如监控某个客户端网站页面中关键词“ATM”是否被修改,通过脚本监控的方法如下:
(1)Agent端编写Shell脚本监控网站关键词,/data/sh/目录Shell脚本内容如下,如图13-49所示:

!/bin/bash

2017年5月24日09:49:48

by author jfedu.net

###################
WEBSITE="http://192.168.149.131/"
NUM=curl -s $WEBSITE|grep -c "ATM"
echo $NUM
图13-49 Zabbix 客户端脚本内容
(2)客户端Zabbix_agentd.conf内容中加入如下代码,并重启Agentd服务即可,如图13-50所示:
UserParameter=check_http_word,sh /data/sh/check_http_word.sh

图13-50 Zabbix 客户端脚本执行结果
(3)服务器端获取客户端的关键词KEY,输入1,则表示ATM关键词存在,如果不为1则表示ATM关键词被串改。
/usr/local/zabbix/bin/zabbix_get -s 192.168.149.131 -k check_http_word
(4)Zabbix WEB端添加客户端的items监控项,如图13-51所示:

图13-51 Zabbix 客户端KEY添加
(5)创建check_http_word监控Graphs图像,如图13-52(a)、13-52(b)所示:

图13-52(a) Zabbix 客户端添加Graphs
图13-52(b) Zabbix 客户端添加Graphs
(6)创建check_http_word触发器,如图13-53(a)、13-53(b)所示:
图13-53(a) Zabbix 客户端创建触发器

图13-53(b) Zabbix 客户端创建触发器
(7)查看Zabbix客户端监控图像,如图13-54(a)、13-54(b)所示:

图13-54(a) Zabbix Http word monitor监控图

图13-55(b) Zabbix Http word monitor触发器微信报警
除了使用如上Shell脚本方法,还可以通过Zabbix WEB界面配置Http URL监控,方法如下:
(1)ConfigurationHostsWEB,创建WEB监控场景,基于Chrome38.0访问HTTP WEB页面,如图13-55(a)、13-55(b)、13-55(c)、13-55(d)、13-55(e)所示:

图13-55(a)Zabbix WEB场景配置

图13-55(b)Zabbix WEB场景配置

图13-55(c)Zabbix WEB场景配置

图13-55(d)Zabbix WEB监控图

图13-55(e)Zabbix WEB监控图
第14章 Nginx WEB服务器企业实战
万维网 (WORLD WIDE WEB,WWW)服务器,也称之为WEB服务器,主要功能是提供网上信息浏览服务。目前主流的WEB服务器软件包括:Apache、Nginx、Lighttpd、IIS、Resin、Tomcat、WebLogic、Jetty。
本章向读者介绍Nginx高性能WEB服务器、Nginx工作原理、安装配置及升级、Nginx配置文件深入剖析、Nginx虚拟主机、Location案例演示、Nginx Rewirte企业案例实战、HTTPS安全WEB服务器及Nginx高性能集群实战等。
14.1 Nginx WEB入门简介
Nginx ("engine x") 是一个高性能HTTP 和 反向代理 服务器、IMAP、POP3、SMTP 服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。
由于Nginx的高性能、轻量级,目前越来越多的互联网企业开始使用Nginx WEB服务器。据Netcraft统计,在2017年4月份,世界上最繁忙的网站中有28.72 %使用Nginx作为其服务器或者代理服务器。
nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev.
For a long time, it has been running on many heavily loaded Russian sites including Yandex, Mail.Ru, VK, and Rambler.
According to Netcraft, nginx served or proxied 28.72% busiest sites in April 2017. Here are some of the success stories: Netflix,Wordpress.com, FastMail.FM.
The sources and documentation are distributed under the 2-clause BSD-like license.
Commercial support is available from Nginx, Inc.
它已经在众多流量很大的俄罗斯网站上使用了很长时间,这些网站包括Yandex、Mail.Ru、VKontakte,以及Rambler。目前互联网主流公司京东、360、百度、新浪、腾讯、阿里都在使用Nginx作为自己的WEB服务器。
Nginx特点是占有内存少,并发能力强,事实上Nginx的并发能力确实在同类型的网页服务器中表现较好。
Nginx相对于Apache优点如下:
高并发响应性能非常好,官方Nginx处理静态文件并发5w/s;
负载均衡及反向代理性能非常强;
系统内存和CPU占用率低;
可对后端服务进行健康检查;
支持PHP cgi方式和FastCGI方式;
可以作为缓存服务器、邮件代理服务器;
配置代码简洁且容易上手。
14.2 Nginx工作原理
Nginx WEB服务器最主要就是各种模块的工作,模块从结构上分为核心模块、基础模块和第三方模块,其中三类模块分别如下:
核心模块:HTTP模块、EVENT模块和MAIL模块等;
基础模块:HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块;
第三方模块:HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块、Limit_req模块等;
Nginx的模块从功能上分为如下三类。
Handlers(处理器模块):此类模块直接处理请求,并进行输出内容和修改headers信息等操作,Handlers处理器模块一般只能有一个;
Filters (过滤器模块):此类模块主要对其他处理器模块输出的内容进行修改操作,最后由Nginx输出;
Proxies (代理类模块):此类模块是Nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务比如FastCGI等进行交互,实现服务代理和负载均衡等功能。
Nginx由内核和模块组成,其中内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端的请求映射到一个location block,而location是Nginx配置中的一个指令,用于访问的URL匹配,而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作,如图14-1所示:
图14-1 Nginx WEB工作流程图
Nginx的高并发得益于其采用了epoll模型,与传统的服务器程序架构不同,epoll是Linux内核2.6以后才出现的,Nginx采用epoll模型,异步非阻塞,而apache采用的是select模型:
Select特点:select 选择句柄的时候,是遍历所有句柄,也就是说句柄有事件响应时,select需要遍历所有句柄才能获取到哪些句柄有事件通知,因此效率是非常低。
epoll的特点:epoll对于句柄事件的选择不是遍历的,是事件响应的,就是句柄上事件来就马上选择出来,不需要遍历整个句柄链表,因此效率非常高。
Nginx默认以80端口监听在服务器上,并且启动一个master进程,同时有master进程生成多个工作进程,当浏览器发起一个HTTP连接请求,每个进程都有可能处理这个连接,怎么做到的呢?怎么保证同一时刻一个HTTP请求被一个工作进程处理呢。
首先每个worker进程都是从Master进程fork出来,在Master进程里面,建立好需要listen的socket(listenfd)之后,会fork出多个worker进程。
所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。
当一个worker进程在accept这个连接之后,就开始读取请求、解析请求、处理请求,产生数据后,再返回给客户端,最后才断开连接,这样形成一个完整的请求流程。如图14-2所示:
图14-2 Nginx Worker进程工作原理
14.3 Nginx安装配置
Nginx WEB安装时可以指定很多的模块,默认需要安装Rewrite模块,也即是需要系统有PCRE库,安装Pcre支持Rewrite功能。如下为安装Nginx WEB服务器方法:
源码的路径,而不是编译后的路径,否则会报错。

安装PCRE库支持

yum install pcre-devel pcre -y

下载Nginx源码包

cd /usr/src
wget -c http://nginx.org/download/nginx-1.12.0.tar.gz

解压Nginx源码包

tar -xzf nginx-1.12.0.tar.gz

进入解压目录,然后sed修改Nginx版本信息为JWS

cd nginx-1.12.0 ; sed -i -e 's/1.12.0//g' -e 's/nginx\//JWS/g' -e
's/"NGINX"/"JWS"/g' src/core/nginx.h

预编译Nginx

useradd www ;./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module

.configure预编译成功后,执行make命令进行编译

make

make执行成功后,执行make install 正式安装

make install

至此Nginx WEB服务器安装完毕。

测试Nginx服务安装是否正确,同时启动Nginx WEB 服务,代码命令如下:
/usr/local/nginx/sbin/nginx -t 检查nginx配置文件是否正确,返回OK即正确。
[root@localhost ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@localhost ~]#
然后启动nginx,/usr/local/nginx/sbin/nginx 回车即可。查看进程是否已启动:
[root@localhost ~]# ps -ef |grep nginx
nobody 5381 30285 0 May16 ? 09:04:31 nginx: worker process
root 30285 1 0 2017 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
root 32260 32220 0 12:34 pts/0 00:00:00 grep nginx
[root@localhost ~]#
通过浏览器访问Nginx默认测试页面,如图14-3所示:
图14-3 Nginx WEB浏览器访问
14.4 Nginx管理及升级
Nginx WEB服务器安装完毕,可以执行如下命令对其进管理和维护,命令如下:

查看nginx进程

ps -ef|grep nginx

平滑启动nginx

kill -HUP cat /var/run/nginx.pid
或者
nginx -s reload
其中进程文件路径在配置文件nginx.conf中可以找到。
平滑启动的意思是在不停止nginx的情况下,重启nginx,重新加载配置文件,启动新的工作线程,完美停止旧的工作线程。

完美停止nginx

kill -QUIT cat /var/run/nginx.pid

快速停止nginx

kill -TERM cat /var/run/nginx.pid
或者
kill -INT cat /var/run/nginx.pid

完美停止工作进程(主要用于平滑升级)

kill -WINCH cat /var/run/nginx.pid

强制停止nginx

pkill -9 nginx

检查对nginx.conf文件的修改是否正确

nginx -t -c /etc/nginx/nginx.conf 或者 nginx -t

停止nginx的命令

nginx -s stop或者pkill nginx

查看nginx的版本信息

nginx -v

查看完整的nginx的配置信息

nginx -V
Nginx WEB服务器定期更新,如果需要将低版本升级或者将高版本降级,升级或者降级方法如下,分为四个步骤,包括软件下载、预编译、编译、配置,具体方法如下:
wget http://www.nginx.org/download/nginx-1.4.2.tar.gz
获取旧版本nginx的configure选项
/usr/local/nginx/sbin/nginx -V
编译新版本的Nginx
tar -xvf nginx-1.4.2.tar.gz
cd nginx-1.4.2
./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_ssl_module
make
备份旧版本的nginx可执行文件,复制新版本的nginx这行文件
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
cp objs/nginx /usr/local/nginx/sbin/
测试新版本nginx是否正常
/usr/local/nginx/sbin/nginx -t
平滑重启升级nginx
kill –QUIT cat /usr/local/nginx/log/nginx.oldbin ##关闭旧版nginx
验证nginx是否升级成功
/usr/local/nginx/sbin/nginx -V显示最新编译的版本信息即可。
14.5 Nginx配置文件优化一
学习Nginx服务的难点在于对配置文件的理解和优化,熟练掌握Nginx配置文件参数的含义可以更快的掌握Nginx,如下为Nginx.conf配置文件常用参数详解:

定义Nginx运行的用户和用户组

user www www;

启动进程,通常设置成和cpu的数量相等

worker_processes 8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

为每个进程分配cpu,上例中将8个进程分配到8个cpu,当然可以写多个,或者将一个进程分配到多个cpu。

worker_rlimit_nofile 102400;

该指令是当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀,所以最好与ulimit -n的值保持一致。

全局错误日志及PID文件

error_log /usr/local/nginx/logs/error.log;

错误日志定义等级,[ debug | info | notice | warn | error | crit ]

pid /usr/local/nginx/nginx.pid;

工作模式及连接数上限

events {
use epoll;

epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能.

worker_connections 102400;

单个后台worker process进程的最大并发链接数 (最大连接数=连接数*进程数)

multi_accept on;

尽可能多的接受请求.

}

设定http服务器,利用它的反向代理功能提供负载均衡支持

http {

设定mime类型,类型由mime.type文件定义

include mime.types;
default_type application/octet-stream;

设定日志格式

access_log /usr/local/nginx/log/nginx/access.log;
sendfile on;

sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用必须设为 on

如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime。

autoindex on;

开启目录列表访问,合适下载服务器,默认关闭。

tcp_nopush on;

防止网络阻塞

keepalive_timeout 60;

keepalive超时时间,客户端到服务器端的连接持续有效时间,当出现对服务器的后继请求时,keepalive-timeout功能可避免建立或重新建立连接。

tcp_nodelay on;

提高数据的实时响应性

开启gzip压缩

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;

压缩级别大小,最大为9,值越小,压缩后比例越小,CPU处理更快。

值越大,消耗CPU比较高。

gzip_types text/plain application/x-javascript text/css application/xml;
gzip_vary on;
client_max_body_size 10m;

允许客户端请求的最大单文件字节数

client_body_buffer_size 128k;

缓冲区代理缓冲用户端请求的最大字节数.

proxy_connect_timeout 90;

nginx跟后端服务器连接超时时间(代理连接超时)

proxy_send_timeout 90;

后端服务器数据回传时间(代理发送超时)

proxy_read_timeout 90;

连接成功后,后端服务器响应时间(代理接收超时)

proxy_buffer_size 4k;

设置代理服务器(nginx)保存用户头信息的缓冲区大小

proxy_buffers 4 32k;

proxy_buffers缓冲区,网页平均在32k以下的话,这样设置

proxy_busy_buffers_size 64k;

高负荷下缓冲大小(proxy_buffers*2)

设定请求缓冲

large_client_header_buffers 4 4k;
client_header_buffer_size 4k;

客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求的头部大小不会超过1k

不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。

open_file_cache max=102400 inactive=20s;

这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。

open_file_cache_valid 30s;

这个是指多长时间检查一次缓存的有效信息。

open_file_cache_min_uses 1;

open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive

包含其它配置文件,如自定义的虚拟主机

include vhosts.conf;

14.6 Nginx配置文件优化二
Nginx WEB默认发布静态页面,也可以均衡后端动态网站,用户发起HTTP请求,如果请求静态页面,Nginx直接处理并返回,如果请求的是动态页面,Nginx收到请求之后会进行判断,转到后端服务器去处理。
Nginx实现负载均衡需要基于upstream模块,同时需要设置location proxy_pass转发指令实现。
如下为Ningx应用负载均衡集群配置,根据后端实际情况修改即可,jfedu_www为负载均衡模块的名称,可以任意指定,但必须跟vhosts.conf、Nginx.conf虚拟主机的proxy_pass段保持一致,否则不能将请求转发至后端的服务器,weight表示配置权重,在fail_timeout内检查max_fails次数,失败则剔除均衡。
upstream jfedu_www {
server 127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=30s;
server 127.0.0.1:8081 weight=1 max_fails=2 fail_timeout=30s;
}

虚拟主机配置

server {
    #侦听80端口
    listen       80;
    #定义使用www.jfedu.net访问
    server_name  www.jfedu.net;
    #设定本虚拟主机的访问日志
    access_log  logs/access.log  main;
        root   /data/webapps/www;  #定义服务器的默认网站根目录位置
    index index.php index.html index.htm;   #定义首页索引文件的名称
    #默认请求
    location ~ /{
      root   /data/webapps/www;      #定义服务器的默认网站根目录位置
      index index.php index.html index.htm;   #定义首页索引文件的名称
      #以下是一些反向代理的配置.
      proxy_next_upstream http_502 http_504 error timeout invalid_header;
      #如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。
      proxy_redirect off;
      #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_pass  http://jfedu_www;     #请求转向后端定义的均衡模块
   }
    # 定义错误提示页面
        error_page   500 502 503 504 /50x.html;  
        location = /50x.html {
        root   html;
    }
    #配置Nginx动静分离,定义的静态页面直接从Nginx发布目录读取。
    location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
    {
        root /data/webapps/www;
        #expires定义用户浏览器缓存的时间为3天,如果静态页面不常更新,可以设置更长,这样可以节省带宽和缓解服务器的压力,在浏览器保存该类型文件的天数。
        expires      3d;
    }
    #PHP脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
    location ~ \.php$ {
        root /root;
        FastCGI_pass 127.0.0.1:9000;
        FastCGI_index index.php;
        FastCGI_param SCRIPT_FILENAME /data/webapps/www$FastCGI_script_name;
        include FastCGI_params;
    }
    #设定查看Nginx状态的地址
    location /NginxStatus {
        stub_status  on;
    }
 }

}
通过Expires参数设置,可以使浏览器缓存过期时间,减少与服务器之前的请求和流量。具体Expires定义是给一个资源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可,所以不会产生额外的流量。
如果静态文件不常更新,Expires可以设置为30d,表示在这30天之内再次访问该静态文件,浏览器会发送一个HTTP请求,会比对服务器该文件最后更新时间是否有变化,如果没有变化,则不会从服务器抓取,返回HTTP状态码304,如果有修改,则直接从服务器重新下载,返回HTTP状态码200。
14.7 Nginx虚拟主机实战
在真实的企业服务器环境中,为了充分利用服务器的资源,单台Nginx WEB服务器同时会配置N个网站,也可称之为配置N个虚拟域名的主机,即多个域名对应同一个80端口。
在Nginx.conf中加入server代码,Nginx虚拟主机完整代码如下:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;

virtual hosts config 2017/5/18

server {
listen 80;
server_name www.jf1.com;
access_log logs/jf1.access.log;
location / {
root html/jf1;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.jf2.com;
access_log logs/jf2.access.log;
location / {
root html/jf2;
index index.html index.htm;
}

}
}
创建两个不同的目录mkdir –p /usr/local/nginx/html/{jf1,jf2},然后分别在两个目录创建两个不同的index.html网站页面即可。通过Windows客户端配置hosts绑定IP与两个域名的对应关系,在IE浏览器访问测试效果,如图14-4(a)、14-4(b)所示:

图14-4(a) Nginx 虚拟主机www.jf1.com

图14-4(b) Nginx 虚拟主机www.jf2.com
14.8 Nginx Location深入剖析
Nginx由内核和模块组成,其中内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端的请求映射到一个location block,而location是Nginx配置中的一个指令,用于访问的URL匹配,而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作。
默认Nginx.conf配置文件中至少存在一个location /,即表示客户端浏览器请求的URL为:域名+/,如果location /newindex/,则表示客户端浏览器请求的URL为:域名+/newindex/。常见Location匹配URL的方式如下:
= 字面精确匹配;
^~ 最大前缀匹配;
/ 不带任何前缀:最大前缀匹配;
~ 大小写相关的正则匹配;
~ 大小写无关的正则匹配;
@ location内部重定向的变量。
其中Location =、^~、/属于普通字符串匹配,Location ~、~
属于正则表达式匹配,Location优先级与其在Nginx.conf配置文件中的先后顺序无关。
Location = 精确匹配会第一个被处理,如果发现精确匹配,Nginx则停止搜索其他任何Location的匹配。
普通字符匹配,正则表达式规则和完整URL规则将被优先和查询匹配,^~为最大前缀匹配,如果匹配到该规则,Nginx则停止搜索其他任何Location的匹配,否则nginx会继续处理其他location指令。
正则匹配"~"和"~",如果找到相应的匹配,则Nginx停止搜索其他任何Location的匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。
Location规则匹配优先级总结如下:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~|~
正则顺序) > (location 部分起始路径) > (/)
如下为Nginx Location规则案例演示:
location = / {
[ configuration L1 ]

只会匹配/,优先级比Location /低。

}
location = /index.html {
[ configuration L2 ]

只会匹配/index.html,优先级最高。

}
location / {
[ configuration L3 ]

匹配任何请求,因为所有请求都是以"/"开始;

但是更长字符匹配或者正则表达式匹配会优先匹配,优先级最低。

}
location = /images/ {
[ configuration L4 ]

匹配任何以/images/开始的请求,并停止匹配其它location;

}
location ~* .(html|txt|gif|jpg|jpeg)$ {
[ configuration L5]

匹配以html、txt、gif、jpg、jpeg结尾的URL文件请求;

但是所有/images/目录的请求将由 [Configuration L4]处理。

}
浏览器发起HTTP Request URI案例与Location规则案例匹配如下:
/ ->匹配configuration L3;
/index.html匹配configuration L2;
/images/匹配configuration L4;
/images/logo.png匹配configuration L4;
/img/test.jpg匹配configuration L5。
企业生产环境中无需在Nginx.conf配置文件中同时添加五种规则匹配,如下为企业生产环境Nginx Location部分配置代码:
location /
{
root /var/www/html/;
expires 60d;
}
location ~ ..(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
{
root /var/www/html/;
expires 60d;
}
location ~ .
.(jsp|php|cgi|do)$
{
root /var/www/html/;
proxy_pass http://linux_web;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location =/newindex.html
{
root /var/www/newwww/;
expires 60d;
}
14.9 企业实战Nginx动静分离架构
Nginx动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用Nginx处理静态页面,Tomcat、Resin、PHP、ASP处理动态页面。
动静分离从目前实现角度来讲大致分为两种,一种是纯粹的把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案;另外一种方法就是动态跟静态文件混合在一起发布,通过Nginx来分开。
Nginx线上WEB服务器动静分离及Nginx.conf完整配置文件代码如下:
user www www;
worker_processes 8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
pid /usr/local/nginx/nginx.pid;
worker_rlimit_nofile 102400;
events
{
use epoll;
worker_connections 102400;
}
http
{
include mime.types;
default_type application/octet-stream;
FastCGI_intercept_errors on;
charset utf-8;
server_names_hash_bucket_size 128;
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;
client_max_body_size 300m;
sendfile on;
tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
client_body_buffer_size 512k;
proxy_connect_timeout 5;
proxy_read_timeout 60;
proxy_send_timeout 5;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml;
gzip_vary on;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
upstream jvm_web1 {
server 192.168.149.130:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.149.130:8081 weight=1 max_fails=2 fail_timeout=30s;
}
include vhosts.conf;
}
如下为vhosts.conf配置文件中内容:
server
{
listen 80;
server_name www.jf1.com;
index index.jsp index.html index.htm;
root /data/webapps/www1;
location /
{
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://jvm_web1
}
location ~ ..(php|jsp|cgi|shtml)?$
{
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://jvm_web1
}
location ~ .
.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
{
root /data/webapps/www1;
expires 30d;
}
access_log /data/logs/jvm_web1/access.log main;
error_log /data/logs/jvm_web1/error.log crit;
}

配置文件代码中:location ~ ..(php|jsp|cgi|shtml)表示匹配动态页面请求,然后将请求proxy_pass到后端服务器,而location ~ ..(html|htm|gif|jpg|jpeg |ico|txt|js|css)表示匹配静态页面请求本地返回。
检查Nginx配置是否正确即可,然后测试动静分离是否成功,在192.168.149.130服务器启动8080、8081 Tomcat服务或者LAMP服务,删除后端Tomcat或者LAMP服务器上的某个静态文件,测试是否能访问该文件,如果可以访问说明静态资源Nginx直接返回了,如果不能访问,则证明动静分离不成功。
14.10 企业实战LNMP高性能服务器
公共网关接口”(Common Gateway Interface,CGI),是HTTP服务器与本机或者其它机器上的程序进行通信的一种工具,其程序须运行在网络服务器上。
CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量,如php、perl、tcl等。
FAST-CGI:WEB服务器与处理程序之间通信的一种协议(App server 和Web server 之间的通信协议),是CGI的改进方案。CGI程序反复加载是CGI性能低下的主要原因,如果CGI程序保持在内存中并接受FastCGI进程管理器调度,则可以提供良好的性能、伸缩性、Fail-Over特性等。FastCGI是常驻型的CGI,它可以一直运行,在请求到达时,不会花费时间去fork一个进程来处理。
FastCGI是语言无关的、可伸缩架构的CGI开放扩展,将CGI解释器进程保持在内存中,以此获得较高的性能。FastCGI是一个协议,php-fpm实现了这个协议,php-fpm的FastCGI协议需要有进程池,php-fpm实现的FastCGI进程叫php-cgi,所以php-fpm其实是他自身的FastCGI或php-cgi进程管理器,如图14-5所示:
图14-5 Nginx+FastCGI通信原理图
企业级LNMP(Nginx+PHP(FastCGI)+MySQL)主流架构配置方法如下,分别安装Nginx、MYSQL、PHP服务,步骤如下:
(1)Nginx安装配置
wget -c http://nginx.org/download/nginx-1.12.0.tar.gz
tar -xzf nginx-1.12.0.tar.gz
cd nginx-1.12.0
useradd www ;./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
make
make install
(2)MYSQL安装配置
yum install cmake ncurses-devel ncurses –y
wget http://down1.chinaunix.net/distfiles/mysql-5.5.20.tar.gz
tar -xzf mysql-5.5.20.tar.gz
cd mysql-5-5.20
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql55 \
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \
-DMYSQL_DATADIR=/data/mysql \
-DSYSCONFDIR=/etc \
-DMYSQL_USER=mysql \
-DMYSQL_TCP_PORT=3306 \
-DWITH_XTRADB_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_EXTRA_CHARSETS=1 \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=all \
-DWITH_BIG_TABLES=1 \
-DWITH_DEBUG=0
make
make install
(3)PHP安装配置
wget http://museum.php.net/php5/php-5.3.10.tar.gz
yum -y install gd curl curl-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel
cd php-5.3.10
./configure --prefix=/usr/local/php5 --enable-fpm --enable-debug --with-gd --with-jpeg-dir --with-png-dir --with-freetype-dir --enable-mbstring --with-curl --with-mysql=/usr/local/mysql55/ --with-mysqli=/usr/local/mysql55/bin/mysql_config --with-config-file-path=/usr/local/php5/etc
make
make install
cp php.ini-development /usr/local/php5/etc/php.ini
cp /usr/local/php5/etc/php-fpm.conf.default /usr/local/php5/etc/php-fpm.conf
/usr/local/php5/sbin/php-fpm
cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
(4)Nginx配置文件配置
server {
include port.conf;
server_name www.jfedu.net jfedu.net;
location / {
index index.html index.php;
root /usr/local/nginx/html;
}
location ~ .php$ {
root html;
FastCGI_pass 127.0.0.1:9000;
FastCGI_index index.php;
FastCGI_param SCRIPT_FILENAME html$FastCGI_script_name;
include FastCGI_params;
}
}
(5)测试LNMP架构测试,创建index.php测试页面,如图14-6所示:
图14-6 LNMP企业实战测试页面
14.11 Nginx Rewrite规则详解一
Rewirte规则也称为规则重写,主要功能是实现浏览器访问HTTP URL的跳转,其正则表达式是基于Perl语言。通常而言,几乎所有的WEB服务器均可以支持URL重写。Rewrite URL规则重写的用途:
对搜索引擎优化(Search Engine Optimization,SEO)友好,利于搜索引擎抓取网站页面;
隐藏网站URL真实地址,浏览器显示更加美观;
网站变更升级,可以基于Rewrite临时重定向到其他页面。
Nginx Rewrite规则使用中有三个概念需要理解,分别是:Rewrite结尾标识符、Rewrite规则常用表达式、Nginx Rewrite变量,如下为三个概念的详解:
(1)Nginx Rewrite结尾标识符,用于Rewrite规则末尾,表示规则的执行属性。
last :相当于Apache里的(L)标记,表示完成rewrite匹配;
break:本条规则匹配完成后,终止匹配,不再匹配后面的规则。
redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址。
permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址。
其中last和break用来实现URL重写时,浏览器地址栏URL地址不变。
(2)Nginx Rewrite规则常用表达式,主要用于匹配参数、字符串及过滤设置。
. 匹配任何单字符;
[word] 匹配字符串:word;
[^word] 不匹配字符串:word;
jfedu|jfteach 可选择的字符串:jfedu|jfteach;
? 匹配0到1个字符;

  •                           匹配0到多个字符;
  •                           匹配1到多个字符;

    ^ 字符串开始标志;
    $ 字符串结束标志;
    \n 转义符标志。
    (3)Nginx Rewrite变量,常用于匹配HTTP请求头信息、浏览器主机名、URL等。
    HTTP headers:HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_HOST, HTTP_ACCEPT;
    connection & request: REMOTE_ADDR, QUERY_STRING;
    server internals: DOCUMENT_ROOT, SERVER_PORT, SERVER_PROTOCOL;
    system stuff: TIME_YEAR, TIME_MON, TIME_DAY。
    详解如下:
    HTTP_USER_AGENT 用户使用的代理,例如浏览器;
    HTTP_REFERER 告知服务器,从哪个页面来访问的;
    HTTP_COOKIE 客户端缓存,主要用于存储用户名和密码等信息;
    HTTP_HOST 匹配服务器ServerName域名;
    HTTP_ACCEPT 客户端的浏览器支持的MIME类型;
    REMOTE_ADDR 客户端的IP地址
    QUERY_STRING URL中访问的字符串;
    DOCUMENT_ROOT 服务器发布目录;
    SERVER_PORT 服务器端口;
    SERVER_PROTOCOL 服务器端协议;
    TIME_YEAR 年;
    TIME_MON 月;
    TIME_DAY 日;
    (4)Nginx Rewrite以下配置均配置在nginx.conf或者vhosts.conf中,企业中常用的Nginx Rewrite案例如下:
    1.将jfedu.net跳转至www.jfedu.net。
    if ($host = 'jfedu.net' ) {
    rewrite ^/(.)$ http://www.jfedu.net/$1 permanent;
    }
    2.访问www.jfedu.net跳转www.test.com/new.index.html。
    rewrite ^/$ http://www.test.com/index01.html permanent;
    3.访问/jfedu/test01/跳转至/newindex.html,浏览器地址不变。
    rewrite ^/jfedu/test01/$ /newindex.html last;
    4.多域名跳转到www.jfedu.net。
    if ($host != ‘www.jfedu.net’ ) {
    rewrite ^/(.
    )$ http://www.jfedu.net/$1 permanent;
    }
    5.访问文件和目录不存在跳转至index.php。
    if ( !-e $request_filename )
    {
    rewrite ^/(.*)$ /index.php last;
    }
    6.目录对换 /xxxx/123456  ====>  /xxxx?id=123456。
    rewrite ^/(.+)/(\d+)  /$1?id=$2 last;
    7.判断浏览器User Agent跳转。
    if( $http_user_agent  ~ MSIE)
    {
    rewrite ^(.*)$ /ie/$1 break;
    }
    8.禁止访问以.sh,.flv,.mp3为文件后缀名的文件。
    location ~ .*\.(sh|flv|mp3)$
    {
    return 403;
    }
    9.将移动用户访问跳转至移动端。
    if ( $http_user_agent ~* "(Android)|(iPhone)|(Mobile)|(WAP)|(UCWEB)" )
    {
    rewrite ^/$ http://m.jfedu.net/ permanent;
    }
    10.匹配URL访问字符串跳转。
    if ($args ~* tid=13){
    return 404;
    }
    11.访问/10690/jfedu/123跳转至/index.php?tid/10690/items=123,[0-9]表示任意一个数字,+表示多个,(.+)表示任何多个字符。
    rewrite ^/([0-9]+)/jfedu/(.+)$ /index.php?tid/$1/items=$2 last;
    14.12 Nginx WEB日志分析
    在企业服务器运维中,当Nginx服务器正常运行后,SA会经常密切关注Nginx的访问日志,发现有异常的日志信息需要进行及时处理。
    Nginx默认日志路径/usr/local/nginx/logs/,其中包含访问日志access.log 和错误记录日志error.log,如图查看nginx访问日志:cat /usr/local/nginx/logs/access.log |more,如图14-7所示:

图14-7 Nginx访问日志信息
Nginx访问日志打印的格式可以自定义,例如Nginx日志打印格式配置如下,Log_format 用来设置日志格式,Name(模块名) Type(日志类型),可以配置多个日志模块,分别供不同的虚拟主机日志记录所调用:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
Nginx日志格式内部变量及函数参数说明:
$remote_addr 记录客户端IP地址;
$server_name 虚拟主机名称;
$http_x_forwarded_for HTTP的请求端真实的IP;
$remote_user 记录客户端用户名称;
$request 记录请求的URL和HTTP协议;
$status 记录返回HTTP请求的状态;
$uptream_status upstream的状态;
$ssl_protocol SSL协议版本;
$body_bytes_sent 发送给客户端的字节数,不包括响应头的大小;
$bytes_sent 发送给客户端的总字节数;
$connection_requests 当前通过一个连接获得的请求数量;
$http_referer 记录从哪个页面链接访问过来的;
$http_user_agent 记录客户端浏览器相关信息;
$request_length 请求的长度,包括请求行,请求头和请求正文;
$msec 日志写入时间;
$request_time 请求处理时间,单位为秒,精度毫秒,Nginx接受用户请求的第一个字节到发送完响应数据的时间,包括:接收请求数据时间、程序响应时间、输出、响应数据时间。
$upstream_response_time 应用程序响应时间,Nginx向后端服务建立连接开始到接受完数据然后关闭连接为止的总时间。
通过Nginx日志,可以简单分析WEB网站的运行状态、数据报表、IP、UV(unique visitor)、PV(page view)访问量等需求,如下为常用需求分析:
(1)统计Nginx服务器独立IP数。 
awk '{print $1}' access.log |sort -r|uniq -c | wc -l
(2)统计Nginx服务器总PV量。
awk '{print $7}' access.log |wc -l
(3)统计Nginx服务器UV统计。
awk '{print $11}' access.log |sort -r|uniq -c |wc -l
(4)分析Nginx访问日志截止目前为止访问量前20的IP列表。
awk '{print $1}' access.log|sort |uniq -c |sort -nr |head -20
(5)分析Nginx访问日志早上9点至中午12点的总请求量。
sed -n "/2016:09:00/,/2016:12:00/"p access.log
awk '/2017:09:00/,/2017:12:00/' access.log|wc –l
(6)分析Nginx访问日志总的独立IP数。
awk '{print $1}' access.log |sort |uniq -c|wc -l
(7)分析Nginx访问日志截止目前为止访问量前20的IP列表。
awk '{print $1}' access.log|sort |uniq -c |sort -nr |head -20
(8)分析Nginx访问日志截止目前为止访问量前20的IP列表。
awk '{print $1}' access.log|sort |uniq -c |sort -nr |head -20
(9)分析Nginx访问日志状态码404、502、503、500、499等错误信息页面,打印错误出现次数大于20的IP地址。
awk '{if ($9~/502|499|500|503|404/) print $1,$9}' access.log|sort|uniq –c|sort –nr | awk '{if($1>20) print $2}'
(10)分析Nginx访问日志访问最多的页面。
awk '{print $7}' access.log |sort |uniq -c|sort -nr|head -20
(11)分析Nginx访问日志请求处理时间大于5秒的URL,并打印出时间、URL、访客IP。
awk '{if ($NF>5) print $NF,$7,$1}' access.log|sort -nr|more
14.13 Nginx日志切割案例
Nginx WEB服务器每天会产生大量的访问日志,而且不会自动地进行切割,如果持续天数访问,将会导致该access.log日志文件容量非常大,不便于SA查看相关的网站异常日志。
可以基于Shell 脚本结合Crontab计划任务对Nginx日志进行自动、快速的切割,其切割的方法使用mv命令即可,如图14-8所示。

!/bin/bash

auto mv nginx log shell

by author jfedu.net

S_LOG=/usr/local/nginx/logs/access.log
D_LOG=/data/backup/date +%Y%m%d
echo -e "\033[32mPlease wait start cut shell scripts...\033[1m"
sleep 2
if [ ! -d $D_LOG ];then
mkdir -p $D_LOG
fi
mv $S_LOG $D_LOG
kill -USR1 cat /usr/local/nginx/logs/nginx.pid
echo "-------------------------------------------"
echo "The Nginx log Cutting Successfully!"
echo "You can access backup nginx log $D_LOG/access.log files."

图14-8 Nginx日志切割
将如上脚本内容写入auto_nginx_log.sh文件,crontab /var/spool/cron/root文件中添加如下代码,每天凌晨自动切割日志:
0 0 /bin/sh /data/sh/auto_nginx_log.sh >>/tmp/nginx_cut.log 2>&1
14.14 Nginx防盗链配置案例配置
防盗链的含义是网站内容本身不在自己公司的服务器上,而通过技术手段,直接在调用其他公司的服务器网站数据,而向最终用户提供此内容。一些小网站盗链高访问量网站的音乐、图片、软件的链接,然后放置在自己的网站中,通过这种方法盗取高访问量网站的空间和流量。
网站每天访问量很大,而且占用了很多不必要的带宽,浪费资源,所以必须采取一些限制措施。防盗链其实就是采用服务器端编程技术,通过URL过滤、主机名等实现的防止盗链的软件。
例如http://www.jfedu.net/linux/页面,如果没有配置防盗链,别人就能轻而易举的在其的网站上引用该页面。Nginx防盗链配置代码如下:
server {
listen 80;
server_name jfedu.net www.jfedu.net;
location / {
root html/b;
index index.html index.htm;
}
location ~
.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked jfedu.net *.jfedu.net;
root html/b;
if ($invalid_referer) {

rewrite ^/ http://www.jfedu.net/403.html

            return 403;
            }
    }

}
Nginx防盗链参数详解:
valid_referers表示可用的referers设置
none 表示没有referers,直接通过浏览器或者其他工具访问。
blocked表示有referers,但是被代理服务器或者防火墙隐藏;
jfedu.net 表示通过jfedu.net访问的referers;
.jfedu.net 表示通过.jfedu.net访问的referers,表示任意host主机。
除了以上方法,按照如下方法设置也可以实现防盗链:
location ~
.(gif|jpg|png|swf|flv)$
if ($host !=’*.jfedu.net’) {
return 403;
}
防盗链测试,找另外一台测试服务器,基于Nginx发布如下test.html页面,代码如下,去调用www.jfedu.net官网的test.png图片,由于www.jfedu.net官网设置了防盗链,所以无法访问该图片。

TEST Nginx PNG

默认没有配置Nginx防盗链,网站正常调用www.jfedu.net的logo图片,访问如图14-9所示:

图14-9 Nginx无防盗链正常调用图片
配置Nginx防盗链,网站无法正常调用www.jfedu.net的logo图片,访问如图14-10所示:

图14-10 Nginx防盗链403禁止访问
14.15 Nginx HTTPS企业实战
超文本传输安全协议(Hyper Text Transfer Protocol over Secure Socket Layer,HTTPS),是以安全为目标的HTTP通道,简单来说就是HTTP的安全版。HTTPS由两个部分组成:HTTP + SSL / TLS,在HTTP基础上又加了一层处理加密信息的模块,服务端和客户端的信息传输都会通过TLS进行加密,传输的数据都是加密后的数据。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:HTTPS。为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
SSL证书是一种数字证书,它使用Secure Socket Layer 协议在浏览器和 Web 服务器之间建立一条安全通道,从而实现数据信息在客户端和服务器之间的加密传输,保证双方传递信息的安全性,不可被第三方窃听。而且用户可以通过服务器证书验证他所访问的网站是否真实可靠。
加密的HTTP传输通道,浏览器访问格式为:https://url,其基于HTTP+TLS,现被广泛应用于互联网上安全敏感的通信,例如安全登录、订单交易、支付结算等方面
HTTPS和HTTP的区别,超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息。HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此HTTP协议不适合传输一些敏感信息,比如信用卡号、密码等。
HTTPS加密、解密、验证完整过程,如图14-11所示:

图14-11 HTTPS传输原理
如下为HTTPS传输八个步骤内容详解:
(1)客户端发起HTTPS请求,用户在浏览器里输入https网址,然后连接到Nginx Server的443端口。
(2)服务器端采用HTTPS协议有一套数字证书,该证书可以自行配置,也可以向证书管理组织去申请,该证书其本质是公钥和私钥。
(3)将公钥传送证书传递给客户端,证书包含了很多信息,例如如证书的颁发机构,过期时间、网址、公钥等等。
(4)客户端解析证书,由客户端的TLS来完成,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出警告框,提示证书存在问题。如果证书没有问题,就会生成一个随机值。然后用证书对该随机值进行加密。
(5)将证书加密后的随机值传送至服务器,让服务端获取该随机值,后续客户端和服务端的通信可以通过该随机值来进行加密解密。
(6)服务端用私钥解密后,得到了客户端传过来的随机值,然后把内容通过该值进行对称加密。
(7)服务器端将用私钥加密后的信息发给客户端。
(8)客户端用之前生成的私钥来解密服务端发送过来的信息,获取解密后的内容。

HTTPS证书申请与颁发方法如下:
(1)生成https证书,可以使用openssl生成服务端RSA密钥及证书,生成的命令如下,如图14-12所示:
openssl genrsa -des3 -out server.key 1024

图14-12 Openssl生成RSA秘钥及证书
(2)创建签名请求的证书(CSR),如图14-13所示:
openssl req -new -key server.key -out server.csr

图14-13 Openssl创建签名请求证书
(3)加载SSL支持的Nginx并使用私钥时去除口令,如图14-14所示:
cp server.key server.key.bak
openssl rsa -in server.key.bak -out server.key

图14-14 Openssl去除口令
(4)自动签发证书,如图14-15所示:
openssl x509 -req -days 10240 -in server.csr -signkey server.key -out server.crt
图14-15 Openssl自动签发证书
HTTPS证书生成完毕,配置Nginx+证书整合,步骤如下:
(1)安装Nginx并加入SSL模块支持,并将证书拷贝至nginx conf目录。
./configure --prefix=/usr/local/nginx --with-http_ssl_module &&make &&make install
cp server.crt server.key /usr/local/nginx/conf/
(2)如下Nginx.conf配置文件内容为如下:

HTTPS server

server {
listen 443 ssl;
server_name www.jfedu.net localhost;
ssl_certificate server.crt;
ssl_certificate_key server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
(3)最后重启Nginx服务,然后访问https://www.jfedu.net或者https://ip/ 即可,如图14-16(a)、14-16(b)所示:

图14-16(a) Nginx监听443端口

图14-16(b) 客户端访问Nginx Https
第15章 Linux性能优化企业实战
随着企业网站访问量越来越大,服务器的压力也逐渐增加,主要体现在CPU使用率、内存、硬盘、网卡流量等方面资源占用情况很高。此时需对服务器性能进行调优,尽量在保持服务器的现有数量,然后对其各个环节参数进行优化。
本章向读者介绍Linux企业级性能服务器优化、TCP/IP报文、TCP三次握手及四次断开、Linux内核深入优化、Linux内核故障解决方案及对Linux性能进行评估等。
15.1 TCP/IP报文详解
TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地,而IP是给因特网的每台联网设备规定一个地址。TCP/IP 协议数据封装的过程包括:用户数据经过应用层协议封装后传递给传输层,传输层封装TCP头部,交给网络层,网络层封装IP头部后,再交给数据链路层,数据链路层封装Ethernet帧头和帧尾,交给物理层,物理层以比特流的形式将数据发送到物理线路上。
一般而言,不同的协议层对数据包有不同的称谓,数据包在传输层叫做段(segment),在网络层叫做数据报(datagram),在链路层叫做帧(frame)。数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理,如图15-1所示:

图15-1 TCP/IP协议数据包封装过程
优化Linux服务器,需要了解TCP协议相关信息,例如TCP/IP数据报文的内容及如何传输的,如图15-2所示为IP数据包报文详细结构图:

图15-2 IP数据包报文详细结构图
IP数据包详解如下:
Source Port和Destination Port:分别占用16位,表示源端口号和目的端口号;用于区别主机中的不同进程,而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一的确定一个TCP连接;
Sequence Number:用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节在数据流中的序号;主要用来解决网络报乱序的问题;
Acknowledgment Number:32位确认序列号包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志(下面介绍)为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;
Offset:给出首部中32 bit字的数目,需要这个值是因为任选字段的长度是可变的。这个字段占4bit(最多能表示15个32bit的的字,即4*15=60个字节的首部长度),因此TCP最多有60字节的首部。然而,没有任选字段,正常的长度是20字节;
TCP Flags:TCP首部中有6个标志比特,它们中的多个可同时被设置为1,主要是用于操控TCP的状态机的,依次为URG,ACK,PSH,RST,SYN,FIN。每个标志位的意思如下:
① URG:此标志表示TCP包的紧急指针域(后面马上就要说到)有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据;
② ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0;
③ PSH:这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队;
④ RST:这个标志表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;
⑤ SYN:表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1,ACK=0;连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手;
⑥ FIN: 表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。
Window:窗口大小,也就是有名的滑动窗口,用来进行流量控制;
15.2 TCP三次握手及四次断开
TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换TCP窗口大小信息。如图15-3所示:

图15-3 TCP三次握手及四次断开
(1)TCP三次握手原理:
第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后客户端进入SYN_SEND状态,等待服务器的确认;
第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
如图15-4所示为基于tcpdump抓取TCP/IP三次握手及数据包传输过程:

图15-4 TCP三次握手抓包分析
(2)TCP四次挥手原理:
第一次挥手:主机A(可以使客户端,可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机B发送一个FIN报文段;此时,主机A进入FIN_WAIT_1状态;这表示主机A没有数据要发送给主机B;
第二次挥手:主机B收到了主机A发送的FIN报文段,向主机A回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机A进入FIN_WAIT_2状态;主机B告诉主机A,我“同意”你的关闭请求;
第三次挥手:主机B向主机A发送FIN报文段,请求关闭连接,同时主机B进入LAST_ACK状态;
第四次挥手:主机A收到主机B发送的FIN报文段,向主机B发送ACK报文段,然后主机A进入TIME_WAIT状态;主机B收到主机A的ACK报文段以后,就关闭连接;此时,主机A等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机A也可以关闭连接。
如图15-5所示为基于tcpdump抓取TCP/IP四次挥手及数据包传输过程:
图15-5 TCP四次挥手抓包分析
15.3 优化Linux文件打开最大数
为了防止失控的进程破坏系统的性能,Unix和Linux会跟踪进程使用的大部分资源,并允许用户和系统管理员使用对进程的资源限制,例如控制某个进程打开的系统文件数、对某个用户打开系统进程数进行限制等,一般限制手段包括:软限制和硬限制。
软限制(soft limit)是内核实际执行的限制,任何进程都可以将软限制设置为任意小于等于对进程限制的硬限制的值,(noproc)最大线程数和(nofile)文件数;
硬限制(hard limit)是可以在任何时候任何进程中设置 但硬限制只能由超级用户修改。
Linux系统一切皆文件,对Linux进行各种操作,其实是对文件进行操作,文件可分为:普通文件、目录文件、链接文件和设备文件。而文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,其值一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。
Linux系统默认已经打开的文件描述符包括:STDIN_FILENO 0表示标准输入、STDOUT_FILENO 1表示标准输出、STDERR_FILENO 2表示标准错误输出,默认打开一个新文件,它的文件描述符为3。
每个文件描述符与一个打开文件相对应,不同的文件描述符可以指向同一个文件。相同的文件可以被不同的进程打开,也可以在同一个进程中被多次打开。
Linux系统为每个进程维护了一个文件描述符表,该表的值都从0开始的,在不同的进程中你会看到相同的文件描述符,相同文件描述符有可能指向同一个文件,也有可能指向不同的文件。Linux内核对文件操作,维护了3个数据结构概念如下:
进程级的文件描述符表;
系统级的打开文件描述符表;
文件系统的i-node表;
其中进程级的描述符表的每一个条目记录了单个文件描述符的相关信息,例如控制文件描述符操作的一组标志及对打开文件句柄的引用。Linux内核对所有打开的文件都维护了一个系统级的描述符表(open file description table)。将描述符表中的记录行称为打开文件句柄(open file handle),一个打开文件句柄存储了与一个打开文件相关的全部信息,详细信息如下:
当前文件偏移量;
打开文件时所使用的状态标识;
文件访问模式;
与信号驱动相关的设置;
对该文件i-node对象的引用;
文件类型和访问权限;
指针,指向该文件所持有的锁列表;
文件的各种属性。
默认Linux内核对每个用户设置了打开文件最大数为1024,对于高并发网站,是远远不够的,需要将默认值调整到更大,调整方法有两种:
Linux每个用户打开文件最大数临时设置方法,重启服务器该参数无效,命令行终端执行如下命令:
ulimit –n 65535
Linux每个用户打开文件最大数永久设置方法,将如下代码加入内核限制文件/etc/security/limits.conf的末尾:

  • soft noproc 65535
  • hard noproc 65535
  • soft nofile 65535
  • hard nofile 65535
    如上设置为对每个用户分别设置nofile、noproc最大数,如果需要对Linux整个系统设置文件最大数限制,需要修改/proc/sys/fs/file-max中的值,该值为Linux总文件打开数,例如设置为:echo 3865161233 >/proc/sys/fs/file-max。
    15.4 内核参数的优化
    Linux /proc/sys目录下存放着多数内核的参数,并且可以在系统运行时进行更改,一般重新启动机器就会失效。而/etc/sysctl.conf是一个允许改变正在运行中的Linux系统的接口,它包含一些TCP/IP堆栈和虚拟内存系统的高级选项,修改内核参数永久生效。
    /proc/sys下内核文件与配置文件sysctl.conf中变量存在着对应关系,即修改sysct.conf配置文件,其实是修改/proc/sys相关参数,所以对Linux内核优化只需修改/etc/sysctl.conf文件即可。如下为BAT企业生产环境/etc/sysct.conf内核完整参数:
    net.ipv4.ip_forward = 0
    net.ipv4.conf.default.rp_filter = 1
    net.ipv4.conf.default.accept_source_route = 0
    kernel.sysrq = 0
    kernel.core_uses_pid = 1
    net.ipv4.tcp_syncookies = 1
    kernel.msgmnb = 65536
    kernel.msgmax = 65536
    kernel.shmmax = 68719476736
    kernel.shmall = 4294967296
    net.ipv4.tcp_max_tw_buckets = 10000
    net.ipv4.tcp_sack = 1
    net.ipv4.tcp_window_scaling = 1
    net.ipv4.tcp_rmem = 4096 87380 4194304
    net.ipv4.tcp_wmem = 4096 16384 4194304
    net.core.wmem_default = 8388608
    net.core.rmem_default = 8388608
    net.core.rmem_max = 16777216
    net.core.wmem_max = 16777216
    net.core.netdev_max_backlog = 262144
    net.core.somaxconn = 262144
    net.ipv4.tcp_max_orphans = 3276800
    net.ipv4.tcp_max_syn_backlog = 262144
    net.ipv4.tcp_timestamps = 0
    net.ipv4.tcp_synack_retries = 1
    net.ipv4.tcp_syn_retries = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_mem = 94500000 915000000 927000000
    net.ipv4.tcp_fin_timeout = 1
    net.ipv4.tcp_keepalive_time = 30
    net.ipv4.ip_local_port_range = 1024 65535
    Linux内核常见参数详解:
    net.ipv4.tcp_timestamps = 1
    该参数控制RFC 1323 时间戳与窗口缩放选项;
    net.ipv4.tcp_sack = 1
    选择性应答(SACK)是 TCP 的一项可选特性,可以提高某些网络中所有可用带宽的使用效率;
    net.ipv4.tcp_fack = 1
    打开FACK(Forward ACK) 拥塞避免和快速重传功能;
    net.ipv4.tcp_retrans_collapse = 1
    打开重传重组包功能,为0的时候关闭重传重组包功能;
    net.ipv4.tcp_syn_retries = 5
    对于一个新建连接,内核要发送多少个SYN 连接请求才决定放弃;
    net.ipv4.tcp_synack_retries = 5
    tcp_synack_retries显示或设定Linux在回应SYN要求时尝试多少次重新发送初始SYN,ACK封包后才决定放弃;
    net.ipv4.tcp_max_orphans = 131072
    系统所能处理不属于任何进程的TCP sockets最大数量;
    net.ipv4.tcp_max_tw_buckets = 5000
    系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息;
    默认为180000,设为较小数值此项参数可以控制TIME_WAIT套接字的最大数量,避免服务器被大量的TIME_WAIT套接字拖死;
    net.ipv4.tcp_keepalive_time = 30
    net.ipv4.tcp_keepalive_probes = 3
    net.ipv4.tcp_keepalive_intvl = 3
    如果某个TCP连接在空闲30秒后,内核才发起probe(探查);
    如果probe 3次(每次3秒既tcp_keepalive_intvl值)不成功,内核才彻底放弃,认为该连接已失效;
    net.ipv4.tcp_retries1 = 3
    放弃回应一个TCP 连接请求前﹐需要进行多少次重试;
    net.ipv4.tcp_retries2 = 15
    在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试;
    net.ipv4.tcp_fin_timeout = 30
    表示如果套接字由本端要求关闭,这个参数决定了它保持在 FIN-WAIT-2状态的时间;
    net.ipv4.tcp_tw_recycle = 1
    表示开启TCP连接中TIME-WAITsockets的快速回收,默认为0,表示关闭;
    net.ipv4.tcp_max_syn_backlog = 8192
    表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数;
    net.ipv4.tcp_syncookies = 1
    tcp 建立连接的 3 路握手过程中,当服务端收到最初的 SYN 请求时,会检查应用程序的syn_backlog队列是否已满;
    启用syncookie,可以解决超高并发时的can’t connect 问题。
    但是会导致 TIME_WAIT 状态fallback为保持2MSL时间,高峰期时会导致客户端无可复用连接而无法连接服务器;
    net.ipv4.tcp_orphan_retries = 0
    关闭TCP连接之前重试多少次;
    net.ipv4.tcp_mem = 178368 237824 356736
    net.ipv4.tcp_mem[0]: 低于此值,TCP没有内存压力;
    net.ipv4.tcp_mem1: 在此值下,进入内存压力阶段;
    net.ipv4.tcp_mem[2]: 高于此值,TCP拒绝分配socket;
    net.ipv4.tcp_tw_reuse = 1
    表示开启重用,允许将TIME-WAITsockets重新用于新的TCP连接;
    net.ipv4.ip_local_port_range = 1024 65000
    表示用于向外连接的端口范围;
    net.ipv4.ip_conntrack_max = 655360
    在内核内存中netfilter可以同时处理的“任务”(连接跟踪条目);
    net.ipv4.icmp_ignore_bogus_error_responses = 1
    开启恶意icmp错误消息保护;
    net.ipv4.tcp_syncookies = 1
    开启SYN洪水攻击保护。

15.5 Linux内核报错剖析
企业生产环境Linux服务器正常运行,由于某种原因会导致内核报错或者抛出很多信息,根据系统SA可以快速定位Linux服务器故障,Linux内核日志一般存在messages日志中,可以通过命令tail -fn 100 /var/log/messages查看Linux内核日志,如下为Linux内核常见报错日志及生产环境解决报错的方案:
(1)Linux内核抛出net.ipv4.tcp_max_tw_buckets错误:
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
Sep 23 04:45:55 localhost kernel: TCP: time wait bucket table overflow
根据TCP协议定义的3次握手及四次断开连接规定,发起socket主动关闭的一方Socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime)。
如果该值设置过小导致,当系统Time wait数量超过默认设置的值,即会抛出如上的警告信息,需要增加net.ipv4.tcp_max_tw_buckets的值,警告信息消除。
当然也不能设置过大,对于一个处理大量短连接的服务器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的Socket,甚至比处于Established状态下的Socket多的多,严重影响服务器的处理能力,甚至耗尽可用的Socket而停止服务,TIME_WAIT是TCP协议用以保证被重新分配的Socket不会受到之前残留的延迟重发报文影响的机制,是TCP传输必要的逻辑保证。
(2)Linux内核抛出Too many open files错误:
Benchmarking localhost (be patient)
socket: Too many open files (24)
socket: Too many open files (24)
socket: Too many open files (24)
socket: Too many open files (24)
socket: Too many open files (24)
每个文件描述符与一个打开文件相对应,不同的文件描述符可以指向同一个文件。相同的文件可以被不同的进程打开,也可以在同一个进程中被多次打开。Linux内核对应每个用户打开的文件最大数一般为1024,需要将该值调高满足大并发网站的访问。
Linux每个用户打开文件最大数永久设置方法,将如下代码加入内核限制文件/etc/security/limits.conf的末尾,Exit退出终端,重新登录即生效:

  • soft noproc 65535
  • hard noproc 65535
  • soft nofile 65535
  • hard nofile 65535
    (3)Linux内核抛出possible SYN flooding on port 80. Sending cookies错误:
    May 31 14:20:14 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    May 31 14:21:28 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    May 31 14:22:44 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    May 31 14:25:33 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    May 31 14:27:06 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    May 31 14:28:44 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    May 31 14:28:51 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    May 31 14:31:01 localhost kernel: possible SYN flooding on port 80. Sending cookies.
    此问题是由于SYN 队列已满,而触发SYN cookies,一般是由于大量的访问,或者恶意访问导致,也称之为SYN Flooding洪水攻击,与DDOS攻击类似。
    完整的TCP连接的三次握手,假设一个用户A向服务器发送了SYN报文后突然死机或掉线,那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的(第三次握手无法完成),这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒-2分钟)。
    一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源,数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。
    实际上如果服务器的TCP/IP栈不够强大,最后的结果往往是堆栈溢出崩溃,即使服务器端的系统足够强大,服务器端也将忙于处理攻击者伪造的TCP连接请求而无暇理睬客户的正常请求(毕竟客户端的正常请求比率非常之小),此时从正常客户的角度看来,服务器失去响应,服务器拒绝提供服务,服务器受到了DDOS攻击,这里攻击的手段为DDOS中SYN Flood攻击(SYN洪水攻击)。
    防护DDOS攻击有两种手段,一是基于硬件专业防火墙、二是基于Linux内核简单防护,,如果攻击流量特别大,单纯配置内核参数是无法抵挡的,还得依靠专业级硬件防火墙,如下为Linux内核防护DDOS优化参数,加入如下代码即可:
    net.ipv4.tcp_fin_timeout = 30
    net.ipv4.tcp_keepalive_time = 1200
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.ip_local_port_range = 1024 65000
    net.ipv4.tcp_max_syn_backlog = 8192
    net.ipv4.tcp_max_tw_buckets = 8000
    net.ipv4.tcp_synack_retries = 2
    net.ipv4.tcp_syn_retries = 2
    (4)Linux内核抛出ip_conntrack: table full, dropping packet.错误:
    May 6 11:15:07 localhost kernel: nf_conntrack:table full, dropping packet.
    May 6 11:19:13 localhost kernel: nf_conntrack:table full, dropping packet.
    May 6 11:20:34 localhost kernel: nf_conntrack:table full, dropping packet.
    May 6 11:23:12 localhost kernel: nf_conntrack:table full, dropping packet.
    May 6 11:24:07 localhost kernel: nf_conntrack:table full, dropping packet.
    May 6 11:24:13 localhost kernel: nf_conntrack:table full, dropping packet.
    May 6 11:25:11 localhost kernel: nf_conntrack:table full, dropping packet.
    May 6 11:26:25 localhost kernel: nf_conntrack:table full, dropping packet.
    由于该服务器开启了iptables防火墙,WEB服务器收到了大量的连接,iptables会把所有的连接都做链接跟踪处理,这样iptables就会有一个链接跟踪表,当这个表满的时候,就会出现上面的错误。ip_conntrack是linux NAT的一个跟踪连接条目的模块,ip_conntrack模块会使用一个哈希表记录 tcp 通讯协议的established connection记录。
    如果是CentOS6.x系统,需执行:modprobe nf_conntrack命令,然后在内核优化文件中加入如下代码,sysctl –p使其内核文件生效,即可解决该报错:
    net.nf_conntrack_max = 655360
    net.netfilter.nf_conntrack_tcp_timeout_established = 36000
    如果是CentOS5.x系统,需执行:modprobe ip_conntrack命令,然后在内核优化文件中加入如下代码,sysctl –p使其内核文件生效,即可解决该报错:
    net.ipv4.ip_conntrack_max = 655350
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 10800

15.6 影响务器性能因素
影响企业生产环境Linux服务器性能的因素有很多,一般分为两大类,分别为操作系统层级和应用程序级别。如下为各级别影响性能的具体项及性能评估的标准:
(1)操作系统级别
内存;
CPU;
磁盘I/O;
网络I/O带宽。
(2)应用程序及软件
Nginx;
Mysql;
Tomcat
PHP;
应用程序代码。
(3)Linux系统性能评估标准如表15-1所示:
影响性能因素 评判标准
好 坏 糟糕
CPU user% + sys%< 70% user% + sys%= 85% user% + sys% >=90%
内存 Swap In(si)=0
Swap Out(so)=0 Per CPU with 10 page/s More Swap In & Swap Out
磁盘 iowait % < 20% iowait % =35% iowait % >= 50%
表15-1 Linux性能评估标准
(4)Linux系统性能分析工具
常用系统性能分析命令;
vmstat、sar、iostat、netstat、free、ps、top、iftop等;
常用系统性能组合分析命令;
vmstat、sar、iostat 检测是否是CPU瓶颈;
free、vmstat 检测是否是内存瓶颈;
iostat 检测是否是磁盘I/O瓶颈;
netstat、iftop 检测是否是网络带宽瓶颈。
15.7 Linux服务器性能评估与优化
Linux服务器性能评估与优化是一项长期的工作,需要随时关注网站服务器的运行状态,及时作出相应的调整,如下为Linux服务器性能评估及优化方案:
(1)Linux系统整体性能评估
uptime命令主要用于查看当前服务器整体性能,例如CPU、负载、内存等值的总览,如下为uptime命令应用案例及详解:
[root@web1 ~]# uptime
13:38:00 up 112 days,  14:01,  5 users,  load average: 6.22, 1.02, 0.91
Load average负载有三个值,分别表示:最近1分钟、5分钟、15分钟系统的负载,三个值的大小一般不能大于系统逻辑CPU核数的2倍,例如Linux操作系统有4个逻辑CPU,如果load average的三个值长期大于8时,说明CPU很繁忙,负载很高,可能会影响系统性能,但是偶尔大于8时,可以不用担心,一般不会影响系统性能。
如果load average的输出值小于CPU逻辑个数的2倍,则表示CPU还有空闲的时间片,例如案例中CPU负载为6.22,表示CPU或者服务器是比较空闲的。基于此参数不能完全确认服务器的性能瓶颈,需要借助其他工具进一步判断。
(2)CPU性能评估
利用vmstat命令监控系统CPU,该命令可以显示关于系统各种资源之间相关性能的简要信息,主要用它来查看CPU负载及队列情况。
如图15-6所示,为vmstat命令在某个系统的输出结果:
图15-6 vmstat工具查看系统CPU资源
Vmstat输出结果详解如下:
r 列表示运行和等待cpu时间片的进程数,这个值如果长期大于系统CPU的个数,说明CPU不足,需要增加CPU;
b 列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等;
us 列显示了用户进程消耗的CPU 时间百分比。us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,就需要考虑优化程序或算法;
sy 列显示了内核进程消耗的CPU时间百分比。Sy的值较高时,说明内核消耗的CPU资源很多;
us+sy的参考值为80%,如果us+sy大于80%说明可能存在CPU资源不足。
利用sar命令监控系统CPU,sar功能很强大,可以对系统的每个方面进行单独的统计,但是使用sar命令会增加系统开销,不过这些开销是可以评估的,对系统的统计结果不会有很大影响。如图15-7所示,为sar命令对某个系统的CPU统计输出:
图15-7 Sar工具查看系统CPU资源
Sar输出结果详解如下:
%user 列显示了用户进程消耗的CPU 时间百分比;
%nice 列显示了运行正常进程所消耗的CPU 时间百分比;
%system 列显示了系统进程消耗的CPU时间百分比;
%iowait 列显示了IO等待所占用的CPU时间百分比;
%idle 列显示了CPU处在空闲状态的时间百分比;
%steal 列显示了在内存相对紧张的环境下pagein强制对不同的页面进行的steal操作。
(3)内存性能评估
利用free指令监控内存,free是监控linux内存使用状况最常用的指令,如图15-8所示为服务器内存使用情况:
图15-8 Free –m查看系统内存情况
一般而言,服务器内存可以通过如下方法判断是否空余:
应用程序可用内存/系统物理内存>70%时,表示系统内存资源非常充足,不影响系统性能。
应用程序可用内存/系统物理内存<20%时,表示系统内存资源紧缺,需要增加系统内存,20%<应用程序可用内存/系统物理内存<70%时,表示系统内存资源基本能满足应用需求,暂时不影响系统性能。
(4)磁盘I/O性能评估
利用iostat评估磁盘性能,监控磁盘IO读写及带宽,如图15-9所示:
图15-9 Iostat评估磁盘性能
Iostat输出结果详解如下:
Blk_read/s 表示每秒读取的数据块数;
Blk_wrtn/s 表示每秒写入的数据块数;
Blk_read 表示读取的所有块数;
Blk_wrtn 表示写入的所有块数。
可以通过Blk_read/s和Blk_wrtn/s的值对磁盘的读写性能有一个基本的了解,如果Blk_wrtn/s值很大,表示磁盘的写操作很频繁,可以考虑优化磁盘或者优化程序,如果Blk_read/s值很大,表示磁盘直接读取操作很多,可以将读取的数据放入内存中进行操作。
利用sar评估磁盘性能,通过sar -d组合,可以对系统的磁盘IO做一个基本的统计,如图15-10所示:
图15-10 Sar查看系统磁盘IO
Sar输出结果详解如下:
await表示平均每次设备I/O操作的等待时间(以毫秒为单位);
svctm表示平均每次设备I/O操作的服务时间(以毫秒为单位);
%util表示一秒中有百分之几的时间用于I/O操作;
磁盘IO性能,评判标准:正常情况下svctm应该是小于await值的,而svctm的大小和磁盘性能有关,CPU、内存的负荷也会对svctm值造成影响,过多的请求也会间接的导致svctm值的增加。
await值的大小一般取决与svctm的值和I/O队列长度以及I/O请求模式,如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘性能很好,如果await的值远高于svctm的值,则表示I/O队列等待太长,系统上运行的应用程序将变慢,此时可以通过更换更快的硬盘来解决问题。
%util项的值也是衡量磁盘I/O的一个重要指标,如果%util接近100%,表示磁盘产生的I/O请求太多,I/O系统已经满负荷的在工作,该磁盘可能存在瓶颈。长期下去,势必影响系统的性能,可以通过优化程序或者通过更换更高、更快的磁盘来解决此问题。
(5)网络性能评估
通过ping命令检测网络的连通性
通过netstat –i组合检测网络接口状况
通过netstat –r组合检测系统的路由表信息
通过sar -n组合显示系统的网络运行状态
通过iftop -i eth0 查看网卡流量,详细参数如下,如图15-11所示:
<= 客户端流入的流量;
=> 服务器端流出的流量;
TX 发送流量;
RX 接收流量;
TOTAL 总流量;
Cumm 运行iftop到目前时间的总流量;
peak 流量峰值;
rates 分别表示过去 2s 10s 40s 的平均流量。
图15-11 Iftop查看系统网卡流量
第16章 大数据备份企业实战
随着互联网不断的发展,企业对运维人员的能力要求也越来越高,尤其是要求运维人员能处理各种故障、专研自动化运维技术、云计算机、虚拟化等,满足公司业务的快速发展。
本章向读者介绍数据库备份方法、数量量2T及以上级别数据库备份方案、xtrabackup企业工具案例演示、数据库备份及恢复实战等。
16.1 企业级数据库备份实战
在日常的运维工作中,数据是公司非常重要的资源,尤其是数据库的相关信息,如果数据丢了,少则损失几千元,高则损失上千万。所以在运维工作中要及时注意网站数据的备份,尤其要及时对数据库进行备份。
企业中如果数据量上T级别,维护和管理是非常复杂的,尤其是对数据库进行备份操作。
16.2 数据库备份方法及策略
企业中MySQL数据库备份最常用的方法如下:
直接cp备份
Sqlhotcopy
主从同步复制
Mysqldump备份
Xtrabackup备份
Mysqldump和Xtrabackup均可以备份MYSQL数据,如下为Mysqldump工具使用方法:
通常小于100G的MYSQL数据库可以使用默认Mysqldump备份工具进行备份,如果超过100G的大数据,由于Mysqldump备份方式是采用的逻辑备份,最大的缺陷是备份和恢复速度较慢。
基于Mysqldump备份耗时会非常长,而且备份期间会锁表,锁表直接导致数据库只能访问Select,不能执行Insert、Update等操作,进而导致部分WEB应用无法写入新数据。
如果是Myisam引擎表,当然也可以执行参数--lock-tables=false禁用锁表,但是有可能造成数据信息不一致。
如果是支持事务的表,例如InnoDB和BDB,--single-transaction参数是一个更好的选择,因为它不锁定表。
mysqldump -uroot -p123456 --all-databases --opt --single-transaction > 2017all.sql
其中--opt快捷选项,等同于添加--add-drop-tables --add-locking --create-option --disable-keys --extended-insert --lock-tables --quick --set-charset选项。
本选项能让 Mysqldump 很快的导出数据,并且导出的数据能很快导回。该选项默认开启,但可以用--skip-opt 禁用。
如果运行 Mysqldump没有指定--quick 或 --opt 选项,则会将整个结果集放在内存中。如果导出大数据库的话可能会导致内存溢出而异常退出。
16.3 Xtrabackup企业实战
Mysql冷备、Mysqldump、Mysql热拷贝均不能实现对数据库进行增量备份,在实际环境中增量备份非常的实用,如果数据量小于100G,存储空间足够,可以每天进行完整备份,如果每天产生的数据量大,需要定制数据备份策略例如:每周日使用完整备份,周一到周六使用增量备份,或者每周六完整备份,周日到周五使用增量备份。
Percona-xtrabackup是为实现增量备份而生一款主流备份工具,Xtrabackup有两个主要的工具,分别为:xtrabackup、innobackupex。
Percona XtraBackup是 Percona 公司开发的一个用于 MySQL 数据库物理热备的备份工具,支持 MySQl、Percona Server及MariaDB,开源免费,是目前互联网数据库备份最主流的工具之一。
Xtrabackup只能备份InnoDB和XtraDB两种数据引擎的表,而不能备份MyISAM数据表,Innobackupex-1.5.1则封装了Xtrabackup,是一个封装好的脚本,使用该脚本能同时备份处理innodb和Myisam,但在处理Myisam时需要加一个读锁。
XtraBackup备份原理,Innobackupex在后台线程不断追踪InnoDB的日志文件,然后复制InnoDB的数据文件。数据文件复制完成之后,日志的复制线程也会结束。这样就得到了不在同一时间点的数据副本和开始备份以后的事务日志。完成上面的步骤之后,就可以使用InnoDB崩溃恢复代码执行事务日志(Redo log),以达到数据的一致性。其备份优点如下:
备份速度快,物理备份更加可靠;
备份过程不会打断正在执行的事务,无需锁表;
能够基于压缩等功能节约磁盘空间和流量;
自动备份校验;
还原速度快;
可以流传将备份传输到另外一台机器上;
节约磁盘空间和网络带宽。
Innobackupex工具的备份过程原理,如图16-1所示:

图16-1 Innobackupex备份过程
Innobackupex备份过程中首先启动Xtrabackup_log后台检测的进程,实时检测Mysql redo的变化,一旦发现Redo有新的日志写入,立刻将日志写入到日志文件Xtrabackup_log中,并复制Innodb的数据文件和系统表空间文件idbdata1到备份目录。
Innode引擎表备份完之后,执行Flush table with read lock操作进行MyIsam表备份。拷贝.frm .myd .myi文件,并且在这一时刻获得binary log的位置,将表进行解锁unlock tables,停止Xtrabackup_log进程,完整整个数据库的备份。
16.4 Percona-xtrabackup备份实战
基于Percona-xtrabackup备份,需要如下几个步骤:
(1)官网下载Percona-Xtrabackup
Percona官方wiki使用帮助:
http://www.percona.com/docs/wiki/percona-xtrabackup:start
wget http://www.percona.com/redir/downloads/XtraBackup/XtraBackup-2.0.0/binary/Linux/x86_64/percona-xtrabackup-2.0.0.tar.gz
(2)Percona-xtrabackup软件安装方法,cp innobackupex、xtrabackup、xtrabackup_51 xtrabackup_55工具到/usr/bin目录下,代码如下:
tar zxvf percona-xtrabackup-2.0.0.tar.gz
cp percona-xtrabackup-2.0.0/bin/innobackupex /usr/bin/innobackupex
cp percona-xtrabackup-2.0.0/bin/xtrabackup /usr/bin/xtrabackup
cp percona-xtrabackup-2.0.0/bin/xtrabackup_51 /usr/bin/xtrabackup_51
cp percona-xtrabackup-2.0.0/bin/xtrabackup_55 /usr/bin/xtrabackup_55
Percona-xtrabackup
(3)MYSQL数据库全备份,如图16-2(a)、16-2(b)所示:
innobackupex --user=root --password=123456 /data/backup/mysql/

图16-2(a) Innobackupex完整备份

图16-2(b) Innobackupex完整备份
(4)Innobackupex数据库恢复,恢复前先保证数据一致性,执行如下命令,如图16-3所示:
innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 --apply-log  /data/backup/mysql/2014-12-20_00-10-24

图16-3 Innobackupex apply-log恢复
通常数据库备份完成后,数据尚不能直接用于恢复操作,因为备份的数据时是一个过程,在备份过程中,有任务会写入数据,可能会包含尚未提交的事务或已经提交但尚未同步至数据文件中的事务。
因此此时数据文件仍处理不一致状态,基于--apply-log可以通过回滚未提交的事务及同步已经提交的事务至数据文件使数据文件处于一致性状态,方可进行恢复数据。
Apply-log过程可以在任何机器上运行,没有强制在线上或者备份库上运行,可以把备份复制在闲置的服务器上去运行,以此来降低备份库的压力,必须保证backup和apply-log所使用的mysqlbackup的版本要一致。
(5)删除原数据目录/var/lib/mysql数据,使用参数--copy-back恢复完整数据,授权mysql用户给所有的数据库文件,如图16-4所示:
rm -rf /var/lib/mysql/*
innobackupex --defaults-file=/etc/my.cnf --user=mysql --password=123456 --copy-back /data/backup/mysql/2014-12-20_00-10-24/
chown –R mysql:mysql /var/lib/mysql/

图16-4 Innobackupex 数据恢复
查看数据库恢复信息,数据完全恢复,如图16-5所示:

图16-5 Innobackupex 数据恢复
16.5 Innobackupex增量备份
增量备份仅能应用于InnoDB或XtraDB表,对于MyISAM表而言,执行增量备份时其实进行的是完全备份。
(1)增量备份之前必须执行完全备份,如图16-6所示:
innobackupex --user=root --password=123456 --databases=wugk01 /data/backup/mysql/

图16-6 Innobackupex 完整备份
(2)执行第一次增量备份:
innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 --databases=wugk01 --incremental /data/backup/mysql/ --incremental-basedir=/data/backup/mysql/2014-12-20_13-01-43/
增量备份完后,会在/data/backup/mysql/目录下生成新的备份目录,如图16-7所示:

图16-7 Innobackupex 增量备份
(3)数据库插入新数据,如图16-8所示:

图16-8 数据库insert into新数据
(4)执行第二次增量备份,备份命令如下,如图16-9(a)、16-9(b):
innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 --databases=wugk01 --incremental /data/backup/mysql/ --incremental-basedir=/data/backup/mysql/2014-12-20_13-07-31/

图16-9(a)数据库增量备份

图16-9(b)数据库增量备份
16.6 Mysql增量备份恢复
删除原数据库中表及数据记录信息,如图16-10所示:

图16-10 删除数据库表信息
MYSQL增量备份数据恢复方法如下步骤:
(1)基于Apply-log确保数据一致性:
innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 --apply-log --redo-only /data/backup/mysql/2014-12-20_13-01-43/
(2)执行第一次增量数据恢复:
innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 --apply-log --redo-only /data/backup/mysql/2014-12-20_13-01-43/ --incremental-dir=/data/backup/mysql/2014-12-20_13-07-31/
(3)执行第二次增量数据恢复:
innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 --apply-log --redo-only /data/backup/mysql/2014-12-20_13-01-43/ --incremental-dir=/data/backup/mysql/2014-12-20_13-11-20/
(4)执行完整数据恢复:
innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 --copy-back /data/backup/mysql/2014-12-20_13-01-43/
(5)测试数据库已完全恢复,如图16-11所示:

图16-11 数据库表信息完整恢复
第17章 Shell企业编程基础
说到Shell编程,很多从事Linux运维工作的朋友都不陌生,都对Shell有基本的了解,读者可能刚开始接触Shell的时候,有各种想法,感觉编程非常困难,SHELL编程是所有编程语言中最容易上手,最容易学习的编程脚本语言。
本章向读者介绍Shell编程入门、Shell编程变量、If、While、For、Case、Select基本语句案例演练及Shell编程四剑客Find、Grep、Awk、Sed深度剖析等。
17.1 SHELL编程入门简介
曾经有人说过,学习Linux不知道Shell编程,那就是不懂Linux,现在细细品味确实是这样。Shell是操作系统的最外层,Shell可以合并编程语言以控制进程和文件,以及启动和控制其它程序。
Shell 通过提示您输入,向操作系统解释该输入,然后处理来自操作系统的任何结果输出,简单来说Shell就是一个用户跟操作系统之间的一个命令解释器。
Shell是用户与Linux操作系统之间沟通的桥梁,用户可以输入命令执行,又可以利用 Shell脚本编程去运行,如图17-1所示:
图17-1 Shell、用户及Kernel位置关系
Linux Shell种类非常多,常见的SHELL如下:
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)
不同的Shell语言的语法有所不同,一般不能交换使用,最常用的shell是Bash,也就是Bourne Again Shell。Bash由于易用和免费,在日常工作中被广泛使用,也是大多数Linux操作系统默认的Shell环境。
Shell、Shell编程、Shell脚本、Shell命令之前都有什么区别呢?简单来说Shell是一个整体的概念,Shell编程与Shell脚本统称为Shell编程,Shell命令是Shell编程底层具体的语句和实现方法。
17.2 SHELL脚本及Hello World
要熟练掌握Shell编程语言,需要大量的练习,初学者可以用Shell打印“Hello World”字符,寓意着开始新的启程!
Shell脚本编程需要如下几个事项:
Shell脚本名称命名一般为英文、大写、小写;
不能使用特殊符号、空格来命名;
Shell脚本后缀以.sh结尾;
不建议Shell命名为纯数字,一般以脚本功能命名。
Shell脚本内容首行需以#!/bin/bash开头;
Shell脚本中变量名称尽量使用大写字母,字母间不能使用“-”,可以使用“_”;
Shell脚本变量名称不能以数字、特殊符号开头。
如下为第一个Shell编程脚本,脚本名称为:first_shell.sh,代码内容如下:

!/bin/bash

This is my First shell

By author jfedu.net 2017

echo “Hello World ”
First_shell.sh脚本内容详解如下:

!/bin/bash 固定格式,定义该脚本所使用的Shell类型;

This is my First shell #号表示注释,没有任何的意义,SHELL不会解析它;

By author jfedu.net 2017 表示脚本创建人,#号表示注解;

echo “Hello World !” Shell脚本主命令,执行该脚本呈现的内容。
Shell脚本编写完毕,如果运行该脚本,运行用户需要有执行权限,可以使用chmod o+x first_shell.sh赋予可执行权限。然后./first_shell.sh执行即可,还可以直接使用命令执行: /bin/sh firstshell.sh直接运行脚本,不需要执行权限,最终脚本执行显示效果一样。
初学者学习Shell编程,可以将在Shell终端运行的各种命令依次写入到脚本内容中,可以把Shell脚本当成是Shell命令的堆积。
17.3 Shell编程之变量详解
Shell变量是非类型的解释型语言,不像C++、JAVA语言编程时需要事先声明变量,Shell给一个变量赋值,实际上就是定义了变量,在Linux支持的所有shell中,都可以用赋值符号(=)为变量赋值,Shell变量为弱类型,定义变量不需要声明类型,但在使用时需要明确变量的类型,可以使用Declare指定类型,Declare常见参数有:
+/- "-"可用来指定变量的属性,"+"为取消变量所设的属性;
-f  仅显示函数;
r  将变量设置为只读;
x  指定的变量会成为环境变量,可供shell以外的程序来使用;
i  指定类型为数值,字符串或运算式。
Shell编程中变量分为三种,分别是系统变量、环境变量和用户变量,其中系统变量在对参数判断和命令返回值判断时使用,而环境变量则主要是在程序运行时需要设置,用户变量又称为局部变量,多使用在Shell脚本内部或者临时局部使用。
Shell变量名在定义时,首个字符必须为字母(a-z,A-Z),不能以数字开头,中间不能有空格,可以使用下划线(
),不能使用(-),也不能使用标点符号等。
例如定义变量A=jfedu.net,定义这样一个变量,A为变量名,jfedu.net是变量的值,变量名有格式规范,变量的值可以随意指定。变量定义完成,如需要引用变量,可以使用$A。
如下脚本var.sh脚本内容如下:

!/bin/bash

By author jfedu.net 2017

A=123
echo “Printf variables is $A.”
执行该Shell脚本,结果将会显示:Printf variables is jfedu.net。Shell常见的系统变量、环境变量、用户变量详解如下:
(1)SHELL编程常见系统变量:
$0 当前脚本的名称;
$n 当前脚本的第n个参数,n=1,2,…9;
$* 当前脚本的所有参数(不包括程序本身);
$# 当前脚本的参数个数(不包括程序本身);
$? 命令或程序执行完后的状态,返回0表示执行成功;
$$ 程序本身的PID号。
(2)SHELL编程常见环境变量:
PATH 命令所示路径,以冒号为分割;
HOME 打印用户家目录;
SHELL 显示当前Shell类型;
USER 打印当前用户名;
ID 打印当前用户id信息;
PWD 显示当前所在路径;
TERM 打印当前终端类型;
HOSTNAME 显示当前主机名。
(3)SHELL编程用户变量:
A=jfedu.net 自定义变量A;
N_SOFT=nginx-1.12.0.tar.gz 自定义变量N_SOFT;
BACK_DIR=/data/backup/ 自定义变量BACK_DIR;
IP1=192.168.1.11 自定义变量IP1;
IP2=192.168.1.12 自定义变量IP2。
创建Echo打印菜单Shell脚本,脚本代码如下:

!/bin/bash

auto install httpd

By author jfedu.net 2017

echo -e '\033[32m-----------------------------\033[0m'
FILE=httpd-2.2.31.tar.bz2
URL=http://mirrors.cnnic.cn/apache/httpd/
PREFIX=/usr/local/apache2/
echo -e "\033[36mPlease Select Install Menu:\033[0m"
echo
echo "1)官方下载Httpd文件包."
echo "2)解压apache源码包."
echo "3)编译安装Httpd服务器."
echo "4)启动HTTPD服务器."
echo -e '\033[32m-----------------------------\033[0m'
sleep 20
运行脚本,执行结果如图17-2所示:

图17-2 Echo打印菜单脚本
17.4 If条件语句实战
Linux Shell编程中,if、for、while、case等条件流程控制语句用的非常多,熟练掌握以上流程控制语句及语法的实验,对编写Shel脚本有非常大的益处。
If条件判断语句,通常以if开头,fi结尾。也可加入else或者elif进行多条件的判断,if表达式如下:
if (表达式)
语句1
else
语句2
fi
If语句Shell脚本编程案例如下:
(1)比较两个整数大小。

!/bin/bash

By author jfedu.net 2017

NUM=100
if (( $NUM > 4 )) ;then
echo “The Num $NUM more than 4.”
else
echo “The Num $NUM less than 4.”
fi
(2)判断系统目录是否存在。

!/bin/bash

judge DIR or Files

By author jfedu.net 2017

if [ ! -d /data/20140515 -a ! -d /tmp/2017/ ];then
mkdir -p /data/20140515
fi
If常见判断逻辑运算符详解:
-f 判断文件是否存在 eg: if [ -f filename ];
-d 判断目录是否存在 eg: if [ -d dir ];
-eq 等于,应用于整型比较 equal;
-ne 不等于,应用于整型比较 not equal;
-lt 小于,应用于整型比较 letter;
-gt 大于,应用于整型比较 greater;
-le 小于或等于,应用于整型比较;
-ge 大于或等于,应用于整型比较;
-a 双方都成立(and) 逻辑表达式 –a 逻辑表达式;
-o 单方成立(or) 逻辑表达式 –o 逻辑表达式;
-z 空字符串;
|| 单方成立;
&& 双方都成立表达式。
(3)if多个条件测试分数判断。

!/bin/bash

By author jfedu.net 2017

scores=$1
if [[ $scores -eq 100 ]]; then
    echo "very good!";
elif [[ $scores -gt 85 ]]; then
    echo "good!";
elif [[ $scores -gt 60 ]]; then
    echo "pass!";
elif [[ $scores -lt 60 ]]; then
    echo "no pass!"
fi
17.5 If判断括号区别
在使用if语句时,经常会使用()、(())、[]、[[]]、{}等括号,如下为几种括号简单区别对比:
( )
用于多个命令组、命令替换、初始化数组;
(( ))
整数扩展、运算符、重定义变量值,算术运算比较;
[]
bash内部命令,[与test是等同的,正则字符范围、引用数组元素编号,不支持+-/数学运算符,逻辑测试使用-a、-o。
[[ ]]
bash程序语言的关键字,不是一个命令,[[ ]]结构比[ ]结构更加通用,不支持+-
/数学运算符,逻辑测试使用&&、||。
{}
主要用于命令集合或者范围,例如mkdir -p /data/201{7,8}/
17.6 MySQL数据库备份脚本
MySQL数据库备份是运维工程师的工作之一,如下为自动备份Mysql数据库脚本。

!/bin/bash

auto backup mysql

By author jfedu.net 2017

Define PATH定义变量

BAK_DIR=/data/backup/mysql/date +%Y-%m-%d
MYSQLDB=webapp
MYSQLPW=backup
MYSQLUSR=backup

must use root user run scripts 必须使用root用户运行,$UID为系统变量

if
[ $UID -ne 0 ];then
echo This script must use the root user ! ! !
sleep 2
exit 0
fi

Define DIR and mkdir DIR 判断目录是否存在,不存在则新建

if
[ ! -d $BAKDIR ];then
mkdir -p $BAKDIR
fi

Use mysqldump backup Databases

/usr/bin/mysqldump -u$MYSQLUSR -p$MYSQLPW -d $MYSQLDB >$BAKDIR/webapp_db.sql
echo "The mysql backup successfully "
17.7 LAMP一键自动化安装脚本
通过前面章节对if语句和变量的学习,现基于所学知识,编写一键源码安装LAMP脚本,
编写脚本可以养成先分解脚本的各个功能的习惯,有利于快速写出脚本,写出更高效的脚本。
一键源码安装LAMP脚本,可以拆分为如下功能:
(1)LAMP打印菜单:
安装apache WEB服务器;
安装Mysql DB服务器;
安装PHP 服务器;
整合LAMP架构
启动LAMP服务;
(2)Apache服务器安装部署:
Apache官网下载httpd-2.2.31.tar.gz版本,解压,进入安装目录,configure、make 、make install。
(3)Mysql服务器的安装:
Mysql官网下载mysql-5.5.20.tar.gz版本,解压,进入安装目录,configure、make 、make install。
(4)PHP服务器安装:
PHP官网下载php-5.3.8.tar.gz版本,解压,进入安装目录,configure、make 、make install。
(5)LAMP整合及服务启动:
vi /usr/local/apache2/htdocs/index.php
<?php
phpinfo();
?>
/usr/local/apache2/bin/apachectl restart
service mysqld restart
一键源码安装LAMP脚本,auto_install_lamp.sh内容如下:

!/bin/bash

auto install LAMP

By author jfedu.net 2017

Httpd define path variable

H_FILES=httpd-2.2.31.tar.bz2
H_FILES_DIR=httpd-2.2.31
H_URL=http://mirrors.cnnic.cn/apache/httpd/httpd-2.2.31.tar.bz2
H_PREFIX=/usr/local/apache2/

MySQL define path variable

M_FILES=mysql-5.5.20.tar.gz
M_FILES_DIR=mysql-5.5.20
M_URL=http://down1.chinaunix.net/distfiles/ mysql-5.5.20.tar.gz
M_PREFIX=/usr/local/mysql/

PHP define path variable

P_FILES=php-5.3.28.tar.bz2
P_FILES_DIR=php-5.3.28
P_URL=http://mirrors.sohu.com/php/
P_PREFIX=/usr/local/php5/
echo -e '\033[32m-----------------------------\033[0m'
echo
if [ -z "$1" ];then
echo -e "\033[36mPlease Select Install Menu follow:\033[0m"
echo -e "\033[32m
1)编译安装Apache服务器\033[1m"
echo "2)编译安装MySQL服务器"
echo "3)编译安装PHP服务器"
echo "4)配置index.php并启动LAMP服务"
echo -e "\033[31mUsage: { /bin/sh $0 1|2|3|4|help}\033[0m"
exit
fi
if [[ "$1" -eq "help" ]];then
echo -e "\033[36mPlease Select Install Menu follow:\033[0m"
echo -e "\033[32m1)编译安装Apache服务器\033[1m"
echo "2)编译安装MySQL服务器"
echo "3)编译安装PHP服务器"
echo "4)配置index.php并启动LAMP服务"
echo -e "\033[31mUsage: { /bin/sh $0 1|2|3|4|help}\033[0m"
exit
fi

Install httpd web server

if [[ "$1" -eq "1" ]];then
wget -c $H_URL/$H_FILES && tar -jxvf $H_FILES && cd $H_FILES_DIR &&./configure --prefix=$H_PREFIX
if [ $? -lt 0 ];then
make && make install
fi
fi

Install Mysql DB server

if [[ "$1" -eq "2" ]];then
wget -c $M_URL/$M_FILES && tar -xzvf $M_FILES && cd $M_FILES_DIR &&yum install cmake -y ;cmake . -DCMAKE_INSTALL_PREFIX=$M_PREFIX \
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \
-DMYSQL_DATADIR=/data/mysql \
-DSYSCONFDIR=/etc \
-DMYSQL_USER=mysql \
-DMYSQL_TCP_PORT=3306 \
-DWITH_XTRADB_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_EXTRA_CHARSETS=1 \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=all \
-DWITH_BIG_TABLES=1 \
-DWITH_DEBUG=0
make && make install
/bin/cp support-files/my-small.cnf /etc/my.cnf
/bin/cp support-files/mysql.server /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
chkconfig --add mysqld
chkconfig mysqld on
if [ $? -eq 0 ];then
make && make install
echo -e "\n\033[32m-----------------------------------------------\033[0m"
echo -e "\033[32mThe $M_FILES_DIR Server Install Success !\033[0m"
else
echo -e "\033[32mThe $M_FILES_DIR Make or Make install ERROR,Please Check......"
exit 0
fi
fi

Install PHP server

if [[ "$1" -eq "3" ]];then
wget -c $P_URL/$P_FILES && tar -jxvf $P_FILES && cd $P_FILES_DIR &&./configure --prefix=$P_PREFIX --with-config-file-path=$P_PREFIX/etc --with-mysql=$M_PREFIX --with-apxs2=$H_PREFIX/bin/apxs
if [ $? -eq 0 ];then
make ZEND_EXTRA_LIBS='-liconv' && make install
echo -e "\n\033[32m-----------------------------------------------\033[0m"
echo -e "\033[32mThe $P_FILES_DIR Server Install Success !\033[0m"
else
echo -e "\033[32mThe $P_FILES_DIR Make or Make install ERROR,Please Check......"
exit 0
fi
fi
if [[ "$1" -eq "4" ]];then
sed -i '/DirectoryIndex/s/index.html/index.php index.html/g' $H_PREFIX/conf/httpd.conf
$H_PREFIX/bin/apachectl restart
echo "AddType application/x-httpd-php .php" >>$H_PREFIX/conf/httpd.conf
IP=ifconfig eth1|grep "Bcast"|awk '{print $2}'|cut -d: -f2
echo "You can access http://$IP/"
cat >$H_PREFIX/htdocs/index.php <<EOF
<?php
phpinfo();
?>
EOF
fi
17.8 For循环语句实战
for循环语句主要用于对某个数据域进行循环读取、对文件进行遍历,通常用于需要循环某个文件或者列表。其语法格式以for…do开头,done结尾。语法格式如下:
For var in (表达式)
do
语句1
done
For循环语句Shell脚本编程案例如下:
(1)循环打印BAT企业官网:

!/bin/bash

By author jfedu.net 2017

for website in www.baidu.com www.taobao.com www.qq.com
do
echo $website
done
(2)循环打印1至100数字,seq表示列出数据范围:

!/bin/bash

By author jfedu.net 2017

for i in seq 1 100
do
echo “NUM is $i”
done
(3)For循环求1-100的总和:

!/bin/bash

By author jfedu.net 2017

auto sum 1 100

j=0
for ((i=1;i<=100;i++))
do
j=expr $i + $j
done
echo $j
(4)对系统日志文件进行分组打包:

!/bin/bash

By author jfedu.net 2017

for i in find /var/log -name “*.log”
do
tar -czf 2017_log$i.tgz $i
done
(5)For循环批量远程主机文件传输:

!/bin/bash

auto scp files for client

By author jfedu.net 2017

for i in seq 100 200
do
scp -r /tmp/jfedu.txt root@192.168.1.$i:/data/webapps/www
done
(6)For循环批量远程主机执行命令:

!/bin/bash

auto scp files for client

By author jfedu.net 2017

for i in seq 100 200
do
ssh -l root 192.168.1.$i ‘ls /tmp’
done
(7)For循环打印10秒等待提示:
for ((j=0;j<=10;j++))
do
echo -ne "\033[32m-\033[0m"
sleep 1
done
echo
17.9 While循环语句实战
While循环语句与for循环功能类似,主要用于对某个数据域进行循环读取、对文件进行遍历,通常用于需要循环某个文件或者列表,满足循环条件会一直循环,不满足则退出循环,其语法格式以while…do开头,done结尾。语法格式如下:
while (表达式)
do
语句1
done
While循环语句Shell脚本编程案例如下:
(1)循环打印BAT企业官网,read指令用于读取行或者读取变量:

!/bin/bash

By author jfedu.net 2017

while read line
do
echo $line
done <jfedu.txt
其中jfedu.txt内容为:
www.baidu.com
www.taobao.com
www.qq.com
(2)While无限每秒输出Hello World:

!/bin/bash

By author jfedu.net 2017

while sleep 1
do
echo -e "\033[32mHello World.\033[0m"
done
其中jfedu.txt内容为:
www.baidu.com
www.taobao.com
www.qq.com
(3)循环打印1至100数字,expr用于运算逻辑工具:

!/bin/bash

By author jfedu.net 2017

i=0
while ((i<=100))
do
echo $i
i=expr $i + 1
done
(4)While循环求1-100的总和:

!/bin/bash

By author jfedu.net 2017

auto sum 1 100

j=0
i=1
while ((i<=100))
do
j=expr $i + $j
((i++))
done
echo $j
(5)While循环逐行读取文件:

!/bin/bash

By author jfedu.net 2017

while read line
do
echo $line;
done < /etc/hosts
(6)While循环判断输入IP正确性:

!/bin/bash

By author jfedu.net 2017

Check IP Address

read -p "Please enter ip Address,example 192.168.0.11 ip": IPADDR
echo $IPADDR|grep -v "[Aa-Zz]"|grep --color -E "([0-9]{1,3}\.){3}[0-9]{1,3}"
while [ $? -ne 0 ]
do
read -p "Please enter ip Address,example 192.168.0.11 ip": IPADDR
echo $IPADDR|grep -v "[Aa-Zz]"|grep --color -E "([0-9]{1,3}.){3}[0-9]{1,3}"
done
(7)每5秒循环判断/etc/passwd是否被非法修改:

!/bin/bash

Check File to change.

By author jfedu.net 2017

FILES="/etc/passwd"
while true
do
echo "The Time is date +%F-%T"
OLD=md5sum $FILES|cut -d" " -f 1
sleep 5
NEW=md5sum $FILES|cut -d" " -f 1
if [[ $OLD != $NEW ]];then
echo "The $FILES has been modified."
fi
done
(8)每10秒循环判断jfedu用户是否登录系统:

!/bin/bash

Check File to change.

By author jfedu.net 2017

USERS="jfedu"
while true
do
echo "The Time is date +%F-%T"
sleep 10
NUM=who|grep "$USERS"|wc -l
if [[ $NUM -ge 1 ]];then
echo "The $USERS is login in system."
fi
done
17.10 Case选择语句实战
Case选择语句,主要用于对多个选择条件进行匹配输出,与if elif语句结构类似,通常用于脚本传递输入参数,打印出输出结果及内容,其语法格式以Case…in开头,esac结尾。语法格式如下:

!/bin/bash

By author jfedu.net 2017

case $1 in
Pattern1)
语句1
;;
Pattern2)
语句2
;;
Pattern3)
语句3
;;
esac
Case条件语句Shell脚本编程案例如下:
(1)打印Monitor及Archive选择菜单:

!/bin/bash

By author jfedu.net 2017

case $1 in
monitor)
monitor_log
;;
archive)
archive_log
;;
help )
echo –e "\033[32mUsage:{$0 monitor | archive |help }\033[0m"
;;
*)
echo –e "\033[32mUsage:{$0 monitor | archive |help }\033[0m "
esac
(2)自动修改IP脚本菜单:

!/bin/bash

By author jfedu.net 2017

case $i in
modify_ip)
change_ip
;;
modify_hosts)
change_hosts
;;
exit)
exit
;;
*)
echo -e "1) modify_ip\n2) modify_ip\n3)exit"
esac
17.11 Select选择语句实战
Select语句一般用于选择,常用于选择菜单的创建,可以配合PS3来做打印菜单的输出信息,其语法格式以selct…in do开头,done结尾:
select i in (表达式)
do
语句
done
Select选择语句Shell脚本编程案例如下:
(1)打印开源操作系统选择:

!/bin/bash

By author jfedu.net 2017

PS3="What you like most of the open source system?"
select i in CentOS RedHat Ubuntu
do
echo "Your Select System: "$i
done
(2)打印LAMP选择菜单

!/bin/bash

By author jfedu.net 2017

PS3="Please enter you select install menu:"
select i in http php mysql quit
do
case $i in
http)
echo Test Httpd.
;;
php)
echo Test PHP.
;;
mysql)
echo Test MySQL.
;;
quit)
echo The System exit.
exit
esac
done
17.12 Shell编程函数实战
Shell允许将一组命令集或语句形成一个可用块,这些块称为Shell函数,Shell函数的用于在于只需定义一次,后期随时使用即可,无需在Shell脚本中添加重复的语句块,其语法格式以function name(){开头,以}结尾。
Shell编程函数默认不能将参数传入()内部,Shell函数参数传递在调用函数名称传递,例如name args1 args2。
function name (){
command1
command2
........
}
name args1 args2
(1)创建Apache软件安装函数,给函数Apache_install传递参数1:

!/bin/bash

auto install LAMP

By author jfedu.net 2017

Httpd define path variable

H_FILES=httpd-2.2.31.tar.bz2
H_FILES_DIR=httpd-2.2.31
H_URL=http://mirrors.cnnic.cn/apache/httpd/
H_PREFIX=/usr/local/apache2/
function Apache_install()
{

Install httpd web server

if [[ "$1" -eq "1" ]];then
wget -c $H_URL/$H_FILES && tar -jxvf $H_FILES && cd $H_FILES_DIR &&./configure --prefix=$H_PREFIX
if [ $? -eq 0 ];then
make && make install
echo -e "\n\033[32m-----------------------------------------------\033[0m"
echo -e "\033[32mThe $H_FILES_DIR Server Install Success !\033[0m"
else
echo -e "\033[32mThe $H_FILES_DIR Make or Make install ERROR,Please Check......"
exit 0
fi
fi
}
Apache_install 1
(2)创建judge_ip判断IP函数:

!/bin/bash

By author jfedu.net 2017

judge_ip(){
read -p "Please enter ip Address,example 192.168.0.11 ip": IPADDR
echo $IPADDR|grep -v "[Aa-Zz]"|grep --color -E "([0-9]{1,3}.){3}[0-9]{1,3}"
}
judge_ip
17.13 Shell编程四剑客之Find
通过如上基础语法的学习,读者对Shell编程有了更近一步的理解,Shell编程不再是简单命令的堆积,而是演变成了各种特殊的语句、各种语法、编程工具、各种命令的集合。
在Shell编程工具中,四剑客工具的使用更加的广泛,Shell编程四剑客包括:find、sed、grep、awk,熟练掌握四剑客会对Shell编程能力极大的提升。
四剑客之Find工具实战,Find工具主要用于操作系统文件、目录的查找,其语法参数格式为:
find path -option [ -print ] [ -exec -ok command ] { } \;
其option常用参数详解如下:
-name filename #查找名为filename的文件;
-type b/d/c/p/l/f #查是块设备、目录、字符设备、管道、符号链接、普通文件;
-size n[c] #查长度为n块[或n字节]的文件;
-perm #按执行权限来查找;
-user username #按文件属主来查找;
-group groupname #按组来查找;
-mtime -n +n #按文件更改时间来查找文件,-n指n天以内,+n指n天以前;
-atime -n +n #按文件访问时间来查找文件;
-ctime -n +n #按文件创建时间来查找文件;
-mmin -n +n #按文件更改时间来查找文件,-n指n分钟以内,+n指n分钟以前;
-amin -n +n #按文件访问时间来查找文件;
-cmin -n +n #按文件创建时间来查找文件;
-nogroup #查无有效属组的文件;
-nouser #查无有效属主的文件;
-newer f1 !f2 #找文件,-n指n天以内,+n指n天以前;
-depth #使查找在进入子目录前先行查找完本目录;
-fstype #查更改时间比f1新但比f2旧的文件;
-mount #查文件时不跨越文件系统mount点;
-follow #如果遇到符号链接文件,就跟踪链接所指的文件;
-cpio #查位于某一类型文件系统中的文件;
-prune #忽略某个目录;
-maxdepth #查找目录级别深度。
(1)Find工具-name参数案列:
find /data/ -name ".txt" #查找/data/目录以.txt结尾的文件;
find /data/ -name "[A-Z]
" #查找/data/目录以大写字母开头的文件;
find /data/ -name "test" #查找/data/目录以test开头的文件;
(2)Find工具-type参数案列:
find /data/ -type d #查找/data/目录下的文件夹;
find /data/ ! -type d #查找/data/目录下的非文件夹;
find /data/ -type l #查找/data/目录下的链接文件。
find /data/ -type d|xargs chmod 755 -R #查目录类型并将权限设置为755;
find /data/ -type f|xargs chmod 644 -R #查文件类型并将权限设置为644;
(3)Find工具-size参数案列:
find /data/ -size +1M #查文件大小大于1Mb的文件;
find /data/ -size 10M #查文件大小为10M的文件;
find /data/ -size -1M #查文件大小小于1Mb的文件;
(4)Find工具-perm参数案列:
find /data/ -perm 755 #查找/data/目录权限为755的文件或者目录;
find /data/ -perm -007 #与-perm 777相同,表示所有权限;
find /data/ -perm +644 #文件权限符号644以上;
(5)Find工具-mtime参数案列:
atime,access time 文件被读取或者执行的时间;
ctime,change time 文件状态改变时间;
mtime,modify time 文件内容被修改的时间;
find /data/ -mtime +30 -name "
.log" #查找30天以前的log文件;
find /data/ -mtime -30 -name ".txt" #查找30天以内的log文件;
find /data/ -mtime 30 -name "
.txt" #查找第30天的log文件;
find /data/ -mmin +30 -name ".log" #查找30分钟以前修改的log文件;
find /data/ -amin -30 -name "
.txt" #查找30分钟以内被访问的log文件;
find /data/ -cmin 30 -name "*.txt" #查找第30分钟改变的log文件。
(6)Find工具参数综合案列:

查找/data目录以.log结尾,文件大于10k的文件,同时cp到/tmp目录;

find /data/ -name "*.log" –type f -size +10k -exec cp {} /tmp/ \;

查找/data目录以.txt结尾,文件大于10k的文件,权限为644并删除该文件;

find /data/ -name "*.log" –type f -size +10k -m perm 644 -exec rm –rf {} \;

查找/data目录以.log结尾,30天以前的文件,大小大于10M并移动到/tmp目录;

find /data/ -name ".log" –type f -mtime +30 –size +10M -exec mv {} /tmp/ \;
17.14 Shell编程四剑客之SED
SED是一个非交互式文本编辑器,它可对文本文件和标准输入进行编辑,标准输入可以来自键盘输入、文本重定向、字符串、变量,甚至来自于管道的文本,与VIM编辑器类似,它一次处理一行内容,Sed可以编辑一个或多个文件,简化对文件的反复操作、编写转换程序等。
在处理文本时把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),紧接着用SED命令处理缓冲区中的内容,处理完成后把缓冲区的内容输出至屏幕或者写入文件。
逐行处理直到文件末尾,然而如果打印在屏幕上,实质文件内容并没有改变,除非你使用重定向存储输出或者写入文件。其语法参数格式为:
sed [-Options] [‘Commands’] filename;
sed工具默认处理文本,文本内容输出屏幕已经修改,但是文件内容其实没有修改,需要加-i参数即对文件彻底修改;
x #x为指定行号;
x,y #指定从x到y的行号范围;
/pattern/ #查询包含模式的行;
/pattern/pattern/ #查询包含两个模式的行;
/pattern/,x #从与pattern的匹配行到x号行之间的行;
x,/pattern/ #从x号行到与pattern的匹配行之间的行;
x,y! #查询不包括x和y行号的行;
r #从另一个文件中读文件;
w #将文本写入到一个文件;
y #变换字符;
q #第一个模式匹配完成后退出;
l #显示与八进制ASCII码等价的控制字符;
{} #在定位行执行的命令组;
p #打印匹配行;
= #打印文件行号;
a\ #在定位行号之后追加文本信息;
i\ #在定位行号之前插入文本信息;
d #删除定位行;
c\ #用新文本替换定位文本;
s #使用替换模式替换相应模式;
n #读取下一个输入行,用下一个命令处理新的行;
N #将当前读入行的下一行读取到当前的模式空间。
h #将模式缓冲区的文本复制到保持缓冲区;
H #将模式缓冲区的文本追加到保持缓冲区;
x #互换模式缓冲区和保持缓冲区的内容;
g #将保持缓冲区的内容复制到模式缓冲区;
G #将保持缓冲区的内容追加到模式缓冲区。
常用SED工具企业演练案列:
(1)替换jfedu.txt文本中old为new:
sed 's/old/new/g' jfedu.txt
(2)打印jfedu.txt文本第一行至第三行:
sed -n '1,3p' jfedu.txt
(3)打印jfedu.txt文本中第一行与最后一行:
sed -n '1p;$p' jfedu.txt
(4)删除jfedu.txt第一行至第三行、删除匹配行至最后一行:
sed '1,3d' jfedu.txt
sed '/jfedu/,$d' jfedu.txt
(5)删除jfedu.txt最后6行及删除最后一行:
for i in seq 1 6;do sed -i '$d' jfedu.txt ;done
sed '$d' jfedu.txt
(6)删除jfedu.txt最后一行:
sed '$d' jfedu.txt
(7)在jfedu.txt查找jfedu所在行,并在其下一行添加word字符,a表示在其下一行添加字符串:
sed '/jfedu/aword' jfedu.txt
(8)在jfedu.txt查找jfedu所在行,并在其上一行添加word字符,i表示在其上一行添加字符串:
sed '/jfedu/iword' jfedu.txt
(9)在jfedu.txt查找以test结尾的行尾添加字符串word,$表示结尾标识,&在Sed中表示添加:
sed 's/test$/&word/g' jfedu.txt
(10)在jfedu.txt查找www的行,在其行首添加字符串word,^表示起始标识,&在Sed中表示添加:
sed '/www/s/^/&word/' jfedu.txt
(11)多个sed命令组合,使用-e参数:
sed -e '/www.jd.com/s/^/&1./' -e 's/www.jd.com$/&./g' jfedu.txt
(12)多个sed命令组合,使用分号“;”分割:
sed -e '/www.jd.com/s/^/&1./;s/www.jd.com$/&./g' jfedu.txt
(13)Sed读取系统变量,变量替换:
WEBSITE=WWW.JFEDU.NET
Sed “s/www.jd.com/$WEBSITE/g” jfedu.txt
(14)修改Selinux策略enforcing为disabled,查找/SELINUX/行,然后将其行enforcing值改成disabled、!s表示不包括SELINUX行:
sed -i '/SELINUX/s/enforcing/disabled/g' /etc/selinux/config
sed -i '/SELINUX/!s/enforcing/disabled/g' /etc/selinux/config
通常而言,SED将待处理的行读入模式空间,脚本中的命令逐行进行处理,直到脚本执行完毕,然后该行被输出,模式空间请空;然后重复刚才的动作,文件中的新的一行被读入,直到文件处理完备。
如果用户希望在某个条件下脚本中的某个命令被执行,或者希望模式空间得到保留以便下一次的处理,都有可能使得sed在处理文件的时候不按照正常的流程来进行。这时可以使用SED高级语法来满足用户需求。总的来说,SED高级命令可以分为三种功能:
N、D、P:处理多行模式空间的问题;
H、h、G、g、x:将模式空间的内容放入存储空间以便接下来的编辑;
:、b、t:在脚本中实现分支与条件结构。
(1)在jfedu.txt每行后加入空行,也即每行占永两行空间,每一行后边插入一行空行、两行空行及前三行每行后插入空行:
sed '/^$/d;G' jfedu.txt
sed '/^$/d;G;G' jfedu.txt
sed '/^$/d;1,3G;' jfedu.txt
(2)将jfedu.txt偶数行删除及隔两行删除一行:
sed 'n;d' jfedu.txt
sed 'n;n;d' jfedu.txt
(3)在jfedu.txt匹配行前一行、后一行插入空行以及同时在匹配前后插入空行:
sed '/jfedu/{x;p;x;}' jfedu.txt
sed '/jfedu/G' jfedu.txt
sed '/jfedu/{x;p;x;G;}' jfedu.txt
(4)在jfedu.txt每行后加入空行,也即每行占永两行空间,每一行后边插入空行:
sed '/^$/d;G' jfedu.txt
(5)在jfedu.txt每行后加入空行,也即每行占永两行空间,每一行后边插入空行:
sed '/^$/d;G' jfedu.txt
(6)在jfedu.txt每行前加入顺序数字序号、加上制表符\t及.符号:
sed = jfedu.txt| sed 'N;s/\n/ /'
sed = jfedu.txt| sed 'N;s/\n/\t/'
sed = jfedu.txt| sed 'N;s/\n/./'
(7)删除jfedu.txt行前和行尾的任意空格:
sed 's/^[ \t]
//;s/[ \t]*$//' jfedu.txt
(8)打印jfedu.txt关键词old与new之间的内容:
sed -n '/old/,/new/'p jfedu.txt
(9)打印及删除jfedu.txt最后两行:
sed '$!N;$!D' jfedu.txt
sed 'N;$!P;$!D;$d' jfedu.txt
(10)合并上下两行,也即两行合并:
sed '$!N;s/\n/ /' jfedu.txt
sed 'N;s/\n/ /' jfedu.txt
17.15 Shell编程四剑客之AWK
AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一,以Aho、Weinberger、Kernighan三位发明者名字首字母命名为AWK,AWK是一个行级文本高效处理工具,AWK经过改进生成的新的版本有Nawk、Gawk,一般Linux默认为Gawk,Gawk是 AWK的GNU开源免费版本。
AWK基本原理是逐行处理文件中的数据,查找与命令行中所给定内容相匹配的模式,如果发现匹配内容,则进行下一个编程步骤,如果找不到匹配内容,则 继续处理下一行。其语法参数格式为,AWK常用参数、变量、函数详解如下:
awk 'pattern + {action}' file
(1)AWK基本语法参数详解:
单引号' '是为了和shell命令区分开;
大括号{ }表示一个命令分组;
pattern是一个过滤器,表示匹配pattern条件的行才进行Action处理;
action是处理动作,常见动作为Print;
使用#作为注释,pattern和action可以只有其一,但不能两者都没有。
(2)AWK内置变量详解:
FS 分隔符,默认是空格;
OFS 输出分隔符;
NR 当前行数,从1开始;
NF 当前记录字段个数;
$0 当前记录;
$1~$n 当前记录第n个字段(列)。
(3)AWK内置函数详解:
gsub(r,s):在$0中用s代替r;
index(s,t):返回s中t的第一个位置;
length(s):s的长度;
match(s,r):s是否匹配r;
split(s,a,fs):在fs上将s分成序列a;
substr(s,p):返回s从p开始的子串。
(4)AWK常用操作符,运算符及判断符:
++ -- 增加与减少( 前置或后置);
^ ** 指数( 右结合性);
! + - 非、一元(unary) 加号、一元减号;
+ - * / % 加、减、乘、除、余数;
< <= == != > >= 数字比较;
&& 逻辑and;
|| 逻辑or;
= += -= *= /= %= ^= **= 赋值。
(5)AWK与流程控制语句:
if(condition) { } else { };
while { };
do{ }while(condition);
for(init;condition;step){ };
break/continue。
常用AWK工具企业演练案列:
(1)AWK打印硬盘设备名称,默认以空格为分割:
df -h|awk '{print $1}'
(2)AWK以空格、冒号、\t、分号为分割:
awk -F '[ :\t;]' '{print $1}' jfedu.txt
(3)AWK以冒号分割,打印第一列,同时将内容追加到/tmp/awk.log下:
awk -F: '{print $1 >>"/tmp/awk.log"}' jfedu.txt
(4)打印jfedu.txt文件中的第3行至第5行,NR表示打印行,$0表示文本所有域:
awk 'NR==3,NR==5 {print}' jfedu.txt
awk 'NR==3,NR==5 {print $0}' jfedu.txt
(5)打印jfedu.txt文件中的第3行至第5行的第一列与最后一列:
awk 'NR==3,NR==5 {print $1,$NF}' jfedu.txt
(6)打印jfedu.txt文件中,长度大于80的行号:
awk 'length($0)>80 {print NR}' jfedu.txt
(7)AWK引用Shell变量,使用-v或者双引号+单引号即可:
awk -v STR=hello '{print STR,$NF}' jfedu.txt
STR="hello";echo| awk '{print "'${STR}'";}'
(8)AWK以冒号切割,打印第一列同时只显示前5行:
cat /etc/passwd|head -5|awk -F: '{print $1}'
awk -F: 'NR>=1&&NR<=5 {print $1}' /etc/passwd
(9)Awk指定文件jfedu.txt第一列的总和:
cat jfedu.txt |awk '{sum+=$1}END{print sum}'
(10)AWK NR行号除以2余数为0则跳过该行,继续执行下一行,打印在屏幕:
awk -F: 'NR%2==0 {next} {print NR,$1}' /etc/passwd
(11)AWK添加自定义字符:
ifconfig eth0|grep "Bcast"|awk '{print "ip_"$2}'
(12)AWK格式化输出passwd内容,printf打印字符串,%格式化输出分隔符,s表示字符串类型,-12表示12个字符,-6表示6个字符:
awk -F: '{printf "%-12s %-6s %-8s\n",$1,$2,$NF}' /etc/passwd
(13)AWK OFS输出格式化\t:
netstat -an|awk '$6 ~ /LISTEN/&&NR>=1&&NR<=10 {print NR,$4,$5,$6}' OFS="\t"
(14)AWK与if组合实战,判断数字比较:
echo 3 2 1 | awk '{ if(($1>$2)||($1>$3)) { print $2} else {print $1} }'
(15)AWK与数组组合实战,统计passwd文件用户数:
awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
(16)awk分析Nginx访问日志的状态码404、502等错误信息页面,统计次数大于20的IP地址。
awk '{if ($9~/502|499|500|503|404/) print $1,$9}' access.log|sort|uniq –c|sort –nr | awk '{if($1>20) print $2}'
(17)用/etc/shadow文件中的密文部分替换/etc/passwd中的"x"位置,生成新的/tmp/passwd文件。
awk 'BEGIN{OFS=FS=":"} NR==FNR{a[$1]=$2}NR>FNR{$2=a[$1];print >>"/tmp/passwd"}' /etc/shadow /etc/passwd
(18)Awk统计服务器状态连接数:
netstat -an | awk '/tcp/ {s[$NF]++} END {for(a in s) {print a,s[a]}}'
netstat -an | awk '/tcp/ {print $NF}' | sort | uniq -c
17.16 Shell编程四剑客之GREP
全面搜索正则表达式(Global search regular expression(RE) ,GREP)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
Unix/Linux的grep家族包括grep、egrep和fgrep,其中egrep和fgrep的命令跟grep有细微的区别,egrep是grep的扩展,支持更多的re元字符, fgrep是fixed grep或fast grep简写,它们把所有的字母都看作单词,正则表达式中的元字符表示其自身的字面意义,不再有其他特殊的含义,一般使用比较少。
目前Linux操作系统默认使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。其语法格式及常用参数详解如下:
grep -[acinv]   'word'   Filename
Grep常用参数详解如下:
-a 以文本文件方式搜索;
-c 计算找到的符合行的次数;
-i 忽略大小写;
-n 顺便输出行号;
-v 反向选择,即显示不包含匹配文本的所有行;
-h 查询多文件时不显示文件名;
-l 查询多文件时只输出包含匹配字符的文件名;
-s 不显示不存在或无匹配文本的错误信息;
-E 允许使用egrep扩展模式匹配。
学习Grep时,需要了解通配符、正则表达式两个概念,很多读者容易把彼此搞混淆,通配符主要用在Linux的Shell命令中,常用于文件或者文件名称的操作,而正则表达式用于文本内容中的字符串搜索和替换,常用在AWK、GREP、SED、VIM工具中对文本的操作。
通配符类型详解:

  •                   0个或者多个字符、数字;

    ? 匹配任意一个字符;

    表示注解;

    | 管道符号;
    ; 多个命令连续执行;
    & 后台运行指令;
    ! 逻辑运算非;
    [ ] 内容范围,匹配括号中内容;
    { } 命令块,多个命令匹配。
    正则表达式详解:

  • 前一个字符匹配0次或多次;
    . 匹配除了换行符以外任意一个字符;
    . 代表任意字符;
    ^ 匹配行首,即以某个字符开头;
    $ 匹配行尾,即以某个字符结尾;
    \(..\) 标记匹配字符;
    [] 匹配中括号里的任意指定字符,但只匹配一个字符;
    [^] 匹配除中括号以外的任意一个字符;
    \ 转义符,取消特殊含义;
    \< 锚定单词的开始;
    \> 锚定单词的结束;
    {n} 匹配字符出现n次;
    {n,} 匹配字符出现大于等于n次;
    {n,m} 匹配字符至少出现n次,最多出现m次;
    \w 匹配文字和数字字符;
    \W \w的反置形式,匹配一个或多个非单词字符;
    \b 单词锁定符;
    \s 匹配任何空白字符;
    \d 匹配一个数字字符,等价于[0-9]。
    常用GREP工具企业演练案列:
    grep -c "test" jfedu.txt 统计test字符总行数;
    grep -i "TEST" jfedu.txt 不区分大小写查找TEST所有的行;
    grep -n "test" jfedu.txt 打印test的行及行号;
    grep -v "test" jfedu.txt 不打印test的行;
    grep "test[53]" jfedu.txt 以字符test开头,接5或者3的行;
    grep "^[^test]" jfedu.txt 显示输出行首不是test的行;
    grep "[Mm]ay" jfedu.txt 匹配M或m开头的行;
    grep "K…D" jfedu.txt 匹配K,三个任意字符,紧接D的行;
    grep "[A-Z][9]D" jfedu.txt 匹配大写字母,紧跟9D的字符行;
    grep "T\{2,\}" jfedu.txt 打印字符T字符连续出现2次以上的行;
    grep "T\{4,6\}" jfedu.txt 打印字符T字符连续出现4次及6次的行;
    grep -n "^$" jfedu.txt 打印空行的所在的行号;
    grep -vE "#|^$" jfedu.txt 不匹配文件中的#和空行;
    grep --color -ra -E "db|config|sql"
    匹配包含db或者config或者sql的文件;
    grep --color -E "\<([0-9]{1,3}.){3}([0-9]{1,3})>" jfedu.txt 匹配IPV4地址。
    17.17 Shell数组编程
    数组是相同数据类型的元素按一定顺序排列的集合,把有限个类型相同的变量用一个名字命名,然后用编号区分他们变量的集合,这个名称称之为数组名,编号成为下标。Linux Shell编程中常用一维数组。
    数组的设计其实了为了处理方便,把具有相同类型的若干变量按有序的形式组织起来的一种形式,以减少重复频繁的单独定义。如图17-3所示:
    图17-3 一维、二维、三维数组
    定义数组一般以小括号的方式来定义,数组的值可以随机指定,如下为一维数组的定义、统计、引用和删除操作,:
    (1)一唯数组定义及创建:
    JFTEST=(
    test1
    test2
    test3
    )
    LAMP=(httpd php php-devel php-mysql mysql mysql-server)
    (2)数组下标一般从0开始,如下为引用数组的方法:
    echo ${JFTEST[0]} 引用第一个数组变量,结果打印test1;
    echo ${JFTEST1} 引用第二个数组变量;
    echo ${JFTEST[@]} 显示该数组所有参数;
    echo ${#JFTEST[@]} 显示该数组参数个数;
    echo ${#JFTEST[0]} 显示test1字符长度;
    echo ${JFTEST[@]:0} 打印数组所有的值;
    echo ${JFTEST[@]:1} 打印从第二个值开始的所有值;
    echo ${JFTEST[@]:0:2} 打印从第一个值与第二个值;
    echo ${JFTEST[@]:1:2} 打印从第二个值与第三个值。
    (3)数组替换操作:
    JFTEST=( [0]=www1 [1]=www2 [2]=www3 ) 数组赋值;
    echo ${JFTEST[@]/test/jfedu} 将数组值test替换为jfedu;
    NEWJFTEST=echo ${JFTEST[@]/test/jfedu} 将结果赋值新数组。
    (4)数组删除操作:
    unset array[0] 删除数组第一个值;
    unset array1 删除数组第二个值;
    unset array 删除整个数组。
    (5)数组Shell脚本企业案例一,网卡bond绑定脚本:

    !/bin/bash

    Auto Make KVM Virtualization

    Auto config bond scripts

    By author jfedu.net 2017

    eth_bond()
    {
    NETWORK=(
    HWADDR=ifconfig eth0 |egrep "HWaddr|Bcast" |tr "\n" " "|awk '{print $5,$7,$NF}'|sed -e 's/addr://g' -e 's/Mask://g'|awk '{print $1}'
    IPADDR=ifconfig eth0 |egrep "HWaddr|Bcast" |tr "\n" " "|awk '{print $5,$7,$NF}'|sed -e 's/addr://g' -e 's/Mask://g'|awk '{print $2}'
    NETMASK=ifconfig eth0 |egrep "HWaddr|Bcast" |tr "\n" " "|awk '{print $5,$7,$NF}'|sed -e 's/addr://g' -e 's/Mask://g'|awk '{print $3}'
    GATEWAY=route -n|grep "UG"|awk '{print $2}'
    )
    cat >ifcfg-bond0<<EOF
    DEVICE=bond0
    BOOTPROTO=static
    ${NETWORK[1]}
    ${NETWORK[2]}
    ${NETWORK[3]}
    ONBOOT=yes
    TYPE=Ethernet
    NM_CONTROLLED=no
    EOF
    (6)数组Shell脚本企业案例二,定义IPv4值:

    !/bin/bash

    auto Change ip netmask gateway scripts

    By author jfedu.net 2017

    ETHCONF=/etc/sysconfig/network-scripts/ifcfg-eth0
    HOSTS=/etc/hosts
    NETWORK=/etc/sysconfig/network
    DIR=/data/backup/date +%Y%m%d
    NETMASK=255.255.255.0
    echo "----------------------------"
    count_ip(){
    count=(echo $IPADDR|awk -F. '{print $1,$2,$3,$4}')
    IP1=${count[0]}
    IP2=${count1}
    IP3=${count[2]}
    IP4=${count[3]}
    }
    第18章 Shell编程高级企业实战
    企业生产环境中,服务器规模成百上千,如果依靠人工去维护和管理是非常吃力的,基于Shell编程脚本管理和维护服务器变得简单、从容,而且对企业自动化运维之路的建设起到极大的推动作用。
    本章向读者介绍企业生产环境Shell编程案例、自动化备份MySQL数据、服务器信息收集、防止恶意IP访问、LAMP+MySQL主从实战、千台服务器IP修改、Nginx+Tomcat高级自动化部署脚本、Nginx虚拟主机配置、Docker管理平台等。
    18.1 Shell编程实战系统备份脚本
    日常企业运维中,需要备份Linux操作系统中重要的文件,例如/etc、/boot分区、重要网站数据等,在备份数据时,由于数据量非常大,需要指定高效的备份方案,如下为常用的备份数据方案:
    每周日进行完整备份,周一至周六使用增量备份;
    每周六进行完整备份,周日至周五使用增量备份。
    企业备份数据的工具主要有:tar、cp、rsync、scp、sersync、dd等工具。如下为基于开源tar工具实现系统数据备份方案:
    Tar工具手动全备份网站,-g参数指定新的快照文件:
    tar -g /tmp/snapshot -czvf /tmp/2017_full_system_data.tar.gz /data/sh/
    Tar工具手动增量备份网站,-g参数指定全备已生成的快照文件,后续增量备份基于上一个增量备份快照文件:
    tar -g /tmp/snapshot -czvf /tmp/2014_add01_system_data.tar.gz /data/sh/
    Tar工具全备、增量备份网站,Shell脚本实现自动打包备份编写思路如下:
    系统备份数据按每天存放;
    创建完整备份函数块;
    创建增量备份函数块;
    根据星期数判断完整或增量;
    将脚本加入Crontab实现自动备份;
    Tar工具全备、增量备份网站,Shell脚本实现自动打包备份,代码如下:

    !/bin/bash

    Auto Backup Linux System Files

    By author jfedu.net 2017

    Define Path variables

    SOURCE_DIR=(
    $?
    if
    [ -z "$IR=/data/backup/
    YEAR=date +%Y
    MONTH=date +%m
    DAY=date +%d
    WEEK=date +%u
    A_NAME=date +%H%M
    FILES=system_backup.tgz
    CODE=$?
    if
    [ -z "$*" ];then
    echo -e "\033[32mUsage:\nPlease Enter Your Backup Files or Directories\n--------------------------------------------\n\nUsage: { $0 /boot /etc}\033[0m"
    exit
    fi

    Determine Whether the Target Directory Exists

    if
    [ ! -d $TARGET_DIR/$YEAR/$MONTH/$DAY ];then
    mkdir -p $TARGET_DIR/$YEAR/$MONTH/$DAY
    echo -e "\033[32mThe $TARGET_DIR Created Successfully !\033[0m"
    fi

    EXEC Full_Backup Function Command

    Full_Backup()
    {
    if
    [ "$WEEK" -eq "7" ];then
    rm -rf $TARGET_DIR/snapshot
    cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;tar -g $TARGET_DIR/snapshot -czvf $FILES ${SOURCE_DIR[@]}
    [ "$CODE" == "0" ]&&echo -e "--------------------------------------------\n\033[32mThese Full_Backup System Files Backup Successfully !\033[0m"
    fi
    }

    Perform incremental BACKUP Function Command

    Add_Backup()
    {
    if
    [ $WEEK -ne "7" ];then
    cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;tar -g $TARGET_DIR/snapshot -czvf $A_NAME$FILES ${SOURCE_DIR[@]}
    [ "$CODE" == "0" ]&&echo -e "-----------------------------------------\n\033[32mThese Add_Backup System Files $TARGET_DIR/$YEAR/$MONTH/$DAY/${YEAR}_$A_NAME$FILES Backup Successfully !\033[0m"
    fi
    }
    sleep 3
    Full_Backup;Add_Backup
    Crontab任务计划中添加如下语句,每天凌晨1点整执行备份脚本即可:
    0 1 * /bin/sh /data/sh/auto_backup.sh /boot /etc/ >> /tmp/back.log 2>&1
    18.2 Shell编程实战收集服务器信息
    在企业上产环境中,经常会对服务器资产进行统计存档,单台服务器可以手动去统计服务器的CPU型号、内存大小、硬盘容量、网卡流量等,如果服务器数量超过百台、千台,使用手工方式就变得非常吃力。
    基于Shell脚本实现自动化服务器硬件信息的收集,并将收集的内容存放在数据库,能更快、更高效的实现对服务器资产信息的管理。Shell脚本实现服务器信息自动收集,编写思路如下:
    创建数据库和表存储服务器信息;
    基于Shell四剑客awk、find、sed、grep获取服务器信息;
    将获取的信息写成SQL语句;
    定期对SQL数据进行备份;
    将脚本加入Crontab实现自动备份;
    创建数据库表,创建SQL语句如下:
    CREATE TABLE audit_system (
    id int(11) NOT NULL AUTO_INCREMENT,
    ip_info varchar(50) NOT NULL,
    serv_info varchar(50) NOT NULL,
    cpu_info varchar(50) NOT NULL,
    disk_info varchar(50) NOT NULL,
    mem_info varchar(50) NOT NULL,
    load_info varchar(50) NOT NULL,
    mark_info varchar(50) NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY ip_info (ip_info),
    UNIQUE KEY ip_info_2 (ip_info)
    );
    Shell脚本实现服务器信息自动收集,代码如下:

    !/bin/bash

    Auto get system info

    By author jfedu.net 2017

    Define Path variables

    echo -e "\033[34m \033[1m"
    cat <<EOF
    ++++++++++++++++++++++++++++++++++++++++++++++
    ++++++++Welcome to use system Collect+++++++++
    ++++++++++++++++++++++++++++++++++++++++++++++
    EOF
    ip_info=ifconfig |grep "Bcast"|tail -1 |awk '{print $2}'|cut -d: -f 2
    cpu_info1=cat /proc/cpuinfo |grep 'model name'|tail -1 |awk -F: '{print $2}'|sed 's/^ //g'|awk '{print $1,$3,$4,$NF}'
    cpu_info2=cat /proc/cpuinfo |grep "physical id"|sort |uniq -c|wc -l
    serv_info=hostname |tail -1
    disk_info=fdisk -l|grep "Disk"|grep -v "identifier"|awk '{print $2,$3,$4}'|sed 's/,//g'
    mem_info=free -m |grep "Mem"|awk '{print "Total",$1,$2"M"}'
    load_info=uptime |awk '{print "Current Load: "$(NF-2)}'|sed 's/\,//g'
    mark_info='BeiJing_IDC'
    echo -e "\033[32m-------------------------------------------\033[1m"
    echo IPADDR:${ip_info}
    echo HOSTNAME:$serv_info
    echo CPU_INFO:${cpu_info1} X${cpu_info2}
    echo DISK_INFO:$disk_info
    echo MEM_INFO:$mem_info
    echo LOAD_INFO:$load_info
    echo -e "\033[32m-------------------------------------------\033[0m"
    echo -e -n "\033[36mYou want to write the data to the databases? \033[1m" ;read ensure
    if [ "$ensure" == "yes" -o "$ensure" == "y" -o "$ensure" == "Y" ];then
    echo "--------------------------------------------"
    echo -e '\033[31mmysql -uaudit -p123456 -D audit -e ''' "insert into audit_system values('','${ip_info}','$serv_info','${cpu_info1} X${cpu_info2}','$disk_info','$mem_info','$load_info','$mark_info')" ''' \033[0m '
    mysql -uroot -p123456 -D test -e "insert into audit_system values('','${ip_info}','$serv_info','${cpu_info1} X${cpu_info2}','$disk_info','$mem_info','$load_info','$mark_info')"
    else
    echo "Please wait,exit......"
    exit
    fi
    手动读取数据库服务器信息命令:
    mysql -uroot -p123 -e 'use wugk1 ;select * from audit_audit_system;'|sed 's/-//g'|grep -v "id"
    18.3 Shell编程实战拒绝恶意IP登录
    企业服务器暴露在外网,每天会有大量的人使用各种用户名和密码尝试登陆服务器,如果让其一直尝试,难免会猜出密码,通过开发Shell脚本,可以自动将尝试登陆服务器错误密码次数的IP列表加入到防火墙配置中。
    Shell脚本实现服务器拒绝恶意IP登陆,编写思路如下:
    登陆服务器日志/var/log/secure;
    检查日志中认证失败的行并打印其IP地址;
    将IP地址写入至防火墙;
    禁止该IP访问服务器SSH 22端口;
    将脚本加入Crontab实现自动禁止恶意IP;
    Shell脚本实现服务器拒绝恶意IP登陆,代码如下:

    !/bin/bash

    Auto drop ssh failed IP address

    By author jfedu.net 2017

    Define Path variables

    SEC_FILE=/var/log/secure
    IP_ADDR=awk '{print $0}'  /var/log/secure|grep -i  "fail"| egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}" | sort -nr | uniq -c |awk '$1>=15 {print $2}'
    IPTABLE_CONF=/etc/sysconfig/iptables
    echo
    cat <<EOF
    ++++++++++++++welcome to use ssh login drop failed ip+++++++++++++++++
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ++++++++++++++++------------------------------------++++++++++++++++++
    EOF
    echo
    for ((j=0;j<=6;j++)) ;do echo -n "-";sleep 1 ;done
    echo
    for i in echo $IP_ADDR
    do
        cat $IPTABLE_CONF |grep $i >/dev/null
    if
        [ $? -ne 0 ];then
    sed -i "/lo/a -A INPUT -s $i -m state --state NEW -m tcp -p tcp --dport 22 -j DROP" $IPTABLE_CONF
    fi
    done
    NUM=find /etc/sysconfig/ -name iptables -a -mmin -1|wc -l
    if [ $NUM -eq 1 ];then
    /etc/init.d/iptables restart
    fi
    18.4 Shell编程实战LAMP一键安装
    LAMP是目前互联网主流WEB网站架构,通过源码安装、维护和管理对于单台很轻松,如果服务器数量多,手工管理就非常困难,基于Shell脚本可以更快速的维护LAMP架构。
    Shell脚本实现服务器LAMP一键源码安装配置,编写思路如下:
    脚本的功能,实现安装LAMP环境、论坛网站;
    Apache安装配置、MYSQL、PHP安装;
    源码LAMP整合配置;
    启动数据库,创建数据库并授权;
    重启LAMP所有服务, 验证访问;
    Shell脚本实现服务器LAMP一键源码安装配置,代码如下:

    !/bin/bash

    Auto install LAMP

    By author jfedu.net 2017

    Define Path variables

    Httpd define path variable

    H_FILES=httpd-2.2.32.tar.bz2
    H_FILES_DIR=httpd-2.2.32
    H_URL=http://mirrors.cnnic.cn/apache/httpd/
    H_PREFIX=/usr/local/apache2/

    MySQL define path variable

    M_FILES=mysql-5.5.20.tar.gz
    M_FILES_DIR=mysql-5.5.20
    M_URL=http://down1.chinaunix.net/distfiles/
    M_PREFIX=/usr/local/mysql/

    PHP define path variable

    P_FILES=php-5.3.28.tar.bz2
    P_FILES_DIR=php-5.3.28
    P_URL=http://mirrors.sohu.com/php/
    P_PREFIX=/usr/local/php5/
    function httpd_install(){
    if [[ "$1" -eq "1" ]];then
    wget -c $H_URL/$H_FILES && tar -jxvf $H_FILES && cd $H_FILES_DIR &&./configure --prefix=$H_PREFIX
    if [ $? -eq 0 ];then
    make && make install
    fi
    fi
    }
    function mysql_install(){
    if [[ "$1" -eq "2" ]];then
    wget -c $M_URL/$M_FILES && tar -xzvf $M_FILES && cd $M_FILES_DIR &&yum install cmake ncurses-devel -y ;cmake . -DCMAKE_INSTALL_PREFIX=$M_PREFIX \
    -DMYSQL_UNIX_ADDR=/tmp/mysql.sock \
    -DMYSQL_DATADIR=/data/mysql \
    -DSYSCONFDIR=/etc \
    -DMYSQL_USER=mysql \
    -DMYSQL_TCP_PORT=3306 \
    -DWITH_XTRADB_STORAGE_ENGINE=1 \
    -DWITH_INNOBASE_STORAGE_ENGINE=1 \
    -DWITH_PARTITION_STORAGE_ENGINE=1 \
    -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
    -DWITH_MYISAM_STORAGE_ENGINE=1 \
    -DWITH_READLINE=1 \
    -DENABLED_LOCAL_INFILE=1 \
    -DWITH_EXTRA_CHARSETS=1 \
    -DDEFAULT_CHARSET=utf8 \
    -DDEFAULT_COLLATION=utf8_general_ci \
    -DEXTRA_CHARSETS=all \
    -DWITH_BIG_TABLES=1 \
    -DWITH_DEBUG=0
    if [ $? -eq 0 ];then
    make && make install
    echo -e "\n\033[32m-----------------------------------------------\033[0m"
    echo -e "\033[32mThe $M_FILES_DIR Server Install Success !\033[0m"
    else
    echo -e "\033[32mThe $M_FILES_DIR Make or Make install ERROR,Please Check......"
    exit 0
    fi
    /bin/cp support-files/my-small.cnf /etc/my.cnf
    /bin/cp support-files/mysql.server /etc/init.d/mysqld
    chmod +x /etc/init.d/mysqld
    chkconfig --add mysqld
    chkconfig mysqld on
    fi
    }
    function php_install(){
    if [[ "$1" -eq "3" ]];then
    yum install libxml2-devel perl-devel perl libtool* -y
    wget -c $P_URL/$P_FILES && tar -jxvf $P_FILES && cd $P_FILES_DIR &&./configure --prefix=$P_PREFIX --with-config-file-path=$P_PREFIX/etc --with-mysql=$M_PREFIX --with-apxs2=$H_PREFIX/bin/apxs
    if [ $? -eq 0 ];then
    make ZEND_EXTRA_LIBS='-liconv' && make install
    echo -e "\n\033[32m-----------------------------------------------\033[0m"
    echo -e "\033[32mThe $P_FILES_DIR Server Install Success !\033[0m"
    else
    echo -e "\033[32mThe $P_FILES_DIR Make or Make install ERROR,Please Check......"
    exit 0
    fi
    fi
    }
    function lamp_config(){
    if [[ "$1" -eq "4" ]];then
    sed -i '/DirectoryIndex/s/index.html/index.php index.html/g' $H_PREFIX/conf/httpd.conf
    $H_PREFIX/bin/apachectl restart
    echo "AddType application/x-httpd-php .php" >>$H_PREFIX/conf/httpd.conf
    IP=ifconfig eth0|grep "Bcast"|awk '{print $2}'|cut -d: -f2
    echo "You can to access http://$IP/"

cat >$H_PREFIX/htdocs/index.php<<EOF
<?php
phpinfo();
?>
EOF
fi
}
PS3="Please enter you select install menu:"
select i in http mysql php config quit
do

case $i in
http)
httpd_install 1
;;
mysql)
mysql_install 2
;;
php)
php_install 3
;;
config)
lamp_config 4
;;
quit)
exit
esac
done
18.5 Shell编程实战MYSQL主从复制
MYSQL数据库服务器应用主要应用于与动态网站结合,存放网站必要的数据,例如订单、交易、员工表、薪资等记录,为了实现数据备份,需引入MYSQL主从架构,MYSQL主从架构脚本可以实现自动化安装、配置和管理。
Shell脚本实现服务器MYSQL一键YUM安装配置,编写思路如下:
MYSQL主库的操作:
主库上安装MYSQL,设置server-id、bin-log;
授权复制同步的用户,对客户端授权;
确认bin-log文件名、position位置点。
MYSQL丛库的操作:
从库上安装MYSQL,设置server-id;
change master 指定主库和bin-log名和position;
start slave; 启动丛库IO线程;
show slave status\G查看主从的状态。
Shell脚本实现服务器MYSQL一键YUM安装配置,需要提前手动授权主库可以免密码登录丛库服务器,代码如下:

!/bin/bash

Auto install Mysql AB Repliation

By author jfedu.net 2017

Define Path variables

MYSQL_SOFT="mysql mysql-server mysql-devel php-mysql mysql-libs"
NUM=rpm -qa |grep -i mysql |wc -l
INIT="/etc/init.d/mysqld"
CODE=$?

Mysql To Install 2017

if [ $NUM -ne 0 -a -f $INIT ];then
echo -e "\033[32mThis Server Mysql already Install.\033[0m"
read -p "Please ensure yum remove Mysql Server,YES or NO": INPUT
if [ $INPUT == "y" -o $INPUT == "yes" ];then
yum remove $MYSQL_SOFT -y ;rm -rf /var/lib/mysql /etc/my.cnf
yum install $MYSQL_SOFT -y
else
echo
fi
else
yum remove $MYSQL_SOFT -y ;rm -rf /var/lib/mysql /etc/my.cnf
yum install $MYSQL_SOFT -y
if [ $CODE -eq 0 ];then
echo -e "\033[32mThe Mysql Install Successfully.\033[0m"
else
echo -e "\033[32mThe Mysql Install Failed.\033[0m"
exit 1
fi
fi
my_config(){
cat >/etc/my.cnf<<EOF
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
log-bin=mysql-bin
server-id = 1
auto_increment_offset=1
auto_increment_increment=2
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
EOF
}
my_config
/etc/init.d/mysqld restart
ps -ef |grep mysql
MYSQL_CONFIG(){

Master Config Mysql

mysql -e "grant replication slave on . to 'tongbu'@'%' identified by '123456';"
MASTER_FILE=mysql -e "show master status;"|tail -1|awk '{print $1}'
MASTER_POS=mysql -e "show master status;"|tail -1|awk '{print $2}'
MASTER_IPADDR=ifconfig eth0|grep "Bcast"|awk '{print $2}'|cut -d: -f2
read -p "Please Input Slave IPaddr: " SLAVE_IPADDR

Slave Config Mysql

ssh -l root $SLAVE_IPADDR "yum remove $MYSQL_SOFT -y ;rm -rf /var/lib/mysql /etc/my.cnf ;yum install $MYSQL_SOFT -y"
ssh -l root $SLAVE_IPADDR "$my_config"

scp -r /etc/my.cnf root@192.168.111.129:/etc/

ssh -l root $SLAVE_IPADDR "sed -i 's#server-id = 1#server-id = 2#g' /etc/my.cnf"
ssh -l root $SLAVE_IPADDR "sed -i '/log-bin=mysql-bin/d' /etc/my.cnf"
ssh -l root $SLAVE_IPADDR "/etc/init.d/mysqld restart"
ssh -l root $SLAVE_IPADDR "mysql -e \"change master to master_host='$MASTER_IPADDR',master_user='tongbu',master_password='123456',master_log_file='$MASTER_FILE',master_log_pos=$MASTER_POS;\""
ssh -l root $SLAVE_IPADDR "mysql -e \"slave start;\""
ssh -l root $SLAVE_IPADDR "mysql -e \"show slave status\G;\""
}

read -p "Please ensure your Server is Master and you will config mysql Replication?yes or no": INPUT
if [ $INPUT == "y" -o $INPUT == "yes" ];then
MYSQL_CONFIG
else
exit 0
fi
18.6 Shell编程实战修改IP及主机名
企业中服务器IP地址系统通过自动化工具安装完系统,IP均是自动获取的,而服务器要求固定的静态IP,百台服务器手工去配置静态IP是不可取的,可以基于Shell脚本自动修改IP、主机名等信息。
Shell脚本实现服务器IP、主机名自动修改及配置,编写思路如下:
静态IP修改;
动态IP修改;
根据IP-生成主机名并配置;
修改DNS域名解析;
Shell脚本实现服务器IP、主机名自动修改及配置,代码如下:

!/bin/bash

Auto Change ip netmask gateway scripts

By author jfedu.net 2017

Define Path variables

ETHCONF=/etc/sysconfig/network-scripts/ifcfg-eth0
HOSTS=/etc/hosts
NETWORK=/etc/sysconfig/network
DIR=/data/backup/date +%Y%m%d
NETMASK=255.255.255.0
echo "----------------------------"
judge_ip(){
read -p "Please enter ip Address,example 192.168.0.11 ip": IPADDR
echo $IPADDR|awk -F. '{print $|grep --color -E "([0-9]{1,3}.){3}[0-9]{1,3}"
}
count_ip(){
count=(echo $IPADDR|awk -F. '{print $1,$2,$3,$4}')
IP1=${count[0]}
IP2=${count1}
IP3=${count[2]}
IP4=${count[3]}
}
ip_check()
{
judge_ip
while [ $? -ne 0 ]
do
judge_ip
done
count_ip
while [ "$IP1" -lt 0 -o "$IP1" -ge 255 -o "$IP2" -ge 255 -o "$IP3" -ge 255 -o "$IP4" -ge 255 ]
do
judge_ip
while [ $? -ne 0 ]
do
judge_ip
done
count_ip
done
}
change_ip()
{
if [ ! -d $DIR ];then
mkdir -p $DIR
fi
echo "The Change ip address to Backup Interface eth0"
cp $ETHCONF $DIR
grep "dhcp" $ETHCONF
if [ $? -eq 0 ];then
read -p "Please enter ip Address:" IPADDR
sed -i 's/dhcp/static/g' $ETHCONF
echo -e "IPADDR=$IPADDR\nNETMASK=$NETMASK\nGATEWAY=echo $IPADDR|awk -F. '{print $1"."$2"."$3}'.2" >>$ETHCONF
echo "The IP configuration success. !"
else
echo -n "Static IP has been configured,please confirm whether to modify,yes or No":
read i
fi
if [ "$i" == "y" -o "$i" == "yes" ];then
ip_check
sed -i -e '/IPADDR/d' -e '/NETMASK/d' -e '/GATEWAY/d' $ETHCONF
echo -e "IPADDR=$IPADDR\nNETMASK=$NETMASK\nGATEWAY=echo $IPADDR|awk -F. '{print $1"."$2"."$3}'.2" >>$ETHCONF
echo "The IP configuration success. !"
echo
else
echo "Static IP already exists,please exit."
exit $?
fi
}
change_hosts()
{

if [ ! -d $DIR ];then
mkdir -p $DIR
fi
cp $HOSTS $DIR
ip_check
host=echo $IPADDR|sed 's/\./-/g'|awk '{print "BJ-IDC-"$0"-jfedu.net"}'
cat $HOSTS |grep "$host"
if [ $? -ne 0 ];then
echo "$IPADDR $host" >> $HOSTS
echo "The hosts modify success "
fi
grep "$host" $NETWORK
if [ $? -ne 0 ];then
sed -i "s/^HOSTNAME/#HOSTNAME/g" $NETWORK
echo "NETWORK=$host" >>$NETWORK
hostname $host;su
fi
}
PS3="Please Select configuration ip or configuration host:"
select i in "modify_ip" "modify_hosts" "exit"
do
case $i in
modify_ip)
change_ip
;;
modify_hosts)
change_hosts
;;
exit)
exit
;;
*)
echo -e "1) modify_ip\n2) modify_ip\n3)exit"
esac

done
18.7 Shell编程实战Zabbix安装配置
Zabbix是一款分布式监控系统,基于C/S模式,需在服务器安装Zabbix_server,在客户端安装Zabbix_agent,通过Shell脚本可以更快速的实现该需求。
Shell脚本实现Zabbix服务器端和客户端自动安装,编写思路如下:
Zabbix软件的版本源码安装、路径、--enable-server、--enable-agent;
cp zabbix_agentd启动进程-/etc/init.d/zabbix_agentd、给执行x权限;
配置zabbix_agentd.conf文件,指定server IP变量;
指定客户端的Hostname其实可以等于客户端IP地址;
启动zabbix_agentd服务,创建zabbix user。
Shell脚本实现Zabbix服务器端和客户端自动安装,代码如下:

!/bin/bash

Auto install zabbix server and client

By author jfedu.net 2017

Define Path variables

ZABBIX_SOFT="zabbix-3.2.6.tar.gz"
INSTALL_DIR="/usr/local/zabbix/"
SERVER_IP="192.168.111.128"
IP=ifconfig|grep Bcast|awk '{print $2}'|sed 's/addr://g'
SERVER_INSTALL(){
yum -y install curl curl-devel net-snmp net-snmp-devel perl-DBI
groupadd zabbix ;useradd -g zabbix zabbix;usermod -s /sbin/nologin zabbix
tar -xzf $ZABBIX_SOFT;cd echo $ZABBIX_SOFT|sed 's/.tar.*//g'
./configure --prefix=/usr/local/zabbix --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl &&make install
if [ $? -eq 0 ];then
ln -s /usr/local/zabbix/sbin/zabbix_ /usr/local/sbin/
fi
cd - ;cd zabbix-3.2.6
cp misc/init.d/tru64/{zabbix_agentd,zabbixserver} /etc/init.d/ ;chmod o+x /etc/init.d/zabbix

mkdir -p /var/www/html/zabbix/;cp -a frontends/php/* /var/www/html/zabbix/

config zabbix server

cat >$INSTALL_DIR/etc/zabbix_server.conf<<EOF
LogFile=/tmp/zabbix_server.log
DBHost=localhost
DBName=zabbix
DBUser=zabbix
DBPassword=123456
EOF

config zabbix agentd

cat >$INSTALL_DIR/etc/zabbix_agentd.conf<<EOF
LogFile=/tmp/zabbix_agentd.log
Server=$SERVER_IP
ServerActive=$SERVER_IP
Hostname = $IP
EOF

start zabbix agentd

/etc/init.d/zabbix_server restart
/etc/init.d/zabbix_agentd restart
/etc/init.d/iptables stop
setenforce 0
}
AGENT_INSTALL(){
yum -y install curl curl-devel net-snmp net-snmp-devel perl-DBI
groupadd zabbix ;useradd -g zabbix zabbix;usermod -s /sbin/nologin zabbix

tar -xzf $ZABBIX_SOFT;cd echo $ZABBIX_SOFT|sed 's/.tar.*//g'
./configure --prefix=/usr/local/zabbix --enable-agent&&make install
if [ $? -eq 0 ];then
ln -s /usr/local/zabbix/sbin/zabbix_* /usr/local/sbin/
fi
cd - ;cd zabbix-3.2.6
cp misc/init.d/tru64/zabbix_agentd /etc/init.d/zabbix_agentd ;chmod o+x /etc/init.d/zabbix_agentd

config zabbix agentd

cat >$INSTALL_DIR/etc/zabbix_agentd.conf<<EOF
LogFile=/tmp/zabbix_agentd.log
Server=$SERVER_IP
ServerActive=$SERVER_IP
Hostname = $IP
EOF

start zabbix agentd

/etc/init.d/zabbix_agentd restart
/etc/init.d/iptables stop
setenforce 0
}

read -p "Please confirm whether to install Zabbix Server,yes or no? " INPUT
if [ $INPUT == "yes" -o $INPUT == "y" ];then
SERVER_INSTALL
else
AGENT_INSTALL
fi
18.8 Shell编程实战Nginx虚拟主机
Nginx WEB服务器的最大特点在于Nginx常被用于负载均衡、反向代理,单台Nginx服务器配置多个虚拟主机,百台服务器配置N多虚拟主机,基于Shell脚本可以更加高效的配置虚拟主机及添加、管理。
Shell脚本实现Nginx自动安装及虚拟主机的维护,编写思路如下:
脚本指定参数v1.jfedu.net;
创建v1.jfedu.net同时创建目录/var/www/v1;
将Nginx虚拟主机配置定向到新的目录;
重复虚拟主机不再添加。
Shell脚本实现Nginx自动安装及虚拟主机的维护,代码如下:

!/bin/bash

Auto config Nginx virtual Hosts

By author jfedu.net 2017

Define Path variables

NGINX_CONF="/usr/local/nginx/conf/"
NGINX_MAKE="--user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module"
NGINX_SBIN="/usr/local/nginx/sbin/nginx"
NGINX_INSTALL(){

Install Nginx server

NGINX_FILE=nginx-1.12.0.tar.gz
NGINX_DIR=echo $NGINX_FILE|sed 's/.tar*.*//g'
if [ ! -e /usr/local/nginx/ -a ! -e /etc/nginx/ ];then
pkill nginx
wget -c http://nginx.org/download/$NGINX_FILE
yum install pcre-devel pcre -y
rm -rf $NGINX_DIR ;tar xf $NGINX_FILE
cd $NGINX_DIR;useradd www;./configure $NGINX_MAKE
make &&make install
grep -vE "#|^$" $NGINX_CONF/nginx.conf >$NGINX_CONF/nginx.conf.swp
\mv $NGINX_CONF/nginx.conf.swp $d' $X_CONF/nginx.conf
for i in seq 1 6;do sed -i '$d' $NGINX_CONF/nginx.conf;done
echo "}" >>$NGINX_CONF/nginx.conf
cd ../
fi
}
NGINX_CONFIG(){

config tomcat nginx vhosts

grep "include domains" $NGINX_CONF/nginx.conf >>/dev/null
if [ $? -ne 0 ];then

sed -i '$d' $NGINX_CONF/nginx.conf

echo -e "\ninclude domains/*;\n}" >>$NGINX_CONF/nginx.conf
mkdir -p $NGINX_CONF/domains/

fi
VHOSTS=$1
ls $NGINX_CONF/domains/$VHOSTS>>/dev/null 2>&1
if [ $? -ne 0 ];then

cp -r xxx.jfedu.net $NGINX_CONF/domains/$VHOSTS

#sed -i "s/xxx/$VHOSTS/g" $NGINX_CONF/domains/$VHOSTS
cat>$NGINX_CONF/domains/$VHOSTS<<EOF
#vhost server $VHOSTS 
server {
    listen       80;
    server_name  $VHOSTS;
    location / {
        root   /data/www/$VHOSTS/;
        index  index.html index.htm;
    }
  }

EOF
mkdir -p /data/www/$VHOSTS/
cat>/data/www/$VHOSTS/index.html<<EOF

The First Test Nginx page.


$VHOSTS

EOF echo -e "\033[32mThe $VHOSTS Config success,You can to access http://$VHOSTS/\033[0m" NUM=`ps -ef |grep nginx|grep -v grep|grep -v auto|wc -l` $NGINX_SBIN -t >>/dev/null 2>&1 if [ $? -eq 0 -a $NUM -eq 0 ];then $NGINX_SBIN else $NGINX_SBIN -t >>/dev/null 2>&1 if [ $? -eq 0 ];then $NGINX_SBIN -s reload fi fi else echo -e "\033[32mThe $VHOSTS has been config,Please exit.\033[0m" fi } if [ -z $1 ];then echo -e "\033[32m--------------------\033[0m" echo -e "\033[32mPlease enter sh $0 xx.jf.com.\033[0m" exit 0 fi NGINX_INSTALL NGINX_CONFIG $1 18.9 Shell编程实战Nginx、Tomcat脚本 Tomcat用于发布JSP WEB页面,根据企业实际需求,会在单台服务器配置N个Tomcat实例,同时手动将Tomcat创建后的实例加入至Nginx虚拟主机中,同时重启Nginx,开发Nginx、Tomcat自动创建Tomcat实例及Nginx虚拟主机管理脚本能让大大的减轻人工的干预,实现快速的交付。 Shell脚本实现Nginx自动安装、虚拟主机及自动将Tomcat加入至虚拟主机,编写思路如下: 手动拷贝Tomcat与脚本一致目录(可自动修改); 手动修改Tomcat端口为6001、7001、8001(可自动修改); 脚本指定参数v1.jfedu.net; 创建v1.jfedu.net Tomcat实例; 修改Tomcat实例端口,保证Port唯一; 将Tomcat实例加入Nginx虚拟主机; 重复创建Tomcat实例,端口自动增加,并加入原Nginx虚拟主机,实现负载均衡; Shell脚本实现Nginx自动安装、虚拟主机及自动将Tomcat加入至虚拟主机,代码如下: #!/bin/bash #Auto config Nginx and tomcat cluster #By author jfedu.net 2017 #Define Path variables NGINX_CONF="/usr/local/nginx/conf/" install_nginx(){ NGINX_FILE=nginx-1.10.2.tar.gz NGINX_DIR=`echo $NGINX_FILE|sed 's/.tar*.*//g'` wget -c http://nginx.org/download/$NGINX_FILE yum install pcre-devel pcre -y rm -rf $NGINX_DIR ;tar xf $NGINX_FILE cd $NGINX_DIR;useradd www;./configure --user=www --group=www --prefix=/usr/local/nginx2 --with-http_stub_status_module --with-http_ssl_module make &&make install cd ../ } install_tomcat(){ JDK_FILE="jdk1.7.0_25.tar.gz" JDK_DIR=`echo $JDK_FILE|sed 's/.tar.*//g'` tar -xzf $JDK_FILE ;mkdir -p /usr/java/ ;mv $JDK_DIR /usr/java/ sed -i '/JAVA_HOME/d;/JAVA_BIN/d;/JAVA_OPTS/d' /etc/profile cat >> /etc/profile <>/dev/null if [ $? -ne 0 ];then sed -i '$d' $NGINX_CONF/nginx.conf echo -e "\ninclude domains/*;\n}" >>$NGINX_CONF/nginx.conf mkdir -p $NGINX_CONF/domains/ fi VHOSTS=$1 NUM=`ls /usr/local/|grep -c tomcat` if [ $NUM -eq 0 ];then cp -r tomcat /usr/local/tomcat_$VHOSTS cp -r xxx.jfedu.net $NGINX_CONF/domains/$VHOSTS #sed -i "s/VHOSTS/$VHOSTS/g" $NGINX_CONF/domains/$VHOSTS sed -i "s/xxx/$VHOSTS/g" $NGINX_CONF/domains/$VHOSTS exit 0 fi #-------------------------------- #VHOSTS=$1 VHOSTS_NUM=`ls $NGINX_CONF/domains/|grep -c $VHOSTS` SERVER_NUM=`grep -c "127" $NGINX_CONF/domains/$VHOSTS` SERVER_NUM_1=`expr $SERVER_NUM + 1` rm -rf /tmp/.port.txt for i in `find /usr/local/ -maxdepth 1 -name "tomcat*"`;do grep "port" $i/conf/server.xml |egrep -v "\--|8080|SSLEnabled"|awk '{print $2}'|sed 's/port=//g;s/\"//g'|sort -nr >>/tmp/.port.txt done MAX_PORT=`cat /tmp/.port.txt|grep -v 8443|sort -nr|head -1` PORT_1=`expr $MAX_PORT - 2000 + 1` PORT_2=`expr $MAX_PORT - 1000 + 1` PORT_3=`expr $MAX_PORT + 1` if [ $VHOSTS_NUM -eq 1 ];then read -p "The $VHOSTS is exists,You sure create mulit Tomcat for the $VHOSTS? yes or no " INPUT if [ $INPUT == "YES" -o $INPUT == "Y" -o $INPUT == "yes" ];then cp -r tomcat /usr/local/tomcat_${VHOSTS}_${SERVER_NUM_1} sed -i "s/6001/$PORT_1/g" /usr/local/tomcat_${VHOSTS}_${SERVER_NUM_1}/conf/server.xml sed -i "s/7001/$PORT_2/g" /usr/local/tomcat_${VHOSTS}_${SERVER_NUM_1}/conf/server.xml sed -i "s/8001/$PORT_3/g" /usr/local/tomcat_${VHOSTS}_${SERVER_NUM_1}/conf/server.xml sed -i "/^upstream/a server 127.0.0.1:${PORT_2} weight=1 max_fails=2 fail_timeout=30s;" $NGINX_CONF/domains/$VHOSTS exit 0 fi exit fi cp -r tomcat /usr/local/tomcat_$VHOSTS cp -r xxx.jfedu.net $NGINX_CONF/domains/$VHOSTS sed -i "s/VHOSTS/$VHOSTS/g" $NGINX_CONF/domains/$VHOSTS sed -i "s/xxx/$VHOSTS/g" $NGINX_CONF/domains/$VHOSTS sed -i "s/7001/${PORT_2}/g" $NGINX_CONF/domains/$VHOSTS #######config tomcat sed -i "s/6001/$PORT_1/g" /usr/local/tomcat_${VHOSTS}/conf/server.xml sed -i "s/7001/$PORT_2/g" /usr/local/tomcat_${VHOSTS}/conf/server.xml sed -i "s/8001/$PORT_3/g" /usr/local/tomcat_${VHOSTS}/conf/server.xml

}
if [ ! -d $NGINX_CONF -o ! -d /usr/java/$JDK_DIR ];then
install_nginx
install_tomcat
fi
config_tomcat_nginx $1
18.10 Shell编程实战Docker管理脚本
Docker虚拟化是目前主流的虚拟化解决方案,越来越多的企业在使用Docker轻量级虚拟化,构建、维护和管理Docker虚拟化平台是运维人员非常重要的一个环节,开发Docker Shell脚本可以在命令行界面快速管理和维护Docker。
Shell脚本实现Docker自动安装、自动导入镜像、创建虚拟机、指定IP地址、将创建的Docker虚拟机加入Excel存档或者加入MYSQL数据库,编写思路如下:
基于CentOS6.5+或者7.x YUM安装Docker;
Docker脚本参数指定CPU、内存、硬盘容量;
Docker自动检测局域网IP并赋予Docker虚拟机;
Docker基于pipework指定IP;
将创建的Docker虚拟机加入至CSV(Excel)或者MYSQL库;
Shell脚本实现Docker自动安装、自动导入镜像、创建虚拟机、指定IP地址、将创建的Docker虚拟机加入CSV(Excel)存档或者加入MYSQL数据库,代码如下:

!/bin/bash

Auto install docker and Create VM

By author jfedu.net 2017

Define Path variables

IPADDR=ifconfig|grep -E "\<inet\>"|awk '{print $2}'|grep "192.168"|head -1
GATEWAY=route -n|grep "UG"|awk '{print $2}'|grep "192.168"|head -1
IPADDR_NET=ifconfig|grep -E "\<inet\>"|awk '{print $2}'|grep "192.168"|head -1|awk -F. '{print $1"."$2"."$3"."}'
LIST="/root/docker_vmlist.csv"
if [ ! -f /usr/sbin/ifconfig ];then
yum install net-tools* -y
fi
for i in seq 1 253;do ping -c 1 ${IPADDR_NET}${i} ;[ $? -ne 0 ]&& DOCKER_IPADDR="${IPADDR_NET}${i}" &&break;done >>/dev/null 2>&1
echo "##################"
echo -e "Dynamic get docker IP,The Docker IP address\n\n$DOCKER_IPADDR"
NETWORK=(
HWADDR=ifconfig eth0|grep ether|awk '{print $2}'
IPADDR=ifconfig eth0|grep -E "\<inet\>"|awk '{print $2}'
NETMASK=ifconfig eth0|grep -E "\<inet\>"|awk '{print $4}'
GATEWAY=route -n|grep "UG"|awk '{print $2}'
)
if [ -z "$1" -o -z "$2" ];then
echo -e "\033[32m---------------------------------\033[0m"
echo -e "\033[32mPlease exec $0 CPU(C) MEM(G),example $0 4 8\033[0m"
exit 0
fi

CPU=expr $2 - 1

if [ ! -e /usr/bin/bc ];then
yum install bc -y >>/dev/null 2>&1
fi
CPU_ALL=cat /proc/cpuinfo |grep processor|wc -l
if [ ! -f $LIST ];then
CPU_COUNT=$1
CPU_1="0"
CPU1=expr $CPU_1 + 0
CPU2=expr $CPU1 + $CPU_COUNT - 1
if [ $CPU2 -gt $CPU_ALL ];then
echo -e "\033[32mThe System CPU count is $CPU_ALL,not more than it.\033[0m"
exit
fi
else
CPU_COUNT=$1
CPU_1=cat $LIST|tail -1|awk -F"," '{print $4}'|awk -F"-" '{print $2}'
CPU1=expr $CPU_1 + 1
CPU2=expr $CPU1 + $CPU_COUNT - 1
if [ $CPU2 -gt $CPU_ALL ];then
echo -e "\033[32mThe System CPU count is $3
REMARK=$t more than it.\033[0m"
exit
fi
fi
MEM_F=echo $2 \* 1024|bc
MEM=printf "%.0f\n" $MEM_F
DISK=20
USER=$3
REMARK=$4
ping $DOCKER_IPADDR -c 1 >>/dev/null 2>&1
if [ $? -eq 0 ];then
echo -e "\033[32m---------------------------------\033[0m"
echo -e "\033[32mThe IP address to be used,Please change other IP,exit.\033[0m"
exit 0
fi
if [ ! -e /usr/bin/docker ];then
yum install docker device-mapper -y
mkdir -p /export/docker/
cd /var/lib/ ;rm -rf docker ;ln -s /export/docker/ .
mkdir -p /var/lib/docker/devicemapper/devicemapper
dd if=/dev/zero of=/var/lib/docker/devicemapper/devicemapper/data bs=1G count=0 seek=2000
service docker start
if [ ${NETWORK[0]}
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
BRIDGE="br0"
$fi
cd /etc/sysconfig/network-scripts/
mkdir -p /data/backup/date +%Y%m%d-%H%M
yes|cp ifcfg-eth* /data/backup/date +%Y%m%d-%H%M/
if
[ -e /etc/sysconfig/network-scripts/ifcfg-br0 ];then
echo
else
cat >ifcfg-eth0 <<EOF
DEVICE=eth0
BOOTPROTO=none
${NETWORK[0]}
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
BRIDGE="br0"
${NETWORK1}
${NETWORK[2]}
${NETWORK[3]}
USERCTL=no
EOF
cat >ifcfg-br0 <<EOF
DEVICE="br0"
BOOTPROTO=none
${NETWORK[0]}
IPV6INIT=no
NM_CONTROLLED=no
ONBOOT=yes
TYPE="Bridge"
${NETWORK1}
${NETWORK[2]}
${NETWORK[3]}
USERCTL=no
EOF
/etc/init.d/network restart
fi
echo 'Your can restart Ethernet Service: /etc/init.d/network restart !'
echo '---------------------------------------------------------'

cd -
#######create docker container
service docker status >>/dev/null
if [ $DOCKER_IPADDR|awk -F"." '{print $restart
fi
NAME="Docker_echo $DOCKER_IPADDR|awk -F"." '{print $(NF-1)"_"$NF}'"
IMAGES=docker images|grep -v "REPOSITORY"|grep -v "none"|grep "jfedu"|head -1|awk '{print $1}'
if [ -z $(docker run -itd --privileged --cpuset-cpus=$Centos Images,you can to be use docker search centos,and docker pull centos6.5-ssh,exit 0"
if [ ! -f jfedu_centos68.tar ];then
echo "Please upload jfedu_centos68.tar for docker server."
exit
fi
cat jfedu_centos68.tar|docker import - jfedu_centos6.8
fi
IMAGES=docker images|grep -v "REPOSITORY"|grep -v "none"|grep "jfedu"|head -1|awk '{print $1}'
CID=$(docker run -itd --privileged --cpuset-cpus=${CPU1}-${CPU2} -m ${MEM}m --net=none --name=$NAME $IMAGES /bin/bash)
echo $CID
docker ps -a |grep "$NAME"
pipework br0 $NAME $DOCKER_IPADDR/24@$IPADDR
docker exec $NAME /etc/init.d/sshd start
if [ ! -e $LIST ];then
echo "编号,容器ID,容器名称,CPU,内存,硬盘,容器IP,宿主机IP,使用人,备注" >$LIST
fi
###################
NUM=cat $LIST |grep -v CPU|tail -1|awk -F, '{print $1}'
if [[ $NAME,$q "" ]];then
NUM="1"
else
NUM=expr $NUM + 1
fi
##################
echo -e "\033[32mCreate virtual client Successfully.\n$NAME,$cho $NAME,$t -b 1-12,$NAME,$CPU1-$CPU2,${MEM}M,${DISK}G,$DOCKER_IPADDR,$IPADDR,$USER,$REMARK\033[0m" if [ -z $USER ];then USER="NULL" REMARK="NULL" fi echo $NUM,echo $NAME,$t -b 1-12,$NAME,$CPU1-$CPU2,${MEM}M,${DISK}G,$DOCKER_IPADDR,$IPADDR,$USER,$REMARK >>$LIST rm -rf /root/docker_vmlist_* iconv -c -f utf-8 -t gb2312 $LIST -o /root/docker_vmlist_date +%H%M`.csv
18.11 Shell编程实战Bind管理脚本
Bind主要应用于企业DNS构建平台,而DNS用于将域名与IP进行解析,用户在浏览器只需输入域名,即可访问服务器IP地址的虚拟主机网站。
Bind难点在于创建各种记录,例如A记录、mail记录、反向记录、资源记录,基于Shell脚本可以减轻人工的操作,节省大量的时间成本。
Shell脚本实现Bind自动安装、初始化Bind环境、自动添加A记录、反向记录、批量添加A记录,编写思路如下:
YUM方式自动安装Bind;
自动初始化Bind配置;
创建安装、初始化、添加记录函数;
自动添加单个A记录及批量添加A记录和反向记录;
Shell脚本实现Bind自动安装、初始化Bind环境、自动添加A记录、反向记录、批量添加A记录,代码如下:

!/bin/bash

Auto install config bind server

By author jfedu.net 2017

Define Path variables

BND_ETC=/var/named/chroot/etc
BND_VAR=/var/named/chroot/var/named
BAKDIR=/data/backup/dnsdate +%Y%m%d-%H%M

Backup named server

if
[ ! -d $BAK_DIR ];then
echo "Please waiting Backup Named Config ............"
mkdir -p $BAK_DIR
cp -a /var/named/chroot/{etc,var} $BAK_DIR
cp -a /etc/named.* $BAK_DIR
fi

Define Shell Install Function

Install ()
{
if
[ ! -e /etc/init.d/named ];then
yum install bind* -y
else
echo -------------------------------------------------
echo "The Named Server is exists ,Please exit ........."
sleep 1
fi
}

Define Shell Init Function

Init_Config ()
{
sed -i -e 's/localhost;/any;/g' -e '/port/s/127.0.0.1/any/g' /etc/named.conf
echo -------------------------------------------------
sleep 2
echo "The named.conf config Init success !"
}

Define Shell Add Name Function

Add_named ()
{

DNS name

   read -p  "Please  Insert Into Your Add Name ,Example 51cto.com :" NAME
   echo $NAME |grep -E "com|cn|net|org"
   while
    [ "$?" -ne 0 ]
     do
    read -p  "Please  reInsert Into Your Add Name ,Example 51cto.com :" NAME
    echo $NAME |grep -E "com|cn|net|org"
 done

IP address

   read -p  "Please  Insert Into Your Name Server IP ADDress:" IP 
   echo $IP |egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}"
   while 
   [ "$?" -ne "0" ]
    do
    read -p  "Please  reInsert Into Your Name Server IP ADDress:" IP 
   echo $IP |egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}"
  done
   ARPA_IP=`echo $IP|awk -F. '{print $3"."$2"."$1}'`
   ARPA_IP1=`echo $IP|awk -F. '{print $4}'`
   cd  $BND_ETC 
   grep  "$NAME" named.rfc1912.zones

if
[ $? -eq 0 ];then
echo "The $NAME IS exist named.rfc1912.zones conf ,please exit ..."
exit
else
read -p "Please Insert Into SLAVE Name Server IP ADDress:" SLAVE
echo $SLAVE |egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}"
while
[ "$?" -ne "0" ]
do
read -p "Please Insert Into SLAVE Name Server IP ADDress:" SLAVE
echo $SLAVE |egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}"
done
grep "rev" named.rfc1912.zones
if
[ $? -ne 0 ];then
cat >>named.rfc1912.zones <<EOF

date +%Y-%m-%d Add $NAME CONFIG

zone "$NAME" IN {
type master;
file "$NAME.zone";
allow-update { none; };
};
zone "$ARPA_IP.in-addr.arpa" IN {
type master;
file "$ARPA_IP.rev";
allow-update { none; };
};
EOF
else
cat >>named.rfc1912.zones <<EOF

date +%Y-%m-%d Add $NAME CONFIG

zone "$NAME" IN {
type master;
file "$NAME.zone";
allow-update { none; };
};
EOF
fi
fi
[ $? -eq 0 ]&& echo "The $NAME config name.rfc1912.zones success !"
sleep 3 ;echo "Please waiting config $NAME zone File ............."
cd $BND_VAR
read -p "Please insert Name DNS A HOST ,EXample www or mail :" HOST
read -p "Please insert Name DNS A NS IP ADDR ,EXample 192.168.111.130 :" IP_HOST
echo $IP_HOST|awk -F. '{print ${1,3}.){3}[0-9]{1,3}"
ARPA_IP2=echo $IP_HOST|awk -F. '{print $3"."$2"."$1}'
ARPA_IP3=echo $IP_HOST|awk -F. '{print $4}'
while
[ "$?" -ne "0" ]
do
read -p "Please Reinsert Name DNS A IPADDRESS ,EXample 192.168.111.130 :" IP_HOST
echo $IP_HOST |egrep -o "([0-9]{1,3}.){3}[0-9]{1,3}"
done
cat >$NAME.zone <<EOF
\$TTL 86400
@ IN SOA localhost. root.localhost. (
43 ; serial (d. adams)
1H ; refresh
15M ; retry
1W ; expiry
1D ) ; minimum

            IN  NS          $NAME.

EOF
REV=ls *.rev
ls *.rev >>/dev/null
if
[ $? -ne 0 ];then
cat >>$ARPA_IP.rev <<EOF
\$TTL 86400
@ IN SOA localhost. root.localhost. (
1997022703 ; Serial
28800 ; Refresh
14400 ; Retry
3600000 ; Expire
86400 ) ; Minimum

        IN  NS  $NAME.

EOF
echo "$HOST IN A $IP_HOST" >>$NAME.zone
echo "$ARPA_IP3 IN PTR $HOST.$NAME." >>$ARPA_IP.rev
[ $? -eq 0 ]&& echo -e "The $NAME config success:\n$HOST IN A $IP_HOST\n$ARPA_IP3 IN PTR $HOST.$NAME."
else
sed -i "9a IN NS $NAME." $REV
echo "$HOST IN A $IP_HOST" >>$NAME.zone
echo "$ARPA_IP3 IN PTR $HOST.$NAME." >>$REV
[ $? -eq 0 ]&& echo -e "The $NAME config success1:\n$HOST IN A $IP_HOST\n$ARPA_IP3 IN PTR $HOST.$NAME."
fi
}

Define Shell List A Function

Add_A_List ()
{
if
cd $NAME.zone" ];then
echo "The $ "Please Insert Into Your Add Name ,Example 51cto.com :" NAME
[ ! -e "$NAME.zone" ];then
echo "The $NAME.zone File is not exist ,Please ADD $NAME.zone File :"
Add_named ;
else
read -p "Please Enter List Name A NS File ,Example /tmp/name_list.txt: " FILE
if
[ -e $FILE ];then
for i in cat $FILE|awk '{print $2}'|sed "s/$NAME//g"|sed 's/\.$//g'

for i in cat $FILE|awk '{print $1}'|sed "s/$NAME//g"|sed 's/\.$//g'

do
j=awk -v I="$i.$NAME" '{if(I==$2)print $1}' $FILE
echo -----------------------------------------------------------
echo "The $j|awk -F. '{print $xist ,Please Enter insert NAME HOST ...."
sleep 1
ARPA_IP=echo $j|awk -F. '{print $3"."$2"."$1}'
ARPA_IP2=echo $j|awk -F. '{print $4}'
echo "$i IN A $j" >>$NAME.zone
echo "$ARPA_IP2 IN PTR $i.$NAME." >>$REV
[ $? -eq 0 ]&& echo -e "The $NAME config success:\n$i IN A $j\n$ARPA_IP2 IN PTR $i.$NAME."
done
else
echo "The $FILE List File IS Not Exist .......,Please exit ..."
fi
fi
}

Define Shell Select Menu

PS3="Please select Menu Name Config: "
select i in "自动安装Bind服务" "自动初始化Bind配置" "添加解析域名" "批量添加A记录"
do
case $i in
"自动安装Bind服务")
Install
;;
"自动初始化Bind配置")
Init_Config
;;
"添加解析域名")
Add_named
;;
"批量添加A记录")
Add_A_List
;;

  • )
    echo -----------------------------------------------------
    sleep 1
    echo "Please exec: sh $0 { Install(1) or Init_Config(2) or Add_named(3) or Add_config_A(4) }"
    ;;
    esac
    done
    第19章 自动化运维发展前景
    随着企业服务器数量越来越多,当到达几百台,上千台服务器之后,服务器日常管理也逐渐繁杂,每天如果通过人工去频繁的更新或者部署及管理这些服务器,势必会浪费大量的时间,而且有可能人为的操作也会造成某些疏忽而遗漏。那我们来看一下传统的运维以及今后运维的发展方向。
    本章向读者介绍如何构建企业自动化运维之路、传统运维方案及自动化运维方案、如何建立高效的IT自动化运维平台以及自动化运维体系各种工具等。
    19.1 传统运维方式简介
    传统的IT运维仍然是等到IT故障出现后再由运维人员采取相应的补救措施。这种被动、孤立、半自动式的IT运维管理模式经常让IT部门疲惫不堪,主要表现在以下三个方面:
    (1)运维人员被动、效率低
    在IT运维过程中,只有当事件已经发生并已造成业务影响时才能发现和着手处理,这种被动“救火”不但使IT运维人员终日忙碌,也使IT运维本身质量很难提高,导致IT部门和业务部门对IT运维的服务满意度都不高。
    (2)缺乏一套高效的IT运维机制
    许多企业在IT运维管理过程中缺少自动化的运维管理模式,也没有明确的角色定义和责任划分,使到问题出现后很难快速、准确地找到根本原因,无法及时地找到相应的人员进行修复和处理,或者是在问题找到后缺乏流程化的故障处理机制,而在处理问题时不但欠缺规范化的解决方案,也缺乏全面的跟踪记录。
    (3)缺乏高效的IT运维技术工具
    随着信息化建设的深入,企业IT系统日趋复杂,林林总总的网络设备、服务器、中间件、业务系统等让IT运维人员难以从容应对,即使加班加点地维护、部署、管理也经常会因设备出现故障而导致业务的中断,严重影响企业的正常运转。
    出现这些问题部分原因是企业缺乏事件监控和诊断工具等IT运维技术工具,因为在没有高效的技术工具的支持下故障事件很难得到主动、快速的处理。
    19.2 自动化运维简介
    IT运维已经在风风雨雨中走过了十几个春秋,如今它正以一种全新的姿态摆在我们面前,运维自动化-这是IT技术发展的必然结果,现在IT系统的复杂性已经客观上要求IT运维必须能够实现数字化、自动化维护。
    运维自动化是指将IT运维中日常的、大量的重复性工作自动化,把过去的手工执行转为自动化操作。自动化是IT运维工作的升华,IT运维自动化不单纯是一个维护过程,更是一个管理的提升过程,是IT运维的最高层次,也是未来的发展趋势。
    19.3 运维自动化的具体内容
    日常IT运维中大量的重复性工作(小到简单的日常检查、配置变更和软件安装,大到整个变更流程的组织调度)由过去的手工执行转为自动化操作,从而减少乃至消除运维中的延迟,实现“零延时”的IT运维。
    简单的说,IT运维自动化是指基于流程化的框架,将事件与IT流程相关联,一旦被监控系统发生性能超标或宕机,会触发相关事件以及事先定义好的流程,可自动启动故障响应和恢复机制。
    19.4 建立高效的IT自动化运维管理
    建立高效的IT自动化运维管理步骤主要包括以下几点:
    (1)建立自动化运维管理平台
    IT运维自动化管理建设的第一步是要先建立IT运维的自动化监控和管理平台。通过监控工具实现对用户操作规范的约束和对IT资源进行实时监控,包括服务器、数据库、中间件、存储备份、网络、安全、机房、业务应用和客户端等内容,通过自动监控管理平台实现故障或问题综合处理和集中管理。
    (2)建立故障事件自动触发流程,提高故障处理效率
    所有IT设备在遇到问题时要会自动报警,无论是系统自动报警还是使用人员报的故障,应以红色标识显示在运维屏幕上。然后IT运维人员只需要按照相关知识库的数据,一步一步操作就可以。
    (3)建立规范的事件跟踪流程,强化运维执行力度
    需要建立故障和事件处理跟踪流程,利用表格工具等记录故障及其处理情况,以建立运维日志,并定期回顾从中辨识和发现问题的线索和根源。
    (4)设立IT运维关键流程,引入优先处理原则
    设置自动化流程时还需要引入优先处理原则,例行的事按常规处理,特别事件要按优先级次序处理,也就是把事件细分为例行事件和例外关键事件。
    19.5 IT自动化运维工具
    对于企业来说,要特别关注两类自动化工具:一是IT运维监控和诊断优化工具;二是运维流程自动化工具。这两类工具主要应用于:
    (1)监控自动化:是指对重要的IT设备实施主动式监控,如路由器、交换机、防火墙等。
    (2)配置变更检测自动化:是指IT设备配置参数一旦发生变化,将触发变更流程转给相关技术人员进行确认,通过自动检测协助IT运维人员发现和维护配置。
    (3)维护事件提醒自动化:是指通过对IT设备和应用活动的时时监控,当发生异常事件时系统自动启动报警和响应机制,第一事件通知相关责任人。
    (4)系统健康检测自动化:是指定期自动地对IT设备硬件和应用系统进行健康巡检,配合IT运维团队实施对系统的健康检查和监控。
    (5)维护报告生成自动化:是指定期自动的对系统做日志的收集分析,记录系统运行状况,并通过阶段性的监控、分析和总结,定时提供IT运维的可用性、性能、系统资源利用状况分析报告。
    19.6 IT自动化运维体系
    一个完善的自动化运维体系包括系统预备、配置管理以及监控报警三种环节,每个环节实现的功能也各不相同,具体功能如下:
    (1)系统预备类:
    自动化安装操作系统;
    自动初始化系统;
    自动安装各种软件包。
    (2)配置管理类:
    自动化部署业务系统软件包并完成配置;
    远程管理服务器;
    配置文件、自动部署Jenkins、网站代码变更回滚。
    (3)监控报警类:
    服务器可用性、性能、安全监控;
    向管理员发送报警信息。
    根据提供的功能不同,自动化运维工具软件分为以下 3 类,如下19-1表所示:
    编号 预备类工具 配置管理类 监控报警类
    1 Kickstart Puppet Nagios
    2 Cobbler Saltstack Cacti
    3 OpenQRM Func Ganglia
    4 Spacewalk Ansible Zabbix
    表19-1 自动化运维工具分类
    第20章 Puppet自动运维企业实战
    Puppet是目前互联网主流三大自动化运维工具(Puppet、Ansible、Saltstack)之一,Puppet是一种Linux、Unix平台的集中配置管理系统,所谓配置管理系统,就是管理机器里面诸如文件、用户、进程、软件包等资源,其设计目标是简化对这些资源的管理以及妥善处理资源间的依赖关系。
    本章向读者介绍Puppet工作原理、Puppet安装配置、企业资源案例讲解、Puppet高可用集群配置、Puppet批量更新部署网站、Puppet+SVN实现代码自动部署等。
    20.1 Puppet入门简介
    Puppet使用一种描述性语言来定义配置项,配置项中被称为”资源”,描述性语言可以声明你的配置的状态,比如声明一个软件包应该被安装或者一个服务应该被启动用。
    Puppet可以运行一台服务器端,每个客户端通过ssl证书连接服务器,得到本机器的配置列表,然后更加列表的来完成配置工作,所以如果硬件性能比较高,维护个管理上千上万台机器是非常轻松的,前提是客户端机器的配置、服务器路径、软件需要保持一致。
    在企业级大规模的生成环境中,如果只有一台puppet master压力会非常大,因为puppet是用ruby语言编写,ruby是解析型语言,每个客户端来访问都要解析一次,当客户端服务器很多,会操作服务器端压力很多,所以需要扩展成一个服务器集群组。
    Puppet master可以看作一个web服务器,实际上也是由ruby提供的web服务器模块来做的。因此可以利用web代理软件来配合puppet master做集群设置,一般使用Nginx+Puppet Master整合构建大型企业自动化运维管理工具,puppet项目主要开发者是Luke Kanies,目前为puppet labs CEO,Puppet遵循GPLv2版权协议。
    从1997年开始Kanies参与UNIX的系统管理工作,Puppet的开发源于这些经验。因为对已有的配置工具不甚满意,从2001年到2005年间,Kanies开始在Reductive实验室从事工具的开发。很快Reductive实验室发布了他们新的旗舰产品。
    Puppet是开源的基于Ruby的系统配置管理工具,Puppet工作流程为:puppet是一个C/S结构,所有的puppet客户端同一个服务器端的puppet通讯,每个puppet客户端每半小时(可以设置)连接一次服务器端,下载最新的配置文件,并且严格按照配置文件来配置服务器,配置完成以后puppet客户端可以反馈给服务器端一个消息,如果报错会给服务器端反馈一个消息。
    20.2 Puppet工作原理
    要熟练掌握Puppet在企业生产环境中的应用,需要深入理解Puppet服务端与客户端详细的工作流程及原理,如图20-1(a)、20-1(b)所示,为Puppet Master与Agent完整工作流程图:
    图20-1(a) Puppet工作原理图
    图20-1(b) Puppet工作原理图
    Puppet工作原理详解如下:
    客户端puppetd调用本地facter,facter会探测出该主机的常用变量,例如主机名、内存大小、IP地址等。然后puppetd把这些信息发送到Puppet服务端。
    Puppet服务端检测到客户端的主机名,然后会检测manifest中对应的node配置,并对这段内容进行解析,facter发送过来的信息可以作为变量进行处理。
    Puppet服务端匹配Puppet客户端相关联的代码才进行解析,其它的代码不解析,解析分几个过程:语法检查、然后会生成一个中间的伪代码,然后再把伪代码发给Puppet客户端。
    Puppet客户端接收到伪代码之后就会执行,执行完后会将执行的结果发送给Puppet服务端。
    Puppet服务端再把客户端的执行结果写入日志。
    20.3 Puppet安装配置
    由于Puppet为C/S模式,构建Puppet平台需安装Puppet Sserver端和Client端,安装之前准备好系统环境,如下:
    操作系统版本:CentOS 6.5 x64
    服务端ip 192.168.149.128 hostname:192-168-149-128-jfedu.net
    客户端ip 192.168.149.130 hostname:192-168-149-130-jfedu.net
    (1)Puppet服务端安装
    由于Puppet主要是基于hostname来检测的,所以Puppet服务器端需修改主机名称为:192-168-149-128-jfedu.net,并且在hosts文件添加主机名和本机IP的对应关系,如果本地局域网有DNS服务器,可以无需修改hosts文件,修改主机名及配置hosts代码如下:
    hostname ifconfig eth0 |grep Bcast|awk '{print $2}'|cut -d: -f 2 |sed 's/\./\-/g'-jfedu.net
    cat >>/etc/hosts<<EOF
    192.168.149.128 192-168-149-128-jfedu.net
    192.168.149.130 192-168-149-130-jfedu.net
    EOF
    Puppet服务端除了需要安装Puppet-server外,还需要Ruby的支持,需要安装Ruby相关软件包,默认YUM安装Puppet Server,会自动下载并安装Ruby相关软件,如图20-2所示:
    rpm -Uvh http://yum.puppetlabs.com/el/6/products/x86_64/puppetlabs-release-6-1.noarch.rpm
    yum install puppet-server -y
    /etc/init.d/puppetmaster start
    /etc/init.d/iptables stop
    sed -i '/SELINUX/S/enforce/disabled/' /etc/selinux/config
    setenforce 0
    图20-2 Puppet-server服务端安装
    (2)Puppet客户端安装
    Puppet主要是基于hostname来检测的,所以Puppet客户端也需要修改主机名称为:192-168-149-130-jfedu.net,并且在hosts文件添加主机名和本机IP的对应关系,如果本地局域网有DNS服务器,可以无需修改hosts文件,修改主机名及配置hosts代码如下:
    hostname ifconfig eth0 |grep Bcast|awk '{print $2}'|cut -d: -f 2 |sed 's/\./\-/g'-jfedu.net
    cat >>/etc/hosts<<EOF
    192.168.149.128 192-168-149-128-jfedu.net
    192.168.149.130 192-168-149-130-jfedu.net
    EOF
    Puppet客户端除了需要安装puppet外,还需要Ruby的支持,需要安装Ruby相关软件包,默认YUM安装Puppet,会自动下载并安装Ruby相关软件,如图20-3所示:
    rpm -Uvh http://yum.puppetlabs.com/el/6/products/x86_64/puppetlabs-release-6-1.noarch.rpm
    yum install puppet -y
    /etc/init.d/puppetmaster start
    /etc/init.d/iptables stop
    sed -i '/SELINUX/S/enforce/disabled/' /etc/selinux/config
    setenforce 0
    图20-3 Puppet客户端服务安装
    (3)Puppet客户端申请证书
    由于Puppet客户端与Puppet服务端是通过SSL隧道通信的,客户端安装完成后,首次使用需向服务器端申请Puppet通信证书, Puppet客户端第一次连接服务器端会发起证书申请,在Puppet客户端执行命令如下,返回结果如图20-4所示:
    puppet agent --server 192-168-149-128-jfedu.net --test
    图20-4 Puppet客户端发起证书申请
    (4)Puppet服务端颁发证书
    Puppet客户端向服务器发起证书申请,服务器端必须审核证书,如果不审核,客户端与服务器端无法进行后续正常通信,Puppet服务端颁发证书命令代码如下,返回结果如图20-5所示:
    puppet cert --list 查看申请证书的客户端主机名;
    puppet cert -s 192-168-149-130-jfedu.net 颁发证书给客户端;
    puppet cert -s 为特定的主机颁发证书;
    puppet cert -s and -a 给所有的主机颁发证书;
    puppet cert --list --all 查看已经颁发的所有证书。

图20-5 Puppet服务端颁发证书
20.4 Puppet企业案例演示
Puppet是基于C/S架构,服务器端保存着所有对客户端服务器的配置代码,在puppet服务端该配置文件叫manifest,客户端下载manifest之后,可以根据manifest对客户端进行配置,例如软件包管理、用户管理、文件管理、命令管理、脚本管理等,Puppet主要基于各种资源或者模块来管理客户端。
默认Puppet服务器端manifest目录在/etc/puppet/manifests/下,只需要在该目录下创建一个site.pp文件,然后写入相应的配置代码,Puppet客户端跟Puppet服务端同步时,会检查客户端node配置文件,匹配之后会将该代码下载至客户端,对代码进行解析,然后在客户端执行。
如下为在Puppet客户端创建test.txt文件,并在该文件中写入测试内容,操作方法如下:
(1)Puppet服务端创建node代码,创建或者编辑vi /etc/puppet/manifests/site.pp文件,在文件中加入如下代码:
node default {
file {
"/tmp/test.txt":
content => "Hello World,jfedu.net 2017";
}
}
manifests site.pp配置文件代码详解如下:
node default 新建node节点,default表示所有主机,可修改为特定主机名;
file 基于file资源模块管理客户端文件或者目录操作;
"/tmp/test.txt": 需在客户端文件创建的文件名;
content 客户端服务器文件内容。
(2)客户端执行同步命令,获取Puppet服务端node配置,代码如下,如图20-6所示,执行报错:
puppet agent --server=192-168-149-128-jfedu.net --test

图20-6 Puppet客户端同步服务端配置
报错原因是因为服务器端与客户端时间不同步导致,需要同步时间,然后再次执行puppet agent命令,如图20-7所示:
ntpdate pool.ntp.org
puppet agent --server=192-168-149-128-jfedu.net --test
图20-7 Puppet客户端获取服务端node配置
Puppet客户端执行同步效果,执行日志如下,会在/tmp/目录创建test.txt文件,内容为:“Hello World,jfedu.net”,即证明Puppet客户端成功获取服务端node配置。
Info: Caching certificate_revocation_list for ca
Warning: Unable to fetch my node definition, but the agent run will continue:
Warning: undefined method `include?' for nil:NilClass
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for 192-168-149-130-jfedu.net
Info: Applying configuration version '1496805041'
Notice: /Stage[main]/Main/Node[default]/File[/tmp/test.txt]/ensure: defined content as '{md5}d1c2906ad0b249a330e936e3bc1d38d9'
Info: Creating state file /var/lib/puppet/state/state.yaml
Notice: Finished catalog run in 0.04 seconds
20.5 Puppet常见资源及模块
Puppet主要基于各种资源模块管理客户端,目前企业主流Puppet管理客户端资源模块如下:
file 主要负责管理文件;
package 软件包的安装管理;
service 系统服务的管理;
cron 配置自动任务计划;
exec 远程执行运行命令。
通过命令puppet describe -l可以查看puppet支持的所有资源和模块,如图20-8(a)、20-8(b)所示:

图20-8(a) Puppet支持的资源及模块
图20-8(b) Puppet支持的资源及模块
通过命令puppet describe -s file可以查看puppet file资源所有的帮助信息,如图20-9(a)、20-9(b)所示:
图20-9(a) Puppet file资源模块详情
图20-9(b) Puppet file资源模块详情
20.6 Puppet file资源案例
Puppet file资源主要用于管理客户端文件,包括文件的内容、所有权和权限,其可管理的文件类型包括:普通文件、目录以及符号链接等。
类型应在“确保”属性中指定,如果是文件内容可以直接用'content属性来管理,或者使用source属性从远程源下载;后者也可以用recurse服务目录(当recurse属性设置为“true”或“local”。Puppet file资源支持参数如下:
ensure 默认为文件或目录;
backup 通过filebucket备份文件;
checksum 检查文件是否被修改的方法;
ctime 只读属性,文件的更新时间;
mtime 只读属性,文件的修改时间;
content 文件的内容,与source和target互斥 ;
force 强制执行删除文件、软链接机目录的操作;
owner 用户名或用户ID;
group 指定文加年的用户组或组id;
link 软链接;
mode 文件权限配置,通常采用数字符号;
path 文件路径;
Parameters
backup, checksum, content, ctime, ensure, force, group, ignore, links,
mode, mtime, owner, path, purge, recurse, recurselimit, replace,
selinux_ignore_defaults, selrange, selrole, seltype, seluser, show_diff,
source, source_permissions, sourceselect, target, type, validate_cmd,
validatereplacement
Providers:
posix, windows
(1)从Puppet服务器下载nginx.conf文件至客户端/tmp目录,首先需要将nginx.conf文件cp至/etc/puppet/files目录,然后在/etc/puppet/fileserver.conf中添加如下三行代码,并重启Puppetmaster即可:
[files]
path /etc/puppet/files/
allow *
创建site.pp文件,文件代码如下:
node default {
file {
'/tmp/nginx.conf':
mode => '644',
owner => 'root',
group => 'root',
source => 'puppet://192-168-149-128-jfedu.net/files/nginx.conf',
}
}
客户端同步配置,如图20-10所示:
图20-10 Puppet file资源远程下载文件
(2)从Puppet服务器下载sysctl.conf,如果客户端该文件存在则备份为sysctl.conf.bak,然后再覆盖原文件,site.pp代码如下,如图20-11所示:
node default {
file {
"/etc/sysctl.conf":
source => "puppet://192-168-149-128-jfedu.net/files/sysctl.conf",
backup => ".bak
$uptime_seconds",
}
}
图20-11 Puppet file资源备份文件
(3)在Agent上创建/export/docker的软连接为/var/lib/docker/,site.pp代码如下,如图20-12所示:
node default {
file {
"/var/lib/docker":
ensure => link,
target => "/export/docker",
}
图20-12 Puppet file资源备份文件
(4)在Agent上创建目录/tmp/20501212,site.pp代码如下,如图20-13所示:
node default {
file {
"/tmp/20501212":
ensure => directory;
}
}
图20-13 Puppet file创建目录
20.7 Puppet package资源案例
Puppet package资源主要用于管理客户端服务器的软件包,yum源为/etc/yum.repo.d/安装和升级操作,通过puppet基于yum自动安装软件包,所以需要先配置好yum源。
常见的操作可以对软件包进行安装、卸载以及升级操作。Puppet package资源支持参数如下:
Parameters
adminfile, allow_virtual, allowcdrom, category, configfiles,
description, ensure, flavor, install_options, instance, name,
package_settings, platform, responsefile, root, source, status,
uninstall_options, vendor
Providers
aix, appdmg, apple, apt, aptitude, aptrpm, blastwave, dpkg, fink,
freebsd, gem, hpux, macports, msi, nim, openbsd, opkg, pacman, pip, pkg,
pkgdmg, pkgin, pkgutil, portage, ports, portupgrade, rpm, rug, sun,
sunfreeware, up2date, urpmi, windows, yum, zipper
ensure => {installed|absent|pureged|latest}
present 检查软件是否存在,不存在则安装;
installed 表示安装软件;
absent 删除(无依赖),当别的软件包依赖时,不可删除;
pureged 删除所有配置文件和依赖包,有潜在风险,慎用;
latest 升级到最新版本;
version 指定安装具体的某个版本号。
(1)客户端安装ntpdate及screen软件,代码如下,执行结果如图20-14所示:
node default {
package {
["screen","ntp"]:
ensure => "installed";
}
图20-14 Puppet package安装软件
(2)客户端卸载ntpdate及screen软件,代码如下,执行结果如图20-15所示:
node default {
package {
["screen","ntp"]:
ensure => "absent";
}
图20-15 Puppet package卸载软件
20.8 Puppet service资源案例
Puppet service资源主要用于启动、重启和关闭客户端的守护进程,同时可以监控进程的状态,还可以将守护进程加入到自启动中。Puppet service资源支持参数如下:
Parameters
binary, control, enable, ensure, flags, hasrestart, hasstatus, manifest,
name, path, pattern, restart, start, status, stop

Providers
base, bsd, daemontools, debian, freebsd, gentoo, init, launchd, openbsd,
openrc, openwrt, redhat, runit, service, smf, src, systemd, upstart,
windows
enable 指定服务在开机的时候是否启动,可以设置true和false;
ensure 是否运行服务,running表示运行,stopped表示停止服务;
name 守护进程的名字;
path 启动脚本搜索路径;
provider 默认为init;
hasrestart 管理脚本是否支持restart参数,如果不支持,就用stop和start实现restart效果;
hasstatus 管理脚本是否支持status参数,puppet用status参数来判断服务是否已经在运行了,如果不支持status参数,puppet利用查找运行进程列表里面是否有服务名来判断服务是否在运行。
(1)启动Agent httpd服务,停止nfs服务,代码如下,结果如图20-16(a)、20-16(b)所示:
node default {
service {
"httpd":
ensure => running;
"nfs":
ensure => stopped;
}
图20-16(a) Puppet service重启服务
图20-16(b) Puppet service重启服务
(2)启动Agent httpd服务并且开启启动,停止nfs服务,开启不启动,代码如下,结果如图20-17(a)、20-17(b)所示:
node default {
service {
"httpd":
ensure => running,
enable => true;
"nfs":
ensure => stopped,
enable => false;
}

图20-17(a) Puppet service开启启动
图20-17(b) Puppet service开启启动
20.9 Puppet exec资源案例
Puppet exec资源主要用于客户端远程执行命令或者软件安装等,相当于shell的调用,exec是一次性执行资源,在不同类里面exec名字可以相同。Puppet exec资源支持参数如下:
Parameters
command, creates, cwd, environment, group, logoutput, onlyif, path,
refresh, refreshonly, returns, timeout, tries, try_sleep, umask, unless,
user
Providers
posix, shell, windows
command 指定要执行的系统命令;
creates 指定命令所生成的文件;
cwd 指定命令执行目录,如果目录不存在,则命令执行失败;
group 执行命令运行的账户组;
logoutput 是否记录输出;
onlyif exec只会在onlyif设定的命令返回0时才执行;
path 命令执行的搜索路径;
refresh =>true|false 刷新命令执行状态;
refreshonly =>true|false 该属性可以使命令变成仅刷新触发的,
returns 指定返回的代码;
timeout 命令运行的最长时间;
tries 命令执行重试次数,默认为1;
try_sleep 设置命令重试的间隔时间,单位为秒;
user 指定执行命令的账户;
provider shell和windows;
environment 为命令设定额外的环境变量;要注意的是如果设定PATH,PATH的属性会被覆盖。
(1)Agent服务器执行tar解压nginx软件包,代码如下,结果如图20-18所示:
node default {
exec {
'Agent tar xzf nginx-1.12.0.tar.gz':
path => ["/usr/bin","/bin"],
user => 'root',
group => 'root',
timeout => '10',
command => 'tar -xzf /tmp/nginx-1.12.0.tar.gz',
}
}
图20-18 Puppet exec远程执行命令
(2)Agent服务器远程执行auto_install_nginx.sh脚本,代码如下,结果如图20-19所示:
node default {
file {
"/tmp/auto_install_nginx.sh":
source =>"puppet://192-168-149-128-jfedu.net/files/auto_install_nginx.sh",
owner => "root",
group => "root",
mode => 755,
}
exec {
"/tmp/auto_install_nginx.sh":
cwd => "/tmp",
user => root,
path => ["/usr/bin","/usr/sbin","/bin","/bin/sh"],
}

图20-19 Puppet exec执行Nginx安装脚本
(3)Agent服务器更新sysctl.conf,如果该文件发生改变,则执行命令sysctl -p,代码如下,结果如图20-20(a)、20-20(b)所示:
node default {
file {
"/etc/sysctl.conf":
source =>"puppet://192-168-149-128-jfedu.net/files/sysctl.conf",
owner => "root",
group => "root",
mode => 644,
}
exec {
"sysctl refresh kernel config":
path => ["/usr/bin", "/usr/sbin", "/bin", "/sbin"],
command => "/sbin/sysctl -p",
subscribe => File["/etc/sysctl.conf"],
refreshonly => true
}
}
图20-20(a) Puppet exec更新执行触发命令
图20-20(b) Puppet exec更新执行触发命令
20.10 Puppet cron资源案例
Puppet cron资源主要用于安装和管理crontab计划任务,每一个cron资源需要一个command属性和user属性以及至少一个周期属性(hour,minute,month,monthday,weekday)。
Crontab计划任务的名字不是计划任务的一部分,它是puppet用来存储和检索该资源。假如你指定了一个除了名字其他的都和一个已经存在的计划任务相同,那么这两个计划任务被认为是等效的,并且新名字将会永久地与该计划任务相关联。Puppet cron资源支持参数如下:
Parameters
command, ensure, environment, hour, minute, month, monthday, name,
special, target, user, weekday
Providers
crontab
user 加某个用户的crontab任务,默认是运行puppet的用户;
command 要执行的命令或脚本路径,可不写,默认是title名称;
ensure 定该资源是否启用,可设置成true或false;
environment crontab环境里面指定环境变量;
hour 设置crontab的小时,可设置成0-23;
minute 指定crontab的分钟,可设置成0-59;
month 指定crontab运行的月份,1-12;
monthday 指定月的天数1-31;
name crontab的名字,区分不同的crontab;
provider 可用的provider有crontab默认的crontab程序;
target crontab作业存放的位置;
weekday 行crontab的星期数,0-7,周日是为0。
(1)Agent服务器添加ntpdate时间同步任务,代码如下,结果如图20-21所示:
node default {
cron{
"ntpdate":
command => "/usr/sbin/ntpdate pool.ntp.org",
user => root,
hour => 0,
minute => 0,
}
}
图20-21 Puppet cron创建任务计划
(2)Agent服务器删除ntpdate时间同步任务,代码如下,结果如图20-22所示:
node default {
cron{
"ntpdate":
command => "/usr/sbin/ntpdate pool.ntp.org",
user => root,
hour => 0,
minute => 0,
ensure => absent,
}
}
图20-22 Puppet cron删除任务计划
20.11 Puppet日常管理与配置
Puppet平台构建完毕,能够简单实用Puppet去管理客户端,对文件、服务、脚本、各种配置的变更,如果要管理批量服务器,还需要进行一些步骤的配置。
20.11.1 Puppet自动认证
企业新服务器通过kickstart自动安装Linux操作系统,安装完毕,可以自动安装puppet相关软件包,Puppet客户端安装完毕,需向Puppet服务端请求证书,然后Puppet服务端颁发证书给客户端,默认需要手动颁发,可以通过配置让Puppet服务端自动颁发证书。
自动颁发证书前提是服务端与客户端能ping通彼此的主机名方可,配置自动颁发证书需Puppet服务器端的puppet.conf配置文件main段加入如下代码,如图20-23所示:
[main]
autosign = true
图20-23 Puppet 服务端添加自动颁发证书
重启puppetmaster服务,并且删除192.168.149.130证书:
/etc/init.d/puppetmaster restart
puppet cert --clean 192-168-149-130-jfedu.net
删除Puppet客户端SSL文件,重新生成SSL文件,执行如下命令自动申请证书:
rm -rf /var/lib/puppet/ssl/
puppet agent --server=192-168-149-128-jfedu.net --test
Puppet服务端会自动认证,即服务器端不必手动颁发证书,减轻人工的干预和操作,如图20-24所示:
图20-24 Puppet客户端自动获取证书
20.11.2 Puppet客户端自动同步
Puppet客户端安装完,并且认证完之后,如果在Puppet服务端配置了node信息,客户端启动服务,默认30分钟自动与服务端同步信息,如何修改同步的时间频率呢,修改puppet客户端配置信息即可:
Puppet客户端配置puppet相关参数和同步时间,修改/etc/sysconfig/puppet配置文件,最终代码如下:

The puppetmaster server

PUPPET_SERVER=192-168-149-128-jfedu.net

If you wish to specify the port to connect to do so here

PUPPET_PORT=8140

Where to log to. Specify syslog to send log messages to the system log.

PUPPET_LOG=/var/log/puppet/puppet.log

You may specify other parameters to the puppet client here

PUPPET_EXTRA_OPTS=--waitforcert=500
/etc/sysconfig/puppet配置文件参数详解:
PUPPET_SERVER=192-168-149-128-jfedu.net 指定Puppet master主机名;
PUPPET_PORT=8140 指定puppet master端口;
PUPPET_LOG=/var/log/puppet/puppet.log puppet客户端日志路径;
PUPPET_EXTRA_OPTS=--waitforcert=500 获取Puppet master证书返回等待时间。
重启puppet客户端服务,户端会半个小时跟服务器同步一次配置信息:
/etc/init.d/puppet restart
可以修改与服务器端同步配置信息的时间,修改vi /etc/puppet/puppet.conf文件,在[agent]段加入如下语句,表示60秒于puppet master同步一次配置信息,重启puppet,同步结果如图20-25所示:
[agent]
runinterval = 60
图20-25 Puppet客户端自动同步服务端配置
20.11.3 Puppet服务端主动推送
如上puppet客户端配置每60秒与服务端同步配置信息,如果服务器端更新了配置信息,想立刻让客户端同步,如何通知客户端来获取最新的配置信息呢,可以使用Puppet master主动推送的方式,让客户端更新服务端最新的配置信息。
Puppet服务器端使用puppet run命令可以给客户端发送一段信号,告诉客户端立刻跟服务器同步配置信息,配置方法如下:
修改Puppet客户端配置文件/etc/puppet/puppet.conf,在agent段加入如下代码:
[agent]
listen = true
修改Puppet客户端配置文件/etc/sysconfig/puppet指定puppet master端主机名:
PUPPET_SERVER=192-168-149-128-jfedu.net
创建Puppet客户端配置文件namespaceauth.conf,写入如下代码:
[puppetrunner]
allow
修改Puppet客户端配置文件auth.conf,在path /前添加如下代码:
path /run
method save
allow

重启Puppet客户端: /etc/init.d/puppet restart
Puppet服务端执行如下命令,通知客户端来同步配置,也可以批量通知其他客户端,只需将客户端的主机名写入host.txt文件,如图20-26所示:
puppet kick -d 192-168-149-130-jfedu.net

puppet kick -d 'cat host.txt'

图20-26 Puppet主动通知客户端同步配置
20.12 Puppet批量部署案例
随着IT行业的迅猛发展,传统的运维方式靠大量人力比较吃力,近几年自动化运维管理快速的发展,得到了很多IT运维人员的青睐,一个完整的自动化运维包括系统安装、配置管理、服务监控三个方面。如下为Puppet生成环境中应用案例。
某互联网公司新到100台硬件服务器,要求统一安装Linux系统,并部署上线以及后期的管理配置。对于Linux系统安装,需采用批量安装,批量安装系统主流工具为Kickstart和Cobbler,任选其一即可。
如果采用自动安装的话,我们可以自动初始化系统、内核简单优化、及常见服务、软件客户端等安装。当然puppet客户端也可以放在kickstart中安装并配置完毕。
当Linux操作系统安装完成后,需要对服务器进行相应的配置,方可在应对高并发网站,例如修改动态IP为静态IP、安装及创建Crontab任务计划、同步操作系统时间、安装Zabbix客户端软件、优化内核参数等,可以基于Puppet统一调整:
20.12.1 Puppet批量修改静态IP案例
现需要修改100台Linux服务器原Dhcp动态获取的IP为Static IP地址,首先需有修改IP脚本,将该脚本推送到客户端,然后执行脚本并重启网卡即可,步骤如下:
(1)修改IP为静态IP的Shell脚本代码如下:

!/bin/bash

auto Change ip netmask gateway scripts

By author jfedu.net 2017

Define Path variables

ETHCONF=/etc/sysconfig/network-scripts/ifcfg-eth0
DIR=/data/backup/date +%Y%m%d
IPADDR=ifconfig|grep inet|grep 192|head -1|cut -d: -f2|awk '{print $1}'
NETMASK=255.255.255.0
grep dhcp $ETHCONF
if [ $? -eq 0 ];then
sed -i 's/dhcp/static/g' $ETHCONF
echo -e "IPADDR=$IPADDR\nNETMASK=$IPADDR|awk -F. '{print $IPADDR|awk -F. '{print $1"."$2"."$3}'.2" >>$ETHCONF echo "The IP configuration success. !" service network restart fi (2)Puppet master 执行kick推送配置至Agent服务器远程,Puppet 客户端修改IP脚本代码如下,结果如图20-27(a)、20-27(b)所示: node default { file { "/tmp/auto_change_ip.sh": source =>"puppet://192-168-149-128-jfedu.net/files/auto_change_ip.sh", owner => "root", group => "root", mode => 755, } exec { "/tmp/auto_change_ip.sh": cwd => "/tmp/", user => root, path => ["/usr/bin","/usr/sbin","/bin","/bin/sh"], } } 图20-27(a) Puppet主动通知客户端同步配置 图20-26 Puppet客户端IP自动配置为Static方式 20.12.2 Puppet批量配置NTP同步服务器 在100台Linux服务器上配置crontab任务,修改ntpdate与ntp服务端同步时间,操作步骤如下: (1)Puppet master上创建客户端node配置,可以编写NTP模块,使用class可以定义模块分组,对不同业务进行分组管理,/etc/puppet/modules/ntp/manifests/init.pp配置文件代码如下,将原ntpdate同步时间从0:0分改成每5分钟同步一次时间,并且修改原pool.ntp.org服务器为本地局域网NTP时间服务器的IP地址: class ntp { Exec { path =>"/bin:/sbin:/bin/sh:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"} exec { "auto change crontab ntp config": command =>"sed -i -e '/ntpdate/s/0/*\/5 /2' -e 's/pool.ntp.org/10.1.1.21/' /var/spool/cron/root", } } (2)在/etc/puppet/manifests目录创建两个文件,分别为modules.pp和nodes.pp,模块入口文件以及node配置段。 modules.pp配置文件内容如下: import "ntp"  nodes.pp配置文件内容如下: node default { include ntp } (3)在site.pp 中加载导入modules.pp 和nodes.pp名称,site.pp代码如下: import "modules.pp" import "nodes.pp" (4)Puppet master 执行kick推送配置至Agent服务器远程,Puppet 客户端最终结果如图20-28(a)、20-28(b)所示: 图20-28(a) Puppet服务端class模块配置 图20-28(b) Puppet主动通知客户端修改NTP同步配置 当服务器分组之后,为了更好的管理和配置,可以使用正则表达式来进行定义node,在定义一个node节点时,要指定节点的名字,并使用单引号将名字引起来,然后在大括号中指定需要应用的配置。 客户端节点名字可以是主机名也可以是客户端的正式域名,目前Puppet版本还不能使用通配符来指定节点,例如不能用*.jfedu.net,可以使用正则表达式,如下代码: node /^Beijing-IDC-web0\d+\-jfedu\.net {     include ntp } 如上规则会匹配所有在jfedu.net域并且主机名以Beijing-IDC开头,紧跟web01、web02、web03...web100...等节点,由此可以进行批量服务器的分组管理。 20.12.3 Puppet自动部署及同步网站 企业生产环境100台服务器,所有服务器要求要求数据一致,可以采用rsync同步,配置rsync服务器端,客户端执行脚本命令即可,同样可以使用Puppet+Shell脚本来同步,这样比较快捷,也可以使用Puppet rsync模块。 (1)Puppet服务器端配置,/etc/puppet/modules/www/manifests/init.pp代码如下: class www { Exec { path =>"/bin:/sbin:/bin/sh:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"} file { "/data/sh/rsync_www_client.sh": source =>"puppet://192-9-117-162-tdt.com/files/www/rsync_www_client.sh", owner =>"root", group =>"root", mode =>"755", } file { "/etc/rsync.pas": source =>"puppet://192-9-117-162-tdt.com/files/www/rsync.pas", owner =>"root", group =>"root", mode =>"600", } exec { "auto backup www data": command =>"mkdir -p /data/backup/date +%Y%m%d;mv /data/index /data/backup/www/date +%Y%m%d; /bin/sh /data/sh/rsync_www_client.sh ", user =>"root", subscribe =>File["/data/sh/rsync_www_client.sh"], refreshonly =>"true", } } (2)在/etc/puppet/manifests目录创建两个文件,分别为modules.pp和nodes.pp,模块入口文件以及node配置段。 modules.pp配置文件内容如下: import "www"  nodes.pp配置文件内容如下: node /^Beijing-IDC-web0\d+\-jfedu\.net { include www } (3)在site.pp 中加载导入modules.pp 和nodes.pp名称,site.pp代码如下: import "modules.pp" import "nodes.pp" Puppet master端批量执行通知客户端来同步配置,命令如下: puppet kick -d --hostcat hosts.txt`
(4)cat hosts.txt内容为需要同步的客户端的主机名:
Beijing-IDC-web01-jfedu.net
Beijing-IDC-web02-jfedu.net
Beijing-IDC-web03-jfedu.net
Beijing-IDC-web04-jfedu.net
第21章 Ansible自动运维企业实战
随着互联网IT运维飞速发展,目前市场上涌现了大量的自动化配置维护工具,例如 PSSH、Puppet、Chef、SaltStack、Ansible等。目前互联网企业使用最多的两款自动化配置工具Ansible和Saltstack。自动配置工具存在的初衷就是为了更方便、快捷的进行配置管理,它易于安装和使用、语法也非常简单易学。
本章向读者介绍Ansible工作原理、Ansible安装配置、生产环境模块讲解、Ansible企业场景案例、PlayBook剧本实战及Ansible性能调优等。
21.1 自动化运维工具简介
曾有媒体报道,Facebook一个运维人员管理上万台服务器,如果使用手工的方法去维护是很难做到的,基于自动化工具就可以轻松的实现管理上万台、甚至十万台。
如下为IT运维主流自动化管理工具Puppet、saltstack、Ansible各自优缺点:
21.1.1 Puppet自动运维工具特点:
Puppet是早期的Linux自动化运维工具,是一种Linux、Unix、Windows平台的集中配置管理系统,发展至今目前已经非常成熟,可以批量管理远程服务器,模块丰富,配置复杂,基于Ruby语言编写。最典型的C/S模式,需要安装服务端与客户端。
puppet采用C/S星状的结构,所有的客户端和一个或几个服务器交互,每个客户端周期的(默认半个小时)向服务器发送请求,获得其最新的配置信息,保证和该配置信息同步。
每个puppet客户端每半小时(可以设置)连接一次服务器端, 下载最新的配置文件,并且严格按照配置文件来配置客户端. 配置完成以后,puppet客户端可以反馈给服务器端一个消息,如果出错也会给服务器端反馈一个消息。
Puppet适用于服务器管理的整个过程,比如初始安装、配置、更新以及系统下线。
21.1.2 Saltstack自动运维工具特点:
Saltstack与Puppet均是C/S模式,需安装服务端与客户端,基于Python编写,加入MQ消息同步,可以使执行命令和执行结果高效返回,但其执行过程需等待客户端全部返回,如果客户端未及时返回或未响应的话,可能会导致部分机器没有执行结果。
21.1.3 Ansible自动运维工具特点:
Ansible与Saltstack均是基于Python语言开发,Ansible只需要在一台普通的服务器上运行即可,不需要在客户端服务器上安装客户端。因为Ansible是基于SSH远程管理,而Linux服务器大都离不开SSH,所以Ansible不需要为配置工作添加额外的支持。
Ansible安装使用非常简单,而且基于上千个插件和模块实现各种软件、平台、版本的管理,支持虚拟容器多层级的部署。很多读者在使用Ansible工具时,认为Ansible比Saltstatck执行效率慢,其实不是软件本身慢,是由于SSH服务慢,可以优化SSH连接速度及使用Ansible加速模块,满足企业上万台服务器的维护和管理。
21.2 Ansible运维工具原理
Ansible是一款极为灵活的开源工具套件,能够大大简化Unix管理员的自动化配置管理与流程控制方式。它利用推送方式对客户系统加以配置,这样所有工作都可在主服务器端完成。其命令行机制同样非常强大,允许大家利用商业许可Web UI实现授权管理与配置。
可以通过命令行或者GUI来使用Ansible,运行Ansible的服务器这里俗称“管理节点”;通过Ansible进行管理的服务器俗称“受控节点”。权威媒体报道Ansible于2015年被Red Hat公司1.5亿美元收购,新版Red Hat内置Ansible软件。
本书以Ansible为案例,基于Ansible构建企业自动化运维平台,实现大规模服务器的快速管理和部署。Ansible将平常复杂的配置工作变得简单,变得更加标准化更容易控制。
Ansible自动运维管理工具优点:
轻量级,更新时,只需要在操作机上进行一次更新即可;
采用SSH协议;
不需要去客户端安装agent;
批量任务执行可以写成脚本,而且不用分发到远程就可以执行;        
使用python编写的,维护更简单;     
支持sudo普通用户命令;
去中心化管理。
Ansible自动运维管理工具工作原理拓扑,如图21-1所示:
图21-1 Ansible工作原理图
21.3 Ansible管理工具安装配置
Ansible 可以工作在Linux、BSD、Mac OS X 等平台,对Python环境的版本最低要求为Python2.6以上,如果操作系统Python软件版本为2.4,需要升级方可使用Ansible工具。
Red Hat、CentOS操作系统可以直接基于YUM工具自动安装Ansible,CentOS6.x或者CentOS7.x安装前,需先安装epel扩展源,代码如下:
rpm -Uvh http://mirrors.ustc.edu.cn/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum install epel-release -y
yum install ansible -y
Ansible工具默认主目录为:/etc/ansible/,其中hosts文件为被管理机IP或者主机名列表,ansible.cfg为ansible主配置文件,roles为角色或者插件路径,默认该目录为空,如图21-2所示:

图21-2 Ansible主目录信息
Ansible远程批量管理,其中执行命令是通过Ad-Hoc来完成,也即点对点单条执行命令,能够快速执行,而且不需要保存执行的命令。默认hosts文件配置主机列表,可以配置分组,可以定义各种ip及规则,hosts列表默认配置如图21-3所示:

图21-3 Hosts主机列表文件内容
Ansible基于多模块管理,常用的Ansible工具管理模块包括:command、shell、script、yum、copy、File、async、docker、cron、mysql_user、ping、sysctl、user、acl、add_host、easy_install、haproxy等。
可以使用ansible-doc –l|more查看ansible支持的模块,也可以查看每个模块的帮助文档,ansible-doc module_name,如图21-4所示:

图21-4 Ansible-doc docker帮助信息
21.4 Ansible工具参数详解
基于Ansible批量管理之前,需将被管理的服务器IP列表添加至/etc/ansible/hosts文件中,如图21-5添加4台被管理端IP地址,分成web和db两组,本机也可以是被管理机。
图21-5 Ansible Hosts主机列表
基于Ansible自动运维工具管理客户端案例操作,由于Ansible管理远程服务器基于SSH,在登录远程服务器执行命令时需要远程服务器的用户名和密码,也可以加入-k参数手动输入密码或者基于ssh-keygen生成免秘钥。
Ansible自动化批量管理工具主要参数如下:
-v,–verbose 打印详细模式;
-i PATH,–inventory=PATH 指定host文件路径;
-f NUM,–forks=NUM 指定fork开启同步进程的个数,默认5;
-m NAME,–module-name=NAME 指定module名称,默认模块command;
-a MODULE_ARGS module模块的参数或者命令;
-k,–ask-pass 输入远程被管理端密码;
–sudo 基于sudo用户执行;
-K,–ask-sudo-pass 提示输入sudo密码与sudo一起使用;
-u USERNAME,–user=USERNAME 指定移动端的执行用户;
-C,–check 测试执行过程,不改变真实内容,相当于预演;
-T TIMEOUT, 执行命令超时时间,默认为10秒;
--version 查看Ansible软件版本信息。
21.5 Ansible ping模块实战
Ansible最基础的模块为ping模块,主要用于判断远程客户端是否在线,用于ping本身服务器,返回值为changed、ping。
Ansible ping模块企业常用案例如下:
(1)Ansible ping服务器状态,如图21-6所示:
ansible -k all -m ping

图21-6 Ansible ping服务器状态
21.6 Ansible command模块实战
Ansible command模块为ansible默认模块,主要用于执行Linux基础命令,可以执行远程服务器命令执行、任务执行等操作。Command模块使用详解:
Chdir 执行命令前,切换到目录;
Creates 当该文件存在时,则不执行该步骤;
Executable 换用shell环境执行命令;
Free_form 需要执行的脚本;
Removes 当该文件不存在时,则不执行该步骤;
Warn 如果在ansible.cfg中存在告警,如果设定了False,不会警告此行。
Ansible command模块企业常用案例如下:
(1)Ansible command模块远程执行date命令,执行结果如图21-7所示:
ansible -k -i /etc/ansible/hosts all -m command -a "date"

图21-7 Ansible command date命令执行结果
(2)Ansible command模块远程执行ping命令,执行结果如图21-8所示:
ansible -k all -m command -a "ping -c 1 www.baidu.com"

图21-8 Ansible command ping命令执行结果
(3)Ansible Hosts正则模式远程执行df -h,执行结果如图21-9所示:
ansible -k 192.168.149.13* -m command -a "df -h"
图21-9 Ansible command df -h命令执行结果
21.7 Ansible copy模块实战
Ansible copy模块主要用于文件或者目录拷贝,支持文件、目录、权限、用户组功能,copy模块使用详解:
src Ansible端源文件或者目录,空文件夹不拷贝;
content 用来替代src,用于将指定文件的内容,拷贝到远程文件内;
dest 客户端目标目录或者文件,需要绝对路径;
backup 拷贝之前,先备份远程节点上的原始文件;
directory_mode 用于拷贝文件夹,新建的文件会被拷贝,而老旧的不会被拷贝;
follow 支持link文件拷贝;
force 覆盖远程主机不一致的内容;
group 设定远程主机文件夹的组名;
mode 指定远程主机文件及文件及的权限;
owner 设定远程主机文件夹的用户名。
Ansible copy模块企业常用案例如下:
(1)Ansible copy模块操作,src表示源文件,dest表示目标目录或者文件,owner指定拥有者,执行结果如图21-10所示:
ansible -k all -m copy -a 'src=/etc/passwd dest=/tmp/ mode=755 owner=root'

图21-10 Ansible copy拷贝文件
(2)Ansible copy模块操作,content文件内容,dest目标文件,owner指定拥有者,执行结果如图21-11所示:
ansible -k all -m copy -a 'content="Hello World" dest=/tmp/jfedu.txt mode=755 owner=root'
图21-11 Ansible copy追加内容
(3)Ansible copy模块操作,content文件内容,dest目标文件,owner指定拥有者,backup=yes开启备份,执行结果如图21-12所示:
ansible -k all -m copy -a 'content="Hello World" dest=/tmp/jfedu.txt backup=yes mode=755 owner=root'

图21-12 Ansible copy客户端备份结果
21.8 Ansible yum模块实战
Ansible yum模块主要用于软件的安装、升级、卸载,支持红帽.rpm软件的管理,YUM模块使用详解:
conf_file 设定远程yum执行时所依赖的yum配置文件
disable_gpg_check 安装软件包之前是否坚持gpg key;
name 需要安装的软件名称,支持软件组安装;
update_cache 安装软件前更新缓存;
enablerepo 指定repo源名称;
skip_broken 跳过异常软件节点;
state 软件包状态,包括:installed、present、latest、absent、removed。
Ansible yum模块企业常用案例如下:
(1)Ansible yum模块操作,name表示需安装的软件名称,state表示状态,常见state= installed表示安装软件,执行结果如图21-13所示:
ansible all -k -m yum -a "name=sysstat,screen state=installed"

图21-13 Ansible YUM安装软件包
(2)Ansible yum模块操作,name表示需安装的软件名称,state表示状态,常见state= installed表示安装软件,执行结果如图21-14所示:
ansible all -k -m yum -a "name=sysstat,screen state=absent"

图21-14 Ansible YUM卸载软件包
(3)Ansible yum模块操作,name表示需安装的软件名称,state表示状态,常见state= installed,表示安装软件,disable_gpg_check=no不检查key,执行结果如图21-15所示:
ansible 192.168.149.129 -k -m yum -a "name=sysstat,screen state=installed disable_gpg_check=no"
图21-15 Ansible YUM安装软件包,不检查KEY
21.9 Ansible file模块实战
Ansible file模块主要用于对文件的创建、删除、修改、权限、属性的维护和管理,File模块使用详解:
src Ansible端源文件或者目录;
follow 支持link文件拷贝;
force 覆盖远程主机不一致的内容;
group 设定远程主机文件夹的组名;
mode 指定远程主机文件及文件及的权限;
owner 设定远程主机文件夹的用户名;
path 目标路径,也可以用dest,name代替;
state 状态包括:file、link、directory、hard、touch、absent;
attributes 文件或者目录特殊属性。
Ansible file模块企业常用案例如下:
(1)Ansible file模块操作,path表示目录的名称和路径, state=directory表示创建目录,执行结果如图21-16所示:
ansible -k 192.168. -m file -a "path=/tmp/date +%F state=directory mode=755"
图21-16 Ansible file创建目录
(2)Ansible file模块操作,path表示目录的名称和路径, state=touch表示创建文件,执行结果如图21-17所示:
ansible -k 192.168.
-m file -a "path=/tmp/jfedu.txt state=touch mode=755"
图21-17 Ansible file创建文件
21.10 Ansible user模块实战
Ansible user模块主要用于操作系统用户、组、权限、密码等操作,user模块使用详解:
system 默认创建为普通用户,为yes则创建系统用户;
append 添加一个新的组;
comment 新增描述信息;
createhome 给用户创建家目录;
force 用于删除强制删除用户;
group 创建用户主组;
groups 将用户加入组或者附属组添加;
home 指定用户的家目录;
name 表示状态,是否create、remove、modify;
password 指定用户的密码,此处为加密密码;
remove 删除用户;
shell 设置用户的shell登录环境;
uid 设置用户id;
update_password 修改用户密码;
state 用户状态,默认为present表示新建用户。
Ansible user模块企业常用案例如下:
(1)Ansible user模块操作,name表示用户名称,home表示其家目录,执行结果如图21-18所示:
ansible -k 192.168.149. -m user -a "name=jfedu home=/tmp/"
图21-18 Ansible user创建新用户
(2)Ansible user模块操作,name表示用户名称,home表示其家目录,执行结果如图21-19所示:
ansible -k 192.168.149.
-m user -a "name=jfedu home=/tmp/ shell=/sbin/nologin"
图21-19 Ansible user指定Shell环境
(3)Ansible user模块操作,name表示用户名称,state=absent表示删除用户,执行结果如图21-20所示:
ansible -k 192.168.149. -m user -a "name=jfedu state=absent force=yes"
图21-20 Ansible user删除用户
21.11 Ansible cron模块实战
Ansible cron模块主要用于添加、删除、更新操作系统Crontab任务计划,Cron模块使用详解:
name 任务计划名称;
cron_file 替换客户端该用户的任务计划的文件;
minute 分( 0-59 ,
/2 );
hour 时( 0-23 ,
/2 );
day 日( 1-31 ,
/2 );
month 月( 1-12 ,
/2 );
weekday 周( 0-6 或 1-7 ,
);
job 任何计划执行的命令,state要等于present;
backup 是否备份之前的任务计划;
user 新建任务计划的用户;
state 指定任务计划present、absent。
Ansible cron模块企业常用案例如下:
(1)Ansible cron模块操作,基于cron模块,创建crontab任务计划,执行结果如图21-21所示:
ansible -k all -m cron -a "minute=0 hour=0 day= month= weekday=* name='Ntpdate server for sync time' job='/usr/sbin/ntpdate 139.224.227.121'"

图21-21 Ansible cron添加任务计划
(2)Ansible cron模块操作,基于cron模块,备份crontab任务计划,backup=yes表示开启备份,备份文件存放于客户端/tmp/,执行结果如图21-22所示:
ansible -k all -m cron -a "minute=0 hour=0 day= month= weekday=* name='Ntpdate server for sync time' backup=yes job='/usr/sbin/ntpdate pool.ntp.org'"
图21-22 Ansible cron删除任务计划
(3)Ansible cron模块操作,基于cron模块,删除crontab任务计划,执行结果如图21-23所示:
ansible -k all -m cron -a "name='Ntpdate server for sync time' state=absent"
图21-23 Ansible cron删除任务计划
21.12 Ansible synchronize模块实战
Ansible synchronize模块主要用于目录、文件同步,基于Rsync命令同步目录,Synchronize模块使用详解:
compress 开启压缩,默认为开启;
archive 是否采用归档模式同步,保证源和目标文件属性一致;
checksum 是否效验;
dirs 以非递归的方式传输目录;
links 同步链接文件;
recursive 是否递归yes/no;
rsync_opts 使用rsync 的参数;
copy_links 同步的时候是否复制连接;
delete 删除源中没有而目标存在的文件;
src 源目录及文件;
dest 目标目录及文件;
dest_port 目标接受的端口;
rsync_path 服务的路径,指定 rsync 命令来在远程服务器上运行;
rsync_timeout 指定rsync操作的IP超时时间;
set_remote_user 设置远程用户名;
--exclude=.log 忽略同步.log结尾的文件;
mode 同步的模式,rsync同步的方式PUSH、PULL,默认都是推送push。
Ansible synchronize模块企业常用案例如下:
(1)Ansible synchronize模块操作,src源目录、dest目标目录,执行结果如图21-24所示:
ansible -k all -m synchronize -a 'src=/tmp/ dest=/tmp/'
图21-24 Ansible 目录同步
(2)Ansible synchronize模块操作,src源目录、dest目标目录、compress=yes开启压缩、delete=yes数据一致、rsync_opts同步参数、--exclude排除文件,执行结果如图21-25所示:
ansible -k all -m synchronize -a 'src=/tmp/ dest=/tmp/ compress=yes delete=yes rsync_opts=--no-motd,--exclude=.txt'
图21-25 Ansible 目录同步排除.txt文件
21.13 Ansible shell模块实战
Ansible shell模块主要用于远程客户端上执行各种Shell命令或者运行脚本,远程执行命令通过/bin/sh环境来执行,支持比command更多的指令,Shell模块使用详解:
Chdir 执行命令前,切换到目录;
Creates 当该文件存在时,则不执行该步骤;
Executable 换用shell环境执行命令;
Free_form 需要执行的脚本;
Removes 当该文件不存在时,则不执行该步骤;
Warn 如果在ansible.cfg中存在告警,如果设定了False,不会警告此行。
Ansible shell模块企业常用案例如下:
(1)Ansible shell模块操作,-m shell指定模块为shell,远程执行Shell脚本,远程执行脚本也可采用script模块。并把执行结果追加至客户端服务器/tmp/var.log文件,执行结果如图21-26所示:
ansible -k all -m shell -a "/bin/sh /tmp/variables.sh >>/tmp/var.log"
图21-26 Ansible shell远程执行脚本
(2)Ansible shell模块操作,远程执行创建目录命令,执行之前切换在/tmp目录,屏蔽警告信息,执行结果如图21-27所示:
ansible -k all -m shell -a "mkdir -p date +%F chdir=/tmp/ state=directory warn=no"
图21-27 Ansible shell远程执行脚本
(3)Ansible shell模块操作,-m shell指定模块为shell,远程客户端查看http进程是否启动,执行结果如图21-28所示:
ansible -k all -m shell -a "ps -ef |grep http"
图21-28 Ansible shell远程查看进程
(4)Ansible shell模块操作,-m shell指定模块为shell,远程客户端查看crontab任务计划,执行结果如图21-29所示:
ansible -k all -m shell -a "crontab -l"
图21-29 Ansible shell远程查看任务计划
21.14 Ansible service模块实战
Ansible service模块主要用于远程客户端各种服务管理,包括启动、停止、重启、重新加载等,service模块使用详解:
enabled 是否开启启动服务;
name 服务名称;
runlevel 服务启动级别;
arguments 服务命令行参数传递;
state 服务操作状态,状态包括started, stopped, restarted, reloaded。
Ansible service模块企业常用案例如下:
(1)Ansible service模块操作,远程重启httpd服务,执行结果如图21-30所示:
ansible -k all -m service -a "name=httpd state=restarted"
图21-30 Ansible service重启httpd服务
(2)Ansible service模块操作,远程重启网卡服务,指定参数eth0,执行结果如图21-31所示:
ansible -k all -m service -a "name=network args=eth0 state=restarted"
图21-31 Ansible service重启network服务
(3)Ansible service模块操作,远程开机启动nfs服务,设置3,5级别自动启动,执行结果如图21-32所示:
ansible -k all -m service -a "name=nfs enabled=yes runlevel=3,5"
图21-32 Ansible service开机启动nfs服务
21.15 Ansible Playbook应用
如上使用Ad-hoc方式点对点命令执行,可以管理远程主机,如果服务器数量很多,配置信息比较多,还可以利用Ansible Playbook编写剧本、从而以非常简便的方式实现任务处理的自动化与流程化。
Playbook由一个或多个"play"组成的列表,play的主要功能Ansible中的Task定义好的角色,指定剧本对应的服务器组。
从根本上说,Task是一个任务,Task调用Ansible各种模块module,将多个paly组织在一个playbook剧本中,然后组成一个非常完整的流程控制集合。
基于Ansible Playbook还可以收集命令、可以创建任务集,这样能够大大降低管理工作的复杂程度,Playbook采用YAML语法结构,易于阅读、方便配置。
YAML(Yet Another Markup Language),是一种直观的能够被电脑识别的数据序列化格式,是一个可读性高并且容易被人类阅读,容易和脚本语言交互,用来表达资料序列的编程语言。它参考了其它多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822,是类似于标准通用标记语言的子集XML的数据描述语言,语法比XML简单很多。
YAML使用空白字符和分行来分隔资料,适合用 grep、Python、Perl、Ruby 操作。
(1)YAML语言特性如下:
可读性强;
和脚本语言的交互性好;
使用实现语言的数据类型;
一致的信息模型;
易于实现;
可以基于流来处理;
可扩展性强。
(2)Playbooks组件包括如下:
Target 定义playbook的远程主机组;
Variable 定义playbook使用的变量;
Task 定义远程主机上执行的任务列表;
Handler 定义task执行完成以后需要调用的任务,例如配置文件被改动,则启动handler任务重启相关联的服务。
(3)Target常用参数如下:
hosts 定义远程主机组;
user 执行该任务的用户;
sudo 设置为yes的时候,执行任务的时候使用root权限;
sudo_user 指定sudo普通用户;
connection 默认基于SSH连接客户端;
gather_facks 获取远程主机facts基础信息。
(4)Variable常用参数如下:
vars 定义格式,变量名:变量值;
vars_files 指定变量文件;
vars_prompt 用户交互模式自定义变量;
setup 模块去远程主机的值;
(5)Task常用参数如下:
name 任务显示名称也即屏幕显示信息;
action 定义执行的动作;
copy 复制本地文件到远程主机;
template 复制本地文件到远程主机,可以引用本地变量;
service 定义服务的状态。
Ansible playbook案例演示如下:
(1)远程主机安装Nginx WEB服务,playbook代码如下,执行结果如图21-33所示:

  • hosts: all
    remote_user: root
    tasks:
    • name: Jfedu Pcre-devel and Zlib LIB Install.
      yum: name=pcre-devel,pcre,zlib-devel state=installed
    • name: Jfedu Nginx WEB Server Install Process.
      shell: cd /tmp;rm -rf nginx-1.12.0.tar.gz;wget http://nginx.org/download/nginx-1.12.0.tar.gz;tar xzf nginx-1.12.0.tar.gz;cd nginx-1.12.0;./configure --prefix=/usr/local/nginx;make;make install
      图21-33 Ansible Playbook远程Nginx安装
      (2)检测远程主机Nginx目录是否存在,不存在则安装Nginx WEB服务,安装完并启动Nginx,playbook代码如下,执行结果如图21-34所示:
  • hosts: all
    remote_user: root
    tasks:
    • name: Nginx server Install 2017
      file: path=/usr/local/nginx/ state=directory
      notify:
      • nginx install
      • nginx start
        handlers:
    • name: nginx install
      shell: cd /tmp;rm -rf nginx-1.12.0.tar.gz;wget http://nginx.org/download/nginx-1.12.0.tar.gz;tar xzf nginx-1.12.0
      .tar.gz;cd nginx-1.12.0;./configure --prefix=/usr/local/nginx;make;make install
    • name: nginx start
      shell: /usr/local/nginx/sbin/nginx
      图21-34 Ansible Playbook Nginx触发安装
      (3)检测远程主机内核参数配置文件是否更新,如果更新则执行命令sysctl –p使内核参数生效,playbook代码如下,执行结果如图21-35所示:
  • hosts: all
    remote_user: root
    tasks:
    • name: Linux kernel config 2017
      copy: src=/data/sh/sysctl.conf dest=/etc/
      notify:
      • source sysctl
        handlers:
    • name: source sysctl
      shell: sysctl -p
      图21-35 Ansible Playbook 内核参数优化
      (4)基于列表items多个值创建用户,通过{{}}定义列表变量,with_items选项传入变量的值,执行结果如图21-36(a)、21-36(b)所示:
  • hosts: all
    remote_user: root
    tasks:
    • name: Linux system Add User list.
      user: name={{ item }} state=present
      with_items:
      • jfedu1
      • jfedu2
      • jfedu3
      • jfedu4

图21-36(a) Ansible Playbook item变量创建用户

图21-36(b) Ansible Playbook item变量创建用户
(5)Ansible Playbook可以自定义template模板文件,模板文件主要用于服务器需求不一致的情况,需要独立定义的,例如两台服务器安装了Nginx,安装完毕之后将服务器A的HTTP端口改成80,服务器B的HTTP端口改成81,基于tempalte模块轻松实现,方法步骤如下:
1.Ansible hosts文件指定不同服务器不同httpd_port端口,代码如下:
[web]
192.168.149.128 httpd_port=80
192.168.149.129 httpd_port=81
2.Ansible 创建nginx.conf jinja2模板文件,cp nginx.conf nginx.conf.j2,并修改listen 80为listen {{httpd_port}},Nginx其他配置项不变,代码如下:
cp nginx.conf nginx.conf.j2
listen {{httpd_port}};
3.Ansible playbook剧本yaml文件创建,代码如下:

  • hosts: all
    remote_user: root
    tasks:
    • name: Nginx server Install 2017
      file: path=/usr/local/nginx/ state=directory
      notify:
      • nginx install
      • nginx config
        handlers:
    • name: nginx install
      shell: cd /tmp;rm -rf nginx-1.12.0.tar.gz;wget http://nginx.org/download/nginx-1.12.0.tar.gz;tar xzf nginx-1.12.0
      .tar.gz;cd nginx-1.12.0;./configure --prefix=/usr/local/nginx;make;make install
    • name: nginx config
      template: src=/data/sh/nginx.conf.j2 dest=/usr/local/nginx/conf/nginx.conf
      4.Ansible playbook执行剧本文件,如图21-37(a)、21-37(b)、21-37(c)所示:

图21-37(a) Ansible Playbook 执行模板yaml

图21-37(b) 149.128服务器Nginx HTTP Port 80

图21-37(c) 149.129服务器Nginx HTTP Port 81
21.16 Ansible配置文件详解
Ansible默认配置文件为/etc/ansible/ansible.cfg,配置文件中可以对ansible进行各项参数的调整,包括并发线程、用户、模块路径、配置优化等,如下为Ansible.cfg常用参数详解:
[defaults] 通用默认配置段;
inventory = /etc/ansible/hosts 被控端IP或者DNS列表;
library = /usr/share/my_modules/ Ansible默认搜寻模块的位置;
remote_tmp = $HOME/.ansible/tmp Ansible远程执行临时文件;
pattern = * 对所有主机通信;
forks = 5 并行进程数;
poll_interval = 15 回频率或轮训间隔时间;
sudo_user = root sudo远程执行用户名;
ask_sudo_pass = True 使用sudo,是否需要输入密码;
ask_pass = True 是否需要输入密码;
transport = smart 通信机制;
remote_port = 22 远程SSH端口;
module_lang = C 模块和系统之间通信的语言;
gathering = implicit 控制默认facts收集(远程系统变量);
roles_path= /etc/ansible/roles 用于playbook搜索Ansible roles;
host_key_checking = False 检查远程主机密钥;

sudo_exe = sudo sudo远程执行命令;

sudo_flags = -H 传递sudo之外的参数;

timeout = 10 SSH超时时间;
remote_user = root 远程登陆用户名;
log_path = /var/log/ansible.log 日志文件存放路径;
module_name = command Ansible命令执行默认的模块;

executable = /bin/sh 执行的Shell环境,用户Shell模块;

hash_behaviour = replace 特定的优先级覆盖变量;

jinja2_extensions 允许开启Jinja2拓展模块;

private_key_file = /path/to/file 私钥文件存储位置;

display_skipped_hosts = True 显示任何跳过任务的状态;

system_warnings = True 禁用系统运行ansible潜在问题警告;

deprecation_warnings = True Playbook输出禁用“不建议使用”警告;

command_warnings = False command模块Ansible默认发出警告;

nocolor = 1 输出带上颜色区别,开启/关闭:0/1;

pipelining = False 开启pipe SSH通道优化;
[accelerate] accelerate缓存加速。
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
accelerate_daemon_timeout = 30
accelerate_multi_key = yes
21.17 Ansible性能调优
Ansible企业实战环境中,如果管理的服务器越来越多,Ansibe执行效率会变得比较慢,可以通过优化Ansible提供工作效率,由于Ansible基于SSH协议通信,SSH连接慢会导致整个基于Ansible执行变得缓慢,也需要对Openssh进行优化,具体优化的方法如下:
(1)Ansible SSH 关闭秘钥检测
默认以SSH登录远程客户端服务器,会检查远程主机的公钥(public key),并将该主机的公钥记录在~/.ssh/known_hosts文件中。下次访问相同主机时,OpenSSH会核对公钥,如果公钥不同,OpenSSH会发出警告,如果公钥相同,则提示输入密码。
SSH对主机的public_key的检查等级是根据StrictHostKeyChecking变量来设定的,StrictHostKeyChecking检查级别包括:no(不检查)、ask(询问)、yes(每次都检查)、False(关闭检查)。
Ansible配置文件中加入如下代码,即可关闭StrictHostKeyChecking检查:
host_key_checking = False
(2)OpenSSH连接优化
使用OpenSSH服务时,默认服务器端配置文件UseDNS=YES状态,该选项会导致服务器根据客户端的IP地址进行DNS PTR反向解析,得到客户端的主机名,然后根据获取到的主机名进行DNS正向A记录查询,并验证该IP是否与原始IP一致。关闭DNS解析代码如下:
sed -i '/^GSSAPI/s/yes/no/g;/UseDNS/d;/Protocol/aUseDNS no' /etc/ssh/sshd_config
/etc/init.d/sshd restart
(3)SSH pipelining加速Ansible
SSH pipelining是一个加速 Ansible 执行速度的简单方法,SSH pipelining 默认是关闭的,关闭是为了兼容不同的 sudo 配置,主要是requiretty 选项。
如果不使用Sudo建议开启该选项,打开此选项可以减少Ansible 执行没有文件传输时,SSH在被控机器上执行任务的连接数。使用Sudo操作的时候, 必须在所有被管理的主机上将配置文件/etc/sudoers中requiretty选项禁用。
sed -i '/^pipelining/s/False/True/g' /etc/ansible/ansible.cfg
(4)Ansible Facts缓存优化
Ansible-playbook 在执行过程中,默认会执行Gather facts,如果不需要获取客户端的fact数据的话,可以关闭获取fact数据功能,关闭之后可以加快ansible-playbook的执行效率。如需关闭fact功能,在playbook yaml文件中加入如下代码即可:
gather_facts: nogather_facts: no
Ansible facts组件主要用于收集客户端设备的基础静态信息,这些信息可以在做配置管理的时候方便引用。Facts信息直接当做Ansible Playbook变量信息进行引用,通过定制facts以便收集我们想要的信息,同时可以通过Facter和Ohai来拓展facts信息,也可以将facts信息存入Redis缓存中,如下为Facts使用Redis缓存的步骤。
1.部署Redis服务
wget http://download.redis.io/releases/redis-2.8.13.tar.gz
tar zxf redis-2.8.13.tar.gz
cd redis-2.8.13
make PREFIX=/usr/local/redis install
cp redis.conf /usr/local/redis/
将/usr/local/redis/bin/目录加入至环境变量配置文件/etc/profile末尾,然后Shell终端执行source /etc/profile让环境变量生效。
export PATH=/usr/local/redis/bin:$PATH
启动及停止Redis服务命令:
nohup /usr/local/redis/bin/redis-server /usr/local/redis/redis.conf &
2.安装Python Redis模块
easy_install pip
pip install redis
3.Ansible整合Redis配置
在配置文件/etc/ansible/ansible.cfg中defaluts段中加入代码,如果redis密码为admin,则开启admin密码行:
gathering = smart
fact_caching = redis
fact_caching_timeout = 86400
fact_caching_connection = localhost:6379

fact_caching_connection = localhost:6379:0:admin

4.测试Redis缓存
Ansible-playbook执行nginx_wget.yaml剧本文件,如图21-38所示:
ansible-playbook nginx_wget.yaml

图21-38 ansible playbook执行yaml
检查Redis服务器,facts key已存入Redis中,如图21-39所示:

图21-39 Redis缓存服务器缓存facts主机信息
(5)ControlPersist SSH优化
ControlPersist 特性需要高版本的SSH支持,CentOS6默认是不支持的,如果需要使用,需要自行升级Openssh。
ControlPersist 即持久化的Socket,一次验证多次通信。并且只需要修改SSH客户端配置,也即Ansible被管理主机。
可使用YUM或者源码编译升级OpenSSH服务,升级完毕ControlPersist的设置办法如下,在其用户的家目录创建config文件,如果ansible以root用户登录客户端,至需要在客户端的/root/.ssh/config目录中添加如下代码即可:
Host *
Compression yes
ServerAliveInterval 60
ServerAliveCountMax 5
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 4h
开启ControlPersist 特性后,SSH 在建立sockets后,节省了每次验证和创建的时间,对Ansible执行速度提升是非常明显的。
第22章 Jenkins持续集成企业实战
构建企业自动化部署平台,可以大大的提升企业网站部署效率,企业生产环境每天需要更新各种系统,传统更网站的方法是使用Shell+Rsync实现网站代码备份、更新,更新完之后,运维人员手动发送邮件给测试人员、开发人员以及相关的业务人员,传统更新网站耗费大量的人力,同时偶尔由于误操作会出现细小问题。构建自动化部署平台变得迫在眉睫。
本章向读者介绍传统网站部署方法、企业主流部署方法、Jenkins持续集成简介、持续集成平台构建、Jenkins插件部署、Jenkins自动化部署网站、Jenkins多实例及Ansible+Jenkins批量自动部署等。
22.1 传统网站部署的流程
服务器网站部署是运维工程师的主要工作之一,传统运维网站部署主要靠手动部署,手工部署网站的流程大致分为:需求分析原型设计开发代码提交测试内网部署确认上线备份数据外网更新发布完毕网站测试等,如果发现外网部署的代码有异常,需要及时回滚。如图22-1所示:
图22-1 网站传统部署方法及流程
服务器部署基于YUM安装LAMP架构,并且部署Discuz,最终效果如图22-2所示:
图22-2 YUM部署LAMP+Discuz网站
通过SecureCRT登陆网站服务器,并将logo.png文件上传至网站目录,手动备份网站,并且更新网站的logo,更新完毕如图22-3所示:

图22-3 手工更新LAMP网站logo文件
22.2 目前主流网站部署的流程
传统部署网站的方法对于单台或者几台服务器更新很容易,如果服务器规模超过百台或者千台,或者更新网站代码很频繁,手工更新就非常消耗时间成本。
基于主流的Hudson/Jenkins工具平台实现全自动网站部署、网站测试、网站回滚会大大的减轻网站部署的成本,Jenkins的前身为Hudson,Hduson主要用于商业版,Jenkins为开源免费版。
Jenkins是一个可扩展的持续集成引擎、框架,是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。而且Jenkins平台的安装和配置非常的容易,使用也非常简单。构建Jenkins平台可以解放如下人员的双手,如图:
开发人员,对于开发人员来说,只需负责网站代码的编写,不需要手动再对源码进行编译、打包、单元测试等工作,开发人员直接将写好的代码分支存放在SVN、GIT仓库即可。
运维人员,对于运维人员来说,使用Jenkins自动部署,可以减轻人工干预的错误率,同时解放运维人员繁杂的上传代码、手动备份、手动更新。
测试人员,对于测试人员来说,可以通过Jenkins进行代码测试、网站功能或者性能测试。
基于Jenkins自动部署网站的流程大致分为:需求分析原型设计开发代码提交测试Jenkins内网部署确认上线Jenkins备份数据Jenkins外网部署发布完毕Jenkins网站测试等,如果发现外网部署的代码有异常,可以通过Jenkins及时回滚,如图22-4所示:
图22-4 Jenkins部署网站的方法及流程
22.3 Jenkins持续集成简介
持续集成(Continuous Integration,CI|CD)是一种软件开发实践,对于提高软件开发效率并保障软件开发质量提供了理论基础,持续集成意义如下:
持续集成中的任何一个环节都是自动完成的,无需太多的人工干预,有利于减少重复过程以节省时间、费用和工作量;
持续集成保障了每个时间点上团队成员提交的代码是能成功集成的。换言之,任何时间点都能第一时间发现软件的集成问题,使任意时间发布可部署的软件成为了可能;
持续集成还能利于软件本身的发展趋势,这点在需求不明确或是频繁性变更的情景中尤其重要,持续集成的质量能帮助团队进行有效决策,同时建立团队对开发产品的信心。
22.4 Jenkins持续集成组件
自动构建过程JOB,JOB的功能主要是:获取SVN/GIT源码、自动编译、自动打包、部署分发和自动测试等;
源代码存储库,开发编写代码需上传至SVN、GIT代码库中,供Jenkins来获取;
Jenkins持续集成服务器,用于部署Jenkins UI、存放JOB工程、各种插件、编译打包的数据等。
22.5 Jenkins平台安装部署
Jenkins官网免费获取Jenkins软件,官网地址为:http://mirrors.jenkins-ci.org/下载稳定的Jenkins版本。由于Jenkins是基于Java开发的一种持续集成工具,所以Jenkins服务器需安装JAVA JDK开发软件。Jenkins平台搭建步骤如下:
(1)Jenkins稳定版下载:
http://updates.jenkins-ci.org/download/war/1.651.2/jenkins.war
(2)官网下载JAVA JDK,并解压安装,代码如下:
tar -xzf jdk-7u25-linux-x64.tar.gz ;mkdir -p /usr/java/ ;mv jdk1.7.0_25/ /usr/java/
(3)配置JAVA环境变量,/etc/profile配置文件中末尾加入如下代码:
export JAVA_HOME=/usr/java/jdk1.7.0_25
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH:$HOMR/bin
执行如下代码使其环境变量,并查看环境变量,命令如下:
source /etc/profile
java --version
(4)Tomcat JAVA容器配置
wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-6/v6.0.53/bin/apache-tomcat-6.0.53.tar.gz
tar xzf apache-tomcat-6.0.53.tar.gz
mv apache-tomcat-6.0.53 /usr/local/tomcat
(5)Tomcat发布Jenkins,将Jenkins war拷贝至Tomcat默认发布目录,并使用jar工具解压,启动Tomcat服务即可,代码如下:
rm -rf /usr/local/tomcat/webapps/*
mkdir -p /usr/local/tomcat/webapps/ROOT/
mv jenkins.war /usr/local/tomcat/webapps/ROOT/
cd /usr/local/tomcat/webapps/ROOT/
jar –xvf jenkins.war;rm -rf Jenkins.war
sh /usr/local/tomcat/bin/startup.sh
(6)通过客户端浏览器访问Jenkins服务器IP地址,如图22-5所示:

图22-5 Jenkins自动部署平台
22.6 Jenkins相关概念
要熟练掌握Jenkins持续集成的配置、使用和管理,需要了解相关的概念,例如代码开发、编译、打包、构建等名称概念,常见的代码相关概念包括:MAKE、ANT、MAVEN、Eclipse、Jenkins等。
(1)Make编译工具
Make编译工具是Linux和Windows最原始的编译工具,在Linux下编译程序常用make,Windows下对应的工具为nmake。读取本地makefile文件,该文件决定了源文件之间的依赖关系,Make负责根据makefile文件去组织构建软件,负责指挥编译器如何编译,连接器如何连接,以及最后生成可用二进制的代码。
(2)Ant编译工具
Make工具在编译比较复杂的工程使用起来不方便,语法很难理解,延伸出Ant工具。Ant工具属于Apache基金会软件成员之一,是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发。
Ant构建文件是XML文件。每个构建文件定义一个唯一的项目(Project元素)。每个项目下可以定义很多目标元素,这些目标之间可以有依赖关系。
构建一个新的项目时,首先应该编写Ant构建文件。因为构建文件定义了构建过程,并为团队开发中每个人所使用。
Ant构建文件默认名为build.xml,也可以取其他的名字。只不过在运行的时候需把这个命名当作参数传给Ant。构建文件可以放在任何的位置,一般做法是放在项目顶层目录也即根目录,这样可以保持项目的简洁和清晰。
(3)Maven编译工具
Maven工具是对ant工具的进一步改进,在make工具中,如果我们要编译某些源文件,首先要安装编译器等工具。有时候需要不同版本的编译器,在java的编译器需要不同的各种包的支持,如果把每个包都下载下来,在makefile中进行配置制定,当需要的包非常多时,很难管理。
Maven与Ant类似,也是个构建(build)工具,它是如何调用各种不同的编译器连接器呢?使用Maven plugin (maven 插件),Maven项目对象模型POM (Project Object Model),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具。Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。
POM是Maven项目中的文件,使用XML表示,名称为pom.xml。在Maven中,当构建Project的时候,不仅仅是一堆包含代码的文件。还包含pom.xml配置文件,该文件包括Project与开发者有关的、缺陷跟踪系统、组织与许可、项目的URL、项目依赖、以及其他配置。
在基于Maven构建编译时,project可以什么都没有,甚至没有代码,但是必须包含pom.xml文件。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。
由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。
(4)Jenkins框架工具
Maven可以实现对软件代码进行编译、打包、测试,功能已经很强大了,那还需要Jenkins做什么呢?Maven可以控制编译,控制连接,可以生成各种报告,可以进行代码测试。
但是默认不能控制完整的流程? 没有顺序定义,是先编译还是先连接?先进行代码测试,还是先生成报告?可以使用脚本来对Maven进行控制,实现这些流程的控制。
(5)Eclipse工具
Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK),主要用于开发者开发网站代码。
22.7 Jenkins平台设置
Jenkins持续基础平台部署完毕,需要进行简单配置,例如配置JAVA路径、安装Maven、指定SVN、GIT仓库地址等,如下为JAVA路径和Maven设置步骤:
(1)Jenkins服务器安装Maven:
wget
http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz
tar -xzf apache-maven-3.3.9-bin.tar.gz
mv apache-maven-3.3.9 /usr/maven/
(2)Jenkins系统设置环境变量,如图22-6(a)、22-6(b)所示:

图22-6(a) Jenkins系统设置

图22-6(b) Jenkins系统设置
(3)Jenkins系统设置完毕,需创建job工程:
Jenkins平台首页创建一个新任务填入Item名称“构建一个maven项目”单击OK,如图22-7所示:
图22-7 Jenkins创建Jenkins JOB工程
(4)创建完JOB任务,需对其任务进行配置,如图22-8所示:

图22-8 Jenkins配置JOB工程
(5)单击www.jfedu.net工程名配置进入JOB工程详细配置源码管理选择Subversion配置SVN仓库地址,如果报错需要输入SVN用户名和密码,如图22-9所示:

图22-9 Jenkins配置SVN仓库地址
源码管理,SVN代码迁出参数详解如下:
Respository url 配置SVN仓库地址;
Local module directory 存储SVN源码的路径;
Ignore externals option 忽略额外参数;
Check-out Strategy 代码检出策略;
Repository browser 仓库浏览器,默认Auto;
add more locations 源码管理,允许下载多个地址的代码;
Repository depth 获取SVN源码的目录深度,默认为infinity;
empty: 不检出项目的任何文件,files: 所有文件,immediates:目录第一级,infinity:整个目录所有文件。
(6)配置Maven编译参数,BuildGoals and options输入“clean install -Dmaven.test.skip=true”,此处为maven自动编译、打包并跳过单元测试选项,如图22-10所示。

图22-10 Jenkins配置MAVEN编译参数
Maven工具常用命令如下:
mvn clean 打包清理(删除target目录内容);
mvn compile 编译项目;
mvn package 打包发布;
mvn package -Dmaven.test.skip=ture 打包时跳过测试。
通过以上步骤的配置步骤,即完成了JOB工程的创建。
22.8 Jenkins构建JOB工程
Jenkins JOB工程创建完毕,如下直接运行构建,Jenkins将从SVN仓库获取SVN代码,然后通过Maven编译、打包,并最终生成可以使用的war包即可。操作步骤如下:
(1)单击www.jfedu.net工程名,进入JOB工程详细配置界面,单击“立即构建”,如图22-11所示:

图22-11 Jenkins JOB工程配置界面
(2)查看Build History,单击最新一次百分比滚动条任务,如图22-12所示:

图22-12 Jenkins JOB工程Build界面
(3)进入JOB工程编译详细页面,单击“Console Output”,如图22-13所示:

图22-13 Jenkins JOB工程Console Output界面
(4)查看Jenkins构建实时日志,如图22-14(a)、22-14(b)所示:

图22-14(a) Jenkins JOB工程编译控制台

图22-14(b) Jenkins JOB工程编译控制台
控制台日志打印“Finished: SUCCESS”,则表示Jenkins持续集成构建完成,会在Jenkins服务器目录www.jfedu.net工程名目录下生产网站可用的war文件,将该war包部署至其他服务器即可,war路径为:/root/.jenkins/workspace/www.jfedu.net/target/edu.war。
至此,Jenkins持续集成平台自动构建软件完成,该步骤只是生成了war包,并没有实现自动将该war包部署至其他服务器,如果要自动部署需要基于Jenkins插件或者基于Shell、Python等自动化部署脚本。
22.9 Jenkins自动化部署
如上通过手动构建Jenkins JOB工程,自动编译、打包生成war包,并不能实现自动部署,如需要实现自动部署可以基于自动部署插件或者Shell脚本、Python脚本等。
如下以Shell脚本实现Jenkins自动部署war至其他多台服务器,并自动启动Tomcat,实现最终WEB浏览器访问。Jenkins自动部署完整操作步骤如下:
(1)单击www.jfedu.net工程名配置构建后操作Add post-build stepArchive the artifacts用于存档的文件输入:*/target/.war,该选项主要用于Jenkins编译后会将war包存档一份到target目录,该文件可以通过Jenkins Tomcat的HTTP端口访问,如图22-15(a)、22-15(b)所示:

图22-15(a) Jenkins JOB工程编译控制台
图22-15(b)Jenkins JOB工程编译控制台
(2)Jenkins构建完毕,访问Jenkins war存档的文件,URL地址如下:
http://139.224.227.121:7001/job/www.jfedu.net/lastSuccessfulBuild/artifact/target/edu.war
(3)选择Add post-build step Execute shellCommand输入如下代码,实现Jenkins edu.war包自动部署,如下为139.199.228.59客户端单台服务器部署edu.war,如果多台可以使用ip.txt列表,将IP加入至ip.txt,通过for循环实现批量部署,如图22-16(a)、22-16(b)所示:
cp /root/.jenkins/workspace/www.jfedu.net/target/edu.war /root/.jenkins/jobs/www.jfedu.net/builds/lastSuccessfulBuild/archive/target/
ssh root@ 139.199.228.59 'bash -x -s' < /data/sh/auto_deploy.sh

for I in cat ip.txt;do ssh root@${I} 'bash -x -s' < /data/sh/auto_deploy.sh ;done

图22-16(a)Jenkins JOB构建完毕执行Shell

图22-16(b)Jenkins JOB构建完毕执行Shell
(4)基于Jenkins将edu.war自动部署至139.199.228.59服务器Tomcat发布目录,需提前配置登录远程客户端免秘钥,免秘钥配置首先在Jenkins服务器执行ssh-keygen命令,然后按Enter键生成公钥和私钥;然后将公钥id_rsa.pub拷贝至客户端/root/.ssh/目录,并重命名为authorized_keys,操作命令如下:
ssh-keygen -t rsa -P ' ' -f /root/.ssh/id_rsa
ssh-copy-id -i /root/.ssh/id_rsa.pub 139.199.228.59
(5)Shell脚本需放在Jenkins服务器/data/sh/,无需放在客户端,Shell脚本内容如下:

!/bin/bash

Auto deploy Tomcat for jenkins

By author jfedu.net 2017

export JAVA_HOME=/usr/java/jdk1.6.0_25
TOMCAT_PID=/usr/sbin/lsof -n -P -t -i :8081
TOMCAT_DIR="/usr/local/tomcat/"
FILES="edu.war"
DES_DIR="/usr/local/tomcat/webapps/ROOT/"
DES_URL="http://139.224.227.121:7001/job/www.jfedu.net/lastSuccessfulBuild/artifact/target/"
BAK_DIR="/export/backup/date +%Y%m%d-%H%M"
[ -n "$TOMCAT_PID" ] && kill -9 $TOMCAT_PID
cd $DES_DIR
rm -rf $FILES
mkdir -p $BAK_DIR;\cp -a $DES_DIR/ $BAK_DIR/
rm -rf $DES_DIR/

wget $DES_URL/$FILES
/usr/java/jdk1.6.0_25/bin/jar -xvf $FILES
####################
cd $TOMCAT_DIR;rm -rf work
/bin/sh $TOMCAT_DIR/bin/start.sh
sleep 10
tail -n 50 $TOMCAT_DIR/logs/catalina.out
如上通过Shell+For循环可以实现网站简单的异步部署,如果需要将Jenkins edu.war包批量快速部署至100台、500台服务器,该如何去实现呢?后续小结会讲解到。
22.10 Jenkins插件安装
Jenkins最大的功能莫过于插件丰富,基于各种插件可以满足各项需求,Jenkins本身是一个框架,真正发挥作用的是各种插件。Jenkins默认自带很多插件,如果需添加新插件,可以在Jenkins平台主页面进行操作,操作步骤如下:
Jenkins平台首页系统管理管理插件可选插件搜索email-ext-plugin插件选择并安装,如果没有该插件,则需单击“高级”,手动上传插件并安装,操作步骤如图22-17所示:
图22-17 Jenkins 添加新插件
访问Jenkins官网手动下载插件,将下载的插件传到服务器Jenkins根目录(/root、)下的plugins目录,即/root/.jenkins/plugins目录,重启jenkins即可。Jenkins插件下载地址:https://wiki.jenkins-ci.org/display/JENKINS/Plugins。安装Email-ext-Plugin邮件插件的方法如下
(1)下载Email-ext和Token-macro、Email-template,可以搜索某个插件,输入插件名称,如图22-18所示:

图22-18 Jenkins 下载新插件
(2)Email-ext和Token-macro、Email-template插件下载URL如下:
https://wiki.jenkins-ci.org/display/JENKINS/Email-ext+plugin
https://wiki.jenkins-ci.org/display/JENKINS/Token+Macro+Plugin
https://wiki.jenkins-ci.org/display/JENKINS/Email-ext+Template+Plugin
(3)安装Token-macro插件,如图22-19(a)、22-19(b)所示:

图22-19(a) Jenkins Token-macro插件安装

图22-19(b) Jenkins Token-macro插件安装
(4)安装email-ext插件,如图22-20所示:

图22-20 Jenkins email-ext插件安装
(5)Email-ext、Token-macro和Email-template插件安装完毕,如图22-21所示:
图22-21 Jenkins 插件安装完毕
(6)Email插件安装完毕, Jenkins主界面系统管理系统设置会出现选项Extended E-mail Notification,则表示Jenkins Email邮件插件安装完毕,如图22-22所示:

图22-22 Jenkins Email邮件插件
如需安装GIT、Publish Over插件或者安装装Jenkins其他任意插件,方法与Email插件安装方法一致。
22.11 Jenkins邮件配置
如上Jenkins持续集成配置完毕,可以进行网站代码的自动更新、部署、升级及回滚操作,通过控制台信息可以查看每个JOB工程构建的状态。
如果网站项目很多,人工去查看状态就变得不可取,可以借助Jenkins Email插件实现网站构建完成,自动发送邮件给相应的开发人员、运维人员或者测试人员。Jenkins发送邮件,需安装Email邮件插件,Email-ext、Token-macro和Email-template,Jenkins Email邮件配置常见参数:
SMTP server 邮件服务器地址;
Default Content Type 内容展现的格式,一般选择HTML;
Default Recipients 默认收件人;
Use SMTP Authentication 使用SMTP身份验证;
User Name 邮件发送账户的用户名;
Password 邮件发送账户的密码;
SMTP port SMTP服务器端口。
Jenkins Email邮件配置方法如下:
(1)设置Jenkins邮件发送者,Jenkins平台首页系统管理系统设置Jenkins Location填写Jenkins URL与系统管理员邮件地址,如图22-23(a)、22-23(b)所示:

图22-23(a) Jenkins Email邮件配置

图22-23(b) Jenkins Email邮件配置
(2)设置发送邮件的SMTP服务器、邮箱后缀,发送类型html、接收者或者抄送者,单击Jenkins平台首页系统管理系统设置 Extended E-mail Notification,填写如图22-24所示的选项,包括SMTP server、默认后缀、使用SMTP认证、Default Recipients邮件接收人等信息:

图22-24 Jenkins Email邮件配置
(3)设置邮件的标题Default Subject内容如下:
构建通知:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS
(4)设置发送邮件的内容,Default Content内容如下:


(本邮件是程序自动下发的,请勿回复!)


项目名称:$PROJECT_NAME

构建编号:$BUILD_NUMBER

构建状态:$BUILD_STATUS

触发原因:${CAUSE}

构建日志地址:${BUILD_URL}console

构建地址:$BUILD_URL

变更集:${JELLY_SCRIPT,template="html"}

(5)每个JOB工程邮件设置,单击www.jfedu.net JOB名称配置构建后操作选择Editable Email Notification,如下信息保持默认,出现如图22-25所示:

图22-25 Jenkins EmailJOB邮件模板配置
(6)选择Advanced Settings,设置Trigger阀值,选择发送邮件的触发器,默认触发器包括:第一次构建、构建失败、总是发送邮件、构建成功等,一般选择always总是发送邮件,发送给developers组,如图22-26所示。
图22-26 Jenkins Email 触发器设置
(7)Jenkins构建邮件验证,如图22-27(a)、22-27(b)、22-27(c)所示:

图22-27(a) Jenkins构建报错触发邮件
图22-27(b) Jenkins Email邮件信息
图22-27(c) Jenkins Email邮件信息
22.12 Jenkins多实例配置
单台Jenkins服务器可以满足企业测试环境及生产环境使用Jenkins自动部署+测试平台,如果每天更新发布多个WEB网站,Jenkins需要同时处理很多的任务。
基于Jenkins分布式,也即多Slave方式可以缓解Jenkins服务器的压力,Jenkins多实例架构如图22-28所示,可以在Windows、Linux、MAC等操作系统上执行Slave。
图22-28 Jenkins Slave架构图
Jenkins多Slave原理是将原本在Jenkins Master端的构建项目分配给Slave端去执行,Jenkins Master分配任务时,Jenkins Master端通过SSH远程Slave,在Slave端启动slave.jar程序,通过Slave.jar实现对网站工程的构建编译以及自动部署。所以在Slave端服务器必须安装Java JDK环境来执行Master端分配的构建任务。配置多Slave服务器方法和步骤如下:
(1)在Slave服务器,创建远程执行Jenkins任务的用户,名称为jenkins,Jenkins工作目录/home/Jenkins,Jenkins Master免秘钥登录Slave服务器或者通过用户名和密码登录Slave;
(2)Slave服务器安装JAVA JDK版本,并将其软件路径加入系统环境变量。
(3)Jenkins master端平台添加管理节点,系统管理管理节点新建节点输入节点名称,分别如图22-29(a)、22-29(b)、22-29(c)所示:
图22-29(a) Jenkins Slave配置
图22-29(b) Jenkins Slave配置

图22-29(c) Jenkins Slave配置
(4)配置www_slave节点,指定其Jenkins编译工作目录,设置IP地址,Credentials Add添加登录Slave用户名和密码,如图22-30(a)、22-30(b)所示:

图22-30(a) Jenkins Slave配置

图22-30(b) Jenkins Slave配置
(5)Jenkins Slave配置完毕,查看SLAVE状态如如图22-31所示:
图22-31 Jenkins Slave状态信息
(6)单击www_slave节点,然后选择launch salve agent,单击测试Slave Agent是否正常工作,如图22-32所示:

图22-32 Jenkins Slave Agent测试
(7)出现如图22-33(a)、22-33(b)所示,即证明Slave添加成功:
图22-33(a) Jenkins Slave测试
图22-33(b) Jenkins Slave测试
(8)如上配置完毕,Jenkins-master通过ssh方式来启动slave的slave.jar脚本,java –jar slave.jar,Slave等待master端的任务分配,单击www.jfedu.net,然后选择立即构建,如图22-34所示:
图22-34 Jenkins Slave构建任务
(9)Jenkins+Slave配置完毕后,如果同时运行多个任务,会发现只会运行一个任务,另外的任务在等待,那需要怎么调整呢,需要配置JOB工程勾选“在必要的时候并发构建”即可,如图22-35(a)、22-35(b)所示:
图22-35(a) Jenkins Slave构建多任务
图22-35(b) Jenkins Slave构建多任务
22.13 Jenkins+Ansible高并发构建
Jenkins自动部署基于Shell+For循环方式部署10台以下的JAVA客户端服务器,效率是可以接受的,但是如果是大规模服务器需要部署或者更新网站,通过for循环串行执行效率会大打折扣,所以需要考虑到并行机制。
Ansible是一款极为灵活的开源工具套件,能够大大简化Unix管理员的自动化配置管理与流程控制方式。它利用推送方式对客户系统加以配置,这样所有工作都可在主服务器端完成。使用Ansible+Jenkins架构方式实现网站自动部署,满足上百台、千台服务器的网站部署和更新。
Ansible服务需要部署在Jenkins服务器,客户端服务器无需安装Ansible。Ansible基于SSH工作,所以需提前做好免秘钥或者通过sudo用户远程更新网站。此处省略Ansible安装,Ansible相关知识请参考本书Ansible章节配置。
Ansible自动部署网站,有两种方法,一种是基于Ansible远程执行Shell脚本,另外一种是Ansible编写Playbook剧本,实现网站自动部署。如下为Ansible+Shell脚本方式自动部署网站方法:
(1)Jenkins服务器安装Ansible软件,Red Hat、CentOS操作系统可以直接基于YUM工具自动安装Ansible,CentOS6.x或者CentOS7.x安装前,需先安装epel扩展源,代码如下:
rpm -Uvh http://mirrors.ustc.edu.cn/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum install epel-release -y
yum install ansible -y
(2)添加客户端服务器,在/etc/ansible/hosts中添加需要部署的客户端IP列表,如下代码:
[www_jfedu]
139.199.228.59
139.199.228.60
139.199.228.61
139.199.228.62
(3)Jenkins平台首页单击www.jfedu.net项目选择配置单击Post StepsExecute shellCommand输入如下代码,www_jfedu为Ansible Hosts组模块名称:
cp /root/.jenkins/workspace/www.jfedu.net/target/edu.war /root/.jenkins/jobs/www.jfedu.net/builds/lastSuccessfulBuild/archive/target/
ansible www_jfedu -m copy -a "src=/data/sh/auto_deploy.sh dest=/tmp/"
ansible www_jfedu -m shell -a "cd /tmp ;/bin/bash auto_deploy.sh"
(4)Jenkins服务器端/data/sh/auto_deploy.sh Shell脚本内容如下:

!/bin/bash

Auto deploy Tomcat for jenkins

By author jfedu.net 2017

export JAVA_HOME=/usr/java/jdk1.6.0_25
TOMCAT_PID=/usr/sbin/lsof -n -P -t -i :8081
TOMCAT_DIR="/usr/local/tomcat/"
FILES="edu.war"
DES_DIR="/usr/local/tomcat/webapps/ROOT/"
DES_URL="http://139.224.227.121:7001/job/www.jfedu.net/lastSuccessfulBuild/artifact/target/"
BAK_DIR="/export/backup/date +%Y%m%d-%H%M"
[ -n "$TOMCAT_PID" ] && kill -9 $TOMCAT_PID
cd $DES_DIR
rm -rf $FILES
mkdir -p $BAK_DIR;\cp -a $DES_DIR/ $BAK_DIR/
rm -rf $DES_DIR/

wget $DES_URL/$FILES
/usr/java/jdk1.6.0_25/bin/jar -xvf $FILES
####################
cd $TOMCAT_DIR;rm -rf work
/bin/sh $TOMCAT_DIR/bin/start.sh
sleep 10
tail -n 50 $TOMCAT_DIR/logs/catalina.out
(5)单击www.jfedu.net构建任务,查看控制台信息,如图22-36(a)、22-36(b)、22-36(c)所示:
图22-36(a) Jenkins Ansible自动部署
图22-36(b) Jenkins Ansible自动部署
图22-36(c) Jenkins Ansible自动部署

第23章 Linux高可用集群实战

23.1 Keepalived高可用软件简介
目前互联网主流的实现WEB网站及数据库服务高可用软件包括:keepalived、heartbeat等。Heartbeat是比较早期的实现高可用软件,而keepalived是目前轻量级的管理方便、易用的高可用软件解决方案,得到互联网公司IT人的青睐。
Keepalived是一个类似于工作在layer3, 4 & 7交换机制的软件,Keepalived软件有两种功能,分别是监控检查、VRRP冗余协议。
Keepalived的作用是检测web服务器的状态,如果有一台web服务器、Mysql服务器宕机,或工作出现故障,Keepalived将检测到后,会将有故障的web服务器或者Mysql服务器从系统中剔除,当服务器工作正常后Keepalived自动将web、Mysql服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的WEB和Mysql服务器。Layer3,4&7工作在IP/TCP协议栈的IP层、传输层及应用层,实现原理分别如下:
Layer3:Keepalived使用Layer3的方式工作式时,Keepalived会定期向服务器群中的服务器发送一个ICMP的数据包(,如果发现某台服务的IP地址无法ping通,Keepalived便报告这台服务器失效,并将它从服务器集群中剔除。Layer3的方式是以服务器的IP地址是否有效作为服务器工作正常与否的标准。
Layer4: Layer4主要以TCP端口的状态来决定服务器工作正常与否。如WEB server的服务端口一般是80,如果Keepalived检测到80端口没有启动,则Keepalived将把这台服务器从服务器群中剔除。
Layer7:Layer7工作在应用层,Keepalived将根据用户的设定检查服务器程序的运行是否正常,如果与用户的设定不相符,则Keepalived将把服务器从服务器群中剔除。
23.2 Keepalived VRRP原理剖析
Keepalived是VRRP的完美实现,在学习keepalived之前,必须了解VRRP协议的原理。在现实的网络环境中,两台需要通信的主机大多数情况下并没有直接的物理连接。对于这样的情况,它们之间路由怎样选择?主机如何选定到达目的主机的下一跳路由,这个问题通常的解决方法有二种:
在主机上使用动态路由协议RIP、OSPF;
在主机上配置静态路由.
在主机上配置路态路由是非常不切实际的,因为管理、维护成本以及是否支持等诸多问题。配置静态路由就变得十分流行,但路由器(或者说默认网关default gateway)却经常成为单点,VRRP的目的就是为了解决静态路由单点故障问题。VRRP通过一竞选(election)协议来动态的将路由任务交给LAN中虚拟路由器中的某台VRRP路由器。
在VRRP虚拟路由器集群中,由多台物理的路由器组成,但是这多台的物理路由器并不能同时工作,而是由一台称为MASTER路由器负责路由工作,其它的都是BACKUP,MASTER并非一成不变,VRRP会让每个VRRP路由器参与竞选,最终获胜的就是MASTER。
MASTER拥有一些特权,例如拥有虚拟路由器的IP地址或者成为VIP,拥有特权的MASTER要负责转发发送给网关地址的包和响应ARP请求。
VRRP通过竞选协议来实现虚拟路由器的功能,所有的协议报文都是通过IP多播(multicast)包(多播地址 224.0.0.18)形式发送的。虚拟路由器由VRID(范围0-255)和一组IP地址组成,对外表现为一个周知的MAC地址。所以在一组虚拟路由器集群中,不管谁是MASTER,对外都是相同的MAC和VIP。客户端主机并不需要因为MASTER的改变而修改自己的路由配置。
作为MASTER的VRRP路由器会一直发送VRRP广播包(VRRP Advertisement message),BACKUP不会抢占MASTER,除非它的优先级(Priority)更高。当MASTER不可用时(BACKUP收不到广播包时), 多台BACKUP中优先级最高的这台会抢占为MASTER。这种抢占是非常快速的,以保证服务的连续性。由于安全性考虑VRRP包使用了加密协议进行。
而keepalived可以基于VRRP技术,将两台物理主机当成路由器,两台物理机主机组成一个虚拟路由集群,Master高的主机产生VIP,该VIP负责转发用户发起的IP包或者负责处理用户的请求,Nginx+Keepalived组合,用户的请求直接访问keepalived VIP地址,然后访问Master相应服务和端口
23.3 企业级Nginx+Keepalived集群实战
随着Nginx在国内的发展潮流,越来越多的互联网公司都在使用Nginx,Nginx高性能、稳定性成为IT人士青睐的HTTP和反向代理服务器。
Nginx负载均衡一般位于整个网站架构的最前端或者中间层,如果为最前端时单台Nginx会存在单点故障,也就是一台Nginx宕机,会影响用户对整个网站的访问。所以需要加入Nginx备份服务器,Nginx主服务器与备份服务器之间形成高可用,一旦发现Nginx主宕机,能快速将网站恢复至备份主机。Nginx+keepalived网络架构如图23-1所示:

图23-1 Nginx+Keepalived架构图
Nginx+keepalived高性能WEB网络架构实战配置如下步骤:
(1)环境准备
Nginx版本:nginx v1.12.0
Keepalived版本:keepalived v1.2.1
Nginx-1:192.168.33.8 (Master)
Nginx-2:192.168.33.10 (Backup)
(2)Nginx安装配置,Master、Backup服务器安装Nginx、keepalived,yum install -y pcre-devel 安装perl 兼容的正规表达式库。
tar -xzf nginx-1.12.0.tar.gz
cd nginx-1.12.0
sed -i -e 's/1.12.0//g' -e 's/nginx\//TDTWS/g' -e 's/"NGINX"/"TDTWS"/g' src/core/nginx.h
./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_ssl_module
make
make install
(3)Keepalived安装配置
tar -xzvf keepalived-1.2.1.tar.gz
cd keepalived-1.2.1
./configure
make
make install
DIR=/usr/local/
cp $DIR/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp $DIR/etc/sysconfig/keepalived /etc/sysconfig/
mkdir -p /etc/keepalived
cp $DIR/sbin/keepalived /usr/sbin/
(4)配置Keepalived,两台服务器keepalived.conf内容都为如下,state均设置为backup,Backup服务器需要修改优先级为90。
! Configuration File for keepalived
global_defs {
notification_email {
support@jfedu.net
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}

vrrp_script chk_nginx {
script "/data/sh/check_nginx.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state BACKUP
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 100
advert_int 5
nopreempt
authentication {
auth_typePASS
auth_pass 1111

 } 
 virtual_ipaddress { 
     192.168.33.188 
 } 
 track_script { 
 chk_nginx 
} 

}
如上配置还需要建立check_nginx脚本,用于检查本地Nginx是否存活,如果不存活,则kill keepalived实现切换。其中check_nginx.sh脚本内容如下:

!/bin/bash

auto check nginx process

2017-5-26 17:47:12

by author jfedu.net

killall -0 nginx
if [[ $? -ne 0 ]];then
/etc/init.d/keepalived stop
fi
在两台Nginx服务器分别新建index.html测试页面,然后启动Nginx服务测试,访问VIP地址,http://192.168.33.188即可
23.4 企业级Nginx+Keepalived双主架构实战
Nginx+keepalived主备模式,始终存在一台服务器处于空闲状态,如何更好的把两台服务器利用起来呢,可以借助Nginx+keepalived双主架构来实现,如图23-2所示,将架构改成双主架构,也即同时两台对外两个VIP地址,同时接收用户的请求。

图23-2 Nginx+Keepalived双主架构
Nginx+Keepalived双主架构实现方法步骤如下:
(1)Master1上keepalived.conf配置文件内容:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_nginx {
script "/data/sh/check_nginx.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state MASTER
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 100
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_nginx
}
}

VIP2

vrrp_instance VI_2 {
state BACKUP
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 152
priority 90
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 2222
}
virtual_ipaddress {
192.168.33.199
}
track_script {
chk_nginx
}
}
(2)Master2上keepalived.conf配置文件内容:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_nginx {
script "/data/sh/check_nginx.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state BACKUP
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 90
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_nginx
}
}

VIP2

vrrp_instance VI_2 {
state MASTER
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 152
priority 100
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 2222
}
virtual_ipaddress {
192.168.33.199
}
track_script {
chk_nginx
}
}
(3)两台Nginx服务器上配置/data/sh/check_nginx.sh脚本,内容如下:

!/bin/bash

auto check nginx process

killall -0 nginx
if
[[ $? -ne 0 ]];then
/etc/init.d/keepalived stop
fi
(4)如图23-3所示,两个VIP在一台服务器,是由于另外一台服务器down机,VIP都漂移到本机网卡下。

图23-3 VIP漂移在单台服务器
(5)Nginx+keepalived双主企业架构,在日常维护及管理过程中需要如下几个方面:
Keepalived主配置文件必须设置不同的VRRP名称,同时优先级和VIP设置也各不相同;
Nginx网站总访问量为两台Nginx服务器之和,可以写脚本自动统计访问量;
两台Nginx为Master,存在两个VIP地址,用户从外网访问VIP,需配置域名映射到两个VIP上方可。
通过外网DNS映射不同VIP的方法也称为DNS负载均衡模式;
可以通过Zabbix实时监控VIP访问状态是否正常。
23.5 Redis+keepalived高可用集群实战
Redis主从复制优点及应用场景,WEB应用程序可以基于主从同步实现读写分离以提高服务器的负载能力。
在常见的场景中,读的频率一般比较大,当单机Redis无法应付大量的读请求时,可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库负责读操作,基于keepalived+Redis对Redis实现高可用,保证网站正常访问。如下为Redis+keepalived高可用架构实现步骤:
(1)Redis主库、丛库分别安装Keepalived服务:
tar -xzvf keepalived-1.2.1.tar.gz
cd keepalived-1.2.1
./configure
make
make install
DIR=/usr/local/
cp $DIR/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp $DIR/etc/sysconfig/keepalived /etc/sysconfig/
mkdir -p /etc/keepalived
cp $DIR/sbin/keepalived /usr/sbin/
(2)Redis+Keepalived Master配置文件代码如下:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_redis {
script "/data/sh/check_redis.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state MASTER
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 100
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_redis
}
}
(3)Redis+Keepalived Backup配置文件代码如下:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_redis {
script "/data/sh/check_redis.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state BACKUP
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 90
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_redis
}
}
(4)两台Redis服务器上配置/data/sh/check_redis.sh脚本,内容如下:

!/bin/bash

auto check redis process

NUM=ps -ef |grep redis|grep -v grep|grep -v check|wc -l
if
[[ $NUM -eq 0 ]];then
/etc/init.d/keepalived stop
fi
23.6 NFS+keepalived高可用集群实战
NFS(Network File System)是一个网络文件系统,是Linux系统直接支持文件共享的一直文件系统,它允许网络中的计算机之间通过TCP/IP网络共享资源。在NFS的应用中,本地NFS的客户端应用可以透明地读写位于远端NFS服务器上的文件,就像访问本地文件一样。一般NFS为单击部署,而NFS服务器主要用于存放企业重要数据,此时为了能保证数据的安全可靠,需要对NFS服务器之前实现同步+keepalived高可用满足企业业务需求,如下为NFS+keepalived高可用架构实现步骤:
(1)NFS主和备分别安装Keepalived服务:
tar -xzvf keepalived-1.2.1.tar.gz
cd keepalived-1.2.1
./configure
make
make install
DIR=/usr/local/
cp $DIR/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp $DIR/etc/sysconfig/keepalived /etc/sysconfig/
mkdir -p /etc/keepalived
cp $DIR/sbin/keepalived /usr/sbin/
(2)NFS+Keepalived Master配置文件代码如下:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_redis {
script "/data/sh/check_nfs.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state MASTER
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 100
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_nfs
}
}
(3)Redis+Keepalived Backup配置文件代码如下:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_redis {
script "/data/sh/check_nfs.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state BACKUP
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 90
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_nfs
}
}
(4)两台NFS服务器上配置/data/sh/check_nfs.sh脚本,内容如下:

!/bin/bash

auto check nfs process

NUM=ps -ef |grep nfs|grep -v grep|grep -v check|wc -l
if
[[ $NUM -eq 0 ]];then
/etc/init.d/keepalived stop
fi
23.7 MYSQL+keepalived高可用集群实战
MySQL主从同步复制可以实现去数据库进行备份,保证网站数据的快速恢复,一般应用程序读写均在Master上,如果一旦Master服务器宕机,需要手工切换WEB网站连接数据库的IP至丛库,可以基于keepalived软件实现自动IP切换,保证网站高可用率,MySQL+keepalived集群架构配置方法如下:
(1)MySQL主库、丛库分别安装Keepalived服务:
tar -xzvf keepalived-1.2.1.tar.gz
cd keepalived-1.2.1
./configure
make
make install
DIR=/usr/local/
cp $DIR/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp $DIR/etc/sysconfig/keepalived /etc/sysconfig/
mkdir -p /etc/keepalived
cp $DIR/sbin/keepalived /usr/sbin/
(2)MySQL+Keepalived Master配置文件代码如下:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_mysql {
script "/data/sh/check_mysql.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state MASTER
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 100
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_redis
}
}
(3)MySQL+Keepalived Backup配置文件代码如下:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_redis {
script "/data/sh/check_mysql.sh"
interval 2
weight 2
}

VIP1

vrrp_instance VI_1 {
state BACKUP
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 151
priority 90
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
track_script {
chk_mysql
}
}
(4)两台MySQL服务器上配置/data/sh/check_mysql.sh脚本,内容如下:

!/bin/bash

auto check mysql process

NUM=ps -ef |grep mysql|grep -v grep|grep -v check|wc -l
if
[[ $NUM -eq 0 ]];then
/etc/init.d/keepalived stop
fi
(5)WEB网站直接连接keepalived VIP即可实现网站自动切换,发现MySQL宕机,会自动切换至丛库上。
23.8 Haproxy+keepalived高可用集群实战
随着互联网火热的发展,开源负载均衡器的大量的应用,企业主流软件负载均衡如LVS、Haproxy、Nginx等,各方面性能不亚于硬件负载均衡F5,Haproxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。
23.8.1 Haproxy入门简介
HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。负载均衡LVS是基于四层,新型的大型互联网公司也在采用Haproxy,了解了Haproxy大并发、七层应用等,Haproxy高性能负载均衡优点:
HAProxy是支持虚拟主机的,可以工作在4、7层;
能够补充Nginx的一些缺点比如Session的保持,Cookie的引导等工作;
支持url检测后端的服务器;
它跟LVS一样,只是一款负载均衡软件,单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的;
HAProxy可以对Mysql读进行负载均衡,对后端的MySQL节点进行检测和负载均衡,HAProxy的支持多种算法。
Haproxy+Keepalived企业高性能WEB能够支持千万级并发网站,实现Haproxy高性能WEB网站架构配置步骤如下:
23.8.2 Haproxy安装配置
Haproxy安装配置步骤相对比较简单,跟其他源码软件安装方法大致相同,如下为Haproxy配置方法及步骤:
(1)Haproxy编译及安装
cd /usr/src
wget http://haproxy.1wt.eu/download/1.4/src/haproxy-1.4.21.tar.gz
tar xzf haproxy-1.4.21.tar.gz
cd haproxy-1.4.21
make TARGET=linux26 PREFIX=/usr/local/haproxy/
make install PREFIX=/usr/local/haproxy
(2)配置Haproxy服务
cd /usr/local/haproxy ;mkdir -p etc/
touch /usr/local/haproxy/etc/haproxy.cfg
(3)Haproxy.cfg配置文件内容如下:
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
maxconn 4096
uid 99
gid 99
daemon
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
frontend http-in
bind *:80
acl is_www.jf1.com hdr_end(host) -i jf1.com
acl is_www.jf2.com hdr_end(host) -i jf2.com
use_backend www.jf1.com if is_www.jf1.com
use_backend www.jf2.com if is_www.jf2.com
default_backend www.jf1.com
backend www.jf1.com
balance roundrobin
cookie SERVERID insert nocache indirect
option httpchk HEAD /index.html HTTP/1.0
option httpclose
option forwardfor
server jf1 192.168.33.11:80 cookie jf1 check inter 1500 rise 3 fall 3 weight 1
backend www.jf2.com
balance roundrobin
cookie SERVERID insert nocache indirect
option httpchk HEAD /index.html HTTP/1.0
option httpclose
option forwardfor
server jf2 192.168.33.11:81 cookie jf2 check inter 1500 rise 3 fall 3 weight 1
(4)启动Haproxy服务
/usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/etc/haproxy.cfg
启动Haproxy报错如下:
[WARNING] 217/202150 (2857) : Proxy 'chinaapp.sinaapp.com': in multi-process mode, stats will be limited to process assigned to the current request.
修改源码配置src/cfgparse.c找到如下行,调整nbproc > 1数值即可:
if (nbproc > 1) {
if (curproxy->uri_auth) {

  •               Warning("Proxy '%s': in multi-process mode, stats will be limited to process assigned to the current request.\n",
  •               Warning("Proxy '%s': in multi-process mode, stats will be limited to the process assigned to the current request.\n",

    23.8.3 Haproxy配置文件详解
    Hproxy配置文件内容详解如下:

    全局配置信息#######

    global
    maxconn 20480 #默认最大连接数
    log 127.0.0.1 local3 #[err warning info debug]
    chroot /usr/local/haproxy #chroot运行的路径
    uid 99 #所属运行的用户uid
    gid 99 #所属运行的用户组
    daemon #以后台形式运行haproxy
    nbproc 8 #进程数量(可以设置多个进程提高性能)
    pidfile /usr/local/haproxy/haproxy.pid #haproxy的pid存放路径,启动进程的用户必须有权限访问此文件
    ulimit-n 65535 #ulimit的数量限制
    ###########默认的全局设置##########

    这些参数可以被利用配置到frontend,backend,listen组件##

    defaults
    log global
    mode http #所处理的类别 (#7层 http;4层tcp )
    maxconn 20480 #最大连接数
    option httplog #日志类别http日志格式
    option httpclose #每次请求完毕后主动关闭http通道
    option dontlognull #不记录健康检查的日志信息
    option forwardfor #如果后端服务器需要获得客户端真实ip需要配置的参数,可以从Http Header中获得客户端ip
    option redispatch #serverId对应的服务器挂掉后,强制定向到其他健康的服务器
    option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的连接
    stats refresh 30 #统计页面刷新间隔
    retries 3 #3次连接失败就认为服务不可用,也可以通过后面设置
    balance roundrobin #默认的负载均衡的方式,轮询方式

    balance source #默认的负载均衡的方式,类似nginx的ip_hash

    #balance leastconn #默认的负载均衡的方式,最小连接 
     contimeout 5000  #连接超时 
     clitimeout 50000 #客户端超时 
     srvtimeout 50000 #服务器超时 
     timeout check 2000 #心跳检测超时 

    ##############监控页面的设置###########
    listen admin_status #Frontend和Backend的组合体,监控组的名称,按需自定义名称
    bind 0.0.0.0:65532 #监听端口
    mode http #http的7层模式
    log 127.0.0.1 local3 err #错误日志记录
    stats refresh 5s #每隔5秒自动刷新监控页面
    stats uri /admin?stats #监控页面的url
    stats realm jfedu\ jfedu #监控页面的提示信息
    stats auth admin:admin #监控页面的用户和密码admin,可以设置多个用户名
    stats hide-version #隐藏统计页面上的HAproxy版本信息
    stats admin if TRUE #手工启用/禁用,后端服务器;
    ##########监控haproxy后端服务器的状态############
    listen site_status
    bind 0.0.0.0:1081 #监听端口
    mode http #http的7层模式
    log 127.0.0.1 local3 err #[err warning info debug]
    monitor-uri /site_status #网站健康检测URL,用来检测HAProxy管理的网站是否可以用,正常返回200,不正常返回503
    acl site_dead nbsrv(server_web) lt 2 #定义网站down时的策略当挂在负载均衡上的指定backend的中有效机器数小于1台时返回true
    monitor fail if site_dead #当满足策略的时候返回503,网上文档说的是500,实际测试为503
    monitor-net 192.168.149.129/32 #来自192.168.149.129的日志信息不会被记录和转发;
    monitor-net 192.168.149.130/32 #来自192.168.149.130的日志信息不会被记录和转发;
    ########frontend配置############

    注意,frontend配置里面可以定义多个acl进行匹配操作########

    frontend http_80_in
    bind 0.0.0.0:80 #监听端口,即haproxy提供web服务的端口,和lvs的vip端口类似
    mode http #http的7层模式
    log global #应用全局的日志配置
    option httplog #启用http的log
    option httpclose #每次请求完毕后主动关闭http通道,HA-Proxy不支持keep-alive模式
    option forwardfor #如果后端服务器需要获得客户端的真实IP需要配置次参数,将可以从Http Header中获得客户端IP
    ########acl策略配置#############
    acl jfedu_web hdr_reg(host) -i ^(www1.jfedu.net|www2.jfedu.net)$

    如果请求的域名满足正则表达式中的2个域名返回true -i是忽略大小写

     #如果请求的域名满足www.jfedu.net返回true -i是忽略大小写 
     #acl jfedu hdr(host) -i jfedu.net 
     #如果请求的域名满足jfedu.net返回true -i是忽略大小写 
     #acl file_req url_sub -i killall= 
     #在请求url中包含killall=,则此控制策略返回true,否则为false 
     #acl dir_req url_dir -i allow 
     #在请求url中存在allow作为部分地址路径,则此控制策略返回true,否则返回false 
     #acl missing_cl hdr_cnt(Content-length) eq 0 
     #当请求的header中Content-length等于0时返回true 

    ########acl策略匹配相应#############

    block if missing_cl

     #当请求中header中Content-length等于0阻止请求返回403 
     #block if !file_req || dir_req 
     #block表示阻止请求,返回403错误,当前表示如果不满足策略file_req,或者满足策略dir_req,则阻止请求 
     use_backend server_web if jfedu_web 
     #当满足jfedu_web的策略时使用server_web的backend 

    ##########backend的设置##############
    backend server_web
    mode http #http的7层模式
    balance roundrobin #负载均衡的方式,roundrobin平均方式
    cookie SERVERID #允许插入serverid到cookie中,serverid后面可以定义
    option httpchk GET /index.html #心跳检测的文件
    server web1 192.168.149.129:80 cookie web1 check inter 1500 rise 3 fall 3 weight 1

    服务器定义,cookie 1表示serverid为web1,check inter 1500是检测心跳频率rise 3是3次正确认为服务器可用,

     #fall 3是3次失败认为服务器不可用,weight代表权重 
     server web2 192.168.149.130:80 cookie web2 check inter 1500 rise 3 fall 3 weight 2 
     #服务器定义,cookie 1表示serverid为web2,check inter 1500是检测心跳频率rise 3是3次正确认为服务器可用, 
     #fall 3是3次失败认为服务器不可用,weight代表权重。

    23.8.4 安装Keepalived服务
    cd /usr/src ;
    wget http://www.keepalived.org/software/keepalived-1.2.1.tar.gz
    tar xzf keepalived-1.2.1.tar.gz
    cd keepalived-1.2.1 &&
    ./configure --with-kernel-dir=/usr/src/kernels/2.6.32-71.el6.x86_64/
    make &&make install
    DIR=/usr/local/ ;cp $DIR/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
    cp $DIR/etc/sysconfig/keepalived /etc/sysconfig/
    mkdir -p /etc/keepalived && cp $DIR/sbin/keepalived /usr/sbin/
    23.8.5 配置Haproxy+keepalived
    Haproxy+keealived Master端keepalived.conf配置文件如下:
    ! Configuration File for keepalived
    global_defs {
    notification_email {
    wgkgood@139.com
    }
    notification_email_from wgkgood@139.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id LVS_DEVEL
    }
    vrrp_script chk_haproxy {
    script "/data/sh/check_haproxy.sh"
    interval 2
    weight 2
    }

    VIP1

    vrrp_instance VI_1 {
    state MASTER
    interface eth0
    lvs_sync_daemon_inteface eth0
    virtual_router_id 151
    priority 100
    advert_int 5
    nopreempt
    authentication {
    auth_typePASS
    auth_pass 2222
    }
    virtual_ipaddress {
    192.168.0.133
    }
    track_script {
    chk_haproxy
    }
    }
    23.8.6 创建haproxy脚本
    设置可执行权限chmod +x check_haproxy.sh,脚本内容如下:

    !/bin/bash

    auto check haprox process

    2017-6-12 jfedu.net

    killall -0 haproxy
    if
    [[ $? -ne 0 ]];then
    /etc/init.d/keepalived stop
    fi
    Haproxy+keealived Backup端keepalived.conf配置文件如下:
    ! Configuration File for keepalived
    global_defs {
    notification_email {
    wgkgood@139.com
    }
    notification_email_from wgkgood@139.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id LVS_DEVEL
    }
    vrrp_script chk_haproxy {
    script "/data/sh/check_haproxy.sh"
    interval 2
    weight 2
    }

    VIP1

    vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    lvs_sync_daemon_inteface eth0
    virtual_router_id 151
    priority 90
    advert_int 5
    nopreempt
    authentication {
    auth_typePASS
    auth_pass 2222
    }
    virtual_ipaddress {
    192.168.0.133
    }
    track_script {
    chk_haproxy
    }
    }
    23.8.7 测试Haproxy+Keepalived服务
    手动kill掉131的haproxy进程后,130的keepalived后台日志显示如下,并且访问133 VIP正常访问,提供服务,则证明Haproxy+keepalived高可用架构配置完毕,如图23-4(a)、23-4(b)、23-24(c)、23-24(d)所示:
    图23-4(a) Haproxy+Keepalived网站架构
    图23-4(b) Haproxy+Keepalived网站架构
    图23-4(c) Haproxy+Keepalived网站架构
    图23-4(d) Haproxy+Keepalived网站架构
    23.9 LVS+Keepalived高可用集群实战
    LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统。本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。LVS 简单工作原理:用户请求LVS VIP,LVS根据转发方式和算法,将请求转发给后端服务器,后端服务器接受到请求,返回给用户。对于用户来说,看不到WEB后端具体的应用。
    23.9.1 LVS负载均衡简介
    互联网主流可伸缩网络服务有很多结构,但是都一个共同的点,它们都需要一个前端的负载调度器(或者多个进行主从备份)。实现虚拟网络服务的主要技术指出IP负载均衡技术是在负载调度器的实现技术中效率最高的。
    已有的IP负载均衡技术中,主要有通过网络地址转换(Network Address Translation)将一组服务器构成一个高性能的、高可用的虚拟服务器,我们称之为VS/NAT技术(Virtual Server via Network Address Translation)。
    在分析VS/NAT的缺点和网络服务的非对称性的基础上,可以通过IP隧道实现虚拟服务器的方法VS/TUN (Virtual Server via IP Tunneling),和通过直接路由实现虚拟服务器的方法VS/DR(Virtual Server via Direct Routing),它们可以极大地提高系统的伸缩性。
    总体来说IP负载均衡技术分为:VS/NAT、VS/TUN和VS/DR技术是LVS集群中实现的三种IP负载均衡技术。
    23.9.2 LVS负载均衡工作原理
    实现LVS负载均衡转发方式有三种,分别为NAT、DR、TUN模式,LVS均衡算法包括:RR(round-robin)、LC(least_connection)、W(weight)RR、WLC模式等(RR为轮询模式,LC为最少连接模式)。
    LVS NAT原理:用户请求LVS到达director,director将请求的报文的目标IP地址改成后端的realserver IP地址,同时将报文的目标端口也改成后端选定的realserver相应端口,最后将报文发送到realserver,realserver将数据返给director,director再把数据发送给用户。(两次请求都经过director,所以访问大的话,director会成为瓶颈),如图23-5所示:
    图23-5 LVS NAT原理详解图
    LVS DR原理:用户请求LVS到达director,director将请求的报文的目标MAC地址改成后端的realserver MAC地址,目标IP为VIP(不变),源IP为用户IP地址(保持不变),然后Director将报文发送到realserver,realserver检测到目标为自己本地VIP,如果在同一个网段,然后将请求直接返给用户。如果用户跟realserver不在一个网段,则通过网关返回用户,如图23-6所示:
    图23-6 LVS DR原理详解图
    LVS TUN原理:用户请求LVS到达director,director通过IP-TUN加密技术将请求的报文的目标MAC地址改成后端的realserver MAC地址,目标IP为VIP(不变),源IP为用户IP地址(保持不变),然后Director将报文发送到realserver,realserver基于IP-TUN解密,然后检测到目标为自己本地VIP,如果在同一个网段,然后将请求直接返给用户。如果用户跟realserver不在一个网段,则通过网关返回用户。如图23-7所示:
    图23-7 LVS TUN原理详解图
    23.9.3 LVS负载均衡实战配置
    LVS负载均衡技术实现是基于Linux内核模块IPVS,与iptables一样是直接工作在内核中,互联网主流的Linux发行版默认都已经集成了ipvs模块,因此只需安装管理工具ipvsadm,所需软件ipvsadm-1.2.4.tar.gz软件,安装配置步骤如下:
    (1)Ipvsadm编译安装方法如下:
    wget -c
    http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz
    ln -s /usr/src/kernels/2.6.* /usr/src/linux
    tar xzvf ipvsadm-1.24.tar.gz
    cd ipvsadm-1.24 
    make
    make install
    (2)Ipvsadm软件安装完毕后,需要进行配置,主要配置方法有三步:添加虚拟服务器IP,添加realserver后端服务及启动LVS服务器VIP地址,配置代码如下:
    ipvsadm -A -t 192.168.33.188:80 -s rr
    ipvsadm -a -t 192.168.33.188:80 -r 192.168.33.12 -g -w 2
    ipvsadm -a -t 192.168.33.188:80 -r 192.168.33.13 -g -w 2
    (3)可以使用Shell脚本自动部署LVS相关软件及配置:

    !/bin/bash

SNS_VIP=$2
SNS_RIP1=$3
SNS_RIP2=$4
if [ "$1" == "stop" -a -z "$2" ];then
echo "------------------------------------------"
echo -e "\033[32mPlease Enter $0 stop LVS_VIP\n\nEXample:$0 stop 192.168.1.111\033[0m"
echo
exit
else
if [ -z "$2" -a -z "$3" -a -z "$4" ];then
echo "----------------------------------------"
echo -e "\033[32mPlease Enter Input $0 start VIP REALSERVER1 REALSERVER2\n\nEXample:$0 start/stop 192.168.1.111 192.168.1.2 192.168.1.3\033[0m"
echo
exit 0
fi
fi
. /etc/rc.d/init.d/functions
logger $0 called with $1
function IPVSADM(){
/sbin/ipvsadm --set 30 5 60
/sbin/ifconfig eth0:0 $SNS_VIP broadcast $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP up
/sbin/route add -host $SNS_VIP dev eth0:0
/sbin/ipvsadm -A -t $SNS_VIP:80 -s wlc -p 120
/sbin/ipvsadm -a -t $SNS_VIP:80 -r $SNS_RIP1:80 -g -w 1
/sbin/ipvsadm -a -t $SNS_VIP:80 -r $SNS_RIP2:80 -g -w 1
}
case "$1" in
start)
IPVSADM
echo "-----------------------------------------------------"
/sbin/ipvsadm -Ln
touch /var/lock/subsys/ipvsadm > /dev/null 2>&1
;;
stop)
/sbin/ipvsadm -C
/sbin/ipvsadm -Z
ifconfig eth0:0 down >>/dev/null 2>&1
route del $SNS_VIP >>/dev/null 2>&1
rm -rf /var/lock/subsys/ipvsadm > /dev/null 2>&1
echo "ipvsadm stopped!"
;;
status)
if [ ! -e /var/lock/subsys/ipvsadm ]
then
echo "ipvsadm stopped!"
exit 1
else
echo "ipvsadm started!"
fi
;;
*)
echo "Usage: $0 {start | stop | status}"
exit 1
esac
exit 0
(4)LVS服务器绑定VIP地址,命令如下:
VIP=192.168.111.190
ifconfig eth0:0 $VIP netmask 255.255.255.255 broadcast $VIP
/sbin/route add -host $VIP dev eth0:0
(5)LVS ipvsadm配置参数说明:
-A 增加一台虚拟服务器VIP地址;
-t 虚拟服务器提供的是tcp服务;
-s 使用的调度算法;
-a 在虚拟服务器中增加一台后端真实服务器;
-r 指定真实服务器地址;
-w 后端真实服务器的权重;
-m 设置当前转发方式为NAT模式;-g为直接路由模式;-i 模式为隧道模式。
(6)查看LVS转发列表命令为:ipvsadm –Ln,如图23-8所示:
图23-8 LVS ipvsadm查看链接状态
(7) Nginx客户端realserver配置VIP脚本:

!/bin/sh

LVS Client Server

VIP=192.168.33.188
case $1 in
start)
ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP
/sbin/route add -host $VIP dev lo:0
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
sysctl -p >/dev/null 2>&1
echo "RealServer Start OK"
exit 0
;;
stop)
ifconfig lo:0 down
route del $VIP >/dev/null 2>&1
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "RealServer Stoped OK"
exit 1
;;
*)
echo "Usage: $0 {start|stop}"
;;
esac
如果单台LVS发生突发情况,例如宕机、发生不可恢复现象,会导致用户无法访问后端所有的应用程序。避免这种问题可以使用HA故障切换,也就是有一台备用的LVS,主LVS 宕机,LVS VIP自动切换到从,可以基于LVS+Keepalived实现负载均衡及高可用功能,满足网站7x24小时稳定高效的运行。
Keepalived基于三层检测(IP层,TCP层,及应用层),主要用于检测WEB服务器的状态,如果有一台WEB服务器死机,或工作出现故障,Keepalived检测到并将有故障的WEB服务器从系统中剔除;
当后端一台WEB服务器工作正常后Keepalived自动将WEB服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的WEB服务器。
需要注意,如果使用了keepalived.conf配置,就不需要再执行ipvsadm -A命令去添加均衡的realserver命令了,所有的配置都在keepalived.conf里面设置即可。
23.9.4 LVS+keepalived实战配置
LVS+Keepalived负载均衡高可用集群架构适用于千万级并发网站,在互联网企业得到大力的应用,如下为完整LVS+Keepalived企业级配置方法和步骤:
(1)Ipvsadm编译安装方法如下:
wget -c
http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz
ln -s /usr/src/kernels/2.6.* /usr/src/linux
tar xzvf ipvsadm-1.24.tar.gz
cd ipvsadm-1.24 
make
make install
(2)Keepalived安装配置:
cd /usr/src
wget -c http://www.keepalived.org/software/keepalived-1.1.15.tar.gz
tar -xzvf keepalived-1.1.15.tar.gz
cd keepalived-1.1.15
./configure
make && make install
DIR=/usr/local/
cp $DIR/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp $DIR/etc/sysconfig/keepalived /etc/sysconfig/
mkdir -p /etc/keepalived
cp $DIR/sbin/keepalived /usr/sbin/
(3)Master上keepalived.conf配置代码:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}

VIP1

vrrp_instance VI_1 {
state MASTER
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 51
priority 100
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
}
virtual_server 192.168.33.188 80 {
delay_loop 6
lb_algo wrr
lb_kind DR
persistence_timeout 60
protocol TCP
real_server 192.168.33.12 80 {
weight 100
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.33.13 80 {
weight 100
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
(4)Backup上keepalived.conf配置代码:
! Configuration File for keepalived
global_defs {
notification_email {
wgkgood@163.com
}
notification_email_from wgkgood@163.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}

VIP1

vrrp_instance VI_1 {
state BACKUP
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 51
priority 90
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.33.188
}
}
virtual_server 192.168.33.188 80 {
delay_loop 6
lb_algo wrr
lb_kind DR
persistence_timeout 60
protocol TCP
real_server 192.168.33.12 80 {
weight 100
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.33.13 80 {
weight 100
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
Master Keepalived配置state状态为MASTER,Priority设置100,Backup Keepalived配置state状态为BACKUP,Priority设置90,转发方式为DR直连路由模式,算采用wrr模式,在LVS BACKUP服务器写入如下配置,需要注意的是客户端的配置要修改优先级及状态:
LVS+keepalived负载均衡主备配置完毕,由于LVS采用DR模式,根据DR模式转发原理,需在客户端realserver绑定VIP。
23.9.5 LVS DR客户端配置VIP
客户通过浏览器访问director的VIP,director接收请求,将通过相应的转发方式及算法将请求转发给相应的realserver。在转发的过程中,会修改请求包的目的mac地址,目的IP地址不变。Realserver接收请求,并直接响应客户端。
Director与realserver位于同一个物理网络中,当director直接将请求转发给realserver时,如果realserver检测到该请求包目的IP是VIP而并非自己,便会丢弃,而不会响应。
为了解决这个问题,需在所有Realserver上都配上VIP,保证数据包不丢弃,同时由于后端realserver都配置VIP会导致IP冲突,所以需将VIP配置在lo网卡上,这样限制了VIP不会在物理交换机上产生MAC地址表,从而避免IP冲突。 LVS DR客户端启动Realserver.sh脚本内容如下:

!/bin/sh

LVS Client Server

VIP=192.168.33.188
case $1 in
start)
ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP
/sbin/route add -host $VIP dev lo:0
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
sysctl -p >/dev/null 2>&1
echo "RealServer Start OK"
exit 0
;;
stop)
ifconfig lo:0 down
route del $VIP >/dev/null 2>&1
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "RealServer Stoped OK"
exit 1
;;
*)
echo "Usage: $0 {start|stop}"
;;
esac
23.9.6 LVS负载均衡企业实战排错经验
LVS在企业生产环境中如何去排错呢,遇到问题我们该怎么办呢?LVS使用过程中,会遇到很多问题,如下为LVS故障排错思路。
企业网站LVS+Keepalived+Nginx架构中,突然发现网站www.jfedu.net 部分用户访问巨慢,甚至无法访问,这个问题我们该如何定位呢?
1)客户端ping www.jfedu.net ,通过ping返回域名对应的IP是否正常;
2)如果无法返回IP,或者响应比较慢,定位DNS或者网络延迟问题,可以通过tracert www.jfedu.net测试客户端本机到服务器的链路延迟;
3)登录LVS服务器,ipvsadm -Ln 查看当前后端web连接信息,显示如下:
[root@LVS-Master keepalived]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.1.10:80 wlc
-> 192.168.1.6:80 Route 100 2 13
-> 192.168.1.5:80 Route 100 120 13
-> 192.168.1.4:80 Route 100 1363 45
通过LVS ipvsadm信息,看到LVS 选择的轮训方式为加权最少连接,而网站也是部分无法访问,猜测是其中一台WEB服务器无法访问或者访问巨慢导致,如果单台WEB异常,为什么LVS+keepalived不能将异常的WEB服务器IP异常均衡列表呢?
查看keepalived.conf负载均衡健康检查配置,部分截图如下:
real_server 192.168.1.4 80 {
weight 100
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
通过配置文件发现LVS默认用的是TCP检测方式,只要80端口能通,请求就会被转发到后端服务器。紧接着在LVS服务器使用wget http://192.168.1.4/ 返回很慢,直至超时,而另外几台Nginx realserver返回正常,查看Nginx 192.168.1.4服务器80端口服务正常启动,所以对于LVS服务器来说是打开的,所以LVS会把请求转发给给它。
为什么部分用户可以访问,有的用户无法访问呢,发现192.168.1.4服务器ifconfig查看IP,但是没有看到VIP地址绑定在lo:0网卡上,经排错由于该服务器被重启,realserver脚本配置VIP异常,启动realserver脚本,网站恢复正常。
为了防止以上突发问题,增加LVS对后端Nginx URL的检测,能访问URL则表示服务正常。 对比之前的检测方式,从单纯的80端口到现在的URL检测,后端如果某台出现502超时错误,keepalived列表会自动踢出异常的realserver,等待后端realserver恢复后自动添加到服务器正常列表。Keepalived基于URL检查代码如下:
real_server 192.168.1.4 80 {
weight 100
HTTP_GET {
url {
path /monitor/warn.jsp
status_code 200
}
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
}
}

第24章 Kubernetes+Etcd分布式集群部署

24.1 Kubernetes必备组件
Kubernetes集群中主要存在两种类型的节点:master、minion节点,Minion节点为运行 Docker容器的节点,负责和节点上运行的 Docker 进行交互,并且提供了代理功能。
Master节点负责对外提供一系列管理集群的API接口,并且通过和 Minion 节点交互来实现对集群的操作管理。
Apiserver:用户和 kubernetes 集群交互的入口,封装了核心对象的增删改查操作,提供了 RESTFul 风格的 API 接口,通过etcd来实现持久化并维护对象的一致性。
scheduler:负责集群资源的调度和管理,例如当有 pod 异常退出需要重新分配机器时,scheduler 通过一定的调度算法从而找到最合适的节点。
controller-manager:主要是用于保证 replication Controller 定义的复制数量和实际运行的 pod 数量一致,另外还保证了从 service 到 pod 的映射关系总是最新的。
kubelet:运行在 minion节点,负责和节点上的Docker交互,例如启停容器,监控运行状态等。
proxy:运行在 minion 节点,负责为 pod 提供代理功能,会定期从 etcd 获取 service 信息,并根据 service 信息通过修改 iptables 来实现流量转发(最初的版本是直接通过程序提供转发功能,效率较低。),将流量转发到要访问的 pod 所在的节点上去。
etcd:key-value键值存储数据库,用来存储kubernetes的信息的。
flannel:Flannel是CoreOS 团队针对 Kubernetes 设计的一个覆盖网络(Overlay Network)工具,Flannel 目的就是为集群中的所有节点重新规划 IP 地址的使用规则,从而使得不同节点上的容器能够获得同属一个内网且不重复的 IP 地址,并让属于不同节点上的容器能够直接通过内网 IP 通信。

24.2 kubernetes环境部署
Kubernetes Master节点:192.168.1.120
Kubernetes Node1节点:192.168.1.121
Kubernetes Node2节点:192.168.1.122
Docker私有库节点:192.168.1.123
每台主机上都运行如下命令:
systemctl stop firewalld
systemctl disable firewalld
yum -y install ntp
systemctl start ntpd
systemctl enable ntpd
24.3 Kubernetes Master安装与配置
Kubernetes Master节点上安装etcd和Kubernetes
yum install kubernetes-master etcd -y
Master /etc/etcd/etcd.conf配置文件,代码如下:

[member]

ETCD_NAME=etcd1
ETCD_DATA_DIR="/var/lib/etcd/etcd1.etcd"

ETCD_WAL_DIR=""

ETCD_SNAPSHOT_COUNT="10000"

ETCD_HEARTBEAT_INTERVAL="100"

ETCD_ELECTION_TIMEOUT="1000"

ETCD_LISTEN_PEER_URLS="http://192.168.1.120:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.1.120:2379,http://127.0.0.1:2379"
CD_MAX_SNAPSHOTS="5"

ETCD_MAX_WALS="5"

ETCD_CORS=""

[cluster]

ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.120:2380"

if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."

ETCD_INITIAL_CLUSTER="etcd1=http://192.168.1.120:2380,etcd2=http://192.168.1.121:2380,etcd3=http://192.168.1.122:2380"

ETCD_INITIAL_CLUSTER_STATE="new"

ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"

ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.120:2379"

ETCD_DISCOVERY=""

ETCD_DISCOVERY_SRV=""

ETCD_DISCOVERY_FALLBACK="proxy"

ETCD_DISCOVERY_PROXY=""

[proxy]

ETCD_PROXY="off"

ETCD_PROXY_FAILURE_WAIT="5000"

ETCD_PROXY_REFRESH_INTERVAL="30000"

ETCD_PROXY_DIAL_TIMEOUT="1000"

ETCD_PROXY_WRITE_TIMEOUT="5000"

ETCD_PROXY_READ_TIMEOUT="0"

[security]

ETCD_CERT_FILE=""

ETCD_KEY_FILE=""

ETCD_CLIENT_CERT_AUTH="false"

ETCD_TRUSTED_CA_FILE=""

ETCD_PEER_CERT_FILE=""

ETCD_PEER_KEY_FILE=""

ETCD_PEER_CLIENT_CERT_AUTH="false"

ETCD_PEER_TRUSTED_CA_FILE=""

[logging]

ETCD_DEBUG="false"

examples for -log-package-levels etcdserver=WARNING,security=DEBUG

ETCD_LOG_PACKAGE_LEVELS=""

启动etcd服务,执行命令:systemctl restart etcd.service

Master /etc/kubernetes/config配置文件,代码如下:

kubernetes system config

The following values are used to configure various aspects of all

kubernetes i, including

kube-apiserver.service

kube-controller-manager.service

kube-scheduler.service

kubelet.service

kube-proxy.service

logging to stderr means we get it in the systemd journal

KUBE_LOGTOSTDERR="--logtostderr=true"

journal message level, 0 is debug

KUBE_LOG_LEVEL="--v=0"

Should this cluster be allowed to run privileged docker containers

KUBE_ALLOW_PRIV="--allow-privileged=false"

How the controller-manager, scheduler, and proxy find the apiserver

KUBE_MASTER="--master=http://192.168.1.120:8080"
将Kubernetes的apiserver进程的服务地址告诉Kubernetes的controller-manager, scheduler,proxy进程。
Master /etc/kubernetes/apiserver配置文件,代码如下:

kubernetes system config

The following values are used to configure the kube-apiserver

The address on the local server to listen to.

KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"

The port on the local server to listen on.

KUBE_API_PORT="--port=8080"

Port minions listen on

KUBELET_PORT="--kubelet-port=10250"

Comma separated list of nodes in the etcd cluster

KUBE_ETCD_SERVERS="--etcd-servers=http://192.168.1.120:2379,http://192.168.1.121:2379,http://192.168.1.122:2379"

Address range to use for i

KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"

default admission control policies

KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"

KUBE_ADMISSION_CONTROL="--admission_control=NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota"

Add your own!

KUBE_API_ARGS=""
启动Kubernetes Master节点上的etcd, apiserver, controller-manager和scheduler进程及状态:
for I in etcd kube-apiserver kube-controller-manager kube-scheduler; do
systemctl restart $I
systemctl enable $I
systemctl status $I
done
24.4 Kubernetes Node1安装配置
在Kubernetes Node1节点上安装flannel、docker和Kubernetes
yum install kubernetes-node etcd flannel -y
编辑node1 /etc/etcd/etcd.conf配置flannel,内容如下:
##########

[member]

ETCD_NAME=etcd2
ETCD_DATA_DIR="/data/etcd"

ETCD_WAL_DIR=""

ETCD_SNAPSHOT_COUNT="10000"

ETCD_HEARTBEAT_INTERVAL="100"

ETCD_ELECTION_TIMEOUT="1000"

ETCD_LISTEN_PEER_URLS="http://192.168.1.121:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.1.121:2379,http://127.0.0.1:2379"
CD_MAX_SNAPSHOTS="5"

ETCD_MAX_WALS="5"

ETCD_CORS=""

[cluster]

ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.121:2380"

if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."

ETCD_INITIAL_CLUSTER="etcd1=http://192.168.1.120:2380,etcd2=http://192.168.1.121:2380,etcd3=http://192.168.1.122:2380"

ETCD_INITIAL_CLUSTER_STATE="new"

ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"

ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.121:2379"

ETCD_DISCOVERY=""

ETCD_DISCOVERY_SRV=""

ETCD_DISCOVERY_FALLBACK="proxy"

ETCD_DISCOVERY_PROXY=""

[proxy]

ETCD_PROXY="off"

ETCD_PROXY_FAILURE_WAIT="5000"

ETCD_PROXY_REFRESH_INTERVAL="30000"

ETCD_PROXY_DIAL_TIMEOUT="1000"

ETCD_PROXY_WRITE_TIMEOUT="5000"

ETCD_PROXY_READ_TIMEOUT="0"

[security]

ETCD_CERT_FILE=""

ETCD_KEY_FILE=""

ETCD_CLIENT_CERT_AUTH="false"

ETCD_TRUSTED_CA_FILE=""

ETCD_PEER_CERT_FILE=""

ETCD_PEER_KEY_FILE=""

ETCD_PEER_CLIENT_CERT_AUTH="false"

ETCD_PEER_TRUSTED_CA_FILE=""

[logging]

ETCD_DEBUG="false"

examples for -log-package-levels etcdserver=WARNING,security=DEBUG

ETCD_LOG_PACKAGE_LEVELS=""

配置信息告诉flannel进程etcd服务的位置以及在etcd上网络配置信息的节点位置,对Node节点上的Kubernetes进行配置,编辑配置文件/etc/kubernetes/config,代码如下:

kubernetes system config

The following values are used to configure various aspects of all

kubernetes services, including

kube-apiserver.service

kube-controller-manager.service

kube-scheduler.service

kubelet.service

kube-proxy.service

logging to stderr means we get it in the systemd journal

KUBE_LOGTOSTDERR="--logtostderr=true"

journal message level, 0 is debug

KUBE_LOG_LEVEL="--v=0"

Should this cluster be allowed to run privileged docker containers

KUBE_ALLOW_PRIV="--allow-privileged=false"

How the controller-manager, scheduler, and proxy find the apiserver

KUBE_MASTER="--master=http://192.168.1.120:8080"
配置文件/etc/kubernetes/kubelet,代码如下:

kubernetes kubelet (minion) config

The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces)

KUBELET_ADDRESS="--address=0.0.0.0"

The port for the info server to serve on

KUBELET_PORT="--port=10250"

You may leave this blank to use the actual hostname

KUBELET_HOSTNAME="--hostname-override=192.168.1.121"

location of the api-server

KUBELET_API_SERVER="--api-servers=http://192.168.1.120:8080"

pod infrastructure container

KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=192.168.1.123:5000/centos68"

KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

Add your own!

KUBELET_ARGS=""
分别启动Kubernetes Node节点上kube-proxy、kubelet、docker、flanneld进程并查看其状态:
for I in kube-proxy kubelet docker flanneld
do
systemctl restart $I
systemctl enable $I
systemctl status $I
done
24.5 Kubernetes Node2安装配置
在Kubernetes Node2节点上安装flannel、docker和Kubernetes
yum -y install flannel docker kubernetes
编辑node1 /etc/etcd/etcd.conf配置flannel,内容如下:
##########

[member]

ETCD_NAME=etcd3
ETCD_DATA_DIR="/data/etcd"

ETCD_WAL_DIR=""

ETCD_SNAPSHOT_COUNT="10000"

ETCD_HEARTBEAT_INTERVAL="100"

ETCD_ELECTION_TIMEOUT="1000"

ETCD_LISTEN_PEER_URLS="http://192.168.1.122:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.1.122:2379,http://127.0.0.1:2379"
CD_MAX_SNAPSHOTS="5"

ETCD_MAX_WALS="5"

ETCD_CORS=""

[cluster]

ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.121:2380"

if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."

ETCD_INITIAL_CLUSTER="etcd1=http://192.168.1.120:2380,etcd2=http://192.168.1.121:2380,etcd3=http://192.168.1.122:2380"

ETCD_INITIAL_CLUSTER_STATE="new"

ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"

ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.122:2379"

ETCD_DISCOVERY=""

ETCD_DISCOVERY_SRV=""

ETCD_DISCOVERY_FALLBACK="proxy"

ETCD_DISCOVERY_PROXY=""

[proxy]

ETCD_PROXY="off"

ETCD_PROXY_FAILURE_WAIT="5000"

ETCD_PROXY_REFRESH_INTERVAL="30000"

ETCD_PROXY_DIAL_TIMEOUT="1000"

ETCD_PROXY_WRITE_TIMEOUT="5000"

ETCD_PROXY_READ_TIMEOUT="0"

[security]

ETCD_CERT_FILE=""

ETCD_KEY_FILE=""

ETCD_CLIENT_CERT_AUTH="false"

ETCD_TRUSTED_CA_FILE=""

ETCD_PEER_CERT_FILE=""

ETCD_PEER_KEY_FILE=""

ETCD_PEER_CLIENT_CERT_AUTH="false"

ETCD_PEER_TRUSTED_CA_FILE=""

[logging]

ETCD_DEBUG="false"

examples for -log-package-levels etcdserver=WARNING,security=DEBUG

ETCD_LOG_PACKAGE_LEVELS=""

配置信息告诉flannel进程etcd服务的位置以及在etcd上网络配置信息的节点位置,对Node节点上的Kubernetes进行配置,编辑配置文件/etc/kubernetes/config,代码如下:

kubernetes system config

The following values are used to configure various aspects of all

kubernetes services, including

kube-apiserver.service

kube-controller-manager.service

kube-scheduler.service

kubelet.service

kube-proxy.service

logging to stderr means we get it in the systemd journal

KUBE_LOGTOSTDERR="--logtostderr=true"

journal message level, 0 is debug

KUBE_LOG_LEVEL="--v=0"

Should this cluster be allowed to run privileged docker containers

KUBE_ALLOW_PRIV="--allow-privileged=false"

How the controller-manager, scheduler, and proxy find the apiserver

KUBE_MASTER="--master=http://192.168.1.120:8080"
配置文件/etc/kubernetes/kubelet,代码如下:

kubernetes kubelet (minion) config

The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces)

KUBELET_ADDRESS="--address=0.0.0.0"

The port for the info server to serve on

KUBELET_PORT="--port=10250"

You may leave this blank to use the actual hostname

KUBELET_HOSTNAME="--hostname-override=192.168.1.122"

location of the api-server

KUBELET_API_SERVER="--api-servers=http://192.168.1.120:8080"

pod infrastructure container

KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=192.168.1.123:5000/centos68"

KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

Add your own!

KUBELET_ARGS=""
分别启动Kubernetes Node节点上kube-proxy、kubelet、docker、flanneld进程并查看其状态:
for I in kube-proxy kubelet docker flanneld
do
systemctl restart $I
systemctl enable $I
systemctl status $I
done
Master节点上使用kubectl get nodes命令,可以看到加入的kubernetes集群的两个Node节点:
kubectl get nodes

至此,Kubernetes集群环境搭建完毕。
24.1 Kubernetes flanneld网络配置
vi /etc/sysconfig/flanneld代码如下:

Flanneld configuration options

etcd url location. Point this to the server where etcd runs

FLANNEL_ETCD_ENDPOINTS="http://192.168.1.120:2379"

etcd config key. This is the configuration key that flannel queries

For address range assignment

FLANNEL_ETCD_PREFIX="/atomic.io/network"

Any additional options that you want to pass

FLANNEL_OPTIONS=""

etcd配置中心创建flannel网络配置:
etcdctl rm /atomic.io/network/ --recursive
etcdctl mk /atomic.io/network/config '{"Network":"172.17.0.0/16"}'
Kubernetes的Node节点搭建和配置flannel网络,etcd中/atomic.io/network/config节点会被Node节点上的flannel用来创建Doker IP地址网段;
查看etcd配置中心网段:
etcdctl ls /atomic.io/network/subnets
24.2 Kubernetes Pods配置
构建完Kubernetes集群环境,接下来创建Pods,用kubectl describe和kubectl logs命令定位原因,发现原因是无法从gcr.io(Google Container-Registry)拉取镜像,可以改成其他可访问的地址,也可以创建Docker私有镜像。

24.3 Kubernetes Web UI配置
创建kube-namespace.yaml,代码如下:
{
"kind": "Namespace",
"apiVersion": "v1",
"metadata": {
"name": "kube-system"
}
}
使用命令:kubectl get namespace查看命名空间。
创建kubernetes-dashboard.yaml,代码如下:

Copyright 2017 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

Configuration to deploy release version of the Dashboard UI.

Example usage: kubectl create -f

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
labels:
app: kubernetes-dashboard
version: latest
name: kubernetes-dashboard
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: kubernetes-dashboard
template:
metadata:
labels:
app: kubernetes-dashboard
spec:
containers:

  • name: kubernetes-dashboard
    image: docker.io/k8scn/kubernetes-dashboard-amd64
    imagePullPolicy: Always
    ports:
    • containerPort: 9090
      protocol: TCP
      args:

      Uncomment the following line to manually specify Kubernetes API server Host

      If not specified, Dashboard will attempt to auto discover the API server and connect

      to it. Uncomment only if the default does not work.

      • --apiserver-host=192.168.169.120:8080
        livenessProbe:
        httpGet:
        path: /
        port: 9090
        initialDelaySeconds: 30
        timeoutSeconds: 30

        kind: Service
        apiVersion: v1
        metadata:
        labels:
        app: kubernetes-dashboard
        name: kubernetes-dashboard
        namespace: kube-system
        spec:
        type: NodePort
        ports:

  • port: 80
    targetPort: 9090
    selector:
    app: kubernetes-dashboard
    创建dashboard pods模块:
    kubectl create -f kubernetes-dashboard.yaml
    创建完成后,查看Pods和Service的详细信息:
    kubectl get pods --all-namespaces
    kubectl describe service/kubernetes-dashboard --namespace="kube-system"
    kubectl describe pod/kubernetes-dashboard-530803917-816df --namespace="kube-system"
    通过浏览器访问该端口就能看到Kubernetes的Web UI:

Nginx WEB pods配置代码:
Pod {5}
kind : Pod
apiVersion : v1
metadata {10}
name : nginx-web1-1187963248-3z862
generateName : nginx-web1-1187963248-
namespace : kube-system
selfLink : /api/v1/namespaces/kube-system/pods/nginx-web1-1187963248-3z862
uid : c2ad1b54-5253-11e7-91ba-000c291c9220
resourceVersion : 156010
creationTimestamp : 2017-06-16T05:22:15Z
labels {2}
app : nginx-web1
pod-template-hash : 1187963248
annotations {1}
kubernetes.io/created-by : {\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicaSet\",\"namespace\":\"kube-system\",\"name\":\"nginx-web1-1187963248\",\"uid\":\"647c4dd7-5253-11e7-91ba-000c291c9220\",\"apiVersion\":\"extensions\",\"resourceVersion\":\"154018\"}}\n
ownerReferences 1
0 {5}
apiVersion : extensions/v1beta1
kind : ReplicaSet
name : nginx-web1-1187963248
uid : 647c4dd7-5253-11e7-91ba-000c291c9220
controller : true
spec {6}
containers 1
0 {6}
name : nginx-web1
image : nginx
resources {0}
(empty object)
terminationMessagePath : /dev/termination-log
imagePullPolicy : Always
securityContext {1}
privileged : false
restartPolicy : Always
terminationGracePeriodSeconds : 30
dnsPolicy : ClusterFirst
nodeName : 192.168.1.122
securityContext {0}
(empty object)
status {6}
phase : Running
conditions [3]
0 {4}
type : Initialized
status : True
lastProbeTime : null
lastTransitionTime : 2017-06-16T05:22:16Z
1 {4}
type : Ready
status : True
lastProbeTime : null
lastTransitionTime : 2017-06-16T05:41:14Z
2 {4}
type : PodScheduled
status : True
lastProbeTime : null
lastTransitionTime : 2017-06-16T05:22:16Z
hostIP : 192.168.1.122
podIP : 10.1.24.5
startTime : 2017-06-16T05:22:16Z
containerStatuses 1
0 {8}
name : nginx-web1
state {1}
running {1}
startedAt : 2017-06-16T05:41:12Z
lastState {0}
(empty object)
ready : true
restartCount : 0
image : nginx
imageID : docker-pullable://docker.io/nginx@sha256:41ad9967ea448d7c2b203c699b429abe1ed5af331cd92533900c6d77490e0268
containerID : docker://42d347c4aadf38757ce6fc071c72650df4b503a9315d306063c03b7b11d91b4a

24.1 Kubernetes 本地私有仓库实战
Docker仓库主要用于存放Docker镜像,Docker仓库分为公共仓库和私有仓库,基于registry可以搭建本地私有仓库,使用私有仓库的优点如下:
节省网络带宽,针对于每个镜像不用去Docker官网仓库下载;
下载Docker镜像从本地私有仓库中下载;
组件公司内部私有仓库,方便各部门使用,服务器管理更加统一;
可以基于GIT或者SVN、Jenkins更新本地Docker私有仓库镜像版本。
官方提供Docker Registry来构建本地私有仓库,目前最新版本为v2,最新版的docker已不再支持v1,Registry v2使用Go语言编写,在性能和安全性上做了很多优化,重新设计了镜像的存储格式。如下为在192.168.1.123服务器上构建Docker本地私有仓库的方法及步骤:
(1)下载Docker registry镜像,命令如下:
docker pull registry
(2)启动私有仓库容器,启动命令如下:
mkdir -p /data/registry/
docker run -itd -p 5000:5000 -v /data/registry:/tmp/registry docker.io/registry
Docker本地仓库启动后台容器启动,如图24-2所示:

默认情况下,会将仓库存放于容器内的/tmp/registry目录下,这样如果容器被删除,则存放于容器中的镜像也会丢失,所以我们一般情况下会指定本地一个目录挂载到容器内的/tmp/registry下。
(3)上传镜像至本地私有仓库:
客户端上传镜像至本地私有仓库,如下以busybox镜像为例,将busybox上传至私有仓库服务器。
docker pull busybox
docker tag busybox 192.168.1.123:5000/busybox
docker push 192.168.1.123:5000/busybox
(4)检测本地私有仓库:
curl -XGET http://192.168.1.123:5000/v2/_catalog
curl -XGET http://192.168.1.123:5000/v2/busybox/tags/list
(5)客户端使用本地私有仓库:
客户端docker配置文件添加如下代码,同时重启docker服务,获取本地私有仓库如图24-3所示:
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false --insecure-registry 192.168.1.123:5000'
ADD_REGISTRY='--add-registry 192.168.1.123:5000'

至此,docker本地私有仓库部署完毕,可以向仓库中添加或者更新Docker镜像。
24.2 Kubernetes使用本地仓库
创建kube-namespace.yaml,代码如下(如果已创建,则无需创建)
{
"kind": "Namespace",
"apiVersion": "v1",
"metadata": {
"name": "kube-system"
}
}
创建kubernetes-dashboard.yaml,读取本地私有仓库,代码如下:

Copyright 2015 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

Configuration to deploy release version of the Dashboard UI.

Example usage: kubectl create -f

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
labels:
app: kubernetes-dashboard
version: latest
name: kubernetes-dashboard
namespace: kube-system
spec:
replicas: 2
selector:
matchLabels:
app: kubernetes-dashboard
template:
metadata:
labels:
app: kubernetes-dashboard
spec:
containers:

  • name: kubernetes-dashboard
    image: 192.168.1.123:5000/kubernetes-dashboard-amd64
    imagePullPolicy: Always
    ports:
    • containerPort: 9090
      protocol: TCP
      args:

      Uncomment the following line to manually specify Kubernetes API server Host

      If not specified, Dashboard will attempt to auto discover the API server and connect

      to it. Uncomment only if the default does not work.

      • --apiserver-host=192.168.1.120:8080
        livenessProbe:
        httpGet:
        path: /
        port: 9090
        initialDelaySeconds: 30
        timeoutSeconds: 30

        kind: Service
        apiVersion: v1
        metadata:
        labels:
        app: kubernetes-dashboard
        name: kubernetes-dashboard
        namespace: kube-system
        spec:
        type: NodePort
        ports:

  • port: 80
    targetPort: 9090
    selector:
    app: kubernetes-dashboard
    使用命令kubectl create -k kube-dashboard.yaml,创建dashboard,POD无法运行,后台日志报错如下:
    The push refers to a repository [192.168.1.123:5000/registry]
    Get https://192.168.1.123:5000/v1/_ping: http: server gave HTTP response to HTTPS client
    需要在Docker主机添加本地仓库地址,添加方法如下:
    (1)/etc/docker/daemon.json文件中代码如下:
    { "insecure-registries":["192.168.1.123:5000"] }
    (2)/etc/kubernetes/kubelet配置文件将KUBELET_POD_INFRA_CONTAINER选项注释,同时添加一个新的KUBELET_POD_INFRA_CONTAINER参数,代码如下,前提需要将pod-infrastructure镜像上传私有仓库。

    KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

    KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=192.168.1.123:5000/pod-infrastructure:latest"
    在每台nodes上重启kubelet服务:systemctl restart kubelet.service
    (3)Nodes上Docker配置文件/etc/sysconfig/docker中,添加如下代码,并重启Docker服务:
    ADD_REGISTRY='--add-registry 192.168.1.123:5000'
    通过WEB-UI创建镜像,则会从本地仓库中获取。
    查看kubernetes-dashboard创建信息如图所示:

Linux高级运维.docx

最后修改:2021 年 08 月 05 日
如果觉得我的文章对你有用,请随意赞赏