分佈式配置中心-Config

一、常規的配置設置方式

  • Hardcode:寫死在代碼之中,每次修改需要發佈修改代碼,並且配置零散的存放在程序各處
  • 配置文件:從代碼中提到application.yml和bootstrap.yml文件中,雖然修改後依舊要重新發布程序,但是配置被集中管理了
  • 環境變量:一般情況下是通過程序啓動參數 和 系統層面的環境變量實現
  • 數據庫(緩存)存儲:將參數存放到數據庫中使用,這種方式會增加數據庫的壓力

1、傳統配置管理的缺點

  • 格式不統一:傳統的配置文件格式不統一,SpringBoot的有properties和yml,spring的用xml配置,再老一點的還有使用json的
  • 沒有版本管理:使用配置文件還有git和svn能管理一下,存到數據庫中的 真的是改掉再也變不回來了。
  • 基於靜態配置:修改、發佈的流程繁瑣,每次變動都需要在發佈
  • 分佈零散:hardcode方式直接散落在代碼中,配置文件的方式好一點,但是隨之時代的進步,在分佈式的架構中配置文件的方式力不從心了,每一個模塊都有大量的配置

二、分佈式配置中心——Config

Config作爲SpringCloud官方指定產品,必然有獨到之處,在配置管理方面主要提供了三大功能

  • 統一配置:提供了一箇中心化的配置方案,將各個項目中的配置內容集中在Config Server一端
  • 環境隔離:Config Server提供了多種環境隔離機制,Client可以根據自身所處的項目環境(比如生產環境、測試環境)加載對應的配置文件
  • 動態刷新:支持運行期改變配置屬性
    除此之外,還有加密解密、定向推送等功能

1、Config的配置文件命名規則

  • application:服務的名字
  • profile:環境名稱
  • label:對應git上不同的分支,默認爲:master(程序的git版本與之對應,可以用於配置文件的版本控制)

規則1:{application}-{profile}.yml或{application}-{profile}.properties
示例:order-dev.yml 訂單服務開發環境的配置文件

規則2:/{label}/{application}-{profile}.yml或/{label}/{application}-{profile}.properties
示例:/master/order-dev.yml 主分支下的訂單服務開發環境的配置文件

規則3:{application}/{profile}[/{label}]

2、config小demo

(1)前期準備

1)創建一個git項目

在git、碼雲或者github上創建一個新的項目,專門用來存放配置文件,我這裏命名爲:config-repo

2)在git上創建配置文件

在config-repo中創建一個文件名爲config-consumer-dev.yml

info: 
    profile: dev
    
name: Saul
words: 'God bless me'

然後提交文件,再創建一個配置文件,文件名爲config-consumer-prod.yml

info: 
    profile: prod
    
name: Paul
words: 'God bless you'

(2)服務端代碼

1)創建一個config-server(配置中心的服務模塊)模塊,修改配置文件
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigServerApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
3)創建配置文件application.yml
server: 
    port: 60000

spring: 
    application: 
        name: config-server
    cloud:
        config: 
            server:
                #強制重載配置,把遠端上的配置覆蓋掉
                overrides:
                    #忽略遠端上的test屬性,使用這裏的test值
                    test: mytest
                git:
                    #git地址
                    uri: https://github.com/xxxx/config-repo.git
                    #git登錄名
                    username: 敲代碼的旺財
                    #git密碼
                    password: 真帥
                    #配置文件在git下的目錄,可以配置多個,主要用於區分開項目
                    #search-paths: test, mall
                    #強制拉取
                    force-pull: true
4)運行模塊進行測試

發送一個git請求到 http://localhost:60000/config-consumer/dev

  • http://localhost:60000/:這部分是服務地址
  • config-consumer/dev:這部分是配置的文件名

可以多嘗試幾種訪問:config會自動轉換格式,返回我們對應的格式

  • http://localhost:60000/config-consumer-dev.yml
  • http://localhost:60000/config-consumer/dev.properties
  • http://localhost:60000/config-consumer/dev.json

(3)客戶端代碼

1)創建一個config-client模塊,修改配置文件
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <!-- 配置中心需要他暴露端口,提供動態拉取參數的能力 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-cloud-starter-actuator</artifactId>
    </dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
public class ConfigClientApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigClientApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
3)創建一個Controller
@RestController
//spring的註解,可以重新初始化當前對象,並且會完全的重新注入對象
@RefreshScope
public class Controller{
    @Value("${name}")
    public String name;
    @Value("${myWords}")
    public String words;
    
    @GetMapping("/name")
    public String getName(){
        return name;
    }
    
    @GetMapping("/words")
    public String getWords(){
        return words;
    }
}
4)創建配置文件application.yml
server: 
    port: 61000
    
#從配置中心獲取words屬性
myWords: ${words}

spring: 
    application: 
        name: config-client
    cloud:
        config: 
            #配置中心地址
            uri: http://localhost:60000
            #加載的配置文件的環境(這裏一般不是寫死的 而是通過啓動參數,或者系統環境變量來配置)
            profile: prod
            label: master
            #指定配置文件中的application,默認的爲spring.application.name的值
            name: config-consumer
#開放端口用於刷新配置文件 
management: 
    security: 
        #關閉安全訪問
        enabled: false
    endpoints:
        web: 
            exposure: 
                #開放所有端口
                include: "*"
    endpoint: 
        helth: 
            show-details: always
                
5)啓動程序,調用controller進行測試
  1. get請求訪問地址http://localhost:61000/name
  2. 然後改變配置文件,把name屬性改掉
