diff --git a/5/alpine/Dockerfile b/5/alpine/Dockerfile new file mode 100644 index 00000000..58b7a0ee --- /dev/null +++ b/5/alpine/Dockerfile @@ -0,0 +1,75 @@ +# https://docs.ghost.org/faq/node-versions/ +# https://github.com/nodejs/Release (looking for "LTS") +# https://github.com/TryGhost/Ghost/blob/v5.0.0/package.json#L54 +FROM node:16-alpine3.15 + +# grab su-exec for easy step-down from root +RUN apk add --no-cache 'su-exec>=0.2' + +RUN apk add --no-cache \ +# add "bash" for "[[" + bash + +ENV NODE_ENV production + +ENV GHOST_CLI_VERSION 1.21.0 +RUN set -eux; \ + npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \ + npm cache clean --force + +ENV GHOST_INSTALL /var/lib/ghost +ENV GHOST_CONTENT /var/lib/ghost/content + +ENV GHOST_VERSION 5.0.0 + +RUN set -eux; \ + mkdir -p "$GHOST_INSTALL"; \ + chown node:node "$GHOST_INSTALL"; \ + \ + su-exec node ghost install "$GHOST_VERSION" --db sqlite3 --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"; \ + \ +# Tell Ghost to listen on all ips and not prompt for additional configuration + cd "$GHOST_INSTALL"; \ + su-exec node ghost config --ip '::' --port 2368 --no-prompt --db sqlite3 --url http://localhost:2368 --dbpath "$GHOST_CONTENT/data/ghost.db"; \ + su-exec node ghost config paths.contentPath "$GHOST_CONTENT"; \ + \ +# make a config.json symlink for NODE_ENV=development (and sanity check that it's correct) + su-exec node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \ + readlink -f "$GHOST_INSTALL/config.development.json"; \ + \ +# need to save initial content for pre-seeding empty volumes + mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \ + mkdir -p "$GHOST_CONTENT"; \ + chown node:node "$GHOST_CONTENT"; \ + chmod 1777 "$GHOST_CONTENT"; \ + \ +# force install "sqlite3" manually since it's an optional dependency of "ghost" +# (which means that if it fails to install, like on ARM/ppc64le/s390x, the failure will be silently ignored and thus turn into a runtime error instead) +# see https://github.com/TryGhost/Ghost/pull/7677 for more details + cd "$GHOST_INSTALL/current"; \ +# scrape the expected version of sqlite3 directly from Ghost itself + sqlite3Version="$(node -p 'require("./package.json").optionalDependencies["sqlite3"]')"; \ + [ -n "$sqlite3Version" ]; \ + [ "$sqlite3Version" != 'undefined' ]; \ + if ! su-exec node yarn add "sqlite3@$sqlite3Version" --force; then \ +# must be some non-amd64 architecture pre-built binaries aren't published for, so let's install some build deps and do-it-all-over-again + apk add --no-cache --virtual .build-deps g++ gcc libc-dev make python2 vips-dev; \ + \ + npm_config_python='python2' su-exec node yarn add "sqlite3@$sqlite3Version" --force --build-from-source; \ + \ + apk del --no-network .build-deps; \ + fi; \ + \ + su-exec node yarn cache clean; \ + su-exec node npm cache clean --force; \ + npm cache clean --force; \ + rm -rv /tmp/yarn* /tmp/v8* + +WORKDIR $GHOST_INSTALL +VOLUME $GHOST_CONTENT + +COPY docker-entrypoint.sh /usr/local/bin +ENTRYPOINT ["docker-entrypoint.sh"] + +EXPOSE 2368 +CMD ["node", "current/index.js"] diff --git a/5/alpine/docker-entrypoint.sh b/5/alpine/docker-entrypoint.sh new file mode 100755 index 00000000..c4d007b5 --- /dev/null +++ b/5/alpine/docker-entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +# allow the container to be started with `--user` +if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then + find "$GHOST_CONTENT" \! -user node -exec chown node '{}' + + exec su-exec node "$BASH_SOURCE" "$@" +fi + +if [[ "$*" == node*current/index.js* ]]; then + baseDir="$GHOST_INSTALL/content.orig" + for src in "$baseDir"/*/ "$baseDir"/themes/*; do + src="${src%/}" + target="$GHOST_CONTENT/${src#$baseDir/}" + mkdir -p "$(dirname "$target")" + if [ ! -e "$target" ]; then + tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")" + fi + done +fi + +exec "$@" diff --git a/5/debian/Dockerfile b/5/debian/Dockerfile new file mode 100644 index 00000000..65d549dd --- /dev/null +++ b/5/debian/Dockerfile @@ -0,0 +1,104 @@ +# https://docs.ghost.org/faq/node-versions/ +# https://github.com/nodejs/Release (looking for "LTS") +# https://github.com/TryGhost/Ghost/blob/v4.1.2/package.json#L38 +FROM node:16-bullseye-slim + +# grab gosu for easy step-down from root +# https://github.com/tianon/gosu/releases +ENV GOSU_VERSION 1.12 +RUN set -eux; \ +# save list of currently installed packages for later so we can clean up + savedAptMark="$(apt-mark showmanual)"; \ + apt-get update; \ + apt-get install -y --no-install-recommends ca-certificates dirmngr gnupg wget; \ + rm -rf /var/lib/apt/lists/*; \ + \ + dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ + wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ + \ +# verify the signature + export GNUPGHOME="$(mktemp -d)"; \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ + gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ + command -v gpgconf && gpgconf --kill all || :; \ + rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ + \ +# clean up fetch dependencies + apt-mark auto '.*' > /dev/null; \ + [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + \ + chmod +x /usr/local/bin/gosu; \ +# verify that the binary works + gosu --version; \ + gosu nobody true + +ENV NODE_ENV production + +ENV GHOST_CLI_VERSION 1.21.0 +RUN set -eux; \ + npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \ + npm cache clean --force + +ENV GHOST_INSTALL /var/lib/ghost +ENV GHOST_CONTENT /var/lib/ghost/content + +ENV GHOST_VERSION 5.0.0 + +RUN set -eux; \ + mkdir -p "$GHOST_INSTALL"; \ + chown node:node "$GHOST_INSTALL"; \ + \ + gosu node ghost install "$GHOST_VERSION" --db sqlite3 --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"; \ + \ +# Tell Ghost to listen on all ips and not prompt for additional configuration + cd "$GHOST_INSTALL"; \ + gosu node ghost config --ip '::' --port 2368 --no-prompt --db sqlite3 --url http://localhost:2368 --dbpath "$GHOST_CONTENT/data/ghost.db"; \ + gosu node ghost config paths.contentPath "$GHOST_CONTENT"; \ + \ +# make a config.json symlink for NODE_ENV=development (and sanity check that it's correct) + gosu node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \ + readlink -f "$GHOST_INSTALL/config.development.json"; \ + \ +# need to save initial content for pre-seeding empty volumes + mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \ + mkdir -p "$GHOST_CONTENT"; \ + chown node:node "$GHOST_CONTENT"; \ + chmod 1777 "$GHOST_CONTENT"; \ + \ +# force install "sqlite3" manually since it's an optional dependency of "ghost" +# (which means that if it fails to install, like on ARM/ppc64le/s390x, the failure will be silently ignored and thus turn into a runtime error instead) +# see https://github.com/TryGhost/Ghost/pull/7677 for more details + cd "$GHOST_INSTALL/current"; \ +# scrape the expected version of sqlite3 directly from Ghost itself + sqlite3Version="$(node -p 'require("./package.json").optionalDependencies["sqlite3"]')"; \ + [ -n "$sqlite3Version" ]; \ + [ "$sqlite3Version" != 'undefined' ]; \ + if ! gosu node yarn add "sqlite3@$sqlite3Version" --force; then \ +# must be some non-amd64 architecture pre-built binaries aren't published for, so let's install some build deps and do-it-all-over-again + savedAptMark="$(apt-mark showmanual)"; \ + apt-get update; \ + apt-get install -y --no-install-recommends g++ gcc libc-dev libvips-dev make python2; \ + rm -rf /var/lib/apt/lists/*; \ + \ + npm_config_python='python2' gosu node yarn add "sqlite3@$sqlite3Version" --force --build-from-source; \ + \ + apt-mark showmanual | xargs apt-mark auto > /dev/null; \ + [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \ + apt-get purge -y --auto-remove; \ + fi; \ + \ + gosu node yarn cache clean; \ + gosu node npm cache clean --force; \ + npm cache clean --force; \ + rm -rv /tmp/yarn* /tmp/v8* + +WORKDIR $GHOST_INSTALL +VOLUME $GHOST_CONTENT + +COPY docker-entrypoint.sh /usr/local/bin +ENTRYPOINT ["docker-entrypoint.sh"] + +EXPOSE 2368 +CMD ["node", "current/index.js"] diff --git a/5/debian/docker-entrypoint.sh b/5/debian/docker-entrypoint.sh new file mode 100755 index 00000000..f4614d4e --- /dev/null +++ b/5/debian/docker-entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +# allow the container to be started with `--user` +if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then + find "$GHOST_CONTENT" \! -user node -exec chown node '{}' + + exec gosu node "$BASH_SOURCE" "$@" +fi + +if [[ "$*" == node*current/index.js* ]]; then + baseDir="$GHOST_INSTALL/content.orig" + for src in "$baseDir"/*/ "$baseDir"/themes/*; do + src="${src%/}" + target="$GHOST_CONTENT/${src#$baseDir/}" + mkdir -p "$(dirname "$target")" + if [ ! -e "$target" ]; then + tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")" + fi + done +fi + +exec "$@" diff --git a/generate-stackbrew-library.sh b/generate-stackbrew-library.sh index 41e157bb..447e25a0 100755 --- a/generate-stackbrew-library.sh +++ b/generate-stackbrew-library.sh @@ -2,7 +2,7 @@ set -eu declare -A aliases=( - [4]='latest' + [5]='latest' ) defaultVariant='debian'