1. 程式人生 > >.NET Core + K8S + Apollo 玩轉配置中心

.NET Core + K8S + Apollo 玩轉配置中心

![](https://upload-images.jianshu.io/upload_images/2799767-43736dd236959afc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # 1.引言 >Apollo(阿波羅)是攜程框架部門研發的分散式配置中心,能夠集中化管理應用不同環境、不同叢集的配置,配置修改後能夠實時推送到應用端,並且具備規範的許可權、流程治理等特性,適用於微服務配置管理場景。 如官網所述:Apollo 是攜程打造的開源配置中心,[GitHub](https://github.com/ctripcorp/apollo)的星星也快點滿22K,因此足見它的成熟度和社群活躍度。因此最近在做配置中心選型的時候,經過一番預演,最終敲定Apollo。 Apollo作為微服務體系中必不可少的基礎服務,其架構設計和基本使用我們不得不有所瞭解。 因此本文接下來將主要來介紹如何基於Helm快速部署Apollo叢集至K8S,並與.NET Core應用進行整合,同時介紹下如何平滑遷移配置到Apollo。 **本文具有詳細的部署步驟,建議動手實操。 部署Chart包和Demo已上傳至GitHub:[K8S.NET.Apollo](https://github.com/sheng-jie/dotnet.on.k8s/tree/master/K8S.NET.Apollo),可收藏備用。** # 2. Apollo 架構一覽 在部署之前,需要了解Apollo的基礎架構,以便在後續部署工作的展開。 ![Apollo 總體設計](https://upload-images.jianshu.io/upload_images/2799767-f467670ed9cee888.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 關於其的解讀,我這裡就不再詳細展開,但以下幾點還是要有所瞭解,感興趣的可以直接看官網詳細介紹:[Apollo配置中心設計](https://github.com/ctripcorp/apollo/wiki/Apollo配置中心設計)。 1. Config Service提供配置的讀取、推送等功能,服務物件是Apollo客戶端 2. Admin Service提供配置的修改、釋出等功能,服務物件是Apollo Portal(管理介面) 3. Config Service和Admin Service都是多例項、無狀態部署,需要通過註冊中心進行服務註冊和發現 4. 註冊中心預設採用的是Eureka,在K8S中由Service充當 5. Apollo客戶端通過註冊中心獲取Config Service服務列表進行配置讀取 6. Apollo Portal通過註冊中心獲取Admin Service服務列表進行配置管理 基於上面對Apollo的介紹,其物理架構總結起來就是: 1. 每一套環境都必須擁有自己獨立的Config Service 和 Admin Service 以及獨立ConfigDB。 2. 多套環境可以公用一套Apollo Portal 進行管理,Portal擁有獨立PortalDB。 # 3. 基於Helm部署到K8S 因為Apollo 1.7.0版本增加了基於Kubernetes原生服務發現的部署模式,來替換內建的Eureka,所以在整體部署上有很大簡化,同時官方也提供了Helm Charts,讓Apollo更加易於開箱即用。下面就以部署一套測試環境為例講解一下Apollo的部署要點。(部署至本機Docker Desktop Local K8S環境)。 *環境要求: Kubernetes 1.10+,Helm 3* ![](https://upload-images.jianshu.io/upload_images/2799767-e92736ebe551b07b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ## 3.1 搭建 Apollo Config&Portal DB 從上圖的物理架構上來看,首先要部署好Config DB和PortalDB。關於DB的搭建,建議直接使用`bitnami/mysql`chart搭建。搭建步驟如下: ``` > helm repo add bitnami https://charts.bitnami.com/bitnami > helm repo list > helm repo update > helm search repo bitnami/mysql NAME CHART VERSION APP VERSION DESCRIPTION bitnami/mysql 6.14.8 8.0.21 Chart to create a Highly available MySQL cluster ``` 執行helm包的安裝,需要自定義配置檔案,也就是`values.yaml`。我們可以先行下載 mysql chart包。 > 之所以選擇將chart包下載到本地,是為了確保後續維護能夠基於一致的chart包版本。避免因為執行`helm repo update`導致chart包版本自動升級,而不自知。 ``` > helm pull bitnami/mysql --untar //下載並解包 mysql ├── Chart.yaml ├── ci │ └── values-production.yaml ├── files │ └── docker-entrypoint-initdb.d │ └── README.md ├── README.md ├── templates │ ├── initialization-configmap.yaml │ ├── master-configmap.yaml │ ├── master-statefulset.yaml │ ├── master-svc.yaml │ ├── NOTES.txt │ ├── secrets.yaml │ ├── serviceaccount.yaml │ ├── servicemonitor.yaml │ ├── slave-configmap.yaml │ ├── slave-statefulset.yaml │ ├── slave-svc.yaml │ └── _helpers.tpl ├── values-production.yaml └── values.yaml ``` 根據官網[分散式部署指南](https://github.com/ctripcorp/apollo/wiki/分散式部署指南)中所示,其提供了DB的初始化指令碼用來分別建立`ApolloConfigDB`和`ApolloPortalDB`。因此可以直接將以上SQL指令碼下載到mysql chart的`files/docker-entrypoint-initdb.d`目錄下,這樣在部署mysql例項時就會自動執行指令碼建立資料庫。 ``` > cd mysql/files/docker-entrypoint-initdb.d > curl https://raw.githubusercontent.com/ctripcorp/apollo/master/scripts/sql/apolloportaldb.sql > apolloportaldb.sql //下載apolloportaldb.sql > curl https://raw.githubusercontent.com/ctripcorp/apollo/master/scripts/sql/apolloconfigdb.sql > apolloconfigdb.sql 下載apolloconfigdb.sql > ls Directory: C:\Users\Shengjie\k8s\helm\charts\apollo\mysql\files\docker-entrypoint-initdb.d Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 8/12/2020 11:01 PM 21291 apolloconfigdb.sql -a--- 8/12/2020 10:56 PM 16278 apolloportaldb.sql -a--- 8/9/2020 6:26 PM 242 README.md ``` 然後複製`values.yaml`並命名為`dev-mysql-values.yaml`。然後修改核心配置: 1. global.storageClass=hostpath 可通過`kubectl get sc`檢視叢集支援的storageClass,我這邊選擇預設的hostpath。其建立的pv的預設回收策略為delete,也就意味著解除安裝mysql,資料直接刪除,這點需要注意!!!如果需要保留測試資料,請更新storageClass。 2. root.password=root 修改預設root使用者的密碼 修改完畢後,執行以下指令碼進行安裝: ``` > kubectl create ns db #建立單獨db名稱空間 > helm install mysql-apollo . -f dev-mysql-values.yaml -n db NAME: mysql-apollo LAST DEPLOYED: Sun Aug 16 11:01:18 2020 NAMESPACE: db STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Please be patient while the chart is being deployed Tip: Watch the deployment status using the command: kubectl get pods -w --namespace db Services: echo Master: mysql-apollo.db.svc.cluster.local:3306 echo Slave: mysql-apollo-slave.db.svc.cluster.local:3306 Administrator credentials: echo Username: root echo Password : $(kubectl get secret --namespace db mysql-apollo -o jsonpath="{.data.mysql-root-password}" | base64 --decode) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-apollo-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.21-debian-10-r17 --namespace db --command -- bash 2. To connect to master service (read/write): mysql -h mysql-apollo.db.svc.cluster.local -uroot -p my_database 3. To connect to slave service (read-only): mysql -h mysql-apollo-slave.db.svc.cluster.local -uroot -p my_database To upgrade this helm chart: 1. Obtain the password as described on the 'Administrator credentials' section and set the 'root.password' parameter as shown below: ROOT_PASSWORD=$(kubectl get secret --namespace db mysql-apollo -o jsonpath="{.data.mysql-root-password}" | base64 --decode) helm upgrade mysql-apollo bitnami/mysql --set root.password=$ROOT_PASSWORD ``` 按照上面提示,驗證資料庫成功建立: ``` > kubectl run mysql-apollo-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.21-debian-10-r17 --namespace db --command -- bash # 建立mysql-client pod I have no name!@mysql-apollo-client:/$ mysql -h mysql-apollo.db.svc.cluster.local -uroot -proot # 連線至master 節點 mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 61 Server version: 8.0.21 Source distribution Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; # 檢視databases; +--------------------+ | Database | +--------------------+ | ApolloConfigDB | | ApolloPortalDB | | information_schema | | my_database | | mysql | | performance_schema | | sys | +--------------------+ 7 rows in set (0.00 sec) mysql> use ApolloConfigDB; # 切換至ApolloConfigDB; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; # 檢視資料表; +--------------------------+ | Tables_in_ApolloConfigDB | +--------------------------+ | AccessKey | | App | | AppNamespace | | Audit | | Cluster | | Commit | | GrayReleaseRule | | Instance | | InstanceConfig | | Item | | Namespace | | NamespaceLock | | Release | | ReleaseHistory | | ReleaseMessage | | ServerConfig | +--------------------------+ 16 rows in set (0.01 sec) ``` 至此,確認Apollo ConfigDB和PortalDB搭建成功。 ## 3.2 搭建 Apollo Config Service 搭建Apollo Service 需要新增攜程官方chart倉庫: ``` > helm repo add apollo http://ctripcorp.github.io/apollo/charts > helm search repo apollo NAME CHART VERSION APP VERSION DESCRIPTION apollo/apollo-portal 0.1.0 1.7.0 A Helm chart for Apollo Portal apollo/apollo-service 0.1.0 1.7.0 A Helm chart for Apollo Config Service and Apol... ``` 從上可知,主要包含兩個chart,分別用來部署service和portal。下來研究下apollo/apollo-service 這個chart。老規矩,先把chart包下載下來: ``` > helm pull apollo/apollo-service --untar apollo-service ├── Chart.yaml ├── templates │ ├── deployment-adminservice.yaml │ ├── deployment-configservice.yaml │ ├── NOTES.txt │ ├── service-adminservice.yaml │ ├── service-configdb.yaml │ ├── service-configservice.yaml │ └── _helpers.tpl └── values.yaml ``` 從上面的樹形圖來看,主要就是用來部署config service 和 admin service。緊接著,複製一個`values.yaml`,命名為`dev-apollo-svc-values.yaml`。主要修改以下配置: 1. configdb.host=mysql-apollo.db 指定configdb的主機,因為是在叢集內部,直接使用服務名即可 2. configdb.password=root 指定configdb的祕密 修改後的配置如下: ``` configdb: name: apollo-configdb # apolloconfigdb host host: "mysql-apollo.db" port: 3306 dbName: ApolloConfigDB # apolloconfigdb user name userName: "root" # apolloconfigdb password password: "root" .... ``` 其他配置可以暫定不動,緊接著執行以下命令進行安裝: ``` > kubectl create ns apollo # 建立apollo 名稱空間 > helm install --dry-run --debug apollo-dev-svc . -f dev-apollo-svc-values.yaml -n apollo # 測試安裝,驗證模板生成的資原始檔是否有誤 > helm install apollo-dev-svc . -f dev-apollo-svc-values.yaml -n apollo NAME: apollo-dev-svc LAST DEPLOYED: Sun Aug 16 11:17:38 2020 NAMESPACE: apollo STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Get meta service url for current release by running these commands: echo http://apollo-dev-svc-apollo-configservice.apollo:8080 For local test use: export POD_NAME=$(kubectl get pods --namespace apollo -l "app=apollo-dev-svc-apollo-configservice" -o jsonpath="{.items[0].metadata.name}") echo http://127.0.0.1:8080 kubectl --namespace apollo port-forward $POD_NAME 8080:8080 ``` 這裡要記住上面的meta service url:`http://apollo-dev-svc-apollo-configservice.apollo:8080` 那如何確認正確部署了呢: ``` > kubectl get all -n apollo # 檢視apollo名稱空間下部署的資源 NAME READY STATUS RESTARTS AGE pod/apollo-dev-svc-apollo-adminservice-7d4468ff46-gw6h4 1/1 Running 0 3m26s pod/apollo-dev-svc-apollo-configservice-58d6c44cd4-n4qk9 1/1 Running 0 3m26s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/apollo-dev-svc-apollo-adminservice ClusterIP 10.99.251.14 8090/TCP 3m26s service/apollo-dev-svc-apollo-configservice ClusterIP 10.108.121.201 8080/TCP 3m26s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/apollo-dev-svc-apollo-adminservice 1/1 1 1 3m26s deployment.apps/apollo-dev-svc-apollo-configservice 1/1 1 1 3m26s NAME DESIRED CURRENT READY AGE replicaset.apps/apollo-dev-svc-apollo-adminservice-7d4468ff46 1 1 1 3m26s replicaset.apps/apollo-dev-svc-apollo-configservice-58d6c44cd4 1 1 1 3m26s ``` 從上可知暴露了兩個服務configservice和adminservice,來嘗試將configservice進行埠轉發到本地埠來看一下。 ``` > kubectl port-forward service/apollo-dev-svc-apollo-configservice 8080:8080 -n apollo # 轉發configservice到本地服務 Forwarding from 127.0.0.1:8080 -> 8080 Forwarding from [::1]:8080 -> 8080 ``` 使用瀏覽器訪問 [localhost:8080](http://localhost:8080),可以看到輸出`[{"appName":"apollo-configservice","instanceId":"apollo-configservice:http://apollo.shisheng.wang/config-svc","homepageUrl":"http://apollo.shisheng.wang/config-svc"},{"appName":"apollo-adminservice","instanceId":"apollo-adminservice:http://apollo.shisheng.wang/admin-svc","homepageUrl":"http://apollo.shisheng.wang/admin-svc"}]`。 至此說明,Apollo Service 搭建成功。 ## 3.3 搭建 Apollo Portal Service 同樣,先來下載portal chart包,並研究下目錄結構: ``` > helm pull apollo/apollo-portal --untar apollo-portal ├── Chart.yaml ├── templates │ ├── deployment-portal.yaml │ ├── ingress-portal.yaml │ ├── NOTES.txt │ ├── service-portal.yaml │ ├── service-portaldb.yaml │ └── _helpers.tpl └── values.yaml ``` 從上可知,portal 相對來說,主要是構建portal服務,並可以通過ingress暴露服務。複製一個`values.yaml`,命名為`dev-apollo-portal-values.yaml`。主要修改以下配置: 1. `ingress.enabled=true` 啟用ingress,並通過註解設定ingress controller,因為portal是個有狀態服務,所以要關注Sessiion狀態維持。以下主要是針對nginx-ingress-controller的配置,如果使用的其他的ingress-controller請注意更改。(nginx-ingress-controller的安裝,這裡就不具體展開了,可以簡單執行`helm install nginx bitnaim/nginx-ingress-controller` 安裝就好了。) ``` ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: / nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "route" hosts: - host: "apollo.demo.com" paths: ["/"] tls: [] ``` 2. 指定配置源 ,主要是envs和metaServers兩個配置項: `config.envs=dev` `config.metaServers.dev=http://apollo-dev-svc-apollo-configservice.apollo:8080`(上面部署apollo service輸出的apollo service url)*如果同時啟用開發、測試和生產環境。可以配置為:`envs: "dev,uat,prd"`,metaServers 分別指定對應環境的配置即可。* 以下是隻啟用開發環境的配置: ``` config: # spring profiles to activate profiles: "github,auth" # specify the env names, e.g. dev,pro envs: "dev" # specify the meta servers, e.g. # dev: http://apollo-configservice-dev:8080 # pro: http://apollo-configservice-pro:8080 metaServers: dev: http://apollo-svc-dev-apollo-configservice.apollo:8080 # dev: http://apollo.shisheng.wang # specify the context path, e.g. /apollo contextPath: "" # extra config files for apollo-portal, e.g. application-ldap.yml files: {} ``` 3. portaldb.host=mysql-apollo.db & portaldb.password=root 指定portaldb的主機和密碼 ``` portaldb: name: apollo-portaldb # apolloportaldb host host: mysql-apollo.db port: 3306 dbName: ApolloPortalDB # apolloportaldb user name userName: root # apolloportaldb password password: root ``` 其他配置可以暫定不動,緊接著執行以下命令進行安裝: ``` > Helm install --dry-run --debug apollo-dev-portal . -f dev-apollo-portal-values.yaml -n apollo # 測試安裝,驗證模板生成的資原始檔是否有誤 > Helm install apollo-dev-portal . -f dev-apollo-portal-values.yaml -n apollo PS C:\Users\Shengjie\k8s\helm\charts\apollo\apollo-portal> Helm install apollo-dev-portal . -f dev-apollo-portal-values.yaml -n apollo NAME: apollo-dev-portal LAST DEPLOYED: Sun Aug 16 11:53:18 2020 NAMESPACE: apollo STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Get apollo portal url by running these commands: http://apollo.demo.com/ ``` 到這一步,如果需要本地可以訪問,還需要修改本地hosts,新增`127.0.0.1 apollo.demo.com`。然後開啟你的Browser輸入[http://apollo.demo.com/](http://apollo.demo.com/),就可以訪問了。預設使用者密碼是:[apollo/admin]。 ![apollo login page](https://upload-images.jianshu.io/upload_images/2799767-021717d0f5f8392c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # 3.4. 暴露 config service 以上部署的是開發環境,但要想開發環境要訪問到config service,我們還需要些小動作。這個時候就需要修改apollo service的chart模板,在`template`目錄增加`ingress-configservice.yaml`檔案,內容如下: ``` # ingress-configservice.yaml {{- if .Values.configService.ingress.enabled -}} {{- $fullName := include "apollo.configService.fullName" . -}} {{- $svcPort := .Values.configService.service.port -}} {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} apiVersion: networking.k8s.io/v1beta1 {{- else -}} apiVersion: extensions/v1beta1 {{- end }} kind: Ingress metadata: name: {{ $fullName }} labels: {{- include "apollo.service.labels" . | nindent 4 }} {{- with .Values.configService.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} spec: {{- if .Values.configService.ingress.tls }} tls: {{- range .Values.configService.ingress.tls }} - hosts: {{- range .hosts }} - {{ . | quote }} {{- end }} secretName: {{ .secretName }} {{- end }} {{- end }} rules: {{- range .Values.configService.ingress.hosts }} - host: {{ .host | quote }} http: paths: {{- range .paths }} - path: {{ . }} backend: serviceName: {{ $fullName }} servicePort: {{ $svcPort }} {{- end }} {{- end }} {{- end }} ``` 然後修改`values.yaml`在`configService`節點下增加`ingress`配置選項: ``` configService: name: apollo-configservice fullNameOverride: "" replicaCount: 2 containerPort: 8080 image: repository: apolloconfig/apollo-configservice pullPolicy: IfNotPresent imagePullSecrets: [] service: fullNameOverride: "" port: 8080 targetPort: 8080 type: ClusterIP # 以下為新增ingress配置項 ingress: enabled: false annotations: {} hosts: - host: "" paths: [] tls: [] ``` 然後再修改上面我們建立的`dev-apollo-svc-values.yaml`下的`configService`節點,新增對應`ingress`和`config.configServiceUrlOverride`配置: ``` configService: name: apollo-configservice fullNameOverride: "" replicaCount: 1 containerPort: 8080 image: repository: apolloconfig/apollo-configservice pullPolicy: IfNotPresent imagePullSecrets: [] service: fullNameOverride: "" port: 8080 targetPort: 8080 type: ClusterIP ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: /$2 hosts: - host: "apollo.demo.com" paths: ["/config-svc(/|$)(.*)"] tls: [] liveness: initialDelaySeconds: 100 periodSeconds: 10 readiness: initialDelaySeconds: 30 periodSeconds: 5 config: # spring profiles to activate profiles: "github,kubernetes" # override apollo.config-service.url: config service url to be accessed by apollo-client configServiceUrlOverride: "http://apollo.demo.com/config-svc" # override apollo.admin-service.url: admin service url to be accessed by apollo-portal adminServiceUrlOverride: "" ``` 修改完畢,執行以下命令升級apollo service: ``` > helm upgrade apollo-service-dev . -f dev-apollo-svc-values.yaml -n apollo NAME: apollo-service-dev LAST DEPLOYED: Tue Aug 18 14:20:41 2020 NAMESPACE: apollo STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Get meta service url for current release by running these commands: echo http://apollo-service-dev-apollo-configservice.apollo:8080 For local test use: export POD_NAME=$(kubectl get pods --namespace apollo -l "app=apollo-service-dev-apollo-configservice" -o jsonpath="{.items[0].metadata.name}") echo http://127.0.0.1:8080 kubectl --namespace apollo port-forward $POD_NAME 8080:8080 > curl http://apollo.demo.com/config-svc [{"appName":"apollo-configservice","instanceId":"apollo-configservice:http://apollo.demo.com/config-svc","homepageUrl":"http://apollo.demo.com/config-svc"},{"appName":"apollo-adminservice","instanceId":"apollo-adminservice:http://apollo-service-dev-apollo-adminservice.apollo:8090","homepageUrl":"http://apollo-service-dev-apollo-adminservice.apollo:8090"}] ``` 從上面的輸出可以看到,現在已經可以通過`http://apollo.demo.com/config-svc`讀取metaServer配置了,後面本地開發環境就可以通過這個連結來讀取Apollo的配置。 # 4. .NET Core 整合Apollo 這一部分我就快速帶過了,執行以下命令建立專案,並引入`apollo`和`swagger`相關包: ``` > dotnet new webapi -n K8S.NET.Apollo > cd K8S.NET.Apollo > dotnet add package Com.Ctrip.Framework.Apollo.Configuration > dotnet add package Swashbuckle.AspNetCore ``` 修改`appsettings.json`增加`apollo`配置: ``` { "AllowedHosts": "*", "apollo": { "AppId": "test", "MetaServer": "http://apollo.demo.com/config-svc", "Env": "Dev" } } ``` 修改`Program.cs`,新增Apollo配置源如下: ``` public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration(configBuilder => { configBuilder.AddApollo(configBuilder.Build().GetSection("apollo")) .AddDefault() .AddNamespace("TEST1.connectionstrings", "ConnectionStrings") .AddNamespace("logging", ConfigFileFormat.Json) ; }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); ``` 修改`Startup.cs`,新增Swagger整合,方便測試: ``` public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = this.GetType().Namespace, Version = "v1" }); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", $"{this.GetType().Namespace} V1"); c.RoutePrefix = string.Empty; }); //... } ``` 新增`ApolloController`,增加以下測試程式碼: ``` namespace K8S.NET.Apollo.Controllers { [ApiController] [Route("[controller]/[action]")] public class ApolloController : Controller { private readonly IConfiguration _configuration; public ApolloController(IConfiguration configuration) { _configuration = configuration; } [HttpGet("key")] public IActionResult GetLogLevelSection() { var key = "Logging:LogLevel"; var val = _configuration.GetSection(key).Get(); return Ok($"{key}:{JsonSerializer.Serialize(val)}"); } [HttpGet("key")] public IActionResult GetString(string key) { var val = _configuration.GetValue(key); return Ok($"{key}:{val}"); } [HttpGet("key")] public IActionResult GetConnectionStrings(string key) { var val = _configuration.GetConnectionString(key); return Ok($"{key}:{val}"); } } public class LoggingOptions : Dictionary { } } ``` 登入Apollo Portal,新增test專案,並增加以下配置,併發布。 ![增加配置](https://upload-images.jianshu.io/upload_images/2799767-26742654e9fa45fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 本地除錯,就能夠獲取雲端配置,另外Apollo同時會同步一份配置到本地目錄:`c:/opt/data/test/config-cache`。這樣就可以保證即使無法建立雲端連線,也可以正常載入本地配置。 執行以下命令,進行配置讀取和驗證: ``` > curl https://localhost:5001/Apollo/GetLogLevelSection Logging:LogLevel:{"Default":"Information","Microsoft":"Warning","Microsoft.Hosting.Lifetime":"Information"} > curl https://localhost:5001/Apollo/GetString/key?key=name name:Shengjie > curl https://localhost:5001/Apollo/GetConnectionStrings/key?key=Default Default:Server=mu3ne-mysql;port=3306;database=mu3ne0001;user id=root;password=abc123;AllowLoadLocalInfile=true ``` # 5.配置遷移指北 相信採用Apollo的絕大多數都不是一開始就用的,都是再配置逐漸複雜之後,才進行遷移的。我也不例外,之前是用K8S的ConfigMap來做配置管理。下面就來講下遷移指南,我將其分為兩種模式: 1. 偷懶模式 如果想改動最小,就直接將專案配置繼續以Json格式維護到Apollo的私有名稱空間下。 ![](https://upload-images.jianshu.io/upload_images/2799767-cb5f7cdd209df803.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![](https://upload-images.jianshu.io/upload_images/2799767-365c7ec8ea0774fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ``` public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { builder.AddApollo(builder.Build().GetSection("apollo")) .AddDefault() .AddNamespace("appsettings",ConfigFileFormat.Json); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); ``` 2. 強迫症模式 也有人考慮,既然上Apollo,就要用到它的特性,因此對現有配置就要分門別類。哪些是公用的,哪些是私有的。對於公用的就要定義到公共的名稱空間下。公共名稱空間的配置格式只有Properties格式,因此需要將Json轉為Properties。比如針對`Logging`配置可以藉助網站 [json2properties converter](https://tools.fromdev.com/json-to-property-converter.html)進行線上轉換。如下所示: ![json2properties](https://upload-images.jianshu.io/upload_images/2799767-145fd931518f0f42.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 如果真這樣做,你就錯了,你會發現最終的日誌配置不生效。這是因為`properties`格式是以**`.`**進行分割,而.NET Core是用**`:`**來識別節點配置, 因此`properties`配置按**`:`**分割就好了,如下所示,以下兩種配置等效: ![json 與 properties 相互轉換](https://upload-images.jianshu.io/upload_images/2799767-bd49e8486057cdd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # 6. 最後 以上,相信若能夠動手實操,你將收穫匪淺。 本文Demo和Chart包的完整配置已上傳至Github:[K8S.NET.Apollo](https://github.com/sheng-jie/dotnet.on.k8s/tree/master/K8S.NET.Apollo),請按需取用。