主要介绍containerd的基本概念,以及docker的一些总结。

containerd

容器运行时(ContainerRuntime),运行于 kubernetes(k8s)集群的每个节点中,负责容器的整个生命周期,其中 docker 是目前应用最广的。

随着容器云的发展,越来越多的容器运行时涌现。为了解决这些容器运行时和 k8s 的集成问题,在 k8s 1.5 版本中,社区推出了
CRI(ContainerRuntimeInterface,容器运行时接口),以支持更多的容器运行时。

Kubelet 通过 CRI 和容器运行时进行通信,使得容器运行时能够像插件一样单独运行。可以说每个容器运行时都有自己的优势,这就允许用户更容易选择和替换自己的容器运行时。

image-tGyu.png

CRI & OCI

OCI(OpenContainerInitiative,开放容器计划)定义了创建容器的格式和运行时的开源行业标准,包括镜像规范(ImageSpecification)和运行时规范(RuntimeSpecification)。

镜像规范定义了 OCI 镜像的标准。高层级运行时将会下载一个 OCI 镜像,并把它解压成 OCI 运行时文件系统包(filesystembundle)。

image-VGmb.png

运行时规范则描述了如何从 OCI 运行时文件系统包运行容器程序,并且定义它的配置、运行环境和生命周期。如何为新容器设置命名空间(namepsaces)和控制组(cgroups),以及挂载根文件系统等等操作,都是在这里定义的。它的一个参考实现是runC。我们称其为低层级运行时(Low-levelRuntime)。除runC 以外,也有很多其他的运行时遵循 OCI 标准,例如 kata-runtime。

为什么弃用Docker

目前 docker 仍是 kubernetes 默认的容器运行时。那为什么会选择换掉 docker 呢?主要的原因是它的复杂性。

我们总结了 docker,containerd 以及 cri-o 的详细调用层级。Docker的多层封装和调用,导致其在可维护性上略逊一筹,增加了线上问题的定位难度(貌似除了重启docker,我们就毫无他法了)。Containerd 和cri-o 的方案比起 docker 简洁很多。因此我们更偏向于选用更加简单和纯粹的 containerd 和 cri-o 作为我们的容器运行时。

image-AZNg.png

我们对 containerd 和 cri-o 进行了一组性能测试,包括创建、启动、停止和删除容器,以比较它们所耗的时间。

containerd在各个方面都表现良好,除了启动容器这项。从总用时来看,containerd 的用时还是要比 cri-o 要短的。

image-AucG.png

从功能性来讲,containerd 和 cri-o 都符合 CRI 和 OCI 的标准。从稳定性来说,单独使用 containerd 和 cri-o都没有足够的生产环境经验。但庆幸的是,containerd 一直在 docker 里使用,而 docker 的生产环境经验可以说比较充足。可见在稳定性上containerd 略胜一筹。所以我们最终选用了 containerd。

containerd操作

更换 containerd 后,常用的 docker 命令也不再有用,containerd 命令行客户端如下图所示:

image-sPeO.png

  • ctr -v 输出的是 containerd 的版本,crictl -v 输出的是当前 k8s 的版本,从结果显而易见你可以认为 crictl 是用于 k8s 的。
  • 一般来说你某个主机安装了 k8s 后,命令行才会有 crictl 命令。而 ctr 是跟 k8s 无关的,你主机安装了 containerd 服务后就可以操作
    ctr 命令。

用 crictl 运行 Pod 沙盒对容器运行时排错很有帮助。 在运行的 Kubernetes 集群中,沙盒会随机地被 kubelet 停止和删除。因此
crictl 尽量不要在单独起容器的情况下使用,因为容器会被停止和删除。

先提前放出docker/ctr/crictl之间命令的对比,后面会详细介绍。

命令dockerctr(containerd)crictl(kubernetes)
查看运行的容器docker psctr task ls/ctr container lscrictl ps
查看镜像docker imagesctr image lscrictl images
查看容器日志docker logscrictl logs
查看容器数据信息docker inspectctr container infocrictl inspect
查看容器资源docker statscrictl stats
启动/关闭已有的容器docker start/stopctr task start/killcrictl start/stop
运行一个新的容器docker runctr run无(最小单元为pod)
打标签docker tagctr image tag
创建一个新的容器docker createctr container createcrictl create
导入镜像docker loadctr image import
导出镜像docker savectr image export
删除容器docker rmctr container rmcrictl rm
删除镜像docker rmictr image rmcrictl rmi
拉取镜像docker pullctr image pullctictl pull
推送镜像docker pushctr image push
登录或在容器内部执行命令docker execcrictl exec
清空不用的容器docker image prunecrictl rmi –prune

