Apollo 設定中心的部署與使用經驗

2023-10-31 21:00:30

前言

Apollo(阿波羅)是攜程開源的分散式設定管理中心。

本文主要介紹其基於 Docker-Compose 的部署安裝和一些使用的經驗

特點

  • 成熟,穩定
  • 支援管理多環境/多叢集/多名稱空間的設定
  • 設定修改釋出實時(1s)通知到應用程式
  • 支援許可權控制、設定繼承,版本管理,灰度釋出,使用監控等
  • 官方提供了 。NET/Java/Go 的 SDK 以及 Http 介面
  • 國產中文,檔案友好,大廠背書,使用方案成熟
  • 使用簡單,支援 Docker , K8S,官方也提供多種高可用方案參考

使用情況

  • 目前在微服務專案中做為設定中心,表現穩定,體驗良好
  • 記憶體情況:新安裝啟動在 100M 左右,工作中實際 20 專案,80 使用者端使用時,三個服務佔 1.5G 左右
  • 測試環境和生產環境分開,安全及避免錯誤操作
  • 為什麼選擇 Apollo:穩定&簡單,雖然比不上 Nacos 的效能,也沒有服務發現功能,但是穩定啊!!!
  • 在我自己部署前,會覺得這個東西好難,好重,好麻煩。寫這篇文章的時候的感受只有兩個字:牛*

實踐

準備

  • 當前版本:v2.1

  • apollo-db:mysql 5.6.6+ 資料庫

    • 預設埠:3306
    • 依賴兩個資料庫:ApolloPortalDB,ApolloConfigDB
    • 預設賬號/密碼:apollo/admin
  • apollo-configservice:Config Service 提供設定的讀取、推播等功能。

    • 預設埠:8080
    • 應用程式端連線到此服務使用
  • apollo-adminservice: Admin Service 提供設定的修改、釋出等功能

    • 預設埠:8090
    • 管理介面使用此服務
  • apollo-portal:Portal 提供 Web 介面用來管理設定

    • 預設埠:8070
    • Web 管理介面
    • 預設賬號/密碼:apollo/admin
  • Deureka:提供服務註冊和發現

    • Config Service 和 Admin Service 會向 Eureka 註冊服務,並保持心跳
    • 在 Admin Service 需要指定 eureka.service.url
  • 服務設定方式的優先順序從高到低分別為:系統引數>環境變數>外部組態檔

使用 Docker Compose 安裝

本篇文章基於 Docker V24 及 Docker Compose V2,安裝可以參考之前的文章

