Skip to content

Commit

Permalink
build!: progress towards static musl builds
Browse files Browse the repository at this point in the history
  • Loading branch information
caspiano committed Jun 2, 2021
1 parent bad54bf commit 1851ab6
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 77 deletions.
132 changes: 86 additions & 46 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,82 +1,122 @@
ARG CRYSTAL_VERSION=1.0.0
FROM crystallang/crystal:${CRYSTAL_VERSION} as build

ARG PLACE_COMMIT=DEV
# Digest CLI
###############################################################################
FROM crystallang/crystal:${CRYSTAL_VERSION} as digest

ARG CRYSTAL_VERSION=1.0.0
ARG PLACE_COMMIT="DEV"

WORKDIR /app

RUN apt update
RUN apt install --no-install-recommends -y \
RUN apt-get update && \
apt-get install -y apt-transport-https && \
apt-get update && \
DEBIAN_FRONTEND=noninteractive \
apt install --no-install-recommends -y \
bash \
ca-certificates \
curl \
git \
libssh2-1 libssh2-1-dev \
libgc-dev \
llvm-10 llvm-10-dev \
tzdata
libssh2-1 libssh2-1-dev \
libyaml-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Add trusted CAs for communicating with external services
RUN update-ca-certificates
# Install shards before adding source.
COPY shard.yml /app
COPY shard.lock /app
RUN shards install --ignore-crystal-version

# Create a non-privileged user
ARG IMAGE_UID="10001"
ENV UID=$IMAGE_UID
ENV USER=appuser
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
"${USER}"
# Build digest tool before copying rest of source for better caching.
COPY src/digest_cli.cr /app/src/digest_cli.cr
RUN CRYSTAL_PATH=lib:/usr/share/crystal/src/ \
LLVM_CONFIG=$(/usr/share/crystal/src/llvm/ext/find-llvm-config) \
shards build digest_cli -Dpreview_mt --ignore-crystal-version --no-debug --production

# These provide certificate chain validation where communicating with external services over TLS
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
# Extract dependencies
RUN ldd /app/bin/digest_cli | tr -s '[:blank:]' '\n' | grep '^/' | xargs -I % sh -c 'mkdir -p $(dirname deps%); cp % deps%;'

# Create binary directories
RUN mkdir -p repositories bin/drivers
# Build
###############################################################################

RUN mkdir /app/.shards
FROM crystallang/crystal:${CRYSTAL_VERSION}-alpine as build

# Install deps
COPY shard.yml /app
COPY shard.lock /app
ARG CRYSTAL_VERSION=1.0.0
ARG PLACE_COMMIT="DEV"

RUN shards install --production --ignore-crystal-version
WORKDIR /app

# Copy source for the long building `digest_cli`
RUN mkdir /app/src
COPY src/digest_cli.cr /app/src/digest_cli.cr
# Install the latest version of LibSSH2, ping, etc
RUN apk add --no-cache \
bash \
ca-certificates \
curl \
iputils \
libssh2-static \
yaml-static

# Add a glibc shim
# NOTE: Once musl builds are a supported target, `asdf` should be updated to use those builds
RUN mkdir keys && (cd keys && curl -slO https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub) && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-2.33-r0.apk && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-i18n-2.33-r0.apk && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-bin-2.33-r0.apk && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-dev-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-dev-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-bin-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-i18n-2.33-r0.apk && \
rm -r keys *.apk

RUN CRYSTAL_PATH=lib:/usr/share/crystal/src/ \
LLVM_CONFIG=$(/usr/share/crystal/src/llvm/ext/find-llvm-config) \
PLACE_COMMIT=${PLACE_COMMIT} \
UNAME_AT_COMPILE_TIME=true \
shards build --error-trace --ignore-crystal-version --release --production -Dpreview_mt digest_cli
# Add trusted CAs for communicating with external services
RUN update-ca-certificates

# Install shards before adding source.
COPY shard.yml /app
COPY shard.lock /app
RUN shards install --ignore-crystal-version

