Run, Run, Run
Overseen by the Open Container Initiative, runC is an open source engine and specification for running containers that adhere to the OCI specification, including Docker containers. The idea with runC, in tandem with the image specification, is to provide an open source container free of any vendor control or cloud stack. It is based on Docker’s LibContainer, the company’s own core container engine, which serves as the interface to the operating system.
On its own runC can run Docker images. It requires two elements. One is a set of configuration instructions. These are the command line flags usually appended to the Docker run command; runC reads them from a manifest file instead, config.json. You can fill it out by hand, or runC can create one automatically.
RunC also requires a root file system from which it can operate the container. The user can manually create a directory, which would serve as the root for the container, or the file system can be exported from the container itself, through the docker export command.
“With those two pieces of information, runC can execute a container,” Estes said.
There a number scenarios where operating runC might be preferable instead of a more full-featured container engine such as Docker’s own, Estes explained.
It could provide the basis for porting containers to new environments — such as Solaris Zones for instance — or for creating new OCI compliant container engines or platforms. Intel’s Clear Containers and Hyper.sh leverage runC.
RunC is the place to test out new features, such as checkpoint restore, which is now being cooked up in runC. Docker’s seccomp, which was introduced in Docker 1.10, started out in runC.
“RunC is the place where you want that first implementation so higher layers can exploit that capability,” Estes said.
Developers may also find runC handy in that it provides an easy, clean interface to rapidly iterate changes in file systems and configurations. “I don’t have to worry about storage or the back-end,” Estes said.
Although runC itself can create a container manifest (“runc spec > config.json“), the resulting file is pretty generic, and will probably still have to be filled in with many environmental variables. Why do that manually when the Docker engine captures that information automatically?
Riddler, on the other hand, allows the user to create a full configuration file for a container merely by running the container and allowing Riddler to slurp draw the necessary details from the Docker engine itself. The Riddler builds a configuration that exactly matches the profile of the container that just ran. “If I had volumes mounted, if I used a read-only file system, if I used user namespaces, all those things were copied over to my runC config,” Estes said.
Riddler will also fill in some typical settings. For instance, seccomp settings are made with many of the same assumptions that the Docker engine makes, such as not allowing system calls. It also captures any commands that were originally run alongside the docker run command. In Estes’ demo, he also ran the Linux date command to show how that command got copied over as well.
Other aspects still must be done manually. Networking is not managed by OCI yet, so those settings must be entered. Riddler provides a hook into netns, which allows the user to prepopulate the network settings. The user still has to create a file system for the container. For this part Estes created a script for himself to match the user network namespaces information that Riddler captured.
After these steps, “We have an environment that is very similar to a simple Docker run,” Estes said.
As an example of how this could be used, Estes demonstrated how to replicate a recently run container with NGINX. He used the -d flag to run the software in daemon mode, which was carried over to runC. He also ran a container with the Lynx text browser.
In this scenario, runC can make things easier for developers in a number of ways. Devs can easily change the configuration of a running container, through the manifest. The containers can access other directories within the developer’s directory tree.
“In a development mode, that simplicity may be really useful for what you are doing,” Estes said.
RunC also provides a way to work with Linux Capabilities has a set of system calls or resource actions typically associated with superuser privileges that can be tailored to individual cases. Docker, for instance, has a set of Linux Capability settings. Through the manifest, runC provides a list of the exact settings, allowing the dev to easily modify them.
For instance, the CAP_NET_RAW setting controls the ability for the users to execute low-level TCP functions, such as the ability to execute Internet Control Message Protocol (ICMP), used for the ping command. A quick demonstration showed that ping did work initially, then after the Estes made the change, no longer worked. Likewise, CAP_SYS_ADMIN can be toggled to allow the users to read and set the host name, or not, among other features.