更多命令操作,可以直接在命令行输入命令查看帮助。

docker --help
ctr --help
crictl --help

以下是各种客户端操作 containerd 的命令,因为之后会安装 k8s,很多操作通过 k8s 直接就完成了,所以对应命令可以先做了解即可。

containerd 客户端 ctr

ctr 是 containerd 项目的一部分提供的命令行客户端。如果一台机器上运行了 containerd,那么ctr二进制文件也一般会进行安装。

由于 containerd 有 namespaces 的概念,对于上层编排系统的支持,ctr 客户端主要区分了3个命名空间分别是k8s.io、moby和default,以上我们用
crictl 操作的均在 k8s.io 命名空间,使用 ctr 看镜像列表就需要加上 -n 参数。crictl 只有一个 k8s.io 命名空间,但是没有 -n 参数。

我们知道 Docker 也是默认调用的 containerd, Docker 使用的命名空间默认是 moby,而不是 default,所以假如我们用 docker
启动容器,那么我们也可以通过 ctr -n moby 来定位容器信息。

【温馨提示】ctr images pull 拉取的镜像默认放在default,而 crictl pull 和 kubelet 默认拉取的镜像都在 k8s.io 命名空间下。所以通过
ctr 导入镜像的时候特别注意一点,最好指定命名空间。

命令示例

# 注意 -n 不能放在命令最后面,下面查看的镜像是一样的
ctr -n=k8s.io image ls
ctr -n k8s.io image ls

# 使用ctr命令指定命名空间导入镜像
ctr -n=k8s.io image import dashboard.tar

ctr 命令

ctr 命令的参数和全局参数如下。

参数命令的格式为:ctr [global options] command [command options] [arguments...]
全局参数可以在任何命令后面使用,并且可以多个参数组合使用。

COMMANDS:
   plugins, plugin            provides information about containerd plugins
   version                    print the client and server versions
   containers, c, container   manage containers
   content                    manage content
   events, event              display containerd events
   images, image, i           manage images
   leases                     manage leases
   namespaces, namespace, ns  manage namespaces
   pprof                      provide golang pprof outputs for containerd
   run                        run a container
   snapshots, snapshot        manage snapshots
   tasks, t, task             manage tasks
   install                    install a new package
   oci                        OCI tools
   shim                       interact with a shim directly
   help, h                    Shows a list of commands or help for one command

GLOBAL OPTIONS:
--debug                      enable debug output in logs
--address value, -a value    address for containerd's GRPC server (default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS]
--timeout value              total timeout for ctr commands (default: 0s)
--connect-timeout value      timeout for connecting to containerd (default: 0s)
--namespace value, -n value  namespace to use with commands (default: "default") [$CONTAINERD_NAMESPACE]
--help, -h                   show help
--version, -v                print the version
  1. 查看版本
ctr -v
ctr --version
  1. 指定空间
ctr -n k8s.io image ls

namespace 相关操作

ctr 所有的命令都支持 -n 参数,用于指定命名空间,如果不指定命名空间,默认为default命名空间。命名空间的概念类似于 docker
的仓库,但是不同的是,docker 的仓库是一个集中的仓库,而 ctr 的命名空间是分布式的,每个命名空间都是一个独立的仓库。

命令 ctr namespace 用于管理命名空间,包括查看、创建和删除命名空间。可以简化为 ctrns

  1. 查看命名空间
  • shell ctr namespace ls
  1. 创建命名空间
  • ctr namespace create k8s.io
  1. 删除命名空间
  • ctr namespace rm k8s.io

镜像相关操作

镜像相关命令如下。

# ctr image -h
NAME:
   ctr images - manage images

USAGE:
   ctr images command [command options] [arguments...]

COMMANDS:

   check       check existing images to ensure all content is available locally
   export      export images
   import      import images
   list, ls    list images known to containerd
   mount       mount an image to a target path
   unmount     unmount the image from the target
   pull        pull an image from a remote
   push        push an image to a remote
   remove, rm  remove one or more images by reference
   tag         tag an image
   label       set and clear labels for an image
   convert     convert an image

OPTIONS:
   --help, -h  show help
  1. 拉取推送镜像