name: Saul and Paul
  1. get請求調用刷新配置的端口http://localhost:61000/actuator/refresh
  2. 再次訪問地址http://localhost:61000/name

三、高可用配置中心

1、實現原理

  現在的配置中心是單節點的,所有的服務都連接在這個單節點的配置中心上,如果配置中心宕機了,那所有服務的配置就不能更新了,我們將配置中心搭建成集羣,在服務和配置中心集羣中間,搭建一個負載均衡器,如果一個配置中心的節點宕機了,負載均衡器將請求轉到還存活的節點上

2、藉助Eureka實現高可用配置中心

(1)服務端代碼修改

1)創建一個config-server(配置中心的服務模塊)模塊,修改配置文件
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServerApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigServerApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
3)創建配置文件application.yml
server: 
    port: 60000
    
eureka: 
    client: 
        serviceUrl: 
            defaultZone: http://localhost:20000/eureka/

spring: 
    application: 
        name: config-server
    cloud:
        config: 
            server:
                git:
                    #git地址
                    uri: https://github.com/xxxx/config-repo.git
                    #git登錄名
                    username: 敲代碼的旺財
                    #git密碼
                    password: 真帥
                    #配置文件在git下的目錄,可以配置多個,主要用於區分開項目
                    #search-paths: test, mall
                    #強制拉取
                    force-pull: true

這裏可以啓動多個config-server,改下端口號就行了

(2)客戶端代碼修改

1)創建一個config-client模塊,修改配置文件
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <!-- 配置中心需要他暴露端口,提供動態拉取參數的能力 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-cloud-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>
2)修改啓動類
@SpringBootApplication
@EnableDiscoveryClient
public class ConfigClientApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigClientApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
4)創建配置文件application.yml
server: 
    port: 61000
    
#從配置中心獲取words屬性
myWords: ${words}

eureka: 
    client: 
        serviceUrl: 
            defaultZone: http://localhost:20000/eureka/

spring: 
    application: 
        name: config-client
    cloud:
        config: 
            discovery: 
                #啓動服務發現功能
                enabled: true
                service-id: config-server-eureka
            #加載的配置文件的環境(這裏一般不是寫死的 而是通過啓動參數,或者系統環境變量來配置)
            profile: prod
            label: master
            #指定配置文件中的application,默認的爲spring.application.name的值
            name: config-consumer
#開放端口用於刷新配置文件 
management: 
    security: 
        #關閉安全訪問
        enabled: false
    endpoints:
        web: 
            exposure: 
                #開放所有端口
                include: "*"
    endpoint: 
        helth: 
            show-details: always
                

四、配置加密

  數據庫密碼是一個相當機密的信息,儘量不要讓安全級別不高的個人或團隊直接接觸到。儘管我們程序猿們個個都是信得過的,不會隨便登錄生產環境做破壞性操作,可也不能保證突發事件的發生。比如今天我和產品經理幹了一架,打輸了,氣不過,拿着密碼登錄生產環境刪庫跑路了。
  我們需要引入一個數據安全機制,減少敏感數據的暴露程度,因此需要對三個環節做嚴格控制。
  數據加密端 就像頒發CA證書一樣,必須由一箇中心機構用密鑰對明文進行加密。這裏也一樣,需要在生產環境中創建一個特定的服務,專門做加密操作。最重要的是,加密所用的祕鑰只能保存在那臺機器裏,不能對外暴露數據存放端 數據存放端(如GitHub)只能保存加密過後的數據數據解密端 由於密鑰都保存在數據加密端,因此數據解密和數據加密必須放在同一個地方進行,加密數據在傳給客戶端之前要經過解密,不能將祕鑰下放到客戶端機器上進行解密。

  我們需要引入一個數據安全機制,減少敏感數據的暴露程度,因此需要對三個環節做嚴格控制

  • 數據加密端:就像頒發CA證書一樣,必須由一箇中心機構用密鑰對明文進行加密。這裏也一樣,需要在生產環境中創建一個特定的服務,專門做加密操作。最重要的是,加密所用的祕鑰只能保存在那臺機器裏,不能對外暴露
  • 數據存放端:數據存放端(如GitHub)只能保存加密過後的數據
  • 數據解密端:由於密鑰都保存在數據加密端,因此數據解密和數據加密必須放在同一個地方進行,加密數據在傳給客戶端之前要經過解密,不能將祕鑰下放到客戶端機器上進行解密

1、加密Demo

(1)修改jdk的jce主鍵

  1. 在Oracle的官網下載jce
    https://www.oracle.com/java/technologies/javase-jce-all-downloads.html
    只有jdk6/7/8並且版本低於6u16/7u171/8u161,才需要下載
  2. 下載的文件解壓,得到loacl_policy.jar和US_export_policy.jar,將解壓後的文件拷貝到java目錄\jre\lib\security下,覆蓋同名文件

(2)config-server修改bootstrap.yml配置文件

encrypt:
    #加密用的key,隨便寫
    key: keyboardDog

發送一個get無參請求到localhost:60001/encrypt/status上,測試配置是否成功

(3)對字符串進行加密/解密

  1. 加密
    發送一個post請求到localhost:60001/encrypt上,使用row傳參,參數直接填寫想要加密的字符串
  2. 解密
    發送一個post請求到localhost:60001/dencrypt上,使用row傳參,參數直接填寫加密過後的字符串

(4)修改github上的配置文件

info: 
    profile: prod
    
name: Paul
#這裏把字符串換掉,{cipher} 表示這個字符串需要解密 ,後面跟上加密過後的字符串
words: '{cipher}xxxxxxxxxxxxxxxxxxxxx'
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章