Migrate website to Hugo
Signed-off-by: Luc Perkins <lucperkins@gmail.com>
This commit is contained in:
111
docs/content/_index.md
Normal file
111
docs/content/_index.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
---
|
||||
|
||||
## News
|
||||
|
||||
{{< news >}}
|
||||
|
||||
## About containerd
|
||||
|
||||
containerd is an industry-standard core container runtime with an emphasis on simplicity, robustness and portability. It is available as a daemon for Linux and Windows, which can manage the complete container lifecycle of its host system: image transfer and storage, container execution and supervision, low-level storage and network attachments, etc..
|
||||
|
||||
containerd is designed to be embedded into a larger system, rather than being used directly by developers or end-users.
|
||||
|
||||
containerd includes a daemon exposing gRPC API over a local UNIX socket. The API is a low-level one designed for higher layers to wrap and extend. It also includes a barebone CLI (`ctr`) designed specifically for development and debugging purpose. It uses [runC](https://github.com/opencontainers/runc) to run containers according to the [OCI specification](https://www.opencontainers.org/about). The code can be found on [GitHub](https://github.com/containerd/containerd), and here are the [contribution guidelines](https://github.com/containerd/containerd/blob/master/CONTRIBUTING.md).
|
||||
|
||||
containerd is based on the Docker Engine’s core container runtime to benefit from its maturity and existing contributors.
|
||||
|
||||

|
||||
|
||||
## Features and roadmap
|
||||
|
||||
{{< features >}}
|
||||
|
||||
containerd, currently in [version 1.0.1](https://github.com/containerd/containerd/releases/tag/v1.0.1), is a daemon born from extracting the container execution subset of the Docker Engine, and is [used internally by Docker since the 1.11 release](https://blog.docker.com/2016/04/docker-engine-1-11-runc/). containerd versions prior to v1.0.x were used in Docker 17.10 and earlier (see Docker [version release notes](https://github.com/docker/docker-ce/releases)), and [Docker 17.12](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce) is the first release to use containerd v1.0.0.
|
||||
|
||||
The containerd maintainers do not provide a consolidated [containerd roadmap](https://github.com/containerd/containerd/blob/master/ROADMAP.md), but have chosen to use issues and milestones to track and implement major and minor features.
|
||||
|
||||
## Architecture
|
||||
|
||||
Containerd [architecture](https://github.com/containerd/containerd/blob/master/design/architecture.md) and [API](https://github.com/containerd/containerd/tree/master/api/) are described in the GitHub repository.
|
||||
|
||||

|
||||
|
||||
## Principles and Releases
|
||||
|
||||
Having a clearly defined scope of a project is important for ensuring consistency and focus.
|
||||
These following criteria will be used when reviewing pull requests, features, and changes for the project before being accepted.
|
||||
|
||||
### Components
|
||||
|
||||
Components should not have tight dependencies on each other so that they are unable to be used independently.
|
||||
The APIs for images and containers should be designed in a way that when used together the components have a natural flow but still be useful independently.
|
||||
|
||||
An example for this design can be seen with the overlay filesystems and the container execution layer.
|
||||
The execution layer and overlay filesystems can be used independently but if you were to use both, they share a common `Mount` struct that the filesystems produce and the execution layer consumes.
|
||||
|
||||
### Primitives
|
||||
|
||||
containerd should expose primitives to solve problems instead of building high level abstractions in the API.
|
||||
A common example of this is how build would be implemented.
|
||||
Instead of having a build API in containerd we should expose the lower level primitives that allow things required in build to work.
|
||||
Breaking up the filesystem APIs to allow snapshots, copy functionality, and mounts allow people implementing build at the higher levels more flexibility.
|
||||
|
||||
### Extensibility and Defaults
|
||||
|
||||
For the various components in containerd there should be defined extension points where implementations can be swapped for alternatives.
|
||||
The best example of this is that containerd will use `runc` from OCI as the default runtime in the execution layer but other runtimes conforming to the OCI Runtime specification they can be easily added to containerd.
|
||||
|
||||
containerd will come with a default implementation for the various components.
|
||||
These defaults will be chosen by the maintainers of the project and should not change unless better tech for that component comes out.
|
||||
Additional implementations will not be accepted into the core repository and should be developed in a separate repository not maintained by the containerd maintainers.
|
||||
|
||||
### Releases
|
||||
|
||||
containerd will be supported for 1 year with security and bug fixes applied and released.
|
||||
|
||||
The upgrade path for containerd is that the 0.0.x patch releases are always backward compatible with its major and minor version.
|
||||
Minor (0.x.0) version will always be compatible with the previous minor release. i.e. 1.2.0 is backwards compatible with 1.1.0 and 1.1.0 is compatible with 1.0.0.
|
||||
There is no compatibility guarantees with upgrades from two minor relases. i.e. 1.0.0 to 1.2.0.
|
||||
|
||||
There are no backwards compatibility guarantees with upgrades to major versions. i.e 1.0.0 to 2.0.0.
|
||||
Each major version will be supported for 1 year with bug fixes and security patches.
|
||||
|
||||
## FAQ
|
||||
|
||||
1. What is the relationship between containerd and Docker?
|
||||
|
||||
Docker is a complete platform and programming environment for containerized applications. containerd is one of dozens of specialized components integrated into Docker. Developers and IT professionals looking to build, ship and run containerized applications should continue to use Docker. Operators and integrators looking for specialized components to swap into their platform should consider containerd.
|
||||
|
||||
|
||||

|
||||
|
||||
containerd 0.2.4 used in Docker 1.12 covers only container execution and process management.
|
||||
|
||||

|
||||
|
||||
containerd's roadmap is to refactor the Docker Engine codebase to extract more of its logic for distribution, networking and storage on a single host into a reusable component that Docker will use, and that can be used by other container orchestration projects or hosted container services.
|
||||
|
||||

|
||||
|
||||
2. What is the relationship between containerd, OCI and runc?
|
||||
|
||||
Docker [donated the OCI specification to the Linux Foundation in 2015](https://blog.docker.com/2015/06/open-container-project-foundation/), along with a reference implementation called `runc`. containerd integrates [OCI](https://www.opencontainers.org/)/[runc](https://runc.io/) into a feature-complete, production-ready core container runtime. runc is a component of containerd, the executor for containers. containerd has a wider scope than just executing containers: downloading container images, managing storage and network interfaces, calling runc with the right parameters to run containers. containerd fully leverages the Open Container Initiative’s (OCI) runtime, image format specifications and OCI reference implementation (runc) and will pursue OCI certification when it is available. Because of its massive adoption, containerd is the industry standard for implementing OCI.
|
||||
|
||||

|
||||
|
||||
3. What is the relationship between containerd and container orchestration systems like Kubernetes and Mesos?
|
||||
|
||||
Kubernetes today uses Docker directly. In a future version Kubernetes can implement container support in the Kubelet by implementing it's [Container Runtime Interface](https://github.com/kubernetes/kubernetes/blob/release-1.5/docs/devel/container-runtime-interface.md) using containerd. Mesos and other orchestration engines can leverage containerd for core container runtime functionality as well.
|
||||
|
||||

|
||||
|
||||
4. What is the relationship between containerd and cloud managed container services?
|
||||
|
||||
See answer above: cloud managed container services can leverage containerd instead of Docker in order to provide container functionalities to their users.
|
||||
|
||||
## CNCF
|
||||
|
||||

|
||||
|
||||
We are a Cloud Native Computing Foundation member project.
|
||||
101
docs/content/docs/client-opts.md
Normal file
101
docs/content/docs/client-opts.md
Normal file
@@ -0,0 +1,101 @@
|
||||
---
|
||||
title: Client options
|
||||
draft: true
|
||||
---
|
||||
|
||||
The containerd client was built to be easily extended by consumers.
|
||||
The goal is that the execution flow of the calls remain the same across implementations while `Opts` are written to extend functionality.
|
||||
To accomplish this we depend on the `Opts` pattern in Go.
|
||||
|
||||
## Method Calls
|
||||
|
||||
For many functions and methods within the client package you will generally see variadic args as the last parameter.
|
||||
|
||||
If we look at the `NewContainer` method on the client we can see that it has a required argument of `id` and then additional `NewContainerOpts`.
|
||||
|
||||
There are a few built in options that allow the container to be created with an existing spec, `WithSpec`, and snapshot opts for creating or using an existing snapshot.
|
||||
|
||||
```go
|
||||
func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) {
|
||||
}
|
||||
```
|
||||
|
||||
## Extending the Client
|
||||
|
||||
As a consumer of the containerd client you need to be able add your domain specific functionality.
|
||||
There are a few ways of doing this, changing the client code, submitting a PR to the containerd client, or forking the client.
|
||||
These ways of extending the client should only be considered after every other method has been tried.
|
||||
|
||||
The proper and supported way of extending the client is to build a package of `Opts` that define your application specific logic.
|
||||
|
||||
As an example, if Docker is integrating containerd support and needs to add concepts such as Volumes, they would create a `docker` package with options.
|
||||
|
||||
#### Bad Extension Example
|
||||
|
||||
```go
|
||||
// example code
|
||||
container, err := client.NewContainer(ctx, id)
|
||||
|
||||
// add volumes with their config and bind mounts
|
||||
container.Labels["volumes"] = VolumeConfig{}
|
||||
container.Spec.Binds = append({"/var/lib/docker/volumes..."})
|
||||
```
|
||||
|
||||
#### Good Extension Example
|
||||
|
||||
```go
|
||||
// example code
|
||||
import "github.com/docker/docker"
|
||||
import "github.com/docker/libnetwork"
|
||||
|
||||
container, err := client.NewContainer(ctx, id,
|
||||
docker.WithVolume("volume-name"),
|
||||
libnetwork.WithOverlayNetwork("cluster-network"),
|
||||
)
|
||||
```
|
||||
|
||||
There are a few advantages using this model.
|
||||
|
||||
1. Your application code is not scattered in the execution flow of the containerd client.
|
||||
2. Your code can be unit tested without mocking the containerd client.
|
||||
3. Contributors can better follow your containerd implementation and understand when and where your application logic is added to standard containerd client calls.
|
||||
|
||||
## Example SpecOpt
|
||||
|
||||
If we want to make a `SpecOpt` to setup a container to monitor the host system with `htop` it can be easily done without ever touching a line of code in the containerd repository.
|
||||
|
||||
```go
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/oci"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// WithHtop configures a container to monitor the host system via `htop`
|
||||
func WithHtop(s *specs.Spec) error {
|
||||
// make sure we are in the host pid namespace
|
||||
if err := oci.WithHostNamespace(specs.PIDNamespace)(s); err != nil {
|
||||
return err
|
||||
}
|
||||
// make sure we set htop as our arg
|
||||
s.Process.Args = []string{"htop"}
|
||||
// make sure we have a tty set for htop
|
||||
if err := oci.WithTTY(s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Adding your new option to spec generation is as easy as importing your new package and adding the option when creating a spec.
|
||||
|
||||
```go
|
||||
import "github.com/crosbymichael/monitor"
|
||||
|
||||
container, err := client.NewContainer(ctx, id,
|
||||
containerd.WithNewSpec(oci.WithImageConfig(image), monitor.WithHtop),
|
||||
)
|
||||
```
|
||||
|
||||
You can see the full code and run the monitor container [here](https://github.com/crosbymichael/monitor).
|
||||
26
docs/content/docs/dockercon-summit.md
Normal file
26
docs/content/docs/dockercon-summit.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Dockercon 2017 Summit
|
||||
draft: true
|
||||
---
|
||||
|
||||
# Dockercon 2017 Summit
|
||||
|
||||
This year at Dockercon US 2017 we will be having a containerd Summit on Thursday morning the week of the conference.
|
||||
|
||||
We are going to change the format slightly compared to the previous summit that was held in February. We will be allocating more time to the breakout sessions and less time to static talks. However, the group will be much larger than the previous summit so this document serves as a way to add discussion points for the breakout sessions.
|
||||
|
||||
If you would like to add a discussion point to the agenda, submit a PR adding it to the list below. A simple one line sentence is enough or expand if needed.
|
||||
|
||||
If you have not signed up to attend the summit you can do so in this [form](https://docs.google.com/forms/d/e/1FAIpQLScNkLm984ABbFChPh02uJR2lJ6y1AXjFaDITCaxTFL-sHhPwQ/viewform).
|
||||
|
||||
## Discussion Points
|
||||
|
||||
The following are proposed discussion points for the containerd summit at Dockercon US 2017:
|
||||
|
||||
|
||||
* Since containerd is one of the bottom bricks in the stack, how can we setup automated integration tests for consumers of containerd?
|
||||
* We'd like to propose an Authorization plugin to containerd that would allow an external component to police events like container start & stop (and have a discussion about the best way to go about it)
|
||||
* Should containerd provide image filesystem metrics? If yes, what metrics should be included? How to implement that?
|
||||
* Support for disk quotas: How? What is the role of containerd? How is it going to be integrated with volume managers that want to be in the same quota group?
|
||||
* Checkpoint/Restore: how can we support more use cases? One of the big issues here is the large number of options that can be passed to CRIU.
|
||||
* How to support multi-OS docker images, for example, Linux Vs Windows using one graph driver plugin properly?
|
||||
435
docs/content/docs/getting-started.md
Normal file
435
docs/content/docs/getting-started.md
Normal file
@@ -0,0 +1,435 @@
|
||||
---
|
||||
title: Getting started with containerd
|
||||
draft: true
|
||||
---
|
||||
|
||||
There are many different ways to use containerd.
|
||||
If you are a developer working on containerd you can use the `ctr` tool to quickly test features and functionality without writing extra code.
|
||||
However, if you want to integrate containerd into your project we have an easy to use client package that allows you to work with containerd.
|
||||
|
||||
In this guide we will pull and run a redis server with containerd using the client package.
|
||||
We will assume that you are running a modern linux host for this example with a compatible build of `runc`.
|
||||
Please refer to [RUNC.md](/RUNC.md) for the currently supported version of `runc`.
|
||||
This project requires Go 1.9.x or above.
|
||||
If you need to install Go or update your currently installed one, please refer to Go install page at https://golang.org/doc/install.
|
||||
|
||||
## Starting containerd
|
||||
|
||||
You can download one of the latest builds for containerd on the [github releases](https://github.com/containerd/containerd/releases) page and then use your favorite process supervisor to get the daemon started.
|
||||
If you are using systemd, we have a `containerd.service` file at the root of the repository that you can use.
|
||||
|
||||
The daemon also uses a configuration file located in `/etc/containerd/config.toml` for specifying daemon level options.
|
||||
A sample configuration file looks like this:
|
||||
|
||||
```toml
|
||||
subreaper = true
|
||||
oom_score = -999
|
||||
|
||||
[debug]
|
||||
level = "debug"
|
||||
|
||||
[metrics]
|
||||
address = "127.0.0.1:1338"
|
||||
|
||||
[plugins.linux]
|
||||
runtime = "runc"
|
||||
shim_debug = true
|
||||
```
|
||||
|
||||
The default configuration can be generated via `containerd config default > /etc/containerd/config.toml`.
|
||||
|
||||
## Connecting to containerd
|
||||
|
||||
We will start a new `main.go` file and import the containerd root package that contains the client.
|
||||
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := redisExample(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func redisExample() error {
|
||||
client, err := containerd.New("/run/containerd/containerd.sock")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
This will create a new client with the default containerd socket path.
|
||||
Because we are working with a daemon over GRPC we need to create a `context` for use with calls to client methods.
|
||||
containerd is also namespaced for callers of the API.
|
||||
We should also set a namespace for our guide after creating the context.
|
||||
|
||||
```go
|
||||
ctx := namespaces.WithNamespace(context.Background(), "example")
|
||||
```
|
||||
|
||||
Having a namespace for our usage ensures that containers, images, and other resources without containerd do not conflict with other users of a single daemon.
|
||||
|
||||
## Pulling the redis image
|
||||
|
||||
Now that we have a client to work with we need to pull an image.
|
||||
We can use the redis image based on Alpine Linux from the DockerHub.
|
||||
|
||||
```go
|
||||
image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
The containerd client uses the `Opts` pattern for many of the method calls.
|
||||
We use the `containerd.WithPullUnpack` so that we not only fetch and download the content into containerd's content store but also unpack it into a snapshotter for use as a root filesystem.
|
||||
|
||||
Let's put the code together that will pull the redis image based on alpine linux from Dockerhub and then print the name of the image on the console's output.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := redisExample(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func redisExample() error {
|
||||
client, err := containerd.New("/run/containerd/containerd.sock")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), "example")
|
||||
image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("Successfully pulled %s image\n", image.Name())
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
> go build main.go
|
||||
> sudo ./main
|
||||
|
||||
2017/08/13 17:43:21 Successfully pulled docker.io/library/redis:alpine image
|
||||
```
|
||||
|
||||
## Creating an OCI Spec and Container
|
||||
|
||||
Now that we have an image to base our container off of, we need to generate an OCI runtime specification that the container can be based off of as well as the new container.
|
||||
|
||||
containerd provides reasonable defaults for generating OCI runtime specs.
|
||||
There is also an `Opt` for modifying the default config based on the image that we pulled.
|
||||
|
||||
The container will be based off of the image, use the runtime information in the spec that was just created, and we will allocate a new read-write snapshot so the container can store any persistent information.
|
||||
|
||||
```go
|
||||
container, err := client.NewContainer(
|
||||
ctx,
|
||||
"redis-server",
|
||||
containerd.WithNewSnapshot("redis-server-snapshot", image),
|
||||
containerd.WithNewSpec(oci.WithImageConfig(image)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
```
|
||||
|
||||
If you have an existing OCI specification created you can use `containerd.WithSpec(spec)` to set it on the container.
|
||||
|
||||
When creating a new snapshot for the container we need to provide a snapshot ID as well as the Image that the container will be based on.
|
||||
By providing a separate snapshot ID than the container ID we can easily reuse, existing snapshots across different containers.
|
||||
|
||||
We also add a line to delete the container along with its snapshot after we are done with this example.
|
||||
|
||||
Here is example code to pull the redis image based on alpine linux from Dockerhub, create an OCI spec, create a container based on the spec and finally delete the container.
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := redisExample(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func redisExample() error {
|
||||
client, err := containerd.New("/run/containerd/containerd.sock")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), "example")
|
||||
image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("Successfully pulled %s image\n", image.Name())
|
||||
|
||||
container, err := client.NewContainer(
|
||||
ctx,
|
||||
"redis-server",
|
||||
containerd.WithNewSnapshot("redis-server-snapshot", image),
|
||||
containerd.WithNewSpec(oci.WithImageConfig(image)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
log.Printf("Successfully created container with ID %s and snapshot with ID redis-server-snapshot", container.ID())
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Let's see it in action.
|
||||
|
||||
```bash
|
||||
> go build main.go
|
||||
> sudo ./main
|
||||
|
||||
2017/08/13 18:01:35 Successfully pulled docker.io/library/redis:alpine image
|
||||
2017/08/13 18:01:35 Successfully created container with ID redis-server and snapshot with ID redis-server-snapshot
|
||||
```
|
||||
|
||||
## Creating a running Task
|
||||
|
||||
One thing that may be confusing at first for new containerd users is the separation between a `Container` and a `Task`.
|
||||
A container is a metadata object that resources are allocated and attached to.
|
||||
A task is a live, running process on the system.
|
||||
Tasks should be deleted after each run while a container can be used, updated, and queried multiple times.
|
||||
|
||||
```go
|
||||
task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer task.Delete(ctx)
|
||||
```
|
||||
|
||||
The new task that we just created is actually a running process on your system.
|
||||
We use `cio.WithStdio` so that all IO from the container is sent to our `main.go` process.
|
||||
This is a `cio.Opt` that configures the `Streams` used by `NewCreator` to return a `cio.IO`
|
||||
for the new task.
|
||||
|
||||
If you are familiar with the OCI runtime actions, the task is currently in the "created" state.
|
||||
This means that the namespaces, root filesystem, and various container level settings have been initialized but the user defined process, in this example "redis-server", has not been started.
|
||||
This gives users a chance to setup network interfaces or attach different tools to monitor the container.
|
||||
containerd also takes this opportunity to monitor your container as well.
|
||||
Waiting on things like the container's exit status and cgroup metrics are setup at this point.
|
||||
|
||||
If you are familiar with prometheus you can curl the containerd metrics endpoint (in the `config.toml` that we created) to see your container's metrics:
|
||||
|
||||
```bash
|
||||
> curl 127.0.0.1:1338/v1/metrics
|
||||
```
|
||||
|
||||
Pretty cool right?
|
||||
|
||||
## Task Wait and Start
|
||||
|
||||
Now that we have a task in the created state we need to make sure that we wait on the task to exit.
|
||||
It is essential to wait for the task to finish so that we can close our example and cleanup the resources that we created.
|
||||
You always want to make sure you `Wait` before calling `Start` on a task.
|
||||
This makes sure that you do not encounter any races if the task has a simple program like `/bin/true` that exits promptly after calling start.
|
||||
|
||||
```go
|
||||
exitStatusC, err := task.Wait(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
Now we should see the `redis-server` logs in our terminal when we run the `main.go` file.
|
||||
|
||||
## Killing the task
|
||||
|
||||
Since we are running a long running server we will need to kill the task in order to exit out of our example.
|
||||
To do this we will simply call `Kill` on the task after waiting a couple of seconds so we have a chance to see the redis-server logs.
|
||||
|
||||
```go
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
if err := task.Kill(ctx, syscall.SIGTERM); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status := <-exitStatusC
|
||||
code, exitedAt, err := status.Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("redis-server exited with status: %d\n", code)
|
||||
```
|
||||
|
||||
We wait on our exit status channel that we setup to ensure the task has fully exited and we get the exit status.
|
||||
If you have to reload containers or miss waiting on a task, `Delete` will also return the exit status when you finally delete the task.
|
||||
We got you covered.
|
||||
|
||||
```go
|
||||
status, err := task.Delete(ctx)
|
||||
```
|
||||
|
||||
## Full Example
|
||||
|
||||
Here is the full example that we just put together.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := redisExample(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func redisExample() error {
|
||||
// create a new client connected to the default socket path for containerd
|
||||
client, err := containerd.New("/run/containerd/containerd.sock")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// create a new context with an "example" namespace
|
||||
ctx := namespaces.WithNamespace(context.Background(), "example")
|
||||
|
||||
// pull the redis image from DockerHub
|
||||
image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create a container
|
||||
container, err := client.NewContainer(
|
||||
ctx,
|
||||
"redis-server",
|
||||
containerd.WithImage(image),
|
||||
containerd.WithNewSnapshot("redis-server-snapshot", image),
|
||||
containerd.WithNewSpec(oci.WithImageConfig(image)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
|
||||
// create a task from the container
|
||||
task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer task.Delete(ctx)
|
||||
|
||||
// make sure we wait before calling start
|
||||
exitStatusC, err := task.Wait(ctx)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// call start on the task to execute the redis server
|
||||
if err := task.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sleep for a lil bit to see the logs
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// kill the process and get the exit status
|
||||
if err := task.Kill(ctx, syscall.SIGTERM); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait for the process to fully exit and print out the exit status
|
||||
|
||||
status := <-exitStatusC
|
||||
code, _, err := status.Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("redis-server exited with status: %d\n", code)
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
We can build this example and run it as follows to see our hard work come together.
|
||||
|
||||
```bash
|
||||
> go build main.go
|
||||
> sudo ./main
|
||||
|
||||
1:C 04 Aug 20:41:37.682 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
|
||||
1:C 04 Aug 20:41:37.682 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
|
||||
1:C 04 Aug 20:41:37.682 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
|
||||
1:M 04 Aug 20:41:37.682 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.
|
||||
1:M 04 Aug 20:41:37.682 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted.
|
||||
1:M 04 Aug 20:41:37.682 # Current maximum open files is 1024. maxclients has been reduced to 992 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
|
||||
1:M 04 Aug 20:41:37.683 * Running mode=standalone, port=6379.
|
||||
1:M 04 Aug 20:41:37.683 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
|
||||
1:M 04 Aug 20:41:37.684 # Server initialized
|
||||
1:M 04 Aug 20:41:37.684 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
|
||||
1:M 04 Aug 20:41:37.684 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
|
||||
1:M 04 Aug 20:41:37.684 * Ready to accept connections
|
||||
1:signal-handler (1501879300) Received SIGTERM scheduling shutdown...
|
||||
1:M 04 Aug 20:41:40.791 # User requested shutdown...
|
||||
1:M 04 Aug 20:41:40.791 * Saving the final RDB snapshot before exiting.
|
||||
1:M 04 Aug 20:41:40.794 * DB saved on disk
|
||||
1:M 04 Aug 20:41:40.794 # Redis is now ready to exit, bye bye...
|
||||
redis-server exited with status: 0
|
||||
```
|
||||
|
||||
In the end, we really did not write that much code when you use the client package.
|
||||
|
||||
I hope this guide helped to get you up and running with containerd.
|
||||
Feel free to join the [slack channel](https://dockr.ly/community) if you have any questions and like all things, if you want to help contribute to containerd or this guide, submit a pull request.
|
||||
67
docs/content/docs/namespaces.md
Normal file
67
docs/content/docs/namespaces.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: containerd Namespaces and Multi-Tenancy
|
||||
draft: true
|
||||
---
|
||||
|
||||
containerd offers a fully namespaced API so multiple consumers can all use a single containerd instance without conflicting with one another.
|
||||
Namespaces allow multi-tenancy within a single daemon. This removes the need for the common pattern of using nested containers to achieve this separation.
|
||||
Consumers are able to have containers with the same names but with settings and/or configurations that vary drastically.
|
||||
For example, system or infrastructure level containers can be hidden in one namespace while user level containers are kept in another.
|
||||
Underlying image content is still shared via content addresses but image names and metadata are separate per namespace.
|
||||
|
||||
It is important to note that namespaces, as implemented, is an administrative construct that is not meant to be used as a security feature.
|
||||
It is trivial for clients to switch namespaces.
|
||||
|
||||
## Who specifies the namespace?
|
||||
|
||||
The client specifies the namespace via the `context`.
|
||||
There is a `github.com/containerd/containerd/namespaces` package that allows a user to get and set the namespace on a context.
|
||||
|
||||
```go
|
||||
// set a namespace
|
||||
ctx := namespaces.WithNamespace(context.Background(), "my-namespace")
|
||||
|
||||
// get the namespace
|
||||
ns, ok := namespaces.Namespace(ctx)
|
||||
```
|
||||
|
||||
Because the client calls containerd's gRPC API to interact with the daemon, all API calls require a context with a namespace set.
|
||||
|
||||
## How low level is the implementation?
|
||||
|
||||
Namespaces are passed through the containerd API to the underlying plugins providing functionality.
|
||||
Plugins must be written to take namespaces into account.
|
||||
Filesystem paths, IDs, and other system level resources must be namespaced for a plugin to work properly.
|
||||
|
||||
## How does multi-tenancy work?
|
||||
|
||||
Simply create a new `context` and set your application's namespace on the `context`.
|
||||
Make sure to use a unique namespace for applications that does not conflict with existing namespaces. The namespaces
|
||||
API, or the `ctr namespaces` client command, can be used to query/list and create new namespaces. Note that namespaces
|
||||
can have a list of labels associated with the namespace. This can be useful for associating metadata with a particular
|
||||
namespace.
|
||||
|
||||
```go
|
||||
ctx := context.Background()
|
||||
|
||||
var (
|
||||
docker = namespaces.WithNamespace(ctx, "docker")
|
||||
vmware = namespaces.WithNamespace(ctx, "vmware")
|
||||
ecs = namespaces.WithNamespace(ctx, "aws-ecs")
|
||||
cri = namespaces.WithNamespace(ctx, "cri")
|
||||
)
|
||||
```
|
||||
|
||||
## Inspecting Namespaces
|
||||
|
||||
If we need to inspect containers, images, or other resources in various namespaces the `ctr` tool allows you to do this.
|
||||
Simply set the `--namespace,-n` flag on `ctr` to change the namespace. If you do not provide a namespace, `ctr` client commands
|
||||
will all use the the default namespace, which is simply named "`default`".
|
||||
|
||||
```bash
|
||||
> sudo ctr -n docker tasks
|
||||
> sudo ctr -n cri tasks
|
||||
```
|
||||
|
||||
You can also use the `CONTAINERD_NAMESPACE` environment variable to specify the default namespace to use for
|
||||
any of the `ctr` client commands.
|
||||
221
docs/content/docs/ops.md
Normal file
221
docs/content/docs/ops.md
Normal file
@@ -0,0 +1,221 @@
|
||||
---
|
||||
title: containerd for Ops and Admins
|
||||
draft: true
|
||||
---
|
||||
|
||||
containerd is meant to be a simple daemon to run on any system.
|
||||
It provides a minimal config with knobs to configure the daemon and what plugins are used when necessary.
|
||||
|
||||
```
|
||||
NAME:
|
||||
containerd -
|
||||
__ _ __
|
||||
_________ ____ / /_____ _(_)___ ___ _________/ /
|
||||
/ ___/ __ \/ __ \/ __/ __ `/ / __ \/ _ \/ ___/ __ /
|
||||
/ /__/ /_/ / / / / /_/ /_/ / / / / / __/ / / /_/ /
|
||||
\___/\____/_/ /_/\__/\__,_/_/_/ /_/\___/_/ \__,_/
|
||||
|
||||
high performance container runtime
|
||||
|
||||
|
||||
USAGE:
|
||||
containerd [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
v1.0.0-alpha3-36-ge9b86af
|
||||
|
||||
COMMANDS:
|
||||
config information on the containerd config
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--config value, -c value path to the configuration file (default: "/etc/containerd/config.toml")
|
||||
--log-level value, -l value set the logging level [debug, info, warn, error, fatal, panic]
|
||||
--address value, -a value address for containerd's GRPC server
|
||||
--root value containerd root directory
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
|
||||
While a few daemon level options can be set from CLI flags the majority of containerd's configuration is kept in the configuration file.
|
||||
The default path for the config file is located at `/etc/containerd/config.toml`.
|
||||
You can change this path via the `--config,-c` flags when booting the daemon.
|
||||
|
||||
## systemd
|
||||
|
||||
If you are using systemd as your init system, which most modern linux OSs are, the service file requires a few modifications.
|
||||
|
||||
```systemd
|
||||
[Unit]
|
||||
Description=containerd container runtime
|
||||
Documentation=https://containerd.io
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/sbin/modprobe overlay
|
||||
ExecStart=/usr/local/bin/containerd
|
||||
Delegate=yes
|
||||
KillMode=process
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
`Delegate=yes` and `KillMode=process` are the two most important changes you need to make in the `[Service]` section.
|
||||
|
||||
`Delegate` allows containerd and its runtimes to manage the cgroups of the containers that it creates.
|
||||
Without setting this option, systemd will try to move the processes into its own cgroups, causing problems for containerd and its runtimes to properly account for resource usage with the containers.
|
||||
|
||||
`KillMode` handles when containerd is being shut down.
|
||||
By default, systemd will look in its named cgroup and kill every process that it knows about for the service.
|
||||
This is not what we want.
|
||||
As ops, we want to be able to upgrade containerd and allow existing containers to keep running without interruption.
|
||||
Setting `KillMode` to `process` ensures that systemd only kills the containerd daemon and not any child processes such as the shims and containers.
|
||||
|
||||
|
||||
## Base Configuration
|
||||
|
||||
In the containerd config file you will find settings for persistent and runtime storage locations as well as grpc, debug, and metrics addresses for the various APIs.
|
||||
|
||||
There are a few settings that are important for ops.
|
||||
The first setting is the `oom_score`. Because containerd will be managing multiple containers, we need to ensure that containers are killed before the containerd daemon in an out of memory condition.
|
||||
We also do not want to make containerd unkillable, but we want to lower its score to the level of other system daemons.
|
||||
|
||||
The `subreaper` setting is also important on linux systems.
|
||||
This allows containerd to reap any re-parented processes from the shims or containers.
|
||||
|
||||
containerd also exports its own metrics as well as container level metrics via the prometheus metrics format.
|
||||
Currently, prometheus only supports TCP endpoints, therefore, the metrics address should be a TCP address that your prometheus infrastructure can scrape metrics from.
|
||||
|
||||
containerd also has two different storage locations on a host system.
|
||||
One is for persistent data and the other is for runtime state.
|
||||
|
||||
`root` will be used to store any type of persistent data for containerd.
|
||||
Snapshots, content, metadata for containers and image, as well as any plugin data will be kept in this location.
|
||||
The root is also namespaced for plugins that containerd loads.
|
||||
Each plugin will have its own directory where it stores data.
|
||||
containerd itself does not actually have any persistent data that it needs to store, its functionality comes from the plugins that are loaded.
|
||||
|
||||
|
||||
```
|
||||
/var/lib/containerd/
|
||||
├── io.containerd.content.v1.content
|
||||
│ ├── blobs
|
||||
│ └── ingest
|
||||
├── io.containerd.metadata.v1.bolt
|
||||
│ └── meta.db
|
||||
├── io.containerd.runtime.v1.linux
|
||||
│ ├── default
|
||||
│ └── example
|
||||
├── io.containerd.snapshotter.v1.btrfs
|
||||
└── io.containerd.snapshotter.v1.overlayfs
|
||||
├── metadata.db
|
||||
└── snapshots
|
||||
```
|
||||
|
||||
`state` will be used to store any type of ephemeral data.
|
||||
Sockets, pids, runtime state, mount points, and other plugin data that must not persist between reboots are stored in this location.
|
||||
|
||||
```
|
||||
/run/containerd
|
||||
├── containerd.sock
|
||||
├── debug.sock
|
||||
├── io.containerd.runtime.v1.linux
|
||||
│ └── default
|
||||
│ └── redis
|
||||
│ ├── config.json
|
||||
│ ├── init.pid
|
||||
│ ├── log.json
|
||||
│ └── rootfs
|
||||
│ ├── bin
|
||||
│ ├── data
|
||||
│ ├── dev
|
||||
│ ├── etc
|
||||
│ ├── home
|
||||
│ ├── lib
|
||||
│ ├── media
|
||||
│ ├── mnt
|
||||
│ ├── proc
|
||||
│ ├── root
|
||||
│ ├── run
|
||||
│ ├── sbin
|
||||
│ ├── srv
|
||||
│ ├── sys
|
||||
│ ├── tmp
|
||||
│ ├── usr
|
||||
│ └── var
|
||||
└── runc
|
||||
└── default
|
||||
└── redis
|
||||
└── state.json
|
||||
```
|
||||
|
||||
Both the `root` and `state` directories are namespaced for plugins.
|
||||
Both directories are an implementation detail of containerd and its plugins.
|
||||
They should not be tampered with as corruption and bugs can and will happen.
|
||||
External apps reading or watching changes in these directories have been known to cause `EBUSY` and stale file handles when containerd and/or its plugins try to cleanup resources.
|
||||
|
||||
```toml
|
||||
# persistent data location
|
||||
root = "/var/lib/containerd"
|
||||
# runtime state information
|
||||
state = "/run/containerd"
|
||||
# set containerd as a subreaper on linux when it is not running as PID 1
|
||||
subreaper = true
|
||||
# set containerd's OOM score
|
||||
oom_score = -999
|
||||
|
||||
# grpc configuration
|
||||
[grpc]
|
||||
address = "/run/containerd/containerd.sock"
|
||||
# socket uid
|
||||
uid = 0
|
||||
# socket gid
|
||||
gid = 0
|
||||
|
||||
# debug configuration
|
||||
[debug]
|
||||
address = "/run/containerd/debug.sock"
|
||||
# socket uid
|
||||
uid = 0
|
||||
# socket gid
|
||||
gid = 0
|
||||
# debug level
|
||||
level = "info"
|
||||
|
||||
# metrics configuration
|
||||
[metrics]
|
||||
# tcp address!
|
||||
address = "127.0.0.1:1234"
|
||||
```
|
||||
|
||||
## Plugin Configuration
|
||||
|
||||
At the end of the day, containerd's core is very small.
|
||||
The real functionality comes from plugins.
|
||||
Everything from snapshotters, runtimes, and content are all plugins that are registered at runtime.
|
||||
Because these various plugins are so different we need a way to provide type safe configuration to the plugins.
|
||||
The only way we can do this is via the config file and not CLI flags.
|
||||
|
||||
In the config file you can specify plugin level options for the set of plugins that you use via the `[plugins.<name>]` sections.
|
||||
You will have to read the plugin specific docs to find the options that your plugin accepts.
|
||||
|
||||
### Linux Runtime Plugin
|
||||
|
||||
The linux runtime allows a few options to be set to configure the shim and the runtime that you are using.
|
||||
|
||||
```toml
|
||||
[plugins.linux]
|
||||
# shim binary name/path
|
||||
shim = ""
|
||||
# runtime binary name/path
|
||||
runtime = "runc"
|
||||
# do not use a shim when starting containers, saves on memory but
|
||||
# live restore is not supported
|
||||
no_shim = false
|
||||
# display shim logs in the containerd daemon's log output
|
||||
shim_debug = true
|
||||
# do not put the shim in its own mount namespace
|
||||
# (this only need to be set on kernel < 3.18)
|
||||
shim_no_newns = true
|
||||
```
|
||||
Reference in New Issue
Block a user