# Installation and configuration manual

In most cases the end user can download and execute udocker without
system administrator intervention. udocker itself is written in Python, but
also uses external binaries and libraries to provide a chroot like
environment where containers are executed in user space. These tools do not
require any privileges and constitute the udocker tools and libraries for
engines that is downloaded and installed by udocker itself.

Redistribution, commercial use and code changes must regard all licenses
shipped with udocker. For more information see
[section 6 External tools and libraries](#6-external-tools-and-libraries).

## 1. Dependencies

The udocker dependencies are minimal and should be supported by most Linux installations.
udocker requires:

* Python 3 or alternatively Python >= 2.6
* pycurl or alternatively the curl command
* python hashlib or alternatively the openssl command
* tar
* find
* chmod
* chgrp
* ldconfig (only used by the Fn execution modes)

## 2. Installation

### 2.1. Install from a released version

Download a release tarball from <https://github.com/indigo-dc/udocker/releases>:

```bash
wget https://github.com/indigo-dc/udocker/releases/download/v1.3.4/udocker-1.3.4.tar.gz
tar zxvf udocker-1.3.4.tar.gz
export PATH=`pwd`/udocker:$PATH
```

Alternatively use `curl` instead of `wget` as follows:

```bash
curl -L https://github.com/indigo-dc/udocker/releases/download/v1.3.4/udocker-1.3.4.tar.gz \
  > udocker-1.3.4.tar.gz
tar zxvf udocker-1.3.4.tar.gz
export PATH=`pwd`/udocker:$PATH
```

udocker executes containers using external tools and libraries that
are enhanced and packaged for use with udocker. For more information see
[section 6 External tools and libraries](#6-external-tools-and-libraries).
Therefore to complete the installation invoke `udocker install` to download
and install the required tools and libraries.

```bash
udocker install
```

### 2.2. Install from the GitHub repositories

To install the latest stable code from the github `master` branch:

```bash
git clone --depth=1 https://github.com/indigo-dc/udocker.git
(cd udocker/udocker; ln -s maincmd.py udocker)  
export PATH=`pwd`/udocker/udocker:$PATH
```

Alternatively, install the latest development code from the github `devel3` branch:

```bash
git clone -b devel3 --depth=1 https://github.com/indigo-dc/udocker.git
(cd udocker/udocker; ln -s maincmd.py udocker)  
export PATH=`pwd`/udocker/udocker:$PATH
```

udocker executes containers using external tools and libraries that
are enhanced and packaged for use with udocker. For more information see
[section 6 External tools and libraries](#6-external-tools-and-libraries).
Therefore to complete the installation invoke `udocker install` to download
and install the required tools and libraries.

```bash
udocker install
```

### 2.3. Install from PyPI using pip

For installation with pip it is advisable to setup a Python3 virtual environment
before proceeding, see
[Creating a virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment).

```bash
python3 -m venv udockervenv
source udockervenv/bin/activate
pip install udocker
```

The udocker command will be `udockervenv/bin/udocker`.

udocker executes containers using external tools and libraries that
are enhanced and packaged for use with udocker. For more information see
[section 6 External tools and libraries](#6-external-tools-and-libraries).
Therefore to complete the installation invoke `udocker install` to download
and install the required tools and libraries.

```bash
udocker install
```

### 2.4. Install without outbound network access

When the installation is attempted without having outbound network connectivity,
the installation of the binary tools and libraries with `udocker install` will
fail the download step. The solution is to fetch the the tarball in advance
and then install the tools and libraries directly from the tarball file.

The tarballs containing the tools and libraries are available at <https://github.com/jorge-lip/udocker-builds>.

First, download a tarball file using:

```bash
curl -L https://github.com/jorge-lip/udocker-builds/raw/master/tarballs/udocker-englib-1.2.8.tar.gz > udocker-englib-1.2.8.tar.gz
```

Second, transfer the udocker code plus the tarball containing the tools and
libraries to the target destination host.

Finally perform the `udocker install` step using the transferred tarball file.

```bash
export UDOCKER_TARBALL=udocker-englib-1.2.8.tar.gz
udocker install
```

The environment variable `UDOCKER_TARBALL` can also point to an URL to fetch
the tarball from a specific or alternate location. To fetch from multiple
possible locations for redundancy the environment variable `UDOCKER_TARBALL`
can contain multiple URLs separated by a blank.

```bash
export UDOCKER_TARBALL="https://... https://... http://..."
udocker install
```

### 2.5. Force the re-installation of the tools and libraries

To force download and re-installation of the udocker tools and libraries.
Invoke `udocker install` with the flag `--force`:

```bash
udocker install --force
```

## 3. Configuration

The configuration of udocker has the following hierarchy:

1. The default configuration options are set in the `conf` dictionary in the `Config` class.
2. If a configuration file is present ([section 4. Configuration files](#4-configuration-files)),
   it will override 1.
3. If environment variables are set ([section 5. Environment variables](#5-environment-variables)),
   they will override 2.
4. The presence of general udocker command line options, will override 3. .

### 3.1. Directories

With the default configuration, udocker creates files and subdirectories under
`$HOME/.udocker` these are:

* `doc`: documentation and licenses.
* `bin`: executables to support the execution engines.
* `lib`: libraries, namely the fakechroot libraries to support the **F** execution mode.
* `repos`: container image repositories.
* `layers`: the layers and metadata for the container images.
* `containers`: created containers.
* `keystore.github`: authentication to access repositories (created on demand).

Both installed files, as well as the containers to be downloaded or created  
with udocker, will be installed by default under `$HOME/.udocker`.

A default configuration file is available at
[udocker.conf](https://github.com/indigo-dc/udocker/blob/master/etc/udocker.conf)
it can be copied to your udocker directory as `$HOME/.udocker/udocker.conf` and
customized.

## 4. Configuration files

The configuration files allow overriding of the udocker `Config` class
`conf` dictionary. Example of the `udocker.conf` syntax:

```ini
dockerio_registry_url = "https://myregistry.mydomain:5000"
http_insecure = True
verbose_level = 5
```

udocker loads the following configuration files if they are present:

1. `/etc/udocker.conf`
2. `$HOME/.udocker/udocker.conf`: overrides the options set in 1.
3. `$UDOCKER_DIR/udocker.conf` (if different from the above): overrides the options set in 2.
4. Configuration file set with the general CLI option `--config=`: overrides the options set in 3.

## 5. Environment variables

The following environment variables can be used to customize the installation.
The location of the udocker directories can be changed via the environment
variables:

* `UDOCKER_DIR`: root directory of udocker usually $HOME/.udocker
* `UDOCKER_BIN`: location of udocker related executables
* `UDOCKER_LIB`: location of udocker related libraries
* `UDOCKER_DOC`: location of documentation and licenses
* `UDOCKER_REPOS` images metadata and links to layers
* `UDOCKER_LAYERS`: the common location for image layers data
* `UDOCKER_CONTAINERS`: location of container directory trees (not images)
* `UDOCKER_TMP`: location of temporary directory
* `UDOCKER_KEYSTORE`: location of keystore for login/logout credentials
* `UDOCKER_TARBALL`: location of installation tarball (file of URL)
* `UDOCKER_NOSYSCONF`: do not read system wide config files in /etc

The Docker index and registry can be overridden via the environment variables.

* `UDOCKER_INDEX=https://...`
* `UDOCKER_REGISTRY=https://...`

The verbosity level of udocker can be enforced. Removing banners and most
messages can be achieved by executing with `UDOCKER_LOGLEVEL=2`.

* `UDOCKER_LOGLEVEL`: set verbosity level from 0 to 5 (MIN to MAX verbosity)

Forcing the use of a given curl executable instead of pycurl can be
specified with:

* `UDOCKER_USE_CURL_EXECUTABLE`: pathname to the location of curl executable

The fakechroot execution modes (Fn modes), the translation of symbolic links
to the actual links can be controlled by the environment variable
`UDOCKER_FAKECHROOT_EXPAND_SYMLINKS`. The default value is
`none` which will select automatically the mode to be used, `false` if mounts are
not performed or if the mount points pathname for the host and container
are equal (e.g `-v /home:/home`), `true` otherwise (e.g `-v /data:/home`).

* `UDOCKER_FAKECHROOT_EXPAND_SYMLINKS`: true, false, none

The location of some executables used by the execution modes can be enforced with
the environment variables described below together with the default behavior.
A value of `UDOCKER` will force the usage of the executables provided by the
udocker installation.

A full pathname can be used to select a specific executable (or library) from the
host or from the udocker installation.

* `UDOCKER_USE_PROOT_EXECUTABLE`: path to proot, default is proot from udocker.
* `UDOCKER_USE_RUNC_EXECUTABLE`: path to runc, default is search the host and
  if not found use runc from udocker.
* `UDOCKER_USE_SINGULARITY_EXECUTABLE`: path to singularity, default is search
  the host.
* `UDOCKER_FAKECHROOT_SO`: path to a fakechroot library, default is search
  in udocker.
* `UDOCKER_DEFAULT_EXECUTION_MODE`: default execution mode can be P1, P2, F1,
  S1, R1, R2 or R3.

## 6. External tools and libraries

### 6.1. Source code repositories

udocker uses external tools and libraries to execute the created containers.
The source code for the udocker tools and libraries is taken from several repositories.
The **F** modes need heavily modified Fakechroot libraries and also a modified Patchelf
both specifically improved to work with udocker. The Fakechroot for musl is a port
of the Fakechroot library for the musl libc performed by the udocker development team.
The **P** modes need a modified PRoot that includes fixes and enhancements to work with
udocker. The **R** modes use the original runc and crun software with small changes for
static compilation. The following table highlights the repositories used by udocker
containing the modified source code and the original repositories.


| Mode  | Engine           | Repository used by udocker                                 | Original repository
|-------|:-----------------|:-----------------------------------------------------------|:-----------------------------------------
| **P** | PRoot            | <https://github.com/jorge-lip/proot-udocker>               | <https://github.com/proot-me/proot>
| **F** | Fakechroot glibc | <https://github.com/jorge-lip/libfakechroot-glibc-udocker> | <https://github.com/dex4er/fakechroot>
| **F** | Fakechroot musl  | <https://github.com/jorge-lip/libfakechroot-musl-udocker>  | <https://github.com/dex4er/fakechroot>
| **F** | Patchelf         | <https://github.com/jorge-lip/patchelf-udocker>            | <https://github.com/NixOS/patchelf>
| **R** | runc             | THE ORIGINAL REPOSITORY IS USED                            | <https://github.com/opencontainers/runc>
| **R** | crun             | THE ORIGINAL REPOSITORY IS USED                            | <https://github.com/containers/crun>

### 6.2. Software Licenses

Redistribution, commercial use and code changes must regard all licenses shipped with udocker.
These include the [udocker license](https://github.com/indigo-dc/udocker/blob/master/LICENSE)
and the individual licenses of the external tools and libraries packaged for use with udocker.

| Mode  | Engine           | License
|-------|:-----------------|:----------------------------------------------------------------------------
| **P** | PRoot            | [GPL v2](https://github.com/jorge-lip/proot-udocker/blob/master/COPYING)
| **F** | Fakechroot glibc | [LGPL v2.1](https://github.com/jorge-lip/libfakechroot-glibc-udocker/blob/master/LICENSE)
| **F** | Fakechroot musl  | [LGPL v2.1](https://github.com/jorge-lip/libfakechroot-musl-udocker/blob/master/LICENSE)
| **F** | Patchelf         | [GPL v3](https://github.com/jorge-lip/patchelf-udocker/blob/master/COPYING)
| **R** | runc             | [Apache v2.0](https://github.com/opencontainers/runc/blob/master/LICENSE)
| **R** | crun             | [GPL v2](https://github.com/containers/crun/blob/master/COPYING)

### 6.3. Binaries

As mentioned in the previous sections the compiled binaries can be installed
with `udocker install`. Optionally they can be downloaded from the repository
containing the binary builds at: <https://github.com/jorge-lip/udocker-builds>

The executables are provided statically compiled for use across systems.
The shared libraries that support the **F** modes need to match the libc
within the container and are provided for several Linux distributions.
See `$HOME/.udocker/lib` for the supported distributions and corresponding
versions. The tools are also delivered for several architectures.

| Mode  | Supported architecture                       |
|-------|:---------------------------------------------|
| **P** | x86_64, i386, aarch64 and arm                |
| **F** | x86_64                                       |
| **R** | x86_64                                       |
| **S** | uses the binaries present in the host system |

The latest binary tarball can be produced from the source code using:

```bash
git clone -b devel3 https://github.com/indigo-dc/udocker
cd udocker/utils
./build_tarball.sh
```

## 7. Central installation

udocker can be installed and made available system wide from a central location
such as a shared read-only directory tree or file-system. The following guidelines
should be followed when installing udocker in a central shared location or in a
read only file system.

### 7.1. Install executables and libraries centrally

The executables and libraries can be installed with any of the methods described
in section 2 of this manual. The directory tree should contain the following
subdirectories: `bin`,  `containers`,  `layers`,  `lib`,  `repos`. For the
binaries and libraries the only directories required are `bin` and `lib`.

The udocker tool should be installed as shown in section 2.1:

```bash
cd /sw
wget https://github.com/indigo-dc/udocker/releases/download/1.3.4/udocker-1.3.4.tar.gz
tar zxvf udocker-1.3.4.tar.gz
```

Directing users to the central udocker installation can be done using the
environment variables described in section 5, or through the configuration files
described in section 6. The recommended approach is to set environment
variables at the user level as in the example where the assumed central location
will be under `/sw/udocker`:

```bash
export UDOCKER_BIN=/sw/udocker/bin
export UDOCKER_LIB=/sw/udocker/lib
export PATH=$PATH:$UDOCKER_BIN:/sw/udocker
```

Note that the command `udocker` will be in `/sw/udocker` with all the python
directory structure, while `/sw/udocker/bin` has all execution engines.

Make sure that the file protections are adequate namely that the files are
not modifiable by others.

### 7.2. Images and layers in central installations

The repository of pulled images can also be placed in a different location
than the user home directory `$HOME/.udocker`. Notice that if the target
location is not writable then the users will be unable to pull new images,
which may be fine if these images are managed centrally by someone else.
Make sure that the file protections are adequate to the intended purpose.

From the images in the common location the users can then create containers
whose content will be placed in the user home directory under `$HOME/.udocker`.
This can be accomplished by redirecting the directories `layers` and  `repos`
to a common location. The users will need to set the following environment
variables. Therefore assuming that the common location will be `/sw/udocker`:

```bash
export UDOCKER_REPOS=/sw/udocker/repos
export UDOCKER_LAYERS=/sw/udocker/layers
```

### 7.3. Containers in central installations

If a container is extracted to the common location, it is possible to
point udocker to execute the container from that location. Making
udocker pointing at different `containers` directory such as for example
`/sw/udocker/containers` can be accomplished with:

```bash
export UDOCKER_CONTAINERS=/sw/udocker/containers
```

Assuming that the container is to be created under `/sw/udocker/containers`
it can be extracted with:

```bash
export UDOCKER_CONTAINERS=/sw/udocker/containers
udocker --allow-root pull  centos:centos7
udocker --allow-root create  --name=myContainerId  centos:centos7
udocker --allow-root run  -v /tmp myContainerId
```

Notice the `--allow-root` should only be used when running
from the root user. However depending on the execution mode and several other
factors the limitations described in the next sections apply.

#### 7.3.1. Selection of execution mode for central installations

The selection of the execution mode requires writing in the `containers`
directory, therefore if the container is in a read-only location the
execution mode cannot be changed. If a container is to be executed in a mode
other than the default then this must be set in advance. This must be done
by someone with write access. A table summarizing the execution modes
and their implications:

|Mode| Engine      | Execution from readonly location
|----|:------------|:------------------------------------------
| P1 | PRoot       | OK
| P2 | PRoot       | OK
| F1 | Fakechroot  | OK
| F2 | Fakechroot  | OK
| F3 | Fakechroot  | OK see restrictions in section 7.3.1.2.
| F4 | Fakechroot  | NOT SUPPORTED REQUIRES WRITE ACCESS
| R1 | runc / crun | OK requires udocker version above v1.1.7
| R2 | runc / crun | OK see restrictions in section 7.3.1.3.
| R3 | runc / crun | OK see restrictions in section 7.3.1.3.
| S1 | Singularity | OK

Changing the execution mode can be accomplished with the following udocker
command where `<MODE>` is one of the supported modes in column one.

```bash
udocker --allow-root setup --execmode=<MODE> myContainerId
```

Notice the `--allow-root` should only be used when running
from the root user.

If the same container is to be provided for execution using more
than one execution mode (e.g. to be executed with P1 and F3), then
make copies of the initial container and setup each one of them with
the intended mode. The command `udocker clone` can be used to create
copies of existing containers.

##### 7.3.1.1. Mode F4 is not supported

The mode F4 is not suitable for readonly containers as it is meant to
support the dynamic creation of new executables and libraries inside of
the container, which cannot happen if the container is readonly. Use the
mode F3 instead of F4.

##### 7.3.1.2. Mode F3 restrictions

The F3 mode (and also F4) perform changes to the container executables
and libraries, in particular they change the pathnames in ELF headers
making them pointing at the container location. This means that the
pathname to the container must be always the same across all the
hosts that may share the common location. Therefore if the original
location pathname is `/sw/udocker/containers` then all hosts must
also mount it at the same exact path `/sw/udocker/containers`.

##### 7.3.1.3. Modes R2 and R3 restrictions

Central installation from readonly location using any of the R modes
requires udocker above v1.1.7.
These modes require the creation of a mount point inside the container
that is transparently created when the container is first executed,
therefore (as recommended for all other modes) the container
must be executed once by someone with write access prior to making it
available to the users. Furthermore these execution modes are nested
they use P1 or P2 inside the R engine, the Pn modes require a tmp
directory that is writable. Therefore it is recommended to mount the
host `/tmp` in the container `/tmp` like this:

```bash
udocker --allow-root run  -v /tmp myContainerId
```

Or alternatively:

```bash
export PROOT_TMP_DIR=/<path-to-host-writable-directory>
udocker --allow-root run  -v /<path-to-host-writable-directory>  myContainerId
```

Notice the `--allow-root` should only be used when running from the root user.

#### 7.3.2. Mount directories and files in central installations

Making host files and directories visible inside the container requires
creating the corresponding mount points. The creation of mount-points
requires write access to the container. Therefore if a container is in
a read-only location these files and directories must be created in
advance.

Notice that some default mount points are required and automatically
created by udocker itself, therefore the container should be executed
by the administrator to ensure that the required files and directories
are created. Furthermore if additional mount points are required to
access data or other user files from the host, such mount points
must also be created by the administrator by executing the container
with the adequate volume pathnames. The example shows how to setup
the default mount points and in addition create a new mount point
named `/data`.

```bash
udocker --allow-root run -v /home:/data  myContainerId
```

Notice the `--allow-root` should only be used when running
from the root user.

Notice that once `/data` is setup the end users can mount other
directories in `/data` at runtime, meaning that users are not
restricted to mount only the `/home` directory as the mapping
is defined at run time.

#### 7.3.3. Protection of container files and directories

For the container to be executed by other users the files and
directories within the container must be readable. When udocker
is installed in the user home directory all files belong to
the user and are therefore readable by him. If a common location
is shared by several users the file protections will likely
need to be adjusted. Consider carefully your security policies
and requirements when changing the file protections.

The following example assumes making all files readable to
anyone and making all files (and directories) that have the
executable bit to be also *executable* by anyone.

```bash
export mycdir=$(udocker --allow-root inspect -p myContainerId)
chmod -R uog+r $mycdir
find $mycdir -executable -exec chmod oug+x {} \;
```

Notice the `--allow-root` should only be used when running
from the root user.

### 7.4. Using a common directory for executables and containers

If the common directory is used both for executables and containers
then the following environment variables can be used:

```bash
export UDOCKER_DIR=/sw/udocker
export PATH=$PATH:$UDOCKER_DIR:$UDOCKER_DIR/bin
```

## 8. Uninstall

udocker does not provide an uninstall command. udocker can be uninstalled
by simply removing the created files and directories. The recommended
approach is as follows:

1. Fix permissions for all created containers
   `for id in $(udocker ps | cut -f1 -d" " | grep -v CONTAINER); do udocker setup --fixperm $id; done`
2. Remove all created containers
   `for id in $(udocker ps | cut -f1 -d" " | grep -v CONTAINER); do udocker rm -f $id; done`
3. Remove the *udocker directory tree* usually under `$HOME/.udocker`
   `cd $HOME ; rm -Rf .udocker`
4. Remove the udocker Python code

The *udocker directory tree* contains the external executables, libraries,
documentation, container images and container file system trees. By removing
it all created containers will be also removed. Changing the file permissions
might be required prior to deletion especially for the container file system
trees in the `containers` subdirectory.

## 9. Quality assurance

The udocker software quality assurance follows the Common Software 
Quality Assurance Baseline Criteria for Research Projects 
DOI: <http://hdl.handle.net/10261/160086.> available at
<https://indigo-dc.github.io/sqa-baseline/>.

udocker uses the Jenkins Pipeline Library 
<https://github.com/indigo-dc/jenkins-pipeline-library>
to implement Jenkins CI/CD pipelines for quality assurance.

### 9.1. Functional and integration tests

High level functional and integration tests used for quality assurance are available 
in <https://github.com/indigo-dc/udocker/tree/master/utils>.
These tests are also suitable to be executed by end-users to verify the installation.
After cloning the udocker repository with `git` the `bash` scripts
can be executed using:

```bash
cd utils
./udocker_test.sh
./udocker_test-run.sh
```

If the `.udocker` directory already exists these tests will not execute as they require
a clean environment. In this case proceed as follows:

1. rename the directory `$HOME/.udocker`, as in `mv $HOME/.udocker $HOME/.udocker.ORIG`
2. execute the tests
3. remove the `$HOME/.udocker` created by the tests
4. restore the original `.udocker` directory as in `mv $HOME/.udocker.ORIG $HOME/.udocker`

### 9.2. Unit and security tests
The unit tests used in the software quality assurance pipelines are available at
<https://github.com/indigo-dc/udocker/tree/master/tests/unit>.
The tests can be executed after creating a virtualenv and installing the development
requirements in [requirements-dev.txt](https://github.com/indigo-dc/udocker/blob/master/requirements-dev.txt)
These tests are meant to be executed by the automated quality assurance pipelines.

```bash
virtualenv -p python3 ud3
source ud3/bin/activate
git clone https://github.com/indigo-dc/udocker.git
cd udocker
pip install -r requirements-dev.txt
```

The unit tests coverage can be executed using:

```bash
nosetests -v --with-coverage --cover-package=udocker tests/unit
```

Other tests configured in `tox.ini`, can be executed as well, such as linting
(code style checking) and static security tests:

```bash
pylint --rcfile=pylintrc --disable=R,C udocker
bandit -r udocker -f html -o bandit.html
```

