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

branch: feature 1218 docker image - makes Metacat deployable on Kubernetes, using a Helm Chart #1637

Merged
merged 54 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
8639779
First pass at a Docker build for metacat.
mbjones Mar 2, 2018
12b7e9b
Modified entrypoint to set admin password if missing.
mbjones Mar 2, 2018
e688fb9
Removing unneeded config directory.
mbjones Mar 2, 2018
bad0518
Configure the metacat app with properties from the environment.
mbjones Mar 2, 2018
1bb2309
Clean up debug output.
mbjones Mar 2, 2018
fb5ead6
Switch to useing catalina start, and tail the logs.
mbjones Mar 2, 2018
94fe94a
Enable changing the context via an environemnt variable.
mbjones Mar 3, 2018
4244e07
Add example docker-compose and README explaining it.
mbjones Mar 3, 2018
26ee56b
Add Apache Let's Encrypt container.
mbjones Mar 3, 2018
948e8da
Enable hazelcase access on port 5701.
mbjones Mar 17, 2018
8f9ec2f
First pass at a Docker build for metacat.
mbjones Mar 2, 2018
7148ba8
Modified entrypoint to set admin password if missing.
mbjones Mar 2, 2018
5f04982
Removing unneeded config directory.
mbjones Mar 2, 2018
977e77a
Configure the metacat app with properties from the environment.
mbjones Mar 2, 2018
75ef3dc
Clean up debug output.
mbjones Mar 2, 2018
1eb8deb
Switch to useing catalina start, and tail the logs.
mbjones Mar 2, 2018
ed87a47
Enable changing the context via an environemnt variable.
mbjones Mar 3, 2018
2f6b7fa
Enable hazelcase access on port 5701.
mbjones Mar 17, 2018
479ce1b
removed apache LE proxy and updated metacat version
artntek Jan 25, 2023
436a7d3
only chaged metacat version from 2.12 to 2.18 - no other changes yet
artntek Feb 9, 2023
8c71381
cleanup only. Spacing and cleaning up syntax
artntek Feb 14, 2023
0de16d3
development WIP snapshot: metacat works in container with connections…
artntek Feb 22, 2023
ff96d67
k8s working - WIP checkin
artntek Feb 28, 2023
f7462dd
WIP checkin: add helm chart. Container runs but incomlpete - still ne…
artntek Mar 2, 2023
88be638
WIP checkin: metacat working after helm deployment, with postgres & s…
artntek Mar 2, 2023
5bc6bbc
WIP: using envFrom: configMapRef: to load config in one go
artntek Mar 9, 2023
05852d1
WIP checkin: helm deploy; postgres & solr outside cluster. Eliminated…
artntek Mar 13, 2023
ce3de24
all working, but with a non-DRY copy of metacat.properties in helm/co…
artntek Mar 15, 2023
fbc4eda
update to mc 2.19; add line to dockerfile RUN cmd so apt-get can find…
artntek May 2, 2023
bc0afce
updated to metacat v2.19.0
artntek May 3, 2023
2c25d53
working with helm/config/metacat-site.properties. (Solr error on uplo…
artntek May 4, 2023
ccabe59
WIP - added persistentVolume
artntek May 9, 2023
dc09ac5
change site properties to be a configMap that is used directly by met…
artntek May 17, 2023
9b23222
no longer needed
artntek May 18, 2023
54ede1a
fixed ezid config
artntek May 19, 2023
6a969d9
StatefulSet instead of Deployment, with volumeClaimTemplates
artntek May 31, 2023
f620f6d
added option for emptyDir
artntek Jun 1, 2023
b3e7000
admin helpers for pv and secrets
artntek Jun 2, 2023
cac74f7
run as metacat user instead of root; rename env vars; add storageClas…
artntek Jun 5, 2023
92038c9
using env vars for secrets
artntek Jun 7, 2023
e69b4a8
docker cleanup before PR
artntek Jun 7, 2023
f798e06
cleanup before PR
artntek Jun 7, 2023
d59a6ba
pre-PR cleanup
artntek Jun 7, 2023
e669351
updated readme
artntek Jun 7, 2023
39f0a83
docker cleanup pre-PR
artntek Jun 8, 2023
fd24861
pre-PR cleanup and added README
artntek Jun 8, 2023
6c8e61a
Delete hpa.yaml
artntek Jun 7, 2023
1616562
refining PV settings and trying to get it working out of the box for …
artntek Jun 8, 2023
158afce
got auto-provisioning workign for PV on rancher desktop
artntek Jun 8, 2023
7309d6f
added explanations
artntek Jun 9, 2023
c47bc88
added PV accessModes to values.yaml; add arbitrary number of key: val…
artntek Jun 13, 2023
68fdb69
distinguish between debug mode (devtools) fro container, and debug fo…
artntek Jun 13, 2023
67f90b1
docker build bug fixes & cleanup
artntek Jun 13, 2023
b449b92
change FROM image: tomcat:8.0-jre8->tomcat:8.5.90-jre8-temurin-jammy.…
artntek Jun 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
FROM tomcat:8.5.90-jre8-temurin-jammy
# TODO: update to tomcat:9.0.76-jre8-temurin-jammy

# ARG default values that can be overridden at build-time
ARG TAG=2.19.0
ARG DEVTOOLS=''

# ENV default key=value env vars shared with container at runtime
ENV METACAT_APP_CONTEXT=metacat
ENV TC_HOME=/usr/local/tomcat
ENV USRBINDIR=/usr/local/bin
ENV PATH=${USRBINDIR}:$PATH
ENV DEVTOOLS=${DEVTOOLS}

# ADDITIONAL USER-SPECIFIC ENV VAR CREDENTIALS NEEDED AT RUNTIME BY docker-entrypoint.sh:
#
# METACAT_AUTH_ADMINISTRATORS is a single admin username or LDAP-style Distinguished Name,
# used to log into the metacat admin pages. It is NOT a list of
# users (despite its name), and must not contain any colons (:)
# METACAT_ADMINISTRATOR_PASSWORD is the corresponding aadmin login password


# Add a user with name 'metacat'
RUN useradd metacat

## ADD auto-inflates the .tar.gz
ADD metacat-bin-${TAG}.tar.gz /tmp

RUN apt-get update && apt-get install -y --no-install-recommends netcat python3-bcrypt unzip && \
bash -c "if [[ \"$DEVTOOLS\" == \"true\" ]]; then echo '* * INSECURE! DEV TOOLS BUILD * *' && \
apt-get install -y --no-install-recommends vim procps lsof telnet; fi" && \
rm -rf /var/lib/apt/lists/* && \
cp /tmp/metacat.war /tmp/metacat-index.war /tmp/metacatui.war ${TC_HOME}/webapps && \
chown -R metacat ${TC_HOME}/webapps && \
# Tomcat Mods - TODO MB - remove after Tomcat9 upgrade
cp ${TC_HOME}/conf/server.xml ${TC_HOME}/conf/server.xml.original && \
sed -i 's/port="8080"/relaxedPathChars="\[\]\|" \
relaxedQueryChars="\[\]\|\{\}\^\&\#x5c\;\&\#x60\;\&quot\;\&lt\;\&gt\;\&\#x2a\;\&\#x2c\;" port="8080"/g' \
$TC_HOME/conf/server.xml

COPY --chown=metacat apply_context.py ${USRBINDIR}/
COPY --chown=metacat docker-entrypoint.sh ${USRBINDIR}/

#Run Container as 'metacat'
USER metacat

EXPOSE 8080
EXPOSE 8009
EXPOSE 8443
EXPOSE 5701

ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]

CMD ["catalina.sh","start"]
27 changes: 27 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Metacat

<img src="https://knb.ecoinformatics.org/knb/docs/_images/metacat-logo-darkgray.png"
alt="metacat" height="75" width="65"/>

This is a [Docker](https://www.docker.com/) image for configuring and running
Metacat in a lightweight container. Metacat requires access to an existing
postgres database, and an existing solr instance, both of which are configured to be
accessed by Metacat. It also assumes that secure https access to the metacat instance is
handled via an external proxy server.

# How to build the Metacat image

Building an image can be accomplished by first building the
metacat distribution associated with a given version, and then
building the docker image based on that. Starting in the root directory of the "metacat" repo:

$ ant distbin
...
... a very long build process ensues, resulting in a tar.gz file
$ cd docker
$ ./build 2.19.0
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
metacat 2.19.0 8da92210dfc4 39 minutes ago 1.27GB

The image can then be deployed in a Kubernetes environment - see the helm chart at `metacat/helm/`
64 changes: 64 additions & 0 deletions docker/apply_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
from __future__ import absolute_import, division, print_function
'''
File name: apply_context.py
Description: Change the default context in the metacat web.xml file
Author: Valerie Hendrix <[email protected]>
Date created: 11/28/2017
Python Version: 2.7
'''
import xml.etree.ElementTree as ET

import sys

# The namespace
javaee = {'javaee': 'http://java.sun.com/xml/ns/javaee'}


if __name__ == "__main__":

# Check for args
if len(sys.argv) < 4:
print("Usage: {} web_xml_file old_context new_context".format(sys.argv[0]),file=sys.stderr)
sys.exit(-1)

web_xml_file = sys.argv[1]
old_context = sys.argv[2]
new_context = sys.argv[3]

# No prefixes for the namespace
ET.register_namespace("","http://java.sun.com/xml/ns/javaee")
tree = ET.parse(web_xml_file)
root = tree.getroot()

# Iterate over the servlet-mappings and change the url pattern to the
# new application context
mappings = root.findall("./javaee:servlet-mapping", javaee)
for mapping in mappings:

servlet_name = mapping.find("javaee:servlet-name", javaee)
url_pattern = mapping.find("javaee:url-pattern",javaee)
if servlet_name is not None and servlet_name.text == "metacat":
url_pattern.text = str(url_pattern.text.replace(old_context, new_context))

# Overwrite the web xml file
tree.write(web_xml_file)

# Update the metacat.properties.path in the metaca-index application
metacat_index_web_xml = "/usr/local/tomcat/webapps/metacat-index/WEB-INF/web.xml"
tree = ET.parse(metacat_index_web_xml)
root = tree.getroot()

# Iterate over the servlet-mappings and change the url pattern to the
# new application context
mappings = root.findall("./context-param", javaee)
for mapping in mappings:

param_name = mapping.find("param-name", javaee)
param_value = mapping.find("param-value", javaee)
if param_name is not None and param_name.text == "metacat.properties.path":
param_value.text = str(param_value.text.replace("/{}/WEB-INF".format(old_context), "/{}/WEB-INF".format(new_context)))
break

# Overwrite the web xml file
tree.write(metacat_index_web_xml)
41 changes: 41 additions & 0 deletions docker/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash

set -e
TAG=$1
DEFAULT_TAG="2.19.0"

if [ -z "$1" ] || [[ "$1" == "-devtools" ]]; then
TAG=${DEFAULT_TAG}
echo
echo "Usage: ${0} [tag] [-devtools]"
echo " or: ${0} [-devtools] (omitting tag defaults it to ${DEFAULT_TAG})"
echo
echo "where: tag is typically set to the metacat version #. Setting to default: ${TAG}"
echo " -devtools is FOR DEV/DEBUGGING ONLY - NOT FOR PRODUCTION USE! Installs dev tools:"
echo " vim, procps, lsof, and telnet in the container (see Dockerfile for"
echo " complete list), thus REDUCING ITS SECURITY!"
echo
fi

DEVTOOLS="false"
DEVBUILDOPTS=""
if [[ "$1" == "-devtools" ]] || [[ "$2" == "-devtools" ]]; then
DEVTOOLS="true"
DEVBUILDOPTS="--no-cache --progress=plain"
fi
echo "Building with \"DEVTOOLS\" set to: ${DEVTOOLS}"
echo

RELEASE="metacat-bin-${TAG}.tar.gz"

# Grab the Metacat release
if [ ! -f "../${RELEASE}" ]; then
echo "Could not find ../${RELEASE}"
echo "You must first build the metacat release with 'ant distbin'. Exiting..."
exit 1
fi

cp ../"${RELEASE}" .

docker image build \
$DEVBUILDOPTS --tag metacat:"$TAG" --build-arg TAG="$TAG" --build-arg DEVTOOLS="$DEVTOOLS" .
168 changes: 168 additions & 0 deletions docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/usr/bin/env bash
set -e

if [ "$1" = 'catalina.sh' ]; then

if [ -z "$METACAT_AUTH_ADMINISTRATORS" ] ||
[ $(echo "$METACAT_AUTH_ADMINISTRATORS" | grep -c ":") -ne 0 ]; then
echo "ERROR: The admin user ($METACAT_AUTH_ADMINISTRATORS) environment variable was either"
echo " not set, or it included a colon (:). It should contain a single username or"
echo " LDAP-style Distinguished Name, not a colon-delimited list of administrators"
echo " (despite its name indicating otherwise - sorry! :-)"
exit 2
else
METACAT_ADMINISTRATOR_USERNAME="$METACAT_AUTH_ADMINISTRATORS"
fi

# Expand the metacat-index.war
if [ ! -d webapps/metacat-index ]; then
unzip webapps/metacat-index.war -d webapps/metacat-index
fi

# set the env vars. Note that TC_HOME and METACAT_APP_CONTEXT are set in Dockerfile
METACAT_DEFAULT_WAR=${TC_HOME}/webapps/metacat.war
METACAT_DIR=${TC_HOME}/webapps/${METACAT_APP_CONTEXT}
METACAT_WAR=${METACAT_DIR}.war

# Check the context
if [ "${METACAT_WAR}" != "${METACAT_DEFAULT_WAR}" ] && [ -f "$METACAT_DEFAULT_WAR" ]; then
# Move the application to match the context
echo "Changing metacat context to ${METACAT_APP_CONTEXT}"
mv "$METACAT_DEFAULT_WAR" "$METACAT_WAR"
else
echo "Installing metacat to context ${METACAT_APP_CONTEXT}"
fi

# Expand the WAR file
if [ ! -d "$METACAT_DIR" ]; then
unzip "$METACAT_WAR" -d "$METACAT_DIR"
fi

# change the context in the web.xml file
apply_context.py "$METACAT_DIR"/WEB-INF/web.xml metacat "${METACAT_APP_CONTEXT}"

# Show KNB skin if nothing else configured.
# TODO: deploy metacatui separately, or make this work with props config later
mkdir "${TC_HOME}"/webapps/config
{
echo "MetacatUI.AppConfig = {"
echo " theme: \"knb\","
echo " root: \"/metacatui\","
echo " metacatContext: \"/${METACAT_APP_CONTEXT}\","
echo " baseUrl: \"http://localhost:8080\""
echo "}"
} > "${TC_HOME}"/webapps/config/config.js


# Make sure all default directories are available
mkdir -p /var/metacat/data \
/var/metacat/inline-data \
/var/metacat/documents \
/var/metacat/temporary \
/var/metacat/logs \
/var/metacat/config \
/var/metacat/.metacat

# if METACAT_DEBUG, set the root log level accordingly
if [[ "$METACAT_DEBUG" == "true" ]]; then
sed -i 's/rootLogger\.level[^\n]*/rootLogger\.level=DEBUG/g' \
"${TC_HOME}"/webapps/metacat/WEB-INF/classes/log4j2.properties;
echo "* * * * * * set Log4J rootLogger level to DEBUG * * * * * *"
fi

# TODO: need a more-elegant way to handle this, without manipulating files
# If env has an admin/password set, but it does not exist in the passwords file, then add it
if [ -n "$METACAT_ADMINISTRATOR_USERNAME" ]; then
USER_PWFILE="/var/metacat/users/password.xml"

if [ -z "$METACAT_ADMINISTRATOR_PASSWORD" ]; then
echo "ERROR: The admin user (METACAT_ADMINISTRATOR_USERNAME) environment variable was"
echo " set, but no password value was set."
echo " You may use the METACAT_ADMINISTRATOR_PASSWORD environment variable to"
echo " set the administrator password"
exit 2
fi
# look for the user password file, as it is expected if the configuration is completed
if [ ! -s "$USER_PWFILE" ] ||
[ $(grep -c "$METACAT_ADMINISTRATOR_USERNAME" "$USER_PWFILE") -eq 0 ]; then
# Note: the Java bcrypt library only supports '2a' format hashes, so override the
# default python behavior so that the hashes created start with '2a' rather than '2y'
cd "${METACAT_DIR}"/WEB-INF/scripts/bash
PASS=$(python3 -c "import bcrypt;print bcrypt.hashpw('$METACAT_ADMINISTRATOR_PASSWORD',\
bcrypt.gensalt(10,prefix='2a'))")
bash ./authFileManager.sh useradd -h "$PASS" -dn "$METACAT_ADMINISTRATOR_USERNAME"
cd "$TC_HOME"
echo
echo '*************************************'
echo 'Added administrator to passwords file'
echo '*************************************'
fi
fi

# Start tomcat
"$@" > /dev/null 2>&1

# Give time for tomcat to start
echo
echo '**************************************'
echo "Waiting for Tomcat to start before"
echo "checking upgrade/initialization status"
echo '**************************************'
while ! nc -z localhost 8080; do
echo -n "."
sleep 1
done
echo

#
# TODO: Replace DB config check with internal metacat check for an "autoconfig" flag at startup
#
# Login to Metacat Admin and start a session (cookie.txt)
echo "doing curl -X POST to localhost admin page"
if [[ "$METACAT_DEBUG" == "true" ]]; then
echo "using password=${METACAT_ADMINISTRATOR_PASSWORD}\
& username=${METACAT_ADMINISTRATOR_USERNAME}"
fi
curl -X POST --data "loginAction=Login&configureType=login&processForm=true&password=\
${METACAT_ADMINISTRATOR_PASSWORD}&username=${METACAT_ADMINISTRATOR_USERNAME}" \
--cookie-jar ./cookie.txt http://localhost:8080/"${METACAT_APP_CONTEXT}"/admin >\
/tmp/login_result.txt 2>&1
echo
echo '**************************************'
echo "admin login result from /tmp/login_result.txt:"
# following lines use "|| true" because grep exits script (-1) if no matches found
grep 'You must log in' /tmp/login_result.txt || true
grep 'You are logged in' /tmp/login_result.txt || true
echo '**************************************'
echo
echo '**************************************'
echo "Checking if Database is configured..."

## If the DB needs to be updated run the migration scripts
DB_CONFIGURED=$(grep -c "configureType=database" /tmp/login_result.txt || true)
if [ "$DB_CONFIGURED" -ne 0 ]; then
echo "Database needs configuring..."
# Run the database initialization to create or upgrade tables
# /${METACAT_APP_CONTEXT}/admin?configureType=database must have an
# authenticated session, then run:
curl -X POST --cookie ./cookie.txt \
--data "configureType=database&processForm=true" \
http://localhost:8080/"${METACAT_APP_CONTEXT}"/admin > /dev/null 2>&1

# Validate the database should be configured
curl -X POST --cookie ./cookie.txt \
--data "configureType=configure&processForm=false" \
http://localhost:8080/"${METACAT_APP_CONTEXT}"/admin > /dev/null 2>&1
else
echo "Database is already configured"
fi
echo '**************************************'
fi

if [[ "$DEVTOOLS" == "true" ]]; then
echo "Container dev tools mode -- starting infinite loop -- ctrl-c to interrupt..."
sh -c 'trap "exit" TERM; while true; do sleep 1; done'
else
echo "tailing logs in: $TC_HOME/logs/*"
exec tail -f "$TC_HOME"/logs/*
fi
5 changes: 5 additions & 0 deletions docker/tomcat_DEBUG/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# INSECURE - DO NOT USE IN PRODUCTION!

These files are for development debugging purposes only.

Each file contains instructions/explanation in comments
6 changes: 6 additions & 0 deletions docker/tomcat_DEBUG/metacat.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- this file goes in $TOMCAT_HOME/conf/Catalina/localhost/
and allows tomcat to follow symlinks in the webapps/metacat context -->
<Context>
<Resources allowLinking="true" />
</Context>
6 changes: 6 additions & 0 deletions docker/tomcat_DEBUG/metacatui.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- this file goes in $TOMCAT_HOME/conf/Catalina/localhost/
and allows tomcat to follow symlinks in the webapps/metacatui context -->
<Context>
<Resources allowLinking="true" />
</Context>
3 changes: 3 additions & 0 deletions docker/tomcat_DEBUG/setenv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# this file goes in $TOMCAT_HOME/bin/ and tells tomcat to allow remote
# debugging connections to the port listed as "address="
export CATALINA_OPTS="$CATALINA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
Loading