使用 gradle bootBuildImage 构建的 SpringBoot Docker 映像无法在 <1024 的任何端口上启动

Posted

技术标签:

【中文标题】使用 gradle bootBuildImage 构建的 SpringBoot Docker 映像无法在 <1024 的任何端口上启动【英文标题】:SpringBoot Docker image built with gradle bootBuildImage failing to start on any port < 1024 【发布时间】:2020-12-05 18:50:04 【问题描述】:

我使用 2.3.3.RELEASE 创建了一个简单的 SpringBoot 应用程序,并且能够使用 ./gradlew bootBuildImage 创建 docker 映像。

重现此问题的代码:https://github.com/sivaprasadreddy/spring-boot-aws-cdk-demo

build.gradle

springBoot 
    buildInfo()


bootJar 


bootBuildImage 
    imageName = "sivaprasadreddy/spring-boot-aws-cdk-demo"

我可以成功启动容器如下:

docker run -p 18080:8080 sivaprasadreddy/spring-boot-aws-cdk-demo

但如果我尝试使用以下命令在任何不同的端口(如 80)上运行应用程序,应用程序将无法启动。

docker run -e SERVER_PORT=80 -p 80:80 sivaprasadreddy/spring-boot-aws-cdk-demo

2020-08-16 12:34:22.707  WARN 1 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server
2020-08-16 12:34:22.715  INFO 1 --- [           main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-08-16 12:34:22.726  INFO 1 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Shutting down ExecutorService 'taskScheduler'
2020-08-16 12:34:22.727  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2020-08-16 12:34:22.731  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-08-16 12:34:22.747  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
2020-08-16 12:34:22.754  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2020-08-16 12:34:22.779  INFO 1 --- [           main] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-08-16 12:34:22.788 ERROR 1 --- [           main] o.s.boot.SpringApplication               : Application run failed
org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:185) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:895) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at com.sivalabs.todolist.TodoListApplication.main(TodoListApplication.java:19) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[workspace/:na]
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:109) ~[workspace/:na]
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[workspace/:na]
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[workspace/:na]
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:229) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:43) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    ... 22 common frames omitted
Caused by: java.lang.IllegalArgumentException: standardService.connector.startFailed
    at org.apache.catalina.core.StandardService.addConnector(StandardService.java:231) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.addPreviouslyRemovedConnectors(TomcatWebServer.java:282) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:213) ~[spring-boot-2.3.3.RELEASE.jar:2.3.3.RELEASE]
    ... 24 common frames omitted
Caused by: org.apache.catalina.LifecycleException: Protocol handler start failed
    at org.apache.catalina.connector.Connector.startInternal(Connector.java:1067) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.StandardService.addConnector(StandardService.java:227) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    ... 26 common frames omitted
Caused by: java.net.SocketException: Permission denied
    at java.base/sun.nio.ch.Net.bind0(Native Method) ~[na:na]
    at java.base/sun.nio.ch.Net.bind(Unknown Source) ~[na:na]
    at java.base/sun.nio.ch.Net.bind(Unknown Source) ~[na:na]
    at java.base/sun.nio.ch.ServerSocketChannelImpl.bind(Unknown Source) ~[na:na]
    at java.base/sun.nio.ch.ServerSocketAdaptor.bind(Unknown Source) ~[na:na]
    at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:228) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:211) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1141) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1227) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:592) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.connector.Connector.startInternal(Connector.java:1064) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    ... 28 common frames omitted

我能够使用 docker build -t sivaprasadreddy/spring-boot-aws-cdk-demo . 构建 docker 映像,并且我可以使用 docker run -e SERVER_PORT=80 -p 90:80 sivaprasadreddy/spring-boot-aws-cdk-demo 成功运行容器

Dockerfile:

FROM openjdk:11-jdk-slim
VOLUME /tmp
ADD build/libs/*.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8787"
ENV SPRING_PROFILES_ACTIVE "default"
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -jar /app.jar" ]

PS: 问题显然是使用端口 是否有可能自定义 SpringBoot Gradle 插件以生成允许使用端口

【问题讨论】:

在端口 80 上启动进程需要 root 权限 AFAIK 【参考方案1】:

它只是“访问”问题,因为您以非 root 身份运行端口 80,这需要它。它属于特权端口:

参考:https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html

来自日志:

Caused by: java.net.SocketException: Permission denied
    at java.base/sun.nio.ch.Net.bind0(Native Method) ~[na:na]

以 sudo 用户身份运行或按照此处的步骤操作: https://serverfault.com/questions/112795/how-to-run-a-server-on-port-80-as-a-normal-user-on-linux

或者使用像 nginx 这样的代理来重新路由。

【讨论】:

【参考方案2】:

我认为,docker-image 是无根的。这意味着 1024 以下的所有端口都不可用(它们需要 root 权限)。

但是为什么需要更改端口?使用 docker,您可以映射端口。像这样:

docker run -p 80:8080 sivaprasadreddy/spring-boot-aws-cdk-demo

【讨论】:

从安全的角度来看,让它无根肯定更好。l。如果我在我的 docker 设置中有 Root 权限,那么我可能能够对其他容器映像进行操作。【参考方案3】:

如果您发布 dockerfile 会很方便,但我猜您正在尝试以非 root 身份运行容器。默认情况下非root用户无权访问1024以下的端口号。

为了实现这一点,您需要在 dockerfile 中添加以下行

RUN groupadd --gid 5000 docker && useradd --home-dir /home/default --create-home --uid 5000 --gid 5000 --shell /bin/sh --skel /dev/null default

【讨论】:

以上是关于使用 gradle bootBuildImage 构建的 SpringBoot Docker 映像无法在 <1024 的任何端口上启动的主要内容,如果未能解决你的问题,请参考以下文章

用于执行 gradle bootBuildImage 命令的 Docker 映像

Gradle bootBuildImage 使用 docker:dind 服务在 GitLab CI/CD 中失败并显示“未找到摘要”

使用 gradle bootBuildImage 构建的 SpringBoot Docker 映像无法在 <1024 的任何端口上启动

Gradle的使用——快速找到自己想要在gradle中使用的jar包

Android 组件化使用 Gradle 实现组件化 ( Gradle 变量定义与使用 )

Android studio使用之[gradle的使用]