# Copy the `digest_cli` binary, and all of its runtime dependencies
COPY --from=digest /app/deps /
COPY --from=digest /app/bin/digest_cli /app/bin

# Add the rest of the source last for efficient caching
COPY scripts /app/scripts
COPY src /app/src

RUN PLACE_COMMIT=${PLACE_COMMIT} \
UNAME_AT_COMPILE_TIME=true \
shards build --error-trace --ignore-crystal-version --release --production -Dpreview_mt build

RUN chown appuser -R /app
shards build --error-trace -Dpreview_mt --release --ignore-crystal-version --production build

###############################################################################

USER appuser:appuser
ENV HOME="/app"
ENV CRYSTAL_VERSION=$CRYSTAL_VERSION
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

# Create a non-privileged user
ARG IMAGE_UID="10001"
ENV UID=$IMAGE_UID
ENV USER=appuser
RUN adduser \
--disabled-password \
--gecos "" \
--home "${HOME}" \
--shell "/sbin/nologin" \
--uid "${UID}" \
"${USER}"

# Install asdf version manager
SHELL ["/bin/bash", "-l", "-c"]
RUN git clone https://github.com/asdf-vm/asdf.git $HOME/.asdf --branch v0.8.0
RUN $HOME/.asdf/bin/asdf plugin-add crystal https://github.com/asdf-community/asdf-crystal.git
RUN echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc && \
RUN git clone --depth 1 https://github.com/asdf-vm/asdf.git $HOME/.asdf --branch v0.8.0 && \
$HOME/.asdf/bin/asdf plugin-add crystal https://github.com/asdf-community/asdf-crystal.git && \
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc && \
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.profile && \
source ~/.bashrc

RUN chown appuser -R "${HOME}"
USER appuser:appuser

EXPOSE 3000
HEALTHCHECK CMD wget -qO- http://localhost:3000/api/build/v1
CMD ["/app/scripts/entrypoint.sh", "--server", "-b", "0.0.0.0", "-p", "3000"]
99 changes: 76 additions & 23 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -1,55 +1,108 @@
ARG CRYSTAL_VERSION=1.0.0
FROM crystallang/crystal:${CRYSTAL_VERSION}

# Digest CLI
###############################################################################
FROM crystallang/crystal:${CRYSTAL_VERSION} as digest

ARG CRYSTAL_VERSION=1.0.0
ARG PLACE_COMMIT="DEV"

WORKDIR /app

RUN apt update
RUN apt install --no-install-recommends -y \
RUN apt-get update && \
apt-get install -y apt-transport-https && \
apt-get update && \
DEBIAN_FRONTEND=noninteractive \
apt install --no-install-recommends -y \
bash \
ca-certificates \
curl \
libssh2-1 libssh2-1-dev \
llvm-10 llvm-10-dev \

