使用 caddy 作為微服務(wù)的 API gateway

背景

大家都知道咒钟,Docker這些年讓IT界產(chǎn)生了深刻的變革卢肃,
從開發(fā)到測試到運維疲迂,處處都有它的身影。
它同時也和微服務(wù)架構(gòu)相互促進(jìn)莫湘,并肩前行尤蒿。

在最新版的 Docker(CE 17.03) 里,隨著 swarm mode 的成熟幅垮,
在較簡單的場景里已經(jīng)可以不再需要專門的基礎(chǔ)設(shè)施管理腰池,
服務(wù)編排服務(wù)發(fā)現(xiàn)忙芒,健康檢查示弓,負(fù)載均衡等等。

但是API gateway還是需要一個的呵萨∽嗍簦或許再加上一個日志收集
你的微服務(wù)架構(gòu)就五臟俱全了潮峦。
我們知道Nginx Plus是可以很好的勝任 API gateway 的工作的囱皿,
但它是商業(yè)軟件勇婴。Nginx我們不說認(rèn)證啊限流啊統(tǒng)計啊之類的功能,
單就請求轉(zhuǎn)發(fā)這一點最基本的就出了問題嘱腥。

我們知道Docker是用DNS的方式耕渴,均衡同一名稱的服務(wù)請求到不同的node,
但是Nginx為了速度齿兔,在反向代理的時候會有一個不可取消的 DNS Cache橱脸,
這樣我們Docker在根據(jù)容器的擴(kuò)展或收縮動態(tài)的更新DNS,可Nginx卻不為所動愧驱,
堅持把請求往固定的IP上發(fā)慰技,不說均衡,這個IP甚至可能已經(jīng)失效了呢组砚。

有一個配置文件上的小Hack可以實現(xiàn)Nginx每次去查詢DNS吻商,我本來準(zhǔn)備寫一篇文章來著,
現(xiàn)在看來不用了糟红,我們找到了更優(yōu)雅的API gateway, Caddy 艾帐。
我上篇文章也寫了一個它的簡介。

接下來的所有代碼盆偿,都在這個demo中柒爸,
你可以clone下來玩,也能在此基礎(chǔ)上做自己的實驗事扭。

應(yīng)用

我們先用golang寫一個最簡單的HTTP API捎稚,你可以用你會的任何語言寫出來,
它為GET請求返回 Hello World 加自己的 hostname .

package main

import (
    "io"
    "log"
    "net/http"
    "os"
)

// HelloServer the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
    hostname, _ := os.Hostname()
    log.Println(hostname)
    io.WriteString(w, "Hello, world! I am "+hostname+" :)\n")
}

func main() {
    http.HandleFunc("/", HelloServer)
    log.Fatal(http.ListenAndServe(":12345", nil))
}

Docker 化

我們需要把上面的應(yīng)用做成一個docker鏡像求橄,暴露端口12345今野。
接著才有可能使用Docker Swarm啟動成集群。
本來做鏡像特別簡單罐农,但我為了讓大家直接拉鏡像測試時快一點条霜,用了兩步構(gòu)建,
先編譯出應(yīng)用涵亏,然后添加到比較小的alpine鏡像中宰睡。大家可以不必在意這些細(xì)節(jié)。
我們還是先來看看最終的docker-compose.yml編排文件吧气筋。

version: '3'
services:
    app:
        image: muninn/caddy-microservice:app
        deploy:
            replicas: 3
    gateway:
        image: muninn/caddy-microservice:gateway
        ports:
            - 2015:2015
        depends_on:
            - app
        deploy:
            replicas: 1
            placement:
                constraints: [node.role == manager]

這是最新版本的docker-compose文件拆内,不再由docker-compose命令啟動,而是要用docker stack deploy命令宠默。
總之現(xiàn)在這個版本在編排方面還沒有完全整合好矛纹,有點暈,不過能用」饧冢現(xiàn)在我們看到編排中有兩個鏡像:

  • muninn/caddy-microservice:app 這是我們上一節(jié)說的app鏡像或南,我們將啟動3個實例孩等,測試上層的負(fù)載均衡。
  • muninn/caddy-microservice:gateway 這是我們接下來要講的gateway了采够,它監(jiān)聽2015端口并將請求轉(zhuǎn)發(fā)給app肄方。

用 caddy 當(dāng)作 gateway

為了讓caddy當(dāng)作gateway,我們主要來看一下Caddyfile:

:2015 {
    proxy / app:12345
}

好吧蹬癌,它太簡單了权她。它監(jiān)聽本機(jī)的2015端口,將所有的請求都轉(zhuǎn)發(fā)到 app:12345 逝薪。
這個app隅要,其實是一個域名,在docker swarm的網(wǎng)絡(luò)中董济,它會被解析到這個名字服務(wù)隨機(jī)的一個實例步清。

將來如果有很多app,將不同的請求前綴轉(zhuǎn)發(fā)到不同的app就好啦虏肾。
所以記得寫規(guī)范的時候讓一個app的endpoint前綴盡量用一樣的廓啊。

然后caddy也需要被容器化,感興趣的可以看看Dockerfile.gateway .

運行服務(wù)端

