kubernetes 安装
虽然官方文档中已经有了很详细的安装说明。但是为了快速安装,并强调一些安装过程中的注意事项,仍然需要一篇简单易操作的 kubernetes 安装文档。
而本文的目的就是通过一篇完整的流程来安装 kubernetes ,并在必要的地方做出提示和指引到相关引用链接。
环境准备
本次安装环境为 Deepin (基于 debian) 操作系统安装。操作步骤适用于 Debian 和 Ubuntu 系列。如果是在 RHEL 系统中操作,除了步骤和特定操作系统的文件目录不同,其他基本一致。
安装时用了最新版本的 kubernetes 环境。使用了 containerd 作为容器运行层。
在安装过程中有些内容是必须使用科学上网才能进行的,所以在需要地方会配置代理。
禁用 SWAP
1 | swapoff -a |
设置主机名
1 | # 使用自定义的主机名设置。 |
增加解析。如果有 dns 可以配置 DNS 解析,如果么有,需要配置 hosts 文件解析
增加如下内容到 /etc/hosts
文件中:
1 | 192.168.2.178 xxx |
创建一个 kubernetes 安装准备目录,用于存放安装过程中需要的内容。
1 | mkdir ~/k8s/ |
安装
安装运行时
kubernetes 是运行在容器运行时(Container Runtime)环境之上的,所以在安装 kubernetes 时,需要先准备容器运行时。当前主流的容器运行时有:
- Docker:在 1.20 弃用,更多细节请参考: 《别慌: Kubernetes 和 Docker》
- containerd
- CRI-O
更详细内容请参考: 容器运行时
安装 containerd
根据当前社区环境,综合考虑后选择 containerd 作为容器运行时。如果需要使用 Docker 作为底层运行时,请查看文档 Docker runtimes 。
在安装 containerd 之前,首先根据 Containerd runtimes设置系统环境:
1 | cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf |
具体安装步骤请参考: Getting started with containerd
安装步骤
在 [https://github.com/containerd/containerd/releases] 找到最新的稳定版,下载 cri-containerd-cni
,然后直接解压到根目录。
这个过程中会安装 containerd 、相关服务 、 runc 、 cni 。
1 | export https_proxy=http:127.0.0.1:1081 |
解压输入如下:
1 | etc/ |
记录一下 containerd 自动生成的 cni 配置 /etc/cni/net.d/10-containerd-net.conflist
。以备不时之需。
1 | { |
配置 containerd 使用代理
安装完成后,为了让 kubernetes 能从 google 拉去 kubernetes 镜像,需要配置 containerd 服务使用代理。
如果直接使用 export https_proxy
的方式设置代理, containerd 并不会使用,具体原因未知,
但猜测可能是读取环境变量的 key 值不一样。所以在此针对该服务直接配置。
修改 /etc/systemd/system/containerd.service
文件如下:
1 | # Copyright The containerd Authors. |
重载服务配置后,重启 containerd ,并检查服务状态:
1 | systemctl daemon-reload |
配置 runc 使用 cgroup
在 kubernetes 文档中提到了配置内容 使用 systemd cgroup 驱动程序
结合 runc 使用 systemd cgroup 驱动,修改 /etc/containerd/config.toml
的 SystemdCgroup
为 true
。
注意:containerd 使用的是默认配置,而且
/etc/containerd/config.toml
是没有创建的。根据 Customizing containerd 中的内容,可以使用containerd config default > /etc/containerd/config.toml
生成默认 containerd 默认配置
1 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] |
然后重启 containerd ,并查看服务状态:
1 | systemctl restart containerd |
镜像加速
在国内使用 docker.io 仓库会时不时抽风,可以通过调整 containerd 配置文件使用国内公共容器加速镜像或者个人的阿里云容器加速镜像。
具体配置说明请参考 Registry Configuration 。
增加阿里云个人容器镜像加速:
修改 /etc/containerd/config.toml
的配置,调整 config_path = "/etc/containerd/certs.d"
1 | [plugins."io.containerd.grpc.v1.cri".registry] |
然后创建目录 /etc/containerd/certs.d
。
创建一个镜像仓库域名的目录。现在需要添加阿里云的镜像仓库 https://xxxxx.mirror.aliyuncs.com
,则需要创建一个 aliyuncs.com
的目录,并在该目录中
创建一个 hosts.toml
的文件,将一下内容加入到该文件中
1 | server = "https://xxxxx.mirror.aliyuncs.com" |
所以具体操作如下:
1 | mkdir /etc/containerd/certs.d/aliyuncs.com/ |
操作结果如下:
1 | root@kevin:~# tree /etc/containerd/certs.d |
注意:此处配置的加速镜像会通过上面配置的代理进行访问。两边都配置的目的有两个:
所以最佳的做法是:加速和代理都配置。然后在代理服务器上将加速地址配置到白名单中。
这样镜像加速时会在代理的白名单中直接访问,除此之外的访问通过代理出去。
安装 cni 插件
为了确保能使用最新稳定版,避免不必要的 BUG ,手动下载安装 cni 插件。
在 [https://github.com/containernetworking/plugins/releases] 中下载 cni-plugins-linux-amd64
的插件,然后将其解压:
1 | export https_proxy=http:127.0.0.1:1081 |
解压操作后的结果:
1 | ./ |
由于在 cni 1.0 时已经将 flannel 独立维护了。所以后面用到的网络工具 flannel 也要升级到最新稳定版。
在 [https://github.com/flannel-io/cni-plugin] 下载 flannel-amd64
,然后移动到 cni 中:
1 | export https_proxy=http:127.0.0.1:1081 |
安装 crictl
将 kubernetes 容器运行时工具 CLI 工具升级到最新版本。
在 [https://github.com/kubernetes-sigs/cri-tools/releases] 中下载最新稳定版,然后解压复制到 usr/local/bin/crictl
:
注意:使用 wget 下载需要代理
1 | # 设置系统全局代理 |
检查 containerd 是否正常
重启 containerd 然后检查 containerd 服务是否正常:
1 | systemctl restart containerd |
输出如下:
1 | root@kevin:~# systemctl status containerd |
使用 ctr 命令,检查 containerd 插件是否正常:
1 | ctr plugin ls |
输出如下:
1 | root@kevin:~# ctr plugin ls |
使用 crictl 检查 cri 是否正常:
1 | crictl --version |
输入如下:
1 | root@kevin:~# crictl --version |
这这一步已经要注意的是 lastCNILoadStatus
要正常。如果 CNI 不正常,后面的 kubernetes 也会无法正常启动。
安装 kubeadm、kubelet 和 kubectl
根据 安装 kubeadm, kubelet and kubectl 的描述,可以有多种安装方法。但在这个过程中使用的是 google 的仓库安装。在国内环境,需要科学上网才可以。当使用系统工具(apt / dnf / yum)安装时可以使用阿里云镜像加速。
Debian/Ubuntu 的国内镜像配置入选:
1 | apt-get update && apt-get install -y apt-transport-https |
其他系统请参考: kubernetes 镜像
注意:这个过程中可能无法安装最新版本的 kubernetes 。所以安装完成后需要检查。如果需要最新版本,
可以通过文档 安装 kubeadm, kubelet and kubectl 的手动安装方式,
从 Github 中下载最新发布版本安装。但下载时请准备代理。
创建集群
注意:具体初始化操作在后面,这里是作为说明。如果你需要立即初始化集群,请跳过此节。
提示:安装过程中,遇到问题请跳转到后面的 问题记录 和重置集群。不要重装系统。
使用 kubeadm init
初始化集群主节点。初始化时,需要调整集群参数,有两种方式:
- 通过命令行传递自定义参数:不便于调整和记录
- 通过配置文件传递自定义参数:方便记录和调整
有关 kubeadm
参数的更多信息,请参见 kubeadm 参考指南。
初始化配置
kubernetes 配置手册文档:kubeadm Configuration (v1beta2) 。
文档中描述了 kubeadm 的配置内容。
1 | apiVersion: kubeadm.k8s.io/v1beta2 |
默认配置
如果你需要立即初始化集群,请跳过此节。
1 | kubeadm config print init-defaults |
命令输出如下:
1 | apiVersion: kubeadm.k8s.io/v1beta3 |
该配置为集群默认配置,里面很多内容并不符合实际环境。
解读 kubeadm Configuration (v1beta2)
如果你需要立即初始化集群,请跳过此节。
kubeadm Configuration (v1beta2) 是使用 kubeadm 初始化集群节点时,传递
配置文件的说明文档。无论是使用 init
初始化一个集群主节点,还是使用 join
将一个新的节点加入到现有集群中个,都可以使用 --config kubeadm-config.yaml
传递配置项,而不是使用冗长的命令行参数。具体相信内容,请阅读文档,这里仅做一些简单介绍。
配置支持如下类型:
1 | apiVersion: kubeadm.k8s.io/v1beta2 |
InitConfiguration
1 | apiVersion: kubeadm.k8s.io/v1beta3 |
InitConfiguration
用来做初始化运行时环境的。其中:
NodeRegistration
:将新节点注册到集群中的相关字段。可以定义节点名称,要使用的 CRI 套接字和任何仅用于该节点的设置。LocalAPIEndpoint
: 表示要部署在节点的 API 服务器实例的端点。
在 API 服务器和控制平面节点的注意事项请参考: Considerations about apiserver-advertise-address and ControlPlaneEndpoint
ClusterConfiguration
1 | apiServer: |
ClusterConfiguration
是用来做集群配置的。
这个配置主要注意如下配置内容:
Networking
:用来这只集群网络的。podSubnet
: 在 安装 Pod 网络附加组件
中提到了在执行kubeadm init
时使用--pod-network-cidr
参数修改网络插件的 CIDR 。
后面会使用 flannel 作为网络服务,所以这里需要修改为 flannel 默认的 CIDR 。
KubeletConfiguration
1 | apiVersion: kubelet.config.k8s.io/v1beta1 |
这个配置在 kubeadm Configuration (v1beta2) 中并没有单独列出来,而是简单的提及。
配置项的具体参数在: [https://godoc.org/k8s.io/kubelet/config/v1beta1#KubeletConfiguration] ,命令行参数在 kubelet 。
KubeletConfiguration 配置唯一需要注意的是 cgroupDriver
,这是指定 kubelet 使用哪种 cgroup driver
。
根据 Configuring the kubelet cgroup driver 中的说明,在 v1.22
版本,如果没有配置 cgroupDriver
则默认使用 systemd
。
KubeProxyConfiguration
1 | apiVersion: kubeproxy.config.k8s.io/v1alpha1 |
这个配置在 kubeadm Configuration (v1beta2) 中并没有单独列出来,而是简单的提及。
配置项的具体参数在: [https://godoc.org/k8s.io/kube-proxy/config/v1alpha1#KubeProxyConfiguration] ,命令行参数在 kube-proxy 。
对于这个配置需要注意的就是调整 mode
为 ipvs
。
mode
的默认值为 iptables
。可选的有 userspace
、 iptables
、 ipvs
、 kernelspace
。
一个完整的示例配置
这是一个完整参数的示例配置,包含执行 kubeadm init
时使用的多个配置项。
1 | apiVersion: kubeadm.k8s.io/v1beta2 |
自定义配置
这里是一个本次需要使用的配置项。
1 | mkdir ~/k8s |
开始安装
初始化集群
操作分为两部,先是初始化操作,完成后,然后配置用户读取集群配置。
1 | # 使用配置文件初始化 kubeadm |
命令输出:
1 | root@kevin:~/k8s# kubeadm init --config=kubeadm-config.yaml --upload-certs |
当出现上述输出内容,则说明集群已经初始化,但是集群并没完全初始化。因为还没有配置网络,所以集群并没有处于完全可用状态。
在输出的最后几行中,提到了如何使用集群。如果是一个普通用户,则需要为普通用户增加集群配置。具体操作如下:
1 | mkdir -p $HOME/.kube |
如果是 root 用户,则可用直接使用环境变量。当然也可以使用上面的操作,为 root 用户增加自己的配置。
1 | export KUBECONFIG=/etc/kubernetes/admin.conf |
**注意:**不要让普通用户使用 /etc/kubernetes/admin.conf
配置。
当集群正常运行后,可以在其他节点通过 kubeadm join
加入当前节点:
1 |
|
查看节点信息
使用 kubectl get nodes
获取节点信息
1 | root@kevin:~/k8s# kubectl get nodes |
这里可以看到节点 kevin
的状态为 NotReady
。这说明集群还没完全启动。
查看节点描述
使用 kubectl describe nodes
获取节点描述信息。如果需要获取具体节点可以使用 kubectl describe nodes kevin
。
1 | root@kevin:~/k8s# kubectl describe nodes |
从状态信息可以看到集群处于无法调度状态。
获取所有 pod
使用 kubectl get pods --all-namespaces
获取所有名称空间的 pod 。
1 | root@kevin:~/k8s# kubectl get pods --all-namespaces |
可以看到现在启动的 pod 都在 kube-system
的名称空间中。从输出信息中可以看得到, coredns 的状态为 READY 。这是因为节点的污点标记为 NoSchedule ,
所以 coredns 不能被调度。
查看 coredns pod 的描述信息:
1 | root@kevin:~/k8s# kubectl -n kube-system describe pod coredns |
可以看到最后的输出中描述为 0/1 nodes are available: 1 node(s) had taint {kubeadmNode: master}, that the pod didn't tolerate.
。因为没有节点可用,仅有的
一个节点存在污点,所以调度失败。
安装 pod 网络组件
使用 flannel 初始化网络组件。
首先下载 flannel 配置 。由于这个地址访问需要
代理,所以建议先下载保存后再执行。
1 | export https_proxy=http://127.0.0.1:1081 |
执行输入结果如下:
1 | oot@kevin:~/k8s# kubectl apply -f ~/k8s/kube-flannel.yml |
检查网络插件 flannel 状态
列出所有 pod
1 | root@kevin:~/k8s# kubectl get pods --all-namespaces |
查看 flannel pod 描述
1 | root@kevin:~/k8s# kubectl -n kube-system describe pod kube-flannel-ds |
可以看到在最后出现了 Started container kube-flannel
,则说明 kube-flannel 网络插件正常启动。
查看 coredns 状态
安装网络插件后,检查 coredns 的状态
1 | root@kevin:~/k8s# kubectl get pods --all-namespaces |
可用发现 coredns 仍然没有被动调度,下面将当前节点的污点信息删除。
去除污点
污点和容忍度是用来设置集群调度策略的一种方式。设置了污点信息则节点不会在节点上运行,容忍度则
允许将 pod 调度到污点节点上。
污点和容忍度一起工作,以确保 pod 不会被调度到不适当的节点上。一个或多个污点被应用到一个节点;这标志着节点不应接受任何不容忍污点的 pod。
1 | root@kevin:~/k8s# kubectl describe nodes kevin |
正如前面在初始化集群的时候提到的,当前被标记为污点:
1 | Taints: kubeadmNode=master:NoSchedule |
所以现在需要将污点标记删除:
1 | kubectl taint nodes --all kubeadmNode=master:NoSchedule- |
输入如下:
1 | root@kevin:~/k8s# kubectl taint nodes --all node-role.kubernetes.io/master- |
再次查看 node 的描述,可以发现污点信息为 Taints: <none>
。
再次查看 pod :
1 | root@kevin:~/k8s# kubectl get pods --all-namespaces |
继续查看 coredns pod 的描述:
1 | root@kevin:~/k8s# kubectl -n kube-system describe pod coredns |
可用看到 coredns 的调度从 FailedScheduling
转换到了 Started
。
至此 kubernetes 集群单节点创建完成。
检查集群
手动检测
请参考 公开外部 IP 地址以访问集群中应用程序 内容一个可以使用外部 IP 访问集群内部服务的示例。
如果一切正常,则说明集群环境没问题。
使用 sonobuoy 检查
使用官方文档中提到的工具 sonobuoy 检测集群。
Sonobuoy 是一种诊断工具,通过以可访问且非破坏性的方式运行一组插件(包括Kubernetes一致性测试),可以更轻松地了解 Kubernetes 集群的状态。它是一种可定制、可扩展且与集群无关的方式,用于生成有关集群的清晰、信息丰富的报告。
它对 Kubernetes 资源对象和集群节点的选择性数据转储允许以下用例:
- 集成的端到端 (e2e)一致性测试
- 工作负载调试
- 通过可扩展插件自定义数据收集
下载最新的 sonobuoy 并将可执行文件放到 /usr/local/bin
中
1 | export https_proxy=http://127.0.0.1:1081 |
在运行之前,记得设置 kubernetes 的访问配置。 root 用户可以使用 export KUBECONFIG=/etc/kubernetes/admin.conf
设置。普通用户,请参考安装文档中的步骤,在用户家目录增加配置文件。
然后执行:
1 | sonobuoy run --wait |
**注意:**此过程耗时非常的长。暂时不知道强制结束会造成什么负面影响。检查是会运行 344
个任务。
使用集群
集群使用技巧可以参考 Kubernetes 教程中的内容。教程中包含:
配置
无状态应用程序
有状态应用程序
其他内容请阅读文档 Kubernetes 教程 。
重置集群
清理集群
1 | # 重置 kubeadm |
输出如下:
1 | root@kevin:~/k8s# kubeadm reset |
以上输出信息为之前搭建过程出错后重置时,做的记录。每个人的输出结果会不一样。
检查是否清理完成
检查 kubelet 服务状态是否已经停止:
1 | systemctl status kubelet |
输出如下:
1 | root@kevin:~/k8s# systemctl status kubelet |
由于 kubernetes 使用了 containerd 作为底层容器运行时,所以在正常清理完成后的 containerd 中是不会在有 kubernetes 的容器运行的。
使用 containerd 内置的工具 ctr
检查
1 | # 查看帮助命令 |
集群管理
问题记录
以下列出的问题,由于在本次安装时,没有再出现,所以无法具体排错过程。列出标题,带以后遇到了再补充。
常见问题
加速镜像
初始化集群-
无法拉去 kubernetes 镜像
这是由于 kubernetes 的镜像在 k8s.io
名称空间下,而不是 docker.io 的镜像,在访问是需要访问 google ,考虑
到国内环境,是无法访问的,所以要正确使用镜像,要么为 containerd 的服务配置代理,要么通过其他方式下载镜像到
本地后导入到 containerd 的镜像库中。
初始化时卡住
在初始化时,会等待 kubelet 启动,等待默认时间为 4 分钟,所以当等待时间较长,则说明启动时有错误。
1 | root@kevin:~/k8s# kubeadm init --config=kubeadm-config.yaml --upload-certs |
使用 journalctl -f -u kubelet
查看 kubelet
服务的日志,通过日志排查。
将 containerd ,和 runc 升级到最新版本,可以避免大部分安装过程中的问题。
cni plugin not initialized"
出现该问题时,请确保 containerd 是最新版本, kubernetes 是最新版本。
确保 containerd 服务正常,确保 ctl plugin ls
输出结果中没有错误, 确保 crictl info
输出正常。这三个是保证 kubernetes 能正确启动的前提。
在安装网络插件后去除污点,集群状态仍为 NotReady
此时查看 kubelet 服务,日志显示为 cni plugin not initialized
1 | root@kevin:~/k8s# systemctl status kubelet |
检查 kube-flannel 的日志为:
1 | root@kevin:~/k8s# kubectl get pods --all-namespaces |
排查
排查 containerd
使用 ctr plugin ls
查看 containerd 的插件是否都正常
1 | root@kevin:~# ctr plugin ls |
可以看到 containerd 的 cri 插件状态为 errror
。
如果 cri 插件出现问题,那么 crictl 也会出现问题。为了更好的拍错,现在修改 crictl 的配置文件,将日志调整到 debug。这个配置为文件是在
前面安装 containerd 时,解压后自动生成的。
修改 /etc/crictl.yaml
文件
1 | runtime-endpoint: unix:///run/containerd/containerd.sock |
然后运行 crictl info :
1 | root@kevin:~/k8s# crictl info |
可以看到 crictl 也有问题。
因为我是升级新的 containerd ,所以猜测可能是老的 containerd 配置文件袋导致了服务问题。
1 | containerd config default > /etc/containerd/config.toml |
配置 runc 使用 cgroup
修改 /etc/containerd/config.toml
,将 SystemdCgroup
调整为 true
1 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] |
然后重启 containerd
1 | systemctl restart containerd |
最后再次检查 cri
1 | ctr pulgin ls |
如果看到 crictl info
的最后输出有 "lastCNILoadStatus": "cni config load failed: no network config found in /etc/cni/net.d: cni plugin not initialized: failed to load cni config"
的字样。则需要在 /etc/cni/net.d
中增加 containerd 的默认配置,因为在重置 kubernetes 集群的时候已经将 /etc/cni/net.d
完全删除了。
增加如下内容到 /etc/cni/net.d/10-containerd-net.conflist
1 | { |
再次重启 containerd 后检查:
1 | ctr pulgin ls |
此时 cri 正常 。同时可以看到输出结果的最后显示 cni 状态 "lastCNILoadStatus": "OK"
。
使用集群-
创建工作负载时拉取镜像出错
在创建工作负载时,由于某些负载使用的镜像并不在 docker.io 中,在拉取时可能因为网络访问缓慢或者无法访问而拉取失败,
此时最佳的方法是配置 containerd 的服务使用代理访问。
无法完全删除工作负载
具体请参考 Using Finalizers to Control Deletion