Skip to content

Commit

Permalink
Added dockerization for the Trino Gateway
Browse files Browse the repository at this point in the history
Adding documentation, image creation, and compose file modifications
required for running the Trino Gateway in a docker container.
  • Loading branch information
rdsarvar committed Jan 26, 2024
1 parent 3614810 commit 1c08e1b
Show file tree
Hide file tree
Showing 12 changed files with 614 additions and 0 deletions.
1 change: 1 addition & 0 deletions .java-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
17.0.9
57 changes: 57 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# syntax=docker/dockerfile:1

FROM registry.access.redhat.com/ubi9/ubi-minimal:latest AS jdk-download
ARG JDK_DOWNLOAD_LINK
ARG JDK_VERSION
ENV JAVA_HOME="/usr/lib/jvm/jdk-${JDK_VERSION}"

RUN \
set -xeuo pipefail && \
microdnf install -y tar gzip && \
# Install JDK from the provided archive link \
echo "Downloading JDK from ${JDK_DOWNLOAD_LINK}" && \
mkdir -p "${JAVA_HOME}" && \
curl -#LfS "${JDK_DOWNLOAD_LINK}" | tar -zx --strip 1 -C "${JAVA_HOME}"

# Use ubi9 minimal as it's more secure
FROM registry.access.redhat.com/ubi9/ubi-minimal:latest
WORKDIR /opt/trino

ARG JDK_VERSION
ENV JAVA_HOME="/usr/lib/jvm/jdk-${JDK_VERSION}"
ENV PATH=$PATH:$JAVA_HOME/bin
COPY --from=jdk-download $JAVA_HOME $JAVA_HOME

RUN \
set -xeu && \
microdnf update -y && \
microdnf install -y tar less shadow-utils && \
groupadd trino --gid 1000 && \
useradd trino --uid 1000 --gid 1000 --create-home && \
mkdir -p /usr/lib/trino && \
chown -R "trino:trino" /usr/lib/trino /opt/trino

COPY --chown=trino:trino gateway-ha /usr/lib/trino

ARG TRINO_GATEWAY_VERSION
ENV GATEWAY_JAR_PATH "/usr/lib/trino/gateway-ha-${TRINO_GATEWAY_VERSION}-jar-with-dependencies.jar"

EXPOSE 8080
USER trino:trino
CMD java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED -jar "${GATEWAY_JAR_PATH}" "server" "/opt/trino/gateway-ha-config.yml"

HEALTHCHECK --interval=10s --timeout=5s --start-period=10s \
CMD /usr/lib/trino/bin/health-check
85 changes: 85 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Trino Gateway Docker Image

## About the Container

This Docker image is designed to:

* be spun up in front of Trino clusters by mounting in a configuration file
* simplify deployment into an orchestration system

## Quickstart

### Dependencies

This docker build process requires:

