Skip to content
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.

Commit

Permalink
Merge pull request #388 from docker/api
Browse files Browse the repository at this point in the history
Merge API Branch into Master
  • Loading branch information
vmarmol committed Feb 20, 2015
2 parents f4a4391 + 7eceabd commit 5b73860
Show file tree
Hide file tree
Showing 150 changed files with 9,185 additions and 5,640 deletions.
1 change: 0 additions & 1 deletion .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ script:
- bash /go/src/github.com/docker/docker/hack/make/validate-dco
- bash /go/src/github.com/docker/docker/hack/make/validate-gofmt
- export GOPATH="$GOPATH:/go:$(pwd)/vendor" # Drone mucks with our GOPATH
- go get golang.org/x/tools/cmd/vet && go vet ./...
- make direct-test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nsinit/nsinit
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ direct-build:

direct-install:
go install -v $(GO_PACKAGES)
local:
go test -v
2 changes: 1 addition & 1 deletion PRINCIPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ In the design and development of libcontainer we try to follow these principles:
* Less code is better.
* Fewer components are better. Do you really need to add one more class?
* 50 lines of straightforward, readable code is better than 10 lines of magic that nobody can understand.
* Don't do later what you can do now. "//FIXME: refactor" is not acceptable in new code.
* Don't do later what you can do now. "//TODO: refactor" is not acceptable in new code.
* When hesitating between two options, choose the one that is easier to reverse.
* "No" is temporary; "Yes" is forever. If you're not sure about a new feature, say no. You can change your mind later.
* Containers must be portable to the greatest possible number of machines. Be suspicious of any change which makes machines less interchangeable.
Expand Down
155 changes: 138 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,169 @@
## libcontainer - reference implementation for containers [![Build Status](https://ci.dockerproject.com/github.com/docker/libcontainer/status.svg?branch=master)](https://ci.dockerproject.com/github.com/docker/libcontainer)

### Note on API changes:
Libcontainer provides a native Go implementation for creating containers
with namespaces, cgroups, capabilities, and filesystem access controls.
It allows you to manage the lifecycle of the container performing additional operations
after the container is created.

Please bear with us while we work on making the libcontainer API stable and something that we can support long term. We are currently discussing the API with the community, therefore, if you currently depend on libcontainer please pin your dependency at a specific tag or commit id. Please join the discussion and help shape the API.

#### Background
#### Container
A container is a self contained execution environment that shares the kernel of the
host system and which is (optionally) isolated from other containers in the system.

libcontainer specifies configuration options for what a container is. It provides a native Go implementation for using Linux namespaces with no external dependencies. libcontainer provides many convenience functions for working with namespaces, networking, and management.
#### Using libcontainer

To create a container you first have to initialize an instance of a factory
that will handle the creation and initialization for a container.

#### Container
A container is a self contained execution environment that shares the kernel of the host system and which is (optionally) isolated from other containers in the system.
Because containers are spawned in a two step process you will need to provide
arguments to a binary that will be executed as the init process for the container.
To use the current binary that is spawning the containers and acting as the parent
you can use `os.Args[0]` and we have a command called `init` setup.

```go
initArgs := []string{os.Args[0], "init"}

root, err := libcontainer.New("/var/lib/container", initArgs)
if err != nil {
log.Fatal(err)
}
```

libcontainer may be used to execute a process in a container. If a user tries to run a new process inside an existing container, the new process is added to the processes executing in the container.
Once you have an instance of the factory created we can create a configuration
struct describing how the container is to be created. A sample would look similar to this:

```go
config := &configs.Config{
Rootfs: rootfs,
Capabilities: []string{
"CHOWN",
"DAC_OVERRIDE",
"FSETID",
"FOWNER",
"MKNOD",
"NET_RAW",
"SETGID",
"SETUID",
"SETFCAP",
"SETPCAP",
"NET_BIND_SERVICE",
"SYS_CHROOT",
"KILL",
"AUDIT_WRITE",
},
Namespaces: configs.Namespaces([]configs.Namespace{
{Type: configs.NEWNS},
{Type: configs.NEWUTS},
{Type: configs.NEWIPC},
{Type: configs.NEWPID},
{Type: configs.NEWNET},
}),
Cgroups: &configs.Cgroup{
Name: "test-container",
Parent: "system",
AllowAllDevices: false,
AllowedDevices: configs.DefaultAllowedDevices,
},

Devices: configs.DefaultAutoCreatedDevices,
Hostname: "testing",
Networks: []*configs.Network{
{
Type: "loopback",
Address: "127.0.0.1/0",
Gateway: "localhost",
},
},
Rlimits: []configs.Rlimit{
{
Type: syscall.RLIMIT_NOFILE,
Hard: uint64(1024),
Soft: uint64(1024),
},
},
}
```

Once you have the configuration populated you can create a container:

```go
container, err := root.Create("container-id", config)
```

To spawn bash as the initial process inside the container and have the
processes pid returned in order to wait, signal, or kill the process:

#### Root file system
```go
process := &libcontainer.Process{
Args: []string{"/bin/bash"},
Env: []string{"PATH=/bin"},
User: "daemon",
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}

A container runs with a directory known as its *root file system*, or *rootfs*, mounted as the file system root. The rootfs is usually a full system tree.
pid, err := container.Start(process)
if err != nil {
log.Fatal(err)
}


#### Configuration
// wait for the process to finish.
wait(pid)

A container is initially configured by supplying configuration data when the container is created.
// destroy the container.
container.Destroy()
```

