Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在Springboot 3中Spring Cloud Gateway 使用Nacos做配置中心,打包Native Image 后,无法通过环境变量和启动参数修改Nacos服务端地址,一直都是默认的127.0.0.1:8848 #12692

Closed
robben766 opened this issue Sep 25, 2024 · 6 comments
Labels
area/Spring Cloud Related to Spring Cloud status/invalid This doesn't seem right

Comments

@robben766
Copy link

Describe the bug
打包成本地镜像(Native Image )后,无法通过环境变量,或者启动参数,修改 spring.cloud.nacos.config.serverAddr值,一直获取的是 NacosConfigProperties 中默认的 public static final String DEFAULT_ADDRESS = "127.0.0.1:8848";

Expected behavior
希望能够在打包为Native Image后,通过修改环境变量,或者传入启动参数后,能够正常连接到Nacos服务端,获取到服务配置

Actually behavior
得到错误


2024-09-25T19:14:25.180+08:00  INFO 62858 --- [gateway] [remote.worker.1] c.a.n.c.remote.client.grpc.GrpcClient    : grpc client connection server:127.0.0.1 ip,serverPort:9848,grpcTslConfig:{"sslProvider":"","enableTls":false,"mutualAuthEnable":false,"trustAll":false}
2024-09-25T19:14:25.180+08:00 ERROR 62858 --- [gateway] [remote.worker.1] c.a.n.c.remote.client.grpc.GrpcClient    : Server check fail, please check server 127.0.0.1 ,port 9848 is available , error ={}

java.util.concurrent.ExecutionException: com.alibaba.nacos.shaded.io.grpc.StatusRuntimeException: UNAVAILABLE: io exception

How to Reproduce
打包Native Image

mvn clean -Pnative native:compile 

启动命令

./gateway -Dspring.cloud.nacos.config.server-addr=192.168.1.7:8848

或者

export SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR=192.168.1.7:8848
./gateway

均得到上面的错误,读取了默认的127.0.0.1:8848的服务端地址

初步结论
在Native Image打包的时候,将默认值打包到二进制中了

启动的时候,创建客户端监听,通过NacosConfigDataLoader的load方法,从Nacos服务端拉取配置。ConfigService configService = getBean(context, NacosConfigManager.class).getConfigService();获取配置服务,调用NacosConfigManagergetConfigService()方法获取,通过自身属性的nacosConfigProperties.assembleConfigServiceProperties()获取服务端地址。

nacosConfigProperties的方法有一段是,如果serverAddr不存在,endpoint也不存在时,则设置默认值127.0.0.1:8848

个人猜测,Native Image打包的时候,将这个方法assembleConfigServiceProperties()“固化”下来了,无法通过环境变量或者启动参数进行修改该值。

尝试解决
修改NacosConfigPropertiesassembleConfigServiceProperties()方法,将properties.put(SERVER_ADDR, DEFAULT_ADDRESS);修改为:properties.put(SERVER_ADDR, System.getenv("SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR"));问题得以解决。

验证方式
基于上面修改后的代码,重新打包(打包时不设置SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR的环境变量)。启动前设置环境变量export SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR=192.168.1.7:8848后,再启动(./gateway),观察日志,连接的不再是127.0.0.1:8848。也不是在打包时的SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR环境变量

关键代码配置类NacosConfigProperties代码

	/**
	 * Nacos default server and port.
	 */
	public static final String DEFAULT_ADDRESS = "127.0.0.1:8848";

