基于Clojure的Docker容器PostgreSQL库加载失败问题求助
问题背景
我有一个访问本地数据库的Clojure应用,使用JDBC,依赖配置如下:
:dependencies [[org.clojure/clojure "1.10.0"] ... [org.clojure/java.jdbc "0.7.12"] [org.postgresql/postgresql "42.3.3"]]
在安装了PostgreSQL的主机上直接运行时,哪怕连接远程数据库都能正常工作,但用clojure镜像构建Docker容器运行时却连接失败。
使用的Dockerfile:
# syntax=docker/dockerfile:1 FROM clojure WORKDIR /ui-service COPY . . CMD ["lein", "ring", "server-headless", "3000"] EXPOSE 3000
报错核心信息:
lan-activity-ui-service-1 | org.postgresql.util.PSQLException: ERROR: could not load library "/usr/lib/postgresql/13/lib/llvmjit.so": /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /lib/x86_64-linux-gnu/libz3.so.4) ...(后续栈追踪省略)
我尝试过用多阶段构建从postgres镜像复制/usr/lib/postgresql/13/目录到clojure镜像,Dockerfile如下,但仍报错ERROR: could not load library "/usr/lib/postgresql/13/lib/llvmjit.so":
# syntax=docker/dockerfile:1 FROM postgres:13 as postgres FROM clojure WORKDIR /ui-service COPY . . COPY --from=postgres /usr/lib/postgresql/ /usr/lib/postgresql/ RUN ls -l /usr/lib/postgresql/13/lib/llvmjit.so CMD ["lein", "ring", "server-headless", "3000"] EXPOSE 3000
我的疑问:
- 怎么确保Docker容器内具备所需依赖?
- 是否需要用多阶段构建引入PostgreSQL镜像?
- 能不能仅通过Java/Clojure添加所需依赖?
问题分析
报错的本质是:clojure镜像的基础系统(通常是Debian旧版本)自带的libstdc++.so.6版本过低,缺少GLIBCXX_3.4.30;而你复制的llvmjit.so依赖的libz3.so.4刚好需要这个高版本的系统库。单独复制PostgreSQL的库解决不了底层系统库的版本问题。
解决方案
方案1:升级容器内的libstdc++库
直接在clojure镜像中安装更新版本的libstdc++:
# syntax=docker/dockerfile:1 FROM clojure WORKDIR /ui-service # 安装更新的libstdc++6 RUN apt-get update && apt-get install -y --no-install-recommends libstdc++6 COPY . . CMD ["lein", "ring", "server-headless", "3000"] EXPOSE 3000
如果Debian默认源的版本还是不够,可以添加backports源(针对旧版Debian):
FROM clojure WORKDIR /ui-service # 添加backports源并安装更新的libstdc++6 RUN echo "deb http://deb.debian.org/debian bullseye-backports main" >> /etc/apt/sources.list && \ apt-get update && \ apt-get install -y --no-install-recommends -t bullseye-backports libstdc++6 COPY . . CMD ["lein", "ring", "server-headless", "3000"] EXPOSE 3000
方案2:使用基于更新系统的Clojure镜像
换用基于Debian Bookworm或Ubuntu 22.04的Clojure镜像,这些系统自带的libstdc++版本更高:
# syntax=docker/dockerfile:1 FROM clojure:bookworm WORKDIR /ui-service COPY . . CMD ["lein", "ring", "server-headless", "3000"] EXPOSE 3000
方案3:关闭PostgreSQL的LLVM JIT功能
如果不需要LLVM JIT的性能优化,可以直接在JDBC连接参数中关闭它,这样就不会加载llvmjit.so了:
;; 示例DB配置 (def db-spec {:dbtype "postgresql" :dbname "your-db-name" :user "db-user" :password "db-pass" :host "db-host" :port 5432 :options "-c jit=off"})
或者直接在连接URL中添加参数:jdbc:postgresql://host:5432/your-db?jit=off
方案4:复制完整依赖链(不推荐)
如果一定要保留LLVM JIT,需要用ldd /usr/lib/postgresql/13/lib/llvmjit.so查看所有依赖的系统库,然后从postgres镜像逐一复制到clojure镜像中。这种方法繁琐且容易出问题,不如前几种方案高效。
疑问解答
- 是否需要多阶段构建引入PostgreSQL镜像?:不需要。你的应用只是连接远程数据库,复制PostgreSQL的库解决不了系统级依赖问题,反而徒增复杂度。
- 能否仅通过Java/Clojure添加所需依赖?:不行。
llvmjit.so是系统级动态链接库,不属于Java/Clojure的依赖生态,无法通过Lein或Clojars仓库引入。
内容的提问来源于stack exchange,提问作者ealfonso

