"ASP.NET Core micro-service real" - reading notes (Chapter 9)

Configuration Chapter 9 micro-service system

Micro-service system configuration requires more attention to other aspects of factors, including:

  • Security configuration values ​​of reading and writing
  • The ability to change the value of audit
  • Configuration information source itself of toughness and reliability
  • Environment variables difficult to carry a small amount of large, complex configuration information
  • Application to decide whether to support online real-time updates and configuration changes value, but also to decide how to implement
  • And support function switches provided hierarchized
  • Sensitive information and encryption key itself is stored and read support

This chapter first discusses the mechanisms use environment variables in the application, and demonstrates the support case Docker

Then explore a configuration server products from Netflix OSS technology stack

Finally, the use etcd, it is a commonly used open source configuration management of distributed key-value database

Use environment variables in the Docker

When configured to provide a default value, you should also consider what settings need to be overridden by the environment variable during application startup

When the configuration settings, can be used to display the specified key, as follows:

$ sudo docker run -e SOME_VAR='foo' \ -e PASSWORD='foo' \
-e USER='bar' \
-e DB_NAME='mydb' \
-p 3000:3000 \
--name container_name microservices-aspnetcore/image:tag

Alternatively, if the do not want the incoming value on the command line, environment variables may be forwarded from the environment into the container to start, as long as the equation does not contain the incoming value can be, for example:

$ docker run -e PORT -e CLIENTSCRET -e CLIENTKEY [...]

This command will command line terminal is located in the PORT, value CLIENTSECRET and CLIENTKEY environment variable is imported Docker containers, their values ​​are not disclosed in the command line text in the process, to protect against potential security vulnerabilities and sensitive information disclosure

If you need to pass a lot of environment variables to the container, you can specify a command to docker key file list contains:

$ docker run --env-file ./myenv.file [...]

Use Spring Cloud server configuration

One of the biggest challenges around configuration management services, not how to value injected into the environment variable, but that routine maintenance of the values ​​themselves

When the value of the original source of the configuration is changed, how do we get notice

Further, when the value changes occur, how do we go back and look at the previous value

You may find that it seems like Git repository available to use to manage configuration values

Spring Cloud configuration server (SCCS) developers who hold the same views

To add support for SCCS client in .NET Core applications only need to add a reference to Steeltoe.Extensions.Configuration.ConfigServer NuGet package in the project

接着,我们需要配置应用,让它从正确的位置获取设置信息

我们需要定义一个 Spring 应用名称,并在 appsettings.json 文件中添加配置服务器的 URL

{
    "spring": {
        "application": {
            "name": "foo"
        },
        "cloud": {
            "config": {
                "uri": "http://localhost:8888"
            }
        }
    },
    "Logging": {
        "IncludeScopes": false,
        "LogLevel": {
            "Default": "Debug",
            "System": "Information",
            "Microsoft": "Information"
        }
    }
}

配置完成后,Startup 构造方法仍然与其他应用几乎一致

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
        .AddEnvironmentVariables()
        .AddConfigServer(env);

    Configuration = builder.Build();
}

要添加对配置服务器的支持,接下来需要修改 ConfigureServices 方法

首先调用 AddConfigServer 向依赖注入子系统加入配置客户端

接着指定泛型参数并调用 Configure 方法

这一操作能把从配置服务器获取的配置信息包装为一个 IOptionsSnapshot 对象,然后可由控制器和其他代码使用

public void ConfigureServices(IServiceCollection services)
{
    services.AddConfigServer(Configuration);
    services.AddMvc();

    services.Configure<ConfigServerData>(Configuration);
}

此处,用于表示从配置服务器获取的数据的数据模型,是基于 Spring Cloud 服务器示例仓库中的示例配置进行建模的

public class ConfigServerData
{
    public string Bar { get; set; }
    public string Foo { get; set; }
    public Info Info { get; set; }
}

public class Info
{
    public string Description { get; set; }
    public string Url { get; set; }
}

然后,在需要时,就可注入这个类的实例,以及配置服务器的客户端参数

public class MyController : MyController
{
    private IOptionsSnapshot<ConfigServerData> MyConfiguration { get; set; }
    private ConfigServerClientSettingsOptions ConfigServerClientSettingsOptions { get; set; }
    public MyController(IOptionsSnapShot<ConfigServerData> opts, IOptions<ConfigServerClientSettingsOptions> clientOpts)
    {
        ...
    }

    ...
}

上述配备完成后,如果配置服务器已处于运行状态,构造器中的 opts 变量将包含应用所有的相关配置

启动配置服务器最简单的方法就是直接通过 Docker 镜像运行以下代码

