diff --git a/Dockerfile b/Dockerfile index 67a5c1f..9d42b7e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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"] diff --git a/Dockerfile.test b/Dockerfile.test index 0d175a8..66802ef 100644 --- a/Dockerfile.test +++ b/Dockerfile.test @@ -1,25 +1,26 @@ 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 @@ -27,29 +28,81 @@ 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 diff --git a/scripts/entrypoint-test.sh b/scripts/entrypoint-test.sh index 49454ac..e02c93e 100755 --- a/scripts/entrypoint-test.sh +++ b/scripts/entrypoint-test.sh @@ -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 @@ -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 ]] @@ -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}