forked from firepress-org/ghostfire
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Dockerfile
executable file
·222 lines (205 loc) · 10.7 KB
/
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
ARG VERSION="2.37.0"
ARG APP_NAME="ghost"
ARG GIT_PROJECT_NAME="ghostfire"
#
ARG ALPINE_VERSION="3.10"
#
ARG GHOST_CLI_VERSION="1.11.0"
ARG NODE_VERSION="10.16-alpine"
ARG USER="node"
ARG GHOST_USER="node"
ARG CREATED_DATE=not-set
ARG SOURCE_COMMIT=not-set
#
ARG DOCKERHUB_USER="devmtl"
ARG GITHUB_USER="firepress"
ARG GITHUB_ORG="firepress-org"
ARG GITHUB_REGISTRY="registry"
#
ARG GIT_REPO_DOCKERFILE="https://github.com/firepress-org/ghostfire"
ARG GIT_REPO_SOURCE="https://github.com/TryGhost/Ghost"
# ----------------------------------------------
# 1) LAYER to manage base image(s) versioning
# credit to Tõnis Tiigi / https://bit.ly/2RoCmvG
# ----------------------------------------------
FROM alpine:${ALPINE_VERSION} AS myalpine
FROM node:${NODE_VERSION} AS mynode
# ----------------------------------------------
# 2) LAYER app-version-debug
# If a package crash on further layers, we don't know which one did crash. This layer make it easy to see.
# ----------------------------------------------
FROM myalpine AS app-version-debug
RUN set -eux && apk update && apk add --no-cache \
'su-exec>=0.2' bash upx curl tini tzdata && \
# Reveal package(s) versions and keep a trace in the CI's logs.
apk upgrade
# ----------------------------------------------
# 3) LAYER node-compress
# before node=39.8MO / after node=14.2MO
# We copy from node image as it's using alpine 3.9. It creates delta between app versions such upx.
# ----------------------------------------------
FROM myalpine AS node-compress
COPY --from=mynode /usr/local/bin/node /usr/local/bin/node
RUN set -eux && \
apk --update add --no-cache \
upx="3.95-r2" && \
upx /usr/local/bin/node && \
upx -t /usr/local/bin/node ;
# ----------------------------------------------
# 4) LAYER node-core
# Build our node-core layer (no extra stuff like yarn, npm, npx, etc.)
# ----------------------------------------------
FROM myalpine AS node-core
ARG GHOST_USER
ENV GHOST_USER="${GHOST_USER}"
# set up node user and group
RUN set -eux && \
addgroup -g 1000 "${GHOST_USER}" && \
adduser -u 1000 -G "${GHOST_USER}" -s /bin/sh -D node ;
COPY --from=node-compress --chown=node:node /usr/local/bin/node /usr/bin/
COPY --from=mynode --chown=node:node /usr/lib/libgcc* /usr/lib/libstdc* /usr/lib/
# credit to https://github.com/mhart/alpine-node/blob/master/slim/Dockerfile
# ----------------------------------------------
# 5) LAYER ghost-base
# ----------------------------------------------
FROM node-core AS ghost-base
RUN set -eux && apk add --no-cache \
# grab su-exec for easy step-down from root
'su-exec>=0.2' \
bash="5.0.0-r0" \
curl="7.66.0-r0" \
tini="0.18.0-r0" \
tzdata="2019c-r0" && \
cp /usr/share/zoneinfo/America/New_York /etc/localtime && \
echo "America/New_York" > /etc/timezone && \
apk del tzdata && \
rm -rvf /var/cache/apk/* /tmp/* ;
COPY --chown=node:node docker-entrypoint.sh /usr/local/bin
COPY --chown=node:node Dockerfile /usr/local/bin
COPY --chown=node:node README.md /usr/local/bin
ARG VERSION
ARG GHOST_CLI_VERSION
ARG NODE_VERSION
ARG ALPINE_VERSION
ENV GHOST_INSTALL="/var/lib/ghost" \
GHOST_CONTENT="/var/lib/ghost/content" \
NODE_ENV="production" \
GHOST_USER="${GHOST_USER}" \
VERSION="${VERSION}" \
GHOST_CLI_VERSION="${GHOST_CLI_VERSION}"
# add knex-migrator bins into PATH
# we want these from the context of Ghost's "node_modules" directory (instead of doing "npm install -g knex-migrator") so they can share the DB driver modules
ENV PATH $PATH:$GHOST_INSTALL/current/node_modules/knex-migrator/bin
# credit to https://github.com/opencontainers/image-spec/blob/master/annotations.md
LABEL org.opencontainers.image.authors="Pascal Andy https://firepress.org/en/contact/" \
org.opencontainers.image.vendors="https://firepress.org/" \
org.opencontainers.image.created="${CREATED_DATE}" \
org.opencontainers.image.revision="${SOURCE_COMMIT}" \
org.opencontainers.image.title="Ghost V2" \
org.opencontainers.image.description="Docker image for Ghost ${VERSION}" \
org.opencontainers.image.url="https://hub.docker.com/r/devmtl/ghostfire/tags/" \
org.opencontainers.image.source="https://github.com/firepress-org/ghostfire" \
org.opencontainers.image.licenses="GNUv3 https://github.com/pascalandy/GNU-GENERAL-PUBLIC-LICENSE/blob/master/LICENSE.md" \
org.firepress.image.cliversion="${GHOST_CLI_VERSION}" \
org.firepress.image.user="${GHOST_USER}" \
org.firepress.image.node-env="${NODE_ENV}" \
org.firepress.image.nodeversion="${NODE_VERSION}" \
org.firepress.image.alpineversion="${ALPINE_VERSION}" \
org.firepress.image.schemaversion="1.0"
WORKDIR "${GHOST_INSTALL}"
VOLUME "${GHOST_CONTENT}"
USER "${GHOST_USER}"
EXPOSE 2368
# HEALTHCHECK CMD wget -q -s http://localhost:2368 || exit 1 // bypassed as attributes are passed during runtime <docker service create>
# next, copy Ghost's app in the final layer
# ----------------------------------------------
# 6) LAYER BUILDER
# ----------------------------------------------
FROM mynode AS ghost-builder
ARG VERSION
ARG GHOST_CLI_VERSION
ARG GHOST_USER
ARG NODE_VERSION
ENV GHOST_INSTALL="/var/lib/ghost" \
GHOST_CONTENT="/var/lib/ghost/content" \
NODE_ENV="production" \
GHOST_USER="${GHOST_USER}" \
VERSION="${VERSION}" \
GHOST_CLI_VERSION="${GHOST_CLI_VERSION}"
# installation process from the official Ghost image https://bit.ly/2JWOTam
RUN set -eux && apk --update add --no-cache \
su-exec>="0.2" \
bash="4.4.19-r1" \
ca-certificates="20190108-r0" && \
update-ca-certificates && \
rm -rvf /var/cache/apk/* && \
\
# install Ghost CLI
npm install --production -g "ghost-cli@${GHOST_CLI_VERSION}" && \
npm cache clean --force && \
\
mkdir -p "${GHOST_INSTALL}" && \
chown -R "${GHOST_USER}":"${GHOST_USER}" "${GHOST_INSTALL}" && \
\
# install Ghost / optional: --verbose
su-exec node ghost install "${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 0.0.0.0 \
--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 -R "${GHOST_USER}":"${GHOST_USER}" "$GHOST_CONTENT" && \
\
# sanity check to ensure knex-migrator was installed
"${GHOST_INSTALL}/current/node_modules/knex-migrator/bin/knex-migrator" --version && \
# sanity check to list all packages
npm config list ;
# 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
RUN set -eux && \
cd "${GHOST_INSTALL}/current" && \
# scrape the expected version of sqlite3 directly from Ghost itself
sqlite3Version="$(npm view . optionalDependencies.sqlite3)" && \
\
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 \
python \
make \
gcc \
g++ \
libc-dev && \
\
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* ;
# ----------------------------------------------
# 7) LAYER final
# ----------------------------------------------
FROM ghost-base AS ghost-final
COPY --from=ghost-builder --chown=node:node "${GHOST_INSTALL}" "${GHOST_INSTALL}"
ENTRYPOINT [ "/sbin/tini", "--", "docker-entrypoint.sh" ]
CMD [ "node", "current/index.js" ]