基於容器的後端服務架構

基於容器的後端服務架構

在探索kubernetes的應用時,調研了幾個gateway,發現fabio支持發現服務,自動生成路由,結合consul,registrator, 能夠很容易的部署一套服務,比較輕量,很容易玩起來。前端

結構大體爲:
圖片描述node

Start Consul

安裝 consul, 若是檢測到多個 private ip, 會報錯,能夠用 -advertise 指定一個ip.golang

// config.json , 指定 DNS port
{
    "recursors" : [ "8.8.8.8" ],
    "ports" : {
        "dns" : 53
    }
}

sudo docker run -d --name=consul --net=host -v $PWD/config.json:/config/config.json gliderlabs/consul-server -bootstrap -advertise=172.28.128.3 

curl 172.28.128.3:8500/v1/catalog/services

Start Registrator

啓動 registrator, 由於須要調用docker api, 因此須要把docker.sock 映射到容器內部,若是你使用了tcp, 那麼須要設置對應的url。 web

若是你但願上報容器內部ip:port, 那麼須要在啓動參數中加入 -internal=true, 這樣註冊的 Service, 都是容器內部的ip, 而port對於同一個service而言,通常是固定的,例如 一個hello服務的兩個實例分別爲 10.10.1.12:9090, 10.10.1.13:9090. 這樣的話,就須要配置一個容器跨host的網絡方案,例如 flannel, 等。 能夠參考上一篇 Flannel with Dockerdocker

爲了簡便測試,這裏就不配置flannel了。-ip是指定註冊service時候使用的ip,建議要指定,選取當前機器的內網 private ip便可。我這裏是 172.28.128.3.json

sudo docker run -d --name=registrator --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:latest -ip=172.28.128.3 consul://172.28.128.3:8500

Start service

啓動服務,這裏須要注意的是這些環境變量,做用是 override Registrator的默認值,見名知意,在 registrator 文檔中有詳細介紹。例如 SERVICE_9090_NAME 就是指 端口爲 9090 的service 的 name。bootstrap

須要注意的是 tags 這個字段,urlprefix-/foo,hello, 這裏 urlprefix- 是 gateway 的一種配置,意思爲 把訪問 /foo 爲前綴的請求轉發到當前應用來。他可以匹配到例如 /foo/bar, footest, 等。若是你想加上域名的限制,能夠這樣 urlprefix-mysite.com/foo。 後面還有一個 hello, 做用是給這個service打一個標記,能夠用做查詢用。segmentfault

sudo docker run -d -P -e SERVICE_9090_CHECK_HTTP=/foo/healthcheck -e SERVICE_9090_NAME=hello -e SERVICE_CHECK_INTERVAL=10s -e SERVICE_CHECK_TIMEOUT=5s -e SERVICE_TAGS=urlprefix-/foo,hello silentred/alpine-hello:v2

curl 172.28.128.3:8500/v1/catalog/services
//如今應該能看到剛啓動的hello服務了
{"consul":[],"hello":["urlprefix-mysite.com/foo","hello","urlprefix-/foo"]}

測試 DNS後端

sudo yum install bind-utils
dig @172.28.128.3 hello.service.consul SRV

能夠設置 /etc/resolv.confapi

nameserver 172.28.128.3
search service.consul

這樣不管在容器內部,仍是外部均可以直接解析 sevice 名, 例如:

[vagrant@localhost ~]$ ping hello
PING hello.service.consul (172.28.128.3) 56(84) bytes of data.
64 bytes from localhost.localdomain.node.dc1.consul (172.28.128.3): icmp_seq=1 ttl=64 time=0.016 ms

[vagrant@localhost ~]$ sudo docker exec -it fdde1b8247b8 bash
bash-4.4# ping hello
PING hello (172.28.128.6): 56 data bytes
64 bytes from 172.28.128.6: seq=0 ttl=63 time=0.361 ms

Start Gateway

前端Gateway 根據 consul中註冊的 service,生成對應的路由規則,把流量分發到各個節點。 這個項目還有一個 ui 管理 route信息,端口爲 9998。

建立一個配置文件 fabio.properties

registry.consul.addr = 172.28.128.3:8500

在當前目錄運行

docker run -d -p 9999:9999 -p 9998:9998 -v $PWD/fabio.properties:/etc/fabio/fabio.properties magiconair/fabio

測試gateway:

curl 172.28.128.3:9999/foo/bar
curl 172.28.128.3:9999/foo/bar -H "Host: mysite.com"

圖片描述

Health Check

sudo ifdown eth1

curl http://localhost:8500/v1/health/state/critical

[
    {
        "Node":"localhost.localdomain",
        "CheckID":"service:afa2769cd049:loving_shannon:9090",
        "Name":"Service 'hello' check",
        "Status":"critical",
        "Notes":"",
        "Output":"Get http://172.28.128.6:32768/foo/healthcheck: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)",
        "ServiceID":"afa2769cd049:loving_shannon:9090",
        "ServiceName":"hello",
        "CreateIndex":379,
        "ModifyIndex":457
    }
]

sudo ifup eth1

在啓動 consul的時候,咱們使用了-ui 參數,咱們能夠在 172.28.128.3:8500/ui 訪問到consul的web ui管理界面,看到各個服務的狀態.

圖片描述

對比

註冊容器外IP:
每一個註冊的service的port都是變化的,而且由於映射內部port到了host,外部能夠隨意訪問,私密性較弱。

註冊容器內IP:
每一個註冊的service的port都是固定的,只能從容器內部訪問。若是用 flannel,可能有一些性能損失。

DNS服務發現

查了一下如何利用DNS SRV類型來發現服務。原本覺得能夠用相似 Dial("hello", SRV) 的魔法 (咱們都是膜法師,+1s), 查了一些資料貌似沒有這麼方便。看了下golang的net包,發現了兩個方法 LookupSRV, LookupHost, 因而測試了一下,看下結果,你們知道該怎麼用了吧,嘿嘿。

cname, addrs, err := net.LookupSRV("", "", "hello.service.consul")
fmt.Printf("%s, %#v, %s \n", cname, addrs, err)
for _, srv := range addrs {
    fmt.Printf("%#v \n", *srv)
}

newAddrs, err := net.LookupHost("hello.service.consul")
fmt.Printf("%#v, %s \n", newAddrs, err)
//output
[vagrant@bogon dns]$ go run mx.go
hello.service.consul., []*net.SRV{(*net.SRV)(0xc420010980), (*net.SRV)(0xc4200109a0)}, %!s(<nil>)
net.SRV{Target:"bogon.node.dc1.consul.", Port:0x8003, Priority:0x1, Weight:0x1}
net.SRV{Target:"bogon.node.dc1.consul.", Port:0x8000, Priority:0x1, Weight:0x1}
[]string{"172.28.128.3", "172.28.128.4"}, %!s(<nil>)
相關文章
相關標籤/搜索