1 部署 Containerd CRI 的 Kubernetes 集群
前面我们介绍了 containerd 的基本使用,也了解了如何将现有 docker 容器运行时的 Kubernetes 集群切换成 containerd,接下来我们使用 kubeadm 从头搭建一个使用 containerd 作为容器运行时的 Kubernetes 集群,这里我们安装最新的 v1.22.1 版本。1.1 环境准备
3个节点,都是 Centos 7.6 系统,内核版本:3.10.0-1062.4.1.el7.x86_64,在每个节点上添加 hosts 信息:节点的 hostname 必须使用标准的 DNS 命名,另外千万不用什么默认的 localhost 的 hostname,会导致各种错误出现的。在 Kubernetes 项目里,机器的名字以及一切存储在 Etcd 中的 API 对象,都必须使用标准的 DNS 命名(RFC 1123)。可以使用命令 hostnamectl set-hostname node1 来修改 hostname。 禁用防火墙:
➜ ~ cat /etc/hosts
192.168.31.30 master
192.168.31.95 node1
192.168.31.215 node2
禁用 SELINUX:
➜ ~ systemctl stop firewalld
➜ ~ systemctl disable firewalld
由于开启内核 ipv4 转发需要加载 br_netfilter 模块,所以加载下该模块:
➜ ~ setenforce 0
➜ ~ cat /etc/selinux/config
SELINUX=disabled
创建/etc/sysctl.d/k8s.conf文件,添加如下内容:
➜ ~ modprobe br_netfilter
bridge-nf 使得 netfilter 可以对 Linux 网桥上的 IPv4/ARP/IPv6 包过滤。比如,设置net.bridge.bridge-nf-call-iptables=1后,二层的网桥在转发包时也会被 iptables的 FORWARD 规则所过滤。常用的选项包括:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
- net.bridge.bridge-nf-call-arptables:是否在 arptables 的 FORWARD 中过滤网桥的 ARP 包
- net.bridge.bridge-nf-call-ip6tables:是否在 ip6tables 链中过滤 IPv6 包
- net.bridge.bridge-nf-call-iptables:是否在 iptables 链中过滤 IPv4 包
- net.bridge.bridge-nf-filter-vlan-tagged:是否在 iptables/arptables 中过滤打了 vlan 标签的包。
安装 ipvs:
➜ ~ sysctl -p /etc/sysctl.d/k8s.conf
上面脚本创建了的/etc/sysconfig/modules/ipvs.modules文件,保证在节点重启后能自动加载所需模块。使用lsmod | grep -e ip_vs -e nf_conntrack_ipv4命令查看是否已经正确加载所需的内核模块。 接下来还需要确保各个节点上已经安装了 ipset 软件包:
➜ ~ cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
➜ ~ chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4
为了便于查看 ipvs 的代理规则,最好安装一下管理工具 ipvsadm:
➜ ~ yum install ipset
同步服务器时间
➜ ~ yum install ipvsadm
关闭 swap 分区:
➜ ~ yum install chrony -y
➜ ~ systemctl enable chronyd
➜ ~ systemctl start chronyd
➜ ~ chronyc sources
210 Number of sources = 4
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^+ sv1.ggsrv.de 2 6 17 32 -823us[-1128us] +/- 98ms
^- montreal.ca.logiplex.net 2 6 17 32 -17ms[ -17ms] +/- 179ms
^- ntp6.flashdance.cx 2 6 17 32 -32ms[ -32ms] +/- 161ms
^* 119.28.183.184 2 6 33 32 +661us[ +357us] +/- 38ms
➜ ~ date
Tue Aug 31 14:36:14 CST 2021
修改/etc/fstab文件,注释掉 SWAP 的自动挂载,使用free -m确认 swap 已经关闭。swappiness 参数调整,修改/etc/sysctl.d/k8s.conf添加下面一行:
➜ ~ swapoff -a
执行 sysctl -p /etc/sysctl.d/k8s.conf 使修改生效。
vm.swappiness=0
1.2 安装 Containerd
我们已经了解过容器运行时 containerd 的一些基本使用,接下来在各个节点上安装 Containerd。 由于 containerd 需要调用 runc,所以我们也需要先安装 runc,不过 containerd 提供了一个包含相关依赖的压缩包 cri-containerd-cni-${VERSION}.${OS}-${ARCH}.tar.gz,可以直接使用这个包来进行安装。首先从 release 页面下载最新版本的压缩包,当前为 1.5.5 版本:直接将压缩包解压到系统的各个目录中:
➜ ~ wget https://github.com/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz
# 如果有限制,也可以替换成下面的 URL 加速下载
# wget https://download.fastgit.org/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz
然后要将 /usr/local/bin 和 /usr/local/sbin 追加到 ~/.bashrc 文件的 PATH 环境变量中:
➜ ~ tar -C / -xzf cri-containerd-cni-1.5.5-linux-amd64.tar.gz
然后执行下面的命令使其立即生效:
export PATH=$PATH:/usr/local/bin:/usr/local/sbin
containerd 的默认配置文件为 /etc/containerd/config.toml,我们可以通过如下所示的命令生成一个默认的配置:
➜ ~ source ~/.bashrc
对于使用 systemd 作为 init system 的 Linux 的发行版,使用 systemd 作为容器的 cgroup driver 可以确保节点在资源紧张的情况更加稳定,所以推荐将 containerd 的 cgroup driver 配置为 systemd。修改前面生成的配置文件 /etc/containerd/config.toml,在 plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes.runc.options 配置块下面将 SystemdCgroup 设置为 true:
➜ ~ mkdir -p /etc/containerd
➜ ~ containerd config default > /etc/containerd/config.toml
然后再为镜像仓库配置一个加速器,需要在 cri 配置块下面的 registry 配置块下面进行配置 registry.mirrors:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
....
由于上面我们下载的 containerd 压缩包中包含一个 etc/systemd/system/containerd.service 的文件,这样我们就可以通过 systemd 来配置 containerd 作为守护进程运行了,现在我们就可以启动 containerd 了,直接执行下面的命令即可:
[plugins."io.containerd.grpc.v1.cri"]
...
# sandbox_image = "k8s.gcr.io/pause:3.5"
sandbox_image = "registry.aliyuncs.com/k8sxio/pause:3.5"
...
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://bqr1dr1n.mirror.aliyuncs.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://registry.aliyuncs.com/k8sxio"]
启动完成后就可以使用 containerd 的本地 CLI 工具 ctr 和 crictl 了,比如查看版本:
➜ ~ systemctl daemon-reload
➜ ~ systemctl enable containerd --now
➜ ~ ctr version
Client:
Version: v1.5.5
Revision: 72cec4be58a9eb6b2910f5d10f1c01ca47d231c0
Go version: go1.16.6
Server:
Version: v1.5.5
Revision: 72cec4be58a9eb6b2910f5d10f1c01ca47d231c0
UUID: cd2894ad-fd71-4ef7-a09f-5795c7eb4c3b
➜ ~ crictl version
Version: 0.1.0
RuntimeName: containerd
RuntimeVersion: v1.5.5
RuntimeApiVersion: v1alpha2
1.3 使用 kubeadm 部署 Kubernetes
上面的相关环境配置也完成了,现在我们就可以来安装 Kubeadm 了,我们这里是通过指定yum 源的方式来进行安装的:当然了,上面的 yum 源是需要科学上网的,如果不能科学上网的话,我们可以使用阿里云的源进行安装:
➜ ~ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
然后安装 kubeadm、kubelet、kubectl:
➜ ~ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
可以看到我们这里安装的是 v1.22.1 版本,然后将 master 节点的 kubelet 设置成开机启动:
# --disableexcludes 禁掉除了kubernetes之外的别的仓库
➜ ~ yum makecache fast
➜ ~ yum install -y kubelet-1.22.1 kubeadm-1.22.1 kubectl-1.22.1 --disableexcludes=kubernetes
➜ ~ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.1", GitCommit:"632ed300f2c34f6d6d15ca4cef3d3c7073412212", GitTreeState:"clean", BuildDate:"2021-08-19T15:44:22Z", GoVersion:"go1.16.7", Compiler:"gc", Platform:"linux/amd64"}
➜ ~ systemctl enable --now kubelet
:::info
到这里为止上面所有的操作都需要在所有节点执行配置。:::
1.3.1 初始化集群
当我们执行 kubelet —help 命令的时候可以看到原来大部分命令行参数都被 DEPRECATED了,这是因为官方推荐我们使用 —config 来指定配置文件,在配置文件中指定原来这些参数的配置,可以通过官方文档 Set Kubelet parameters via a config file 了解更多相关信息,这样 Kubernetes 就可以支持动态 Kubelet 配置(Dynamic Kubelet Configuration)了,参考 Reconfigure a Node’s Kubelet in a Live Cluster。 然后我们可以通过下面的命令在 master 节点上输出集群初始化默认使用的配置:然后根据我们自己的需求修改配置,比如修改 imageRepository 指定集群初始化时拉取 Kubernetes 所需镜像的地址,kube-proxy 的模式为 ipvs,另外需要注意的是我们这里是准备安装 flannel 网络插件的,需要将 networking.podSubnet 设置为10.244.0.0/16:
➜ ~ kubeadm config print init-defaults --component-configs KubeletConfiguration > kubeadm.yaml
对于上面的资源清单的文档比较杂,要想完整了解上面的资源对象对应的属性,可以查看对应的 godoc 文档,地址: https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3。 在开始初始化集群之前可以使用kubeadm config images pull —config kubeadm.yaml预先在各个服务器节点上拉取所k8s需要的容器镜像。 配置文件准备好过后,可以使用如下命令先将相关镜像 pull 下面:
# kubeadm.yaml
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.31.30 # 指定master节点内网IP
bindPort: 6443
nodeRegistration:
criSocket: /run/containerd/containerd.sock # 使用 containerd的Unix socket 地址
imagePullPolicy: IfNotPresent
name: master
taints: # 给master添加污点,master节点不能调度应用
- effect: "NoSchedule"
key: "node-role.kubernetes.io/master"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs # kube-proxy 模式
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/k8sxio
kind: ClusterConfiguration
kubernetesVersion: 1.22.1
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16 # 指定 pod 子网
scheduler: {}
---
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
cgroupDriver: systemd # 配置 cgroup driver
logging: {}
memorySwap: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
上面在拉取 coredns 镜像的时候出错了,没有找到这个镜像,我们可以手动 pull 该镜像,然后重新 tag 下镜像地址即可:
➜ ~ kubeadm config images pull --config kubeadm.yaml
[config/images] Pulled registry.aliyuncs.com/k8sxio/kube-apiserver:v1.22.1
[config/images] Pulled registry.aliyuncs.com/k8sxio/kube-controller-manager:v1.22.1
[config/images] Pulled registry.aliyuncs.com/k8sxio/kube-scheduler:v1.22.1
[config/images] Pulled registry.aliyuncs.com/k8sxio/kube-proxy:v1.22.1
[config/images] Pulled registry.aliyuncs.com/k8sxio/pause:3.5
[config/images] Pulled registry.aliyuncs.com/k8sxio/etcd:3.5.0-0
failed to pull image "registry.aliyuncs.com/k8sxio/coredns:v1.8.4": output: time="2021-08-31T15:09:13+08:00" level=fatal msg="pulling image: rpc error: code = NotFound desc = failed to pull and unpack image \"registry.aliyuncs.com/k8sxio/coredns:v1.8.4\": failed to resolve reference \"registry.aliyuncs.com/k8sxio/coredns:v1.8.4\": registry.aliyuncs.com/k8sxio/coredns:v1.8.4: not found"
, error: exit status 1
To see the stack trace of this error execute with --v=5 or higher
然后就可以使用上面的配置文件在 master 节点上进行初始化:
➜ ~ ctr -n k8s.io i pull docker.io/coredns/coredns:1.8.4
docker.io/coredns/coredns:1.8.4: resolved |++++++++++++++++++++++++++++++++++++++|
index-sha256:6e5a02c21641597998b4be7cb5eb1e7b02c0d8d23cce4dd09f4682d463798890: done |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:10683d82b024a58cc248c468c2632f9d1b260500f7cd9bb8e73f751048d7d6d4: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:bc38a22c706b427217bcbd1a7ac7c8873e75efdd0e59d6b9f069b4b243db4b4b: done |++++++++++++++++++++++++++++++++++++++|
config-sha256:8d147537fb7d1ac8895da4d55a5e53621949981e2e6460976dae812f83d84a44: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:c6568d217a0023041ef9f729e8836b19f863bcdb612bb3a329ebc165539f5a80: exists |++++++++++++++++++++++++++++++++++++++|
elapsed: 12.4s total: 12.0 M (991.3 KiB/s)
unpacking linux/amd64 sha256:6e5a02c21641597998b4be7cb5eb1e7b02c0d8d23cce4dd09f4682d463798890...
done: 410.185888ms
➜ ~ ctr -n k8s.io i tag docker.io/coredns/coredns:1.8.4 registry.aliyuncs.com/k8sxio/coredns:v1.8.4
根据安装提示拷贝 kubeconfig 文件:
➜ ~ kubeadm init --config kubeadm.yaml
[init] Using Kubernetes version: v1.22.1
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local master] and IPs [10.96.0.1 192.168.31.30]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost master] and IPs [192.168.31.30 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost master] and IPs [192.168.31.30 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 12.501933 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.22" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node master as control-plane by adding the labels: [node-role.kubernetes.io/master(deprecated) node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: abcdef.0123456789abcdef
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.31.30:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:8c1f43da860b0e7bd9f290fe057f08cf7650b89e650ff316ce4a9cad3834475c
然后可以使用 kubectl 命令查看 master 节点已经初始化成功了:
➜ ~ mkdir -p $HOME/.kube
➜ ~ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
➜ ~ sudo chown $(id -u):$(id -g) $HOME/.kube/config
➜ ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane,master 2m10s v1.22.1
1.3.2 添加节点
记住初始化集群上面的配置和操作要提前做好,将 master 节点上面的 $HOME/.kube/config 文件拷贝到 node 节点对应的文件中,安装 kubeadm、kubelet、kubectl(可选),然后执行上面初始化完成后提示的 join 命令即可:
➜ ~ kubeadm join 192.168.31.30:6443 --token abcdef.0123456789abcdef \
> --discovery-token-ca-cert-hash sha256:8c1f43da860b0e7bd9f290fe057f08cf7650b89e650ff316ce4a9cad3834475c
[preflight] Running pre-flight checks
[preflight] WARNING: Couldn't create the interface used for talking to the container runtime: docker is required for container runtime: exec: "docker": executable file not found in $PATH
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
“
如果忘记了上面的 join 命令可以使用命令 kubeadm token create —print-join-command 重新获取。”
执行成功后运行 get nodes 命令:可以看到是 NotReady 状态,这是因为还没有安装网络插件,接下来安装网络插件,可以在文档 https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/ 中选择我们自己的网络插件,这里我们安装 flannel:
➜ ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane,master 47m v1.22.1
node2 NotReady <none> 46s v1.22.1
隔一会儿查看 Pod 运行状态:
➜ ~ wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 如果有节点是多网卡,则需要在资源清单文件中指定内网网卡
# 搜索到名为 kube-flannel-ds 的 DaemonSet,在kube-flannel容器下面
➜ ~ vi kube-flannel.yml
......
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.14.0
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
- --iface=eth0 # 如果是多网卡的话,指定内网网卡的名称
......
➜ ~ kubectl apply -f kube-flannel.yml # 安装 flannel 网络插件
当我们部署完网络插件后执行 ifconfig 命令,正常会看到新增的 cni0 与 flannel1 这两个虚拟设备,但是如果没有看到 cni0 这个设备也不用太担心,我们可以观察 /var/lib/cni 目录是否存在,如果不存在并不是说部署有问题,而是该节点上暂时还没有应用运行,我们只需要在该节点上运行一个 Pod 就可以看到该目录会被创建,并且 cni0 设备也会被创建出来。 网络插件运行成功了,node 状态也正常了:
➜ ~ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7568f67dbd-5mg59 1/1 Running 0 8m32s
coredns-7568f67dbd-b685t 1/1 Running 0 8m31s
etcd-master 1/1 Running 0 66m
kube-apiserver-master 1/1 Running 0 66m
kube-controller-manager-master 1/1 Running 0 66m
kube-flannel-ds-dsbt6 1/1 Running 0 11m
kube-flannel-ds-zwlm6 1/1 Running 0 11m
kube-proxy-jq84n 1/1 Running 0 66m
kube-proxy-x4hbv 1/1 Running 0 19m
kube-scheduler-master 1/1 Running 0 66m
用同样的方法添加另外一个节点即可。
➜ ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane,master 111m v1.22.1
node2 Ready <none> 64m v1.22.1
1.4 Kubernetes Dashboard
v1.22.1 版本的集群需要安装最新的 2.0+ 版本的 Dashboard:直接创建:
# 推荐使用下面这种方式
➜ ~ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
➜ ~ vi recommended.yaml
# 修改Service为NodePort类型
......
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
type: NodePort # 加上type=NodePort变成NodePort类型的服务
......
新版本的 Dashboard 会被默认安装在 kubernetes-dashboard 这个命名空间下面:
➜ ~ kubectl apply -f recommended.yaml
我们仔细看可以发现上面的 Pod 分配的 IP 段是 10.88.xx.xx,包括前面自动安装的 CoreDNS 也是如此,我们前面不是配置的 podSubnet 为 10.244.0.0/16 吗?我们先去查看下 CNI 的配置文件:
➜ ~ kubectl get pods -n kubernetes-dashboard -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dashboard-metrics-scraper-856586f554-pllvt 1/1 Running 0 24m 10.88.0.7 master <none> <none>
kubernetes-dashboard-76597d7df5-82998 1/1 Running 0 21m 10.88.0.2 node2 <none> <none>
可以看到里面包含两个配置,一个是 10-containerd-net.conflist,另外一个是我们上面创建的 Flannel 网络插件生成的配置,我们的需求肯定是想使用 Flannel 的这个配置,我们可以查看下 containerd 这个自带的 cni 插件配置:
➜ ~ ls -la /etc/cni/net.d/
total 8
drwxr-xr-x 2 1001 docker 67 Aug 31 16:45 .
drwxr-xr-x. 3 1001 docker 19 Jul 30 01:13 ..
-rw-r--r-- 1 1001 docker 604 Jul 30 01:13 10-containerd-net.conflist
-rw-r--r-- 1 root root 292 Aug 31 16:45 10-flannel.conflist
可以看到上面的 IP 段恰好就是 10.88.0.0/16,但是这个 cni 插件类型是 bridge 网络,网桥的名称为 cni0:
➜ ~ cat /etc/cni/net.d/10-containerd-net.conflist
{
"cniVersion": "0.4.0",
"name": "containerd-net",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"promiscMode": true,
"ipam": {
"type": "host-local",
"ranges": [
[{
"subnet": "10.88.0.0/16"
}],
[{
"subnet": "2001:4860:4860::/64"
}]
],
"routes": [
{ "dst": "0.0.0.0/0" },
{ "dst": "::/0" }
]
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true}
}
]
}
但是使用 bridge 网络的容器无法跨多个宿主机进行通信,跨主机通信需要借助其他的 cni 插件,比如上面我们安装的 Flannel,或者 Calico 等等,由于我们这里有两个 cni 配置,所以我们需要将 10-containerd-net.conflist 这个配置删除,因为如果这个目录中有多个 cni 配置文件,kubelet 将会使用按文件名的字典顺序排列的第一个作为配置文件,所以前面默认选择使用的是 containerd-net 这个插件。
➜ ~ ip a
...
6: cni0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 9a:e7:eb:40:e8:66 brd ff:ff:ff:ff:ff:ff
inet 10.88.0.1/16 brd 10.88.255.255 scope global cni0
valid_lft forever preferred_lft forever
inet6 2001:4860:4860::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::98e7:ebff:fe40:e866/64 scope link
valid_lft forever preferred_lft forever
...
然后记得重建 coredns 和 dashboard 的 Pod,重建后 Pod 的 IP 地址就正常了:
➜ ~ mv /etc/cni/net.d/10-containerd-net.conflist /etc/cni/net.d/10-containerd-net.conflist.bak
➜ ~ ifconfig cni0 down && ip link delete cni0
➜ ~ systemctl daemon-reload
➜ ~ systemctl restart containerd kubelet
查看 Dashboard 的 NodePort 端口:
➜ ~ kubectl get pods -n kubernetes-dashboard -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dashboard-metrics-scraper-856586f554-tp8m5 1/1 Running 0 42s 10.244.1.6 node2 <none> <none>
kubernetes-dashboard-76597d7df5-9rmbx 1/1 Running 0 66s 10.244.1.5 node2 <none> <none>
➜ ~ kubectl get pods -n kube-system -o wide -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-7568f67dbd-n7bfx 1/1 Running 0 5m40s 10.244.1.2 node2 <none> <none>
coredns-7568f67dbd-plrv8 1/1 Running 0 3m47s 10.244.1.4 node2 <none> <none>
然后可以通过上面的 31050 端口去访问 Dashboard,要记住使用 https,Chrome 不生效可以使用Firefox 测试,如果没有 Firefox 下面打不开页面,可以点击下页面中的信任证书即可:
➜ ~ kubectl get svc -n kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.99.37.172 <none> 8000/TCP 25m
kubernetes-dashboard NodePort 10.103.102.27 <none> 443:31050/TCP 25m
直接创建:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admin
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: admin
namespace: kubernetes-dashboard
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: kubernetes-dashboard
然后用上面的 base64 解码后的字符串作为 token 登录 Dashboard 即可,新版本还新增了一个暗黑模式:
➜ ~ kubectl apply -f admin.yaml
➜ ~ kubectl get secret -n kubernetes-dashboard|grep admin-token
admin-token-lwmmx kubernetes.io/service-account-token 3 1d
➜ ~ kubectl get secret admin-token-lwmmx -o jsonpath={.data.token} -n kubernetes-dashboard |base64 -d
# 会生成一串很长的base64后的字符串
➜ ~ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master Ready control-plane,master 36m v1.22.1 192.168.31.30 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 containerd://1.5.5
node2 Ready <none> 27m v1.22.1 192.168.31.215 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 containerd://1.5.5
1.5 清理
如果你的集群安装过程中遇到了其他问题,我们可以使用下面的命令来进行重置:
➜ ~ kubeadm reset
➜ ~ ifconfig cni0 down && ip link delete cni0
➜ ~ ifconfig flannel.1 down && ip link delete flannel.1
➜ ~ rm -rf /var/lib/cni/
2 如何丝滑般将 Kubernetes 容器运行时从 Docker 切换成 Containerd
前面我们了解了 containerd 的发展历史和基本使用方式,本节我们就来尝试下使用 containerd 来作为 Kubernetes 集群的容器运行时。 前面我们安装的集群默认使用的是 Docker 作为容器运行时,那么应该如何将容器运行时从 Docker 切换到 containerd 呢?2.1 维护节点
首先标记需要切换的节点为维护模式,强制驱逐节点上正在运行的 Pod,这样可以最大程度降低切换过程中影响应用的正常运行,比如我们先将 node1 节点切换到 containerd。 首先使用 kubectl cordon 命令将 node1 节点标记为 unschedulable 不可调度状态:执行完上面的命令后,node1 节点变成了一个 SchedulingDisabled 状态,表示不可调度,这样新创建的 Pod 就不会调度到当前节点上来了。 接下来维护 node1 节点,使用 kubectl drain 命令来维护节点并驱逐节点上的 Pod:
# 将 node1 标记为 unschedulable
➜ ~ kubectl cordon node1
node/node1 cordoned
➜ ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 85d v1.19.11
node1 Ready,SchedulingDisabled <none> 85d v1.19.11
node2 Ready <none> 85d v1.19.11
上面的命令会强制将 node1 节点上的 Pod 进行驱逐,我们加了一个 —ignore-daemonsets 的参数可以用来忽略 DaemonSet 控制器管理的 Pods,因为这些 Pods 不用驱逐到其他节点去,当节点驱逐完成后接下来我们就可以来对节点进行维护操作了,除了切换容器运行时可以这样操作,比如我们需要变更节点配置、升级内核等操作的时候都可以先将节点进行驱逐,然后再进行维护。
# 维护 node1 节点,驱逐 Pod
➜ ~ kubectl drain node1 --ignore-daemonsets
node/node1 already cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/kube-flannel-ds-mzdgl, kube-system/kube-proxy-vddh9, lens-metrics/node-exporter-2g4hr
evicting pod "kiali-85c8cdd5b5-27cwv"
evicting pod "jenkins-587b78f5cd-9gvn8"
evicting pod "argocd-application-controller-0"
pod/argocd-application-controller-0 evicted
pod/kiali-85c8cdd5b5-27cwv evicted
pod/jenkins-587b78f5cd-9gvn8 evicted
node/node1 evicted
2.2 切换 containerd
接下来停掉 docker、containerd 和 kubelet:因为我们安装的 Docker 默认安装使用了 containerd 作为后端的容器运行时,所以不需要单独安装 containerd 了,当然你也可以将 Docker 和 containerd 完全卸载掉,然后重新安装,这里我们选择直接使用之前安装的 containerd。 因为 containerd 中默认已经实现了 CRI,但是是以 plugin 的形式配置的,以前 Docker 中自带的 containerd 默认是将 CRI 这个插件禁用掉了的(使用配置 disabled_plugins = [“cri”]),所以这里我们重新生成默认的配置文件来覆盖掉:
➜ ~ systemctl stop kubelet
➜ ~ systemctl stop docker
➜ ~ systemctl stop containerd
前面我们已经介绍过上面的配置文件了,首先我们修改默认的 pause 镜像为国内的地址,替换 [plugins.”io.containerd.grpc.v1.cri”] 下面的 sandbox_image:
➜ ~ containerd config default > /etc/containerd/config.toml
同样再配置下镜像仓库的加速器地址:
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.aliyuncs.com/k8sxio/pause:3.2"
......
接下来修改 kubelet 配置,将容器运行时配置为 containerd,打开 /etc/sysconfig/kubelet 文件,在该文件中可以添加一些额外的 kubelet 启动参数,配置如下所示:
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://bqr1dr1n.mirror.aliyuncs.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://registry.aliyuncs.com/k8sxio"]
上面的配置中我们增加了两个参数,—container-runtime 参数是用来指定使用的容器运行时的,可选值为 docker 或者 remote,默认是 docker,由于我们这里使用的是 containerd 这种容器运行时,所以配置为 remote 值(也就是除 docker 之外的容器运行时都应该指定为 remote),然后第二个参数 —container-runtime-endpoint 是用来指定远程的运行时服务的 endpiont 地址的,在 Linux 系统中一般都是使用 unix 套接字的形式,比如这里我们就是指定连接 containerd 的套接字地址 unix:///run/containerd/containerd.sock。 其实还应该配置一个 —image-service-endpoint 参数用来指定远程 CRI 的镜像服务地址,如果没有指定则默认使用 —container-runtime-endpoint 的值了,因为 CRI 都会实现容器和镜像服务的。 配置完成后重启 containerd 和 kubelet 即可:
KUBELET_EXTRA_ARGS="--container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock"
重启完成后查看节点状态是否正常:
➜ ~ systemctl daemon-reload
➜ ~ systemctl restart containerd
➜ ~ systemctl restart kubelet
获取节点的时候加上 -o wide 可以查看节点的更多信息,从上面对比可以看到 node1 节点的容器运行时已经切换到 containerd://1.4.4 了。 最后把 node1 节点重新加回到集群中来允许调度 Pod 资源:
➜ ~ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master Ready master 85d v1.19.11 192.168.31.30 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 docker://19.3.9
node1 Ready,SchedulingDisabled <none> 85d v1.19.11 192.168.31.95 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 containerd://1.4.4
node2 Ready <none> 85d v1.19.11 192.168.31.215 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 docker://19.3.9
用同样的方法再去处理其他节点即可将整个集群切换成容器运行时 containerd 了。
➜ ~ kubectl uncordon node1
node/node1 uncordoned
➜ ~ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 85d v1.19.11
node1 Ready <none> 85d v1.19.11
node2 Ready <none> 85d v1.19.11
2.3 crictl
现在我们可以 node1 节点上使用 ctr 命令来管理 containerd,查看多了一个名为 k8s.io 的命名空间:上文我们已经介绍 kubernetes 集群对接的 containerd 所有资源都在 k8s.io 的命名空间下面,而 docker 的则默认在 moby 下面,当然现在 moby 下面没有任何的数据了,但是在 k8s.io 命名空间下面就有很多镜像和容器资源了:
➜ ~ ctr ns ls
NAME LABELS
k8s.io
moby
我们当然可以直接使用 ctr 命令来直接管理镜像或容器资源,但是我们在使用过程中明显可以感觉到该工具没有 docker CLI 方便,从使用便捷性和功能性上考虑,我们更推荐使用 crictl 作为管理工具,crictl 为 CRI 兼容的容器运行时提供 CLI,这允许 CRI 运行时开发人员在无需设置 Kubernetes 组件的情况下调试他们的运行时。 接下来我们就先简单介绍下如何使用 crictl 工具来提升管理容器运行时的效率。
➜ ~ ctr -n moby c ls
CONTAINER IMAGE RUNTIME
➜ ~ ctr -n moby i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
➜ ~ ctr -n moby t ls
TASK PID STATUS
ctr -n k8s.io i ls -q
docker.io/library/busybox:latest
docker.io/library/busybox@sha256:0f354ec1728d9ff32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60
quay.io/coreos/flannel:v0.14.0
quay.io/coreos/flannel@sha256:4a330b2f2e74046e493b2edc30d61fdebbdddaaedcb32d62736f25be8d3c64d5
registry.aliyuncs.com/k8sxio/pause:3.2
......
2.3.1 安装
首先我们需要先安装 crictl 工具,直接从 cri-tools 的 release 页面下载对应的二进制包,解压放入 PATH 路径下即可:到这里证明 crictl 工具安装成功了。
➜ ~ VERSION="v1.22.0"
➜ ~ wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
# 如果有限制,也可以替换成下面的 URL 加速下载
# wget https://download.fastgit.org/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
➜ ~ tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
➜ ~ rm -f crictl-$VERSION-linux-amd64.tar.gz
➜ ~ crictl -v
crictl version v1.22.0
2.3.2 用法
crictl 安装完成后,接下来我们来了解下该工具的一些常见使用方法。 首先需要修改下默认的配置文件,默认为 /etc/crictl.yaml,在文件中指定容器运行时和镜像的 endpoint 地址,内容如下所示:配置完成后就可以使用 crictl 命令了。
runtime-endpoint: unix:///var/run/containerd/containerd.sock
image-endpoint: unix:///var/run/containerd/containerd.sock
debug: false
pull-image-on-create: false
disable-pull-on-run: false
获取 Pod 列表
通过 crictl pods 命令可以获取当前节点上运行的 Pods 列表,如下所示:还可以使用 —name 参数获取指定的 Pod:
➜ ~ crictl pods
POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
cb18081b33933 39 minutes ago Ready kube-flannel-ds-mzdgl kube-system 1 (default)
95d6004c55902 40 minutes ago Ready node-exporter-2g4hr lens-metrics 1 (default)
cfae80b3209db 40 minutes ago Ready kube-proxy-vddh9 kube-system 1 (default)
99ac2583da87f 40 minutes ago Ready jenkins-587b78f5cd-dfzns kube-ops 0 (default)
07ebdc51f1def 45 minutes ago NotReady node-exporter-2g4hr lens-metrics 0 (default)
bec027b98f194 45 minutes ago NotReady kube-proxy-vddh9 kube-system 0 (default)
b44b5ec385053 45 minutes ago NotReady kube-flannel-ds-mzdgl kube-system 0 (default)
同样也可以根据标签来筛选 Pod 列表:
➜ ~ crictl pods --name kube-flannel-ds-mzdgl
POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
cb18081b33933 About an hour ago Ready kube-flannel-ds-mzdgl kube-system 1 (default)
➜ ~ crictl pods --label app=flannel
POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
cb18081b33933 About an hour ago Ready kube-flannel-ds-mzdgl kube-system 1 (default)
获取镜像列表
使用 crictl images 命令可以获取所有的镜像:同样在命令后面可以加上 -v 参数来显示镜像的详细信息:
➜ ~ crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/jenkins/jenkins lts 3b4ec91827f28 303MB
docker.io/library/busybox latest 69593048aa3ac 771kB
quay.io/coreos/flannel v0.14.0 8522d622299ca 21.1MB
quay.io/prometheus/node-exporter v1.0.1 0e0218889c33b 13MB
registry.aliyuncs.com/k8sxio/kube-proxy v1.19.11 732e0635ac9e0 49.3MB
registry.aliyuncs.com/k8sxio/pause 3.2 80d28bedfe5de 300kB
➜ ~ crictl images -v
ID: sha256:3b4ec91827f28ed482b08f6e379c56ea2308967d10aa4f458442c922e0771f87
RepoTags: docker.io/jenkins/jenkins:lts
RepoDigests: docker.io/jenkins/jenkins@sha256:abcd55c9f19c85808124a4d82e3412719cd5c511c03ebd7d4210e9fa9e8f1029
Size: 302984002
Username: jenkins
ID: sha256:69593048aa3acfee0f75f20b77acb549de2472063053f6730c4091b53f2dfb02
RepoTags: docker.io/library/busybox:latest
RepoDigests: docker.io/library/busybox@sha256:0f354ec1728d9ff32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60
Size: 770886
......
获取容器列表
使用 crictl ps 命令可以获取正在运行的容器列表:还有更多其他可选参数,可以通过 crictl ps -h 获取,比如显示最近创建的两个容器:
➜ ~ crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
c8474738e4587 3b4ec91827f28 About an hour ago Running jenkins 0 99ac2583da87f
0f9c826f87ef8 8522d622299ca About an hour ago Running kube-flannel 1 cb18081b33933
da444f718d37b 0e0218889c33b About an hour ago Running node-exporter 1 95d6004c55902
a484a8a69ea59 732e0635ac9e0 About an hour ago Running kube-proxy 1 cfae80b3209db
使用 -s 选项按照状态进行过滤:
➜ ~ crictl ps -n 2
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
c8474738e4587 3b4ec91827f28 About an hour ago Running jenkins 0 99ac2583da87f
0f9c826f87ef8 8522d622299ca About an hour ago Running kube-flannel 1 cb18081b33933
➜ ~ crictl ps -s Running
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
c8474738e4587 3b4ec91827f28 About an hour ago Running jenkins 0 99ac2583da87f
0f9c826f87ef8 8522d622299ca About an hour ago Running kube-flannel 1 cb18081b33933
da444f718d37b 0e0218889c33b About an hour ago Running node-exporter 1 95d6004c55902
a484a8a69ea59 732e0635ac9e0 About an hour ago Running kube-proxy 1 cfae80b3209db
在容器中执行命令
crictl 也有类似 exec 的命令支持,比如在容器 ID 为 c8474738e4587 的容器中执行一个 date 命令:
➜ ~ crictl exec -it c8474738e4587 date
Tue 17 Aug 2021 08:23:02 AM UTC
输出容器日志
还可以获取容器日志信息:和 kubectl logs 类似于,还可以使用 -f 选项来 Follow 日志输出,—tail N 也可以指定输出最近的 N 行日志。
➜ ~ crictl logs c8474738e4587
......
2021-08-17 07:19:51.846+0000 [id=155] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$0: Started Periodic background build discarder
2021-08-17 07:19:51.854+0000 [id=155] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$0: Finished Periodic background build discarder. 6 ms
2021-08-17 08:19:51.846+0000 [id=404] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$0: Started Periodic background build discarder
2021-08-17 08:19:51.848+0000 [id=404] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$0: Finished Periodic background build discarder. 1 ms
资源统计
使用 crictl stats 命令可以列举容器资源的使用情况:此外镜像和容器相关的一些操作也都支持,比如:
➜ ~ crictl stats
CONTAINER CPU % MEM DISK INODES
0f9c826f87ef8 0.00 21.2MB 0B 17
a484a8a69ea59 0.00 23.55MB 12.29kB 25
c8474738e4587 0.08 413.2MB 3.338MB 12
da444f718d37b 0.00 14.46MB 0B 16
- 拉取镜像:crictl pull
- 运行 Pod:crictl runp
- 运行容器:crictl run
- 启动容器:crictl start
- 删除容器:crictl rm
- 删除镜像:crictl rmi
- 删除 Pod:crictl rmp
- 停止容器:crictl stop
- 停止 Pod:crictl stopp
- ……
2.4 CLI 对比
前面我们了解了围绕镜像、容器和 Pod 可以使用 docker、ctr、crictl 这些命令行工具进行管理,接下来我们就来比较下这几个常用命令的使用区别。命令 | Docker | Containerd | |
---|---|---|---|
docker | crictl(推荐) | ctr | |
查看容器列表 | docker ps | crictl ps | ctr -n k8s.io c ls |
查看容器详情 | docker inspect | crictl inspect | ctr -n k8s.io c info |
查看容器日志 | docker logs | crictl logs | 无 |
容器内执行命令 | docker exec | crictl exec | 无 |
挂载容器 | docker attach | crictl attach | 无 |
显示容器资源使用情况 | docker stats | crictl stats | 无 |
创建容器 | docker create | crictl create | ctr -n k8s.io c create |
启动容器 | docker start | crictl start | ctr -n k8s.io run |
停止容器 | docker stop | crictl stop | 无 |
删除容器 | docker rm | crictl rm | ctr -n k8s.io c del |
查看镜像列表 | docker images | crictl images | ctr -n k8s.io i ls |
查看镜像详情 | docker inspect | crictl inspecti | 无 |
拉取镜像 | docker pull | crictl pull | ctr -n k8s.io i pull |
推送镜像 | docker push | 无 | ctr -n k8s.io i push |
删除镜像 | docker rmi | crictl rmi | ctr -n k8s.io i rm |
查看Pod列表 | 无 | crictl pods | 无 |
查看Pod详情 | 无 | crictl inspectp | 无 |
启动Pod | 无 | crictl runp | 无 |
停止Pod | 无 | crictl stopp | 无 |
2.5 日志配置
docker 和 containerd 除了在常用命令上有些区别外,在容器日志及相关参数配置方面也存在一些差异。 当使用 Docker 作为 Kubernetes 容器运行时的时候,容器日志的落盘是由 Docker 来完成的,日志被保存在类似 /var/lib/docker/containers/而当使用 containerd 作为 Kubernetes 容器运行时的时候,容器日志的落盘则由 kubelet 来完成了,被直接保存在 /var/log/pods/
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file: "10"
}
}
所以如果我们有进行日志收集理论上来说两种方案都是兼容的,基本上不用改动。 当然除了这些差异之外,可能对于我们来说镜像构建这个环节是我们最需要关注的了。切换到 containerd 之后,需要注意 docker.sock 不再可用,也就意味着不能再在容器里面执行 docker 命令来构建镜像了。所以接下来需要和大家介绍几种不需要使用 docker.sock 也可以构建镜像的方法。
--container-log-max-files=10 --container-log-max-size="100Mi"