Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GemStone 64 3.6.6 docker images #1

Merged
merged 14 commits into from
Jul 31, 2023
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data/*
locks/*
logs/*
conf/*
projects/*
25 changes: 25 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,28 @@

**Unofficial** docker images for GemStone/S 64 bits server and gem sessions.
This is a community project not endorsed by [GemTalk](https://gemtalksystems.com).

## Configuration

You can configure some things with environment variables:

- `NETLDI_SERVICE_NAME` Netldi service name. Defaults to `gs64ldi`
- `NETLDI_PORT` NetLDI service port. Defaults to `50384`
- `STONE_SERVICE_NAME` Stone service name. Defaults to `gs64stone`
- `STONE_PORT` Stone service port. Defaults to `50385`
- `GEMSTONE_NRS_ALL` Defaults to `#netldi:gs64ldi#dir:/opt/gemstone/logs/#log:/opt/gemstone/logs/%N_%P.log`
- `GS_FORCE_CLEAN_LOG_FILE_DELETE` Defaults to `true`
- `DATA_CURATOR_PASSWORD` Password of the `DataCurator` user, used for stopping
the services. Defaults to `swordfish`.
- `STOPSTONE_TIMEOUT_SECONDS` time-out in seconds to wait for `stopstone`
command to finish.
gcotelli marked this conversation as resolved.
Show resolved Hide resolved

## Important directories and files

- `/opt/gemstone/conf/${STONE_SERVICE_NAME}.conf` Stone configuration, created if missing.
gcotelli marked this conversation as resolved.
Show resolved Hide resolved
- `/opt/gemstone/conf/system.conf` GemStone system configuration, created if missing.
- `/opt/gemstone/data` Extent and transaction log location
- `/opt/gemstone/locks` Lock files
- `/opt/gemstone/logs` Log files
- `/opt/gemstone/product/sys/gemstone.key` License key, by default `community.starter.key`
is used.
5 changes: 5 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
conf/*
data/*
logs/*
locks/*
projects/*
20 changes: 20 additions & 0 deletions examples/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: "3"

services:
stone:
init: true
network_mode: host
build:
context: ../source
target: docker-gs64-rowan-loader
args:
GS_VERSION: 3.6.6
environment:
TZ: America/Argentina/Buenos_Aires
volumes:
- ./conf/:/opt/gemstone/conf/
- ./locks/:/opt/gemstone/locks/
- ./logs/:/opt/gemstone/logs/
- ./projects/:/opt/gemstone/projects/
- ~/.ssh/:/home/gemstone/.ssh/:ro

146 changes: 146 additions & 0 deletions source/Dockerfile
ytsejam78 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Runs on a multi-stage build: https://docs.docker.com/develop/develop-images/multistage-build/
# - Prepare a base image with all dependencies installed
# - Download and prepare environment
# - Copy prepared environment onto the final image

FROM debian:12-slim AS base

ENV SHELL=/bin/bash
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8

ENV GS_USER=gemstone
ENV GS_UID=1001
ENV GS_GID=100

RUN apt-get update \
&& apt-get install --assume-yes --no-install-recommends \
ca-certificates \
gosu \
locales \
&& echo "en_US.UTF-8 UTF-8" > /etc/locale.gen \
&& echo "en_US.ISO-8859-15 ISO-8859-15" >> /etc/locale.gen \
&& locale-gen \
&& apt-get clean \
&& rm --recursive --force /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& useradd --uid ${GS_UID} --gid ${GS_GID} --no-create-home --no-user-group ${GS_USER} \
;

## Donwload GemStone 64 bits release
FROM alpine:3.18 as download

ARG GS_VERSION
ENV GEMSTONE_GLOBAL_DIR=/opt/gemstone
ENV GEMSTONE=${GEMSTONE_GLOBAL_DIR}/product
ENV DOWNLOAD_LOCATION=/tmp

# Download official release
RUN wget https://downloads.gemtalksystems.com/pub/GemStone64/${GS_VERSION}/GemStone64Bit${GS_VERSION}-x86_64.Linux.zip \
-O ${DOWNLOAD_LOCATION}/GemStone.zip

#Extract it
RUN mkdir - ${GEMSTONE_GLOBAL_DIR} \
&& unzip -qq ${DOWNLOAD_LOCATION}/GemStone.zip -d ${DOWNLOAD_LOCATION} \
&& mv ${DOWNLOAD_LOCATION}/GemStone64Bit${GS_VERSION}-x86_64.Linux ${GEMSTONE}

# Create required directories
RUN mkdir -p \
${GEMSTONE_GLOBAL_DIR}/conf/ \
${GEMSTONE_GLOBAL_DIR}/data/ \
${GEMSTONE_GLOBAL_DIR}/locks/ \
${GEMSTONE_GLOBAL_DIR}/logs/ \
;

# Remove non-essential files to keep the final image size small
RUN rm -rf \
${GEMSTONE}/bin32/ \
${GEMSTONE}/examples/ \
${GEMSTONE}/include/ \
${GEMSTONE}/install/ \
${GEMSTONE}/lib32/ \
${GEMSTONE}/rowan/ \
${GEMSTONE}/seaside/ \
${GEMSTONE}/upgrade/ \
${GEMSTONE}/bin/vsd* \
${GEMSTONE}/lib/tcl* \
${GEMSTONE}/lib/tk* \
${GEMSTONE}/lib/Tix* \
${GEMSTONE}/lib/pkgconfig/tcl* \
${GEMSTONE}/lib/pkgconfig/tk* \
${GEMSTONE}/lib/rbc* \
${GEMSTONE}/doc/man1/vsd.1 \
&& mv ${GEMSTONE}/bin/extent0*.dbf ${DOWNLOAD_LOCATION} \
;

# Replace `data` location in the default system.conf
RUN sed -ri 's|\$GEMSTONE/data|\$GEMSTONE_GLOBAL_DIR/data|g' ${GEMSTONE}/data/system.conf

# Copy startup scripts
COPY start-gemstone.sh ${GEMSTONE_GLOBAL_DIR}/start-gemstone.sh
COPY entrypoint.sh ${GEMSTONE_GLOBAL_DIR}/entrypoint.sh

## Prepare server image
FROM base as docker-gs64-server
LABEL maintainer="Buenos Aires Smalltalk <[email protected]>"

ENV GEMSTONE_GLOBAL_DIR=/opt/gemstone
ENV GEMSTONE=${GEMSTONE_GLOBAL_DIR}/product
ENV GEMSTONE_EXE_CONF=${GEMSTONE_GLOBAL_DIR}/conf
ENV GEMSTONE_SYS_CONF=${GEMSTONE_GLOBAL_DIR}/conf
ENV GEMSTONE_LOG_DIR=${GEMSTONE_GLOBAL_DIR}/logs

ENV PATH=$GEMSTONE/bin:$PATH
# Used to determine what shell to use for an exec, such as by System class>>performOnServer:.
ENV SHELL=/usr/bin/bash

ENV NETLDI_SERVICE_NAME=gs64ldi
ENV NETLDI_PORT=50384
ENV STONE_SERVICE_NAME=gs64stone
ENV STONE_PORT=50385

ENV DATA_CURATOR_PASSWORD=swordfish
# By default `docker stop` will wait 10 seconds for the container to handle
# SIGTERM signals, after the grace period docker will send a SIGKILL.
# By default we wait 8 seconds to allow a clean shutdown of the Stone.
# If your installation needs a greater timeout change the docker wait time
# and this timet-out in consequence
ENV STOPSTONE_TIMEOUT_SECONDS=8

ENV GS_FORCE_CLEAN_LOG_FILE_DELETE=true
ENV GEMSTONE_NRS_ALL=#netldi:$NETLDI_SERVICE_NAME#dir:$GEMSTONE_LOG_DIR/#log:$GEMSTONE_LOG_DIR/%N_%P.log

COPY --from=download --chown=${GS_USER}:users ${GEMSTONE_GLOBAL_DIR} ${GEMSTONE_GLOBAL_DIR}
RUN ln -s ${GEMSTONE}/bin/gemsetup.sh /etc/profile.d/gemstone.sh


WORKDIR ${GEMSTONE_GLOBAL_DIR}
VOLUME ${GEMSTONE_GLOBAL_DIR}/data/
CMD ["./entrypoint.sh"]

## Prepare server base image
FROM docker-gs64-server as docker-gs64-base

COPY --from=download --chown=${GS_USER}:users /tmp/extent0.dbf ${GEMSTONE_GLOBAL_DIR}/data/extent0.dbf
CMD ["./entrypoint.sh"]

## Prepare server rowan image
FROM docker-gs64-server as docker-gs64-rowan

ENV ROWAN_PROJECTS_HOME=${GEMSTONE_GLOBAL_DIR}/projects

RUN mkdir ${ROWAN_PROJECTS_HOME}
COPY --from=download --chown=${GS_USER}:users /tmp/extent0.rowan.dbf ${GEMSTONE_GLOBAL_DIR}/data/extent0.dbf
CMD ["./entrypoint.sh"]

## Prepare server rowan loader image
FROM docker-gs64-rowan as docker-gs64-rowan-loader

# Install git
RUN apt-get update \
&& apt-get install --assume-yes --no-install-recommends git \
&& apt-get clean \
&& rm --recursive --force /var/lib/apt/lists/* /tmp/* /var/tmp/* \
;

CMD ["./entrypoint.sh"]
36 changes: 36 additions & 0 deletions source/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash

set -eu

echo "${NETLDI_SERVICE_NAME} ${NETLDI_PORT}/tcp # GemStone - Netldi" >> /etc/services
echo "${STONE_SERVICE_NAME} ${STONE_PORT}/tcp # GemStone - Stone" >> /etc/services

# Copy default system config if missing
if [ ! -f "${GEMSTONE_SYS_CONF}/system.conf" ]; then
cp -p "${GEMSTONE}/data/system.conf" "${GEMSTONE_SYS_CONF}/system.conf"
fi

# Create (empty) stone config if missing
if [ ! -f "${GEMSTONE_EXE_CONF}/${STONE_SERVICE_NAME}.conf" ]; then
touch "${GEMSTONE_EXE_CONF}/${STONE_SERVICE_NAME}.conf"
fi

# Ensure write permissions
NEED_WRITE_PERMISSION=(
"${GEMSTONE_SYS_CONF}/system.conf"
"${GEMSTONE_EXE_CONF}/${STONE_SERVICE_NAME}.conf"
"${GEMSTONE_GLOBAL_DIR}/data/"
"${GEMSTONE_GLOBAL_DIR}/data/extent0.dbf"
"${GEMSTONE_GLOBAL_DIR}/locks/"
"${GEMSTONE_LOG_DIR}/"
)

for path in "${NEED_WRITE_PERMISSION[@]}"; do
if ! gosu "${GS_USER}" test -w "$path"; then
chown "${GS_UID}:${GS_GID}" "$path"
chmod ug+w "$path"
fi
done

# Run gemstone as GS_USER
exec gosu "${GS_USER}" "${GEMSTONE_GLOBAL_DIR}/start-gemstone.sh"
50 changes: 50 additions & 0 deletions source/start-gemstone.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# based on https://medium.com/@gchudnov/trapping-signals-in-docker-containers-7a57fdda7d86
# see also https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example
set -eu

# SIGTERM-handler
sigterm_handler() {
echo 'Got SIGTERM, stopping GemStone/S 64 server'
stopnetldi
stopstone \
-i \
-t "${STOPSTONE_TIMEOUT_SECONDS}" \
"$STONE_SERVICE_NAME" \
DataCurator \
"${DATA_CURATOR_PASSWORD}"
exit 143; # 128 + 15 -- SIGTERM
}

# setup handlers
# on callback, kill the last background process,
# which is `tail -f /dev/null` and execute the specified handler
trap 'kill ${!}; sigterm_handler' SIGTERM

# start GemStone services
# shellcheck disable=SC2086
startnetldi \
-g \
-a "${GS_USER}" \
-n \
-P "${NETLDI_PORT}" \
-l "${GEMSTONE_LOG_DIR}/${NETLDI_SERVICE_NAME}.log" \
${NETLDI_ARGS:-} \
"${NETLDI_SERVICE_NAME}"

# shellcheck disable=SC2086
startstone \
-e "${GEMSTONE_EXE_CONF}" \
-z "${GEMSTONE_SYS_CONF}" \
-l "${GEMSTONE_LOG_DIR}/${STONE_SERVICE_NAME}.log" \
${STONE_ARGS:-} \
${STONE_SERVICE_NAME}

# list GemStone servers
gslist -cvl

# wait forever, (loop to handle multiple signals if needed)
while true
do
tail -f /dev/null & wait ${!}
done