基于 Docker、Registrator、Zookeeper 實現的服務自動注冊

hallen 7年前發布 | 35K 次閱讀 Docker ZooKeeper Kubernetes

基于Docker、Registrator、Zookeeper實現的服務自動注冊

本文所有服務均采用docker容器化方式部署

當前環境

  1. 系統:Mac OS
  2. docker 1.12.1
  3. docker-compose 1.8.0

場景

在微服務架構中,傳統的大型單一應用會根據業務場景被拆分成眾多功能單一且獨立自治的微型服務。每個服務模塊不僅能獨立的對外暴露服務,而且根據業務需求,可以動態的進行擴容或縮減,充分利用了服務器資源。

但此架構引入了很多新的問題。其中一個是,隨著服務的增多,以及服務的動態擴容,服務地址(IP、Port)硬編碼的方式已經顯得不太合適。我們需要尋求一種機制,讓每個服務能動態的創建地址,同時調用方要能獲取到這些信息、且感知地址的動態變化。

注冊中心

為解決上述問題,業界給出的一種方案是使用注冊中心,通過服務的發布-訂閱模式,來解決上述場景,即所謂的 “服務的注冊&發現”。

舉例來講,大家過去是否有翻查電話簿打電話的經歷。有一天,你想給小明打個電話,可是不知道他的電話號碼是多少。于是去翻查電話簿上對方的電話信息,這里電話簿就是所謂的注冊中心,而翻查電話簿的動作就是屬于服務的發現過程,那么小明給出自己的電話號碼,由自己(或他人)記錄在電話簿上的動作就屬于服務的注冊過程。

理解了小明的例子,再來看服務注冊發現的流程,是不是一樣呢?

  1. 服務注冊:服務提供者將自身的服務信息注冊進注冊中心;
  2. 服務訂閱:服務消費者從注冊中心獲取服務信息,并對其進行監聽;
  3. 緩存服務信息:將獲取到的服務信息緩存到本地,減少與注冊中心的網絡通信;
  4. 服務調用:查找本地緩存,找到對應的服務地址,發送服務請求;
  5. 變更通知:當服務節點有變動時(服務新增、刪除等),注冊中心將通知監聽節點變化的消費者,使其更新服務信息。

服務注冊

