Skip to content

Commit

Permalink
*: re-org the spec
Browse files Browse the repository at this point in the history
We had an in-person spec discussion, lets separate the spec into some
high-level sections to clarify future discussion.

Crosby agreed to let me merge to master :)
  • Loading branch information
Brandon Philips committed Jun 25, 2015
1 parent 33bd340 commit 5d2eb18
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 514 deletions.
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,47 @@
# Open Container Specifications

This project is where the Open Container Project Specifications are written. This is a work in progress. We should have a first draft by end of July 2015.
* [Open Container Runtime](runtime.md)

Table of Contents

- [Filesystem Bundle](bundle.md)
- [Container Configuration](config.md)
- [Linux Specific Configuration](config-linux.md)
- [Runtime and Lifecycle](runtime.md)

# The 5 principles of Standard Containers

Define a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in a format that is self-describing and portable, so that any compliant runtime can run it without extra dependencies, regardless of the underlying machine and the contents of the container.

The specification for Standard Containers is straightforward. It mostly defines 1) a file format, 2) a set of standard operations, and 3) an execution environment.

A great analogy for this is the shipping container. Just like how Standard Containers are a fundamental unit of software delivery, shipping containers are a fundamental unit of physical delivery.

## 1. Standard operations

Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, Standard Containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged.

## 2. Content-agnostic

Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts.

## 3. Infrastructure-agnostic

Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest

routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions.

## 4. Designed for automation

Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterparts, are extremely well-suited for automation. In fact, you could say automation is their secret weapon.

Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods.

Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider.

## 5. Industrial-grade delivery

There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded onto the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away.

With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality.

31 changes: 31 additions & 0 deletions bundle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Bundle Container Format

