-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
david.fischak@eodc.eu
committed
Feb 27, 2025
1 parent
454cb6e
commit cc6a138
Showing
24 changed files
with
3,366 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Ubuntu 18.04.1 LTS Bionic | ||
ARG BASE_CONTAINER=quay.io/jupyter/scipy-notebook:2025-02-24 | ||
FROM $BASE_CONTAINER | ||
|
||
ENV PATH=$PATH:$CONDA_DIR/bin | ||
|
||
# Add debugger support | ||
RUN pip install --upgrade ipykernel | ||
|
||
RUN conda install --quiet --yes \ | ||
cffi \ | ||
future \ | ||
pycryptodomex && \ | ||
conda clean --all && \ | ||
fix-permissions $CONDA_DIR && \ | ||
fix-permissions /home/$NB_USER | ||
|
||
ADD jupyter_enterprise_gateway_kernel_image_files*.tar.gz /usr/local/bin/ | ||
|
||
USER root | ||
|
||
RUN apt-get update && apt-get install -yq --no-install-recommends \ | ||
libkrb5-dev \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
|
||
RUN chown jovyan:users /usr/local/bin/bootstrap-kernel.sh && \ | ||
chmod 0755 /usr/local/bin/bootstrap-kernel.sh && \ | ||
chown -R jovyan:users /usr/local/bin/kernel-launchers | ||
|
||
USER jovyan | ||
|
||
ENV KERNEL_LANGUAGE python | ||
|
||
# Disble healthcheck inherited from notebook image | ||
HEALTHCHECK NONE | ||
|
||
CMD /usr/local/bin/bootstrap-kernel.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
#!/bin/bash | ||
|
||
PORT_RANGE=${PORT_RANGE:-${EG_PORT_RANGE:-0..0}} | ||
RESPONSE_ADDRESS=${RESPONSE_ADDRESS:-${EG_RESPONSE_ADDRESS}} | ||
PUBLIC_KEY=${PUBLIC_KEY:-${EG_PUBLIC_KEY}} | ||
KERNEL_LAUNCHERS_DIR=${KERNEL_LAUNCHERS_DIR:-/usr/local/bin/kernel-launchers} | ||
KERNEL_SPARK_CONTEXT_INIT_MODE=${KERNEL_SPARK_CONTEXT_INIT_MODE:-none} | ||
KERNEL_CLASS_NAME=${KERNEL_CLASS_NAME} | ||
|
||
echo $0 env: `env` | ||
|
||
launch_python_kernel() { | ||
# Launch the python kernel launcher - which embeds the IPython kernel and listens for interrupts | ||
# and shutdown requests from Enterprise Gateway. | ||
|
||
export JPY_PARENT_PID=$$ # Force reset of parent pid since we're detached | ||
|
||
if [ -z "${KERNEL_CLASS_NAME}" ] | ||
then | ||
kernel_class_option="" | ||
else | ||
kernel_class_option="--kernel-class-name ${KERNEL_CLASS_NAME}" | ||
fi | ||
|
||
set -x | ||
python ${KERNEL_LAUNCHERS_DIR}/python/scripts/launch_ipykernel.py --kernel-id ${KERNEL_ID} \ | ||
--port-range ${PORT_RANGE} --response-address ${RESPONSE_ADDRESS} --public-key ${PUBLIC_KEY} \ | ||
--spark-context-initialization-mode ${KERNEL_SPARK_CONTEXT_INIT_MODE} ${kernel_class_option} | ||
{ set +x; } 2>/dev/null | ||
} | ||
|
||
launch_R_kernel() { | ||
# Launch the R kernel launcher - which embeds the IRkernel kernel and listens for interrupts | ||
# and shutdown requests from Enterprise Gateway. | ||
|
||
set -x | ||
Rscript ${KERNEL_LAUNCHERS_DIR}/R/scripts/launch_IRkernel.R --kernel-id ${KERNEL_ID} --port-range ${PORT_RANGE} \ | ||
--response-address ${RESPONSE_ADDRESS} --public-key ${PUBLIC_KEY} \ | ||
--spark-context-initialization-mode ${KERNEL_SPARK_CONTEXT_INIT_MODE} | ||
{ set +x; } 2>/dev/null | ||
} | ||
|
||
launch_julia_kernel() { | ||
# Launch the Julia kernel launcher - which embeds the IJulia kernel and listens for interrupts | ||
# and shutdown requests from Enterprise Gateway. | ||
|
||
set -x | ||
export JULIA_NUM_THREADS=$(( ($(nproc) - 2) > 0 ? $(nproc) - 2 : 1 )) # Use all but 2 cores for Julia | ||
|
||
julia --debug-info=1 --optimize=1 \ | ||
${KERNEL_LAUNCHERS_DIR}/julia/scripts/launch_ijuliakernel.jl \ | ||
--kernel-id ${KERNEL_ID} --port-range ${PORT_RANGE} \ | ||
--response-address ${RESPONSE_ADDRESS} --public-key ${PUBLIC_KEY} | ||
|
||
{ set +x; } 2>/dev/null | ||
} | ||
|
||
launch_scala_kernel() { | ||
# Launch the scala kernel launcher - which embeds the Apache Toree kernel and listens for interrupts | ||
# and shutdown requests from Enterprise Gateway. This kernel is currenly always launched using | ||
# spark-submit, so additional setup is required. | ||
|
||
PROG_HOME=${KERNEL_LAUNCHERS_DIR}/scala | ||
KERNEL_ASSEMBLY=`(cd "${PROG_HOME}/lib"; ls -1 toree-assembly-*.jar;)` | ||
TOREE_ASSEMBLY="${PROG_HOME}/lib/${KERNEL_ASSEMBLY}" | ||
if [ ! -f ${TOREE_ASSEMBLY} ]; then | ||
echo "Toree assembly '${PROG_HOME}/lib/toree-assembly-*.jar' is missing. Exiting..." | ||
exit 1 | ||
fi | ||
|
||
# Toree launcher jar path, plus required lib jars (toree-assembly) | ||
JARS="${TOREE_ASSEMBLY}" | ||
# Toree launcher app path | ||
LAUNCHER_JAR=`(cd "${PROG_HOME}/lib"; ls -1 toree-launcher*.jar;)` | ||
LAUNCHER_APP="${PROG_HOME}/lib/${LAUNCHER_JAR}" | ||
if [ ! -f ${LAUNCHER_APP} ]; then | ||
echo "Scala launcher jar '${PROG_HOME}/lib/toree-launcher*.jar' is missing. Exiting..." | ||
exit 1 | ||
fi | ||
|
||
SPARK_OPTS="--name ${KERNEL_USERNAME}-${KERNEL_ID}" | ||
TOREE_OPTS="--alternate-sigint USR2" | ||
|
||
set -x | ||
eval exec \ | ||
"${SPARK_HOME}/bin/spark-submit" \ | ||
"${SPARK_OPTS}" \ | ||
--jars "${JARS}" \ | ||
--class launcher.ToreeLauncher \ | ||
"${LAUNCHER_APP}" \ | ||
"${TOREE_OPTS}" \ | ||
"--kernel-id ${KERNEL_ID} --port-range ${PORT_RANGE} --response-address ${RESPONSE_ADDRESS} --public-key ${PUBLIC_KEY} --spark-context-initialization-mode ${KERNEL_SPARK_CONTEXT_INIT_MODE}" | ||
{ set +x; } 2>/dev/null | ||
} | ||
|
||
# Ensure that required envs are present, check language before the dynamic values | ||
if [ -z "${KERNEL_LANGUAGE+x}" ] | ||
then | ||
echo "KERNEL_LANGUAGE is required. Set this value in the image or when starting container." | ||
exit 1 | ||
fi | ||
if [ -z "${KERNEL_ID+x}" ] || [ -z "${RESPONSE_ADDRESS+x}" ] || [ -z "${PUBLIC_KEY+x}" ] | ||
then | ||
echo "Environment variables, KERNEL_ID, RESPONSE_ADDRESS, and PUBLIC_KEY are required." | ||
exit 1 | ||
fi | ||
|
||
# Invoke appropriate launcher based on KERNEL_LANGUAGE (case-insensitive) | ||
|
||
if [[ "${KERNEL_LANGUAGE,,}" == "python" ]] | ||
then | ||
launch_python_kernel | ||
elif [[ "${KERNEL_LANGUAGE,,}" == "julia" ]] | ||
then | ||
launch_julia_kernel | ||
elif [[ "${KERNEL_LANGUAGE,,}" == "scala" ]] | ||
then | ||
launch_scala_kernel | ||
elif [[ "${KERNEL_LANGUAGE,,}" == "r" ]] | ||
then | ||
launch_R_kernel | ||
else | ||
echo "Unrecognized value for KERNEL_LANGUAGE: '${KERNEL_LANGUAGE}'!" | ||
exit 1 | ||
fi | ||
exit 0 |
92 changes: 92 additions & 0 deletions
92
kernel-python/container/kernel-launchers/python/scripts/kernel-pod.yaml.j2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# This file defines the Kubernetes objects necessary for kernels to run witihin Kubernetes. | ||
# Substitution parameters are processed by the launch_kubernetes.py code located in the | ||
# same directory. Some values are factory values, while others (typically prefixed with 'kernel_') can be | ||
# provided by the client. | ||
# | ||
# This file can be customized as needed. No changes are required to launch_kubernetes.py provided kernel_ | ||
# values are used - which be automatically set from corresponding KERNEL_ env values. Updates will be required | ||
# to launch_kubernetes.py if new document sections (i.e., new k8s 'kind' objects) are introduced. | ||
# | ||
apiVersion: v1 | ||
kind: Pod | ||
metadata: | ||
name: "{{ kernel_pod_name }}" | ||
namespace: "{{ kernel_namespace }}" | ||
labels: | ||
kernel_id: "{{ kernel_id }}" | ||
app: enterprise-gateway | ||
component: kernel | ||
source: kernel-pod.yaml | ||
annotations: | ||
cluster-autoscaler.kubernetes.io/safe-to-evict: "false" | ||
spec: | ||
restartPolicy: Never | ||
serviceAccountName: "{{ kernel_service_account_name }}" | ||
# NOTE: that using runAsGroup requires that feature-gate RunAsGroup be enabled. | ||
# WARNING: Only using runAsUser w/o runAsGroup or NOT enabling the RunAsGroup feature-gate | ||
# will result in the new kernel pod's effective group of 0 (root)! although the user will | ||
# correspond to the runAsUser value. As a result, BOTH should be uncommented AND the feature-gate | ||
# should be enabled to ensure expected behavior. In addition, 'fsGroup: 100' is recommended so | ||
# that /home/jovyan can be written to via the 'users' group (gid: 100) irrespective of the | ||
# "kernel_uid" and "kernel_gid" values. | ||
{% if kernel_uid is defined or kernel_gid is defined %} | ||
securityContext: | ||
{% if kernel_uid is defined %} | ||
runAsUser: {{ kernel_uid | int }} | ||
{% endif %} | ||
{% if kernel_gid is defined %} | ||
runAsGroup: {{ kernel_gid | int }} | ||
{% endif %} | ||
fsGroup: 100 | ||
{% endif %} | ||
containers: | ||
- image: "{{ kernel_image }}" | ||
name: "{{ kernel_pod_name }}" | ||
env: | ||
# Add any custom envs here that aren't already configured for the kernel's environment | ||
# - name: MY_CUSTOM_ENV | ||
# value: "my_custom_value" | ||
{% if kernel_cpus is defined or kernel_memory is defined or kernel_gpus is defined or kernel_cpus_limit is defined or kernel_memory_limit is defined or kernel_gpus_limit is defined %} | ||
resources: | ||
{% if kernel_cpus is defined or kernel_memory is defined or kernel_gpus is defined %} | ||
requests: | ||
{% if kernel_cpus is defined %} | ||
cpu: "{{ kernel_cpus }}" | ||
{% endif %} | ||
{% if kernel_memory is defined %} | ||
memory: "{{ kernel_memory }}" | ||
{% endif %} | ||
{% if kernel_gpus is defined %} | ||
nvidia.com/gpu: "{{ kernel_gpus }}" | ||
{% endif %} | ||
{% endif %} | ||
{% if kernel_cpus_limit is defined or kernel_memory_limit is defined or kernel_gpus_limit is defined %} | ||
limits: | ||
{% if kernel_cpus_limit is defined %} | ||
cpu: "{{ kernel_cpus_limit }}" | ||
{% endif %} | ||
{% if kernel_memory_limit is defined %} | ||
memory: "{{ kernel_memory_limit }}" | ||
{% endif %} | ||
{% if kernel_gpus_limit is defined %} | ||
nvidia.com/gpu: "{{ kernel_gpus_limit }}" | ||
{% endif %} | ||
{% endif %} | ||
{% endif %} | ||
{% if kernel_working_dir %} | ||
workingDir: "{{ kernel_working_dir }}" | ||
{% endif %} | ||
volumeMounts: | ||
# Define any "unconditional" mounts here, followed by "conditional" mounts that vary per client | ||
{% if kernel_volume_mounts %} | ||
{% for volume_mount in kernel_volume_mounts %} | ||
- {{ volume_mount }} | ||
{% endfor %} | ||
{% endif %} | ||
volumes: | ||
# Define any "unconditional" volumes here, followed by "conditional" volumes that vary per client | ||
{% if kernel_volumes %} | ||
{% for volume in kernel_volumes %} | ||
- {{ volume }} | ||
{% endfor %} | ||
{% endif %} |
Oops, something went wrong.