Skip to content

Commit 10e5ead

Browse files
committed
Added multiple docker files for use-cases (prod, dev, etc) along with Makefile. Updated env vars with service specific prefix.
1 parent 7ff89a2 commit 10e5ead

File tree

10 files changed

+186
-125
lines changed

10 files changed

+186
-125
lines changed

README.md

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,41 @@ Full list found in [requirements.txt](./requirements.txt).
3737

3838
## Security
3939

40-
Certificates used are located in the `./security/` folder, taken from the [Cogstack-NiFi](https://github.com/CogStack-NiFi) security folder, [root-ca.key](https://raw.githubusercontent.com/CogStack/CogStack-NiFi/refs/heads/main/security/root-ca.key) and [root-ca.pem](https://raw.githubusercontent.com/CogStack/CogStack-NiFi/refs/heads/main/security/root-capem), read the [security section](https://cogstack-nifi.readthedocs.io/en/latest/security.html) for more info on how to generate them from the main NiFi repository.
40+
Certificates used are located in the `./security/` folder, taken from the [Cogstack-NiFi](https://github.com/CogStack-NiFi) security folder, [nifi.key](https://raw.githubusercontent.com/CogStack/CogStack-NiFi/refs/heads/main/security/certificates/nifi/nifi.key) and [nifi.pem](https://raw.githubusercontent.com/CogStack/CogStack-NiFi/refs/heads/main/security/certificates/nifi/nifi.pem), read the [security section](https://cogstack-nifi.readthedocs.io/en/latest/security.html) for more info on how to generate them from the main NiFi repository.
4141

4242
## Setting up your own hub
4343

44-
There are two docker compose files:
45-
`docker-compose-dev.yml` - this will build the build the hub image from scratch, it will not build the singleuser one however.
46-
`docker-compose.yml` - default, for production.
44+
This folder contains a modular Docker Compose setup for running the CogStack Jupyter Hub across multiple environments.
45+
46+
```bash
47+
docker/
48+
├── docker-compose.base.yml # Canonical base definition
49+
├── docker-compose.yml # Extends the base (always loaded)
50+
├── docker-compose.override.yml # Local overrides (auto-loaded)
51+
├── docker-compose.dev.yml # Dev overrides
52+
├── docker-compose.prod.yml # Prod overrides
53+
├── Makefile # Helper commands (up, down, ps, show-env)
54+
└── export_env_vars.sh # Loads ../env/*.env files
55+
```
56+
57+
### 🧩 Usage
58+
59+
- **Local:** `make up` → uses base + override (bridge network)
60+
- **Dev:** `make up-dev` → uses base + dev overrides
61+
- **Prod:** `make up-prod` → uses base + prod overrides
62+
- **Stop:** `make down`
63+
- **Show envs:** `make show-env`
64+
65+
This structure keeps the base clean while allowing environment-specific overlays.
4766

4867
Check the [env/general.env](./env/general.env), set the `CPU_ARCHITECTURE` variable to whatever you need, the default for most Laptops/PCs is `amd64`, if you have an ARM laptop/device then set to `arm64`, that should suffice.
4968

5069
Execute the following in the main repo directory:
5170

52-
```bash
53-
bash export_env_vars.sh
54-
cd docker
55-
docker compose up -d -f docker-compose.yml cogstack-jupyter-hub
56-
```
71+
```bash
72+
cd docker
73+
make start
74+
```
5775

5876
Updating certificates and env settings from the main repo:
5977
- sometimes it is necessary to grab new certificates if the old ones expired (from the main Cogstack-NiFi repo)
@@ -77,8 +95,8 @@ Pre-requisites (for Linux and Windows): - for Linux, you need to install the nvi
7795

7896
In [env/jupyter.env](./env/jupyter.env):
7997

80-
- change `DOCKER_ENABLE_GPU_SUPPORT` from `false` to `true`.
81-
- change `DOCKER_NOTEBOOK_IMAGE` from `cogstacksystems/jupyter-singleuser:latest` to `cogstacksystems/jupyter-singleuser-gpu:latest`.
98+
- change `JUPYTERHUB_DOCKER_ENABLE_GPU_SUPPORT` from `false` to `true`.
99+
- change `JUPYTERHUB_JUPYTER_HUB_SINGLEUSER_DOCKER_NOTEBOOK_IMAGE` from `cogstacksystems/jupyter-singleuser:latest` to `cogstacksystems/jupyter-singleuser-gpu:latest`.
82100
- in the main repo folder, execute the following command in terminal: `source env/jupyter.env`, then `docker compose up -d`.
83101

84102
*Use any release version you want instead of `latest` as necessary .
@@ -89,12 +107,12 @@ Users can have their resources limited (currently only CPU + RAM), there is a de
89107
Change the coresponding variables in [env/jupyter.env](./env/jupyter.env):
90108

91109
* General user resource cap per container, default 2 cores, 2GB ram:
92-
- `RESOURCE_ALLOCATION_USER_CPU_LIMIT`="2"
93-
- `RESOURCE_ALLOCATION_USER_RAM_LIMIT`="2.0G"
110+
- `JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_USER_CPU_LIMIT`="2"
111+
- `JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_USER_RAM_LIMIT`="2.0G"
94112

95113
* Admin resource cap per container, default 2 cores, 4 GB RAM:
96-
- `RESOURCE_ALLOCATION_ADMIN_CPU_LIMIT`="2"
97-
- `RESOURCE_ALLOCATION_ADMIN_RAM_LIMIT`="4.0G"
114+
- `JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_ADMIN_CPU_LIMIT`="2"
115+
- `JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_ADMIN_RAM_LIMIT`="4.0G"
98116

99117
## Sharing storage between users
100118

@@ -103,4 +121,4 @@ This feature is currently experiemntal, it requires admins to add users to the s
103121

104122
## DEVELOPING
105123

106-
Please make sure to set DOCKER_JUPYTER_HUB_CONTAINER_NAME="cogstack-jupyter-hub-dev" in the `env/jupyter.env` otherwise singleuser containers won't be able to start.
124+
Please make sure to set JUPYTER_HUB_DOCKER_CONTAINER_NAME="cogstack-jupyter-hub-dev" in the `env/jupyter.env` otherwise singleuser containers won't be able to start.

config/jupyterhub_config.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,36 @@ class LocalNativeAuthenticator(NativeAuthenticator, LocalAuthenticator):
1717
pass
1818

1919

20-
DOCKER_NOTEBOOK_IMAGE = os.getenv("DOCKER_NOTEBOOK_IMAGE", "cogstacksystems:jupyterhub/singleuser:latest")
20+
DOCKER_NOTEBOOK_IMAGE = os.getenv("JUPYTER_HUB_SINGLEUSER_DOCKER_NOTEBOOK_IMAGE",
21+
"cogstacksystems:jupyterhub/singleuser:latest")
2122

2223
# JupyterHub requires a single-user instance of the Notebook server, so we
2324
# default to using the `start-singleuser.sh` script included in the
2425
# jupyter/docker-stacks *-notebook images as the Docker run command when
2526
# spawning containers. Optionally, you can override the Docker run command
26-
# using the DOCKER_SPAWN_CMD environment variable.
27-
SPAWN_CMD = os.environ.get("DOCKER_SPAWN_CMD", "start-singleuser.py")
27+
# using the JUPYTER_HUB_DOCKER_SPAWN_CMD environment variable.
28+
SPAWN_CMD = os.environ.get("JUPYTER_HUB_DOCKER_SPAWN_CMD", "start-singleuser.py")
2829

2930
# Connect containers to this Docker network
3031
# IMPORTANT, THIS MUST MATCH THE NETWORK DECLARED in "services.yml", by default: "cogstack-net"
31-
NETWORK_NAME = os.environ.get("DOCKER_NETWORK_NAME", "cogstack-net")
32+
NETWORK_NAME = os.environ.get("JUPYTER_HUB_DOCKER_NETWORK_NAME", "cogstack-net")
3233

3334
# The IP address or hostname of the JupyterHub container in the Docker network
34-
HUB_CONTAINER_IP_OR_NAME = os.environ.get("DOCKER_JUPYTER_HUB_CONTAINER_NAME", "cogstack-jupyter-hub")
35+
HUB_CONTAINER_IP_OR_NAME = os.environ.get("JUPYTER_HUB_DOCKER_CONTAINER_NAME", "cogstack-jupyter-hub")
3536

3637
# The timeout in seconds after which the idle notebook container will be shutdown
3738
NOTEBOOK_IDLE_TIMEOUT = int(os.environ.get("DOCKER_NOTEBOOK_IDLE_TIMEOUT", "7200"))
3839

39-
SELECT_NOTEBOOK_IMAGE_ALLOWED = str(os.environ.get("DOCKER_SELECT_NOTEBOOK_IMAGE_ALLOWED", "false")).lower()
40+
SELECT_NOTEBOOK_IMAGE_ALLOWED = str(os.environ.get("JUPYTERHUB_DOCKER_SELECT_NOTEBOOK_IMAGE_ALLOWED", "false")).lower()
4041

41-
RUN_IN_DEBUG_MODE = str(os.environ.get("DOCKER_NOTEBOOK_DEBUG_MODE", "false")).lower()
42+
RUN_IN_DEBUG_MODE = str(os.environ.get("JUPYTERHUB_DOCKER_NOTEBOOK_DEBUG_MODE", "false")).lower()
4243

4344
# Explicitly set notebook directory because we"ll be mounting a host volume to
4445
# it. Most jupyter/docker-stacks *-notebook images run the Notebook server as
4546
# user `jovyan`, and set the notebook directory to `/home/jovyan/work`.
4647
# We follow the same convention.
47-
NOTEBOOK_DIR = os.environ.get("DOCKER_NOTEBOOK_DIR", "/home/jovyan/work")
48-
SHARED_CONTENT_DIR = os.environ.get("DOCKER_SHARED_DIR", "/home/jovyan/scratch")
48+
NOTEBOOK_DIR = os.environ.get("JUPYTER_HUB_DOCKER_NOTEBOOK_DIR", "/home/jovyan/work")
49+
SHARED_CONTENT_DIR = os.environ.get("JUPYTER_HUB_DOCKER_SHARED_DIR", "/home/jovyan/scratch")
4950
#WORK_DIR = os.environ.get("DOCKER_JUPYTER_WORK_DIR", "/lab/workspaces/auto-b/tree/" + str(NOTEBOOK_DIR.split("/")[-1]))
5051
WORK_DIR = "/lab/"
5152

@@ -127,7 +128,7 @@ def start(self):
127128
}
128129

129130
# this is a temporary fix, need to actually check permissions
130-
self.mem_limit = resource_allocation_user_ram_limit
131+
self.mem_limit = RESOURCE_ALLOCATION_USER_RAM_LIMIT
131132
self.post_start_cmd = "chmod -R 777 " + SHARED_CONTENT_DIR
132133

133134
return super().start()
@@ -190,15 +191,15 @@ def pre_spawn_hook(spawner):
190191

191192
# Resource allocation env vars
192193
# RAM - GB of ram, CPU - num of cores
193-
resource_allocation_user_cpu_limit = os.environ.get("RESOURCE_ALLOCATION_USER_CPU_LIMIT", "2")
194-
resource_allocation_user_ram_limit = os.environ.get("RESOURCE_ALLOCATION_USER_RAM_LIMIT", "2.0G")
195-
resource_allocation_admin_cpu_limit = os.environ.get("RESOURCE_ALLOCATION_ADMIN_CPU_LIMIT", "2")
196-
resource_allocation_admin_ram_limit = os.environ.get("RESOURCE_ALLOCATION_ADMIN_RAM_LIMIT", "4.0G")
194+
RESOURCE_ALLOCATION_USER_CPU_LIMIT = os.environ.get("JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_USER_CPU_LIMIT", "2")
195+
RESOURCE_ALLOCATION_USER_RAM_LIMIT = os.environ.get("JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_USER_RAM_LIMIT", "2.0G")
196+
RESOURCE_ALLOCATION_ADMIN_CPU_LIMIT = os.environ.get("JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_ADMIN_CPU_LIMIT", "2")
197+
RESOURCE_ALLOCATION_ADMIN_RAM_LIMIT = os.environ.get("JUPYTER_HUB_SINGLEUSER_RESOURCE_ALLOCATION_ADMIN_RAM_LIMIT", "4.0G")
197198

198199

199200
def per_user_limit(role):
200-
ram_limits = {"user": (int(resource_allocation_user_cpu_limit), resource_allocation_user_ram_limit),
201-
"admin": (int(resource_allocation_admin_cpu_limit), resource_allocation_admin_ram_limit)}
201+
ram_limits = {"user": (int(RESOURCE_ALLOCATION_USER_CPU_LIMIT), RESOURCE_ALLOCATION_USER_RAM_LIMIT),
202+
"admin": (int(RESOURCE_ALLOCATION_ADMIN_CPU_LIMIT), RESOURCE_ALLOCATION_ADMIN_RAM_LIMIT)}
202203
return ram_limits.get(role)
203204

204205

@@ -256,7 +257,7 @@ def per_user_limit(role):
256257
for member in members:
257258
team_map[member].add(team)
258259

259-
gpu_support_enabled = os.environ.get("DOCKER_ENABLE_GPU_SUPPORT", "false")
260+
gpu_support_enabled = os.environ.get("JUPYTERHUB_DOCKER_ENABLE_GPU_SUPPORT", "false")
260261

261262
if gpu_support_enabled.lower() == "true":
262263
c.DockerSpawner.extra_host_config = {
@@ -301,11 +302,11 @@ def per_user_limit(role):
301302

302303
# TLS config
303304
c.JupyterHub.port = jupyter_hub_ssl_port
304-
c.JupyterHub.ssl_key = os.environ.get("SSL_KEY", "/srv/jupyterhub/security/nifi.key")
305-
c.JupyterHub.ssl_cert = os.environ.get("SSL_CERT", "/srv/jupyterhub/security/nifi.pem")
305+
c.JupyterHub.ssl_key = os.environ.get("JUPYTERHUB_SSL_KEY", "/srv/jupyterhub/security/nifi.key")
306+
c.JupyterHub.ssl_cert = os.environ.get("JUPYTERHUB_SSL_CERT", "/srv/jupyterhub/security/nifi.pem")
306307

307308
# Persist hub data on volume mounted inside container
308-
data_dir = os.environ.get("DATA_VOLUME_CONTAINER", "")
309+
data_dir = os.environ.get("JUPYTERHUB_DATA_VOLUME_CONTAINER", "")
309310

310311
c.JupyterHub.cookie_secret_file = data_dir + "jupyterhub_cookie_secret"
311312

docker/Makefile

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
PROJECT = cogstack-jupyter-hub
2+
CONTAINER_NAME = $(PROJECT)
3+
CONTAINER_NAME_DEV= $(PROJECT)-dev
4+
COMPOSE_BASE = docker-compose.base.yml
5+
SHELL := /usr/bin/env bash
6+
.SHELLFLAGS := -o pipefail -c
7+
8+
DC_START_CMD := up -d
9+
DC_STOP_CMD := stop
10+
DC_DOWN_CMD := down
11+
12+
define WITH_ENV
13+
set -a && source ../export_env_vars.sh;
14+
endef
15+
16+
.PHONY: up down restart build logs cert-check health-check
17+
18+
load-env:
19+
$(WITH_ENV) echo "Environment variables loaded."
20+
21+
show-env:
22+
${WITH_ENV} >/dev/null 2>&1; printenv | grep -E "^(JUPYTER)" | sort
23+
24+
start-dev:
25+
$(WITH_ENV) docker compose -f docker-compose.dev.yml $(DC_START_CMD)
26+
27+
start-dev-build:
28+
$(WITH_ENV) docker compose -f docker-compose.dev.yml ${DC_START_CMD} --build
29+
30+
start:
31+
$(WITH_ENV) docker compose -f $(COMPOSE_BASE) -f docker-compose.yml $(DC_START_CMD)
32+
33+
start-prod:
34+
$(WITH_ENV) docker compose -f $(COMPOSE_BASE) -f docker-compose.prod.yml $(DC_START_CMD)
35+
36+
stop-all:
37+
$(WITH_ENV) docker compose -f $(COMPOSE_BASE) -f docker-compose.dev.yml -f docker-compose.local.yml -f docker-compose.prod.yml docker-compose.yml ${DC_DOWN_CMD}
38+
39+
logs-dev:
40+
docker logs -f --tail 10000 ${CONTAINER_NAME_DEV}
41+
42+
logs:
43+
docker logs -f --tail 10000 $(CONTAINER_NAME)
44+
45+
health-check:
46+
curl -k -v https://localhost:8888/

docker/docker-compose-dev.yml renamed to docker/docker-compose.base.yml

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
services:
2-
cogstack-jupyter-hub-dev:
3-
build:
4-
context: ../
5-
dockerfile: "Dockerfile_hub"
6-
container_name: cogstack-jupyter-hub-dev
2+
cogstack-jupyter-hub:
3+
image: cogstacksystems/jupyter-hub:${JUPYTER_HUB_IMAGE_RELEASE_VERSION:-latest}
4+
container_name: cogstack-jupyter-hub
75
restart: always
86
environment:
97
- http_proxy=$HTTP_PROXY
@@ -13,8 +11,9 @@ services:
1311
- JUPYTERHUB_INTERNAL_PROXY_API_PORT=${JUPYTERHUB_INTERNAL_PROXY_API_PORT:-8887}
1412
- JUPYTERHUB_SSL_PORT=${JUPYTERHUB_SSL_PORT:-443}
1513
env_file:
16-
- ../env/general.env
17-
- ../env/jupyter.env
14+
- ${DEPLOYMENT_ENV_FILE_PATH_GENERAL:-../env/general.env}
15+
- ${JUPYTERHUB_ENV_FILE_PATH_CONFIG:-../env/jupyter.env}
16+
user: "root"
1817
volumes:
1918
- jupyter-hub-shared-scratch:/home/jovyan/scratch
2019
- jupyter-hub-vol:/srv/jupyterhub
@@ -23,8 +22,8 @@ services:
2322
- ../config/jupyterhub_cookie_secret:/srv/jupyterhub/jupyterhub_cookie_secret:ro
2423
# User list and jupyter config
2524
- ../config/jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py:ro
26-
- ../config/userlist:/srv/jupyterhub/userlist:ro
27-
- ../config/teamlist:/srv/jupyterhub/teamlist:ro
25+
- ../config/userlist:/srv/jupyterhub/userlist:rw
26+
- ../config/teamlist:/srv/jupyterhub/teamlist:rw
2827
# Give access to Docker socket
2928
- /var/run/docker.sock:/var/run/docker.sock
3029
ulimits:
@@ -38,15 +37,17 @@ services:
3837
- "${JUPYTERHUB_INTERNAL_PORT:-8888}:${JUPYTERHUB_SSL_PORT:-443}"
3938
networks:
4039
- cognet
40+
extra_hosts:
41+
- ${ELASTICSEARCH_1_HOST_NAME:-test-1:0.0.0.0}
42+
- ${ELASTICSEARCH_2_HOST_NAME:-test-2:0.0.0.0}
43+
- ${ELASTICSEARCH_3_HOST_NAME:-test-3:0.0.0.0}
44+
- ${KIBANA_HOST_NAME:-test-4:0.0.0.0}
45+
- ${NIFI_HOST_NAME:-test-5:0.0.0.0}
4146

4247
volumes:
4348
jupyter-hub-vol:
49+
name: "${VOLUME_PREFIX:-deploy_}jupyter-hub-vol"
4450
driver: local
4551
jupyter-hub-shared-scratch:
52+
name: "${VOLUME_PREFIX:-deploy_}jupyter-hub-shared-scratch"
4653
driver: local
47-
48-
networks:
49-
cognet:
50-
name: cogstack-net
51-
52-

docker/docker-compose.dev.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
services:
2+
cogstack-jupyter-hub-dev:
3+
extends:
4+
file: docker-compose.base.yml
5+
service: cogstack-jupyter-hub
6+
build:
7+
context: ../
8+
dockerfile: Dockerfile_hub
9+
container_name: cogstack-jupyter-hub-dev
10+
networks:
11+
- cognet
12+
13+
volumes:
14+
jupyter-hub-vol:
15+
driver: local
16+
jupyter-hub-shared-scratch:
17+
driver: local
18+
19+
networks:
20+
cognet:
21+
name: cogstack-net
22+
23+

docker/docker-compose.override.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
services:
2+
cogstack-jupyter-hub:
3+
container_name: cogstack-jupyter-hub
4+
networks:
5+
- cognet
6+
7+
volumes:
8+
jupyter-hub-vol:
9+
jupyter-hub-shared-scratch:
10+
11+
networks:
12+
cognet:
13+
name: cogstack-net
14+
driver: bridge

docker/docker-compose.prod.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
services:
2+
cogstack-jupyter-hub:
3+
networks:
4+
- cognet
5+
6+
networks:
7+
cognet:
8+
name: cogstack-net
9+
external: true

0 commit comments

Comments
 (0)