簡體   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