寫在前面
為了不違反廣告法,我竭盡全力,不過“最佳實踐”確是標題黨無疑,如果硬要說的話 只能是個人最佳實踐。
問題引出
可能很多新手都會遇到同樣的問題:我要我的Asp.net Core 應用傳統方式直接部署(host),docker部署(docker-compose),kubernetes(以下稱k8s)下部署,都用統一的方式讀取配置,怎麼實現呢?。
大家知道,我們預設平時配置檔案以appsettings.json
、appsettings.{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
使用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 ,確確實實有我們要的配置;
這裡因為我們是volumes 的方式的,大家可以試著改下上面的configMap-- hei-ocelot-config.yml 再重新apply 一下,會看到這裡的配置是幾乎是即時更新的(有一點點延遲);
PS:有一個問題有些在startup使用的配置,即時更新了也需要重啟下應用,這個我暫時還沒想到什麼辦法好辦法,各位老哥有什麼思路的可以直接甩我一臉~
總結
其實寫完我覺得也有點怪怪,說新手引導吧,不夠保姆式、說經驗分享,不夠精簡,下次我定好好想,認真寫好點;
然後我的主題,其實思考過同樣問題的讀者,全文就一句:volumes掛載配置做到各種環境下的配置統一;
最後,我提出了一個問題:程式啟動使用的配置,如何在配置檔案更新的情況後重啟程式應用新配置(或者叫熱載入配置?當然這裡不是指配置檔案的reloadOnChange=true);
github:https://github.com/gebiWangshushu/Hei.Ocelot.ApiGateway