|
1 | 1 | # ENROOT |
2 | 2 |
|
3 | | -A set of scripts and utilities to run container images as unprivileged "chroot" (or what some people refer to as HPC containers). |
| 3 | +A simple, yet powerful tool to turn traditional container/OS images into unprivileged sandboxes. |
4 | 4 |
|
5 | | -Example: |
6 | | -```bash |
7 | | -enroot import docker://alpine |
8 | | -enroot create alpine.sqsh |
9 | | -enroot start alpine |
10 | | -``` |
11 | | - |
12 | | -## Prerequisites |
13 | | - |
14 | | -Kernel settings: |
15 | | -```bash |
16 | | -# Make sure your kernel is fairly recent (~ 3.10) and supports what's required: |
17 | | -grep -E '(CONFIG_NAMESPACES|CONFIG_USER_NS|CONFIG_OVERLAY_FS|CONFIG_SECCOMP_FILTER)=' /boot/config-$(uname -r) |
18 | | -# For running old containers (e.g. Centos 6) on new kernels (4.8+) |
19 | | -grep 'CONFIG_X86_VSYSCALL_EMULATION'/boot/config-$(uname -r) && grep 'vsyscall=emulate' /proc/cmdline |
20 | | - |
21 | | -# Configure namespace limits appropriately if necessary |
22 | | -sudo tee -a /etc/sysctl.d/10-namespace.conf <<< "user.max_user_namespaces = 65536" |
23 | | -sudo tee -a /etc/sysctl.d/10-namespace.conf <<< "user.max_mnt_namespaces = 65536" |
24 | | - |
25 | | -# Debian distributions |
26 | | -sudo tee -a /etc/sysctl.d/10-namespace.conf <<< "kernel.unprivileged_userns_clone = 1" |
27 | | - |
28 | | -# RHEL distributions |
29 | | -sudo grubby --args="namespace.unpriv_enable=1 user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)" |
30 | | - |
31 | | -sudo reboot |
32 | | -``` |
33 | | - |
34 | | -Dependencies: |
35 | | -```bash |
36 | | -# Debian distributions (build, required, optional) |
37 | | -sudo apt install -y gcc make libcap2-bin libbsd-dev |
38 | | -sudo apt install -y curl tar pigz jq squashfs-tools parallel |
39 | | -sudo apt install -y pv nvidia-container-cli |
40 | | - |
41 | | -# RHEL distributions (build, required, optional) |
42 | | -sudo yum install -y epel-release |
43 | | -sudo yum install -y gcc make libcap libbsd-devel |
44 | | -sudo yum install -y curl tar pigz jq squashfs-tools parallel |
45 | | -sudo yum install -y pv nvidia-container-cli |
46 | | -```` |
47 | | - |
48 | | -## Installation |
49 | | - |
50 | | -```bash |
51 | | -git submodule update --init |
52 | | -
|
53 | | -sudo make install |
54 | | -# In order to allow unprivileged users to import images |
55 | | -sudo make setcap |
56 | | -``` |
57 | | - |
58 | | -Environment settings: |
59 | | - |
60 | | -| Environment | Default | Description | |
61 | | -| ------ | ------ | ------ | |
62 | | -| `ENROOT_LIBEXEC_PATH` | `/usr/local/libexec/enroot` | Path to sources and utilities | |
63 | | -| `ENROOT_SYSCONF_PATH` | `/usr/local/etc/enroot` | Path to system configuration files | |
64 | | -| `ENROOT_CONFIG_PATH` | `${XDG_CONFIG_HOME}/enroot` | Path to user configuration files | |
65 | | -| `ENROOT_CACHE_PATH` | `${XDG_CACHE_HOME}/enroot` | Path to user image/credentials cache | |
66 | | -| `ENROOT_DATA_PATH` | `${XDG_DATA_HOME}/enroot` | Path to user container storage | |
67 | | -| `ENROOT_RUNTIME_PATH` | `${XDG_RUNTIME_DIR}/enroot` | Path to the runtime working directory | |
68 | | - |
69 | | -## Usage |
70 | | -``` |
71 | | -Usage: enroot COMMAND [ARG...] |
72 | | - |
73 | | - Commands: |
74 | | - version |
75 | | - import [--output|-o IMAGE] URI |
76 | | - export [--output|-o IMAGE] NAME |
77 | | - create [--name|-n NAME] IMAGE |
78 | | - list [--fancy|-f] |
79 | | - remove [--force|-f] NAME... |
80 | | - start [--root|-r] [--rw|-w] [--conf|-c CONFIG] NAME [COMMAND] [ARG...] |
81 | | - bundle [--all|-a] [--output|-o BUNDLE] [--checksum|-c] [--target|-t TARGET] [--desc|-d TEXT] IMAGE |
82 | | -``` |
83 | | -
|
84 | | -## Commands |
85 | | -
|
86 | | -### version |
87 | | -Show the version of Enroot. |
88 | | -
|
89 | | -### import |
90 | | -Import and convert a Docker container image to an [Enroot image](#image-format) where the URI is of the form |
91 | | -`docker://[<user>@][<registry>#]<image>[:<tag>]`. Digests will be cached under `${ENROOT_CACHE_PATH}`. |
92 | | -
|
93 | | -Credentials can be configured by writing to the file `${ENROOT_CONFIG_PATH}/.credentials` following the netrc file format. For example: |
94 | | -``` |
95 | | -# NVIDIA GPU Cloud |
96 | | -machine authn.nvidia.com login $oauthtoken password <TOKEN> |
97 | | -# Docker Hub |
98 | | -machine auth.docker.io login <LOGIN> password <PASSWORD> |
99 | | -``` |
| 5 | +Enroot can be thought of as an enhanced unprivileged `chroot(1)`. It uses the same underlying technologies as containers but removes much of the isolation they inherently provide while preserving filesystem separation. |
100 | 6 |
|
101 | | -Environment settings: |
| 7 | +This approach is generally preferred in high-performance environments or virtualized environments where portability and reproducibility is important, but extra isolation is not warranted. |
102 | 8 |
|
103 | | -| Environment | Default | Description | |
104 | | -| ------ | ------ | ------ | |
105 | | -| `ENROOT_GZIP_PROG` | `pigz` _or_ `gzip` | Gzip program used to uncompress digest layers | |
106 | | -| `ENROOT_SQUASH_OPTS` | `-comp lzo -noD` | Options passed to `mksquashfs` to produce the image | |
| 9 | +Enroot is also similar to other tools like `proot(1)` or `fakeroot(1)` but instead relies on more recent features from the Linux kernel (i.e. user and mount namespaces), and provides facilities to import well known container image formats (e.g. [Docker](https://www.docker.com/)). |
107 | 10 |
|
108 | | -### export |
109 | | -Export a container root filesystem found under `${ENROOT_DATA_PATH}` to a container image. |
110 | | -The resulting artifact can then be unpacked using the [create](#create) command. |
| 11 | +Usage example: |
111 | 12 |
|
112 | | -Environment settings: |
113 | | -
|
114 | | -| Environment | Default | Description | |
115 | | -| ------ | ------ | ------ | |
116 | | -| `ENROOT_SQUASH_OPTS` | `-comp lzo -noD` | Options passed to `mksquashfs` to produce the image | |
117 | | -
|
118 | | -### create |
119 | | -Take a container image and unpack its root filesystem under `${ENROOT_DATA_PATH}` with the given name (optionally). |
120 | | -The resulting artifact can then be started using the [start](#start) command. |
121 | | -
|
122 | | -### list |
123 | | -List all the containers along with their size on disk (optionally). |
124 | | -
|
125 | | -### remove |
126 | | -Remove a container, deleting its root filesystem from disk. |
127 | | -
|
128 | | -### start |
129 | | -Start a previously [created](#create) container by executing its command script (or entrypoint), refer to [Image format (/etc/rc)](#image-format). |
130 | | -By default the root filesystem of the container is made read-only unless the `--rw` option has been provided. |
131 | | -The `--root` option can also be provided in order to remap your current user to be root inside the container. |
132 | | -
|
133 | | -Additionally, a configuration script can be provided with `--conf` to perform specific actions before the container starts. |
134 | | -This script is a standard bash script called before any configuration happens with the command and arguments passed as input parameters. |
135 | | -One or more of the following functions can be defined: |
136 | | -
|
137 | | -| Function | Description | |
138 | | -| ------ | ------ | |
139 | | -| `environ()` | Outputs [environment configuration](#environment-configuration-files) | |
140 | | -| `mounts()` | Outputs [mount configuration](#mount-configuration-files) | |
141 | | -| `hooks()` | A specific instance of [pre-start hook scripts](#pre-start-hook-scripts) | |
142 | | -
|
143 | | -Here is an example of such configuration: |
144 | | -
|
145 | | -```bash |
146 | | -environ() { |
147 | | - # Keep all the environment from the host |
148 | | - env |
149 | | -} |
150 | | -
|
151 | | -mounts() { |
152 | | - # Mount the X11 unix-domain socket |
153 | | - echo "/tmp/.X11-unix /tmp/.X11-unix none x-create=dir,bind" |
154 | | - # Mount the current working directory to /mnt |
155 | | - echo "${PWD} /mnt none bind" |
156 | | -} |
157 | | -
|
158 | | -hooks() { |
159 | | - # Set the DISPLAY environment variable if not set |
160 | | - [ -z "${DISPLAY-}" ] && echo "DISPLAY=:0.0" >> ${ENROOT_ENVIRON} |
161 | | - # Record the date when the container was last started |
162 | | - date > ${ENROOT_ROOTFS}/last_started |
163 | | -} |
164 | | -``` |
165 | | - |
166 | | -Environment settings: |
167 | | - |
168 | | -| Environment | Default | Description | |
169 | | -| ------ | ------ | ------ | |
170 | | -| `ENROOT_LOGIN_SHELL` | `/bin/sh` | Login shell used to run the container initialization (i.e. `/init`)| |
171 | | -| `ENROOT_ROOTFS_RW` | | Equivalent to `--rw` if set | |
172 | | -| `ENROOT_REMAP_ROOT` | | Equivalent to `--root` if set | |
173 | | - |
174 | | -### bundle |
175 | | -Create a self-extracting bundle from a container image which can be used to start a container with no external dependencies (on most Linux distributions). |
176 | | -The resulting bundle takes the same arguments as the [start](#start) command with the addition of `--info` which displays the bundle information, and |
177 | | -`--keep` which keeps the container filesystem extracted to the target directory after exiting. If `--keep` was not provided, `${TMPDIR}` is used for extraction. |
178 | | - |
179 | | -By default, only system-wide configuration is copied to the bundle unless `--all` is specified, in which case user-specified configuration is copied as well. |
180 | | -The target directory used to keep the container filesystem can be defined using the `--target` option and defaults to `${PWD}/<bundle>`. |
181 | | -Additionally, a checksum can be generated and a description provided with `--checksum` and `--desc` respectively. |
182 | | - |
183 | | -Example: |
184 | | -```bash |
185 | | -enroot import docker://alpine |
186 | | -enroot bundle -t '${HOME}/.local/share/enroot/foobar' alpine.sqsh |
187 | | -./alpine.run --keep --rw cp /etc/os-release /release |
188 | | -enroot start foobar cat /release |
| 13 | +```sh |
| 14 | +# Import and start an Ubuntu image from DockerHub |
| 15 | +$ enroot import docker://ubuntu |
| 16 | +$ enroot create ubuntu.sqsh |
| 17 | +$ enroot start ubuntu |
189 | 18 | ``` |
190 | 19 |
|
191 | | -Environment settings: |
192 | | - |
193 | | -| Environment | Default | Description | |
194 | | -| ------ | ------ | ------ | |
195 | | -| `ENROOT_BUNDLE_ALL` | | Equivalent to `--all` if set | |
196 | | -| `ENROOT_BUNDLE_SUM` | | Equivalent to `--checksum` if set | |
197 | | - |
198 | | -## Image format |
199 | | -Enroot images are standard squashfs images with the following configuration files influencing runtime behaviors. |
200 | | - |
201 | | -| File | Description | |
202 | | -| ------ | ------ | |
203 | | -| `/etc/rc` | Command script of the container (entrypoint) | |
204 | | -| `/etc/fstab` | Mount configuration of the container | |
205 | | -| `/etc/environment` | Environment of the container | |
| 20 | +## Key Concepts |
206 | 21 |
|
207 | | -These files follow the same format as the standard Linux/Unix ones (see _fstab(5)_, _rc(8)_, _pam_env(8)_) with the exceptions listed below. |
208 | | - |
209 | | -`/etc/rc`: |
210 | | - - The command and arguments of the [start](#start) command are passed as input parameters. |
211 | | - |
212 | | - |
213 | | -`/etc/fstab`: |
214 | | - - Adds two additional mount options, `x-create=dir` or `x-create=file` to create an empty directory or file before performing the mount. |
215 | | - - The target mountpoint is relative to the container rootfs. |
216 | | - - References to environment variables from the host of the form `${ENVVAR}` will be substituted |
217 | | - |
218 | | -``` |
219 | | -# Example mounting your home directory from the host |
220 | | -${HOME} ${HOME} none x-create=dir,bind |
221 | | -``` |
| 22 | +* Adheres to the [KISS principle](https://en.wikipedia.org/wiki/KISS_principle) and [Unix philosophy](https://en.wikipedia.org/wiki/Unix_philosophy) |
| 23 | +* Standalone (no daemon) |
| 24 | +* Fully unprivileged and multi-user capable (no setuid binary, cgroup inheritance, per-user configuration/container store...) |
| 25 | +* Easy to use (simple image format, scriptable, root remapping...) |
| 26 | +* Little to no isolation (no performance overhead, simplifies HPC deployements) |
| 27 | +* Entirely composable and extensible (system-wide and user-specific configurations) |
| 28 | +* Fast Docker image import (3x to 5x speedup on large images) |
| 29 | +* Built-in GPU support with [libnvidia-container](https://github.com/nvidia/libnvidia-container) |
| 30 | +* Facilitate collaboration and development workflows (bundles, in-memory containers...) |
222 | 31 |
|
223 | | -`/etc/environment`: |
224 | | - - References to environment variables from the host of the form `${ENVVAR}` will be substituted |
| 32 | +## Documentation |
225 | 33 |
|
226 | | - ```bash |
227 | | - # Example preserving the DISPLAY environment variable from the host |
228 | | - DISPLAY=${DISPLAY} |
229 | | - ``` |
| 34 | +1. [Requirements](doc/requirements.md) |
| 35 | +1. [Installation](doc/installation.md) |
| 36 | +1. [Image format](doc/image-format.md) |
| 37 | +1. [Configuration](doc/configuration.md) |
| 38 | +1. [Standard Hooks](doc/standard-hooks.md) |
| 39 | +1. [Usage](doc/usage.md) |
230 | 40 |
|
231 | | -## Configuration |
232 | 41 |
|
233 | | -Common configurations can be applied to all containers by leveraging the following directories under `${ENROOT_SYSCONF_PATH}` (system-wide) and/or `${ENROOT_CONFIG_PATH}` (user-specific). |
| 42 | +## Copyright and License |
234 | 43 |
|
235 | | -| Directory | Description | |
236 | | -| ------ | ------ | |
237 | | -| `environ.d` | Environment configuration files | |
238 | | -| `mounts.d` | Mount configuration files | |
239 | | -| `hooks.d` | Pre-start hook scripts | |
| 44 | +This project is released under the [BSD 3-clause license](https://github.com/NVIDIA/enroot/blob/master/LICENSE). |
240 | 45 |
|
241 | | -### Environment configuration files |
242 | | -Environment files have the `.env` extension and follow the same format as described in [Image format (/etc/environment)](#image-format) |
| 46 | +## Issues and Contributing |
243 | 47 |
|
244 | | -### Mount configuration files |
245 | | -Mount files have the `.fstab` extension and follow the same format as described in [Image format (/etc/fstab)](#image-format) |
| 48 | +* Please let us know by [filing a new issue](https://github.com/NVIDIA/enroot/issues/new) |
| 49 | +* You can contribute by opening a [pull request](https://help.github.com/articles/using-pull-requests/) |
246 | 50 |
|
247 | | -### Pre-start hook scripts |
248 | | -Pre-start hooks are standard bash scripts with the `.sh` extension. |
249 | | -They run with full capabilities before the container has switched to its final root. |
250 | | -Scripts are started with the host environment as well as the following environment variables: |
| 51 | +## Reporting Security Issues |
251 | 52 |
|
252 | | -| Environment | Description | |
253 | | -| ------ | ------ | |
254 | | -| `ENROOT_PID` | PID of the container | |
255 | | -| `ENROOT_ROOTFS` | Path to the container rootfs | |
256 | | -| `ENROOT_ENVIRON` | Path to the container environment file to be read at startup | |
| 53 | +When reporting a security issue, do not create an issue or file a pull request. |
| 54 | +Instead, disclose the issue responsibly by sending an email to `psirt<at>nvidia.com`. |
0 commit comments