tessellator / openfaas-clojure-template

An OpenFaaS template for writing functions in Clojure
MIT License
9 stars 6 forks source link

faas-cli build stalled at: clojure -e "(compile 'entrypoint.core)" #6

Closed ccfontes closed 3 years ago

ccfontes commented 3 years ago

faas-cli build stalls at the following step in the Dockerfile:

clojure -e "(compile 'entrypoint.core)"

See details below (verbose):

#8 [4/6] RUN clojure -Sverbose -e "(compile 'entrypoint.core)"
#8 sha256:35927bc393935f40eb61cc60a1c6da0a9f718fb0e59bd6c3875b52afd9ff9035
#8 0.214 version      = 1.10.0.411
#8 0.214 install_dir  = /usr/local/lib/clojure
#8 0.214 config_dir   = /root/.clojure
#8 0.214 config_paths = /usr/local/lib/clojure/deps.edn /root/.clojure/deps.edn deps.edn
#8 0.215 cache_dir    = .cpcache
#8 0.215 cp_file      = .cpcache/246823853.cp
#8 0.215
#8 0.216 Refreshing classpath

This only happens on my macbook M1 (arm64). Others seem to have similar issue with JVM processes, quote:

I had issues with the JVM, experiencing random process hangs. It seems that there are no official OpenJDK builds for aarch64

from https://earthly.dev/blog/using-apple-silicon-m1-as-a-cloud-engineer-two-months-in/

I confirmed that the openjdk:8u121-jdk-alpine image used in openfaas-clojure-builder doesn't support arm64 architecture:

❯ docker run --rm --platform=linux/arm64 openjdk:8u121-jdk-alpine uname -m
Unable to find image 'openjdk:8u121-jdk-alpine' locally
8u121-jdk-alpine: Pulling from library/openjdk
Digest: sha256:020e0b5248b1e4963ea1ce9b1248f153d671c8c95b6ff3c3857d0c409c5b5c65
Status: Image is up to date for openjdk:8u121-jdk-alpine
docker: Error response from daemon: image with reference openjdk:8u121-jdk-alpine was found but does not match the specified platform: wanted linux/arm64, actual: linux/amd64.
See 'docker run --help'.

Successfully attempted a fix with an alternative image supporting arm64 – balenalib/generic-aarch64-alpine-openjdk:8:

FROM balenalib/generic-aarch64-alpine-openjdk:8-20210225 as builder

LABEL maintainer="Chad Taylor <taylor.thomas.c@gmail.com>"
LABEL description="A base builder image for the OpenFaaS Clojure Template"

WORKDIR /home/app

RUN apk --no-cache add curl bash \
    && curl -O https://download.clojure.org/install/linux-install-1.10.0.411.sh \
    && chmod +x linux-install-1.10.0.411.sh \
    && ./linux-install-1.10.0.411.sh

WORKDIR /home/app/entrypoint
COPY . /home/app

RUN clojure -e "(compile 'entrypoint.core)" \
    && clojure -A:depstar -m hf.depstar.uberjar Entrypoint.jar \
    && if [ -f ../function/manifest.mf ] ; then echo "applying manifest" && jar umf ../function/manifest.mf ./Entrypoint.jar ; fi

Would you be interested in supporting arm64? I'd leave at your discretion to find a solution compatible with both x86 and arm64.

tessellator commented 3 years ago

Hey @ccfontes -

I have spent some time thinking about this. I would prefer to stick with official images whenever possible but would also like to support ARM64. I would like to propose a compromise (implemented in #7) until ARM64 is supported in one of the official images:

Do you think this is a reasonable approach?

ccfontes commented 3 years ago

Hey @tessellator

Thanks for asking my opinion! (and sorry for the late reply). I think yours is a reasonable approach.

Additionally, I had to change fwatchdog to fwatchdog-arm64 and also the final stage image to run the jar.

Full Dockerfile follows:

FROM balenalib/generic-aarch64-alpine-openjdk:8-20210225 as builder

LABEL maintainer="Chad Taylor <taylor.thomas.c@gmail.com>"
LABEL description="A base builder image for the OpenFaaS Clojure Template"

WORKDIR /home/app

RUN apk --no-cache add curl bash \
    && curl -O https://download.clojure.org/install/linux-install-1.10.0.411.sh \
    && chmod +x linux-install-1.10.0.411.sh \
    && ./linux-install-1.10.0.411.sh

WORKDIR /home/app/entrypoint
COPY . /home/app

RUN clojure -e "(compile 'entrypoint.core)" \
    && clojure -A:depstar -m hf.depstar.uberjar Entrypoint.jar \
    && if [ -f ../function/manifest.mf ] ; then echo "applying manifest" && jar umf ../function/manifest.mf ./Entrypoint.jar ; fi

## -----------------------------------------------------------------------------

FROM alpine:latest as fwatchdog-fetcher

WORKDIR /home

RUN apk add curl \
    && curl -sSL https://github.com/openfaas/of-watchdog/releases/download/0.8.4/fwatchdog-arm64 > fwatchdog \
    && chmod +x ./fwatchdog

## -----------------------------------------------------------------------------

FROM balenalib/generic-aarch64-alpine-openjdk:8-20210225 as ship

RUN addgroup -S app && adduser -S app -G app
USER app

ENV upstream_url="http://127.0.0.1:4000"
ENV mode="http"

ENV fprocess="java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -cp Entrypoint.jar clojure.main -m entrypoint.core"
EXPOSE 8080

HEALTHCHECK --interval=2s CMD [ -e /tmp/.lock ] || exit 1

# Do not let the watchdog create the lock file. The watchdog can create the lock
# file before the Jetty instance is actually ready, causing the function to be
# exposed too early and causing 500 Internal Server Error responses. Instead,
# rely on the entrypoint to create the lock file when Jetty is ready.
ENV suppress_lock=true

CMD ["./fwatchdog"]

COPY --chown=app --from=fwatchdog-fetcher /home/fwatchdog ./fwatchdog
COPY --chown=app --from=builder /home/app/entrypoint/Entrypoint.jar ./Entrypoint.jar

PS – this is great, thanks!:

# During the build step, the dev dependencies from the function are fetched. I
# do not know why. This line will go and fetch those dependencies as an
# independent step so that if only the function code changes there will be no
# need to fetch the dev dependencies.
tessellator commented 3 years ago

Please do not apologize; there is nothing to apologize for. :) I appreciate your help and feedback.

I have taken your feedback and incorporated it into the Dockerfile writeup.