Skip to content

Commit 62e6411

Browse files
authored
Add Ghost 5 support (#306)
* Bump base node image for alpine and debian to node 16 * Switch 'latest' tag creation from version 4 to 5
1 parent 054059f commit 62e6411

File tree

5 files changed

+224
-1
lines changed

5 files changed

+224
-1
lines changed

5/alpine/Dockerfile

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# https://docs.ghost.org/faq/node-versions/
2+
# https://github.com/nodejs/Release (looking for "LTS")
3+
# https://github.com/TryGhost/Ghost/blob/v5.0.0/package.json#L54
4+
FROM node:16-alpine3.15
5+
6+
# grab su-exec for easy step-down from root
7+
RUN apk add --no-cache 'su-exec>=0.2'
8+
9+
RUN apk add --no-cache \
10+
# add "bash" for "[["
11+
bash
12+
13+
ENV NODE_ENV production
14+
15+
ENV GHOST_CLI_VERSION 1.21.0
16+
RUN set -eux; \
17+
npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \
18+
npm cache clean --force
19+
20+
ENV GHOST_INSTALL /var/lib/ghost
21+
ENV GHOST_CONTENT /var/lib/ghost/content
22+
23+
ENV GHOST_VERSION 5.0.0
24+
25+
RUN set -eux; \
26+
mkdir -p "$GHOST_INSTALL"; \
27+
chown node:node "$GHOST_INSTALL"; \
28+
\
29+
su-exec node ghost install "$GHOST_VERSION" --db sqlite3 --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"; \
30+
\
31+
# Tell Ghost to listen on all ips and not prompt for additional configuration
32+
cd "$GHOST_INSTALL"; \
33+
su-exec node ghost config --ip '::' --port 2368 --no-prompt --db sqlite3 --url http://localhost:2368 --dbpath "$GHOST_CONTENT/data/ghost.db"; \
34+
su-exec node ghost config paths.contentPath "$GHOST_CONTENT"; \
35+
\
36+
# make a config.json symlink for NODE_ENV=development (and sanity check that it's correct)
37+
su-exec node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \
38+
readlink -f "$GHOST_INSTALL/config.development.json"; \
39+
\
40+
# need to save initial content for pre-seeding empty volumes
41+
mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \
42+
mkdir -p "$GHOST_CONTENT"; \
43+
chown node:node "$GHOST_CONTENT"; \
44+
chmod 1777 "$GHOST_CONTENT"; \
45+
\
46+
# force install "sqlite3" manually since it's an optional dependency of "ghost"
47+
# (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)
48+
# see https://github.com/TryGhost/Ghost/pull/7677 for more details
49+
cd "$GHOST_INSTALL/current"; \
50+
# scrape the expected version of sqlite3 directly from Ghost itself
51+
sqlite3Version="$(node -p 'require("./package.json").optionalDependencies["sqlite3"]')"; \
52+
[ -n "$sqlite3Version" ]; \
53+
[ "$sqlite3Version" != 'undefined' ]; \
54+
if ! su-exec node yarn add "sqlite3@$sqlite3Version" --force; then \
55+
# 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
56+
apk add --no-cache --virtual .build-deps g++ gcc libc-dev make python2 vips-dev; \
57+
\
58+
npm_config_python='python2' su-exec node yarn add "sqlite3@$sqlite3Version" --force --build-from-source; \
59+
\
60+
apk del --no-network .build-deps; \
61+
fi; \
62+
\
63+
su-exec node yarn cache clean; \
64+
su-exec node npm cache clean --force; \
65+
npm cache clean --force; \
66+
rm -rv /tmp/yarn* /tmp/v8*
67+
68+
WORKDIR $GHOST_INSTALL
69+
VOLUME $GHOST_CONTENT
70+
71+
COPY docker-entrypoint.sh /usr/local/bin
72+
ENTRYPOINT ["docker-entrypoint.sh"]
73+
74+
EXPOSE 2368
75+
CMD ["node", "current/index.js"]

5/alpine/docker-entrypoint.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# allow the container to be started with `--user`
5+
if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then
6+
find "$GHOST_CONTENT" \! -user node -exec chown node '{}' +
7+
exec su-exec node "$BASH_SOURCE" "$@"
8+
fi
9+
10+
if [[ "$*" == node*current/index.js* ]]; then
11+
baseDir="$GHOST_INSTALL/content.orig"
12+
for src in "$baseDir"/*/ "$baseDir"/themes/*; do
13+
src="${src%/}"
14+
target="$GHOST_CONTENT/${src#$baseDir/}"
15+
mkdir -p "$(dirname "$target")"
16+
if [ ! -e "$target" ]; then
17+
tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")"
18+
fi
19+
done
20+
fi
21+
22+
exec "$@"

5/debian/Dockerfile

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# https://docs.ghost.org/faq/node-versions/
2+
# https://github.com/nodejs/Release (looking for "LTS")
3+
# https://github.com/TryGhost/Ghost/blob/v4.1.2/package.json#L38
4+
FROM node:16-bullseye-slim
5+
6+
# grab gosu for easy step-down from root
7+
# https://github.com/tianon/gosu/releases
8+
ENV GOSU_VERSION 1.12
9+
RUN set -eux; \
10+
# save list of currently installed packages for later so we can clean up
11+
savedAptMark="$(apt-mark showmanual)"; \
12+
apt-get update; \
13+
apt-get install -y --no-install-recommends ca-certificates dirmngr gnupg wget; \
14+
rm -rf /var/lib/apt/lists/*; \
15+
\
16+
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
17+
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
18+
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
19+
\
20+
# verify the signature
21+
export GNUPGHOME="$(mktemp -d)"; \
22+
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
23+
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
24+
command -v gpgconf && gpgconf --kill all || :; \
25+
rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
26+
\
27+
# clean up fetch dependencies
28+
apt-mark auto '.*' > /dev/null; \
29+
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
30+
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
31+
\
32+
chmod +x /usr/local/bin/gosu; \
33+
# verify that the binary works
34+
gosu --version; \
35+
gosu nobody true
36+
37+
ENV NODE_ENV production
38+
39+
ENV GHOST_CLI_VERSION 1.21.0
40+
RUN set -eux; \
41+
npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \
42+
npm cache clean --force
43+
44+
ENV GHOST_INSTALL /var/lib/ghost
45+
ENV GHOST_CONTENT /var/lib/ghost/content
46+
47+
ENV GHOST_VERSION 5.0.0
48+
49+
RUN set -eux; \
50+
mkdir -p "$GHOST_INSTALL"; \
51+
chown node:node "$GHOST_INSTALL"; \
52+
\
53+
gosu node ghost install "$GHOST_VERSION" --db sqlite3 --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"; \
54+
\
55+
# Tell Ghost to listen on all ips and not prompt for additional configuration
56+
cd "$GHOST_INSTALL"; \
57+
gosu node ghost config --ip '::' --port 2368 --no-prompt --db sqlite3 --url http://localhost:2368 --dbpath "$GHOST_CONTENT/data/ghost.db"; \
58+
gosu node ghost config paths.contentPath "$GHOST_CONTENT"; \
59+
\
60+
# make a config.json symlink for NODE_ENV=development (and sanity check that it's correct)
61+
gosu node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \
62+
readlink -f "$GHOST_INSTALL/config.development.json"; \
63+
\
64+
# need to save initial content for pre-seeding empty volumes
65+
mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \
66+
mkdir -p "$GHOST_CONTENT"; \
67+
chown node:node "$GHOST_CONTENT"; \
68+
chmod 1777 "$GHOST_CONTENT"; \
69+
\
70+
# force install "sqlite3" manually since it's an optional dependency of "ghost"
71+
# (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)
72+
# see https://github.com/TryGhost/Ghost/pull/7677 for more details
73+
cd "$GHOST_INSTALL/current"; \
74+
# scrape the expected version of sqlite3 directly from Ghost itself
75+
sqlite3Version="$(node -p 'require("./package.json").optionalDependencies["sqlite3"]')"; \
76+
[ -n "$sqlite3Version" ]; \
77+
[ "$sqlite3Version" != 'undefined' ]; \
78+
if ! gosu node yarn add "sqlite3@$sqlite3Version" --force; then \
79+
# 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
80+
savedAptMark="$(apt-mark showmanual)"; \
81+
apt-get update; \
82+
apt-get install -y --no-install-recommends g++ gcc libc-dev libvips-dev make python2; \
83+
rm -rf /var/lib/apt/lists/*; \
84+
\
85+
npm_config_python='python2' gosu node yarn add "sqlite3@$sqlite3Version" --force --build-from-source; \
86+
\
87+
apt-mark showmanual | xargs apt-mark auto > /dev/null; \
88+
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
89+
apt-get purge -y --auto-remove; \
90+
fi; \
91+
\
92+
gosu node yarn cache clean; \
93+
gosu node npm cache clean --force; \
94+
npm cache clean --force; \
95+
rm -rv /tmp/yarn* /tmp/v8*
96+
97+
WORKDIR $GHOST_INSTALL
98+
VOLUME $GHOST_CONTENT
99+
100+
COPY docker-entrypoint.sh /usr/local/bin
101+
ENTRYPOINT ["docker-entrypoint.sh"]
102+
103+
EXPOSE 2368
104+
CMD ["node", "current/index.js"]

5/debian/docker-entrypoint.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# allow the container to be started with `--user`
5+
if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then
6+
find "$GHOST_CONTENT" \! -user node -exec chown node '{}' +
7+
exec gosu node "$BASH_SOURCE" "$@"
8+
fi
9+
10+
if [[ "$*" == node*current/index.js* ]]; then
11+
baseDir="$GHOST_INSTALL/content.orig"
12+
for src in "$baseDir"/*/ "$baseDir"/themes/*; do
13+
src="${src%/}"
14+
target="$GHOST_CONTENT/${src#$baseDir/}"
15+
mkdir -p "$(dirname "$target")"
16+
if [ ! -e "$target" ]; then
17+
tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")"
18+
fi
19+
done
20+
fi
21+
22+
exec "$@"

generate-stackbrew-library.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
set -eu
33

44
declare -A aliases=(
5-
[4]='latest'
5+
[5]='latest'
66
)
77
defaultVariant='debian'
88

0 commit comments

Comments
 (0)