This repo contains a Dockerfile, docker-compose.yml
, and various other files for creating a docker container of LabKey products. Please review this document and especially the "Tips" section below.
This repo is a work in progress. Containers created from these sources are untested. Until further work is done, integrations with LabKey products that traditionally have relied on OS configuration such as R reports or Python scripts will NOT work.
March 2024 saw many changes in an effort to bring this repo in line with LabKey server versioning/releases, starting with v24.3, in which the embedded tomcat version has been upgraded from 9 to 10.
v24.3 also removes the version number from the .jar extracted from the build archive, so it is now simply labkeyServer.jar
.
Using a pre-24.3 version of the .jar with a post-24.3 version of this repo will fail spectacularly.
To fully use this repo, you will need installed:
- Docker >= v20.10.24 recommended
- GNU Make
- GNU Awk
Optionally, to publish containers to AWS's ECR service using this repo's Makefile
, you will need:
- AWS CLI
You will also need the .jar
file of an embedded LabKey distribution.
A COPY
instruction in the Dockerfile expects this .jar
file's filename to look like: "labkeyServer.jar", and for it to be in the root of this repo.
Set the LABKEY_VERSION
environment variable to the version number from the installation archive filename (eg '24.3.4' from 'LabKey24.3.4-6-community-embedded.tar.gz').
You can obtain this file by following these steps:
-
Visit the LabKey Server Community Edition downloads page and fill in the required fields
-
Download the "Embedded Tomcat Beta Installer"
.tar.gz
file -
Extract the
.jar
into the root of the repo:tar -xzf [path/to/.tar.gz] --include='LabKey*labkeyServer*.jar' --strip-components 1 -C [path/to/repo/]
-
brew install docker jq awscli
-
Clone the repo to a local directory on a machine with docker installed
git clone https://github.com/LabKey/Dockerfile.git
-
Copy in the labkey community embedded
.jar
file to the same directory as the repo (see above on how to obtain) -
Export the minimal required environment variables or edit and source the quickstart_envs.sh
export LABKEY_VERSION="24.3.4"
...or
source ./quickstart_envs.sh
-
Run the Make Build command to create the container
make build
-
Run the Make Up command to start the container using the makefile docker-compose settings
make up
-
After a few minutes LabKey should be available by opening a browser window and connecting to https://localhost:8443
-
enable Chrome to accept self-signed certificates, such as the one generated within
entrypoint.sh
, by enabling this Chrome flag:chrome://flags/#allow-insecure-localhost
-
Explore
This repo includes a Makefile
which aims to ease the running of the necessary commands for creating containers. The default action of the Makefile
is to log into the AWS ECR service, build, tag, and push a docker container (the all:
target) to an ECR repo named after the chosen distribution.
Building a container is as simple as make build
:
$make build
docker build \
--rm \
--compress \
--no-cache \
-t labkey/community:24.3.4 \
-t labkey/community:latest \
--build-arg 'DEBUG=' \
--build-arg 'LABKEY_VERSION=24.3.4' \
--build-arg 'LABKEY_DISTRIBUTION=community'
--build-arg 'LABKEY_EK=123abc456' \
.
Sending build context to Docker daemon 756.1MB
...
Step 27/27 : ENTRYPOINT /entrypoint.sh
---> Running in db19946ff9de
Removing intermediate container db19946ff9de
---> 6c15d5de57a6
Successfully built 6c15d5de57a6
Successfully tagged labkey/community:24.3.4
Successfully tagged labkey/community:latest
This repo and Dockerfile have been built from the ground up to support LabKey products that include Spring Boot/Embedded Tomcat which can be configured using application.properties
files. This change was made to simplify the installation of LabKey by reducing the dependencies required to get LabKey products off the ground. And to increase the configurability of LabKey products running within containers.
Environment variables (ENVs) are used to control both halves of the lifecycle of the container: "build time" (when the container is built) and "run time" (when the container is being used after having been built). As such, the list of Docker "build args" is pretty short; being limited to just the base container to use w/ FROM
, the distribution/version of LabKey, and DEBUG
. Environment variables are instead used by scripts within the Dockerfile
itself, and from within the entrypoint.sh
script (which ultimately executes java -jar
). The container will fail to start if any required LABKEY_*
environment variables are not supplied as in the following:
labkey | value required for 'LABKEY_SYSTEM_DESCRIPTION'
dockerfile_labkey_1 exited with code 1
These crucial ENVs can be broken up into a couple categories relating to their function and/or relevance to LabKey or Docker, build time or run time.
Setting DEBUG
to any value will suffice: docker build ... --build-arg DEBUG=1
or make DEBUG=1 build
.
name | purpose | default |
---|---|---|
DEBUG | whether or not to print extra information during build & run time | <empty> |
The Dockerfile
currently supports 2 base-container operating systems, Alpine Linux and Debian-based Linux, both of which originate from eclipse-temurin
. Debian-based Linux deployments are much more thoroughly tested. Toggling between the two or overriding them can be achieved by changing the FROM_TAG
Docker build arg. The Dockerfile
provides 2 examples:
- debian-based
- FROM_TAG=17-jre
- alpine-based
- FROM_TAG=17-jre-alpine
name | purpose | default |
---|---|---|
FROM_REPO_IMAGE | Docker repository & image to use as basis of container | eclipse-temurin |
FROM_TAG | repository tag to use as basis of container | 17-jre |
LABKEY_HOME | The Docker WORKDIR and top level under which all LabKey-related files are nested | /labkey |
BUILD_REMOTE_TAG | allows for alternate remote tags during make tag and make push |
[BUILD_REPO_URI]/labkey/community:[LABKEY_VERSION] |
Several ENVs and 'up' commands were added to faciliate running different distribution containers on the same system (though not simultaneously)
name | purpose | default |
---|---|---|
COMPOSE_IMAGE | 'image:' for docker-compose service | labkey/community |
IDENT | isolate postgres data directory from other containers (.pgdata/[IDENT]-data) | postgres |
These can be leveraged with commands such as:
- COMPOSE_IMAGE=labkey/lims_starter IDENT=lims_starter LABKEY_DISTRIBUTION=lims_starter make up-lims_starter
- COMPOSE_IMAGE=labkey/enterprise IDENT=enterprise LABKEY_DISTRIBUTION=enterprise make up-enterprise
Non-Docker LabKey server installations prior to 24.3 kept configuration details in a range of XML files (eg server.xml
, ROOT.xml
, labkey.xml
), ENVs consumed by java (JAVA_OPTS
), ENVs consumed directly by LabKey, and ENVs consumed by tomcat (setenv.sh
, CATALINA_OPTS
). The goal here is to expose them all as ENVs configurable via Docker at both build time and run time. If you are migrating to this Docker setup from a standard server installation, you may need to first gather your configuration details. See this upgrade document for more details, but note that it is intended for server-to-server migrations, not server-to-Docker.
A better description of the LabKey settings can be found in the LabKey docs here.
LABKEY_GUID
is only relevant if you are attempting to created/run a container destined to connect to a pre-existing database belonging to a pre-existing LabKey.
name | purpose | default |
---|---|---|
LABKEY_BASE_SERVER_URL | full URI LabKey will use to refer to itself | https://localhost:8443 |
LABKEY_COMPANY_NAME | name of your organization; appears in emails | Sirius Cybernetics |
LABKEY_DEFAULT_DOMAIN | (DNS) domain where the LabKey server resides | localhost |
LABKEY_DISTRIBUTION | "flavor" of labkey; | community |
LABKEY_FILES_ROOT | path within which will serve as the root of the "files" directory | /labkey/files |
LABKEY_GUID | LabKey server GUID | <empty> |
LABKEY_EK | LabKey encryption key | 123abc456 |
LABKEY_PORT | port to which labkey will bind within the container | 8443 |
LABKEY_SYSTEM_DESCRIPTION | brief description of server; appears in emails | Sirius Cybernetics |
LABKEY_SYSTEM_EMAIL_ADDRESS | email address system email will be sent "from" | do_not_reply@localhost |
LABKEY_SYSTEM_SHORT_NAME | name of server displayed in header | Sirius Cybernetics |
You can optionally bypass the initial user creation "wizard" by creating an initial user using the following environment variables. At time of writing, there is no way to set the initial user's password. Assuming valid SMTP configuration, the "forgot password" link can be used to accomplish this. Additionally, an API can be created for that user. If both LABKEY_CREATE_INITIAL_USER
& LABKEY_CREATE_INITIAL_USER_APIKEY
are set to a values other than empty strings, but LABKEY_INITIAL_USER_APIKEY
is not set, a randomly generated string will be used. Setting LABKEY_CREATE_INITIAL_USER_APIKEY
without having set LABKEY_CREATE_INITIAL_USER
will result in NO initial user being added.
Creating an initial user API key in this way will cause that API key to be output from the container in cleartext.
Initial user/API key creation is a powerful feature that can be a security concern. If you're using this feature, care should be taken when considering where the container's output (and thus the cleartext API key) is directed.
Initial user API key creation was implemented in LabKey Server 20.11.
name | purpose | default |
---|---|---|
LABKEY_CREATE_INITIAL_USER | set to a non-empty string to trigger initial user creation/bypass initial user wizard UI | <empty> |
LABKEY_INITIAL_USER_EMAIL | email to be used for initial user | "toor@localhost" |
LABKEY_INITIAL_USER_ROLE | role to be used for initial user | "SiteAdminRole" |
LABKEY_INITIAL_USER_GROUP | group to be used for initial user | "Administrators" |
LABKEY_CREATE_INITIAL_USER_APIKEY | set to a non-empty string to also create an API key for the initial user | <empty> |
LABKEY_INITIAL_USER_APIKEY | value to be used as the API key for the initial user, generated if missing | <empty> |
The POSTGRES_*
default values are meant to match those of the library/postgres containers.
name | purpose | default |
---|---|---|
POSTGRES_DB | "name" of database; compounds to URI connection string | postgres |
POSTGRES_HOST | (DNS) hostname of database ""; compounds to URI connection string | localhost |
POSTGRES_PARAMETERS | suffix of database URI; compounds to URI connection string | <empty> |
POSTGRES_PASSWORD | password of database user which container will utilize as main dataSource | <empty> |
POSTGRES_PORT | port of database; compounds to URI connection string | 5432 |
POSTGRES_USER | user of database which container will utilize as main dataSource | postgres |
These replace values previously housed in context.xml
(ROOT.xml
or labkey.xml
) governing mail/Session
resources.
name | purpose | default |
---|---|---|
SMTP_HOST | SMTP host configuration | localhost |
SMTP_PASSWORD | SMTP password configuration | <empty> |
SMTP_PORT | SMTP port configuration | 25 |
SMTP_USER | SMTP user configuration | root |
SMTP_FROM | SMTP from email address | <empty> |
SMTP_AUTH | SMTP Auth flag | false |
SMTP_STARTTLS | SMTP STARTTLS flag | <empty> |
The CERT_*
ENVs should look familiar to anyone that has used the openssl
command to generate a pkcs12 keystore.
name | purpose | default |
---|---|---|
TOMCAT_KEYSTORE_ALIAS | self-signed cert/keystore "alias" | tomcat |
TOMCAT_KEYSTORE_FILENAME | self-signed cert/keystore filename | labkey.p12 |
TOMCAT_KEYSTORE_FORMAT | self-signed cert/keystore format | PKCS12 |
TOMCAT_SSL_CIPHERS | allowable SSL ciphers for use by tomcat | HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA:!EDH:!DHE:!DH:!CAMELLIA:!ARIA:!AESCCM:!SHA:!CHACHA20 |
TOMCAT_SSL_ENABLED_PROTOCOLS | allowable SSL protocols and versions | TLSv1.3,TLSv1.2 |
TOMCAT_SSL_PROTOCOL | basic SSL protocol to use | TLS |
CERT_C | "Country" value for the generated self-signed cert | US |
CERT_CN | "Common Name" value for the generated self-signed cert | localhost |
CERT_L | "Location" value for the generated self-signed cert | Seattle |
CERT_O | "Organization" value for the generated self-signed cert | <empty> |
CERT_OU | "Organization Unit" value for the generated self-signed cert | IT |
CERT_ST | "State" value for the generated self-signed cert | Washington |
Since java can be picky about the position of CLI values, JAVA_PRE_JAR_EXTRA
and JAVA_POST_JAR_EXTRA
are provided to allow for additional CLI values (flags, etc.) to be added to the java -jar
command at the end of entrypoint.sh
. This method is the preferred way of supplying additional flags and options to java over using JAVA_OPTS
name | purpose | default |
---|---|---|
JAVA_TIMEZONE | java configured Timezone | America/Los_Angeles |
JAVA_TMPDIR | java configured "temp" directory | /var/tmp |
MAX_JVM_RAM_PERCENT | jvm maximum memory occupancy | 90.0 |
JAVA_PRE_JAR_EXTRA | additional CLI values to pass to java before -jar |
<empty> |
JAVA_POST_JAR_EXTRA | additional CLI values to pass to java after -jar |
<empty> |
In contrast to application.properties
, the "startup properties" files housed in startup/
, are LabKey's own implementation of .properties
file(s) and generally are less feature rich that Spring Boot's, and are specific to LabKey application settings.
For the datadog agent to collect JMX metrics from inside a container running in ECS, set the JAVA_RMI_SERVER_HOSTNAME
env var. This can be set to 'localhost' in most deployments.
If deploying to ECS with EC2 instances, and using awsvpc
mode (instead of bridge), you will likely also need to set up Discovery Service for the ECS service, and use the resulting URI as both the JAVA_RMI_SERVER_HOSTNAME
env var and as a dockerLabel, for the datadog agent to see and use with AutoDiscovery.
Note: this is fairly specific to LabKey's usage. Your mileage may vary.
Q: Why is my labkey container "unhealthy"?
A: LabKey containers produced from this repo contain a HEALTHCHECK
instruction which defines a simple "smoke" test Docker can use internally to determine if the container is healthy. The healthcheck built into this Dockerfile boils down to a curl
to localhost
-- but it can be customized based on a number of HEALTHCHECK_*
ENVs that the Dockerfile defines. A customization that may be helpful would be to define a HEALTHCHECK_HEADER_NAME
or HEALTHCHECK_HEADER_USER_AGENT
that matches a value already filtered out of the access log by the application. Most container orchestrations tools either explicitely disable containers' built-in HEALTCHECKs or give you the option to disable able it. A succinct example of this is docker-compose
's own healthcheck syntax.
- Sample
application.properties
file - Sample
pg.properties
file -- contains some values referenced in application.properties above - LabKey Bootstrap Properties
- Dockerfile Reference
- Compose file Reference
logback
"pattern" Referencelog4j2
"pattern" Referencelog4j
Migration Reference- How the JVM Finally Plays Nice with Containers