* [Docker Compose V2](https://docs.docker.com/compose/)
* jq

### Run the Trino Gateway server

You can launch the Trino Gateway and relevant dependencies through docker for testing purposes.

```bash
# Replace these variables to match your test requirements
# Ex: You may be locally building the docker image so something like
# `trino-gateway:5-SNAPSHOT-amd64` might be what you're expecting
TEST_GATEWAY_IMAGE="trinodb/trino-gateway:latest"
TEST_PLATFORM="amd64"

TRINO_GATEWAY_IMAGE=${TEST_GATEWAY_IMAGE} DOCKER_DEFAULT_PLATFORM=${TEST_PLATFORM} \
docker compose -f minimal-compose.yml \
up --wait
```

This will wait until docker has spun up the services and the gateway is healthy.
If the service doesn't come up successfully you can attempt to debug it by pulling the logs:
```
docker compose -f minimal-compose.yml logs gateway
```

The Trino Gateway server is now running on `localhost:8080` (the default port).

### Verify it Runs

Now that the gateway is up and running, here's a sample query that shows the backends configured:
```bash
curl localhost:8080/api/public/backends
```

Or, visit it in your browser by opening http://localhost:8080

## Configuration

Configuration is expected to be mounted to the exact path of `/opt/trino/gateway-ha-config.yml`.
If it is not mounted then the gateway will fail to initialize.

## Health Checking

By default the container health checking is done by the [/usr/lib/trino/bin/health-check](./bin/health-check)
script which simply expects a 2XX response from the server at `/api/public/backends`.

## Building a custom Docker image

To build an image for a locally modified version of Trino Gateway, run the Maven
build as normal for the `gateway-ha` modules, then build the image:

```bash
./build.sh
```

The Docker build process will print the ID of the image, which will also
be tagged with `trino-gateway:xxx-SNAPSHOT-yyy`, where `xxx-SNAPSHOT` is the version
number of the Trino Maven build and `-yyy` is the platform the image was built for.

To build an image for a specific released version of Trino Gateway,
specify the `-r` option, and the build script will download
all the required artifacts:

```bash
./build.sh -r 4
```

## Getting Help

Join the Trino community [Slack](https://trino.io/slack.html).
75 changes: 75 additions & 0 deletions docker/bin/health-check
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash

set -euo pipefail

function get_2nd_level_yaml_key() {
local parent_key=$1
local target_key=$2
local yaml_file_path=$3

# In order to get the nested key we will leverage awk to do some parsing
awk -v parent_key=${parent_key} \
-v target_key=${target_key} \
'
function count_indentation(line) {
match(line, /^[[:space:]]*/);
return RLENGTH;
}
# First we search for the parent_key, once we find it we set in_block to true
match($0, "^" parent_key ":") {
in_block=1;
parent_indent_level = count_indentation($0);
next;
} \
in_block {
# All lines we deem to be a comment will be skipped.
if (match($0, "^[[:space:]]*#")) { next; }
# If we determine that we have left the parent_key block we will exit.
if ($0 ~ /^[^\t #]/) { exit; }
current_indent_level = count_indentation($0);
# Next, because we dont know the indentation levels being provided, we will attempt
# to find the indentation level of the 2nd level keys.
if ( !first_level_indentation \
&& match($0, "^[[:space:]]+.*:") \
&& current_indent_level > parent_indent_level) {
first_level_indentation = current_indent_level;
}
# Then we will attempt to find the 2nd level target key based on:
# 1. Theres only spaces before the target_key
# 2. The indentation level is equal to the found 2nd level indentation
if (match($0, "^[[:space:]]+" target_key ":") \
&& current_indent_level == first_level_indentation) {
# If we decide that the key matches our expectations, we will print the matched value
sub(/:/, "", $2);
print $2;
}
}
' \
${yaml_file_path}
}

config=/opt/trino/gateway-ha-config.yml
scheme=http
port=8080

# prefer to use http even if https is enabled
if [ "$(get_2nd_level_yaml_key 'requestRouter' 'ssl' "$config")" == "true" ]; then
scheme=https
fi

potential_port=$(get_2nd_level_yaml_key 'requestRouter' 'port' "$config")
if [ "${potential_port}" != "" ]; then
port=${potential_port}
fi

endpoint="${scheme}://localhost:${port}/api/public/backends"

# add --insecure to disable certificate verification in curl, in case a self-signed certificate is being used
if ! info=$(curl --fail --silent --show-error --insecure "$endpoint"); then
echo >&2 "Server is not responding to requests"
exit 1
fi
143 changes: 143 additions & 0 deletions docker/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/usr/bin/env bash

set -xeuo pipefail

usage() {
cat <<EOF 1>&2
Usage: $0 [-h] [-a <ARCHITECTURES>] [-r <VERSION>]
Builds the Trino Gateway Docker image
-h Display help
-a Build the specified comma-separated architectures, defaults to amd64,arm64,ppc64le
-r Build the specified Trino Gateway release version, downloads all required artifacts
-j Build the Trino Gateway release with specified Temurin JDK release
EOF
}

# Retrieve the script directory.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
cd "${SCRIPT_DIR}" || exit 2

SOURCE_DIR="${SCRIPT_DIR}/.."

ARCHITECTURES=(amd64 arm64 ppc64le)
TRINO_GATEWAY_VERSION=
JDK_VERSION=$(cat "${SOURCE_DIR}/.java-version")

while getopts ":a:h:r:j:" o; do
case "${o}" in
a)
IFS=, read -ra ARCHITECTURES <<< "$OPTARG"
;;
r)
TRINO_GATEWAY_VERSION=${OPTARG}
;;
h)
usage
exit 0
;;
j)
JDK_VERSION="${OPTARG}"
;;
*)
usage
exit 1
;;
esac
done
shift $((OPTIND - 1))

function check_environment() {
if ! command -v jq &> /dev/null; then
echo >&2 "Please install jq"
exit 1
fi
if ! $(docker compose version &> /dev/null); then
echo >&2 "Please install Docker Compose V2"
exit 1
fi
}

