github.com/mgoltzsche/ctnr@v0.7.1-alpha/README.md (about)

     1  ctnr [![Build Status](https://travis-ci.org/mgoltzsche/ctnr.svg?branch=master)](https://travis-ci.org/mgoltzsche/ctnr)
     2  =
     3  
     4  ctnr is a CLI built on top of [runc](https://github.com/opencontainers/runc)
     5  to manage and build OCI images as well as containers on Linux.  
     6  ctnr aims to ease system container creation and execution as unprivileged user.  
     7  Also ctnr is a tool to experiment with runc features.
     8  
     9  THIS PROJECT IS NOT MAINTAINED ANYMORE IN FAVOUR OF [podman](https://github.com/containers/libpod).
    10  
    11  ## Features
    12  - OCI bundle and container preparation as well as execution as unprivileged user using [runc](https://github.com/opencontainers/runc)
    13  - OCI image build as unprivileged user
    14  - Simple concurrently accessible image and bundle store
    15  - Image and bundle file system creation (based on [umoci](https://github.com/openSUSE/umoci))
    16  - Various image formats and transports supported by [containers/image](https://github.com/containers/image)
    17  - Container networking using [CNI](https://github.com/containernetworking/cni) (optional, requires root, as OCI runtime hook)
    18  - [Dockerfile](https://docs.docker.com/engine/reference/builder/) support
    19  - [Docker Compose 3](https://docs.docker.com/compose/compose-file/) support (subset) using [docker/cli](https://github.com/docker/cli/) (WIP)
    20  - Easy to learn: [docker](https://www.docker.com/)-like CLI
    21  - Easy installation: single statically linked binary (plus optional binaries: CNI plugins, proot) and convention over configuration
    22  
    23  
    24  ## Rootless containers
    25  
    26  Concerning accessibility, usability and security a rootless container engine has several advantages:
    27  - **Containers can be run by unprivileged users.**  
    28    _Required in restrictive environments and useful for graphical applications._
    29  - **Container images can be built in almost every Linux environment.**  
    30    _More flexibility in unprivileged builds - nesting containers is also possible (see [experiments and limitations](nested-containers.md))._
    31  - **A higher degree and more flexible level of security.**  
    32    _Less likely for an attacker to gain root access when run as unprivileged user._  
    33    _User/group-based container access control._
    34    _Separation of responsibilities._
    35  
    36  
    37  ### Limitations & challenges
    38  
    39  Container execution as unprivileged user is limited:
    40  
    41  
    42  **Container networking is limited.**
    43  With plain ctnr/runc only the host network can be used.
    44  The standard [CNI plugins](https://github.com/containernetworking/plugins) require root privileges.  
    45  One workaround is to map ports on the host network using [PRoot](https://github.com/rootless-containers/PRoot)* accepting bad performance.  
    46  A better solution is to use [slirp4netns](https://github.com/rootless-containers/slirp4netns) which emulates the TCP/IP stack in a user namespace efficiently.
    47  It can be used with ctnr via the [slirp-cni-plugin](https://github.com/mgoltzsche/slirp-cni-plugin).
    48  Once container initialization is also moved into a user namespace with slirp the standard CNI plugins can be used again.
    49  For instance the [bridge](https://github.com/containernetworking/plugins/tree/master/plugins/main/bridge) can be used to achieve communication between containers (see [user-mode networking](user-mode-networking.md)).  
    50  
    51  
    52  **Inside the container a process' or file's user cannot be changed.**
    53  This is caused by the fact that all operations in the container are still run by the host user (who is just mapped to user 0 inside the container).
    54  Unfortunately this stops many package managers as well as official docker images from working:
    55  While `apk` or `dnf` already work with plain [runc](https://github.com/opencontainers/runc) `apt-get` does not since it requires to change a user permanently.  
    56  To overcome this limitation ctnr supports the `user.rootlesscontainers` xattr and integrates with [PRoot](https://github.com/rootless-containers/PRoot)*.  
    57  
    58  
    59  For more details see Aleksa Sarai's [summary](https://rootlesscontaine.rs/) of the state of the art of rootless containers.
    60  
    61  
    62  \* _[PRoot](https://github.com/rootless-containers/PRoot) is a binary that hooks its child processes' kernel-space system calls using `ptrace` to simulate them in the user-space. This is more reliable but slower than hooking libc calls using `LD_PRELOAD` as [fakechroot](https://github.com/dex4er/fakechroot) does it._  
    63  
    64  
    65  ## Installation
    66  Download the binary:
    67  ```
    68  wget -O ctnr https://github.com/mgoltzsche/ctnr/releases/download/v0.7.0-alpha/ctnr.linux-amd64 &&
    69  chmod +x ctnr &&
    70  sudo mv ctnr /usr/local/bin/
    71  ```
    72  If you need [PRoot](https://github.com/rootless-containers/PRoot) or [CNI plugins](https://github.com/containernetworking/plugins)
    73  you can build them by calling `make proot cni-plugins-static` within this repository's directory.
    74  
    75  
    76  ## Build
    77  Build the binary `dist/bin/ctnr` as well as `dist/bin/cni-plugins` on a Linux machine with git, make and docker:
    78  ```
    79  git clone https://github.com/mgoltzsche/ctnr.git
    80  cd ctnr
    81  make
    82  ```  
    83  Install in `/usr/local`:
    84  ```
    85  sudo make install
    86  ```  
    87  Optionally the project can now be opened with LiteIDE running in a ctnr container  
    88  _(Please note that it takes some time to build the LiteIDE container image)_:
    89  ```
    90  make ide
    91  ```
    92  
    93  
    94  ## Examples
    95  
    96  The following examples assume your policy accepts docker images or you have copied [image-policy-example.json](image-policy-example.json) to `/etc/containers/policy.json` on your host.
    97  
    98  ### Create and run container from Docker image
    99  ```
   100  $ ctnr run docker://alpine:3.8 echo hello world
   101  hello world
   102  ```
   103  
   104  ### Create and run Firefox as unprivileged user
   105  Build a Firefox ESR container image `local/firefox:alpine` (cached operation):
   106  ```
   107  $ ctnr image build \
   108  	--from=docker://alpine:3.8 \
   109  	--author='John Doe' \
   110  	--run='apk add --update --no-cache firefox-esr libcanberra-gtk3 adwaita-icon-theme ttf-ubuntu-font-family' \
   111  	--cmd=firefox \
   112  	--tag=local/firefox:alpine
   113  ```  
   114  
   115  Create and run a bundle named `firefox` from the previously built image:
   116  ```
   117  $ ctnr run -b firefox --update \
   118  	--env DISPLAY=$DISPLAY \
   119  	--mount src=/tmp/.X11-unix,dst=/tmp/.X11-unix \
   120  	--mount src=/etc/machine-id,dst=/etc/machine-id,opt=ro \
   121  	local/firefox:alpine
   122  ```  
   123  _(Unfortunately tabs in firefox tend to crash)_
   124  The `-b <BUNDLE>` and `--update` options make this operation idempotent:
   125  The bundle's file system is reused and only recreated when the underlying image has changed.
   126  Use these options to restart containers very quickly. Without them ctnr copies the
   127  image file system on bundle creation which can take some time and disk space depending on the image's size.  
   128  Also these options enable a container update on restart when the base image is frequently updated before the child image is rebuilt using the following command:
   129  ```
   130  $ ctnr image import docker://alpine:3.8
   131  ```
   132  
   133  ### Build Dockerfile as unprivileged user
   134  This example shows how to build a debian-based image with the help of [PRoot](https://github.com/rootless-containers/PRoot).
   135  
   136  Dockerfile `Dockerfile-cowsay`:
   137  ```
   138  FROM debian:9
   139  RUN apt-get update && apt-get install -y cowsay
   140  ENTRYPOINT ["/usr/games/cowsay"]
   141  ```
   142  Build the image (Please note that this works only with `--proot` enabled. With plain ctnr/runc `apt-get` fails to change uid/gid.):
   143  ```
   144  $ ctnr image build --proot --dockerfile Dockerfile-cowsay --tag example/cowsay
   145  ```
   146  Run a container using the previously built image (Please note that `--proot` is not required anymore):
   147  ```
   148  $ ctnr run example/cowsay hello from container
   149   ______________________
   150  < hello from container >
   151   ----------------------
   152          \   ^__^
   153           \  (oo)\_______
   154              (__)\       )\/\
   155                  ||----w |
   156                  ||     ||
   157  ```
   158  
   159  
   160  ### Port mapping
   161  ctnr supports port mapping using the `-p, --publish` option.
   162  Unprivileged users can use the `--proot` option in addition.
   163  
   164  #### Port mapping as root using a contained CNI network
   165  When a container is run as root in a contained network (`--network default`, default as root)
   166  the [portmap CNI plugin](https://github.com/containernetworking/plugins/tree/master/plugins/meta/portmap)
   167  is used to map ports from a specified IP or the host network to the container.
   168  
   169  Map the container network's port 80 to port 8080 on the host:
   170  ```
   171  $ sudo ctnr run -p 8080:80 docker://alpine:3.8 nc -l -p 80 -e echo hello from container
   172  ```
   173  Connectivity test on the host on another shell:
   174  ```
   175  $ nc 127.0.0.1 8080
   176  hello from container
   177  ```
   178  
   179  #### Port mapping as unprivileged user using proot
   180  Unprivileged users can enable the `--proot` option to map ports
   181  within the host network namespace on a syscall level.
   182  
   183  Map `bind`/`connect` syscalls with port 80 to port 8080:
   184  ```
   185  $ ctnr run --proot -p 8080:80 docker://alpine:3.8 nc -l -p 80 -e echo hello from container
   186  ```
   187  You can now also run another container using the same port as long as you don't
   188  map it on the same host port (proot maps it to a random free port and back within the container):
   189  ```
   190  $ ctnr run --proot docker://alpine:3.8 /bin/sh -c 'nc -l -p 80 -e echo hello & sleep 1; timeout -t 1 nc 127.0.0.1 80'
   191  hello
   192  ```
   193  Connectivity test on the host on another shell:
   194  ```
   195  $ nc 127.0.0.1 8080
   196  hello from container
   197  ```
   198  
   199  
   200  ## OCI specs and this implementation
   201  
   202  An *[OCI image](https://github.com/opencontainers/image-spec/tree/v1.0.0)* provides a base [configuration](https://github.com/opencontainers/image-spec/blob/v1.0.0/config.md) and file system to create an OCI bundle from. The file system consists of a list of layers represented by tar files each containing the diff to its predecessor.  
   203  ctnr manages images in its local store directory in the [OCI image layout format](https://github.com/opencontainers/image-spec/blob/v1.0.0/image-layout.md).
   204  Images are imported into the local store using the [containers/image](https://github.com/containers/image) library.
   205  A new bundle is created by extracting the image's file system into a directory and [deriving](https://github.com/opencontainers/image-spec/blob/v1.0.0/conversion.md) the bundle's default configuration from the image's configuration plus user-defined options.
   206  
   207  
   208  An *[OCI bundle](https://github.com/opencontainers/runtime-spec/blob/v1.0.0/bundle.md)* describes a container by
   209  a [configuration](https://github.com/opencontainers/runtime-spec/blob/v1.0.0/config.md) and a file system.
   210  Basically it is a directory containing a `config.json` file with the configuration and a sub directory with the root file system.  
   211  ctnr manages bundles in its local store directory. Alternatively a custom directory can also be used as bundle.
   212  OCI bundles generated by ctnr can also be run with plain [runc](https://github.com/opencontainers/runc/).
   213  
   214  
   215  An *[OCI container](https://github.com/opencontainers/runtime-spec/blob/v1.0.0/runtime.md)* is a host-specific bundle instance.
   216  On Linux it is a set of namespaces in which a configured process can be run.  
   217  ctnr provides two wrapper implementations of the OCI runtime reference implementation
   218  [runc/libcontainer](https://github.com/opencontainers/runc/blob/v1.0.0-rc5/libcontainer/README.md)
   219  to either use an external runc binary or use libcontainer (no runtime dependencies!) controlled by a compiler flag.
   220  
   221  
   222  ## Related tools
   223  
   224  - [cri-o](https://github.com/kubernetes-incubator/cri-o)
   225  - [containerd](https://containerd.io/)
   226  - [docker](https://www.docker.com/)
   227  - [lxc](https://linuxcontainers.org/lxc/introduction/)
   228  - [rkt](https://rkt.io)
   229  - [rkt-compose](https://github.com/mgoltzsche/rkt-compose)
   230  - [runc](https://github.com/opencontainers/runc)
   231  - [runrootless](https://github.com/AkihiroSuda/runrootless)
   232  - [singularity](http://singularity.lbl.gov/)
   233  - [skopeo](https://github.com/projectatomic/skopeo), [umoci](https://github.com/openSUSE/umoci), [orca-build](https://github.com/cyphar/orca-build)
   234  - [udocker](https://github.com/indigo-dc/udocker)
   235  
   236  
   237  ## Roadmap
   238  
   239  - system.Context aware processes, unpacking/packing images
   240  - improved multi-user support (store per user group, file permissions, lock location)
   241  - CLI integration tests
   242  - advanced rootless networking (using a network daemon run by root)
   243  - separate OCI CNI network hook binary
   244  - health check
   245  - improved Docker Compose support
   246  - service discovery integration (hook / DNS; consul, etcd)
   247  - detached mode
   248  - systemd integration (cgroup, startup notification)
   249  - advanced logging
   250  - support additional read-only image stores
   251