Google Cloud Run部署Scala3+Akka服务启动后异常终止求助
问题根源与解决方案
核心问题分析
sbt run启动方式的缺陷:直接用sbt run作为Docker启动命令时,sbt在完成编译启动流程后会主动退出进程,导致容器随之关闭——即便Akka HTTP服务已经成功启动并监听端口。- sbt-native-packager配置不完整:之前的配置未正确关联主类、传递端口参数,导致容器无法正常监听Cloud Run指定的端口。
方案一:优化Dockerfile,打包可执行JAR运行
1. 修改Dockerfile(分层构建减少镜像体积)
# 构建阶段:使用预配置的Scala+sbt镜像完成编译打包 FROM hseeberger/scala-sbt:11.0.16_1.9.8_3.3.1 AS builder WORKDIR /app COPY . . # 打包包含所有依赖的可执行JAR RUN sbt assembly # 运行阶段:使用轻量JRE镜像 FROM openjdk:11-jre-slim WORKDIR /app # 从构建阶段复制打包好的JAR COPY --from=builder /app/target/scala-3.3.1/Test-assembly-*.jar app.jar EXPOSE 8080 ENV PORT 8080 # 直接运行JAR,避免sbt进程退出问题 CMD ["java", "-jar", "app.jar"]
2. 完善build.sbt与插件配置
在project/plugins.sbt中添加sbt-assembly插件:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
修改build.sbt,配置assembly打包规则:
import sbt.Keys.libraryDependencies ThisBuild / version := "scala-http" ThisBuild / scalaVersion := "3.3.1" lazy val root = (project in file(".")) .settings( name := "Test", libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-http" % "10.5.0", "com.typesafe.akka" %% "akka-actor-typed" % "2.8.5", "com.typesafe.akka" %% "akka-stream" % "2.8.5", "ch.qos.logback" % "logback-classic" % "1.4.14" ), // 指定主类 assembly / mainClass := Some("Main"), // 处理依赖冲突 assemblyMergeStrategy in assembly := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first } )
方案二:正确配置sbt-native-packager构建Docker镜像
1. 完善插件与build.sbt配置
在project/plugins.sbt中添加插件:
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.8")
修改build.sbt,启用Docker打包插件并配置参数:
import sbt.Keys.libraryDependencies import com.typesafe.sbt.packager.docker.DockerPlugin.autoImport._ ThisBuild / version := "scala-http" ThisBuild / scalaVersion := "3.3.1" // 全局指定主类,避免未使用警告 Global / mainClass := Some("Main") lazy val root = (project in file(".")) .enablePlugins(JavaAppPackaging, DockerPlugin) .settings( name := "Test", libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-http" % "10.5.0", "com.typesafe.akka" %% "akka-actor-typed" % "2.8.5", "com.typesafe.akka" %% "akka-stream" % "2.8.5", "ch.qos.logback" % "logback-classic" % "1.4.14" ), // Docker基础镜像选择轻量JRE dockerBaseImage := "openjdk:11-jre-slim", // 暴露端口 dockerExposedPorts := Seq(8080), // 设置环境变量传递端口 dockerEnvVars := Map("PORT" -> "8080"), // 自定义启动命令 dockerEntrypoint := Seq("java", "-jar", s"${name.value}-${version.value}.jar") )
2. 构建与部署
执行命令构建镜像:
sbt docker:publishLocal
将构建好的镜像推送到GCP Artifact Registry,再部署至Cloud Run即可。
代码层面优化(可选)
为确保ActorSystem持续运行,避免意外退出,可在Main对象末尾添加等待逻辑:
// 监听ActorSystem终止事件,保持进程活跃 system.whenTerminated.onComplete { _ => logger.info("ActorSystem terminated") }
Cloud Run部署注意事项
- 确保Cloud Run服务的端口设置与容器内
PORT环境变量一致(默认8080)。 - 部署镜像需存储在GCP Artifact Registry或可公开访问的镜像仓库中。
- 部署后查看Cloud Run日志,确认无端口监听失败类错误。
内容的提问来源于stack exchange,提问作者Alexandre Leal
相关产品推荐
相关产品推荐

