zoukankan      html  css  js  c++  java
  • .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 总体设计

    关于其的解读,我这里就不再详细展开,但以下几点还是要有所了解,感兴趣的可以直接看官网详细介绍: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

    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的初始化脚本用来分别创建ApolloConfigDBApolloPortalDB。因此可以直接将以上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:UsersShengjiek8shelmchartsapollomysqlfilesdocker-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     <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。主要修改以下配置:

    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: []
    
    1. 指定配置源 ,主要是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: {}
    
    1. 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:UsersShengjiek8shelmchartsapolloapollo-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]。
    apollo login page

    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.yamlconfigService节点下增加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节点,添加对应ingressconfig.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

    这一部分我就快速带过了,执行以下命令创建项目,并引入apolloswagger相关包:

    > 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来做配置管理。下面就来讲下迁移指南,我将其分为两种模式:

    1. 偷懒模式
      如果想改动最小,就直接将项目配置继续以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>();
            });
    
    1. 强迫症模式
      也有人考虑,既然上Apollo,就要用到它的特性,因此对现有配置就要分门别类。哪些是公用的,哪些是私有的。对于公用的就要定义到公共的命名空间下。公共命名空间的配置格式只有Properties格式,因此需要将Json转为Properties。比如针对Logging配置可以借助网站 json2properties converter进行在线转换。如下所示:

    json2properties

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

    json 与 properties 相互转换

    6. 最后

    以上,相信若能够动手实操,你将收获匪浅。

    本文Demo和Chart包的完整配置已上传至Github:K8S.NET.Apollo,请按需取用。

  • 相关阅读:
    231. Power of Two
    204. Count Primes
    205. Isomorphic Strings
    203. Remove Linked List Elements
    179. Largest Number
    922. Sort Array By Parity II
    350. Intersection of Two Arrays II
    242. Valid Anagram
    164. Maximum Gap
    147. Insertion Sort List
  • 原文地址:https://www.cnblogs.com/sheng-jie/p/use-apollo-with-dotnet-on-k8s.html
Copyright © 2011-2022 走看看