# Install watchexec
RUN curl -sLO https://github.com/watchexec/watchexec/releases/download/cli-v1.16.0/watchexec-1.16.0-x86_64-unknown-linux-gnu.deb && \
dpkg -i watchexec-1.16.0-x86_64-unknown-linux-gnu.deb && \
rm -rf ./*.deb

# Add trusted CAs for communicating with external services
RUN update-ca-certificates
libssh2-1 libssh2-1-dev \
libyaml-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install shards before adding source.
COPY shard.yml /app
COPY shard.lock /app
RUN shards install --ignore-crystal-version

# Build digest tool before copying rest of source for better caching.
RUN mkdir /app/src
COPY src/digest_cli.cr /app/src/digest_cli.cr

RUN CRYSTAL_PATH=lib:/usr/share/crystal/src/ \
LLVM_CONFIG=$(/usr/share/crystal/src/llvm/ext/find-llvm-config) \
shards build digest_cli --ignore-crystal-version --no-debug
shards build digest_cli -Dpreview_mt --ignore-crystal-version --no-debug --production

COPY src/digest_cli.cr /app/src/digest_cli.cr
# Extract dependencies
RUN ldd /app/bin/digest_cli | tr -s '[:blank:]' '\n' | grep '^/' | xargs -I % sh -c 'mkdir -p $(dirname deps%); cp % deps%;'

COPY scripts /app/scripts
COPY src /app/sr
# Build
###############################################################################

FROM crystallang/crystal:${CRYSTAL_VERSION}-alpine as build

ARG CRYSTAL_VERSION=1.0.0
ARG PLACE_COMMIT="DEV"

WORKDIR /app

# Install the latest version of LibSSH2, ping, etc
RUN apk add --no-cache \
bash \
ca-certificates \
curl \
iputils \
libssh2-static \
yaml-static

RUN mkdir -p /app/bin/drivers
# Add a glibc shim
# NOTE: Once musl builds are a supported target, `asdf` should be updated to use those builds
RUN mkdir keys && (cd keys && curl -slO https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub) && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-2.33-r0.apk && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-i18n-2.33-r0.apk && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-bin-2.33-r0.apk && \
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-dev-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-dev-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-bin-2.33-r0.apk && \
apk add --allow-untrusted --keys-dir keys glibc-i18n-2.33-r0.apk && \
rm -r keys *.apk

# Add trusted CAs for communicating with external services
RUN update-ca-certificates

# Add watchexec
RUN apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing watchexec

# Install shards before adding source.
COPY shard.yml /app
COPY shard.lock /app
RUN shards install --ignore-crystal-version

# Copy the `digest_cli` binary, and all of its runtime dependencies
COPY --from=digest /app/deps /
COPY --from=digest /app/bin/digest_cli /app/bin

COPY scripts /app/scripts
COPY src /app/src

# These provide certificate chain validation where communicating with external services over TLS
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

# Install asdf version manager
###############################################3###############################

ENV CRYSTAL_PATH=lib:/usr/share/crystal/src
ENV CRYSTAL_LIBRARY_PATH=/usr/local/lib
ENV CRYSTAL_VERSION=${CRYSTAL_VERSION}

ENV HOME="/app"
SHELL ["/bin/bash", "-l", "-c"]
RUN git clone https://github.com/asdf-vm/asdf.git $HOME/.asdf --branch v0.8.0 && \

# Install asdf version manager
RUN git clone --depth 1 https://github.com/asdf-vm/asdf.git $HOME/.asdf --branch v0.8.0 && \
$HOME/.asdf/bin/asdf plugin-add crystal https://github.com/asdf-community/asdf-crystal.git && \
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc && \
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.profile && \
echo -e '\n. $HOME/.asdf/asdf.sh' >> $HOME/.bashrc && \
echo -e '\n. $HOME/.asdf/asdf.sh' >> $HOME/.profile && \
source ~/.bashrc

CMD /app/scripts/entrypoint-test.sh
13 changes: 5 additions & 8 deletions scripts/entrypoint-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

set -eu

source $HOME/.asdf/asdf.sh
source ${HOME}/.asdf/asdf.sh

asdf install crystal 1.0.0
asdf global crystal 1.0.0
asdf install crystal ${CRYSTAL_VERSION}
asdf global crystal ${CRYSTAL_VERSION}

if [ -z ${GITHUB_ACTION+x} ]
then
Expand All @@ -16,9 +16,6 @@ then
crystal lib/ameba/bin/ameba.cr
fi

export CRYSTAL_PATH=lib:/usr/share/crystal/src
export CRYSTAL_LIBRARY_PATH=/usr/local/lib

watch="false"
multithreaded="false"
while [[ $# -gt 0 ]]
Expand All @@ -36,13 +33,13 @@ do
esac
done

if [[ "$multithreaded" == "true" ]]; then
if [[ "${multithreaded}" == "true" ]]; then
args="-Dpreview_mt"
else
args=""
fi

if [[ "$watch" == "true" ]]; then
if [[ "${watch}" == "true" ]]; then
CRYSTAL_WORKERS=$(nproc) watchexec -e cr -c -r -w src -w spec -- scripts/crystal-spec.sh -v ${args}
else
CRYSTAL_WORKERS=$(nproc) scripts/crystal-spec.sh -v ${args}
Expand Down

0 comments on commit 1851ab6

Please sign in to comment.