先从一个报错开始吧
[root@node-129 kubernetes]# crictl ps
WARN[0000] runtime connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
WARN[0000] image connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
E0717 03:21:14.371287 48865 remote_runtime.go:390] "ListContainers with filter from runtime service failed" err="rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial unix /var/run/dockershim.sock: connect: no such file or directory\"" filter="&ContainerFilter{Id:,State:&ContainerStateValue{State:CONTAINER_RUNNING,},PodSandboxId:,LabelSelector:map[string]string{},}"
FATA[0000] listing containers: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial unix /var/run/dockershim.sock: connect: no such file or directory"
错误信息可以看到crictl连接的runtime是docker,并且连接失败。查看containerd启动信息(journalctl -exu containerd),containerd启动完成后监听的unix sock路径是:/run/containerd/containerd.sock。
创建crictl配置文件:/etc/crictl.yaml。修改crictl默认配置,把runtime-endpoint和image-endpoint指向containerd
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: true
pull-image-on-create: false
修改后
[root@node-129 kubernetes]# crictl ps
DEBU[0000] get runtime connection
DEBU[0000] get image connection
DEBU[0000] ListContainerResponse:
...
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
4ceba0f7bfc5a 38c11b8f4aa19 52 minutes ago Running kube-flannel 0 567933503bde5 kube-flannel-ds-bxvqv
d2572be6709d3 5f82fc39fa816 About an hour ago Running kube-proxy 0 2f0c651c078ab kube-proxy-wc9zz
d5cedeb28123c 86b6af7dd652c About an hour ago Running etcd 1 ca981be82701c etcd-node-129
8d4fe5da9d6ce 95fe52ed44570 About an hour ago Running kube-controller-manager 1 b0920110bc805 kube-controller-manager-node-129
46d11f2893f06 6f707f569b572 About an hour ago Running kube-apiserver 1 11762c37e44d5 kube-apiserver-node-129
de7f51d606efa f73f1b39c3fe8 About an hour ago Running kube-scheduler 1 e33497db48470 kube-scheduler-node-129
由于本次部署k8s使用kubeadm,而其容器引擎使用的是containerd,作为新产品(相对于docker),他们有什么区别与联系呢?
1. docker 和 containerd
- docker 由 docker-client ,dockerd,containerd,docker-shim,runc 组成,所以 containerd 是 docker 的基础组件之一
- 从 k8s 的角度看,可以选择 containerd 或 docker 作为运行时组件:其中 containerd 调用链更短,组件更少,更稳定,占用节点资源更少。所以 k8s 后来的版本开始默认使用 containerd 。
- containerd 相比于 docker , 多了 namespace 概念,每个 image 和 container 都会在各自的 namespace 下可见。
- docker 作为 k8s 容器运行时,调用关系为:kubelet --> dockershim (在 kubelet 进程中) --> dockerd --> containerd
containerd 作为 k8s 容器运行时,调用关系为:kubelet --> cri plugin(在 containerd 进程中) --> containerd
至于docker和containerd的恩怨情仇,前文中已经提及,此处不再赘述。
1.1 命令区分
- ctr 是 containerd 的一个客户端工具。
- crictl 是 CRI 兼容的容器运行时命令行接口,可以使用它来检查和调试 k8s 节点上的容器运行时和应用程序。
ctr -v 输出的是 containerd 的版本,crictl -v 输出的是当前 k8s 的版本,从结果显而易见你可以认为 crictl 是用于 k8s 的。
[root@node-129 kubernetes]# crictl -v
crictl version v1.26.0
[root@node-129 kubernetes]# ctr -v
ctr containerd.io 1.6.21
所以说某个主机安装了 k8s 后,命令行才会有 crictl 命令。而 ctr 是跟 k8s 无关的,主机安装了 containerd 服务后就可以操作 ctr 命令。
1.2 常用命令
又是一大波的命令来袭
命令 | docker | ctr(containerd) | crictl(kubernetes) |
---|---|---|---|
查看运行的容器 | docker ps | ctr task ls/ctr container ls | crictl ps |
查看镜像 | docker images | ctr image ls | crictl images |
查看容器日志 | docker logs | 无 | crictl logs |
查看容器数据信息 | docker inspect | ctr container info | crictl inspect |
查看容器资源 | docker stats | 无 | crictl stats |
启动/关闭已有的容器 | docker start/stop | ctr task start/kill | crictl start/stop |
运行一个新的容器 | docker run | ctr run | 无(最小单元为 pod) |
修改镜像标签 | docker tag | ctr image tag | 无 |
创建一个新的容器 | docker create | ctr container create | crictl create |
导入镜像 | docker load | ctr image import | 无 |
导出镜像 | docker save | ctr image export | 无 |
删除容器 | docker rm | ctr container rm | crictl rm |
删除镜像 | docker rmi | ctr image rm | crictl rmi |
拉取镜像 | docker pull | ctr image pull | ctictl pull |
推送镜像 | docker push | ctr image push | 无 |
在容器内部执行命令 | docker exec | 无 | crictl exec |
ctr并没有build命令,也就是没办法构建镜像,怎么办呢?
containerd 有一个子项目:nerdctl ,用来兼容 docker cli,可以像 docker 命令一样来管理本地的镜像和容器
想深入了解的朋友可以参考containerd 镜像构建工具 – nerdctl 和 buildkit
1.3 关于crictl
#查看containerd客户端即服务器版本信息
ctr version
#ctr全局命令概览
[root@localhost ~]# ctr --help
USAGE: (注意看这个格式:ctr 全局选项 命令 命令选项 参数)
ctr [global options] command [command options] [arguments...]
COMMANDS:
plugins, plugin provides information about containerd plugins
version 打印客户端和服务端版本
containers, c, container 管理containers
content 管理content
events, event 显示containerd events
images, image, i 管理镜像
leases 管理leases
namespaces, namespace, ns 管理namespaces
pprof provide golang pprof outputs for containerd
run 运行一个container
snapshots, snapshot 管理snapshots
tasks, t, task 管理tasks
install 安装一个新的package
oci OCI tools
shim interact with a shim directly
help, h 显示命令帮助
全局选项:
--debug 在logs中开启enable输出
--address value, -a value containerd's GRPC server的地址 (默认: "/run/containerd/containerd.sock")
--timeout value ctr命令超时时间(默认: 0s)
--connect-timeout value 连接containerd超时时间 (默认: 0s)
--namespace value, -n value 命名空间 (默认: "default")
--help, -h 显示帮助
--version, -v 打印版本信息
万幸的是,containerd和docker的镜像是通用的(想想也是,真想直接取代docker也不太可能的,毕竟受众在那呢)
[root@node-129 kubernetes]# ctr image import my.tar
unpacking docker.io/library/mypython:latest (sha256:962b1654766f57616a6f36a67e8eaac6c67b13e79207f4864d85ab1a5641bdc5)...done
[root@node-129 kubernetes]# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
docker.io/library/mypython:latest application/vnd.docker.distribution.manifest.v2+json sha256:962b1654766f57616a6f36a67e8eaac6c67b13e79207f4864d85ab1a5641bdc5 348.5 MiB linux/amd64 -
[root@node-129 kubernetes]# ctr i tag docker.io/library/mypython:latest mypython:latest
mypython:latest
[root@node-129 kubernetes]# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
docker.io/library/mypython:latest application/vnd.docker.distribution.manifest.v2+json sha256:962b1654766f57616a6f36a67e8eaac6c67b13e79207f4864d85ab1a5641bdc5 348.5 MiB linux/amd64 -
mypython:latest application/vnd.docker.distribution.manifest.v2+json sha256:962b1654766f57616a6f36a67e8eaac6c67b13e79207f4864d85ab1a5641bdc5 348.5 MiB linux/amd64 -
2. 示例
2.1 部署nginx
[root@node-128 kubernetes]# cat nginx-svc-deploy.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-servie
name: nginx-service
namespace: hello-world
spec:
ports:
- nodePort: 30013
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-pod
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
namespace: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
namespace: hello-world
spec:
containers:
- image: docker.io/library/nginx:latest
name: nginx
ports:
- containerPort: 80
resources: {}
我们先创建命名空间hello-world,然后部署
[root@node-128 kubernetes]# kubectl create namespace hello-world
namespace/hello-world created
[root@node-128 kubernetes]# kubectl apply -f nginx-svc-deploy.yaml
service/nginx-service created
deployment.apps/nginx-deploy created
[root@node-128 kubernetes]# kubectl get pods -n hello-world
NAME READY STATUS RESTARTS AGE
nginx-deploy-65fcf47dd5-62sgb 1/1 Running 0 6m42s
可以看到我们访问VIP展现了nginx的主页面
[root@node-128 kubernetes]# curl http://192.168.17.120:30013/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>