在Kubrnetes的最底层是容器运行时(Container Runtime),他们负责启动、暂停容器。最有名的容器运行时就是Docker了,后面又支持rkt。在kubernetes 1.5版本,kubernetes引入了CRI,即Container Runtime Interface。

1. 什么是容器运行时,为什么Kubrenes需要它?

每一种容器运行时,都有自己的有点,kubernetes的许多用户都要求kubernetes引入新的运行时。因为在kubernetes 1.5中引入了CRI。有了CRI,kubrentes不需要重新编译,就可以支持多种容器运行时。CRI本质上只是一种抽象的软件协议,它定义了kubrentes与容器运行时之间的接口。

为什么要提出这一接口协议呢?在此之前,kubernetes支持docker和rkt两种容器运行时,这两种容器运行时的代码与kubelet源码镶嵌在一起。这样就导致了许多问题,首先假如容器运行时接口发生了变化,也必然导致,其他容器运行时代码需要改动,这样会给维护带来很大的问题,其次,假如用户想要增加一类新的容器运行时代码,那必须十分了解Kubelet的源码结构,不利于扩展。因此kuberntes推出了CRI这一接口,使的容器运行时,就像网络、存储一样,是一个可以插拔的软件

2. CRI框架

CRI规定了kubelet与容器运行时之间的接口,kubelet通过unix套接字与容器运行时进行通信,为了高性能,通信必须使用grpc协议。因此kubelet是作为客户端,而CRI则作为服务器端接受请求。CRI包括了CRI shim和容器运行时,CRI shim就是接受请求的服务器端,cri shim接受到请求后,再去调用容器运行时创建容器。如下图所示

cri

grpc使用protocol buffers进行序列化。CRI主要规定了两类接口,即ImageService和RuntimeService,ImageService提供Pull、查看、删除镜像的RPC接口。而RuntimeSerivce主要包括容器和Pod生命周期管理的RPC接口

ImageService接口

type ImageManagerService interface {
    // ListImages lists the existing images.
    ListImages(filter *runtimeapi.ImageFilter) ([]*runtimeapi.Image, error)
    // ImageStatus returns the status of the image.
    ImageStatus(image *runtimeapi.ImageSpec) (*runtimeapi.Image, error)
    // PullImage pulls an image with the authentication config.
    PullImage(image *runtimeapi.ImageSpec, auth *runtimeapi.AuthConfig) (string, error)
    // RemoveImage removes the image.
    RemoveImage(image *runtimeapi.ImageSpec) error
    // ImageFsInfo returns information of the filesystem that is used to store images.
    ImageFsInfo(req *runtimeapi.ImageFsInfoRequest) (*runtimeapi.ImageFsInfoResponse, error)
}

RuntimeService接口。RuntiemService接口主要可以分为两类,即PodSandboxManager和ContainerManager,其中PodSandboxManager主要给Pod提供隔离用的,假如容器运行时是Docker,则是一个名为Pod的容器,Pod为该Pod内的所有容器提供Network、IPC环境,假如容器运行时是基于Hypervisor,如hyper,则Pod代表一个虚拟机。ContainerManager则负责创建具体的容器

type RuntimeService interface {
    RuntimeVersioner
    ContainerManager
    PodSandboxManager
    ContainerStatsManager

    // UpdateRuntimeConfig updates runtime configuration if specified
    UpdateRuntimeConfig(runtimeConfig *runtimeapi.RuntimeConfig) error
    // Status returns the status of the runtime.
    Status() (*runtimeapi.RuntimeStatus, error)
}

type RuntimeVersioner interface {
    // Version returns the runtime name, runtime version and runtime API version
    Version(apiVersion string) (*runtimeapi.VersionResponse, error)
}

type ContainerManager interface {
    // CreateContainer creates a new container in specified PodSandbox.
    CreateContainer(podSandboxID string, config *runtimeapi.ContainerConfig, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error)
    // StartContainer starts the container.
    StartContainer(containerID string) error
    // StopContainer stops a running container with a grace period (i.e., timeout).
    StopContainer(containerID string, timeout int64) error
    // RemoveContainer removes the container.
    RemoveContainer(containerID string) error
    // ListContainers lists all containers by filters.
    ListContainers(filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error)
    // ContainerStatus returns the status of the container.
    ContainerStatus(containerID string) (*runtimeapi.ContainerStatus, error)
    // ExecSync executes a command in the container, and returns the stdout output.
    // If command exits with a non-zero exit code, an error is returned.
    ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error)
    // Exec prepares a streaming endpoint to execute a command in the container, and returns the address.
    Exec(*runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error)
    // Attach prepares a streaming endpoint to attach to a running container, and returns the address.
    Attach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error)
}

type PodSandboxManager interface {
    // RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure
    // the sandbox is in ready state.
    RunPodSandbox(config *runtimeapi.PodSandboxConfig) (string, error)
    // StopPodSandbox stops the sandbox. If there are any running containers in the
    // sandbox, they should be force terminated.
    StopPodSandbox(podSandboxID string) error
    // RemovePodSandbox removes the sandbox. If there are running containers in the
    // sandbox, they should be forcibly removed.
    RemovePodSandbox(podSandboxID string) error
    // PodSandboxStatus returns the Status of the PodSandbox.
    PodSandboxStatus(podSandboxID string) (*runtimeapi.PodSandboxStatus, error)
    // ListPodSandbox returns a list of Sandbox.
    ListPodSandbox(filter *runtimeapi.PodSandboxFilter) ([]*runtimeapi.PodSandbox, error)
    // PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address.
    PortForward(*runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error)
}

type ContainerStatsManager interface {
    // ContainerStats returns stats of the container. If the container does not
    // exist, the call returns an error.
    ContainerStats(req *runtimeapi.ContainerStatsRequest) (*runtimeapi.ContainerStatsResponse, error)
    // ListContainerStats returns stats of all running containers.
    ListContainerStats(req *runtimeapi.ListContainerStatsRequest) (*runtimeapi.ListContainerStatsResponse, error)
}

3. 现有的CRI

目前kubernetes源码里面包括了dockershim这个CRI运行时,该运行时是自动嵌入kubelet源码中的,因此只要适当的配置参数就可以运行。此外kubernetes还支持如下CRI运行时

  • cri-o:OCI运行时
  • rktlet:rkt容器运行时
  • frakti:基于hypervisor的容器运行时

4. 如何开启

要开启CRI接口,kubelet主要需要配置两个参数,即–container-runtime-endpoint和–image-service-endpoint。

假如你不是使用的dockershim,则你需要自己启动CRI服务器端

文章转自:http://licyhust.com/%E5%AE%B9%E5%99%A8%E6%8A%80%E6%9C%AF/2017/11/03/cri/

Logo

开源、云原生的融合云平台

更多推荐