public Properties assembleConfigServiceProperties() {
		Properties properties = new Properties();
		properties.put(SERVER_ADDR, Objects.toString(this.serverAddr, ""));
		properties.put(USERNAME, Objects.toString(this.username, ""));
		properties.put(PASSWORD, Objects.toString(this.password, ""));
		properties.put(ENCODE, Objects.toString(this.encode, ""));
		properties.put(NAMESPACE, this.resolveNamespace());
		properties.put(ACCESS_KEY, Objects.toString(this.accessKey, ""));
		properties.put(SECRET_KEY, Objects.toString(this.secretKey, ""));
		properties.put(RAM_ROLE_NAME, Objects.toString(this.ramRoleName, ""));
		properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, ""));
		properties.put(MAX_RETRY, Objects.toString(this.maxRetry, ""));
		properties.put(CONFIG_LONG_POLL_TIMEOUT,
				Objects.toString(this.configLongPollTimeout, ""));
		properties.put(CONFIG_RETRY_TIME, Objects.toString(this.configRetryTime, ""));
		properties.put(ENABLE_REMOTE_SYNC_CONFIG,
				Objects.toString(this.enableRemoteSyncConfig, ""));
		String endpoint = Objects.toString(this.endpoint, "");
		if (endpoint.contains(":")) {
			int index = endpoint.indexOf(":");
			properties.put(ENDPOINT, endpoint.substring(0, index));
			properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));
		}
		else {
			properties.put(ENDPOINT, endpoint);
		}

		enrichNacosConfigProperties(properties);

		// set default value when serverAddr and endpoint is empty
		if (StringUtils.isEmpty(this.serverAddr) && StringUtils.isEmpty(this.endpoint)) {
			properties.put(SERVER_ADDR, DEFAULT_ADDRESS);
		}

		return properties;
	}

Desktop (please complete the following information):

  • OS: Centos、Macos
  • Version: [Spring Boot 3.3.3, Spring Cloud Gateway 4.1.5, Spring Cloud Starter Alibaba Nacos Config 2023.0.1.2]
  • JDK [GraalVM 21.0.2+13.1 ]

Additional context

Pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.3</version>
    <relativePath/>
  </parent>

  <groupId>com.demo.gateway</groupId>
  <artifactId>gateway</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>gateway</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>

    <spring-cloud.version>2023.0.3</spring-cloud.version>
    <alibaba.version>2023.0.1.2</alibaba.version>
    <maven.javadoc.skip>true</maven.javadoc.skip>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>${alibaba.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

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

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>

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


  <build>
    <plugins>
      <plugin>
        <groupId>org.graalvm.buildtools</groupId>
        <artifactId>native-maven-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <fallback>false</fallback>
          <buildArgs>
            <buildArg>-march=x86-64</buildArg>
          </buildArgs>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <mainClass>com.demo.gateway.GatewayApplication</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

application.yml

spring:
  cloud:
    nacos:
      config:
        server-addr: nacos-cs.nacos.svc:8848
        group: test
        namespace: local-dev
        enabled: true
  config:
    import: optional:nacos:gateway-prod.yml

其他补充
最终我希望在K8S环境中使用,Nacos部署在K8S中,地址通过k8s的service+端口暴露,为了减少Nacos内置差异(端口偏移量+1000的内置设计),均采用推荐端口。

通过上面方式解决后,还遇到了其他问题,还未来得及排查和解决

2024-09-25T18:13:22.203+08:00 ERROR 1 --- [gateway] [listener.task-0] com.alibaba.nacos.common.remote.client   : Send request fail, request = ConfigBatchListenRequest{headers={charset=UTF-8, Client-AppName=unknown, Client-RequestToken=f439a1297a63d58c01a51a5afd11c17d, Client-RequestTS=1727259202103, exConfigInfo=true}, requestId='null'}, retryTimes = 0, errorMessage = Client not connected, current status:STARTING
2024-09-25T18:13:22.304+08:00 ERROR 1 --- [gateway] [listener.task-0] com.alibaba.nacos.common.remote.client   : Send request fail, request = ConfigBatchListenRequest{headers={charset=UTF-8, Client-AppName=unknown, Client-RequestToken=f439a1297a63d58c01a51a5afd11c17d, Client-RequestTS=1727259202103, exConfigInfo=true}, requestId='null'}, retryTimes = 1, errorMessage = Client not connected, current status:STARTING
2024-09-25T18:13:22.404+08:00 ERROR 1 --- [gateway] [listener.task-0] com.alibaba.nacos.common.remote.client   : Send request fail, request = ConfigBatchListenRequest{headers={charset=UTF-8, Client-AppName=unknown, Client-RequestToken=f439a1297a63d58c01a51a5afd11c17d, Client-RequestTS=1727259202103, exConfigInfo=true}, requestId='null'}, retryTimes = 2, errorMessage = Client not connected, current status:STARTING
2024-09-25T18:13:22.505+08:00 ERROR 1 --- [gateway] [listener.task-0] com.alibaba.nacos.common.remote.client   : Send request fail, request = ConfigBatchListenRequest{headers={charset=UTF-8, Client-AppName=unknown, Client-RequestToken=f439a1297a63d58c01a51a5afd11c17d, Client-RequestTS=1727259202103, exConfigInfo=true}, requestId='null'}, retryTimes = 3, errorMessage = Client not connected, current status:STARTING
2024-09-25T18:13:22.505+08:00 ERROR 1 --- [gateway] [listener.task-0] c.a.n.client.config.impl.ClientWorker    : Execute listen config change error
com.alibaba.nacos.api.exception.NacosException: Client not connected, current status:STARTING
at com.alibaba.nacos.common.remote.client.RpcClient.request(RpcClient.java:644) ~[gateway:na]
at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.requestProxy(ClientWorker.java:1221) ~[gateway:na]
at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.requestProxy(ClientWorker.java:1202) ~[gateway:na]
at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.lambda$checkListenCache$7(ClientWorker.java:1018) ~[gateway:na]
at [email protected]/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]
at [email protected]/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[gateway:na]
at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[gateway:na]
at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
at [email protected]/java.lang.Thread.run(Thread.java:840) ~[gateway:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:807) ~[gateway:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:210) ~[na:na]
@robben766
Copy link
Author