$ docker run -p 8888:8888 \
-e SPRING_CLOUD_CONFIG_SERVER_GET_URI=http://github.com/spring-cloud-samples/ \config-repohyness/spring-cloud-config-server

如果服务器运行正确,应该能通过以下命令获取配置信息

curl http://localhost:8888/foo/development

在本地用 Docker 镜像启动配置服务器后,使用上面展示的 C# 代码,就能体验将外部配置数据提供给 .NET Core 微服务的过程

使用 etcd 配置微服务

Spring Cloud 配置服务器的替代品不计其数,etcd 是其中很流行的一个

上一章简单提到,etcd 是一个轻量级的分布式键值数据库

它就是为你存储分布式系统所需要的最关键信息的位置

etcd 是一个集群产品,其节点之间的通信是基于 Raft 共识算法实现的

etcd 的一个最常见运用场景就是存储和检索配置信息以及功能标志

在本章的例子里,我访问 compose.io 并注册了一个免费试用的托管 etcd

创建 etcd 配置提供程序

GitHub链接:https://github.com/microservices-aspnetcore/etcd-client

创建配置源

using System;
using Microsoft.Extensions.Configuration;

namespace ConfigClient
{
    public class EtcdConfigurationSource : IConfigurationSource
    {
        public EtcdConnectionOptions Options { get; set; }

        public EtcdConfigurationSource(EtcdConnectionOptions options)
        {
            this.Options = options;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new EtcdConfigurationProvider(this);
        }
    }
}

创建配置构建器

using System;
using System.Collections.Generic;
using EtcdNet;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Primitives;

namespace ConfigClient
{
    public class EtcdConfigurationProvider : ConfigurationProvider
    {
        private EtcdConfigurationSource source;

        public EtcdConfigurationProvider(EtcdConfigurationSource source)
        {
            this.source = source;
        }

        public override void Load()
        {
            EtcdClientOpitions options = new EtcdClientOpitions()
            {
                Urls = source.Options.Urls,
                Username = source.Options.Username,
                Password = source.Options.Password,
                UseProxy = false,
                IgnoreCertificateError = true
            };
            EtcdClient etcdClient = new EtcdClient(options);
            try
            {
                EtcdResponse resp = etcdClient.GetNodeAsync(source.Options.RootKey,
                    recursive: true, sorted: true).Result;
                if (resp.Node.Nodes != null)
                {
                    foreach (var node in resp.Node.Nodes)
                    {
                        // child node
                        Data[node.Key] = node.Value;
                    }
                }
            }
            catch (EtcdCommonException.KeyNotFound)
            {
                // key does not 
                Console.WriteLine("key not found exception");
            }
        }
    }
}

借助如下扩展方法

using Microsoft.Extensions.Configuration;

namespace ConfigClient
{
    public static class EtcdStaticExtensions
    {
        public static IConfigurationBuilder AddEtcdConfiguration(this IConfigurationBuilder builder,
            EtcdConnectionOptions connectionOptions)
        {
            return builder.Add(new EtcdConfigurationSource(connectionOptions));
        }
    }

    public class EtcdConnectionOptions
    {
        public string[] Urls { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string RootKey { get; set; }
    }
}

便能在 Startup 类中把 etcd 添加为配置源

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace ConfigClient
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEtcdConfiguration(new EtcdConnectionOptions
                {
                    Urls = new string[] {
                    "https://portal1934-21.euphoric-etcd-31.capital-one-3.composedb.com:17174",
                    "https://portal2016-22.euphoric-etcd-31.capital-one-3.composedb.com:17174"
                     },
                    Username = "root",
                    Password = "changeme",
                    RootKey = "/myapp"
                })
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public static IConfigurationRoot Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole();
            loggerFactory.AddDebug();

            app.UseMvc();
        }
    }
}

使用来自 etcd 的配置值

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using EtcdNet;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;

namespace ConfigClient.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private ILogger logger;

        public ValuesController(ILogger<ValuesController> logger)
        {
            this.logger = logger;
        }

        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            List<string> values = new List<string>();
            values.Add(Startup.Configuration.GetSection("/myapp/hello").Value);
            values.Add(Startup.Configuration.GetSection("/myapp/rate").Value);

            return values;
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

现在访问 http://localhost:3000/api/values 端点,将返回这些值:

{"world", "12.5"}

这些正是本节前面面向 etcd 服务器添加的值

只使用了少数几行代码,我们便创建了一个由远程配置服务器支持的、稳定而符合标准的 ASP.NET 配置源

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 ([email protected]) 。

Guess you like

Origin www.cnblogs.com/MingsonZheng/p/12289596.html