Additional ways to interact with a running container are:

```go
// return all the pids for all processes running inside the container.
processes, err := container.Processes()

// get detailed cpu, memory, io, and network statistics for the container and
// it's processes.
stats, err := container.Stats()


// pause all processes inside the container.
container.Pause()

// resume all paused processes.
container.Resume()
```


#### nsinit

`nsinit` is a cli application which demonstrates the use of libcontainer. It is able to spawn new containers or join existing containers, based on the current directory.
`nsinit` is a cli application which demonstrates the use of libcontainer.
It is able to spawn new containers or join existing containers. A root
filesystem must be provided for use along with a container configuration file.

To use `nsinit`, cd into a Linux rootfs and copy a `container.json` file into the directory with your specified configuration. Environment, networking, and different capabilities for the container are specified in this file. The configuration is used for each process executed inside the container.
To use `nsinit`, cd into a Linux rootfs and copy a `container.json` file into
the directory with your specified configuration. Environment, networking,
and different capabilities for the container are specified in this file.
The configuration is used for each process executed inside the container.

See the `sample_configs` folder for examples of what the container configuration should look like.

To execute `/bin/bash` in the current directory as a container just run the following **as root**:
```bash
nsinit exec /bin/bash
nsinit exec --tty /bin/bash
```

If you wish to spawn another process inside the container while your current bash session is running, run the same command again to get another bash shell (or change the command). If the original process (PID 1) dies, all other processes spawned inside the container will be killed and the namespace will be removed.
If you wish to spawn another process inside the container while your
current bash session is running, run the same command again to
get another bash shell (or change the command). If the original
process (PID 1) dies, all other processes spawned inside the container
will be killed and the namespace will be removed.

You can identify if a process is running in a container by looking to see if `state.json` is in the root of the directory.
You can identify if a process is running in a container by
looking to see if `state.json` is in the root of the directory.

You may also specify an alternate root place where the `container.json` file is read and where the `state.json` file will be saved.
You may also specify an alternate root place where
the `container.json` file is read and where the `state.json` file will be saved.

#### Future
See the [roadmap](ROADMAP.md).
Expand Down
21 changes: 0 additions & 21 deletions api_temp.go

This file was deleted.

1 change: 0 additions & 1 deletion apparmor/apparmor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ func ApplyProfile(name string) error {
if name == "" {
return nil
}

cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))

Expand Down
53 changes: 26 additions & 27 deletions cgroups/cgroups.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,35 @@ package cgroups
import (
"fmt"

"github.com/docker/libcontainer/devices"
"github.com/docker/libcontainer/configs"
)

type FreezerState string
type Manager interface {
// Apply cgroup configuration to the process with the specified pid
Apply(pid int) error

const (
Undefined FreezerState = ""
Frozen FreezerState = "FROZEN"
Thawed FreezerState = "THAWED"
)
// Returns the PIDs inside the cgroup set
GetPids() ([]int, error)

// Returns statistics for the cgroup set
GetStats() (*Stats, error)

// Toggles the freezer cgroup according with specified state
Freeze(state configs.FreezerState) error

// Destroys the cgroup set
Destroy() error

// NewCgroupManager() and LoadCgroupManager() require following attributes:
// Paths map[string]string
// Cgroups *cgroups.Cgroup
// Paths maps cgroup subsystem to path at which it is mounted.
// Cgroups specifies specific cgroup settings for the various subsystems

// Returns cgroup paths to save in a state file and to be able to
// restore the object later.
GetPaths() map[string]string
}

type NotFoundError struct {
Subsystem string
Expand All @@ -32,26 +51,6 @@ func IsNotFound(err error) bool {
if err == nil {
return false
}

_, ok := err.(*NotFoundError)
return ok
}

type Cgroup struct {
Name string `json:"name,omitempty"`
Parent string `json:"parent,omitempty"` // name of parent cgroup or slice

AllowAllDevices bool `json:"allow_all_devices,omitempty"` // If this is true allow access to any kind of device within the container. If false, allow access only to devices explicitly listed in the allowed_devices list.
AllowedDevices []*devices.Device `json:"allowed_devices,omitempty"`
Memory int64 `json:"memory,omitempty"` // Memory limit (in bytes)
MemoryReservation int64 `json:"memory_reservation,omitempty"` // Memory reservation or soft_limit (in bytes)
MemorySwap int64 `json:"memory_swap,omitempty"` // Total memory usage (memory + swap); set `-1' to disable swap
CpuShares int64 `json:"cpu_shares,omitempty"` // CPU shares (relative weight vs. other containers)
CpuQuota int64 `json:"cpu_quota,omitempty"` // CPU hardcap limit (in usecs). Allowed cpu time in a given period.
CpuPeriod int64 `json:"cpu_period,omitempty"` // CPU period to be used for hardcapping (in usecs). 0 to use system default.
CpusetCpus string `json:"cpuset_cpus,omitempty"` // CPU to use
CpusetMems string `json:"cpuset_mems,omitempty"` // MEM to use
BlkioWeight int64 `json:"blkio_weight,omitempty"` // Specifies per cgroup weight, range is from 10 to 1000.
Freezer FreezerState `json:"freezer,omitempty"` // set the freeze value for the process
Slice string `json:"slice,omitempty"` // Parent slice to use for systemd
}
Loading

0 comments on commit 5b73860

Please sign in to comment.