Skip to content
This repository has been archived by the owner on Jan 16, 2021. It is now read-only.

Switch to Docker multi-stage builds #22

Open
jml opened this issue Sep 2, 2017 · 9 comments
Open

Switch to Docker multi-stage builds #22

jml opened this issue Sep 2, 2017 · 9 comments

Comments

@jml
Copy link
Owner

jml commented Sep 2, 2017

https://docs.docker.com/engine/userguide/eng-image/multistage-build/

@arianvp
Copy link

arianvp commented Sep 2, 2017

Stack also has a multi stage docker builder built in:

stack --docker image container --build

@jml
Copy link
Owner Author

jml commented Sep 2, 2017

Useful, thanks! I didn't see that documented at https://docs.haskellstack.org/en/stable/GUIDE/#docker.

Do you know if it copies over dynamic libraries, etc.?

@jml
Copy link
Owner Author

jml commented Sep 2, 2017

Also, which version of stack?

$ stack --version
Version 1.5.1, Git revision 600c1f01435a10d127938709556c1682ecfd694e (4861 commits) x86_64 hpack-0.17.1
$ stack --docker image container --builder
Invalid option `--builder'

Usage: stack image container [--[no-]build] [--image ARG] [--help]
  Build a Docker image for the project

@arianvp
Copy link

arianvp commented Sep 2, 2017

Sorry, --build

Also, you need to do some config in your stack.yaml such that all the right dynamic libraries are in the base image:

resolver: lts-9.1
image:
  containers:
    - base: "fpco/ubuntu-with-libgmp:14.04"

@jml
Copy link
Owner Author

jml commented Sep 2, 2017

I can see how this would be handy, but it doesn't seem to provide enough control over the built image. e.g. https://github.com/weaveworks-experiments/compare-revisions needs git installed to work, and uses alpine as a base to keep image size down (59M total rather than 89M for ubuntu-with-libgmp).

To make stack --docker image container --build work for me, I'd still need a separate build step in my CI to build the base image. Maybe that's OK? I feel like there's some more composable solution just out of reach.

compare-revisions uses a hideous series of hacks to do both Dockerized builds and build in container, partly because my colleagues don't want to have to install stuff (including stack) before building, and partly because of things like above.

@arianvp
Copy link

arianvp commented Sep 4, 2017

I guess for more complex environments, multi-stage docker is indeed the answer...

Something like this would work (permute until the syntax checks, I'm typing from phone)

FROM fpco/stack-build:lts-9 as build
RUN stack build
RUN cp $(stack path --local-install-root)/bin/my-app  ./bin
FROM alpine:latest  
RUN apk --no-cache add ca-certificates libgmp
WORKDIR /root
COPY --from=build ./bin/my-app .
CMD ["./my-app"]  

@naushadh
Copy link

naushadh commented Mar 4, 2018

@arianvp I tried your snippet above with a simple hello-world app, but I encountered issues:

  • building was ok
$ docker build --tag hello-world-exe:latest .
run ok, exit code 0
  • running not so much
$ docker run hello-world-exe:latest
standard_init_linux.go:195: exec user process caused "no such file or directory"
  • commented out "CMD" from docker file before trying to inspect the binary
$ docker run --security-opt seccomp:unconfined -it hello-world-exe:latest sh
/ # apk add strace
(1/1) Installing strace (4.19-r0)
Executing busybox-1.27.2-r8.trigger
OK: 6 MiB in 14 packages
/ # strace app
execve("/bin/app", ["app"], 0x7ffdfb3a41f0 /* 6 vars */) = -1 ENOENT (No such file or directory)
writev(2, [{iov_base="strace: exec: No such file or di"..., iov_len=39}, {iov_base="\n", iov_len=1}], 2strace: exec:
No such file or directory
) = 40
writev(2, [{iov_base="", iov_len=0}, {iov_base=NULL, iov_len=0}], 2) = 0
getpid()                                = 10
exit_group(1)                           = ?
+++ exited with 1 +++

Here's the sample project with your sample Dockerfile (with some modifications): https://github.com/naushadh/hello-world/blob/e6ed594660b77da315f4e34bbf8d89746981e470/hello-world/Dockerfile

Would appreciate any help you can offer.

Edit: Me thinks the issue has to do with fundamental incompatibility of debian+glibc and alpine+musl.
Edit 2: the base image frolvlad/alpine-glibc:latest works for pure Haskell apps. would still run into linking issues trying to depend on c libs from APK as they'd be built with musl.

@arianvp
Copy link

arianvp commented Mar 4, 2018

Yeh this is probably an issue with dynamic linking... Alpine is probably not the best base image for this.. Haskell apps depend on : libc, libgmp, and libz. Changing the base image to Debian should probably work (but of course increase the build size)

I do remember there is a stack-build image that is alpine-based floating around . This would allow you to build your Haskell apps against musl and statically linked libgmp. I'll look in my bookmarks.

@arianvp
Copy link

arianvp commented Mar 4, 2018

fpco/ubuntu-with-libgmp:14.04 should work as base image for sure

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants