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

1.引言
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
如官网所述:Apollo 是携程打造的开源配置中心,GitHub的星星也快点满22K,因此足见它的成熟度和社区活跃度。因此最近在做配置中心选型的时候,经过一番预演,最终敲定Apollo。
Apollo作为微服务体系中必不可少的基础服务,其架构设计和基本使用我们不得不有所了解。
因此本文接下来将主要来介绍如何基于Helm快速部署Apollo集群至K8S,并与.NET Core应用进行集成,同时介绍下如何平滑迁移配置到Apollo。
本文具有详细的部署步骤,建议动手实操。
部署Chart包和Demo已上传至GitHub:K8S.NET.Apollo,可收藏备用。
2. Apollo 架构一览
在部署之前,需要了解Apollo的基础架构,以便在后续部署工作的展开。

关于其的解读,我这里就不再详细展开,但以下几点还是要有所了解,感兴趣的可以直接看官网详细介绍:Apollo配置中心设计。
- Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端
- Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
- Config Service和Admin Service都是多实例、无状态部署,需要通过注册中心进行服务注册和发现
- 注册中心默认采用的是Eureka,在K8S中由Service充当
- Apollo客户端通过注册中心获取Config Service服务列表进行配置读取
- Apollo Portal通过注册中心获取Admin Service服务列表进行配置管理
基于上面对Apollo的介绍,其物理架构总结起来就是:
- 每一套环境都必须拥有自己独立的Config Service 和 Admin Service 以及独立ConfigDB。
- 多套环境可以公用一套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

3.1 搭建 Apollo Config&Portal DB
从上图的物理架构上来看,首先要部署好Config DB和PortalDB。关于DB的搭建,建议直接使用bitnami/mysqlchart搭建。搭建步骤如下:
> 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
根据官网分布式部署指南中所示,其提供了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。然后修改核心配置:
- global.storageClass=hostpath
 可通过kubectl get sc查看集群支持的storageClass,我这边选择默认的hostpath。其创建的pv的默认回收策略为delete,也就意味着卸载mysql,数据直接删除,这点需要注意!!!如果需要保留测试数据,请更新storageClass。
- 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。主要修改以下配置:
- configdb.host=mysql-apollo.db
 指定configdb的主机,因为是在集群内部,直接使用服务名即可
- 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     <none>        8090/TCP   3m26s
service/apollo-dev-svc-apollo-configservice   ClusterIP   10.108.121.201   <none>        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,可以看到输出[{"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。主要修改以下配置:
- 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: []
- 指定配置源 ,主要是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: {}
- 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/,就可以访问了。默认用户密码是:[apollo/admin]。

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>();
        });
修改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<LoggingOptions>();
            return Ok($"{key}:{JsonSerializer.Serialize(val)}");
        }
        [HttpGet("key")]
        public IActionResult GetString(string key)
        {
            var val = _configuration.GetValue<string>(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<string, string>
    {
    }
}
登录Apollo Portal,添加test项目,并增加以下配置,并发布。

本地调试,就能够获取云端配置,另外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来做配置管理。下面就来讲下迁移指南,我将其分为两种模式:
- 偷懒模式
 如果想改动最小,就直接将项目配置继续以Json格式维护到Apollo的私有命名空间下。
  
  
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<Startup>();
        });
- 强迫症模式
 也有人考虑,既然上Apollo,就要用到它的特性,因此对现有配置就要分门别类。哪些是公用的,哪些是私有的。对于公用的就要定义到公共的命名空间下。公共命名空间的配置格式只有Properties格式,因此需要将Json转为Properties。比如针对Logging配置可以借助网站 json2properties converter进行在线转换。如下所示:

如果真这样做,你就错了,你会发现最终的日志配置不生效。这是因为properties格式是以.进行分割,而.NET Core是用:来识别节点配置, 因此properties配置按:分割就好了,如下所示,以下两种配置等效:

6. 最后
以上,相信若能够动手实操,你将收获匪浅。
本文Demo和Chart包的完整配置已上传至Github:K8S.NET.Apollo,请按需取用。
.NET Core + K8S + Apollo 玩转配置中心的更多相关文章
- .NET Core微服务之基于Apollo实现统一配置中心
		Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.关于统一配置中心与Apollo 在微服务架构环境中,项目中配置文件比较繁杂,而且不同环境的不同配置修改相对频繁,每次发布都需要对应修改 ... 
