1. 程式人生 > >Spring Cloud:多環境配置、註冊中心安全認證、容器宿主機IP註冊

Spring Cloud:多環境配置、註冊中心安全認證、容器宿主機IP註冊

記錄一下搭建 Spring Cloud 過程中踩過的一些坑。寫這篇隨筆時候不知道為什麼想到了看過的一個短片《斷崖》,看的時候真的感受到了女主的絕望和無助。感覺自己就像女主一樣,我在自己技術水平的坑裡努力的爬著,好的是我爬出來了,壞的是外面還有一個更大的坑!!!人生路漫漫,且爬且珍惜!

Spring 版本

  • Spring Boot:2.0.0.RELEASE
  • Spring Cloud:Finchley.SR2

多環境配置

多配置的切換在開發中真是很常用,能有效提高效率。一些成熟的框架基本都有關於配置切換的解決方案,當然了 Spring Cloud 也不例外!

先看看我的配置檔案結構:

配置檔案通過後綴區分:dev - 開發環境配置,test - 測試環境配置,prod - 生產環境配置。

bootstrap.yml 檔案來配置載入那個配置檔案:

spring:
  profiles:
    active: dev

 spring.profiles.active 配置的就是需要載入的配置檔案,這樣就能通過配置來載入不同的配置檔案。

但是,我們一般都是打包成 jar 包來執行,這樣分別打包還是有點麻煩,所以可以打包一個 jar 包,通過新增啟動引數來載入不同的配置:

java -jar xxx.jar --spring.profiles.active=dev 表示使用開發環境的配置
java -jar xxx.jar --spring.profiles.active=test 表示使用測試環境的配置
java -jar xxx.jar --spring.profiles.active=prod 表示使用生產環境的配置

這裡貼一個我封裝的啟動 jar 包的 shell 指令碼:

#!/bin/bash
JARURI=$1 # 第一個引數為jar包絕對路徑
CONFENV=$2 # 第二個引數為配置環境
LOGSDIR=$3 # 第三個引數為日誌目錄

# 判斷檔案是否存在
if [ ! -f "$JARURI" ];then
    echo "ERROR:File does not exist;"
    exit 1
fi

# 判斷日誌目錄是否存在
if [ ! -d "$LOGSDIR" ];then
    echo "ERROR:Directory does not exist;
" exit 1 fi # 判斷配置環境 ENVARR=("dev" "test" "prod") if echo "${ENVARR[@]}" | grep -w "$CONFENV" &>/dev/null; then : else echo "ERROR:Env does not exist;" exit 1 fi # 啟動 OLD_IFS="$IFS" IFS="/" file_array=($JARURI) IFS="$OLD_IFS" file_array_len=${#file_array[*]} file_name_index=`expr $file_array_len - 1` log_uri=${LOGSDIR%*/}/${file_array[$file_name_index]}_"$CONFENV"_$(date "+%Y_%b_%d_%H_%M_%S_%N").txt java -jar $JARURI > $log_uri --spring.profiles.active=$CONFENV &

註冊中心安全認證

註冊中心的頁面是直接就能訪問的,這肯定不是我們所希望的,所以需要新增安全機制進行保護,這裡需要用到依賴 spring-boot-starter-security 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

配置檔案增加 spring.security.user.name 和 spring.security.user.password 配置,修改註冊中心地址:

eureka:
  client:
    service-url:
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.1.254:9010/eureka/ # 註冊中心地址
    register-with-eureka: false # 是否註冊到註冊中心
    fetch-registry: false # 是否拉取服務列表
  server:
    enable-self-preservation: true # 是否開啟註冊中心保護機制
    eviction-interval-timer-in-ms: 60000 # 服務清理間隔,毫秒
  instance:
    prefer-ip-address: true # 是否使用IP地址廣播服務
    lease-renewal-interval-in-seconds: 30 # 服務租約時間,秒
    lease-expiration-duration-in-seconds: 90 # 間隔多久時間沒有傳送心跳,認為服務不可用,秒

spring:
  # 服務設定
  application:
    name: server-eureka
  # 安全機制
  security:
    user:
      name: eureka
      password: 123456

# 服務設定
server:
  port: 9010

使用此元件,安全是實現了,訪問註冊中心頁面,需要登入使用者名稱和密碼了,但是問題也出現了,客戶端服務一直註冊不上去。我查詢資料給出的解決方案是禁用 security 的 csrf,下面是處理方案,但是我使用此方案並不生效

@EnableWebSecurity
    static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);//加這句是為了訪問eureka控制檯和/actuator時能做安全控制
            http.csrf().disable();
        }
    }

上面的方案我使用不生效,我使用下面的方案解決的:

package com.microview.servereureka.basic;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;

/**
 * 註冊中心basic認證
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${spring.security.user.name}")
    private String username;

    @Value("${spring.security.user.password}")
    private String password;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .passwordEncoder(NoOpPasswordEncoder.getInstance())
                .withUser(username).password(password)
                .authorities("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf()
                .disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }
}

容器宿主機IP註冊

由於所有的專案都執行在 Docker 容器中,這就導致客戶端註冊到註冊中心的 IP 地址為容器的虛擬 IP,無法通過外部訪問,這裡的解決方案是構建容器時候設定容器的網路模式為橋接模式。

docker-compose.yml 中配置 network_mode: "bridge" 

客戶端配置檔案中相關配置(192.168.1.254 為宿主機IP地址):

eureka:
  client:
    service-url:
      defaultZone: http://eureka:[email protected]:9010/eureka/
  instance:
    instance-id: ${eureka.instance.ip-address}:${server.port}
    ip-address: 192.168.1.254
    prefer-ip-address: true

這樣註冊到註冊中心的IP地址就是宿主機的IP了。

參考資料

https://blog.csdn.net/quanqxj/article/details/80592231

https://github.com/spring-cloud/spring-cloud-netflix/issues/2754

https://www.oschina.net/question/556985_2273961

https://blog.csdn.net/qq_36148847/article/details/79427878