使用 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包