补充:
Native Image 对于 Refesh Scope 暂时不支持
Refresh scope is not supported with native images

Nacos 对 Native Image 支持存在问题,启动从Nacos获取配置后,无法加载到配置中

@KomachiSion
Copy link
Collaborator

这应该和nacos没有关系,首先nacos只负责推送新配置, 不负责应用新配置。如果是通过nacos-client直接订阅配置,那么在你的listner中需要自行实现新应用的配置逻辑。

如果是spring cloud, 那么使用新配置,并更新到bean或重建bean的逻辑,需要有spring cloud的实现对象来控制,也就是你依赖的Spring cloud alibaba。。

至于你提供的报错,更是和native没有关系, 单纯的就是你的客户端连接不上服务端,一直处于初始化状态(未完成首次连接)。

建议你排查环境上的问题,比如应用是否和nacos server网络不同,配置错误等等。

@KomachiSion
Copy link
Collaborator

另外, 一直使用默认值127.0.0.1的问题,也是spring cloud读取本地配置的问题,也需要您自行排查一下。配置错误读取了错误的文件,或者有--变量强制覆盖了配置文件等等。

@robben766
Copy link
Author

这应该和nacos没有关系,首先nacos只负责推送新配置, 不负责应用新配置。如果是通过nacos-client直接订阅配置,那么在你的listner中需要自行实现新应用的配置逻辑。

如果是spring cloud, 那么使用新配置,并更新到bean或重建bean的逻辑,需要有spring cloud的实现对象来控制,也就是你依赖的Spring cloud alibaba。。

至于你提供的报错,更是和native没有关系, 单纯的就是你的客户端连接不上服务端,一直处于初始化状态(未完成首次连接)。

建议你排查环境上的问题,比如应用是否和nacos server网络不同,配置错误等等。

确实不是直接使用Nacos Client,而是采用Spring Cloud Alibaba,所以这个问题我应该提给Spring Cloud Alibaba 的nacos config 吗?

网络环境已经排查没有问题,我分别是用jar包和native 文件测试验证的,jar是没有问题的。

@robben766
Copy link
Author

另外, 一直使用默认值127.0.0.1的问题,也是spring cloud读取本地配置的问题,也需要您自行排查一下。配置错误读取了错误的文件,或者有--变量强制覆盖了配置文件等等。

并没有使用--进行覆盖配置

@KomachiSion
Copy link
Collaborator

那就需要提交issue到spring cloud alibaba社区询问一下了, 因为这个默认值是SCA的,nacos-client本身没有默认值。

@KomachiSion KomachiSion added status/invalid This doesn't seem right and removed status/need feedback labels Oct 12, 2024
@KomachiSion KomachiSion closed this as not planned Won't fix, can't repro, duplicate, stale Oct 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/Spring Cloud Related to Spring Cloud status/invalid This doesn't seem right
Projects
None yet
Development

No branches or pull requests

2 participants