- Spring Cloud Config、Apollo、Nacos配置中心选型及对比
		Spring Cloud Config.Apollo.Nacos配置中心选型及对比 1.Nacos 1.1 Nacos主要提供以下四大功能 2.Spring Cloud Config 3.Apollo ... 
- .Net Core with 微服务 - Consul 配置中心
		上一次我们介绍了Elastic APM组件.这一次我们继续介绍微服务相关组件配置中心的使用方法.本来打算介绍下携程开源的重型配置中心框架 apollo 但是体系实在是太过于庞大,还是让我爱不起来.因为 ... 
- Apollo阿波罗配置中心docker
		前言 在分布式系统中,要改个配置涉及到很多个系统,一个一个改效率低下,吃力不讨好.用配置中心可以解决这个问题.当然配置中心有不少,以下对比的表格是照搬Apollo Wiki的. 功能点 Apollo ... 
- Apollo 高可用配置中心搭建教程
		Apollo开源文档中搭建流程讲的很详细,此处只提供传送门 1.Apollo配置中心开源地址 2.服务包下载地址 3.教程文档地址 4.视频教程地址 5.Apollo使用指南 说明: apollo-c ... 
- .NET Core + K8S + Loki  玩转日志聚合
		1. Intro 最近在了解日志聚合系统,正好前几天看到一篇文章<用了日志系统新贵Loki,ELK突然不香了!>,所以就决定动手体验一下.本文就带大家快速了解下Loki,并简单介绍.NET ... 
- 【NET CORE微服务一条龙应用】第二章 配置中心使用
		背景 系列目录:[NET CORE微服务一条龙应用]开始篇与目录 在分布式或者微服务系统里,通过配置文件来管理配置内容,是一件比较令人痛苦的事情,再谨慎也有湿鞋的时候,这就是在项目架构发展的过程中,配 ... 
- Apollo 配置中心详细教程
		一.简介 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理 ... 
- 每天学点SpringCloud(八):使用Apollo做配置中心
		由于Apollo支持的图形化界面相对于我们更加的友好,所以此次我们使用Apollo来做配置中心 本篇文章实现了使用Apollo配置了dev和fat两个环境下的属性配置.Apollo官方文档https: ... 
随机推荐
- 2020最新全栈必备 Redis,你还不了解么
			什么是Redis Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如字符串, 散列, 列表, 集合, 有序集合与范围查 ... 
- etcd3.0集群安装
			etcd 是一个分布式一致性键值存储,用于共享配置和服务发现,Go编写,并使用 Raft 一致性算法来管理高可用复制日志. 特性 简单:支持curl方式的用户API(http+json)安全:可选ss ... 
- PHP 实例 - AJAX 与 XML-AJAX XML 实例
			PHP 实例 - AJAX 与 XML AJAX 可用来与 XML 文件进行交互式通信. AJAX XML 实例 下面的实例将演示网页如何通过 AJAX 从 XML 文件读取信息: 实例 Sele ... 
- PHP getimagesizefromstring - 获取图片信息函数
			getimagesizefromstring — 从字符串中获取图像尺寸信息.高佣联盟 www.cgewang.com 语法 array getimagesizefromstring ( string ... 
- IC行业常见用语
			https://www.cnblogs.com/yeungchie/ Active Devices 有源器件 MOSFET Metal-Oxide-Semicoductor Field-Effect ... 
- SparkBench安装使用入门
			SparkBench安装以及快速开始 欢迎关注我的GitHub~ 本指南假定已经可以正常使用Spark 2.x,并且可以访问安装它的系统. 系统环境 CentOS 7.7.1908 Ambari-Sp ... 
- SpringMVC入门和常用注解
			SpringMVC的基本概念 关于 三层架构和 和 MVC 三层架构 我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就 是浏览器服务器.在 ... 
- 41-native关键字的理解
			使用 native 关键字说明这个方法是原生函数,也就是这个方法是用 C/C++等非Java 语言实现的,并且被编译成了 DLL,由 java 去调用. (1)为什么要用 native 方法 java ... 
- ThreadLocal刨根问底
			一.ThreadLocal使用场景 数据库连接connection对象使用,每个客户都能使用自己的connection对象.不会出现客户A操作关闭了客户B的connection 案例:https:// ... 
- Python编写的桌面图形界面程序实现更新检测和下载安装
			在Python中我们有很多种方案来编写桌面图形用户界面程序,譬如内置的 Tkinter .强大的 PyQt5 和 PySide2 ,还有 wxPython .借助这些或内置或第三方的模块,我们可以轻松 ... 