# 拉取镜像
# docker默认是docker.io官网去找镜像,所以docker拉去镜像可以这样写:docker pull nginx:alpine,而containerd没有默认仓库,所以必须写完整的镜像名字才能拉去镜像
ctr i pull docker.io/library/nginx:alpine
   
# 推送镜像到harbor
#
# --namespace=k8s.io 指定命名空间,不是必须,根据环境而定
# --skip-verify 跳过认证
# --user 指定harbor用户名及密码
ctr --namespace=k8s.io images push harbor.mydomain.com/k8s/pause:1.25.1 --skip-verify --user admin:Harbor12345

# 不想 -u user:password 可以在配置文件进行配置,也可以使用 nerdctl ,下面有介绍
   
# 拉取带认证的镜像
ctr images pull --user admin:Harbor12345 --tlscacert=/etc/containerd/harbor.mydomain.com/ca.crt harbor.mydomain.com/k8s/pause:1.25.1
  1. 检查镜像列表,确认镜像是否存在以及镜像的完整性,主要查看其中的 STATUScomplete 表示镜像是完整可用的状态。
ctr image check
ctr i check
  1. 导入/导出镜像
ctr i export nginx.tar.gz docker.io/library/nginx:alpine
ctr i import nginx.tar.gz
  1. 查看镜像列表
ctr i ls
ctr i list
# 只查看镜像名称
ctr i ls -q
  1. 挂载/卸载镜像
# ctr 支持将镜像挂载到指定目录,这样就可以直接访问镜像中的文件了,而不需要启动容器,可以确认镜像中的文件是否正确
ctr i mount docker.io/library/nginx:alpine /tmp/nginx
ctr i unmount /tmp/nginx
  1. 删除镜像
ctr i rm nginx:alpine
ctr i remove nginx:alpine
  1. 打标签
# crictl 没有 tag 命令,只能使用 nerdctl 和 ctr,必须指定命名空间,要不然 kubelet 无法使用。
ctr -n k8s.io i tag my-nginx:v1 harbor.mydomain.com/my-nginx:v1
  1. 镜像转换
# ctr 支持将镜像转换为 OCI 格式,这样就可以使用其他容器运行时运行镜像了,比如 runc
ctr i convert --oci nginx:alpine nginx:alpine-oci
# 也支持将 OCI 格式的镜像转换为 docker 格式
ctr i convert nginx:alpine nginx:alpine-docker
  1. 镜像构建
  • containerd 不提供开箱即用的镜像构建支持。一般使用更高级别的工具用来构建镜像,比如 docker。

  • cat > Dockerfile <<EOF
    FROM nginx:alpine
    RUN echo 'Build Image From Containerd' > /usr/share/nginx/html/index.html
    EOF
    
    # 可以使用docker构建镜像,然后导出到本地,再使用ctr导入到containerd
    docker build -t my-nginx:v1 .
    docker save -o my-nginx.tar my-nginx:v1
     
    ctr images import my-nginx.tar
    
    # 或者使用nerdctl进行构建,与docker功能一样
    # 不加-n指定命名空间,crictl看不到,kubelet也不能使用它,默认在default命名空间下
    nerdctl -n k8s.io build -t nginx:nerctl -f ./Dockerfile .
    
    # 参数解释:(下一节会有 nerctl 介绍)
    # -t:指定镜像名称
    # . :当前目录Dockerfile
    # -f:指定Dockerfile路径
    #  --no-cache:不缓存
    

容器相关操作

容器相关操作,包括创建、启动、停止、删除等。

 ~# ctr container --help
 NAME:
    ctr containers - manage containers
 
 USAGE:
    ctr containers command [command options] [arguments...]
 
 COMMANDS:
    create           create container
    delete, del, rm  delete one or more existing containers
    info             get info about a container
    list, ls         list containers
    label            set and clear labels for a container
    checkpoint       checkpoint a container
    restore          restore a container from checkpoint
 
 OPTIONS:
    --help, -h  show help
  1. 创建容器
# container 只是创建了静态容器,此时容器还未启动运行。如果要启动容器,需要使用 task start 命令。
ctr c create docker.io/library/nginx:alpine my-nginx
  1. 删除容器
ctr c rm my-nginx
ctr c delete my-nginx
ctr c del my-nginx
  1. 查看指定容器的信息
ctr c info my-nginx
  1. 查看所有容器
ctr c ls
ctr c list
  1. 容器标签
# 容器标签可以用来标记容器,方便管理(只能通过 ctr c info 查看, ctr ls 不会显示)
ctr c label my-nginx mylabel=nginx
  1. 容器检查点