function temurin_jdk_link() {
JDK_VERSION="${1}"
ARCH="${2}"

versionsUrl="https://api.adoptium.net/v3/info/release_names?heap_size=normal&image_type=jdk&os=linux&page=0&page_size=20&project=jdk&release_type=ga&semver=false&sort_method=DEFAULT&sort_order=ASC&vendor=eclipse&version=%28${JDK_VERSION}%2C%5D"
if ! result=$(curl -fLs "$versionsUrl" -H 'accept: application/json'); then
echo >&2 "Failed to fetch release names for JDK version [${JDK_VERSION}, ) from Temurin API : $result"
exit 1
fi

if ! RELEASE_NAME=$(echo "$result" | jq -er '.releases[]' | grep "${JDK_VERSION}" | head -n 1); then
echo >&2 "Failed to determine release name: ${RELEASE_NAME}"
exit 1
fi

case "${ARCH}" in
arm64)
echo "https://api.adoptium.net/v3/binary/version/${RELEASE_NAME}/linux/aarch64/jdk/hotspot/normal/eclipse?project=jdk"
;;
amd64)
echo "https://api.adoptium.net/v3/binary/version/${RELEASE_NAME}/linux/x64/jdk/hotspot/normal/eclipse?project=jdk"
;;
ppc64le)
echo "https://api.adoptium.net/v3/binary/version/${RELEASE_NAME}/linux/ppc64le/jdk/hotspot/normal/eclipse?project=jdk"
;;
*)
echo "${ARCH} is not supported for Docker image"
exit 1
;;
esac
}

check_environment

if [ -n "$TRINO_GATEWAY_VERSION" ]; then
echo "🎣 Downloading gateway server artifact for release version ${TRINO_GATEWAY_VERSION}"
"${SOURCE_DIR}/mvnw" -C dependency:get -Dtransitive=false -Dartifact="io.trino.gateway:gateway-ha:${TRINO_GATEWAY_VERSION}:jar:jar-with-dependencies"
local_repo=$("${SOURCE_DIR}/mvnw" -B help:evaluate -Dexpression=settings.localRepository -q -DforceStdout)
trino_gateway_ha="$local_repo/io/trino/gateway/gateway-ha/${TRINO_GATEWAY_VERSION}/gateway-ha-${TRINO_GATEWAY_VERSION}-jar-with-dependencies.jar"
chmod +x "$trino_gateway_ha"
else
TRINO_GATEWAY_VERSION=$("${SOURCE_DIR}/mvnw" -f "${SOURCE_DIR}/pom.xml" --quiet help:evaluate -Dexpression=project.version -DforceStdout)
echo "🎯 Using currently built artifacts from the gateway-ha module and version ${TRINO_GATEWAY_VERSION}"
trino_gateway_ha="${SOURCE_DIR}/gateway-ha/target/gateway-ha-${TRINO_GATEWAY_VERSION}-jar-with-dependencies.jar"
fi

echo "🧱 Preparing the image build context directory"
WORK_DIR="$(mktemp -d)"
GATEWAY_WORK_DIR="${WORK_DIR}/gateway-ha"
mkdir "${GATEWAY_WORK_DIR}"
cp "$trino_gateway_ha" "${GATEWAY_WORK_DIR}"
cp -R bin "${GATEWAY_WORK_DIR}"
cp "${SCRIPT_DIR}/Dockerfile" "${WORK_DIR}"

TAG_PREFIX="trino-gateway:${TRINO_GATEWAY_VERSION}"

for arch in "${ARCHITECTURES[@]}"; do
echo "🫙 Building the image for $arch with JDK ${JDK_VERSION}"
DOCKER_BUILDKIT=1 \
docker build \
"${WORK_DIR}" \
--pull \
--build-arg JDK_VERSION="${JDK_VERSION}" \
--build-arg JDK_DOWNLOAD_LINK="$(temurin_jdk_link "${JDK_VERSION}" "${arch}")" \
--build-arg TRINO_GATEWAY_VERSION="${TRINO_GATEWAY_VERSION}" \
--platform "linux/$arch" \
-f Dockerfile \
-t "${TAG_PREFIX}-$arch"
done

echo "🧹 Cleaning up the build context directory"
rm -r "${WORK_DIR}"

echo "🏃 Testing built images"
source container-test.sh

for arch in "${ARCHITECTURES[@]}"; do
# TODO: remove when https://github.com/multiarch/qemu-user-static/issues/128 is fixed
if [[ "$arch" != "ppc64le" ]]; then
test_container "${TAG_PREFIX}-$arch" "linux/$arch" "${SCRIPT_DIR}/minimal-compose.yml" "gateway" "postgres"
fi
docker image inspect -f '🚀 Built {{.RepoTags}} {{.Id}}' "${TAG_PREFIX}-$arch"
done
Loading

0 comments on commit 1c08e1b

Please sign in to comment.