理解了上面的內(nèi)容封豪,就可以開始運行服務(wù)端了谴轮。直接用我上傳到云端的鏡像就可以。本文用到的三個鏡像下載時總計26M左右吹埠,不大第步。
clone我背景章節(jié)提到的庫進(jìn)入項目目錄,或者僅僅復(fù)制上文提到的compose文件存成docker-compose.yml缘琅,然后執(zhí)行如下命令粘都。

docker-compose pull
docker stack deploy -c docker-compose.yml caddy

啊,對了胯杭,第二個stack命令需要你已經(jīng)將docker切到了swarm模式驯杜,如果沒有會自動出來提示受啥,根據(jù)提示切換即可做个。
如果成功了,我們檢查下狀態(tài):

docker stack ps caddy

如果沒問題滚局,我們能看到已經(jīng)啟動了3個app和一個gateway居暖。然后我們來測試這個gateway是否能將請求分配到三個后端。

測試

我們是可以通過訪問http://{your-host-ip}:2015來測試服務(wù)是不是通的藤肢,用瀏覽器或者curl太闺。
然后你會發(fā)現(xiàn),怎么刷新內(nèi)容都不變啊嘁圈,并沒有像想象中的那樣會訪問到隨機(jī)的后端省骂。

不要著急蟀淮,這個現(xiàn)象并非因為caddy像nginx那樣緩存了dns導(dǎo)致均衡失敗,而是另一個原因钞澳。
caddy為了反向代理的速度怠惶,會和后端保持一個連接池。當(dāng)只有一個客戶端的時候轧粟,用到總是那第一個連接呢策治。
為了證明這一點,我們需要并發(fā)的訪問我們的服務(wù)兰吟,再看看是否符合我們的預(yù)期通惫。

同樣的,測試我也為大家準(zhǔn)備了鏡像混蔼,可以直接通過docker使用履腋。

docker run --rm -it muninn/caddy-microservice:client

感興趣的人可以看client文件夾里的代碼,它同時發(fā)起了30個請求拄丰,并且打印出了3個后端被命中的次數(shù)府树。

另外我還做了一個shell版本,只需要sh test.sh就可以料按,不過只能看輸出拉奄侠,沒有自動檢查結(jié)果。

好了载矿,現(xiàn)在我們可以知道垄潮,caddy可以很好的勝任微服務(wù)架構(gòu)中的 API Gateway 了。

API Gateway

什么闷盔?你說沒看出來這是個 API Gateway 啊弯洗。我們前邊只是解決了容器項目中 API Gateway 和DNS式服務(wù)發(fā)現(xiàn)配合的一個難題,
接下來就簡單了啊逢勾,我們寫n個app牡整,每個app是一個微服務(wù),在gateway中把不同的url路由到不同的app就好了啊溺拱。

進(jìn)階

caddy還可以輕松的順便把認(rèn)證中心做了逃贝,微服務(wù)建議用jwt做認(rèn)證,將權(quán)限攜帶在token中迫摔,caddy稍微配置下就可以沐扳。
我后續(xù)也會給出教程和demo 。auth2.0我認(rèn)為并不適合微服務(wù)架構(gòu)句占,但依然是有個復(fù)雜的架構(gòu)方案的沪摄,這個主題改天再說。

caddy還可以做API狀態(tài)監(jiān)控,緩存,限流等API gateway的職責(zé),不過這些就要你進(jìn)行一些開發(fā)了杨拐。
你還有什么更多的想法嗎祈餐?歡迎留言。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哄陶,一起剝皮案震驚了整個濱河市昼弟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奕筐,老刑警劉巖舱痘,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異离赫,居然都是意外死亡芭逝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門渊胸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旬盯,“玉大人,你說我怎么就攤上這事翎猛∨趾玻” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵切厘,是天一觀的道長萨咳。 經(jīng)常有香客問我,道長疫稿,這世上最難降的妖魔是什么培他? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮遗座,結(jié)果婚禮上舀凛,老公的妹妹穿的比我還像新娘。我一直安慰自己途蒋,他們只是感情好猛遍,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著号坡,像睡著了一般懊烤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上筋帖,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天奸晴,我揣著相機(jī)與錄音冤馏,去河邊找鬼日麸。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的代箭。 我是一名探鬼主播墩划,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嗡综!你這毒婦竟也來了乙帮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤极景,失蹤者是張志新(化名)和其女友劉穎察净,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盼樟,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡氢卡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晨缴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片译秦。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖击碗,靈堂內(nèi)的尸體忽然破棺而出筑悴,到底是詐尸還是另有隱情,我是刑警寧澤稍途,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布阁吝,位于F島的核電站,受9級特大地震影響械拍,放射性物質(zhì)發(fā)生泄漏求摇。R本人自食惡果不足惜菠隆,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一剿吻、第九天 我趴在偏房一處隱蔽的房頂上張望鲸沮。 院中可真熱鬧动遭,春花似錦鸭津、人聲如沸蛾派。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽海蔽。三九已至共屈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間党窜,已是汗流浹背拗引。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留幌衣,地道東北人矾削。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓壤玫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哼凯。 傳聞我的和親對象是個殘疾皇子欲间,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容