This section defines a format for encoding a container as a *bundle* - a directory organized in a certain way, and containing all the necessary data and metadata for any compliant runtime to perform all standard operations against it. See also *[Mac OS application bundle*s](http://en.wikipedia.org/wiki/Bundle_%28OS_X%29) for a similar use of the term *bundle*.

The format does not define distribution. In other words, it only specifies how a container must be stored on a local filesystem, for consumption by a runtime. It does not specify how to transfer a container between computers, how to discover containers, or assign names or versions to them. Any distribution method capable of preserving the original layout of a container, as specified here, is considered compliant.

A standard container bundle is made of the following 4 parts:

- A top-level directory holding everything else
- One or more content directories
- A configuration file

# Directory layout

A Standard Container bundle is a directory containing all the content needed to load and run a container. This includes its configuration file, content directories, and cryptographic signatures. The main property of this directory layout is that it can be moved as a unit to another machine and run the same container.

One or more *content directories* may be adjacent to the configuration file. This at least includes the root filesystem (referenced in the configuration by the *rootfs* field), and any number of and other related content (signatures, other configs, etc.). The interpretation of these resources is specified in the configuration.

```
/
!
-- config.json
!
--- rootfs1
!
--- rootfs2
```

The syntax and semantics for config.json are described in this specification.

One or more content directories can be specified as root file systems for containers. They COULD be called rootfs..10^100 but SHALL be called whatever you want.
49 changes: 49 additions & 0 deletions config-linux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Linux

## Linux Namespaces

```
"namespaces": [
"process",
"network",
"mount",
"ipc",
"uts"
],
```

Namespaces for the container are specified as an array of strings under the namespaces key. The list of constants that can be used is portable across operating systems. Here is a table mapping these names to native OS equivalent.

For Linux the mapping is

* process -> pid: the process ID number space is specific to the container, meaning that processes in different PID namespaces can have the same PID

* network -> network: the container will have an isolated network stack

* mount -> mnt container can only access mounts local to itself

* ipc -> ipc processes in the container can only communicate with other processes inside same container

* uts -> uts Hostname and NIS domain name are specific to the container

## Linux Control groups

## Linux Seccomp

## Linux Process Capabilities

```
"capabilities": [
"AUDIT_WRITE",
"KILL",
"NET_BIND_SERVICE"
],
```

capabilities is an array of Linux process capabilities. Valid values are the string after `CAP_` for capabilities defined in http://linux.die.net/man/7/capabilities

## SELinux

## Apparmor


209 changes: 209 additions & 0 deletions config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# Configuration file

The container’s top-level directory MUST contain a configuration file called config.json. The configuration file MUST comply with the Open Container Configuration JSON Schema attached to this document. For now the schema is defined in [spec.go](https://github.com/opencontainers/runc/blob/master/spec.go) and [spec_linux.go](https://github.com/opencontainers/runc/blob/master/spec_linux.go), this will be moved to a JSON schema overtime.

The configuration file contains metadata necessary to implement standard operations against the container. This includes processes to run, environment variables to inject, sandboxing features to use, etc.

Below is a detailed description of each field defined in the configuration format.

## Manifest version

The `version` element specifies the version of the OCF specification which the container complies with. If the container is compliant with multiple versions, it SHOULD advertise the most recent known version to be supported.

*Linux example*

```
"version": "1",
```

## File system configuration

Each container has exactly one *root filesystem*, and any number of optional *mounted filesystems*. Both need to be declared in the manifest.

The rootfs string element specifies the path to the root file system for the container, relative to the path where the manifest is. A directory MUST exist at the relative path declared by the field.

The readonlyRootfs is an optional boolean element which defaults to false. If it is true, access to the root file system MUST be read-only for all processes running inside it. whether you want the root file system to be readonly or not for the processes running on it.

*Example (Linux)*

```
"rootfs": "rootfs",
"readonlyRootfs": true,
```

*Example (Windows)*

```
"rootfs": "My Fancy Root FS",
"readonlyRootfs": true,
```

Additional file systems can be declared as "mounts", declared by the the array element mounts. The parameters are similar to the ones in Linux mount system call. [http://linux.die.net/man/2/mount](http://linux.die.net/man/2/mount)

type: Linux, *filesystemtype* argument supported by the kernel are listed in */proc/filesystems* (e.g., "minix", "ext2", "ext3", "jfs", "xfs", "reiserfs", "msdos", "proc", "nfs", "iso9660"). Windows: ntfs

source: a device name, but can also be a directory name or a dummy. Windows, the volume name that is the target of the mount point. \\?\Volume\{GUID}\ (on Windows source is called target)

destination: where the file system is mounted in the container.

options: in the fstab format [https://wiki.archlinux.org/index.php/Fstab](https://wiki.archlinux.org/index.php/Fstab).

*Example (Linux)*

```
"mounts": [
{
"type": "proc",
"source": "proc",
"destination": "/proc",
"options": ""
},
{
"type": "tmpfs",
"source": "tmpfs",
"destination": "/dev",
"options": "nosuid,strictatime,mode=755,size=65536k"
},
{
"type": "devpts",
"source": "devpts",
"destination": "/dev/pts",
"options": "nosuid,noexec,newinstance,ptmxmode=0666,mode=0620,gid=5"
},
{
"type": "tmpfs",
"source": "shm",
"destination": "/dev/shm",
"options": "nosuid,noexec,nodev,mode=1777,size=65536k"
},
]
```

*Example (Windows)*
```
"mounts": [
{
"type": "ntfs",
"source": "\\?\Volume\{2eca078d-5cbc-43d3-aff8-7e8511f60d0e}\
",
"destination": "C:\Users\crosbymichael\My Fancy Mount Point\",
"options": ""
}
```

See links for details about mountvol in Windows.

[https://msdn.microsoft.com/en-us/library/windows/desktop/aa365561(v=vs.85).aspx](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365561(v=vs.85).aspx)

[http://ss64.com/nt/mountvol.html](http://ss64.com/nt/mountvol.html)

### Processes configuration

- Command-line arguments
- Terminal allocation
- User ID
- Environment variables
- Working directory

*Example (Linux)*
```
"processes": [
{
"tty": true,
"user": "daemon",
"args": [
"sh"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": ""
}
],
```

The processes to be created inside the container are specified in a processes array. They are started in order.

```
"processes": [...]
```

The command to start a process is specified in an array of args. It will be run in the working directory specified in the string cwd.

Environment variables are specified is an array called env.

Elements in the array are specified as Strings in the form "KEY=value"

The user inside the container under which the process is running is specified under the user key.

tty is a boolean that lets you specify whether you want a terminal attached to that process. tty cannot be set to true for more than one process in the array, else oc returns the error code THERE_CAN_BE_ONLY_ONE_TTY.

*Example (Windows)*

```
"processes": [
{
"tty": true,
"user": "Contoso\ScottGu",
"args": [
"cmd.exe"
],
"env": [
"PATH=D:\Windows\Microsoft.NET\Framework\v4.0.30319;D:\Program Files (x86)\Git\bin",
"TERM=cygwin"
],
"cwd": ""
}
],
```

hostname is a string specifying the hostname for that container as it is accessible to processes running in it.

### Resource Constraints

*Example*

```
"hostname": "mrsdalloway",
```

The number of CPUs is specified as a positive decimal under the key cpus.

The amount of memory allocated to this container is specified under the memory key, as an integer and is expressed in MBb.

If the cpu or memory requested are too high for the underlying environment capabilities, an error code NOT_ENOUGH_CPU or NOT_ENOUGH_MEM will be returned.


### Access to devices

```
"devices": [
"null",
"random",
"full",
"tty",
"zero",
"urandom"
],
```

Devices is an array specifying the list of devices from the host to make available in the container.

The array contains names: for each name, the device /dev/<name> will be made available inside the container.

## Machine-specific configuration

```
"os": "linux",
"arch": "amd64",
```

os specifies the operating system family this image must run on.

arch specifies the instruction set for which the binaries in the image have been compiled.

values for os and arch must be in the list specified by by the Go Language documentation for $GOOS and $GOARCH https://golang.org/doc/install/source#environment

OS or architecture specific settings can be added in the json file. They will be interpreted by the implementation depending on the os and arch values specified at the top of the manifest.
Loading

0 comments on commit 5d2eb18

Please sign in to comment.