Skip to content

Commit

Permalink
ci: improve dockerfile for static build
Browse files Browse the repository at this point in the history
  • Loading branch information
stevana committed Oct 21, 2024
1 parent 9c3c315 commit 513e365
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 49 deletions.
114 changes: 78 additions & 36 deletions release/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,43 +1,85 @@
# Inspired by https://entropicthoughts.com/deploying-single-binary-haskell-web-app
ARG GHC_VERSION=9.6.6
ARG CABAL_VERSION=3.12.1.0

FROM docker.io/library/alpine:3.20.3
FROM docker.io/library/alpine:3.20.3 AS build

RUN apk update \
&& apk add --no-cache \
autoconf automake bash binutils-gold curl dpkg fakeroot file \
findutils g++ gcc git make perl shadow tar xz \
ARG GHC_VERSION
ARG CABAL_VERSION

LABEL org.opencontainers.image.source=https://github.com/spex-lang/spex
LABEL org.opencontainers.image.description="GHC musl"
LABEL org.opencontainers.image.licenses=BSD-2-Clause

# Install system dependencies needed for ghcup.
# https://www.haskell.org/ghcup/install/#system-requirements
RUN apk upgrade --no-cache \
&& apk add --no-cache \
brotli brotli-static \
bzip2 bzip2-dev bzip2-static \
curl libcurl curl-static \
freetype freetype-dev freetype-static \
gmp-dev \
libffi libffi-dev \
libpng libpng-static \
ncurses-dev ncurses-static \
openssl-dev openssl-libs-static \
pcre pcre-dev \
pcre2 pcre2-dev \
sdl2 sdl2-dev \
sdl2_image sdl2_image-dev \
sdl2_mixer sdl2_mixer-dev \
sdl2_ttf sdl2_ttf-dev \
xz xz-dev \
zlib zlib-dev zlib-static \
&& ln -s /usr/lib/libncursesw.so.6 /usr/lib/libtinfo.so.6

ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local

RUN curl --fail --output /bin/ghcup \
'https://downloads.haskell.org/ghcup/x86_64-linux-ghcup' \
binutils-gold \
curl \
gcc \
g++ \
gmp-dev \
gpg \
gpg-agent \
libc-dev \
libffi-dev \
make \
musl-dev \
ncurses-dev \
perl \
tar \
xz

# Install ghcup as per:
# https://www.haskell.org/ghcup/install/#manual-installation
RUN curl --proto '=https' --tlsv1.2 --silent --show-error --fail \
--output /bin/ghcup \
'https://downloads.haskell.org/ghcup/x86_64-linux-ghcup' \
&& chmod 0755 /bin/ghcup \
&& ghcup upgrade --target /bin/ghcup \
&& ghcup install cabal --set \
&& /usr/local/.ghcup/bin/cabal update
&& gpg --batch --keyserver keyserver.ubuntu.com \
--recv-keys 7D1E8AFD1D4A16D71FADA2F2CCC85C0E40C06A8C \
&& gpg --batch --keyserver keyserver.ubuntu.com \
--recv-keys FE5AB6C91FEA597C3B31180B73EDE9E8CFBAEF01 \
&& gpg --batch --keyserver keyserver.ubuntu.com \
--recv-keys 88B57FCF7DB53B4DB3BFA4B1588764FBE22D19C4 \
&& gpg --batch --keyserver keyserver.ubuntu.com \
--recv-keys EAF2A9A722C0C96F2B431CA511AAD8CEDEE0CAEF \
&& ghcup install cabal $CABAL_VERSION --set \
&& ghcup install ghc $GHC_VERSION --set

FROM docker.io/library/alpine:3.20.3

ARG GHC_VERSION
ARG CABAL_VERSION

