繁体   English   中英

为什么我的 Haskell 程序不能在带有 Alpine 或 Scratch 的 Docker 中运行?

[英]Why doesn't my Haskell program run in Docker with Alpine or Scratch?

我在尝试构建一个无限期运行一个 Haskell 应用程序的 Docker 容器时遇到了一些问题。 首先,我想使用一个基本图像,它提供了一个我需要从我的代码中使用的程序。 它基于scratch linux。 但是,当我构建 Haskell 程序并将其复制到该容器时,出现错误:

standard_init_linux.go:211: exec 用户进程导致“没有这样的文件或目录”

接下来,如果可能的话,我想保持我的构建过程和文件结构非常简单。 我在 Main.hs 中的 Haskell 中只有一个脚本,并且它依赖于进程。 如果避免堆栈和 cabal 文件以及子目录和所有这些是可能且合理的,那么如果构建指令仅在 Docker 或 Haskell 文件中,那就太好了。

但是,我在构建时遇到了一个问题,即堆栈 ghc 行需要几分钟才能下载 ghc 并处理和构建所有内容,每当我对代码进行小的更改时,该行都会重新执行。 这使得开发非常困难。

在 Docker 镜像中运行一个简单的 Haskell 脚本的更好的过程是什么?

这是我的简化 Docker 镜像:

# Pretty standard just using the latest stack-build
FROM fpco/stack-build:lts-15.4 as haskell
# Setup a build dir and copy code to it
WORKDIR /opt/build
COPY Main.hs /opt/build
# This step takes forever and reruns every time I make a code change.
RUN stack ghc --package process -- Main.hs

# Alpine failed here for file not found.
FROM ubuntu:latest
COPY --from=haskell /opt/build/Main /Main
ENTRYPOINT ["/Main"]

Haskell 程序的简化版本。

import System.Process (readProcess)
import Control.Monad (forever)
main = forever $ do
    output <- readProcess "/bin/ls" [] ""
    print output

该映像旨在与Haskell Stack 的 Docker 集成一起使用 一种非常合理的路径是使用该路径在主机系统目录中构建二进制文件,然后使用该 Dockerfile 的后半部分将二进制文件打包成 Docker 映像。

如果您查看构建的内容,它是一个动态链接的二进制文件,具有非默认依赖项。 如果我将ubuntu更改为alpine (临时)并将ENTRYPOINT更改为CMD那么我可以运行

$ docker run --rm 101681db8d96 ldd /Main
Error loading shared library libgmp.so.10: No such file or directory (needed by /Main)

这也不会从打包在 Alpine 映像中的 musl libc 开始(原因并不明显),因此您需要安装 GNU libc 兼容包以及 libgmp 包。

(因为它是一个动态链接的二进制文件,所以您也不能在FROM scratch映像中运行它,除非您愿意手动安装 GNU libc 和您需要的其他支持库。

对于构建阶段,顾名思义,它包含LTS Haskell 15.4的完整副本,但需要在图像中四处寻找才能找到它。

$ docker run --rm -it fpco/stack-build:lts-15.4 sh

在这个 shell 中,您可以在/home/stackage/.stack找到 Stack 安装; STACK_ROOT环境变量指向该目录将使stack命令找到它。 这避免了在重建时再次下载 ghc 和 LTS Haskell 环境的其余部分的需要。 完成此操作后,Dockerfile 的其余部分就如您所展示的那样工作。

这给我们留下了最终的 Dockerfile:

FROM fpco/stack-build:lts-15.4 as haskell

# Tell `stack` where to find its content (not in $HOME)
ENV STACK_ROOT /home/stackage/.stack

WORKDIR /opt/build
COPY Main.hs .
RUN stack ghc --package process -- Main.hs

# Switch Ubuntu back to Alpine
FROM alpine:latest

# Add the libraries we need to run the application
RUN apk add libc6-compat gmp

COPY --from=haskell /opt/build/Main /Main
CMD ["/Main"]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM