当前位置:首页 » JAVA技术教程

Spring Cloud官方文档中文版-Spring Cloud Config(上)-服务端(配置中心)

2017-10-26 16:21 本站整理 浏览(8)

官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feign

文中例子我做了一些测试在:http://git.oschina.net/dreamingodd/spring-cloud-preparation

官方项目:https://github.com/spring-cloud-samples/config-repo

II.Spring Cloud Config

Dalston.SR2

Spring Cloud Config为分布式系统的外部配置提供客户端的服务端的支持。使用了它,开发人员就可以在一个中心仓库管理应用程序在所有环境中的外部配置。服务器和客户端映射的概念都和Spring环境以及PropertySource的抽象完全相同,因此和Spring应用程序结合的相当好,并且支持任何语言编写的任何程序。当应用程序随着部署流程在DEV,TEST和PROD环境间迁移时,开发人员可以统一管理这些环境的配置,并且能确认应用程序拥有所有的运行所需的东西。服务器后端服务器默认使用git,因此,它可以轻松支持标签版本的配置环境,并且可以被大多数内容管理工具访问到。可以轻松添加替代实现,并使用Spring配置实现插拔。

4.快速开始

启动服务器:(可下载参考官方项目)

$ cd spring-cloud-config-server

$ ../mvnw spring-boot:run

此服务器是一个Spring Boot应用,所以如果愿意开发人员也可以在IDE中跑(main类为ConfigServerApplication)。然后试一试客户端:

$ curl localhost:8888/foo/development

{"name":"development","label":"master","propertySources":[{"name":"https://github.com/scratches/config-repo/foo-development.properties","source":{"bar":"spam"}},{"name":"https://github.com/scratches/config-repo/foo.properties","source":{"foo":"bar"}}]}

定位属性配置源的默认策略为克隆一个git仓库(使用spring.cloud.config.server.git.uri),并且使用它去初始化一个迷你SpringApplication。迷你SpringApplication用于枚举属性源并通过JSON节点发布。

HTTP服务支持以下属性数据源。

/{application}/{profile}[/{label}]

/{application}-{profile}.yml

/{label}/{application}-{profile}.yml

/{application}-{profile}.properties

/{label}/{application}-{profile}.properties

“application”是以SpringApplication的spring.config.name注入的(即常规Spring Boot应用程序中通常为“application”),“profile”为生效的配置文件(或以逗号分隔的属性列表), 而“label”是可选的git标签(通常为“master”)。

Spring Cloud Config服务器从git仓库(必须提供)为远程客户端拉取配置信息:

spring:

  cloud:

    config:

      server:

        git:

          uri: https://github.com/spring-cloud-samples/config-repo

使用客户端

要在应用程序中使用这些特性,只需要创建一个依赖于spring-cloud-config-client的Spring Boot的应用(例如:借鉴config-client的测试,或同一个app)。最便捷的方式时用过Spring Boot starter的org.springframework.cloud:spring-cloud-starter-config依赖。使用Maven的父pom(spring-cloud-starter-parent)或Gradle的Spring CLI,Spring IO version management properties file也可以。Maven示例:

pom.xml

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.3.5.RELEASE</version>

        <relativePath/><!-- lookup parent from repository -->
    </parent>
    <dependencyManagement>

        <dependencies>

            <dependency>

                <groupId>org.springframework.cloud</groupId>

                <artifactId>spring-cloud-dependencies</artifactId>

                <version>Brixton.RELEASE</version>

                <type>pom</type>

                <scope>import</scope>

            </dependency>

        </dependencies>
    </dependencyManagement>
    <dependencies>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-config</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>
    </dependencies>
    <build>

        <plugins>

            <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

            </plugin>

        </plugins>
    </build><!-- repositories also needed for snapshots and milestones -->

然后创建一个标准的Spring Boot应用,如下例,简单HTTP服务器:

@SpringBootApplication

@RestController

public class Application {

    @RequestMapping("/")

    public String home() {

        return "Hello World!";

    }

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }

}

App启动时,它会从默认的本地配置服务器的8888端口拉取外部配置,当然前提是服务器已在8888启动。使用bootstrap.properties切换配置服务器的地址开发人员能够改变应用启动的行为(就像一个应用程序上下文在程序引导阶段使用的application.properties),例如:

