Skip to content

Commit 071fdea

Browse files
authored
Polish the "Container Engine" document (#130)
This PR polishes the document on "Container Engine." - Update the content to be up to date with the Confluence counterpart. - Split the document into multiple child pages (for readability).
1 parent 37a4243 commit 071fdea

File tree

8 files changed

+908
-885
lines changed

8 files changed

+908
-885
lines changed

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ If you cannot find the information that you need in the documentation, help is a
127127

128128
[:octicons-arrow-right-24: uenv][ref-uenv]
129129

130-
[:octicons-arrow-right-24: Container engine](software/container-engine.md)
130+
[:octicons-arrow-right-24: Container engine][ref-container-engine]
131131

132132

133133
- :fontawesome-solid-screwdriver-wrench: __Data management and storage__

docs/software/container-engine.md

Lines changed: 0 additions & 883 deletions
This file was deleted.
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
[](){#ref-ce-edf-reference}
2+
# EDF reference
3+
4+
EDF files use the [TOML format](https://toml.io/en/). For details about the data types used by the different parameters, please refer to the [TOML spec webpage](https://toml.io/en/v1.0.0).
5+
6+
## EDF entries
7+
8+
### `base_environment`
9+
10+
| | |
11+
|-------------|-----------------|
12+
| **Type** | array or string |
13+
| **Default** | `""` |
14+
15+
Ordered list of EDFs that this file inherits from. Parameters from listed environments are evaluated sequentially. Supports up to 10 levels of recursion.
16+
17+
!!! example
18+
* Single environment inheritance:
19+
```toml
20+
base_environment = "common_env"
21+
```
22+
23+
* Multiple environment inheritance:
24+
```toml
25+
base_environment = ["common_env", "ml_pytorch_env1"]
26+
```
27+
28+
!!! note
29+
* Parameters from the listed environments are evaluated sequentially, adding new entries or overwriting previous ones, before evaluating the parameters from the current EDF. In other words, the current EDF inherits the parameters from the EDFs listed in `base_environment`. When evaluating `mounts` or `env` parameters, values from downstream EDFs are appended to inherited values.
30+
* The individual EDF entries in the array follow the same search rules as the arguments of the `--environment` CLI option for Slurm; they can be either file paths or filenames without extension if the file is located in the [EDF search path][ref-ce-edf-search-path].
31+
* This parameter can be a string if there is only one base environment.
32+
33+
### `image`
34+
35+
| | |
36+
|-------------|--------|
37+
| **Type** | string |
38+
| **Default** | `""` |
39+
40+
The container image to use. If empty, CE doesn't enter a container. Can reference a remote Docker/OCI registry or a local Squashfs file as a filesystem path.
41+
42+
!!! example
43+
* Reference of Ubuntu image in the Docker Hub registry (default registry)
44+
```toml
45+
image = "library/ubuntu:24.04"
46+
```
47+
48+
* Explicit reference of Ubuntu image in the Docker Hub registry
49+
```toml
50+
image = "docker.io#library/ubuntu:24.04"
51+
```
52+
53+
* Reference to PyTorch image from NVIDIA Container Registry (nvcr.io)
54+
```toml
55+
image = "nvcr.io#nvidia/pytorch:22.12-py3"
56+
```
57+
58+
* Image from third-party quay.io registry
59+
```toml
60+
image = "quay.io#madeeks/osu-mb:6.2-mpich4.1-ubuntu22.04-arm64"
61+
```
62+
63+
* Reference to a manually pulled image stored in parallel FS
64+
```toml
65+
image = "/path/to/image.squashfs"
66+
```
67+
68+
!!! note
69+
* The full format for remote references is `[USER@][REGISTRY#]IMAGE[:TAG]`.
70+
* `[REGISTRY#]`: (optional) registry URL, followed by #. Default: Docker Hub.
71+
* `IMAGE`: image name.
72+
* `[:TAG]`: (optional) image tag name, preceded by :.
73+
* The registry user can also be specified in the `$HOME/.config/enroot/.credentials` file.
74+
75+
### `workdir`
76+
77+
| | |
78+
|-------------|------------------------|
79+
| **Type** | string |
80+
| **Default** | (inherited from image) |
81+
82+
Initial working directory when the container starts.
83+
84+
!!! example
85+
* Workdir pointing to a user defined project path 
86+
```toml
87+
workdir = "/home/user/projects"
88+
```
89+
* Workdir pointing to the `/tmp` directory
90+
```toml
91+
workdir = "/tmp"
92+
```
93+
94+
### `entrypoint`
95+
96+
| | |
97+
|-------------|--------|
98+
| **Type** | bool |
99+
| **Default** | `true` |
100+
101+
If true, run the entrypoint from the container image.
102+
103+
!!! example
104+
```toml
105+
entrypoint = false
106+
```
107+
108+
### `writable`
109+
110+
| | |
111+
|-------------|--------|
112+
| **Type** | bool |
113+
| **Default** | `true` |
114+
115+
If false, the container filesystem is read-only.
116+
117+
!!! example
118+
```toml
119+
writable = true
120+
```
121+
122+
### `mounts`
123+
124+
| | |
125+
|-------------|-------|
126+
| **Type** | array |
127+
| **Default** | `[]` |
128+
129+
List of bind mounts in the format `SOURCE:DESTINATION[:FLAGS]`. Flags are optional and can include `ro`, `private`, etc.
130+
131+
!!! example
132+
* Literal fixed mount map
133+
```toml
134+
mounts = ["/capstor/scratch/cscs/amadonna:/capstor/scratch/cscs/amadonna"]
135+
```
136+
137+
* Mapping path with `env` variable expansion
138+
```toml
139+
mounts = ["/capstor/scratch/cscs/${USER}:/capstor/scratch/cscs/${USER}"]
140+
```
141+
142+
* Mounting the scratch filesystem using a host environment variable
143+
```toml
144+
mounts = ["${SCRATCH}:/scratch"]
145+
```
146+
147+
!!! note
148+
* Mount flags are separated with a plus symbol, for example: `ro+private`.
149+
150+
## EDF tables
151+
152+
### `env`
153+
154+
Environment variables to set in the container. Empty string values will unset the variable. Inherited from the host and the image by default.
155+
156+
!!! example
157+
* Basic `env` block
158+
```toml
159+
[env]
160+
MY_RUN = "production",
161+
DEBUG = "false"
162+
```
163+
164+
* Use of environment variable expansion
165+
```toml
166+
[env]
167+
MY_NODE = "${VAR_FROM_HOST}",
168+
PATH = "${PATH}:/custom/bin",
169+
DEBUG = "true"
170+
```
171+
172+
!!! note
173+
* By default, containers inherit environment variables from the container image and the host environment, with variables from the image taking precedence.
174+
* The env table can be used to further customize the container environment by setting, modifying, or unsetting variables.
175+
* Values of the table entries must be strings. If an entry has a null value, the variable corresponding to the entry key is unset in the container.
176+
177+
### `annotations`
178+
179+
OCI-like annotations for the container. For more details, refer to the [Annotations][ref-ce-annotations] section.
180+
181+
!!! example
182+
* Disabling the CXI hook
183+
```toml
184+
[annotations]
185+
com.hooks.cxi.enabled = "false"
186+
```
187+
188+
* Control of SSH hook parameters via annotation and variable expansion
189+
```toml
190+
[annotations.com.hooks.ssh]
191+
authorize_ssh_key = "/capstor/scratch/cscs/${USER}/tests/edf/authorized_keys"
192+
enabled = "true"
193+
```
194+
195+
* Alternative example for usage of annotation with fixed path
196+
```toml
197+
[annotations]
198+
com.hooks.ssh.authorize_ssh_key = "/path/to/authorized_keys"
199+
com.hooks.ssh.enabled = "true"
200+
```
201+
202+
## Environment variable expansion
203+
204+
Environment variable expansion allows for dynamic substitution of environment variable values within the EDF (Environment Definition File). This capability applies across all configuration parameters in the EDF, providing flexibility in defining container environments.
205+
206+
* *Syntax*. Use `${VAR}` to reference an environment variable `VAR`. The variable's value is resolved from the combined environment, which includes variables defined in the host and the container image, the later taking precedence.
207+
* *Scope*. Variable expansion is supported across all EDF parameters. This includes EDF’s parameters like mounts, workdir, image, etc. For example, `${SCRATCH}` can be used in mounts to reference a directory path.
208+
* *Undefined Variables*. Referencing an undefined variable results in an error. To safely handle undefined variables, you can use the syntax `${VAR:-}`, which evaluates to an empty string if VAR is undefined.
209+
* *Preventing Expansion*. To prevent expansion, use double dollar signs $$. For example, `$${VAR}` will render as the literal string `${VAR}`.
210+
* *Limitations*
211+
* Variables defined within the `[env]` EDF table cannot reference other entries from `[env]` tables in the same or other EDF files (e.g. the ones entered as base environments). Therefore, only environment variables from the host can be referenced.
212+
* *Environment Variable Resolution Order*. The environment variables in containers are set based on the following order:
213+
* EDF env: Variable values as defined in EDF’s `[env]` table.
214+
* Container Image: Variables defined in the container image's environment take precedence.
215+
* Host Environment: Environment variables defined in the host system.
216+
217+
## Relative paths expansion
218+
219+
Relative filesystem paths can be used within EDF parameters, and will be expanded by the CE at runtime.
220+
The paths are interpreted as relative to the working directory of the process calling the CE, not to the location of the EDF file.
221+
Relative paths should be prepended by `./`.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
[](){#ref-container-engine}
2+
# Container Engine
3+
4+
The Container Engine (CE) toolset is designed to enable computing jobs to seamlessly run inside Linux application containers, thus providing support for containerized user environments.
5+
6+
## Concept
7+
8+
Containers effectively encapsulate a software stack; however, to be useful in HPC computing environments, they often require the customization of bind mounts, environment variables, working directories, hooks, plugins, etc.
9+
To simplify this process, the Container Engine (CE) toolset supports the specification of user environments through Environment Definition Files.
10+
11+
An Environment Definition File (EDF) is a text file in the [TOML format](https://toml.io/en/) that declaratively and prescriptively represents the creation of a computing environment based on a container image.
12+
Users can create their own custom environments and share, edit, or build upon already existing environments.
13+
14+
The Container Engine (CE) toolset leverages its tight integration with the Slurm workload manager to parse Fs directly from the command line or batch script and instantiate containerized user environments seamlessly and transparently.
15+
16+
Through the EDF, container use cases can be abstracted to the point where end users perform their workflows as if they were operating natively on the computing system.
17+
18+
## Benefits
19+
20+
* *Freedom*: Container gives users full control of the user space. The user can decide what to install without involving a sysadmin.
21+
* *Reproducibility*: Workloads consistently run in the same environment, ensuring uniformity across job experimental runs.
22+
* *Portability*: The self-contained nature of containers simplifies the deployment across architecture-compatible HPC systems.
23+
* *Seamless Access to HPC Resources*: CE facilitates native access to specialized HPC resources like GPUs, interconnects, and other system-specific tools crucial for performance.
24+
25+
## Quick Start
26+
27+
Let's set up a containerized Ubuntu 24.04 environment on the scratch folder (`${SCRATCH}`).
28+
29+
### Step 1. Create an environment
30+
31+
Save this file below as `ubuntu.toml` in `${HOME}/.edf` directory (the default location of EDF files).
32+
Create `${HOME}/.edf` if the folder doesn't exist.
33+
A more detailed explanation of each entry for the EDF can be seen in the [EDF reference][ref-ce-edf-reference].
34+
35+
```toml
36+
image = "library/ubuntu:24.04"
37+
mounts = ["/capstor/scratch/cscs/${USER}:/capstor/scratch/cscs/${USER}"]
38+
workdir = "/capstor/scratch/cscs/${USER}"
39+
```
40+
41+
### Step 2. Launch a program
42+
43+
Use Slurm on the login node to launch a program inside the environment.
44+
Notice that the environment (EDF) is specified with the `--environment` option.
45+
CE pulls the image automatically when the container starts.
46+
47+
```console
48+
$ srun --environment=ubuntu echo "Hello"
49+
Hello
50+
```
51+
52+
Or, use `--pty` to directly enter the environment.
53+
54+
```console
55+
$ srun --environment=ubuntu --pty bash
56+
[compute-node]$
57+
```
58+
59+
!!! Example "Entering the environment on Daint"
60+
```console
61+
[daint-ln002]$ srun --environment=ubuntu --pty bash # (1)
62+
63+
[nid005333]$ pwd # (2)
64+
/capstor/scratch/cscs/<username>
65+
66+
[nid005333]$ cat /etc/os-release # (3)
67+
PRETTY_NAME="Ubuntu 24.04 LTS"
68+
NAME="Ubuntu"
69+
VERSION_ID="24.04"
70+
...
71+
72+
[nid005333]$ exit # (4)
73+
[daint-ln002]$
74+
```
75+
76+
1. Starting an interactive shell session within the Ubuntu 24.04 container deployed on a compute node using `srun --environment=ubuntu --pty bash`.
77+
2. Check the current folder (dubbed _the working directory_) is set to the user's scratch folder, as per EDF.
78+
3. Show the OS version of your container (using `cat /etc/os-release`) based on Ubuntu 24.04 LTS.
79+
4. Exiting the container (`exit`), returning to the login node.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
## Compatibility with Alpine Linux
2+
3+
Alpine Linux is incompatible with some hooks, causing errors when used with Slurm. For example,
4+
5+
```toml title="EDF: alpine.toml"
6+
image = "alpine:3.19"
7+
```
8+
9+
```console title="Command-line"
10+
$ srun -lN1 --environment=alpine echo "abc"
11+
0: slurmstepd: error: pyxis: container start failed with error code: 1
12+
0: slurmstepd: error: pyxis: printing enroot log file:
13+
0: slurmstepd: error: pyxis: [ERROR] Failed to refresh the dynamic linker cache
14+
0: slurmstepd: error: pyxis: [ERROR] /etc/enroot/hooks.d/87-slurm.sh exited with return code 1
15+
0: slurmstepd: error: pyxis: couldn't start container
16+
0: slurmstepd: error: spank: required plugin spank_pyxis.so: task_init() failed with rc=-1
17+
0: slurmstepd: error: Failed to invoke spank plugin stack
18+
```
19+
20+
This is because some hooks (e.g., Slurm and CXI hooks) leverage `ldconfig` (from Glibc) when they bind-mount host libraries inside containers; since Alpine Linux provides an alternative `ldconfig` (from Musl Libc), it does not work as intended by hooks. As a workaround, users may disable problematic hooks. For example,
21+
22+
```toml title="EDF: alpine_workaround.toml"
23+
image = "alpine:3.19"
24+
25+
[annotations]
26+
com.hooks.cxi.enabled = "false"
27+
28+
[env]
29+
ENROOT_SLURM_HOOK = "0"
30+
```
31+
32+
```console title="Command-line"
33+
$ srun -lN1 --environment=alpine_workaround echo "abc"
34+
abc
35+
```
36+
37+
Notice the section `[annotations]` disabling Slurm and CXI hooks.
38+
39+
## Using NCCL from remote SSH terminals
40+
41+
We are aware of an issue when enabling both [the AWS OFI NCCL hook][ref-ce-aws-ofi-hook] and [the SSH hook][ref-ce-ssh-hook], and launching programs using NCCL from Bash sessions connected via SSH.
42+
The issue manifests with messages reporting `Error: network 'AWS Libfabric' not found`.
43+
44+
In addition to setting up a server for remote connections, the SSH hook also performs actions intended to improve the user experience. One of these is creating a script to be loaded by Bash in order to propagate the container job environment variables when connecting through SSH.
45+
The script is translating the value of the `NCCL_NET` variable as `"'AWS Libfabric'"`, that is with additional quotes compared to the original value set by the AWS OFI NCCL hook. The quoted string induces NCCL to look for a network which is not defined, resulting in the unrecoverable error mentioned earlier.
46+
47+
As a workaround, resetting the NCCL_NET variable to the correct value is effective in allowing NCCL to use the AWS OFI plugin and access the Slingshot network, e.g. `export NCCL_NET="AWS Libfabric"`.
48+
49+
## Mounting home directories when using the SSH hook
50+
51+
Mounting individual home directories (usually located on the `/users` filesystem) overrides the files created by the SSH hook in `${HOME}/.ssh`, including the one which includes the authorized key entered in the EDF through the corresponding annotation. In other words, when using the SSH hook and bind mounting the user's own home folder or the whole `/users`, it is necessary to authorize manually the desired key.
52+
53+
It is generally NOT recommended to mount home folders inside containers, due to the risk of exposing personal data to programs inside the container.
54+
Defining a mount related to `/users` in the EDF should only be done when there is a specific reason to do so, and the container image being deployed is trusted.

0 commit comments

Comments
 (0)