# 容器检查点可以用来备份容器,方便恢复 (没有测试)
ctr c checkpoint my-nginx mycheckpoint
ctr c restore my-nginx mycheckpoint

管理任务

管理任务,包括创建、启动、停止、删除等。

# ctr task --help
NAME:
   ctr tasks - manage tasks

USAGE:
   ctr tasks command [command options] [arguments...]

COMMANDS:
   attach           attach to the IO of a running container
   checkpoint       checkpoint a container
   delete, rm       delete one or more tasks
   exec             execute additional processes in an existing container
   list, ls         list tasks
   kill             signal a container (default: SIGTERM)
   pause            pause an existing container
   ps               list processes for container
   resume           resume a paused container
   start            start a container that has been created
   metrics, metric  get a single data point of metrics for a task with the built-in Linux runtime

OPTIONS:
   --help, -h  show help
  1. 启动已经创建的容器
ctr t start my-nginx
ctr t start -d my-nginx
  1. 查看任务
ctr t ls
ctr t list
  1. 查看任务中的进程
# 注意:这里的进程是指容器中进程在宿主机上的进程号。
ctr t ps my-nginx
  1. 任务中执行命令
ctr t exec my-nginx ls /
# 进入容器内部终端,997,是随便指定的,只要不重复就行
ctr t exec --exec-id 997 -t my-nginx /bin/sh
  1. 暂停/回复任务
ctr t pause my-nginx
ctr t resume my-nginx
  1. 杀死/删除任务
# 只是给任务发送了 SIGTERM 信号,任务还是存在的,状态为 stopped
ctr t kill my-nginx
# 删除任务,任务必须是 stopped 状态
ctr t rm my-nginx
ctr t delete my-nginx
   
# 给特定进程发送信号,这里是把刚刚创建的进程强制杀死
ctr t kill --exec-id 999 -s SIGTERM my-nginx
  1. 获取任务的指标
# 我们可以通过metric命令获取容器关于cgroup相关的信息,包括CPU、内存、PID的限额和使用情况等。
ctr t metric my-nginx

运行容器

容器运行需要进行两步,第一步是创建容器,第二步是启动容器。

使用ctr run命令可以一步到位,创建并启动容器。

# ctr run --help
NAME:
   ctr run - run a container

USAGE:
   ctr run [command options] [flags] Image|RootFS ID [COMMAND] [ARG...]

OPTIONS:
   --rm                                    remove the container after running
   --null-io                               send all IO to /dev/null
   --log-uri value                         log uri
   --detach, -d                            detach from the task after it has started execution
   --fifo-dir value                        directory used for storing IO FIFOs
   --cgroup value                          cgroup path (To disable use of cgroup, set to "" explicitly)
   --platform value                        run image for specific platform
   --runc-binary value                     specify runc-compatible binary
   --runc-root value                       specify runc-compatible root
   --runc-systemd-cgroup                   start runc with systemd cgroup manager
   --uidmap container-uid:host-uid:length  run inside a user namespace with the specified UID mapping range; specified with the format container-uid:host-uid:length
   --gidmap container-gid:host-gid:length  run inside a user namespace with the specified GID mapping range; specified with the format container-gid:host-gid:length
   --remap-labels                          provide the user namespace ID remapping to the snapshotter via label options; requires snapshotter support
   --cpus value                            set the CFS cpu quota (default: 0)
   --cni                                   enable cni networking for the container
   --snapshotter value                     snapshotter name. Empty value stands for the default value. [$CONTAINERD_SNAPSHOTTER]
   --config value, -c value                path to the runtime-specific spec config file
   --cwd value                             specify the working directory of the process
   --env value                             specify additional container environment variables (e.g. FOO=bar)
   --env-file value                        specify additional container environment variables in a file(e.g. FOO=bar, one per line)
   --label value                           specify additional labels (e.g. foo=bar)
   --mount value                           specify additional container mount (e.g. type=bind,src=/tmp,dst=/host,options=rbind:ro)
   --net-host                              enable host networking for the container
   --privileged                            run privileged container
   --read-only                             set the containers filesystem as readonly
   --runtime value                         runtime name (default: "io.containerd.runc.v2")
   --runtime-config-path value             optional runtime config path
   --tty, -t                               allocate a TTY for the container
   --with-ns value                         specify existing Linux namespaces to join at container runtime (format '<nstype>:<path>')
   --pid-file value                        file path to write the task's pid
   --gpus value                            add gpus to the container (default: 0)
   --allow-new-privs                       turn off OCI spec's NoNewPrivileges feature flag
   --memory-limit value                    memory limit (in bytes) for the container (default: 0)
   --device value                          file path to a device to add to the container; or a path to a directory tree of devices to add to the container
   --seccomp                               enable the default seccomp profile
   --seccomp-profile value                 file path to custom seccomp profile. seccomp must be set to true, before using seccomp-profile
   --apparmor-default-profile value        enable AppArmor with the default profile with the specified name, e.g. "cri-containerd.apparmor.d"
   --apparmor-profile value                enable AppArmor with an existing custom profile
   --rootfs                                use custom rootfs that is not managed by containerd snapshotter
   --no-pivot                              disable use of pivot-root (linux only)
   --cpu-quota value                       Limit CPU CFS quota (default: -1)