spring.cloud.config.uri: http://myconfigserver.com

bootstrap属性将作为高优先级属性源显示在/env的链接返回结果中,例如:

$ curl localhost:8080/env

{

"profiles":[],"configService:https://github.com/spring-cloud-samples/config-repo/bar.properties":{"foo":"bar"},  

"servletContextInitParams":{},  "systemProperties":{...},

...

}

(a property source called "configService:<URL of remote repository>/<file name>" contains the property "foo" with value "bar" and is highest priority).

(一个叫做"configService:<URL of remote repository>/<file name>"的最高优先级属性源包含一个值为“bar”的“foo“属性)

NOTE the URL in the property source name is the git repository not the config server URL.

注意 属性源名称中的URL是git仓库地址而不是配置服务器的URL。

5.配置中心

Spring Cloud Config服务器为外部配置提供了一个HTTP,基于资源的API(名称-值对,或等价的YAML)。使用@EnableConfigServer注解,服务器能轻易嵌入Spring Boot应用。故这个应用就是一个配置服务器:

ConfigServer.java

@SpringBootApplication@EnableConfigServerpublic class ConfigServer {

    public static void main(String[] args) {

        SpringApplication.run(ConfigServer.class, args);

    }

}

与通用的Spring Boot应用一样,服务器默认跑在8080端口上,开发人员可以使用多种方式换成8888端口。最简单的方式是,发布为spring.config.name=configserver(配置服务器jar包中有一个configserver.yml),同时将其设定为一个配置仓库。另一种方式是使用自身的application.properties(application.yml),如下:

application.properties

server.port: 8888

spring.cloud.config.server.git.uri: file://${user.home}/config-repo

其中${user.home}/config-repo为包含了YAML和属性文件的git仓库。

注意 在Windows系统中如果路径是一个带盘符的绝对路径,那么开发人员需要额外的“/”,如下: file:///${user.home}/config-repo.

提示 以下是创建上例中git仓库的操作步骤:

$ cd $HOME

$ mkdir config-repo

$ cd config-repo

$ git init .

$ echo info.foo: bar > application.properties$ git add -A .$ git commit -m "Add application.properties"

警告 使用本地的git仓库只能用做测试目的。在生产环境要使用配置服务器。

警告 如果开发人员只保留文本文件,那么配置仓库的初始克隆将快速而高效。如果开始使用二进制文件,尤其是体积大的,开发人员很可能会碰到第一次请求的延时甚至是服务器内存溢出错误。

环境仓库

配置中心的配置信息存在哪里呢?管理这个的策略是传说中的EnvironmentRepository,提供Environment对象。这个Environment是一个Spring Environment的浅层次拷贝(主要包含属性源)。Environment数据源由三个变量参数化:

{application}由客户端的"spring.application.name"属性指定

{profile}由客户端的"spring.profiles.active"属性指定

{label}为服务器的标注“版本”配置集(git为分支)

仓库实现通常与Spring Boot应用一样,从“spring.config.name”和“spring.profiles.active”(也就是{application}和{profiles})加载配置文件。Profiles的优先级规则也和普通的应用一样:active的profile优先于默认配置,还有,如果有多个profiles,那么应用最后一个(就像在Map中添加数据一样)。

示例:一个客户端应用程序和他的bootstrap配置:

bootstrap.yml

spring:

  application:

    name: foo

  profiles:

    active: dev,mysql

(当然和Spring Boot应用一样,这些属性也可以在环境变量和命令行中定义)。

如果仓库是基于文件的,那么服务器会从application.yml(被所有客户端共享)和foo.yml(优先级高)中创建环境。如果YAML文件中有文档指向Spring profiles,则应用较高优先级(根据profiles列出的顺序),如果指明profile的YAML文件,那么这些文件的优先级也比默认的高。高优先级的配置将在环境中率先转换为PropertySource。

Git后端

