Git 后端

EnvironmentRepository 的默认实现使用 Git 后端,这对于管理升级、物理环境以及审计变更非常方便。要更改仓库的位置,您可以在配置服务器中设置 spring.cloud.config.server.git.uri 配置属性(例如在 application.yml 中)。如果您将其设置为 file: 前缀,它应该可以从本地仓库工作,这样您可以快速轻松地入门,而无需服务器。但是,在这种情况下,服务器直接操作本地仓库,而不克隆它(即使它不是裸仓库也没关系,因为配置服务器永远不会更改“远程”仓库)。要扩展配置服务器并使其高可用,您需要让所有服务器实例指向同一个仓库,因此只有共享文件系统可以工作。即使在这种情况下,最好对共享文件系统仓库使用 ssh: 协议,以便服务器可以克隆它并使用本地工作副本作为缓存。

此仓库实现将 HTTP 资源的 {label} 参数映射到 Git 标签(提交 ID、分支名称或标签)。如果 Git 分支或标签名称包含斜杠 (/),则 HTTP URL 中的标签应使用特殊字符串 ({special-string}) 指定(以避免与其他 URL 路径产生歧义)。例如,如果标签是 foo/bar,替换斜杠后的标签将是 foo({special-string})bar。特殊字符串 ({special-string}) 的包含也可以应用于 {application} 参数。如果您使用像 curl 这样的命令行客户端,请小心 URL 中的括号 — 您应该使用单引号 ('') 从 shell 中转义它们。

跳过 SSL 证书验证

可以通过将 git.skipSslValidation 属性设置为 true(默认为 false)来禁用配置服务器对 Git 服务器 SSL 证书的验证。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          skipSslValidation: true

设置连接超时

您可以配置配置服务器等待获取 HTTP 或 SSH 连接的时间(以秒为单位)。使用 git.timeout 属性(默认为 5)。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          timeout: 4

Git URI 中的占位符

Spring Cloud Config Server 支持带有 {application}{profile} 占位符(如果您需要,也可以使用 {label},但请记住标签无论如何都会作为 Git 标签应用)的 Git 仓库 URL。因此,您可以通过使用类似于以下的结构来支持“每个应用一个仓库”的策略:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/myorg/\{application}

您也可以使用类似模式但使用 {profile} 来支持“每个 profile 一个仓库”的策略。

此外,在您的 {application} 参数中使用特殊字符串 "({special-string})" 可以支持多个组织,如下例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/\{application}

其中 {application} 在请求时以以下格式提供:organization({special-string})application

模式匹配和多个仓库

Spring Cloud Config 还支持更复杂的需求,通过对应用程序和 profile 名称进行模式匹配。模式格式是以逗号分隔的 {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} 与任何模式都不匹配,则使用 spring.cloud.config.server.git.uri 下定义的默认 URI。在上例中,对于“simple”仓库,模式是 simple/*(它仅匹配所有 profile 中名为 simple 的一个应用程序)。“local”仓库匹配所有 profile 中名称以 local 开头的所有应用程序(任何没有 profile 匹配器的模式都会自动添加 /* 后缀)。

“simple”示例中使用的“一句话”快捷方式只能在唯一需要设置的属性是 URI 时使用。如果您需要设置其他任何内容(凭据、模式等),则需要使用完整形式。

仓库中的 pattern 属性实际上是一个数组,因此您可以使用 YAML 数组(或属性文件中的 [0][1] 等后缀)来绑定到多个模式。如果您要运行具有多个 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 推断,包含不以 * 结尾的 profile 的模式意味着您实际上想要匹配以此模式开头的一系列 profile(因此 */staging["*/staging", "*/staging,*"] 等的快捷方式)。这在例如您需要在本地使用“development”profile 运行应用程序,同时在远程使用“cloud”profile 时很常见。

每个仓库还可以选择将配置文件存储在子目录中,并且可以指定搜索这些目录的模式作为 search-paths。以下示例显示了一个顶层配置文件:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          search-paths:
            - 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: https://git/team-a/config-repo.git
            team-b:
                pattern: team-b-*
                cloneOnStart: false
                uri: https://git/team-b/config-repo.git
            team-c:
                pattern: team-c-*
                uri: https://git/team-a/config-repo.git

在前例中,服务器在启动时克隆 team-a 的 config-repo,然后才接受任何请求。所有其他仓库直到请求该仓库中的配置时才被克隆。

在配置服务器启动时设置要克隆的仓库有助于快速识别配置源配置错误(例如无效的仓库 URI),这在配置服务器启动过程中发生。如果未为配置源启用 cloneOnStart,配置服务器可能会成功启动,即使配置源配置错误或无效,直到应用程序请求该配置源中的配置时才检测到错误。

认证

