Skip to content

Improve docker image building support #3381

Open
@arianvp

Description

@arianvp

I'm planning to improve the docker image support for Stack.

Currently, stack supports some features for building slim containers containing the executables with the stack image container

  1. generate a base docker image of your (umbrella) project.
    This means, multiple targets (cabal files) are built and put in the same image.
    With the executables option you can target which executables end up in the image. So
    if you have a stack project like:

    ❯ tree
    umbrella
    ├── bar
    │   ├── A.hs 
    │   ├── bar.cabal
    │   ├── B.hs
    │   └── package.yaml
    ├── baz
    │   ├── A.hs
    │   ├── baz.cabal
    │   ├── B.hs
    │   └── package.yaml
    ├── foo
    │   ├── A.hs
    │   ├── B.hs
    │   ├── foo.cabal
    │   └── package.yaml
    └── stack.yaml
    

    One docker image named umbrella:latest will be generated.

  2. Create derivate images with ENTRYPOINT set to the executables that there is a docker image
    for each executable. So for the above example we could generate the following docker images:

    umbrella-foo-a:latest
    umbrella-foo-b:latest
    umbrella-bar-a:latest
    umbrella-bar-b:latest
    umbrella-baz-a:latest
    umbrella-baz-b:latest
    
  3. All images are always tagged with the latest tag, instead of the library versions. This is understandable,
    because an umbrella project consists of multiple libraries, and then the question is, which version to use to tag the docker image?

However, these features are a little bit fragile. For exampe, the entrypoints option does not check if the executable actually exists.

I would like to improve the image building support a bit, by making it a bit more stack aware. Currently, the approach is totally file based, and doesn't know about what targets there are, and what executables exist.

Features I want to implement:

  1. Have a base image per build target instead of one base image for the entire stack project
    So if you have an umbrella project with multiple cabal projects there will be a base image for each cabal project created. Because we now have a base image per target. We can tag the base image with the target package version. this is nice because now you can keep track of what version of images you are running in production

    So for the above mentioned umbrella project, the following base images will be generated:

    foo:0.1.0
    bar:0.2.0
    baz:0.1.1
    
  2. To get the entrypoint images, instead of iterating over the entrypoints field in stack.yaml, we could
    now just look at the target metadata in stack and generate a docker image with the correct ENTRYPOINT for each executable section in the cabal file, along with the correct version tag

    foo-foo-a:0.1.0
    foo-foo-b:0.1.0
    bar-bar-a:0.2.0
    bar-bar-b:0.2.0
    baz-baz-a:0.1.1
    baz-baz-b:0.1.1
    

Now the questions to you:

  1. Do you agree with this design and would like to have this added? I think it will make
    deploying haskell in kubernetes etc even easier. Please leave any feedback in the comments. Perhaps
    we should discuss this a bit before I start implementing new features.

  2. I'm not familiar with the code base too much, so can I ask questions for pointers where to get certain information that I need to get this done?

  3. What about backwards compatibility? I have not really thought of it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions