Docker 容器内 Springboot 项目启动慢问题

源起

Springboot项目启动很慢,日志报:

o.springframework.boot.StartupInfoLogger - InetAddress.getLocalHost().getHostName() took 20020 milliseconds to respond. Please verify your network configuration.

查阅发现是由于DNS或网络问题,ping容器的hostname不通。

在/etc/hosts文件里指定 127.0.0.1 hostname可以解决。

不过为了清楚原理做了一些探究。

探究

JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
    char hostname[NI_MAXHOST+1];
 
    hostname[0] = '\0';
    if (JVM_GetHostName(hostname, sizeof(hostname))) {//如果获取失败,则设置默认值localhost
        /* Something went wrong, maybe networking is not setup? */
        strcpy(hostname, "localhost");
    } else {
        struct addrinfo hints, *res;
        int error;
 
        hostname[NI_MAXHOST] = '\0'; //设置默认结束符
        memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_CANONNAME; //这个参数很重要,要求返回主机规范名称,非别名
        hints.ai_family = AF_INET;
 
        error = getaddrinfo(hostname, NULL, &hints, &res); //这里hostname会重新改写
 
        if (error == 0) {/* host is known to name service */
            getnameinfo(res->ai_addr,
                        res->ai_addrlen,
                        hostname,
                        NI_MAXHOST,
                        NULL,
                        0,
                        NI_NAMEREQD);
 
            /* if getnameinfo fails hostname is still the value
               from gethostname */
 
            freeaddrinfo(res);
        }
    }
    return (*env)->NewStringUTF(env, hostname);

JDK的源码大致如上,通过JVM_GetHostName获取hostname

对应Linux的源码:

inline int hpi::get_host_name(char* name, int namelen){
  return ::gethostname(name, namelen);
}

查阅资料得知,这里的gethostname获取的是/etc/hostname里保存的主机名。但如果在容器里修改/etc/hostname,这个方法依然还是打印的旧的,暂时无法生效。这个有待研究。

尝试通过设置宿主机的/etc/hosts,将 127.0.0.1 hostname加入配置文件,但发现容器里的/etc/hosts并不同步宿主机/etc/hosts的修改。容器运行时已经添加了 --network=host 参数,但是同时有 --add-host 参数。测试不加--add-host参数,则可以实现同步,看起来就是设置了--add-host则不继承/etc/hosts的设置。这部分没搜到资料,已经发帖询问docker官方。

所以目前的解决方法是添加 --add-host hostname:127.0.0.1

类似案例:

stackoerflow

CSDN

 
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口

    29 引用
  • 虚拟化

    4 引用
  • 云原生

    13 引用
  • 运维

    8 引用