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
类似案例:
其实我并不懂,都是靠大佬的分析
结合自己啥都略懂的能力