概述
這節(jié)其實(shí)是上一篇nginx教程的補(bǔ)充,因?yàn)橛信笥芽戳酥髮τ诜聪虼砟菈K還有點(diǎn)疑問.所以這邊就舉一個簡單的例子(負(fù)載均衡).順便加上了一些docker的知識。所以廢話不說,進(jìn)入正題吧~
nginx反向代理
上一篇文章提到了反向代理的概念.概念其實(shí)很簡單,但是實(shí)際上有什么應(yīng)用呢?
有個最簡單也是很實(shí)用的例子,也就是負(fù)載均衡.作為反向代理的nginx在收到請求后按照一定規(guī)則再分發(fā)給下游的服務(wù)器.在這里對服務(wù)端而言客戶端是明確的,并且通常配置的時候會帶上realip.但是對于客戶端來講卻不知道請求最后落到了哪臺機(jī)器,這就是一個常見的反向代理的場景.這里并沒有其他可以補(bǔ)充的知識,在nginx的官網(wǎng)上都是有相關(guān)介紹的.
這就著重以一個例子來實(shí)現(xiàn).
這邊會借助docker來實(shí)現(xiàn)這個例子.
最簡單的一個例子就是兩個服務(wù)容器一個nginx容器.
nginx容器就是直接使用官方鏡像即可.
首先是server的代碼,go語言編寫
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
log.Println(r)
hostName, _ := os.Hostname()
w.Write([]byte(fmt.Sprintf("server:%s\n", hostName)))
return
})
log.Println("start...")
log.Panic(http.ListenAndServe(":8081", nil))
}
本身沒什么難度,主要是會輸出自己的hostname,這個在后面幫助我們區(qū)分實(shí)際訪問的服務(wù)器.
然后go build 編譯即可,根據(jù)自己的實(shí)際需求選擇編譯條件.這里我提供了現(xiàn)成的docker鏡像,地址為(https://cloud.docker.com/u/evanshao/repository/docker/evanshao/lbserver),
就不多贅述了.
然后是Dockerfile
FROM debian
MAINTAINER evan
COPY server /
ENTRYPOINT ["./server"]
這個也很簡單,就是借助debian基礎(chǔ)鏡像運(yùn)行編譯好的server.
然后是nginx配置(已經(jīng)提供了鏡像,地址是:https://cloud.docker.com/u/evanshao/repository/docker/evanshao/lbnginx).
這里可以參考上一篇文章的基礎(chǔ)配置:
#user nobody;
worker_processes 4; # 按照機(jī)器情況定
events {
worker_connections 10240; # 按照機(jī)器情況定
}
http{
include mime.types;
default_type application/json; # 按照自己服務(wù)設(shè)置
error_page 500 502 503 504 /50x.html;
error_page 404 /404.html; # 這個自己寫了放到html目錄下,不然應(yīng)該是nginx代碼里寫死的
resolver 114.114.114.114;
# 定義日志格式 這個別名是main
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 30;
include sites/*.http.conf; # 具體的server放在這里
}
重點(diǎn)是sites下需要兩個新建的配置文件,
一個是ups.http.upstream:
upstream test_server{
server serverA:8081;
server serverB:8081;
}
這里其實(shí)是有兩個注意點(diǎn)的,一個是serverA 這個是配合后面的dockerDNS使用的,還有個自然是端口號,和server程序監(jiān)聽的端口號一致.
另外一個文件是 ups.http.conf,這里在開頭引用了upsream文件,并利用proxy_pass實(shí)現(xiàn)了轉(zhuǎn)發(fā).
include sites/ups.http.upstream;
server{
listen 80 default_server;
server_name localhost;
access_log logs/ups.log main;
location /{
set $upstream_host $host;
proxy_pass http://test_server;
}
}
這邊是Dockerfile,myconf下就是上面的文件nginx.conf以及sites文件夾,sites里是其他兩個文件.另外還創(chuàng)建了一個空的logs文件夾
FROM nginx
MAINTAINER evan
COPY myconf/ /etc/nginx
EXPOSE 80
ENTRYPOINT ["nginx","-g","daemon off;"]
到這里實(shí)驗(yàn)環(huán)境就準(zhǔn)備好了,下面其實(shí)就是docker部分了,時間有限,這里僅僅提下使用方法.如果docker沒有安裝的話可以參考官方文檔進(jìn)行操作,后面有機(jī)會我也會開始寫一些docker的簡單教程~
上文提到的dockerDNS其實(shí)是docker提供的一種容器間通信的方法.具體的就不贅述了,如果有興趣的話可以自行搜索或者等我的blog哦.
首先我們要創(chuàng)建自己的docker子網(wǎng)
docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net
這里相當(dāng)于創(chuàng)建了一個局域網(wǎng),網(wǎng)段是172.22.16.然后在運(yùn)行server和nginx容器的時候我會把他們都指定到這個網(wǎng)段,這樣才能保證局域網(wǎng)內(nèi)各容器的網(wǎng)絡(luò)通信.
接下來首先啟動兩臺server容器
docker run -itd --rm --name serverA --hostname serverA --network=my_net evanshao/lbserver
docker run -itd --rm --name serverB --hostname serverB --network=my_net evanshao/lbserver
這里用--hostname 指定機(jī)器的host配合server的取值,--name相當(dāng)于指定局域網(wǎng)內(nèi)的通信域名,這里需要注意的是--name 指定的才是我們訪問的域名,這里我順手寫成和hostname一樣的了,不要混淆.
然后我們需要啟動nginx
docker run -itd --rm --name lbnginx -p 80:80 --network=my_net evanshao/lbnginx
這時候?qū)嶒?yàn)環(huán)境就已經(jīng)搭建完成了,我們通過瀏覽器訪問http://192.168.31.147/test就可以看到效果了:

刷新就變成

這邊配置默認(rèn)應(yīng)該是輪詢,當(dāng)你停掉一個容器的時候就會只訪問到活著的那臺機(jī)器了.
這里如果沒時間自己操作的話,直接按照我上面的三條docker run命令執(zhí)行即可.
后面可以慢慢還原.
這里寫的有些粗略了,因?yàn)樯弦黄恼乱呀?jīng)有提到一些nginx關(guān)鍵字的用法,官方也寫得很詳細(xì)了.主要還是展示下如果通過docker展現(xiàn)這一場景,后續(xù)我也會慢慢補(bǔ)充一些docker的知識,希望到時候能對你們有所幫助.