要在远程仓库上使用 HTTP 基本认证,请分别添加 usernamepassword 属性(不要放在 URL 中),如下例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          username: trolley
          password: strongpassword

如果您不使用 HTTPS 和用户凭据,当您将密钥存储在默认目录 (~/.ssh) 中并且 URI 指向 SSH 位置(例如 [email protected]:configuration/cloud-configuration)时,SSH 也应该开箱即用。重要的是 ~/.ssh/known_hosts 文件中存在 Git 服务器的条目,并且格式为 ssh-rsa。不支持其他格式(例如 ecdsa-sha2-nistp256)。为避免意外,您应该确保 known_hosts 文件中对于 Git 服务器只有一个条目,并且与您提供给配置服务器的 URL 匹配。如果您在 URL 中使用主机名,则希望 known_hosts 文件中也是完全一样的主机名(而不是 IP)。仓库通过 JGit 访问,因此您找到的任何 JGit 文档都应该适用。HTTPS 代理设置可以在 ~/.git/config 中或(与任何其他 JVM 进程相同的方式)通过系统属性 (-Dhttps.proxyHost-Dhttps.proxyPort) 进行设置。

如果您不知道 ~/.git 目录在哪里,请使用 git config --global 来操作设置(例如,git config --global http.sslVerify false)。

JGit 需要 PEM 格式的 RSA 密钥。以下是 ssh-keygen(来自 openssh)命令的一个示例,它将生成正确格式的密钥:

ssh-keygen -m PEM -t rsa -b 4096 -f ~/config_server_deploy_key.rsa

警告:使用 SSH 密钥时,预期的 SSH 私钥必须以 -----BEGIN RSA PRIVATE KEY----- 开头。如果密钥以 -----BEGIN OPENSSH PRIVATE KEY----- 开头,则在启动 spring-cloud-config 服务器时将无法加载 RSA 密钥。错误类似于:

- Error in object 'spring.cloud.config.server.git': codes [PrivateKeyIsValid.spring.cloud.config.server.git,PrivateKeyIsValid]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [spring.cloud.config.server.git.,]; arguments []; default message []]; default message [Property 'spring.cloud.config.server.git.privateKey' is not a valid private key]

要纠正上述错误,必须将 RSA 密钥转换为 PEM 格式。上面提供了一个使用 openssh 生成新密钥的示例,其格式是适当的。

AWS CodeCommit 认证

Spring Cloud Config Server 还支持 AWS CodeCommit 认证。AWS CodeCommit 在从命令行使用 Git 时使用认证助手。JGit 库不使用此助手,因此如果 Git URI 与 AWS CodeCommit 模式匹配,则会创建一个用于 AWS CodeCommit 的 JGit CredentialProvider。AWS CodeCommit URI 遵循以下模式:

https://git-codecommit.${AWS_REGION}.amazonaws.com/v1/repos/${repo}

如果您为 AWS CodeCommit URI 提供了用户名和密码,它们必须是提供仓库访问权限的 AWS accessKeyId 和 secretAccessKey。如果您未指定用户名和密码,则使用 默认凭证提供程序链 获取 accessKeyId 和 secretAccessKey。

如果您的 Git URI 与 CodeCommit URI 模式(如前所示)匹配,则必须在用户名和密码中或默认凭证提供程序链支持的位置之一提供有效的 AWS 凭据。AWS EC2 实例可以使用 适用于 EC2 实例的 IAM 角色

software.amazon.awssdk:auth jar 是一个可选依赖项。如果 software.amazon.awssdk:auth jar 不在您的 classpath 中,则不会创建 AWS Code Commit 凭证提供程序,无论 Git 服务器 URI 如何。

Google Cloud Source 认证

Spring Cloud Config Server 还支持针对 Google Cloud Source 仓库进行认证。

如果您的 Git URI 使用 httphttps 协议且域名是 source.developers.google.com,则将使用 Google Cloud Source 凭证提供程序。Google Cloud Source 仓库 URI 的格式为 source.developers.google.com/p/${GCP_PROJECT}/r/${REPO}。要获取您的仓库 URI,请在 Google Cloud Source UI 中点击“Clone”,然后选择“Manually generated credentials”。不要生成任何凭据,只需复制显示的 URI 即可。

Google Cloud Source 凭证提供程序将使用 Google Cloud Platform 应用程序默认凭据。有关如何为系统创建应用程序默认凭据,请参阅 Google Cloud SDK 文档。此方法适用于开发环境中的用户账户和生产环境中的服务账户。

com.google.auth:google-auth-library-oauth2-http 是一个可选依赖项。如果 google-auth-library-oauth2-http jar 不在您的 classpath 中,则不会创建 Google Cloud Source 凭证提供程序,无论 Git 服务器 URI 如何。

