{"id":13581893,"url":"https://github.com/mgoltzsche/ctnr","last_synced_at":"2025-10-07T03:30:52.118Z","repository":{"id":57522289,"uuid":"99162281","full_name":"mgoltzsche/ctnr","owner":"mgoltzsche","description":"rootless runc-based container engine - deprecated in favour of podman","archived":true,"fork":false,"pushed_at":"2019-08-02T00:09:35.000Z","size":22332,"stargazers_count":33,"open_issues_count":2,"forks_count":2,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-01-25T12:33:25.665Z","etag":null,"topics":["cli","cni","container-engine","containers","docker","docker-image","image-build","libcontainer","oci","oci-bundle","oci-image","oci-images","oci-runtime","proot","rootless","rootless-containers","runc","unprivileged","unprivileged-user","unprivileged-users"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mgoltzsche.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-02T21:26:43.000Z","updated_at":"2024-08-16T14:40:25.000Z","dependencies_parsed_at":"2022-09-26T19:13:32.543Z","dependency_job_id":null,"html_url":"https://github.com/mgoltzsche/ctnr","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mgoltzsche/ctnr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoltzsche%2Fctnr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoltzsche%2Fctnr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoltzsche%2Fctnr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoltzsche%2Fctnr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mgoltzsche","download_url":"https://codeload.github.com/mgoltzsche/ctnr/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoltzsche%2Fctnr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278715508,"owners_count":26033296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cni","container-engine","containers","docker","docker-image","image-build","libcontainer","oci","oci-bundle","oci-image","oci-images","oci-runtime","proot","rootless","rootless-containers","runc","unprivileged","unprivileged-user","unprivileged-users"],"created_at":"2024-08-01T15:02:18.266Z","updated_at":"2025-10-07T03:30:47.110Z","avatar_url":"https://github.com/mgoltzsche.png","language":"Go","readme":"ctnr [![Build Status](https://travis-ci.org/mgoltzsche/ctnr.svg?branch=master)](https://travis-ci.org/mgoltzsche/ctnr)\n=\n\nctnr is a CLI built on top of [runc](https://github.com/opencontainers/runc)\nto manage and build OCI images as well as containers on Linux.  \nctnr aims to ease system container creation and execution as unprivileged user.  \nAlso ctnr is a tool to experiment with runc features.\n\nTHIS PROJECT IS NOT MAINTAINED ANYMORE IN FAVOUR OF [podman](https://github.com/containers/libpod).\n\n## Features\n- OCI bundle and container preparation as well as execution as unprivileged user using [runc](https://github.com/opencontainers/runc)\n- OCI image build as unprivileged user\n- Simple concurrently accessible image and bundle store\n- Image and bundle file system creation (based on [umoci](https://github.com/openSUSE/umoci))\n- Various image formats and transports supported by [containers/image](https://github.com/containers/image)\n- Container networking using [CNI](https://github.com/containernetworking/cni) (optional, requires root, as OCI runtime hook)\n- [Dockerfile](https://docs.docker.com/engine/reference/builder/) support\n- [Docker Compose 3](https://docs.docker.com/compose/compose-file/) support (subset) using [docker/cli](https://github.com/docker/cli/) (WIP)\n- Easy to learn: [docker](https://www.docker.com/)-like CLI\n- Easy installation: single statically linked binary (plus optional binaries: CNI plugins, proot) and convention over configuration\n\n\n## Rootless containers\n\nConcerning accessibility, usability and security a rootless container engine has several advantages:\n- **Containers can be run by unprivileged users.**  \n  _Required in restrictive environments and useful for graphical applications._\n- **Container images can be built in almost every Linux environment.**  \n  _More flexibility in unprivileged builds - nesting containers is also possible (see [experiments and limitations](nested-containers.md))._\n- **A higher degree and more flexible level of security.**  \n  _Less likely for an attacker to gain root access when run as unprivileged user._  \n  _User/group-based container access control._\n  _Separation of responsibilities._\n\n\n### Limitations \u0026 challenges\n\nContainer execution as unprivileged user is limited:\n\n\n**Container networking is limited.**\nWith plain ctnr/runc only the host network can be used.\nThe standard [CNI plugins](https://github.com/containernetworking/plugins) require root privileges.  \nOne workaround is to map ports on the host network using [PRoot](https://github.com/rootless-containers/PRoot)* accepting bad performance.  \nA better solution is to use [slirp4netns](https://github.com/rootless-containers/slirp4netns) which emulates the TCP/IP stack in a user namespace efficiently.\nIt can be used with ctnr via the [slirp-cni-plugin](https://github.com/mgoltzsche/slirp-cni-plugin).\nOnce container initialization is also moved into a user namespace with slirp the standard CNI plugins can be used again.\nFor 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)).  \n\n\n**Inside the container a process' or file's user cannot be changed.**\nThis 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).\nUnfortunately this stops many package managers as well as official docker images from working:\nWhile `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.  \nTo overcome this limitation ctnr supports the `user.rootlesscontainers` xattr and integrates with [PRoot](https://github.com/rootless-containers/PRoot)*.  \n\n\nFor more details see Aleksa Sarai's [summary](https://rootlesscontaine.rs/) of the state of the art of rootless containers.\n\n\n\\* _[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._  \n\n\n## Installation\nDownload the binary:\n```\nwget -O ctnr https://github.com/mgoltzsche/ctnr/releases/download/v0.7.0-alpha/ctnr.linux-amd64 \u0026\u0026\nchmod +x ctnr \u0026\u0026\nsudo mv ctnr /usr/local/bin/\n```\nIf you need [PRoot](https://github.com/rootless-containers/PRoot) or [CNI plugins](https://github.com/containernetworking/plugins)\nyou can build them by calling `make proot cni-plugins-static` within this repository's directory.\n\n\n## Build\nBuild the binary `dist/bin/ctnr` as well as `dist/bin/cni-plugins` on a Linux machine with git, make and docker:\n```\ngit clone https://github.com/mgoltzsche/ctnr.git\ncd ctnr\nmake\n```  \nInstall in `/usr/local`:\n```\nsudo make install\n```  \nOptionally the project can now be opened with LiteIDE running in a ctnr container  \n_(Please note that it takes some time to build the LiteIDE container image)_:\n```\nmake ide\n```\n\n\n## Examples\n\nThe 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.\n\n### Create and run container from Docker image\n```\n$ ctnr run docker://alpine:3.8 echo hello world\nhello world\n```\n\n### Create and run Firefox as unprivileged user\nBuild a Firefox ESR container image `local/firefox:alpine` (cached operation):\n```\n$ ctnr image build \\\n\t--from=docker://alpine:3.8 \\\n\t--author='John Doe' \\\n\t--run='apk add --update --no-cache firefox-esr libcanberra-gtk3 adwaita-icon-theme ttf-ubuntu-font-family' \\\n\t--cmd=firefox \\\n\t--tag=local/firefox:alpine\n```  \n\nCreate and run a bundle named `firefox` from the previously built image:\n```\n$ ctnr run -b firefox --update \\\n\t--env DISPLAY=$DISPLAY \\\n\t--mount src=/tmp/.X11-unix,dst=/tmp/.X11-unix \\\n\t--mount src=/etc/machine-id,dst=/etc/machine-id,opt=ro \\\n\tlocal/firefox:alpine\n```  \n_(Unfortunately tabs in firefox tend to crash)_\nThe `-b \u003cBUNDLE\u003e` and `--update` options make this operation idempotent:\nThe bundle's file system is reused and only recreated when the underlying image has changed.\nUse these options to restart containers very quickly. Without them ctnr copies the\nimage file system on bundle creation which can take some time and disk space depending on the image's size.  \nAlso 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:\n```\n$ ctnr image import docker://alpine:3.8\n```\n\n### Build Dockerfile as unprivileged user\nThis example shows how to build a debian-based image with the help of [PRoot](https://github.com/rootless-containers/PRoot).\n\nDockerfile `Dockerfile-cowsay`:\n```\nFROM debian:9\nRUN apt-get update \u0026\u0026 apt-get install -y cowsay\nENTRYPOINT [\"/usr/games/cowsay\"]\n```\nBuild the image (Please note that this works only with `--proot` enabled. With plain ctnr/runc `apt-get` fails to change uid/gid.):\n```\n$ ctnr image build --proot --dockerfile Dockerfile-cowsay --tag example/cowsay\n```\nRun a container using the previously built image (Please note that `--proot` is not required anymore):\n```\n$ ctnr run example/cowsay hello from container\n ______________________\n\u003c hello from container \u003e\n ----------------------\n        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n                ||----w |\n                ||     ||\n```\n\n\n### Port mapping\nctnr supports port mapping using the `-p, --publish` option.\nUnprivileged users can use the `--proot` option in addition.\n\n#### Port mapping as root using a contained CNI network\nWhen a container is run as root in a contained network (`--network default`, default as root)\nthe [portmap CNI plugin](https://github.com/containernetworking/plugins/tree/master/plugins/meta/portmap)\nis used to map ports from a specified IP or the host network to the container.\n\nMap the container network's port 80 to port 8080 on the host:\n```\n$ sudo ctnr run -p 8080:80 docker://alpine:3.8 nc -l -p 80 -e echo hello from container\n```\nConnectivity test on the host on another shell:\n```\n$ nc 127.0.0.1 8080\nhello from container\n```\n\n#### Port mapping as unprivileged user using proot\nUnprivileged users can enable the `--proot` option to map ports\nwithin the host network namespace on a syscall level.\n\nMap `bind`/`connect` syscalls with port 80 to port 8080:\n```\n$ ctnr run --proot -p 8080:80 docker://alpine:3.8 nc -l -p 80 -e echo hello from container\n```\nYou can now also run another container using the same port as long as you don't\nmap it on the same host port (proot maps it to a random free port and back within the container):\n```\n$ ctnr run --proot docker://alpine:3.8 /bin/sh -c 'nc -l -p 80 -e echo hello \u0026 sleep 1; timeout -t 1 nc 127.0.0.1 80'\nhello\n```\nConnectivity test on the host on another shell:\n```\n$ nc 127.0.0.1 8080\nhello from container\n```\n\n\n## OCI specs and this implementation\n\nAn *[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.  \nctnr 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).\nImages are imported into the local store using the [containers/image](https://github.com/containers/image) library.\nA 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.\n\n\nAn *[OCI bundle](https://github.com/opencontainers/runtime-spec/blob/v1.0.0/bundle.md)* describes a container by\na [configuration](https://github.com/opencontainers/runtime-spec/blob/v1.0.0/config.md) and a file system.\nBasically it is a directory containing a `config.json` file with the configuration and a sub directory with the root file system.  \nctnr manages bundles in its local store directory. Alternatively a custom directory can also be used as bundle.\nOCI bundles generated by ctnr can also be run with plain [runc](https://github.com/opencontainers/runc/).\n\n\nAn *[OCI container](https://github.com/opencontainers/runtime-spec/blob/v1.0.0/runtime.md)* is a host-specific bundle instance.\nOn Linux it is a set of namespaces in which a configured process can be run.  \nctnr provides two wrapper implementations of the OCI runtime reference implementation\n[runc/libcontainer](https://github.com/opencontainers/runc/blob/v1.0.0-rc5/libcontainer/README.md)\nto either use an external runc binary or use libcontainer (no runtime dependencies!) controlled by a compiler flag.\n\n\n## Related tools\n\n- [cri-o](https://github.com/kubernetes-incubator/cri-o)\n- [containerd](https://containerd.io/)\n- [docker](https://www.docker.com/)\n- [lxc](https://linuxcontainers.org/lxc/introduction/)\n- [rkt](https://rkt.io)\n- [rkt-compose](https://github.com/mgoltzsche/rkt-compose)\n- [runc](https://github.com/opencontainers/runc)\n- [runrootless](https://github.com/AkihiroSuda/runrootless)\n- [singularity](http://singularity.lbl.gov/)\n- [skopeo](https://github.com/projectatomic/skopeo), [umoci](https://github.com/openSUSE/umoci), [orca-build](https://github.com/cyphar/orca-build)\n- [udocker](https://github.com/indigo-dc/udocker)\n\n\n## Roadmap\n\n- system.Context aware processes, unpacking/packing images\n- improved multi-user support (store per user group, file permissions, lock location)\n- CLI integration tests\n- advanced rootless networking (using a network daemon run by root)\n- separate OCI CNI network hook binary\n- health check\n- improved Docker Compose support\n- service discovery integration (hook / DNS; consul, etcd)\n- detached mode\n- systemd integration (cgroup, startup notification)\n- advanced logging\n- support additional read-only image stores\n\n","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgoltzsche%2Fctnr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmgoltzsche%2Fctnr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgoltzsche%2Fctnr/lists"}