Skip to content

Commit

Permalink
no gosu
Browse files Browse the repository at this point in the history
  • Loading branch information
ngeorger committed Jul 25, 2023
1 parent c8650bf commit e6b7efe
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 116 deletions.
9 changes: 2 additions & 7 deletions .github/workflows/build-custom-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,7 @@ on:
jobs:
docker:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
platform:
- linux/amd64
- linux/arm64

steps:
-
name: Checkout
Expand Down Expand Up @@ -91,7 +86,7 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
platforms: ${{ matrix.platform }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down
138 changes: 33 additions & 105 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,130 +1,58 @@
# 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:18-bookworm

# grab gosu for easy step-down from root
# https://github.com/tianon/gosu/releases
ENV GOSU_VERSION 1.16
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 upgrade -y; \
apt-get install -y --no-install-recommends ca-certificates 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; \
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; \
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
FROM node:18-bookworm-slim

ENV NODE_ENV production

ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y --no-install-recommends g++ make python3 libvips-dev nano && apt-get clean && rm -rf /var/lib/apt/lists/*



# ENV GHOST_CLI_VERSION 1.24.1
RUN set -eux; \
npm install -g "ghost-cli@latest"; \
npm cache clean --force
RUN npm install -g "ghost-cli@latest" && npm cache clean --force

ENV GHOST_INSTALL /var/lib/ghost
ENV GHOST_CONTENT /var/lib/ghost/content

ARG GHOST_VERSION
ARG GHOST_VERSION=5.55.1
ENV GHOST_VERSION $GHOST_VERSION

RUN set -eux; \
mkdir -p "$GHOST_INSTALL"; \
chown node:node "$GHOST_INSTALL"; \
\
savedAptMark="$(apt-mark showmanual)"; \
aptPurge=; \
\
installCmd='gosu node ghost install "$GHOST_VERSION" --db mysql --dbhost mysql --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"'; \
if ! eval "$installCmd"; then \
aptPurge=1; \
apt-get update && apt-get upgrade -y; \
apt-get install -y --no-install-recommends g++ make python3; \
eval "$installCmd"; \
fi; \
\
# Tell Ghost to listen on all ips and not prompt for additional configuration
cd "$GHOST_INSTALL"; \
gosu node ghost config --no-prompt --ip '::' --port 2368 --url 'http://localhost:2368'; \
gosu node ghost config paths.contentPath "$GHOST_CONTENT"; \
\
RUN mkdir -pv "$GHOST_INSTALL" && \
chown node:node -Rf "$GHOST_INSTALL"

USER node
WORKDIR $GHOST_INSTALL

RUN ghost install "$GHOST_VERSION" --db mysql --dbhost mysql --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" && ghost config --no-prompt --ip '::' --port 2368 --url 'http://localhost:2368' && \
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"; \
\
RUN 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"; \
\
USER root
RUN mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig" && \
mkdir -pv "$GHOST_CONTENT" && \
chown node:node "$GHOST_CONTENT" && \
chmod 1777 "$GHOST_CONTENT" && \
# force install a few extra packages manually since they're "optional" dependencies
# (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 versions directly from Ghost/dependencies
packages="$(node -p ' \
var ghost = require("./package.json"); \
var transform = require("./node_modules/@tryghost/image-transform/package.json"); \
[ \
"sharp@" + transform.optionalDependencies["sharp"], \
"sqlite3@" + ghost.optionalDependencies["sqlite3"], \
].join(" ") \
')"; \
if echo "$packages" | grep 'undefined'; then exit 1; fi; \
for package in $packages; do \
installCmd='gosu node yarn add "$package" --force'; \
if ! eval "$installCmd"; 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
aptPurge=1; \
apt-get update && apt-get upgrade -y; \
apt-get install -y --no-install-recommends g++ make python3; \
case "$package" in \
# TODO sharp@*) apt-get install -y --no-install-recommends libvips-dev ;; \
sharp@*) apt-get install -y --no-install-recommends libvips-dev ;; \
# sharp@*) echo >&2 "sorry: libvips 8.10 in Debian bullseye is not new enough (8.12.2+) for sharp 0.30 😞"; continue ;; \
esac; \
\
eval "$installCmd --build-from-source"; \
fi; \
done; \
\
if [ -n "$aptPurge" ]; then \
apt-mark showmanual | xargs apt-mark auto > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
apt-get purge -y --auto-remove; \
rm -rf /var/lib/apt/lists/*; \
fi; \
\
gosu node yarn cache clean; \
gosu node npm cache clean --force; \
npm cache clean --force; \
cd "$GHOST_INSTALL/current" && \
yarn cache clean && \
npm cache clean --force && \
rm -rv /tmp/yarn* /tmp/v8*

COPY --chmod=0777 docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh && apt-get autoclean && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
USER node
WORKDIR $GHOST_INSTALL
VOLUME $GHOST_CONTENT

COPY --chmod=0777 docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENV PATH $PATH:/usr/local/bin:$GHOST_INSTALL/current/node_modules/.bin
ENTRYPOINT ["docker-entrypoint.sh"]

Expand Down
132 changes: 132 additions & 0 deletions Dockerfile.orig
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# 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:18-bookworm

# grab gosu for easy step-down from root
# https://github.com/tianon/gosu/releases
ENV GOSU_VERSION 1.16
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 upgrade -y; \
apt-get install -y --no-install-recommends ca-certificates 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; \
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; \
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.24.1
RUN set -eux; \
npm install -g "ghost-cli@latest"; \
npm cache clean --force

ENV GHOST_INSTALL /var/lib/ghost
ENV GHOST_CONTENT /var/lib/ghost/content

ARG GHOST_VERSION
ENV GHOST_VERSION $GHOST_VERSION

RUN set -eux; \
mkdir -p "$GHOST_INSTALL"; \
chown node:node "$GHOST_INSTALL"; \
\
savedAptMark="$(apt-mark showmanual)"; \
aptPurge=; \
\
installCmd='gosu node ghost install "$GHOST_VERSION" --db mysql --dbhost mysql --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"'; \
if ! eval "$installCmd"; then \
aptPurge=1; \
apt-get update && apt-get upgrade -y; \
apt-get install -y --no-install-recommends g++ make python3; \
eval "$installCmd"; \
fi; \
\
# Tell Ghost to listen on all ips and not prompt for additional configuration
cd "$GHOST_INSTALL"; \
gosu node ghost config --no-prompt --ip '::' --port 2368 --url 'http://localhost:2368'; \
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 a few extra packages manually since they're "optional" dependencies
# (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 versions directly from Ghost/dependencies
packages="$(node -p ' \
var ghost = require("./package.json"); \
var transform = require("./node_modules/@tryghost/image-transform/package.json"); \
[ \
"sharp@" + transform.optionalDependencies["sharp"], \
"sqlite3@" + ghost.optionalDependencies["sqlite3"], \
].join(" ") \
')"; \
if echo "$packages" | grep 'undefined'; then exit 1; fi; \
for package in $packages; do \
installCmd='gosu node yarn add "$package" --force'; \
if ! eval "$installCmd"; 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
aptPurge=1; \
apt-get update && apt-get upgrade -y; \
apt-get install -y --no-install-recommends g++ make python3; \
case "$package" in \
# TODO sharp@*) apt-get install -y --no-install-recommends libvips-dev ;; \
sharp@*) apt-get install -y --no-install-recommends libvips-dev ;; \
# sharp@*) echo >&2 "sorry: libvips 8.10 in Debian bullseye is not new enough (8.12.2+) for sharp 0.30 😞"; continue ;; \
esac; \
\
eval "$installCmd --build-from-source"; \
fi; \
done; \
\
if [ -n "$aptPurge" ]; then \
apt-mark showmanual | xargs apt-mark auto > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
apt-get purge -y --auto-remove; \
rm -rf /var/lib/apt/lists/*; \
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 --chmod=0777 docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENV PATH $PATH:/usr/local/bin:$GHOST_INSTALL/current/node_modules/.bin
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 2368
CMD ["node", "current/index.js"]
2 changes: 1 addition & 1 deletion charts/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.1.1
version: 1.1.2
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
Expand Down
1 change: 1 addition & 0 deletions charts/templates/05-ghost-statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ spec:
value: {{ quote .Values.kubernetesClusterDomain }}
image: {{ .Values.ghostOnKubernetes.ghostOnKubernetes.image.repository }}:{{ .Values.ghostOnKubernetes.ghostOnKubernetes.image.tag }}
name: {{ include "ghost-on-kubernetes.fullname" . }}-ghost
imagePullPolicy: {{ .Values.ghostOnKubernetes.ghostOnKubernetes.image.pullPolicy }}
ports:
- containerPort: {{ .Values.ghostConfigProd.port }}
name: http
Expand Down
1 change: 1 addition & 0 deletions charts/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ ghostOnKubernetes:
image:
repository: ghcr.io/sredevopsdev/ghost-on-kubernetes
tag: main
imagePullPolicy: Always
replicas: 1


Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ version: "3"
services:
ghost:
image: ghcr.io/sredevopsdev/ghost-on-kubernetes:main
command: ["gosu", "node", "node", "current/index.js"]
command: ["node", "current/index.js"]
platform: linux/amd64
container_name: ghost
volumes:
- ./content:/var/lib/ghost/content
- ./ghost-local.db:/var/lib/ghost/content/data/ghost-local.db
- ./ghost-local2.db:/var/lib/ghost/content/data/ghost-local.db
environment:
NODE_ENV: development
database__client: sqlite3
Expand Down
2 changes: 1 addition & 1 deletion docker-entrypoint.sh
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ 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" "$@"
exec "$BASH_SOURCE" "$@"
fi

if [[ "$*" == node*current/index.js* ]]; then
Expand Down
22 changes: 22 additions & 0 deletions docker-entrypoint.sh.bak
Original file line number Diff line number Diff line change
@@ -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 "$@"

0 comments on commit e6b7efe

Please sign in to comment.