什麼是服務發現?

摘要: 將容器應用部署到集羣時,其服務地址,即IP端口, 是由集羣系統動態分配的。那麼,當咱們須要訪問這個服務時,如何肯定它的地址呢?這時,就須要服務發現(Service Discovery)了。本文將以Nginx的部署爲例,介紹服務發現的原理與實踐。html

圖片描述

一. 單機部署Nginx

Nginx做爲網頁服務器,功能與Apache一致。使用Docker, 能夠快速部署Nginx。python

1. 下載Nginx鏡像
sudo docker pull nginx:1.10
2. 運行Nginx容器
sudo docker run -d \
                -p 8080:80 \
                nginx:1.10

其中,-d選項表示Nginx容器在後臺運行,-p選項表示主機的8080端口映射爲容器的80端口。nginx

3. 訪問Nginx服務

使用瀏覽器服務Nginxgit

http://192.168.59.1:8080github

或者使用curl命令訪問Nginx, 其返回結果爲html文件。docker

curl 192.168.59.1:8080

Nginx的服務地址是192.168.59.1:8080,其中,192.168.59.1是運行Nginx容器的主機的IP,而8080是Nginx提供服務的端口。json

可知,將容器應用部署到單個主機上時,服務的IP即爲運行容器的主機IP,而服務的端口能夠經過-p選項手動指定,這時服務地址至關因而靜態分配的,所以不存在服務發現的問題。然而,當咱們將容器應用部署到多個節點的集羣時呢?後端

二. Mesos/Marathon集羣中部署Nginx

首先,能夠按照基於Docker搭建多節點Mesos/Marathon介紹的方法,快速搭建3個節點的Mesos/Marathon集羣。部署Nginx時,能夠不使用服務發現,也可使用Marathon LB提供服務發現。經過對比兩種方式,能夠更好地理解服務發現。

1. 不使用服務發現

Nginx定義(nginx1.json):

{
    "id": "nginx1",
    "cpus": 0.2,
    "mem": 20.0,
    "instances": 1,
    "healthChecks": [{
        "path": "/"
    }],
    "container": {
        "type": "DOCKER",
        "docker": {
            "image": "nginx:1.10",
            "network": "BRIDGE",
            "portMappings": [{ "containerPort": 80, "hostPort": 0, "protocol": "tcp" }]
        }
    }
}

其中,instances爲1,表示僅部署單個Nginx容器; hostPort爲0,表示Nginx容器綁定的主機端口由Marathon隨機分配。

部署Nginx:

curl -Ss \
     -X POST \
     -H "Content-Type: application/json" \
     --data "@nginx1.json" \
     http://127.0.0.1:8080/v2/apps | python2.7 -mjson.tool

這時,Nginx容器可能運行node2(192.168.59.2)上,也可能運行在node3(192.168.59.3)上,所以Nginx服務的IP是沒法事先肯定的。而Nginx容器綁定的主機端口由Marathon隨機分配,也不肯定。

固然,服務端口能夠經過hostPort指定,可是這樣作並不合適,由於有可能會發生端口衝突。當集羣中運行了很是多不一樣的服務時,靜態分配端口是不現實的,也限制了集羣的靈活性與擴展性

在Slave節點上使用docker ps命令能夠獲取Nginx服務的IP與端口。

node2(192.168.59.2)

sudo docker ps | grep nginx
b863d407b880        nginx:1.10              "nginx -g 'daemon off"   15 minutes ago      Up 15 minutes       443/tcp, 0.0.0.0:31575->80/tcp   mesos-d34d0b5b-c3b1-4020-9bb2-bb8582252bf3-S0.d2de6d05-9751-4fbe-af10-d7e35e9e6c7b

node3(192.168.59.3)

sudo docker ps | grep nginx

可知Nginx服務的IP與端口分別爲192.168.59.231575,即Nginx的服務地址爲:http://192.168.59.2:31575

每次從新部署Nginx時,其IP和端口會發生變化,這就意味着每次都要手動去查詢服務地址,這很不方便,且沒法將部署任務自動化。在容器集羣中,一般須要運行很是多不一樣的應用,這就意味着服務發現是容器集羣系統的必備功能。

2. 使用Marathon LB提供服務發現

Marathon LB是Marathon的服務發現系統。Marathon LB經過使用Haproxy實現了代理服務器的功能。

經過使用Marathon LB能夠配置服務的固定端口,而服務的IP就是運行Marathon LB的節點IP。Marathon LB會監聽Marathon的調度事件,獲取容器實際運行的IP與端口,而後更新Haproxy的配置文件。所以,當從新部署Nginx時,咱們仍然能夠經過固定的IP與端口訪問該服務。

Nginx定義(nginx2.json):

{
    "id": "nginx2",
    "labels": {
        "HAPROXY_GROUP": "external"
    },
    "cpus": 0.2,
    "mem": 20.0,
    "instances": 1,
    "healthChecks": [{
        "path": "/"
    }],
    "container": {
        "type": "DOCKER",
        "docker": {
            "image": "nginx:1.10",
            "network": "BRIDGE",
            "portMappings": [{ "containerPort": 80, "hostPort": 0, "servicePort": 10000, "protocol": "tcp" }]
        }
    }
}

其中,nginx2.json只有HAPROXY_GROUPservicePort兩處修改。HAPROXY_GROUP爲external,表示Nginx將使用分組爲external的Marathon LB作服務發現。servicePort爲10000,表示Nginx將使用Marathon LB節點的10000端口提供服務。

部署Nginx:

curl -Ss \
     -X POST \
     -H "Content-Type: application/json" \
     --data "@nginx2.json" \
     http://127.0.0.1:8080/v2/apps | python2.7 -mjson.tool

這時,Nginx服務的IP爲運行Marathon LB的節點IP,即192.168.59.1,而Nginx服務的端口爲servicePort指定的端口,即10000。所以,Nginx的服務地址爲:http://192.168.59.1:10000。而Nginx容器的實際地址爲http://192.168.59.2:31270,Marathon LB使用Haproxy做爲代理服務器轉發的服務請求。Marathon LB會監聽Marathon的調度事件,獲取容器實際運行的IP與端口,而後更新Haproxy的配置文件。下面即爲Marathon LB自動生成的Haproxy配置文件:

frontend nginx2_10000
  bind *:10000
  mode http
  use_backend nginx2_10000

backend nginx2_10000
  balance roundrobin
  mode http
  option forwardfor
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https if { ssl_fc }
  option  httpchk GET /
  timeout check 20s
  server 192_168_59_2_31270 192.168.59.2:31270 check inter 60s fall 4

可知Haproxy中,niginx服務的前端(frontend)地址爲: *:10000,然後端(backend)地址爲: 192.168.59.2:31270。Haproxy負責將服務請求轉發到Nginx容器。

當咱們從新部署Nginx時,Nginx容器的IP和端口會發生變化,Marathon LB會更新Haproxy的配置文件,所以咱們仍然能夠經過http://192.168.59.1:10000訪問服務。

所以,Marathon LB的任務就是發現服務的地址(IP和端口),而後用戶就不用每次手動查詢了。bamboonixy實現了一樣的功能。

三. 參考

  1. Understanding Modern Service Discovery with Docker

  2. 基於Docker技術構建PaaS雲平臺

  3. Youzan 服務發現概述

相關文章
相關標籤/搜索