无需Stack:如何为Haskell项目生成Dockerfile构建镜像?
Question
I have a Haskell project that I can build into a Docker image on macOS using the
stack image buildcommand, with the following configuration in mystack.yml:resolver: lts-11.1 packages: - . docker: enable: true image: container: base: "gcr.io/myapp/myapp-base" name: "gcr.io/myapp/myapp-api"However, our CI server doesn't have Stack installed — it only has Docker and docker-compose. Is there a way to generate a Dockerfile using Stack so I can build the image on the CI server without needing Stack?
Answer
Absolutely! You can generate a standalone Dockerfile using your local Stack environment (on your Mac), then use that file in your CI pipeline to build the image without needing Stack installed there at all. Here's how to do it step by step:
Step 1: Generate the Dockerfile locally with Stack
From your project root directory (where your stack.yml lives), run this command on your Mac:
stack dockerfile
This command parses your stack.yml configuration — including your base image, resolver version, and project packages — and outputs a fully functional Dockerfile directly in your project folder. The generated file replicates all the build logic that stack image build uses under the hood.
Step 2: Review and customize the Dockerfile (optional)
Take a quick look at the generated Dockerfile to make sure it aligns with your needs. By default, it will:
- Start from your specified base image (
gcr.io/myapp/myapp-base) - Copy your project files into the container
- Use the lts-11.1 resolver to build your Haskell project
- Set up a minimal runtime image (most likely using a multi-stage build to keep the final image size small)
If you need to add customizations — like extra system dependencies, environment variables, or post-build commands — feel free to edit the Dockerfile directly before committing it to your version control system.
Step 3: Build the image in CI using Docker/docker-compose
Commit the generated Dockerfile to your repo, then in your CI pipeline, use standard Docker commands to build the image:
docker build -t gcr.io/myapp/myapp-api .
If you prefer using docker-compose, add a service definition pointing to this Dockerfile in your docker-compose.yml:
services: myapp-api: build: . image: gcr.io/myapp/myapp-api
Then run the build command in CI:
docker-compose build myapp-api
Key Notes
- Ensure your CI server can pull the base image (
gcr.io/myapp/myapp-base). If it's a private Google Container Registry image, you'll need to authenticate Docker in the CI environment first usinggcloud auth configure-dockeror similar. - The generated Dockerfile produces an identical image to what
stack image buildcreates locally, so you won't have consistency issues between your local builds and CI builds.
内容的提问来源于stack exchange,提问作者Leo Zhang

