可能是Asp.net Core On host、 docker、kubernetes(K8s) 配置讀取的最佳實踐

喬達摩發表於2020-08-03

寫在前面

為了不違反廣告法,我竭盡全力,不過“最佳實踐”確是標題黨無疑,如果硬要說的話 只能是個人最佳實踐。

問題引出

​ 可能很多新手都會遇到同樣的問題:我要我的Asp.net Core 應用傳統方式直接部署(host),docker部署(docker-compose),kubernetes(以下稱k8s)下部署,都用統一的方式讀取配置,怎麼實現呢?。

​ 大家知道,我們預設平時配置檔案以appsettings.jsonappsettings.{EnvironmentName}.json 形式存在,這樣在host方式下面沒有問題,但在docker下,如果直接把配置打包到映象,那每次改一下下配置就需要重新打包,那成本太大了。另外在k8s下面又有Secret、ConfigMap等多種方式管理配置,如何把多種配置儲存和讀取,有機結合、同一份程式碼統一管理使用,是我們今天的主題。

​ 下面我用一個Api閘道器Ocelot作為示例(demo),講講我處理的方式,希望能給大家帶來一定啟發。

一、先把配置檔案改成Yaml格式

注:

其實不改為yml也可以的!!

主要考慮到後面在docker、k8s等裡面,更好管理,比如yaml的註釋和json的註釋語法不一致等等問題;

比如我原來的appsettings.json長這樣:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "AddAdministration": {
    "Path": "/administration",
    "IdentityServer": {
      "Authority": "http://172.16.3.117:5100", 
      "ApiName": "ocelot",
      "RequireHttpsMetadata": false,
      "ApiSecret": "secret"
    }
  }
}


改成 appsettings.yml

Logging:
  LogLevel:
    Default: Information
    Microsoft: Warning
    Microsoft.Hosting.Lifetime: Information
AllowedHosts: '*'
AddAdministration:
  Path: /administration
  IdentityServer:
    Authority: 'http://172.16.3.117:5100'
    ApiName: ocelot
    RequireHttpsMetadata: false
    ApiSecret: secret

是不是看起來簡單清晰了很多,其實我現在越來越喜歡用yml了

既然配置源的格式變了,那讀取配置的方法也肯定變了,起碼config.AddJsonFile(“xx.json”) 要改為 config.AddYamlFile(“xx.yml”)

新增引用的擴充套件:NetEscapades.Configuration.Yaml

載入配置檔案改寫為:

 .AddYamlFile("appsettings.yml", optional: false, reloadOnChange: true)
 .AddYamlFile($"appsettings.{env.EnvironmentName}.yml", optional: true, reloadOnChange: true)

二、Docker使用

“但在docker下,如果直接把配置打包到映象,那每次改一下下配置就需要重新打包,那成本太大了”

我前面提出了這個問題,如想不重新打包,Volume(掛載)就好了。

把你的配置檔案放到/home/heidemo/config目錄後,比如我們什麼的示例配置檔案: appsettings.yml

docker run --rm=true -v /home/heidemo/config:/config   gebiwangshushu/hei-ocelot-apigateway:1.0

這樣就可以隨性更新/home/heidemo/config下的配置資訊而不需要每次都重新build映象了,這樣是支援熱更新的,當然如果你修改的那個配置是需要重啟程式才可以載入的,那還是要用docker-compose 重啟下對應服務的;

三、docker-compose使用

我們知道 Docker是 官方編排(Orchestration)專案之一,如果我們在Docker環境下掛載配置的話,那在docker-compose下面的配置也是掛載的,我們來看下我們掐頭去尾後的 docker-compose.yml:

version: '3.4'

services:
  hei.ocelot.apigateway:
    ...
    
    volumes:
      - /home/heidemo/config:/app/config
    
    ...

沒錯,docker-compose 額掛載就這麼定義,這樣可以實現跟Docker一樣的掛載效果;

大家可以用以上配置 clone我的demo,然後 docker-compose up 一下,看看效果;

四、k8s使用

前面的docker、docker-compose 的方式還是非常容易理解的,就是掛載;那我們在k8s下面執行的時候,它的容器例項是動態的執行到叢集的各臺機器上的,那如果我們我們只用檔案掛載很明顯就不滿足要求了,我們來看看怎麼實現。

先準備一個configMap,hei-ocelot-config.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: hei-ocelot-apigateway
  namespace: dotnetcore
data:
  appsettings.yml: |
    Logging:
      LogLevel:
        Default: Information
        Microsoft: Warning
        Microsoft.Hosting.Lifetime: Information
    AllowedHosts: '*'
    AddAdministration:
      Path: /administration
      IdentityServer:
         Authority: 'http://172.16.1.30:31100' #這裡的授權中心可以配置你自己的
        ApiName: ocelot
        RequireHttpsMetadata: false
        ApiSecret: secret

完整請看這裡

大家可以看到,我們的data節點是跟我們程式裡面的appsettings.json一樣一樣的,這也是我們比較喜歡不再用json的原因。

建立configMap:

kubectl apply -f hei-ocelot-config.yml

檢視configMap:

kubectl describe configmaps hei-ocelot-apigateway -n dotnetcore

1596101753461

使用configMap:

這裡是使用示例,在我的demo根目錄下面完整配置deploy.yml 是可以直接部署的。

apiVersion: apps/v1
kind: Deployment
metadata:
 name: hei-ocelot-apigateway 
 namespace: dotnetcore
spec:
 replicas: 1
 selector:
  matchLabels:
   app: hei-ocelot-apigateway 
 template:
  metadata:
   labels:
    app: hei-ocelot-apigateway 
  spec:
   containers:
    - name: hei-ocelot-apigateway 
      image: gebiwangshushu/hei-ocelot-apigateway:1.1
      ports:
       - containerPort: 80
      volumeMounts:
       - name: hei-ocelot-apigateway
         mountPath: "/app/config"
         readOnly: true
   volumes:
    - name: hei-ocelot-apigateway
      configMap:
       name: hei-ocelot-apigateway

可以看到我們在k8s下面也是用volumes的方式使用我們的configMap的,其中掛載目錄volumeMounts:mountPath是"/app/config",我們進入執行中pod看下配置:

kubectl exec -it hei-ocelot-apigateway-795495f7c8-vpmhb sh -n dotnetcore

cd /app/config 

我們可以看到我們的pod裡面的/app/config ,確確實實有我們要的配置;

1596383131953

這裡因為我們是volumes 的方式的,大家可以試著改下上面的configMap-- hei-ocelot-config.yml 再重新apply 一下,會看到這裡的配置是幾乎是即時更新的(有一點點延遲);

PS:有一個問題有些在startup使用的配置,即時更新了也需要重啟下應用,這個我暫時還沒想到什麼辦法好辦法,各位老哥有什麼思路的可以直接甩我一臉~

總結

其實寫完我覺得也有點怪怪,說新手引導吧,不夠保姆式、說經驗分享,不夠精簡,下次我定好好想,認真寫好點;

然後我的主題,其實思考過同樣問題的讀者,全文就一句:volumes掛載配置做到各種環境下的配置統一;

最後,我丟擲了一個問題:On K8s的時候, 程式啟動使用的配置,如何在配置檔案更新的情況後重啟程式應用新配置(或者叫熱載入配置?當然這裡不是指配置檔案的reloadOnChange=true);

github:https://github.com/gebiWangshushu/Hei.Ocelot.ApiGateway

相關文章