設定說明

  • 掛載了紀錄檔檔案到。/logs 目錄
  • 固定了映象版本 mysql v5.7 , apollo v2.1.0
  • 指定 MySql 賬號密碼: root devops666 ,修改了埠對映 13306:3306
  • 掛載 MySql 資料,初始化指令碼資料夾 。/initsql(v2.1 指令碼
  • Apollo 服務中使用服務名 apollo-db 連線 MySql:SPRING_DATASOURCE_URL:'...apollo-db:3306/...'
  • 設定先啟動資料庫:depends_on:apollo-db
  • apollo-configservice 服務中指定向 Deureka(Apollo 服務發現元件)註冊的地址:http://192.168.123.214:8080
  • apollo-adminservice 服務中指定向 Deureka 註冊的服務地址:http://192.168.123.214:809
  • apollo-adminservice 服務需指定 Deureka 服務地址-Deureka.service.url=``http://192.168.123.214:8080/eureka/
  • 指定網路:devopsnetwork (docker network create devopsnetwork)
  • web 管理端預設賬號密碼:apollo admin,登入後修改!!!

組態檔 compose.yml

  • 準備好 compose.yml 及 。/initsql/初始化指令碼,修改其中的 IP

  • 拷貝到伺服器

  • 然後執行docker compose up -d即可

     version: '3.1'
     services:
       # Apollo資料庫
       apollo-db:
         image: mysql:5.7
         container_name: apollo_db_5_7
         restart: always
         environment:
           TZ: Asia/Shanghai
           MYSQL_ROOT_PASSWORD: 'devops666'
         ports:
           - "13306:3306"
         volumes:
           - ./initsql:/docker-entrypoint-initdb.d
           - ./data:/var/lib/mysql
         networks:
           - devopsnetwork
    
       # Apollo 服務發現註冊中心
       apollo-configservice:
         container_name: apollo_configservice_2_1
         image: apolloconfig/apollo-configservice:2.1.0
         restart: always
         depends_on:
           - apollo-db
         environment:
           SPRING_DATASOURCE_URL: 'jdbc:mysql://apollo-db:3306/ApolloConfigDB?characterEncoding=utf8'
           SPRING_DATASOURCE_USERNAME: 'root'
           SPRING_DATASOURCE_PASSWORD: 'devops666'
           JAVA_OPTS: "-Deureka.instance.homePageUrl=http://192.168.123.214:8080"
           # EUREKA_INSTANCE_HOME_PAGE_URL: http://192.168.123.214:8080
           # EUREKA_INSTANCE_PREFER_IP_ADDRESS: false
         volumes:
           - ./logs:/opt/logs
         ports:
           - "8080:8080"
         networks:
           - devopsnetwork
    
       #核心介面服務
       apollo-adminservice:
         container_name: apollo_adminservice_2_1
         image: apolloconfig/apollo-adminservice:2.1.0
         restart: always
         environment:
           SPRING_DATASOURCE_URL: 'jdbc:mysql://apollo-db:3306/ApolloConfigDB?characterEncoding=utf8'
           SPRING_DATASOURCE_USERNAME: 'root' 
           SPRING_DATASOURCE_PASSWORD: 'devops666'
           JAVA_OPTS: "-Deureka.instance.homePageUrl=http://192.168.123.214:8090 -Deureka.service.url=http://192.168.123.214:8080/eureka/ "
         depends_on:
           - apollo-db
         ports:
           - "8090:8090"
         volumes:
           - ./logs/:/opt/logs      
         networks:
           - devopsnetwork
           
      
       apollo-portal:
         image: apolloconfig/apollo-portal:2.1.0
         container_name: apollo_portal_2_1
         restart: always
         environment:
           SPRING_DATASOURCE_URL: 'jdbc:mysql://apollo-db:3306/ApolloPortalDB?characterEncoding=utf8'
           SPRING_DATASOURCE_USERNAME: 'root'
           SPRING_DATASOURCE_PASSWORD: 'devops666'
           APOLLO_PORTAL_ENVS: 'dev'      
           DEV_META: 'http://192.168.123.214:8080'
           # 預設賬號 apollo admin
         depends_on:
           - apollo-db
         ports:
           - "8070:8070"
         volumes:
           - ./logs/:/opt/logs         
         networks:
           - devopsnetwork
    
     networks:
       devopsnetwork:
         external: true
     ```
    
    

部署成功

部署機器IP:192.168.123.214

使用 K8S 安裝

跟著官方檔案一步步來即可,helm 的檔案可以從 apolloconfig/apollo-helm-chart 獲取,這裡只分享下步驟和些注意的地方

  1. 初始化資料庫

    1. 可以使用已有或者部署 mysql 服務,並建立 apollo 專門的賬號密碼
    2. 執行 Apollo 對應版本的 v2.1 預設初始化指令碼 建立 ApolloConfigDB,ApolloPortalDB
    3. 生產環境 記得修改 ServerConfig 表的 環境和組織apollo.portal.envs:pro organizations:[{"orgId":"xxx","orgName":"xxx公司"}]
  2. 使用 helm 新增 apollo repo

  3. 安裝 apollo-service

  4. 安裝 apollo-portal

  5. k8s 使用

    • 可以將 Apollo 相關設定儲存到 k8s 的 ConfigMap 中方便 k8s 服務中使用

使用

.NET SDK

官方:Com.Ctrip.Framework.Apollo.Configuration

  1. 新增包:Com.Ctrip.Framework.Apollo.Configuration

  2. appsetting.json 中新增 apollo 設定

    1. MetaServer:Apollo 服務地址,系統資訊中也可以檢視到
    2. AppId:應用 Id
    3. Namespaces:名稱空間預設是 application
  3. 獲取引數註冊:可以是設定,也可以是從環境變數中

    builder.Configuration.AddApollo(builder.Configuration.GetSection("apollo"));

  4. 注入 IConfiguration 使用即可

連線設定

  "apollo": {
    "MetaServer": "http://192.168.123.214:8080",
    "AppId": "devops.test",
    "Namespaces": [ "application" ]
  }

Demo 範例

dotnet v7.0

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddApollo(builder.Configuration.GetSection("apollo"));
app.MapGet("/config", context =>
{
    context.Response.Headers["Content-Type"] = "text/html; charset=utf-8";
    //設定服務
    var configService = context.RequestServices.GetRequiredService<IConfiguration>();
    string? key = context.Request.Query["key"];
    if (string.IsNullOrWhiteSpace(key))
    {
        return context.Response.WriteAsync("獲取設定:/config?key=test");
    }
    var value = configService[key];
    return context.Response.WriteAsync(value ?? "undefined");
});

完整 Demo 範例 :Github 地址

踩過的坑

  • 資料庫設定連線,使用服務名,而不是容器名
  • -Deureka.instance.homePageUrl 和 -Deureka.service.url 引數一開始沒有理解到是做什麼的,只知道設定健康檢查失敗,看了檔案才理解到是 Deureka.instance.homePageUrl 是註冊的服務地址,-Deureka.service.url 是註冊中心的介面地址

相關檔案

後語

時間充裕的情況最好是過一遍檔案,知道是怎麼設計的,遇到問題真會一頭霧水。

每天進步一點,哪怕只是一點!