# Copy in the bare minimum possible (I think) from .ghcup (which is massive).
COPY --from=build \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/lib/x86_64-linux-ghc-$GHC_VERSION/*.so \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/lib/x86_64-linux-ghc-$GHC_VERSION/
COPY --from=build \
/root/.ghcup/bin/cabal /root/.ghcup/bin/cabal
COPY --from=build \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/bin/ \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/bin/
COPY --from=build \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/lib/settings \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/lib/settings
COPY --from=build \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/lib/package.conf.d \
/root/.ghcup/ghc/$GHC_VERSION/lib/ghc-$GHC_VERSION/lib/package.conf.d

# Install system dependencies for cabal (curl), ghc (gmp and ncurses) and spex
# (zlib).
RUN apk upgrade --no-cache \
&& apk add --no-cache \
curl \
gmp-dev \
libffi-dev \
ncurses-dev \
zlib-dev

ENV PATH="/usr/local/.ghcup/bin:$PATH"
ENV PATH="/root/.ghcup/bin:$PATH"

RUN ghcup install cabal 3.12.1.0 --set
RUN ghcup install ghc 9.6.6 --set
COPY --chmod=0755 entrypoint.sh /entrypoint.sh

ENTRYPOINT [ "/mnt/release/entrypoint.sh" ]
ENTRYPOINT [ "/entrypoint.sh" ]
39 changes: 28 additions & 11 deletions release/Makefile
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
all: bin/spex
all: bin/spex bin/spex-demo-petstore

bin/spex bin/spex-demo-petstore: build-image
mkdir -p "cache/cabal-cache-musl" \
"cache/cabal-store-musl" \
"cache/dist-newstyle-musl"
# We can't use cabal list-bin here, because it thinks the binary is in
# ../dist-newstyle rather than cache/dist-newstyle-musl.
bin/spex: static-build
@mkdir -p bin
cp "$(shell find cache/dist-newstyle-musl \
-name spex -type f -executable)" bin

bin/spex-demo-petstore: static-build
@mkdir -p bin
cp "$(shell find cache/dist-newstyle-musl \
-name spex-demo-petstore -type f -executable)" bin

static-build: build-image
mkdir -p cache/cabal-cache-musl \
cache/cabal-store-musl \
cache/dist-newstyle-musl
docker run \
-v "${PWD}/..":/mnt/:ro \
-v "${PWD}/cache/cabal-cache-musl":/root/.cache/cabal \
-v "${PWD}/cache/cabal-store-musl":/root/.local/state/cabal/store \
-v "${PWD}/cache/dist-newstyle-musl":/mnt/dist-newstyle \
muslghc
mkdir -p bin
cp "$(shell cabal list-bin spex)" bin
cp "$(shell cabal list-bin petstore)" bin
ghcr.io/spex-lang/static-build:latest

build-image: Dockerfile
docker build --tag muslghc .
docker build --tag ghcr.io/spex-lang/static-build .

push-image: build-image
@echo ${GITHUB_TOKEN} | \
docker login ghrc.io --username spex-lang --password-stdin
docker push ghcr.io/spex-lang/static-build:latest

bin/spex.upx: bin/spex
upx --best -q bin/spex -o bin/spex.upx
Expand All @@ -25,4 +39,7 @@ clean:
rm -f bin/spex.upx
rm -f bin/spex-demo-petstore

.PHONY: all build-image clean
distclean: clean
rm -rf cache

.PHONY: all static-build build-image push-image clean distclean
17 changes: 15 additions & 2 deletions release/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
#!/bin/sh

# To avoid cabal update always refetching the latest packages, we pin it to a
# specific date. This can be removed once the following bug is fixed:
# https://github.com/haskell/cabal/issues/8572

cd /mnt \
&& cabal update \
&& cabal build exe:spex exe:spex-demo-petstore --enable-executable-static
&& cabal update hackage.haskell.org,2024-10-17T07:25:36Z \
&& cabal build exe:spex exe:spex-demo-petstore --enable-executable-static

# We can't use cabal install here, because that causes --version to break
# due to the following bug: https://github.com/acfoltzer/gitrev/issues/23
#
# && cabal install exe:spex exe:spex-demo-petstore \
# --enable-executable-static \
# --install-method=copy \
# --overwrite-policy=always \
# --installdir=/mnt/bin

0 comments on commit 513e365

Please sign in to comment.