Почему моя Haskell программа не работает в Docker с Alpine или Scratch? - PullRequest
1 голос
/ 19 марта 2020

У меня есть несколько проблем, попробуйте создать контейнер Docker, который будет бесконечно запускать одно приложение Haskell. Для начала я хотел бы использовать базовое изображение, которое предоставляет программу, которую мне нужно использовать из моего кода. Он основан на царапине linux. Однако, когда я собираю свою Haskell программу и копирую ее в этот контейнер, я получаю ошибку:

standard_init_ linux. go: 211: exe c вызван пользовательский процесс " нет такого файла или каталога "

Далее, я хотел бы сохранить процесс сборки и структуру файла очень простой, если это возможно. У меня есть только один скрипт в Haskell в Main.hs, и он имеет одну зависимость от процесса. Если возможно и разумно избежать использования как стека, так и файла cabal, а также подкаталогов и всего такого, было бы неплохо, если бы директива build находилась где-то в Docker или в Haskell файле.

Однако у меня есть проблема со сборкой, потому что строка gh c стека занимает несколько минут, чтобы загрузить gh c, обработать и собрать все, и эта строка перезапускается всякий раз, когда я делаю небольшое изменение кода. Это очень усложняет разработку.

Какой способ запуска простого сценария Haskell в изображении Docker лучше?

Вот мое упрощенное 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

1 Ответ

3 голосов
/ 19 марта 2020

Это изображение предназначено для использования с Haskell Интеграция стека 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)

Это также не начнется с musl lib c, который упакован в образ Alpine (непонятно почему), поэтому вам нужно установить пакет совместимости GNU lib c, а также пакет libgmp.

(Поскольку это двоичный файл с динамической связью, вы также не можете запустить в образе FROM scratch, если вы не хотите вручную установить GNU lib c и другие необходимые вам вспомогательные библиотеки.

Для этапа сборки, как следует из названия, он включает полная копия LTS Haskell 15.4 , но для того, чтобы найти его, нужно немного покопаться в изображении.

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

В этой оболочке вы можете найти установку Stack в /home/stackage/.stack; указание переменной окружения STACK_ROOT на этот каталог заставит команду stack найти ее. Это избавит от необходимости загружать gh c и остальную часть среды LTS Haskell при повторной сборке. сделал это, остальные ваши ckerfile работает почти так же, как вы показали.

Это оставляет нам окончательный 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"]
...