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

猜你喜欢

转载自www.cnblogs.com/bndong/p/10037197.html