# Development Report for May 26, 2017

## Project Status

Overall, containerd is very close to being feature complete.  The final features like namespace support are being worked on.  We have a couple consumers that are working on containerd implementations such as a CRI for kube, Docker execution, Swarmkit, and Linuxkit consuming containerd.

We hope to be feature complete by the end of this month.  That will leave the month of June to focus on quality of the API and making sure that client needs are met.  We have some work on error codes and reviewing our protos to make sure we have an API that we can support for the life of containerd 1.x.

# Image push

We added a `push` and `push-object` command to the dist tool. The `push` command
can be used to push a manifest and all the related objects to a registry. The
`push-object` can push individual blobs from the content store to a registry.

The push command does not require first tagging an image, just specify the
remote name of the image as well as the local name. If the remote and local
name are the same, only one argument is needed. The remote name may exclude
the object identifier (Docker-style tag or digest), in which case the manifest
may be repulled using the manifest digest as the object identifier. Push only
handles pushing images which already exist, it will not create an image manifest
if one does not exist. We will add a separate command for creating new images in
the future.

Example pushing image to a local registry.
```
$ dist image list
REF                               TYPE                                                 DIGEST                                                                  SIZE
docker.io/library/ubuntu:latest   application/vnd.docker.distribution.manifest.v2+json sha256:382452f82a8bbd34443b2c727650af46aced0f94a44463c62a9848133ecb1aa8 44.7 MiB
$ dist push localhost:5000/ubuntu docker.io/library/ubuntu:latest
manifest-sha256:382452f82a8bbd34443b2c727650af46aced0f94a44463c62a9848133ecb1aa8: done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:cf9722e506aada1109f5c00a9ba542a81c9e109606c01c81f5991b1f93de7b66:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:b6f892c0043b37bd1834a4a1b7d68fe6421c6acbc7e7e63a4527e1d379f92c1b:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:55010f332b047687e081a9639fac04918552c144bc2da4edb3422ce8efcc1fb1:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:3deef3fcbd3072b45771bd0d192d4e5ff2b7310b99ea92bce062e01097953505:    done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:ebcd9d4fca80e9e8afc525d8a38e7c56825dfb4a220ed77156f9fb13b14d4ab7:   done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:2955fb827c947b782af190a759805d229cfebc75978dba2d01b4a59e6a333845:    done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 6.5 s                                                                    total:  44.7 M (6.9 MiB/s)
```

[#886 Add dist push-object](https://github.com/containerd/containerd/pull/886)

[#911 Add dist push](https://github.com/containerd/containerd/pull/911)

## Client

We started work on the initial containerd client.  Since we will have multiple consumers using the API, we want to reduce duplicated code for users of containerd.  Another goal for our client is to give users a stable client API that does not feel like they are working with a remote daemon.  Containers are already complex for most people but this does not need to be the case.  Building a platform on top of containerd should be effortless.  We want to handle the low level system aspects so that you can build a platform for your users and not worry about the underlying system, unless you want to.


### Creating a client for Docker

```go
client, err := containerd.New(address, containerd.WithNamespace("docker"))
if err != nil {
	return err
}
defer client.Close()
```

### Pulling an Image from DockerHub

```go
// pull && unpack the image to your snapshot ( overlayfs default ) of choice
image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack)
if err != nil {
	return err
}
```

### Generate an OCI runtime specification

```go
// generate the spec based on the image that we pulled
spec, err := containerd.GenerateSpec(containerd.WithImageConfig(ctx, image))
if err != nil {
	return err
}
```

### Create a new container based on the image

```go
// create the container with a persistent ReadWrite layer based on the image and spec
container, err := client.NewContainer(ctx, "redis", spec, containerd.WithNewRootFS("redis-rootfs", image))
if err != nil {
	return err
}
defer container.Delete(ctx)
```

### Run the container

```go
// use the current process's stdio
task, err := container.NewTask(ctx, containerd.Stdio)
if err != nil {
	return err
}
defer task.Delete(ctx)

pid := task.Pid()

// start the redis process
if err := task.Start(ctx); err != nil {
	return err
}

task.Kill(ctx, syscall.SIGTERM)

status, err := task.Wait(ctx)

os.Exit(status)
```

This is a very simple but common usecase for containerd.  Pull an image and run a container based on that image.  The client lets you write code, use `defer` statements and any other logic you want without having to do complex filesystem operations, deal with tar files or setting up root filesystems.  The API is split up and allows you to look into the lifecycle of an executing container without the need to register hooks and provide callbacks.

Over the next few weeks we will be expanding the client to support the full containerd feature set.

## Testing

With the initial client merged into the code base we are also starting work on integration tests.  We have full integration tests running on travis ci.  You don't have to mess with any other test frameworks to write tests for containerd, just the standard Go testing package.

We also designed the client to allow mocking of calls so that our tests can be mocked out or users of our client to easily mock their own code for testing.

You can view the PR [here](https://github.com/containerd/containerd/pull/910).


## What's Next?

We still need to finish Events.  This is one of the last major features that we need before we consider containerd feature complete.  The namespace work is in progress with the initial service spec'd.

Within the next few weeks we should have namespaces done, a complete client, and hopefully a stable events service.