EnvironmentRepository的默认实现使用了Git,这种方式可以便捷的管理升级和物理环境以及审核修改。修改仓库地址只需要在配置中心修改"spring.cloud.config.server.git.uri"(application.yml)。如果用文件设置:前缀设置它,它应该从本地存储库中运行,以便在没有服务器的情况下快速轻松地启动,但在这种情况下,服务器直接在本地存储库上操作,而不克隆它(它是不是裸机不重要,因为配置中心从不对“远程”存储库进行更改。要扩展中心并使其高度可用,开发人员需要将服务器的所有实例指向同一个存储库,这样共享文件系统才能正常工作。即使在这种情况下,最好使用ssh:协议用于共享文件系统存储库,以便服务器可以将其克隆,并将本地工作副本用作缓存。

这个仓库实现将HTTP资源的{label}参数映射到git标签(commit,branch或tag)。如果git branch或tag中有斜线(/),那么HTTP URL的标签需要用特定字符串"()"代替指定(避免URL歧义)。例如,若标签为foo/bar,则替换为foo()bar。注意若使用命令行工具的话,URL中的()需要特殊处理(例如,在shell中使用"转义)。

Git URI中的占位符

Spring Cloud Config Server支持git仓库URL中的{application}和{profile}占位符(若需要,也支持{label},但记住标签应用为git标签)。因此,开发人员可以轻松支持“一个应用一套配置”的策略。

spring:

  cloud:

config:

      server:

        git:

          uri: https://github.com/myorg/{application}

或使用一样的模式加上{profile}实现“一个profile一套配置”的策略。

多仓库pattern匹配

还可以通过application和profile的pattern匹配来支持更复杂的需求。pattern的格式是带有通配符的{application} / {profile}名称的逗号分隔列表(可能需要引用以通配符开头的模式)。 例:

spring:

  cloud:

    config:

      server:

        git:

          uri: https://github.com/spring-cloud-samples/config-repo

          repos:

            simple: https://github.com/simple/config-repo

            special:

              pattern: special*/dev*,*special*/dev*

              uri: https://github.com/special/config-repo

            local:

              pattern: local*

              uri: file:/home/configsvc/config-repo

如果{application} / {profile}与任何pattern不匹配,它将使用“spring.cloud.config.server.git.uri”下定义的默认uri。 在上面的例子中,对于“simple”仓库,pattern为simple/*(即它只匹配一个在所有配置文件中名为“simple”的应用程序)。 “local”仓库将所有配置文件中以“local”开头的所有应用程序名称匹配(/*后缀自动添加到任何没有不匹配profile的pattern)。

注意 上文simple的一行快捷设置只能在仅设定URI的场合使用。设置其他任何值都不能再用这种方式。repo中的pattern属性其实是一个数组,因此开发人员也可以使用YAML数组(或[0],[1]等后缀)绑定到多个patterns。这是为了运行不同profile的多个程序。示例:

spring:

  cloud:

    config:

      server:

        git:

          uri: https://github.com/spring-cloud-samples/config-repo

          repos:

            development:

              pattern:

                - '*/development'

                - '*/staging'

              uri: https://github.com/development/config-repo

            staging:

              pattern:

                - '*/qa'

                - '*/production'

              uri: https://github.com/staging/config-repo

注意 Spring Cloud会认为不以结尾的配置文件的pattern意味着实际上要匹配一个以此pattern开头的配置文件列表(/staging是["/staging", "/staging,*"]的快捷方式)。这很常见,例如开发人员需要在本地跑"development" profile,同时在远程跑"cloud" profile。

spring:

  cloud:

    config:

      server:

        git:

          uri: https://github.com/spring-cloud-samples/config-repo

          searchPaths: foo,bar*

本例中服务器会搜索最上级和“foo/”子文件夹和以“bar”开头的子文件夹。

默认情况下,服务器会在配置第一次被请求时从远程仓库克隆。开发人员可以配置服务启动的时候去克隆。例如:

spring:

  cloud:

    config:

      server:

        git:

          uri: https://git/common/config-repo.git

          repos:

            team-a:

                pattern: team-a-*

                cloneOnStart: true

                uri: http://git/team-a/config-repo.git

            team-b:

                pattern: team-b-*

                cloneOnStart: false

                uri: http://git/team-b/config-repo.git

            team-c:

                pattern: team-c-*

                uri: http://git/team-a/config-repo.git

本例中,服务器在启动时,也就是接收请求之前就已经从team-a仓库克隆了配置。其他两个要在请求之后。

注意 启动时克隆可以快速定位错误的配置源(如无效的仓库URI)。若cloneOnStart为false,那么服务可能会在配置源错误的情况下顺利启动,并在应用请求的时候才发现配置源错误了。

安全认证

使用基本的HTTP安全认证只需分别加入用户名和密码,例如:

spring:

  cloud:

    config:

      server:

        git:

          uri: https://github.com/spring-cloud-samples/config-repo

          username: trolley

          password: strongpassword

若不使用HTTPS和用户证书,那么将密钥存在默认文件夹(/.ssh)并用URI指向SSH地址,也可以做到SSH的开箱即用,如"git@github.com:configuration/cloud-configuration"。重要的是,Git服务器的入口存在于/.ssh/known_hosts文件中,并且以ssh-rsa格式存在。 其他格式(像ecdsa-sha2-nistp256)均不支持。为了避免意外,应确保Git服务器的known_hosts文件中只有一个入口,并且与您提供给配置服务器的URL相匹配。如果开发人员在URL中使用了主机名,那么需要在known_hosts文件中有这个名称,而不是IP。当使用JGit访问存储库,任何文档都适用。HTTPS代理选项可以在~/.git/config中设置,或通过类似于JVM进程的系统变量(-Dhttps.proxyHost and -Dhttps.proxyPort)。

提示 如果找不到~/.git文件夹,使用git config --global设置(例如git config --global http.sslVerify false)。

AWS CodeCommit的安全认证这段用不上

AWS CodeCommit authentication can also be done. AWS CodeCommit uses an authentication helper when using Git from the command line. This helper is not used with the JGit library, so a JGit CredentialProvider for AWS CodeCommit will be created if the Git URI matches the AWS CodeCommit pattern. AWS CodeCommit URIs always look like https://git-codecommit.${AWS_REGION}.amazonaws.com/${repopath}.

If you provide a username and password with an AWS CodeCommit URI, then these must be the AWS accessKeyId and secretAccessKey to be used to access the repository. If you do not specify a username and password, then the accessKeyId and secretAccessKey will be retrieved using the AWS Default Credential Provider Chain.

If your Git URI matches the CodeCommit URI pattern (above) then you must provide valid AWS credentials in the username and password, or in one of the locations supported by the default credential provider chain. AWS EC2 instances may use IAM Roles for EC2 Instances.

Note: The aws-java-sdk-core jar is an optional dependency. If the aws-java-sdk-core jar is not on your classpath, then the AWS Code Commit credential provider will not be created regardless of the git server URI.

Git SSH属性配置

默认情况下,当通过SSH URI连接Git仓库的时候,Spring Cloud Config Server的JGit library使用SSH配置文件如~/.ssh/known_hosts和/etc/ssh/ssh_config。在类似Cloud Foundry的云环境下,本地文件系统可能是短暂的或难以访问的。这些情况下,可以使用Java属性去设置SSH配置。为了激活基于属性的SSH配置,须将属性spring.cloud.config.server.git.ignoreLocalSshSettings设置为true。例:

spring:

    cloud:

      config:

        server:

          git:

            uri: git@gitserver.com:team/repo1.git

            ignoreLocalSshSettings: true

            hostKey: someHostKey

            hostKeyAlgorithm: ssh-rsa

            privateKey: |

                         -----BEGIN RSA PRIVATE KEY-----

                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX

                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF

                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud

                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i

                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W

                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd

                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b

                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG

                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj

                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8

                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe

                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG

                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ

                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW

                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi

                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX

                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z

                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R

                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4

                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV

                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee

                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N

                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs

                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J

                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT

                         -----END RSA PRIVATE KEY-----

表1-SSH 配置属性

Property Name

Remarks

ignoreLocalSshSettings

true:使用基于属性的SSH代替基于文件的SSH。需通过spring.cloud.config.server.git.ignoreLo calSshSettings设置,而不能在一个仓库中定义。

privateKey

合法的SSH私有密钥。若ignoreLocalSshSettings为true且Git URI是SSH格式的,则必须设置。

hostKey

合法的SSH主机主机密钥。若设置了hostKeyAlgorithm,则必须设置

hostKeyAlgorithm

ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384 ,ecdsa-sha2-nistp521之中一个,必须设置若hostKey设置了。

strictHostKeyChecking

true或false. 若为false,则忽略host key的错误。

Git搜索路径的占位符

Spring Cloud Config Server也支持搜索路径的占位符如{application}和{profile}(若需要{label}也支持)。例如:

Spring Cloud Config Server

spring:

  cloud:

    config:

      server:

        git:

          uri: https://github.com/spring-cloud-samples/config-repo

          searchPaths: '{application}'

在仓库中搜索与目录(以及顶级)相同名称的文件。在占位符中使用通配符也是有效的(搜索中包含任何匹配的目录)。

Git仓库的强制拉取

如前所述,Spring Cloud Config Server克隆了远程git仓库,如果本地副本被污染了,则Spring Cloud Config Server无法从远程仓库更新本地副本。

为解决这个问题,当本地副本被污染,Spring Cloud Config Server提供了force-pull属性来让其强制从远程服务器拉取配置。

spring:

  cloud:

    config:

      server:

        git:

          uri: https://github.com/spring-cloud-samples/config-repo

          force-pull: true

若有多个仓库配置,那么可以为每个都配置上这个属性。如下:

spring:

  cloud:

    config:

      server:

        git:

          uri: https://git/common/config-repo.git

          force-pull: true

          repos:

            team-a:

                pattern: team-a-*

                uri: http://git/team-a/config-repo.git

                force-pull: true

            team-b:

                pattern: team-b-*

                uri: http://git/team-b/config-repo.git

                force-pull: true

            team-c:

                pattern: team-c-*

                uri: http://git/team-a/config-repo.git

注意 Force-pull的默认值是false。

使用版本控制后端服务器

警告 当使用基于版本控制的后端(git,svn)时,文件被克隆到本地文件系统。它们会被默认放在系统的带config-repo-前缀的临时目录下。例如在linux系统中,它是/tmp/config-repo-<randomid>。有些操作系统定期清理临时文件。这会导致如丢失属性这样不可预知的错误。为避免这种情况出现,要通过设置spring.cloud.config.server.git.basedir或spring.cloud.config.server.svn.basedir到一个非临时文件的文件结构中,让配置中心使用这个值。

 文件系统后端

配置中心还有个不使用Git的“原生”配置,它从本地classpath或文件系统加载配置文件(使用spring.cloud.config.server.native.searchLocations指向任何的静态URL)。启动配置中心时加上spring.profiles.active=native参数就可以使用这个原生配置。

注意 记住使用文件时:文件资源要加前缀(没有前缀的通常是classpath里的)。跟Spring Boot配置一样,可以使用${}风格的占位符,但记住windows的绝对路径需要一个额外的"/",例如:file:///${user.home}/config-repo

警告 默认searchLocations的值适合本地Spring Boot应用完全相同的([classpath:/, classpath:/config, file:./, file:./config])。这不会把服务器的application.properties暴露给所有的客户端,因为服务器所有存在的属性源在发送到客户端之前就已经被删除了。

提示 本地文件系统适合初学者的测试。在生产环境使用的话,必须保证文件系统的可靠性,并在配置中心的所有实例间共享。

搜索字段可以包括{application},{profile}和{label}。这样开发人员可以在路径中隔离文件夹,并选择一个适合的策略(例如每个应用一个子文件夹,或每个profile一个子文件夹)。

如果不使用占位符,那么仓库将把HTTP资源的{label}参数加到搜索路径上的后缀,所以属性文件将从从每个搜索位置一个与标签名称相同的子目录加载(标记属性在Spring环境中优先)。因此,没有占位符的话,默认与添加以/{label}/结尾的搜索位置一样。比如 file:/tmp/config 和 file:/tmp/config,file:/tmp/config/{label}一样。禁用这个功能可以通过设定spring.cloud.config.server.native.addLabelLocations=false。

Vault后端

Spring Cloud Config Server also supports Vault as a backend.

Spring Cloud Config Server也支持Vault作为后端。

保险柜是安全访问保密信息(secret)的工具。Secret是任意需要开发人员严格控制访问的信息,比如API key,密码,证书等等。Vault为任意的secret提供统一的访问接口,同时提供严格的访问控制和记录详细的审核信息。

更多信息请参考Vault quickstart guide

配置中心启用Vault后端,开发人员必须使用Vault profile去跑配置中心。例如在配置中心的application.properties中可以加入spring.profiles.active=vault。

配置中心一般默认Vault服务器跑在http://127.0.0.1:8200上。同时也默认后端名称是secret以及应用是key。下面的列表是可配置的Vault属性。所有的属性都以spring.cloud.config.server.vault为前缀。

Name

Default Value

host

127.0.0.1

port

8200

scheme

http

backend

secret

defaultKey

application

profileSeparator

,

org.springframework.cloud.config.server.environment.VaultEnvironmentRepository中可以找到所有的可配置属性。

运行配置中心服务器,开发人员可以向服务器发送HTTP请求来从Vault获取信息。这样做的话Vault服务器需要一个token。

首先在Vault中加入一些数据。比如:

$ vault write secret/application foo=bar baz=bam

$ vault write secret/myapp foo=myappsbar

现在向配置中心服务器发送HTTP请求来获取信息。

$ curl -X "GET" "http://localhost:8888/myapp/default" -H "X-Config-Token: yourtoken"

接下来通过上面的请求应该可以获得一个类似于下面的响应。

{

   "name":"myapp",

   "profiles":[

      "default"

   ],

   "label":null,

   "version":null,

   "state":null,

   "propertySources":[

      {

         "name":"vault:myapp",

         "source":{

            "foo":"myappsbar"

         }

      },

      {

         "name":"vault:application",

         "source":{

            "baz":"bam",

            "foo":"bar"

         }

      }

   ]}
多属性源

使用Vault时,开发人员还可以给应用程序提供多属性源。例如,假设开发人员在Vault中写入以下数据。

secret/myApp,dev

secret/myApp

secret/application,dev

secret/application

使用配置中心可以将secret/应用写入属性的方式应用在所有应用程序中。名称为myApp的应用将具有写入secret/myApp和secret/应用程序的任何属性。当myApp启用开发配置时,写入上述所有路径的属性就可用,在列表中的第一个路径中的属性优先于其他所有的路径。

在应用间分享所有的配置

基于文件的仓库

使用基于文件的(即git,svn和native)仓库,应用程序中的文件名资源在所有的客户端应用间共享(application.properties, application.yml, application-*.properties etc)。开发人员可以使用这些文件名资源来配置全局默认值,并按需覆盖指定应用中的文件。

#_property_overrides[属性覆盖]功能也可以用于设定全局默认值,并且使用占位符应用程序可以本地覆盖默认值。

提示 使用"native" profile(本地文件系统后端),建议开发人员使用显示不属于服务器自带配置的搜索位置。否则由于默认搜索位置的应用资源是服务器的一部分,它们将被删除。

Vault服务器

当使用Vault作为后端的时候,开发人员可以通过将配置放入secret/应用的方式在应用间共享配置。例如运行以下的Vault命令

$ vault write secret/application foo=bar baz=bam

使用配置中心,所有的应用都将有可用的foo和baz属性(不知道有啥用)。

组合环境仓库

一些情景中开发人员可能希望从多个环境的仓库拉取配置数据。开发人员需要在配置中心的application.properties或application.yml启用多profiles。如果,例如,如果还需要从Git仓库或SVN仓库拉取配置数据,则需要在配置服务器中设定下列属性:

spring:

  profiles:

    active: git, svn

  cloud:

    config:

      server:

        svn:

          uri: file:///path/to/svn/repo

          order: 2

        git:

          uri: file:///path/to/git/repo

          order: 1

除每个仓库制定一个URI之外,还可以制定一个order属性。order属性帮助开发人员指定所有仓库的优先顺序。order属性的数值越低,仓库的优先级越高。仓库的优先级能解决仓库间包含统一属性时的潜在冲突问题。

注意 从环境仓库取值过程中的所有类型的故障都将导致整个组合环境的故障。

注意 当使用组合环境时,所有仓库都有相同的标签很重要。比如有一个类似于上述的环境,若向SVN仓库请求master标签下的配置数据但是仓库里却没有master分支,那么整个请求将失败。

自定义组合环境仓库

除了使用Spring Cloud中的一个环境仓库之外,还可以提供自己的环境仓库bean作为复合环境的一部分。为此,需要实现EnvironmentRepository接口。如果开发人员希望在组合环境中控制自定义EnvironmentRepository的优先级,那么就实现Ordered接口并覆盖getOrdered方法。如果不这么做,则自定义的EnvironmentRepository会拥有最低的优先级。

属性覆盖

配置中心有一个“overrides”功能,它允许操作符给所有应用提供配置属性,这些属性不会被普通的Spring Boot hooks意外更改。声明覆盖只要加一个name-value键值对map到spring.cloud.config.server.overrides。例如:

spring:

  cloud:

    config:

      server:

        overrides:

          foo: bar

这会导致所有客户端应用读取到foo: bar配置,独立于它们自身的配置之外。(当然一个应用可以任意使用配置中心的数据,故并不需要强制覆盖,但是只要它们是Spring Cloud Config客户端,它们就会提供可用的默认行为)

提示 正常情况下,Spring环境的占位符使用反斜杠("")来转义"${}",例如${app.foo:bar}解析为"bar",除非应用提供了"app.foo"。当开发人员在服务器覆盖配置是,注意在YAML格式中,不需要转义反斜杠本身,而在属性文件中需要。开发人员可以在客户端修改所有覆盖的优先级为类似默认值那样,这使应用通过在远程仓库设定spring.cloud.config.overrideNone=true(默认为false),来为环境变量和系统属性提供自己的值。

健康指标

配置中心附带一个Health Indicator,用于检查配置的EnvironmentRepository是否工作。默认它向EnvironmentRepository询问一个名为app的应用,由EnvironmentRepository实现提供的默认profile和默认label。

开发人员可以配置Health Indicator来检查更多的应用连同自定义的profiles和labels。例如:

spring:

  cloud:

    config:

      server:

        health:

          repositories:

            myservice:

              label: mylabel

            myservice-dev:

              name: myservice

              profiles: development

You can disable the Health Indicator by setting spring.cloud.config.server.health.enabled=false.

安全

开发人员可以自由应用任何有意义的方式(从物理网络安全到OAuth2承载令牌)来加强配置中心的安全,而且使用Spring Security和Spring Boot几乎可以轻松做任何事情。

要使用Spring Boot默认的HTTP Basic安全,只需要在classpath中接入Spring Security(例如通过spring-boot-starter-security)。默认是"user"的用户名和随机生成的密码,实践中不这样用,因此推荐开发人员配置密码(通过security.user.password)并进行加密(参考下面的说明来做)。

加密和解密

重要 先决条件:要使用加密和解密功能,开发人员需要在JVM中安装完整的JCE(默认情况下没有)。开发人员可以从Oracle下载“Java加密扩展(JCE)无限强度管理策略文件”,并按照安装说明(实际上将JRE lib/security目录中的2个策略文件替换为下载的文件)。如果远程属性源包含加密内容(以{cipher}开头的值),则它们将在通过HTTP发送给客户端之前被解密。这种设置的主要优点是,当“静止”(例如,在git仓库中)时,属性值不必是纯文本。如果值无法解密,则从属性源中删除该值,并添加一个附加属性,并使用相同的键,但以“invalid”为前缀。和“不适用”(通常为“<n/a>”)的值。这主要是为了防止密文被用作密码并意外泄漏。

如果开发人员正在为配置客户端应用程序设置远程配置存储库,可能会包含一个这样的application.yml:

application.yml

spring:

  datasource:

     username: dbuser

     password: '{cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ'

.properties文件中的加密值不能用引号括起来,否则将不会被解密:

application.properties

spring.datasource.username: dbuser

spring.datasource.password: {cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ

You can safely push this plain text to a shared git repository and the secret password is protected.

服务器还暴露 /encrypt和/decrypt路径(假设这些会被保护且只能由授权代理访问)。若开发人员在编辑一个远程配置文件,可以使用配置中心通过POST到/encrypt来加密值,例如:

$ curl localhost:8888/encrypt -d mysecret682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda

注意 若开发人员要加密带有需要进行URL编码的字符的值,则应使用--data-urlencode选项来curl以确保它们已正确编码。

提示 确保不要在加密值中包含任何curl命令统计信息。 将值输出到文件可以帮助避免此问题。逆操作也可以通过/decrypt实现(假设服务器配置了对称密钥或全密钥对):

$ curl localhost:8888/decrypt -d 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda

mysecret

提示 如果开发人员使用curl进行测试,则使用--data-urlencode(而不是-d)或设置显式的Content-Type:text/plain,以确保在有特殊字符('+')时,curl对数据进行正确编码('+'号特别棘手)。在将加密值添加到YAML或属性文件并在提交并将其推送到远程的,潜在风险的存储之前,需要先为加密值添加{cipher}前缀。

/encrypt和/decrypt也都接受形式为/*/{name}/{profiles}的路径,当客户端调用到主环境资源时,可以使用每个应用程序(name)和配置文件控制加密方式。

注意 为了以这种细微的方式控制加密方式,开发人员还必须提供一种类型为TextEncryptorLocator的@Bean来为每个不同的应用和配置文件创建不同的加密器。默认不提供(所有加密使用相同的密钥)。 spring命令行客户端(安装了Spring Cloud CLI扩展)也可以用于加密和解密,例如:

$ spring encrypt mysecret --key foo

682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda

$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda

mysecret

要使用文件中的密钥(例如,用于加密的RSA公钥),预先使用“@”来填充密钥值并提供文件路径,例如:

$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pubAQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...

key参数是强制性的(尽管有一个--前缀)。

密钥管理

配置中心可以使用对称的(共享的)密钥或非对称的(RSA密钥对)。在安全方面考量,非对称更优,不过对称的往往是更便捷的,因为它只需要配置一个属性值。

配置对称密钥,开发人员需要将encrypt.key设置为保密字符串(或使用环境变量ENCRYPT_KEY将其保持在纯文本配置文件之外)。

配置非对称密钥,开发人员可以将密钥设置为PEM加密的文本值(encrypt.key),或者通过密钥库(比如JDK附带的keytool工具)。密钥库相关属性为encrypt.keyStore.*,具体是:

  • location(资源位置),
  • password (解锁密钥库) 和
  • alias (定位库中使用的密钥).

创建一个测试密钥库

以下命令用于创建密钥库

$ keytool -genkeypair -alias mytestkey -keyalg RSA \

-dname "CN=Web Server,OU=Unit,O=Organization,L=City,S=State,C=US" \  -keypass changeme -keystore server.jks -storepass letmein

把server.jks文件加入classpath,并加入配置中心的application.yml中:

encrypt:

  keyStore:

    location: classpath:/server.jks

    password: letmein

    alias: mytestkey

    secret: changeme

使用多个密钥和密钥转置

除了在加密属性值的{cipher}前缀之外,配置中心在(Base64 encoded)密文开始之前查找{name:value}前缀(零或多个)。密钥被传递给TextEncryptorLocator-可以为定位一个密码的TextEncryptor执行任意逻辑。如果开发人员配置了一个密钥库(encrypt.keystore.location),则默认定位器将使用“密钥”提供的别名来查找存储库中的密钥,也就是用以下密码:

foo:

  bar: `{cipher}{key:testkey}...`

定位器会查找一个名为“testkey”的密钥。前缀{secret:…}值也可以提供secret,但若非默认情况下使用的是密钥库密码(这是当开发人员建立一个密钥库且不指定secret时得到的)。如果确定要提供secret,那么建议开发人员也用一个自定义的SecretLocator来加密secrets。

如果密钥仅仅用来加密几个字节的配置数据(即只在一个地方使用),那么使用密钥转置的理由并不充分,但有时还是需要改变密钥,比如当有安全漏洞的时候。这种情况下所有的客户端都需要更改其源配置文件(比如git)并使用新的{key:...}前缀,当然也要预先检查密钥别名在配置中心的可用性。

提示 如果想要让配置中心处理所有的加密解密,那么也可以将{name:value}前缀明文发布到/encrypt链接。

提供加密属性

有时需要客户端在本地而非服务器解密配置信息。这种情况下,开发人员仍然可以使用/encrypt和/decrypt链接(只要提供了encrypt.*的配置去定位密钥),但需要使用spring.cloud.config.server.encrypt.enabled=false来显式关闭转出属性的解密。如果不关心链接,那么只要不配置密钥且不启用开关,就可以正常工作。

dreamingodd原创文章,如转载请注明出处。