Docker化Scalapy Scala应用时遇‘Unable to load python3’错误求助
问题
我正在Docker化一个用Scalapy运行Python代码的Scala应用,Scala版本2.13.1,sbt版本1.2.8。应用在IntelliJ的sbt-shell中运行正常,但Docker化后启动容器时出现Unable to load python3错误。已确认容器内已安装Python3(路径为/usr/bin/python3),但仍报无法加载libpython3.so的UnsatisfiedLinkError,请求解决该Docker化问题。
Scala主类代码
import me.shadaj.scalapy.interpreter.CPythonInterpreter import me.shadaj.scalapy.py object Main extends App { val pythonCode = """ |import os | |myFile = os.path.join("src", "main", "resources", "myFile.txt") | |with open(myFile, "w") as file: | file.write("Hello World!") |""".stripMargin py.local { CPythonInterpreter.execManyLines(pythonCode) } }
project/plugins.sbt依赖
libraryDependencies += "ai.kien" %% "python-native-libs" % "0.2.2"
build.sbt配置
import com.typesafe.sbt.packager.docker.{DockerChmodType, DockerPermissionStrategy, ExecCmd} import ai.kien.python.Python lazy val root = (project in file(".")) .settings( name := "my-project" ) ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "2.13.1" ThisBuild / scapegoatVersion := "1.4.0" enablePlugins(JavaAppPackaging, DockerPlugin) packageName in Docker:= "my-project" version in Docker:= "0.0.3" dockerExposedPorts:= Seq(8083) dockerChmodType := DockerChmodType.UserGroupWriteExecute dockerPermissionStrategy := DockerPermissionStrategy.CopyChown dockerAdditionalPermissions += (DockerChmodType.UserGroupPlusExecute, "/var/run/") daemonUserUid in Docker := None daemonUser in Docker := "root" dockerCommands ++= Seq( ExecCmd("RUN", "apt-get", "update"), ExecCmd("RUN", "apt-get", "install", "-y", "python3") ) fork:= true lazy val python = Python("/usr/bin/python3") lazy val javaOpts = python.scalapyProperties.get.map { case (k, v) => s"""-D$k=$v""" }.toSeq javaOptions ++= javaOpts libraryDependencies ++= Seq( "me.shadaj" %% "scalapy-core" % "0.5.2" )
自动生成的Dockerfile
FROM openjdk:8 WORKDIR /opt/docker COPY --chown=root:root opt /opt EXPOSE 8083 USER root ENTRYPOINT ["/opt/docker/bin/notary-scraping"] CMD [] RUN ["apt-get", "update"] RUN ["apt-get", "install", "-y", "python3"]
报错信息
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'python3': libpython3.so: cannot open shared object file: No such file or directory libpython3.so: cannot open shared object file: No such file or directory Native library (linux-x86-64/libpython3.so) not found in resource path (...)
解决方法
1. 修复Dockerfile命令顺序问题
自动生成的Dockerfile中,Python安装命令放在了ENTRYPOINT之后,容器启动时Python还未安装。需要调整dockerCommands顺序,让安装操作在COPY之前执行,同时安装包含libpython3.so的python3-dev包:
修改build.sbt中的dockerCommands部分:
dockerCommands := Seq( Cmd("FROM", "openjdk:8"), Cmd("WORKDIR", "/opt/docker"), ExecCmd("RUN", "apt-get", "update"), ExecCmd("RUN", "apt-get", "install", "-y", "python3", "python3-dev"), Cmd("COPY", "--chown=root:root", "opt", "/opt"), Cmd("EXPOSE", "8083"), Cmd("USER", "root"), Cmd("ENTRYPOINT", "/opt/docker/bin/my-project"), // 确保与packageName一致,替换原错误的notary-scraping Cmd("CMD", "[]") )
2. 创建libpython3.so软链接
容器内libpython3.so通常以版本化名称存在(如libpython3.8.so),JVM无法直接识别。添加软链接命令让JNA找到库文件:
在上述dockerCommands中添加一行:
ExecCmd("RUN", "ln", "-s", "/usr/lib/x86_64-linux-gnu/libpython3.8.so", "/usr/lib/libpython3.so")
注:可通过
RUN ls /usr/lib/x86_64-linux-gnu/libpython*.so查看容器内实际的库文件名,替换对应版本号。
3. 显式指定JNA库路径
在build.sbt中添加JNA路径配置,确保JVM能定位到Python库:
javaOptions ++= javaOpts ++ Seq("-Djna.library.path=/usr/lib/x86_64-linux-gnu/")
4. 修正Python代码中的文件路径
原代码中src/main/resources/myFile.txt在Docker容器内不存在,修改为容器工作目录下的路径:
val pythonCode = """ |import os | |myFile = os.path.join(os.getcwd(), "myFile.txt") | |with open(myFile, "w") as file: | file.write("Hello World!") |""".stripMargin
内容的提问来源于stack exchange,提问作者Zaryab Ali