创建并启动容器

ctr run -d -t --net-host docker.io/library/nginx:alpine my-nginx

containerd 客户端 nerdctl

推荐使用 nerdctl,使用效果与 docker 命令的语法一致
二进制包的 github 下载链接:https://github.com/containerd/nerdctl/releases

  • 精简 (nerdctl-{version}-linux-amd64.tar.gz): 只包含nerdctl
  • 完整 (nerdctl-full-{version}-linux-amd64.tar.gz): 包含 containerd, runc, and CNI等依赖
    nerdctl 的目标并不是单纯地复制 docker 的功能,它还实现了很多 docker 不具备的功能,例如延迟拉取镜像(lazy-pulling)、镜像加密(imgcrypt)等。

image-zJTJ.png

安装 nerdctl

精简版只包含nerdctl,完整版包含nerdctl和CNI插件等依赖,k8s的网络插件会在/opt/cni/bin/下会生成cni插件目录。这里选择完整版进行安装,因为启动容器的时候配置网络需要cni网络插件的支持。

  1. 精简版 nerdctl 安装
wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
# 解压
tar -xf nerdctl-0.22.2-linux-amd64.tar.gz

# 查看解压后的文件,可以看见除了nerdctl还有containerd-rootless-setuptool.sh、containerd-rootless.sh,另外两个文件是用来在非root用户下使用nerdctl的
ls -l

total 37624
-rwxr-xr-x 1 root root    21562 Aug  1  2022 containerd-rootless-setuptool.sh
-rwxr-xr-x 1 root root     7032 Aug  1  2022 containerd-rootless.sh
-rwxr-xr-x 1 root root 27807744 Aug  1  2022 nerdctl
-rw-r--r-- 1 root root 10685899 Aug  1  2022 nerdctl-0.22.2-linux-amd64.tar.gz
   
# 将nerdctl复制到/usr/local/bin/目录下,这样就可以直接使用nerdctl命令了。具体目录根据机器上的PATH环境变量来定。
cp nerdctl /usr/local/bin/
  1. 完整版 nerdctl 安装
wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-full-0.22.2-linux-amd64.tar.gz
# 解压后还有如下4个目录 
# 1. bin(二进制模式,包括 nerdctl buildkitd runc tini等)
# 2. lib(systemctl 的 service 文件)
# 3. libexec(cni组件)
# 4. share(说明文档)
tar -xf nerdctl-full-0.22.2-linux-amd64.tar.gz -C /usr/local/

