Installation and deployment
1. Installing Docker¶
First we need to install Docker. We can use the following commands for Azure VM with Ubuntu 24.04:
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Install Docker
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Add user to docker group
sudo groupadd docker
sudo usermod -aG docker $USERVM needs to be restarted to make sure that Docker functions properly. After restart, make sure that docker ps command does not give any errors.
Then we clone this repository.
git clone --depth 1 https://ci.tno.nl/gitlab/zonmw-phaeton/phaeton-hub.git
cd phaeton-hub2. Configuring network¶
When we are sure that Docker is functional, first we create a (virtual) network called jupyterhub-network .
docker network create jupyterhub-networkChange the domain name to your domain name or IP inside the config/Caddyfile.
your.domain.or.ip.com {
reverse_proxy jupyterhub:8000
}Make sure that ports 80 and 443 are available and open to outside such that Caddy can configure SSL certificates automatically.
3. Building images¶
Build Docker images that are going to be run by the users of the hub.
./build_images.shIf this command fails first try chmod u+x build_images.sh and try running it again. You can also build images separately with the following command.
docker build -f "images/<docker file name>" -t "<image name>:latest" "images"In this case you might need to add images you built to the inside c.DockerSpawner.allowed_images inside jupyterhub_config.py.
4. Running docker compose¶
Then we run docker compose.
docker compose up This command will create and run three containers, phaeton-hub-jupyterhub which is the Jupyterhub app, caddy:latest proxy server for HTTPS and dxflrs/garage:v1.0.0 which is the S3 storage. When we deploy it for the first time, we need to configure the Garage.
5. Configuring Garage¶
First we create an alias to run garage commands from the container.
alias garage="docker exec -it garage /garage"Afterwards we need to create a cluster layout (see Garage docs). We run the following command:
garage statusIt should give an output similar to this:
2025-04-28T09:27:09.622672Z INFO garage_net::netapp: Connected to 127.0.0.1:3901, negotiating handshake...
2025-04-28T09:27:09.664938Z INFO garage_net::netapp: Connection established to c01dae13498aa25e
==== HEALTHY NODES ====
ID Hostname Address Tags Zone Capacity DataAvail
c01dae13498aa25e 6cc0485836c5 127.0.0.1:3901 NO ROLE ASSIGNEDHere, we copy the ID of the node (c01dae13498aa25e) and run the following to create a cluster layout:
garage layout assign c01dae13498aa25e -z dc1 -c 1G -t phaetonwhere dc1 is a name for the zone (irrelevant if we are using only one server for data), 1G is the capacity of the data storage (it is 1 gigabyte, we can choose the size we like, e.g. 500G or 1T), and phaeton is the tag (name) of the storage instance. Afterwards we can check the layout with
garage layout show and we will see such an output:
2025-04-28T10:52:48.813723Z INFO garage_net::netapp: Connected to 127.0.0.1:3901, negotiating handshake...
2025-04-28T10:52:48.855927Z INFO garage_net::netapp: Connection established to c01dae13498aa25e
==== CURRENT CLUSTER LAYOUT ====
No nodes currently have a role in the cluster.
See `garage status` to view available nodes.
Current cluster layout version: 0
==== STAGED ROLE CHANGES ====
ID Tags Zone Capacity
c01dae13498aa25e phaeton dc1 1000.0 MB
2025-04-28T10:52:48.922957Z INFO garage_rpc::layout::history: Layout history: pruning old invalid version 0
==== NEW CLUSTER LAYOUT AFTER APPLYING CHANGES ====
ID Tags Zone Capacity Usable capacity
c01dae13498aa25e phaeton dc1 1000.0 MB 1000.0 MB (100.0%)
Zone redundancy: maximum
==== COMPUTATION OF A NEW PARTITION ASSIGNATION ====
Partitions are replicated 1 times on at least 1 distinct zones.
Optimal partition size: 3.9 MB
Usable capacity / total cluster capacity: 1000.0 MB / 1000.0 MB (100.0 %)
Effective capacity (replication factor 1): 1000.0 MB
dc1 Tags Partitions Capacity Usable capacity
c01dae13498aa25e phaeton 256 (256 new) 1000.0 MB 1000.0 MB (100.0%)
TOTAL 256 (256 unique) 1000.0 MB 1000.0 MB (100.0%)
To enact the staged role changes, type:
garage layout apply --version 1
You can also revert all proposed changes with: garage layout revertAfterwards we can apply the layout as suggested by the output of garage layout show and Garage service will be ready to use.
garage layout apply --version 1We should see such an output as below, then we are done.
2025-04-28T10:56:13.123958Z INFO garage_net::netapp: Connected to 127.0.0.1:3901, negotiating handshake...
2025-04-28T10:56:13.165981Z INFO garage_net::netapp: Connection established to c01dae13498aa25e
2025-04-28T10:56:13.229611Z INFO garage_rpc::layout::history: Layout history: pruning old invalid version 0
==== COMPUTATION OF A NEW PARTITION ASSIGNATION ====
Partitions are replicated 1 times on at least 1 distinct zones.
Optimal partition size: 3.9 MB
Usable capacity / total cluster capacity: 1000.0 MB / 1000.0 MB (100.0 %)
Effective capacity (replication factor 1): 1000.0 MB
dc1 Tags Partitions Capacity Usable capacity
c01dae13498aa25e phaeton 256 (256 new) 1000.0 MB 1000.0 MB (100.0%)
TOTAL 256 (256 unique) 1000.0 MB 1000.0 MB (100.0%)
New cluster layout with updated role assignment has been applied in cluster.
Data will now be moved around between nodes accordingly.After configuring Garage, stop the containers (either Ctrl+C inside the terminal or docker compose down) and restart them again with docker compose up.