回到小明的例子,小明有兩種方式將自己的電話寫入電話簿,一種是自己親自登記,一種是找他人代為登記。即所謂的服務 “自注冊” 與 “第三方注冊”。

  • 自注冊:服務內部啟動客戶端,連接注冊中心,寫入服務信息。

    • 問題:
      • 服務代碼對注冊中心進行了硬編碼,若更換了注冊中心,服務代碼也必須跟著調整;
      • 注冊中心必須與每個服務都保持通信,來做心跳檢測。如果服務很多時,對注冊中心也是一種額外的開銷;
      </li> </ul> </li>
    • 第三方注冊(本文采用方式):采用協同進程的方式,監聽服務進程的變化,將服務信息寫入注冊中心。

      • 好處:做到了服務與注冊中心的解耦,對服務而言,完成了服務的自動化注冊;
      • 問題:協同進程本身也要考慮高可用,否則將成為單點故障的風險點;
      • </ul> </li> </ul>

        考慮篇幅原因,服務消費者相關內容將在下篇進行講述

        技術方案

        服務注冊中心:作為整個架構中的核心,注冊中心要做到的是支持分布式、支持持久化存儲。可以把它想象成一個集中化管理的中心服務器。同時負責將服務注冊信息的變動實時通知給服務消費者。

        這里,技術上我們選用的 ZK (ZooKeeper) 。大家可以把 ZK 想象成文件服務器,注冊中心在 ZK 中的展現就是節點路徑圖,每個節點下存放者相應的服務信息,ZK路徑圖如下:

        服務提供者:服務以 docker 容器化方式部署(實現服務端口的動態生成),并以 docker-compose 的方式來管理,這里包含各種語言實現的服務(如JAVA、PHP等),通過 Registrator 完成服務的自動注冊。

        技術說明

        Docker:是一個開源工具,能將一個WEB應用封裝在一個輕量級,便攜且獨立的容器里,然后可以運行在幾乎任何服務環境下。 Docker的一般使用在以下幾點: 自動化打包和部署應用。

        Docker-compose:是一個用來定義、啟動和管理服務的工具,通過compose配置文件,將一個或多個 Docker 容器組合成一個服務。并通過簡單的命令對服務進行管理,如啟動、銷毀、水平擴展等等。

        Registrator:一個由Go語言編寫的,針對docker使用的,通過檢查容器在線或者停止運行狀態自動注冊和去注冊服務的工具。

        ZK:作為一個分布式服務框架,是 Apache Hadoop 的一個子項目,它主要是用來解決分布式應用中經常遇到的一些數據管理問題,如:統一命名服務、狀態同步服務、集群管理、分布式應用配置項的管理等等。

        示例

        代碼地址: https://github.com/jasonGeng88/service_registry_discovery

        示例主要從3個方面演示:

        1. 框架搭建
        2. 服務準備
        3. 場景演示

        框架搭建:

        ZK 部署

        當前位置: 項目根目錄

        • zookeeper/docker-compose.yml ( 為演示方便,這里在單臺機器上運行 ):
        version: '2' #docker-compose版本
        services:
            zoo1:
                image: zookeeper
                restart: always
                ports:

                - 2181:2181
            environment:
                ZOO_MY_ID: 1
                ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
        
        zoo2:
            image: zookeeper
            restart: always
            ports:
                - 2182:2181
            environment:
                ZOO_MY_ID: 2
                ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
        
        zoo3:
            image: zookeeper
            restart: always
            ports:
                - 2183:2181
            environment:
                ZOO_MY_ID: 3
                ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888</pre> 
        

        • 啟動命令( 執行上述文件
        cd zookeeper && docker-compose up -d
        • 查看結果

        Registrator 部署

        當前位置: 項目根目錄

        • registrator/docker-compose.yml
        version: '2'
        services:
          registrator1:
            image: gliderlabs/registrator
            restart: always
            network_mode: "host"
            volumes:

          - /var/run/docker.sock:/tmp/docker.sock
        # -ip 設置服務寫入注冊中心的IP地址
        # zookeeper:// 設置連接的 ZK 協議、地址、注冊的根節點
        command: "-ip 127.0.0.1 zookeeper://127.0.0.1:2181/services"
        
        

        registrator2: image: gliderlabs/registrator restart: always network_mode: "host" volumes:

          - /var/run/docker.sock:/tmp/docker.sock
        command: "-ip 127.0.0.1 zookeeper://127.0.0.1:2182/services"
        
        

        registrator3: image: gliderlabs/registrator restart: always network_mode: "host" volumes:

          - /var/run/docker.sock:/tmp/docker.sock
        command: "-ip 127.0.0.1 zookeeper://127.0.0.1:2183/services"</pre> 
        

        • 啟動命令
        cd registrator/ && docker-compose up -d
        • 查看結果

        目前框架已搭建完畢,我們來連接一臺ZK,來觀察節點情況:

        進入 ZK 容器

        docker exec -it zookeeper_zoo1_1 /bin/bash

        連接 ZK

        zkCli.sh -server 127.0.0.1:2181</pre>

        服務準備:

        項目中為演示準備了2個服務,分別是用JAVA、PHP實現的。

        java_service_1(由springboot實現):

        當前位置: services/java_service_1

        • 啟動文件
        package com.example;

        import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;

        @RestController @SpringBootApplication public class DemoApplication {

        @RequestMapping("/")
        String home() {
            return "This is Service 1.";
        }
        
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
        

        }</pre>

        • 生成 jar 文件

        這里使用 Spring Boot CLI 進行打包

        spring jar ROOT.jar src/main/java/com/example/DemoApplication.java
        • 構建鏡像

        java_service_1 為你要構建的鏡像名,tag默認為latest

        docker build -t java_service_1 .</pre>

        php_service_2:

        當前位置: services/php_service_2

        • index.php
        <?php

        echo 'This is Service 2.'; </pre>

        • 構建鏡像

        php_service_2 為你要構建的鏡像名,tag默認為latest

        docker build -t php_service_2 .</pre>

        現兩個服務鏡像以構建完畢,展示如下:

        場景演示:

        當前位置: services

        • 場景 1: 啟動 service_1(JAVA)服務
        docker-compose up -d service_1

        查看 ZK 節點情況

        • 場景 2: 啟動service_2(PHP)服務
        docker-compose up -d service_2

        查看 ZK 節點情況

        • 場景 3: 擴展service_2(PHP)服務,個數為2
        docker-compose up -d service_2

        查看 ZK 節點情況

        • 場景 4: 注銷service_1(JAVA)服務
        docker-compose up -d service_2

        查看 ZK 節點情況

        優化點

        • 在生產環境中,zk安全連接、節點訪問控制都是需要注意的。簡單做法,可以把連接地址改成內網IP,添加防火墻策略來限制連接客戶端。

        • Registrator這里采用的是其多個進程分別連接不同的節點,來防止Registrator的單點故障。由于Registrator所用開銷較小,在服務數量與ZK節點數量不大的情況下,不會產生問題。 較好的方式是:Registrator提供失效自動地址切換功能( 目前官方文檔好像沒有提供此方案,有了解的同學可以留言告訴我 )。

        總結

        本文從介紹何為 “服務注冊&發現” 切入,以通俗易懂的語言介紹了其內在的本質,最后講到了實現的所用的具體技術方案,以及以 Demo 的方式,演示了 Registrator 是如何做到服務的自動化注冊的。

        當然,這只是實現的一種形式。注冊中心用 etcd、consul 也都是可行的,而且 Registrator 官方最好的支持是 consul。我們這里就不細究它們的差別了,找到適合自己、滿足業務的就是最好的 :blush: 。

        后續

        1. 服務發現機制與實現

         

        來自:https://github.com/jasonGeng88/blog/blob/master/201703/service_registry.md

         

 本文由用戶 hallen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!