Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ulidtko/haskell-stack-builder
Unprivileged/rootless Docker Image for building Haskell projects with Stack without Nix
https://github.com/ulidtko/haskell-stack-builder
Last synced: 24 days ago
JSON representation
Unprivileged/rootless Docker Image for building Haskell projects with Stack without Nix
- Host: GitHub
- URL: https://github.com/ulidtko/haskell-stack-builder
- Owner: ulidtko
- Created: 2021-03-22T11:54:40.000Z (over 3 years ago)
- Default Branch: opensource
- Last Pushed: 2024-02-06T15:26:15.000Z (9 months ago)
- Last Synced: 2024-02-06T16:37:28.058Z (9 months ago)
- Language: Dockerfile
- Size: 45.9 KB
- Stars: 3
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
[![CI](https://github.com/ulidtko/haskell-stack-builder/actions/workflows/docker-image-ci.yaml/badge.svg)](https://github.com/ulidtko/haskell-stack-builder/actions?query=workflow:docker-image-ci)
# `haskell-stack-builder` #
This is an unprivileged (rootless) Docker Image for building Haskell using Stack.
Default build config:
* GHC version: 8.10.7
* Cabal version: 3.2.1.0
* Stack version: 2.7.5
* Stackage snapshot: LTS-18.28Versions are customizable via `--build-arg`'s, see below.
## Basic usage, volumes ##
First build the image (or [pull from GHCR](#built-images-on-ghcr)):
docker build -t haskell-stack-builder:lts-18.28 .
Then supposing you have a Stack project under `foobar_project` and `binary_outputs` directory:
docker run --rm -t \
-v $PWD/foobar_project:/home/builder/src \
-v $PWD/binary_outputs:/home/builder/bin \
haskell-stack-builder:lts-18.28 \
stack build --copy-binsThat's it. On build success, find the executables under `binary_outputs/`.
## Size ##
In LTS-14.27 build config & `FROM debian:buster-slim`:
**3.05 GiB** (3.28 GB):
* 1.35 GiB for GHC,
* 1.35 GiB for Stack package index,
* 229 MiB for a few basic Debian packages,
* 60 MiB for Stack static binary.Extra effort has been applied to prune unnecessary stuff; see [Dockerfile](./Dockerfile).
## Build config options ##
With the primary purpose to minimize Dockerfile branching, these are accepted:
`--build-arg` key | Example values | Default value | Explanation
------------------|----------------|---------------|---------------------------
`GHC_VERSION` | 8.8.2, 8.8.4 | 8.6.5 | Used in `stack setup --install-ghc`
`STACK_RESOLVER` | lts-16.31 | lts-14.27 | Stackage snapshot tag
`UID` | 1001, 65534 | 1000 | POSIX UID of `builder` userComplete `docker build` commandline specifying all the options (example):
docker build \
--build-arg UID=$(id -u) \
--build-arg GHC_VERSION=8.8.4 \
--build-arg STACK_RESOLVER=lts-16.31 \
-t haskell-stack-builder:lts-16.31 \
.## Dependency caching on CI ##
Unlike some [other builders][YARN_CACHE_FOLDER], Stack does not provide a clear-cut option to preserve compiled dependencies externally. This often leads to ridiculously long CI builds, as those hundreds of dependency packages get recompiled from scratch in every pipeline run.
A way around this is to pick apart the `~/.stack` directory, and bind-mount the relevant parts:
docker run --rm -t \
-v HOST_HASKELL_CACHE_DIR/stack.sqlite3:/home/builder/.stack/stack.sqlite3 \
-v HOST_HASKELL_CACHE_DIR/snapshots:/home/builder/.stack/snapshots \
\
-v $PWD/foobar_project:/home/builder/src \
-v $PWD/binary_outputs:/home/builder/bin \
haskell-stack-builder:latest \
stack build --copy-bins`stack.sqlite3` is the package DB of Stack, there it remembers installed package metadata. `snapshots` is where build products go¹. **No need to cache anything else** under `~/.stack`: doing so can spawn weird issues (via stale `config.yaml`), or bloat your cache by several gigs unnecessarily (via accidentally caching a GHC under `programs`). The `pantry` subdir is important, somewhat heavy too, *should not* be cached — it contains effectively immutable index of available packages and is already included in the docker image. Per Stack's immutable snapshots architecture, refreshing pantry involves updating the `lts-14.27` tag, and thus rebuilding this image.
Look into the [lockfile][stack.yaml.lock] if you want to know the best **invalidation strategy** for such a cache. The lockfile varies across projects, but within one there's a nice property: `stack.yaml.lock` contents will change exactly on changes in the project's dependency forest, and will stay the same otherwise. Thus a hashsum of it makes a good caching key.
[YARN_CACHE_FOLDER]: https://classic.yarnpkg.com/en/docs/cli/cache/
[stack.yaml.lock]: https://docs.haskellstack.org/en/stable/lock_files/\[¹\]: roughly speaking; there's also the `my_project/.stack-work` serving a similar purpose. The difference is of a local/global kind; once compiled, `my_project` modules (`Config.hs`, `Utils.hs`, what have you) will go under the project-local `.stack-work`; but dependency *packages* (e.g. `text`, `lens`, `aeson`) will go under the user-global `~/.stack/snapshots`. Doing so enjoys deterministic-build properties of packages in Stack, and facilitates built deps reuse across projects (so there won't appear gazillion builds of `text-1.2.3.1`, just a single one per `(cpu_architecture, compile_flag_set)` will exist).
## Built images on GHCR ##
Rebuilt and tested automatically by CI pipeline, and published to GHCR.io.
See https://github.com/ulidtko/haskell-stack-builder/pkgs/container/haskell-stack-builder
```
docker pull ghcr.io/ulidtko/haskell-stack-builder:lts-17.15
docker pull ghcr.io/ulidtko/haskell-stack-builder:lts-18.18
docker pull ghcr.io/ulidtko/haskell-stack-builder:lts-19.2
```