使用属性配置 Git SSH

默认情况下,Spring Cloud Config Server 使用的 JGit 库在通过 SSH URI 连接到 Git 仓库时会使用 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: [email protected]: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-----

下表描述了 SSH 配置属性。

表 1. SSH 配置属性
属性名称 备注

ignoreLocalSshSettings

如果为 true,则使用基于属性而非基于文件的 SSH 配置。必须设置为 spring.cloud.config.server.git.ignoreLocalSshSettings不能设置在仓库定义内部。

privateKey

有效的 SSH 私钥。如果 ignoreLocalSshSettings 为 true 且 Git URI 为 SSH 格式,则必须设置。

hostKey

有效的 SSH 主机密钥。如果 hostKeyAlgorithm 也已设置,则必须设置。

hostKeyAlgorithm

以下之一:ssh-dss, ssh-rsa, ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, or ecdsa-sha2-nistp521。如果 hostKey 也已设置,则必须设置。

strictHostKeyChecking

truefalse。如果为 false,则忽略主机密钥错误。

knownHostsFile

自定义 .known_hosts 文件的位置。

preferredAuthentications

覆盖服务器认证方法顺序。这应该允许在服务器将 keyboard-interactive 认证置于 publickey 方法之前时绕过登录提示。

Git 搜索路径中的占位符

Spring Cloud Config Server 还支持带有 {application}{profile} 占位符(如果您需要,也可以使用 {label})的搜索路径,如下例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          search-paths: '\{application}'

前面的列表导致搜索仓库中与目录同名(以及顶层)的文件。通配符在带有占位符的搜索路径中也是有效的(任何匹配的目录都包含在搜索中)。

在 Git 仓库中强制拉取

如前所述,Spring Cloud Config Server 会克隆远程 Git 仓库,以防本地副本变脏(例如,文件夹内容因 OS 进程而更改),导致 Spring Cloud Config Server 无法从远程仓库更新本地副本。

为解决此问题,有一个 force-pull 属性,如果本地副本脏了,它将使 Spring Cloud Config Server 强制从远程仓库拉取,如下例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          force-pull: true

如果您有多个仓库配置,可以为每个仓库配置 force-pull 属性,如下例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://git/common/config-repo.git
          force-pull: true
          repos:
            team-a:
                pattern: team-a-*
                uri: https://git/team-a/config-repo.git
                force-pull: true
            team-b:
                pattern: team-b-*
                uri: https://git/team-b/config-repo.git
                force-pull: true
            team-c:
                pattern: team-c-*
                uri: https://git/team-a/config-repo.git
force-pull 属性的默认值为 false

删除 Git 仓库中的未跟踪分支

由于 Spring Cloud Config Server 在检出分支到本地仓库(例如通过标签获取属性)后会克隆远程 Git 仓库,它将永久保留此分支,直到下次服务器重启(这会创建新的本地仓库)。因此,可能会出现远程分支被删除,但本地副本仍可用于获取的情况。如果 Spring Cloud Config Server 客户端服务以 --spring.cloud.config.label=deletedRemoteBranch,master 启动,它将从 deletedRemoteBranch 本地分支获取属性,而不是从 master 获取。

为了保持本地仓库分支干净并与远程保持一致,可以设置 deleteUntrackedBranches 属性。这将使 Spring Cloud Config Server 强制删除本地仓库中的未跟踪分支。例如:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          deleteUntrackedBranches: true
deleteUntrackedBranches 属性的默认值为 false

Git 刷新频率

您可以使用 spring.cloud.config.server.git.refreshRate 控制配置服务器从 Git 后端获取更新配置数据的频率。此属性的值以秒为单位指定。默认值为 0,表示配置服务器在每次请求时都会从 Git 仓库获取更新的配置。如果值为负数,则不会发生刷新。

默认标签

Git 使用的默认标签是 main。如果您未设置 spring.cloud.config.server.git.defaultLabel 且名为 main 的分支不存在,配置服务器默认也会尝试检出名为 master 的分支。如果您想禁用回退分支行为,可以将 spring.cloud.config.server.git.tryMasterBranch 设置为 false

在容器中使用 Git 运行配置服务器

如果您在容器中运行配置服务器时遇到类似于以下的 java.io.IOException

2022-01-03 20:04:02,892 [tributeWriter-2] ERROR org.eclipse.jgit.util.FS$FileStoreAttributes.saveToConfig - Cannot save config file 'FileBasedConfig[/.config/jgit/config]'
java.io.IOException: Creating directories for /.config/jgit failed

您必须要么

  1. 在容器内提供一个具有写入权限的主目录的用户。

  2. 在容器内设置环境变量 XDG_CONFIG_HOME,指向 Java 进程具有写入权限的目录。