# 将service文件复制到/etc/systemd/system/目录下
cp /usr/local/lib/systemd/system/*.service /etc/systemd/system/

# 启动服务buildkit
systemctl enable buildkit containerd --now
systemctl status buildkit containerd
  1. 安装 buildkit 支持构建镜像

    buildkit GitHub地址: https://github.com/moby/buildkit

    使用精简版 nerdctl 无法直接通过 containerd 构建镜像,需要与 buildkit 组全使用以实现镜像构建。当然你也可以安装上面的完整
    nerdctl,完整版可以直接使用 nerdctl build 命令构建镜像,是因为完整版已经有现成的 buildkit.service 服务了。
    buildkit项目是Docker公司开源出来的一个构建工具包,支持OCI标准的镜像构建。它主要包含以下部分:

    • 服务端buildkitd,当前支持runc和containerd作为worker,默认是runc;
    • 客户端buildctl,负责解析Dockerfile,并向服务端buildkitd发出构建请求。
    • buildkit是典型的C/S架构,client和server可以不在一台服务器上。而nerdctl在构建镜像方面也可以作为buildkitd的客户端。
# 下载地址 https://github.com/moby/buildkit/releases
wget https://github.com/moby/buildkit/releases/download/v0.10.4/buildkit-v0.10.4.linux-amd64.tar.gz

# 解压之后只有一个bin目录,里面有buildkit所需要的二进制文件
# 以下的命令会将buildkit的二进制文件合并到/usr/local/bin/目录下
tar -xf buildkit-v0.10.4.linux-amd64.tar.gz  -C /usr/local/

# buildkit需要配置两个文件:
# 1. /usr/lib/systemd/system/buildkit.socket
# 2. /usr/lib/systemd/system/buildkit.service

cat > /etc/systemd/system/buildkit.socket <<EOF
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit
[Socket]
ListenStream=%t/buildkit/buildkitd.sock
SocketMode=0660
[Install]
WantedBy=sockets.target
EOF

cat > /etc/systemd/system/buildkit.service << EOF
[Unit]
Description=BuildKit
Requires=buildkit.socket
After=buildkit.socket
Documentation=https://github.com/moby/buildkit
[Service]
# Replace runc builds with containerd builds  
ExecStart=/usr/local/bin/buildkitd --addr fd://
[Install]
WantedBy=multi-user.target
EOF

# 启动buildkit
systemctl daemon-reload
systemctl enable buildkit --now
  1. 设置nerdctl自动补全
# 编辑文件
vim /etc/profile
source <(nerdctl completion bash)
# 让其生效
source /etc/profile

namespace 相关操作

  1. 创建 namespace
nerdctl namespace create mynamespace
  1. 列出 namespace
nerdctl namespace ls
  1. 删除 namespace
nerdctl namespace rm mynamespace

镜像相关操作

  1. 拉取镜像
nerdctl pull nginx:alpine
  1. 列出镜像
nerdctl image ls
  1. 删除镜像
nerdctl image rm nginx:alpine
  1. 拉取推送镜像
# 拉取镜像
nerdctl pull nginx:alpine
# 重命名镜像
nerdctl image tag nginx:alpine harbor.mydomain.com/library/nginx:alpine
# 推送镜像
nerdctl push harbor.mydomain.com/library/nginx:alpine

更详细的镜像拉取操作请参考下面的内容:

# http方式,配置如下:
mkdir -p /etc/containerd/harbor.mydomain.com
cat > /etc/containerd/certs.d/harbor.mydomain.com/hosts.toml <<EOF
server = "https://docker.io"

[host."http://myharbor-minio.com"]
capabilities = ["pull", "resolve","push"]
# skip_verify = true
# ca = "ca.crt" #相对路径
# ca = "/opt/auth/ca.crt" #绝对路径
# ca = ["/opt/auth/ca.crt"]
# ca = ["ca.crt"]
# client = [["/opt/auth/nginx.cclinux.cn.crt", "/opt/auth/nginx.cclinux.cn.key"]]
EOF
   
# https方式,配置如下:
mkdir -p /etc/containerd/certs.d/harbor.secure.mydomain.com:443

cat > /etc/containerd/certs.d/harbor.secure.mydomain.com\:443/hosts.toml <<EOF
server = "https://docker.io"

[host."https://harbor.secure.mydomain.com:443"]
capabilities = ["pull", "resolve","push"]
skip_verify = true
# ca = "ca.crt" #相对路径
# ca = "/opt/auth/ca.crt" #绝对路径
# ca = ["/opt/auth/ca.crt"]
ca = ["/etc/containerd/harbor.secure.mydomain.com/ca.crt"]
# client = [["/opt/auth/nginx.cclinux.cn.crt", "/opt/auth/nginx.cclinux.cn.key"]]
EOF
   
# 可以通过 nerdctl 登录
echo Harbor12345 | nerdctl login --username "admin" --password-stdin harbor.secure.mydomain.com:443
   
# 登出命令
# nerdctl logout harbor.secure.mydomain.com:443
   
# 推送到私有仓库
nerdctl --insecure-registry --namespace=k8s.io push harbor.secure.mydomain.com:443/k8s/pause:1.25.1
  1. 镜像构建
# 从Dockerfile构建镜像
nerdctl build -t nginx:my-alpine -f Dockerfile .
# 从Dockerfile构建镜像并推送到私有仓库
nerdctl build -t harbor.secure.mydomain.com:443/k8s/nginx:alpine -f Dockerfile 

容器相关操作

  1. 创建容器
nerdctl run -d --name mynginx -p 80:80 nginx:alpine
  1. 列出容器
nerdctl ps -a
nerdctl container ls -a
  1. 删除容器(停止容器后才能删除)
nerdctl stop mynginx
nerdctl rm mynginx
   
nerdctl container stop mynginx
nerdctl container rm mynginx
  1. 进入容器
nerdctl exec -it mynginx sh

nerdcrl container exec -it mynginx sh
  1. 查看容器日志
nerdctl logs mynginx
   
nerdctl container logs mynginx
  1. 查看容器详细信息
nerdctl inspect mynginx
   
nerdctl container inspect mynginx
  1. 查看容器内进程
nerdctl top mynginx

k8s 操作 containerd 的客户端 crictl

crictl 命令

这里我使用的是 crictl v1.26.0 版本,命令里面有些是与 pod 相关的,暂时略过,这里只介绍与 container 相关的命令。

crictl -h
NAME:
   crictl - client for CRI

USAGE:
   crictl [global options] command [command options] [arguments...]

VERSION:
   v1.26.0

COMMANDS:
   attach              Attach to a running container
   create              Create a new container
   exec                Run a command in a running container
   version             Display runtime version information
   images, image, img  List images
   inspect             Display the status of one or more containers
   inspecti            Return the status of one or more images
   imagefsinfo         Return image filesystem info
   inspectp            Display the status of one or more pods
   logs                Fetch the logs of a container
   port-forward        Forward local port to a pod
   ps                  List containers
   pull                Pull an image from a registry
   run                 Run a new container inside a sandbox
   runp                Run a new pod
   rm                  Remove one or more containers
   rmi                 Remove one or more images
   rmp                 Remove one or more pods
   pods                List pods
   start               Start one or more created containers
   info                Display information of the container runtime
   stop                Stop one or more running containers
   stopp               Stop one or more running pods
   update              Update one or more running containers
   config              Get and set crictl client configuration options
   stats               List container(s) resource usage statistics
   statsp              List pod resource usage statistics
   completion          Output shell completion code
   checkpoint          Checkpoint one or more running containers
   help, h             Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --config value, -c value            Location of the client config file. If not specified and the default does not exist, the program's directory is searched as well (default: "/etc/crictl.yaml") [$CRI_CONFIG_FILE]
   --debug, -D                         Enable debug mode (default: false)
   --image-endpoint value, -i value    Endpoint of CRI image manager service (default: uses 'runtime-endpoint' setting) [$IMAGE_SERVICE_ENDPOINT]
   --runtime-endpoint value, -r value  Endpoint of CRI container runtime service (default: uses in order the first successful one of [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]). Default is now deprecated and the endpoint should be set instead. [$CONTAINER_RUNTIME_ENDPOINT]
   --timeout value, -t value           Timeout of connecting to the server in seconds (e.g. 2s, 20s.). 0 or less is set to default (default: 2s)
   --help, -h                          show help (default: false)
   --version, -v                       print the version (default: false)

命令示例

使用 crictl 命令之前,需要先配置 /etc/crictl.yaml 如下:

vim /etc/crictl.yaml

runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false

# 也可以通过命令进行设置
crictl config runtime-endpoint unix:///run/containerd/containerd.sock
crictl config image-endpoint unix:///run/containerd/containerd.sock

命令行示例:

# crictl 没有 -n 参数,操作都在 k8s.io 命名空间下。
crictl image ls
crictl images
# crictl image list = ctr -n k8s.io image list
# crictl image ls = ctr -n k8s.io image ls
# crictl images = ctr -n k8s.io image list
# crictl images = ctr -n k8s.io image ls

image相关操作

# 查看所有的 image
crictl image list
# 拉取 image
# 注意:回车之后屏幕会卡住,不要着急,正常现象。crictl 没有进度条,拉取镜像的过程中,会一直卡在这里,直到拉取完成,只能耐心等待完成。
crictl pull nginx:1.25
# 删除 image
crictl rmi nginx:1.25

container 相关操作

# 查看所有的 container
crictl ps -a

crictl 运行一个容器比较复杂,需要书写两个 json 文件
比如以下两个文件,一个是 pod-config.json,一个是 container-config.json,其中 pod-config.json 是 pod 的配置,container-config.json 是 container 的配置。
pod 的概念是 k8s 中有的,这里先知道即可。

$ cat pod-config.json
{
    "metadata": {
        "name": "nginx-sandbox",
        "namespace": "default",
        "attempt": 1,
        "uid": "hdishd83djaidwnduwk28bcsb"
    },
    "log_directory": "/tmp",
    "linux": {
    }
}

$ cat container-config.json
{
    "metadata": {
        "name": "busybox"
    },
    "image":{
        "image": "busybox"
    },
    "command": [
        "top"
    ],
    "log_path":"busybox.0.log",
    "linux": {
    }
}
# 根据以上两个文件创建 container, 注意如果 k8s 没有安装好可能会报错,因为 crictl 是 k8s 的客户端,需要 k8s 的环境。
crictl run container-config.json pod-config.json
# 删除 container
crictl rm mynginx
# 进入 container,注意这里的 container id 是 crictl ps -a 查看到的
crictl exec -it <container id> sh
# 查看 container 日志
crictl logs <container id>
# 查看 container 详细信息
crictl inspect <container id>

总结

使用 k8s 后,对于容器的操作,基本上都是通过 kubelet 完成,这个之后会使用到。
镜像的构建推荐使用 docker build 等方式,推送到镜像仓库后,再通过 containerd 进行使用。
查看容器中的日志,使用 crictl logs 命令。
常规的对于 containerd 的操作,推荐使用 nerdctl 命令,使用效果与 docker 命令的语法一致。

docker总结

  1. 清理主机上所有退出的容器
$ docker rm  $(docker ps -aq)
  1. 调试或者排查容器启动错误
## 若有时遇到容器启动失败的情况,可以先使用相同的镜像启动一个临时容器,先进入容器
$ docker run --rm -ti <image_id> sh
## 进入容器后,手动执行该容器对应的ENTRYPOINT或者CMD命令,这样即使出错,容器也不会退出,因为bash作为1号进程,我们只要不退出容器,该容器就不会自动退出

docker总结

如下图所示:
image-nEQx.png

  1. 为了解决软件交付过程中的环境依赖,同时提供一种更加轻量的虚拟化技术,Docker出现了。

  2. 2013年诞生,15年开始迅速发展,从17.03月开始,使用时间日期管理版本,稳定版以每季度为准。

  3. Docker是一种CS架构的软件产品,可以把代码及依赖打包成镜像,作为交付介质,并且把镜像启动成为容器,提供容器生命周期的管理。

  4. 使用yum部署docker,启动后通过操作docker这个命令行,自动调用docker daemon完成容器相关操作。

  5. 常用操作,围绕镜像|容器|仓库三大核心要素

    • systemctl start|stop|restart docker
    • docker build | pull -> docker tag -> docker push
    • docker run –name my-demo -d -p 8080:80 -v /opt/data:/data demo:v20200327 ping xx.com
    • docker cp /path/a.txt mycontainer:/opt
    • docker exec -ti mycontainer /bin/sh
    • docker logs -f –tail=100 mycontainer
  6. 通过dockerfile构建业务镜像,先使用基础镜像,然后通过一系列的指令把我们的业务应用所需要的运行环境和依赖都打包到镜像中,然后通过CMD或者ENTRYPOINT指令把镜像启动时的入口制定好,完成封装即可。有点类似于,先找来一个集装箱模板(基础镜像),然后把项目依赖的服务都扔到集装箱中,然后设置好服务的启动入口,关闭箱门,即完成了业务镜像的制作。

  7. 容器的实现依赖于内核模块提供的namespace和control-group的功能,通过namespace创建一块虚拟空间,空间内实现了各类资源(进程、网络、文件系统)的隔离,提供control-group实现了对隔离的空间的资源使用的限制。

  8. docker镜像使用分层的方式进行存储,根据主机的存储驱动的不同,实现方式会不同,kernel在3.10.0-514以上自动支持overlay2存储驱动,也是目前Docker推荐的方式。

  9. 得益于分层存储的模式,多个容器可以通过copy-on-write的策略,在镜像的最上层加一个可写层,同时利用存储驱动的UnionFS的能力,实现一个镜像快速启动多个容器的场景。

  10. docker的网络模式分为4种,最常用的为bridge和host模式。bridge模式通过docker0网桥,启动容器的时候通过创建一对虚拟网卡,将容器连接在桥上,同时维护了虚拟网卡与网桥端口的关系,实现容器间的通信。容器与宿主机之间的通信通过iptables端口映射的方式,docker利用iptables的PREROUTING和POSTROUTING的nat功能,实现了SNAT与DNAT,使得容器内部的服务被完美的保护起来。

  11. 本章重点内容是docker的核心要素及基础的操作,实现原理以及docker的网络模式为选修包,目的为了帮助有docker基础及经验的同学更好的进一步理解docker。