前言:本文記述了搭建一個小型web服務器集羣的過程,因爲篇幅所限,系統、軟件的安裝和基本配置我這裏就省略了,只記敘關鍵配置和腳本內容。假如各位朋友想了解各軟件詳細配置建議查閱官方文檔。php
一 需求分析:html
1.總體需求:搭建一個高可用的網站服務器集羣,能承受高併發請求,能抵禦通常的網絡攻擊,任何一臺服務器的退服不影響整個集羣的運做,而且能對各服務器的運行狀況做出實時監控。前端
2.詳細需求分析:node
根據需求,計劃根據如下拓撲搭建運行環境:python
二 詳細功能描述:mysql
1.前端服務器採用nginx實現反向代理和負載均衡,用keepalive實現HA。此部分由centos1和centos4實現,centos1做爲主服務器,centos4做爲熱備服務器。Nginx會根據不一樣的請求ip機會均等地把請求發送到後端兩臺服務器,而且以ip hash的方式保持各個ip的會話。ios
2.後端服務器構建在centos2與centos3上,採用apache做爲web發佈軟件,mysql做爲數據庫,測試網頁用Django來實現。兩臺服務器的數據庫可以自動同步。nginx
3.做爲熱備服務器,centos4在centos1沒有故障時並無業務流量,處於相對空閒的狀態,所以在centos4上配置nfs使它成爲文件共享服務器,網站文件放在這臺服務器上。web
4.centos5做爲監控服務器,運行nagios監控各服務器狀態。出現告警時經過告警通知管理員。另外centos5還做爲saltstack的服務器,其餘主機的軟件安裝、文件傳輸、命令運行等操做均經過saltstack批量實現。sql
三 整體部署描述:
1.各個服務器均安裝centos6.4 64位版本,採用cobbler實現批量自動安裝。
2.各個軟件均安裝最新的穩定版,centos自帶的軟件也要進行升級,例如python,Centos自帶的版本比較久,會影響Django的運行。
四 詳細部署描述:
1.nginx設置
Nginx在這裏的做用主要是反向代理、做爲用戶以及服務器之間的緩存、以及以負載均衡的方式把請求發送到後端兩臺服務器。
採用編譯安裝的方式安裝nginx,具體過程就不在此記述了,不過爲了更好地抵擋入侵,建議編譯前修改一下安裝文件,使入侵者難以查出nginx的版本號,修改安裝文件中的nginx.h,把相關字段修改以下:
#define NGINX_VERSION "1.0" #define NGINX_VER "webserver" NGINX_VERSION
Nginx的配置文件以下:
user www www; worker_processes 2; events { worker_connections 12800; use epoll; } http { include mime.types; #協助部分瀏覽器(如firefox)識別網頁文件的類型 default_type application/octet-stream; limit_conn_zone $binary_remote_addr zone=addr:10m; sendfile on;#指定nginx是否調用sendfile函數來輸出文件,能提升性能。 tcp_nopush on; tcp_nodelay on; keepalive_timeout 20; #客戶端鏈接保持活動的超時時間 send_timeout 20; #指定響應客戶端的超時時間 client_body_buffer_size 1k; #指定客戶端請求主體緩衝區大小 client_header_buffer_size 1k; #指定來自客戶端請求頭的headerbuffer大小 large_client_header_buffers 2 1k; #客戶端請求中較大的消息頭指定的緩存最大數量和大小 server_tokens off; #禁止在錯誤頁面上顯示nginx版本號 client_body_timeout 20; #設置客戶端請求主體讀取超時時間 client_header_timeout 20; #設置客戶端請求頭讀取超時時間 gzip on; upstream WebServers{ #指定負載均衡服務器 ip_hash; #以ip_hash的方式保持會話 server 10.0.0.3; #沒有設定權重,所以兩臺後端服務器將機會均等地接受請求 server 10.0.0.2; } server { listen 80; server_name localhost; location / { proxy_pass http://WebServers; limit_conn addr 100; #指定每一個ip最多隻容許創建100個鏈接 limit_rate 500k; #每一個ip最大帶寬是500k
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_404; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
由於後端測試網頁是用Django寫的,所以nginx就不用處理php等動態網頁的請求了。
設置完畢後,把nginx設置爲開機啓動,能夠用以下方式:
echo 「/usr/local/nginx/sbin/nginx」 >>/etc/rc.local
2.Keeplive設置
Keeplive的做用是在兩臺服務器(centos1、centos4)之間,以VRRP協議實現HA。經過虛擬出一個Virtul IP(本例子中是192.168.48.138)來對外發布業務。兩臺服務器中的任一臺退服了,keeplive會自動把業務轉到另外一臺上。在這裏centos1是主服務器,centos4是備用服務器。平時的數據流量只會經過centos1,只有centos1退服了,數據流量纔會割接到centos4上。
centos1上的keepalive配置:
! Configuration File for keepalived global_defs { notification_email { test@test.com #指定告警郵箱,當發現對端服務器退服時發郵件警報 } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_instance VI_1 { state MASTER interface eth0 #綁定網卡接口 virtual_router_id 51 mcast_src_ip 192.168.48.139 #設置本機經過哪一個ip發送vrrp包 priority 100 #設置優先級 advert_int 1 #檢查間隔,這裏設置爲1秒 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.48.138 } }
對於從服務器centos4,只須要把以上配置文件的部份內容修改便可:
state BACKUP mcast_src_ip 192.168.48.140 priority 90
一樣,配置好配置文件後,把keepalive添加到開機啓動中。
對於keepalive,因爲是使用VRRP協議來檢查對端是否在線的,只要對端能ping通,那麼keeplive就會認爲對端在線。但也有一種狀況是對端服務器沒有宕機,但nginx出錯關閉了,這種狀況下keepalive仍然會判斷對端在線,不會把業務割接到備用服務器。所以咱們須要在服務器上運行一個腳本,監控nginx進程的狀態。假如nginx進程關閉了,先嚐試重啓nginx,沒法重啓時就關閉keepalive的進程,使業務割接到備用端。腳本以下:
#!/bin/bash #nginxStatus.sh while : do nginxStatus=`ps -C nginx --no-header |wc -l` if ((nginxStatus==0));then /usr/local/nginx/sbin/nginx
sleep 5 nginxStatus=`ps -C nginx --no-header |wc -l` if ((nginxStatus==0));then /etc/init.d/keepalived stop fi else #當判斷到主服務器的nginx已經從新啓動後,再啓動keepalive,使業務倒置回主 #服務器 keepaliveStatus=`ps -C keepalived --no-header |wc -l` if ((keepaliveStatus==0));then /etc/init.d/keepalived start fi fi sleep 5 done
把這個腳本放在centos1上,設置開機後於後臺運行:
echo 「nohup ~/nginxStatus.sh &」>>/etc/rc.local
因爲腳本中的while會不斷循環下去來檢查進程運行狀況,所以不必添加進計劃任務。不過謹慎起見,防止腳本意外中止,也能夠在計劃任務中設置每30分鐘運行一次。
3.後端Web服務器設置
後端web服務器運行在centos2、centos3上,採用apache搭建,測試網頁使用Django編寫,網頁文件存放在共享文件服務器centos4上,分別掛載在本機的/var/www/html目錄。
用saltstack批量在兩臺服務器上安裝apache、apache-devel、wsgi、Django、mysql以及升級python,過程省略。
部署好運行環境後,修改一下apache的配置文件(http.conf),把運行用戶名和組名改成apache,根目錄指向/var/www/html
接下來設置mysql,把兩臺服務器的mysql設置互爲主從,使得其中一臺服務器的數據庫變動了,立刻同步到另外一臺,保證兩臺服務器的數據一致。設置步驟以下:
首先設置centos2
打開centos2上mysql的配置文件my.cnf,做以下修改:
[mysqld] log-bin=MySQL-bin #開啓二進制日誌,從服務器靠讀取主服務器的二進制日誌來執行同步 server-id=1 #設置爲1代表這是主服務器。 binlog-ignore-db=mysql binlog-ignore-db=information_schema # binlog-ignore-db用來指定忽略哪些數據庫記錄到二進制日誌,這樣在同步的時候就會忽略掉這些數據庫。其中「mysql」數據庫用於記錄用戶信息,「information_schema」用於記錄整個數據庫各個庫和表的信息。
而後以root身份登錄mysql,執行下面命令:
grant replication slave on *.* to ‘test’@’10.0.0.3’ identified ‘test123’;
這命令的含義是,在10.0.0.3機器上創建一個test用戶,用戶密碼爲test123,這個用戶擁有對centos2上全部數據庫的全部表同步到centos3(10.0.0.3)的權限。
而後執行:
show master status;
能夠看到如下信息:
記錄好這個信息,而後以root身份登錄centos3的mysql,執行下面的命令(有一點須要注意,假如同步以前須要同步的數據庫不是空的話,須要先在數據庫上加上讀鎖,把主服務器的相關數據庫導入到從數據庫中):
change master to master_host='10.0.0.2', master_user='test', master_password='test123', master_log_file='MySQL-bin.000070', master_log_pos=106;
上面的master_log_file和master_log_pos的信息就是以前centos2上執行show master status命令後所顯示的信息。執行show slave status;命令,查看一下centos3是否已經成功成爲從服務器:
能夠看到centos3的mysql已經成爲centos2(10.0.0.2)的從服務器了。至此centos3的mysql已經能主動同步centos2的數據了,咱們只須要把以上操做在centos3上操做一次(先修改my.cnf,其中server-id要設爲2,而後再執行建立用戶以及受權命令),就能實現兩個數據庫互爲主從,相互之間自動同步。
4.共享文件服務器nfs
本環節中,咱們須要把centos4配置成共享文件的服務器端,後端兩臺web服務器的網頁內容將放在共享文件服務器上,以此保證兩臺web服務器的網頁文件內容一致。
nfs在centos6.2上默認已安裝,咱們首先在centos4的/etc目錄下新建exports文件,加入如下內容:
/home/apache/html 10.0.0.2(rw,sync) #sync是指數據同時寫入緩存和硬盤中,執行較慢但保證數據精確 /home/apache/html 10.0.0.3(rw,sync)
而後在centos4上一步步執行下面的命令:
groupadd apache useradd -g apache -s /sbin/nologin apache passwd apache mkdir -p /home/apache/html #把網頁文件複製到/home/apache/html,而後再執行下面命令: chown -R apache:apache /home/apache/html chmod -R 700 /home/apache/html chkconfig --level 35 nfs on service nfs start
關於共享目錄的權限設置,因爲後端兩臺web服務器的apache都是以apache:apache這個用戶來執行的,文件的讀寫也是經過這個用戶,所以爲保證數據安全,共享目錄只開放權限給這個用戶便可,其餘用戶一概什麼權限都不給予。另外還要把共享文件夾的所屬者設爲apache:apache這個用戶。
接下來到centos2、centos3兩臺web服務器上做以下設置,使它們開機時自動加載共享目錄:
echo "mount -t nfs 10.0.0.4:/home/apache/html /var/www/html -o hard,bg,nfsvers=3 ">>/etc/rc.local
上面選項中hard表示網絡短暫中斷時會繼續嘗試鏈接服務器,而且不會顯示錯誤信息;
bg表示執行mount時若是沒法順利mount上時,系統會將mount的操做轉移到後臺並繼續嘗試mount,直到mount成功爲止;
nfsvers=3表示採用第3版的nfs。
5.nagios設置
監控軟件安裝在centos5上,負責監控其餘4臺服務器的狀況,出現異常時發出郵件給管理員進行警報。
安裝過程:須要在centos5上安裝nagios、nagios插件包、nrpe、apache(用於搭建監控網頁)、pnp(用於生成監控數據的分析圖表)。4臺被監控的主機須要安裝nagios插件包以及nrpe,詳細安裝過程這裏省略。
如下項目是對於4臺服務器都須要監控的:
1.Check Swap:監控交換分區的剩餘空間
2.Check Zombie Procs:監控殭屍進程的數目
3.Total Processes:監控總進程的數目
4.check-no_alowed_user:監控是否有非容許的用戶登錄
5.check-system-load:監控系統負載
對於nagios的工做原理,簡單來講就是:在服務端的nagios目錄下的services.cfg文件上定義須要監控各個客戶端的哪一個監控項目,對應的監控腳本被放在客戶端執行,執行結果經過客戶端上的nrpe守護進程反饋給nagios服務器端。
默認狀況下監控腳本返回的值所表明的的含義以下:
OK—退出代碼 0—表示服務正常地工做。
WARNING—退出代碼 1—表示服務處於警告狀態。
CRITICAL—退出代碼 2—表示服務處於危險狀態。
UNKNOWN—退出代碼 3—表示服務處於未知狀態。
所以,要實現上述5個監控項目,首先修改nagios服務器端(即centos5)上的services.cfg文件,添加上如下內容:
define service{ use local-service host_name centos1 service_description check-no_alowed_user check_command check_nrpe!check_no_allowed_user #對於腳本在客戶端執行的命令,都要在命令前加上check_nrpe! notifications_enabled 1 #開啓告警功能 flap_detection_enabled 0 #關閉抖動檢測(當數據出現較大抖動時nagios不會做出提示) notification_options w,c,r #warning、critical、recover時發出告警 notification_interval 5 #假如服務的狀態沒有恢復正常的話,告警將每5分鐘發一次 notification_period 24x7 #設定告警的時段,這裏設置爲24X7 } define service{ use local-service,services-pnp #對於添加上services-pnp的服務,nagios將調用pnp把服務返回的數據畫成圖表。 host_name centos1 service_description check-system-load check_command check_nrpe!check_load notifications_enabled 1 flap_detection_enabled 0 notification_options w,c,r notification_interval 5 notification_period 24x7 } define service{ use local-service,services-pnp host_name centos1 service_description Total Processes check_command check_nrpe!check_total_procs notifications_enabled 1 flap_detection_enabled 0 notification_options w,c,r notification_interval 5 notification_period 24x7 } define service{ use local-service,services-pnp host_name centos1 service_description Check Zombie Procs check_command check_nrpe!check_zombie_procs notifications_enabled 1 flap_detection_enabled 0 notification_options w,c,r notification_interval 5 notification_period 24x7 } define service{ use local-service,services-pnp host_name centos1 service_description Check Swap check_command check_nrpe!check_swap notifications_enabled 1 flap_detection_enabled 0 notification_options w,c,r notification_interval 5 notification_period 24x7 }
以上寫出了描述centos1監控服務的描述,其餘3臺服務器的描述都是同樣的,只是host_name不同,限於篇幅,這裏就不把剩餘部分列出了。
接下來修改客戶端的設置,一樣以centos1爲例,修改nagios目錄下的nrpe.cfg文件,添加如下內容(部份內容默認已經存在的,修改的時候須要注意有沒有重複):
command[check_swap]=/usr/local/nagios/libexec/check_swap -w 20% -c 10% #-w後面的參數告訴腳本當交換空間小於20%時,返回warming狀態(即返回1),-c後面的參數告訴腳本當交換空間小於10%時,返回critical狀態(即返回2) command[check_load]=/usr/local/nagios/libexec/check_load -w 1.8,1.5,1.2 -c 2.5,2,1.8 command[check_zombie_procs]=/usr/local/nagios/libexec/check_procs -w 5 -c 10 -s Z command[check_total_procs]=/usr/local/nagios/libexec/check_procs -w 150 -c 200 command[check_no_allowed_user]=/usr/local/nagios/libexec/check_no_allowed_user.py –a cjyfff
上面這5個命令對應的腳本中,check_no_allowed_user.py是我編寫的腳本,另外4個是nagios自帶的。check_no_allowed_user.py的做用是檢測是否有容許用戶之外的用戶登陸系統。使用方法是腳本後面加上選項-a,而後添加容許登陸的用戶列表(格式是-a user1,user2...,root默認已添加到容許列表,所以無需添加root)。當容許用戶列表之外的用戶登陸時,將會觸發nagios的critial告警。這個腳本的內容以下:
#! /usr/bin/env python #coding=utf-8 #check_no_allowed_user.py import os, sys, getopt def Usage(): print "Usage:\n\tpython check_no_allowed_user.py [-h|--help][-a|--add allowedUser01,allowUser02...]\n" print "\tTo creat the allowed user list,please use this format:-a user1,user2...." print "\tAny user(s) not in allowed user list login this system will alter Nagios." sys.exit(3) def CheckUser(args): a = os.popen("who").read() #這裏a被賦值成一個包含換行符的字符串 #下面須要以換行符分隔把a建成列表,而後提取列表元素的第一個字段,這纔是 #咱們所須要的當前用戶名 b = list(a.split("\n")) c = [] i = 0 while i<len(b)-1: c.append(b[i].split(" ")[0]) i += 1 userList = set(c) allowedList = list(args.split(",")) #建立容許用戶的列表 allowedList.append("root") #容許用戶的列表中默認添加上root #print allowedList rs = [user for user in userList if user not in allowedList] #查出在當前用戶列表中但不在容許列表中的用戶 #print rs if rs : print "Detected NO ALLOWED user(s)%s"%rs sys.exit(2) else: print "All user is ALLOWED." sys.exit(0) try: options, args = getopt.getopt(sys.argv[1:], "ha:", ["help", "add="]) except getopt.GetoptError: Usage() for o,r in options: if o in ("-h", "--help"): Usage() if o in ("-a", "--add"): #print type(r) CheckUser(r)
另外,對於centos1、centos4兩臺前端服務器,還須要添加2項監控服務:
80port:監控80端口的狀況
CheckNginxState:監控nginx進程是否啓動
一樣,以centos1爲例,修改centos5上的services.cfg,添加上如下內容:
define service{ use local-service,services-pnp host_name centos1 service_description 80port check_command check_tcp!80 #這個命令是經過服務器端的腳原本監控客戶端的80端口的,所以無需加上check_nrpe!,客戶端也不須要存在這個命令對應的腳本。 } define service{ use local-service host_name centos1 service_description CheckNginxState check_command check_nrpe!check_nginx }
而後修改centos1上的nrpe.cfg,添加上如下內容:
command[check_nginx]=/usr/local/nagios/libexec/check_nginx.sh
這裏的check_nginx.sh也是我本身編寫的腳本,腳本內容以下:
#!/bin/bash #check_nginx.sh use_age="This script is for checking nginx status,if nginx is stop Nagios will alarm." if (($#!=0));then echo $use_age exit 3 fi a=`ps -C nginx --no-header |wc -l` if ((a!=0));then echo "nginx is running." exit 0 else echo "nginx is NOT running." exit 2 fi
對於centos4這臺共享文件服務器,還須要增長一個監控項目,監控硬盤的容量大小,這裏能夠用nagios自帶的check_disk腳本,方法和上面同樣的,這裏就不在敘述了。
對於做爲後端web服務器的centos2、centos3,也頗有必要監控服務器上apache以及mysql是否正在運行。監控腳本很簡單,只須要把上面check_nginx.sh中「a=`ps -C nginx --no-header |wc -l`」修改一下,把「nginx」替換爲「httpd」和「mysqld」便可。
最後,客戶端都設置好監控設置了,做爲服務器端,也能夠爲centos5增長監控內容,服務器端的監控腳本一樣放在服務器端的libexec/下,監控服務是在localhost.cfg中定義的。
謹記添加本身寫的腳本後要把用戶改成nagios:nagios,而且增長執行權限。
最終配置完畢後,打開nagios監控頁面的效果圖以下:
六、安全設置
爲了減小ssh密碼被暴力破解的風險,在各個服務器上把ssh端口從默認的22端口更改成其餘端口(本例子中改成2002),而且在/etc/hosts.allow中指定容許sshd通訊的ip,在/etc/hosts.deny中添加sshd:ALL
考慮到服務器都是在內網環境,已經能隔絕外網的不少攻擊,而且開啓防火牆的話會影響服務器之間數據轉發速度,所以我在這4臺服務器上都關閉iptables,僅在centos5上開啓。在實際生產環境中,依靠在集羣前面的防火牆對集羣進行進一步保護。
centos5的iptables腳本以下:
!#/bin/bash #centos5-iptables.sh iptables -F iptables -X iptables -Z iptables -P INPUT DROP iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT iptables -A INPUT -p icmp -j ACCEPT#容許icmp協議包經過 iptables -A INPUT -s 192.168.48.139 -j ACCEPT iptables -A INPUT -s 192.168.48.140 -j ACCEPT iptables -A INPUT -s 10.0.0.2 -j ACCEPT iptables -A INPUT -s 10.0.0.3 -j ACCEPT iptables -A INPUT -p tcp -m multiport --dport 22,80 -j ACCEPT /etc/rc.d/init.d/iptables save
五 結語:
最後我用apache benchmark測試了一下網站。雖然是在虛擬機環境,測試數據沒多大參考價值,可是經過測試也能夠看看在高併發的環境下,那些服務器負荷最大。經測試,在100併發的環境下,雖然網頁還能打開,可是nagios已經失去了後端兩臺web服務器的響應,提示request timeout了,其餘兩臺服務器的負載仍是很低,說明在高併發的環境下,後端的web服務器負荷最大,也是重點須要優化的對象。
這個實驗環境存在一個不足,那就是共享文件只放在一臺服務器上,容易形成單邊,建議條件許可的狀況下可以使用分佈式存儲系統,例如MFS。
另外在搭建實驗環境的過程當中還有2點待往後跟進:
一、優化apache的性能,讓後端服務器能應付更大併發。
二、Mysql的主從同步存在延遲問題,可能會致使主、從數據庫不一致。這個查看網上資料能夠經過插件來解決,下一步嘗試接觸這些插件的使用方法。