kubeadm 是 Kubernetes 官方提供的用于快速安部署 Kubernetes 集群的工具,伴随 Kubernetes 每个版本的发布都会同步更新,kubeadm 会对集群配置方面的一些实践做调整,通过实验 kubeadm 可以学习到 Kubernetes 官方在集群配置上一些新的最佳实践。
1.1 系统配置
在安装之前,需要先做好如下准备。3 台 CentOS 7.9 主机如下:
在各个主机上完成下面的系统配置。
如果各个主机启用了防火墙策略,需要开放 Kubernetes 各个组件所需要的端口,可以查看Ports and Protocols中的内容, 开放相关端口或者关闭主机的防火墙。
禁用 SELINUX:
创建/etc/modules-load.d/containerd.conf 配置文件:
执行以下命令使配置生效:
创建/etc/sysctl.d/99-kubernetes-cri.conf 配置文件:
执行以下命令使配置生效:
1.2 配置服务器支持开启 ipvs 的前提条件
由于 ipvs 已经加入到了内核的主干,所以为 kube-proxy 开启 ipvs 的前提需要加载以下的内核模块:
在各个服务器节点上执行以下脚本:
上面脚本创建了的/etc/sysconfig/modules/ipvs.modules
文件,保证在节点重启后能自动加载所需模块。 使用lsmod | grep -e ip_vs -e nf_conntrack_ipv4
命令查看是否已经正确加载所需的内核模块。
接下来还需要确保各个节点上已经安装了 ipset 软件包,为了便于查看 ipvs 的代理规则,最好安装一下管理工具 ipvsadm。
如果不满足以上前提条件,则即使 kube-proxy 的配置开启了 ipvs 模式,也会退回到 iptables 模式。
1.3 部署容器运行时 Containerd
在各个服务器节点上安装容器运行时 Containerd。
下载 Containerd 的二进制包:
cri-containerd-cni-1.6.4-linux-amd64.tar.gz
压缩包中已经按照官方二进制部署推荐的目录结构布局好。 里面包含了 systemd 配置文件,containerd 以及 cni 的部署文件。 将解压缩到系统的根目录/
中:
注意经测试 cri-containerd-cni-1.6.4-linux-amd64.tar.gz 包中包含的 runc 在 CentOS 7 下的动态链接有问题,这里从 runc 的 github 上单独下载 runc,并替换上面安装的 containerd 中的 runc:
接下来生成 containerd 的配置文件:
根据文档Container runtimes 中的内容,对于使用 systemd 作为 init system 的 Linux 的发行版,使用 systemd 作为容器的 cgroup driver 可以确保服务器节点在资源紧张的情况更加稳定,因此这里配置各个节点上 containerd 的 cgroup driver 为 systemd。
修改前面生成的配置文件/etc/containerd/config.toml
:
再修改/etc/containerd/config.toml
中的
配置 containerd 开机启动,并启动 containerd
使用 crictl 测试一下,确保可以打印出版本信息并且没有错误信息输出:
2.使用 kubeadm 部署 Kubernetes
2.1 安装 kubeadm 和 kubelet
下面在各节点安装 kubeadm 和 kubelet:
运行kubelet --help
可以看到原来 kubelet 的绝大多数命令行 flag 参数都被DEPRECATED
了,官方推荐我们使用--config
指定配置文件,并在配置文件中指定原来这些 flag 所配置的内容。具体内容可以查看这里Set Kubelet parameters via a config file。最初 Kubernetes 这么做是为了支持动态 Kubelet 配置(Dynamic Kubelet Configuration),但动态 Kubelet 配置特性从 k8s 1.22 中已弃用,并在 1.24 中被移除。如果需要调整集群汇总所有节点 kubelet 的配置,还是推荐使用 ansible 等工具将配置分发到各个节点。
kubelet 的配置文件必须是 json 或 yaml 格式,具体可查看这里。
Kubernetes 1.8 开始要求关闭系统的 Swap,如果不关闭,默认配置下 kubelet 将无法启动。 关闭系统的 Swap 方法如下:
修改 /etc/fstab 文件,注释掉 SWAP 的自动挂载,使用free -m
确认 swap 已经关闭。
swappiness 参数调整,修改/etc/sysctl.d/99-kubernetes-cri.conf 添加下面一行:
执行sysctl -p /etc/sysctl.d/99-kubernetes-cri.conf
使修改生效。
2.2 使用 kubeadm init 初始化集群
在各节点开机启动 kubelet 服务:
使用kubeadm config print init-defaults --component-configs KubeletConfiguration
可以打印集群初始化默认的使用的配置:
从默认的配置中可以看到,可以使用imageRepository
定制在集群初始化时拉取 k8s 所需镜像的地址。基于默认配置定制出本次使用 kubeadm 初始化集群所需的配置文件 kubeadm.yaml:
这里定制了imageRepository
为阿里云的 registry,避免因 gcr 被墙,无法直接拉取镜像。criSocket
设置了容器运行时为 containerd。 同时设置 kubelet 的cgroupDriver
为 systemd,设置 kube-proxy 代理模式为 ipvs。
在开始初始化集群之前可以使用kubeadm config images pull --config kubeadm.yaml
预先在各个服务器节点上拉取所 k8s 需要的容器镜像。
接下来使用 kubeadm 初始化集群,选择 node1 作为 Master Node,在 node1 上执行下面的命令:
上面记录了完成的初始化输出的内容,根据输出的内容基本上可以看出手动初始化安装一个 Kubernetes 集群所需要的关键步骤。 其中有以下关键内容:
-
[certs]
生成相关的各种证书 -
[kubeconfig]
生成相关的 kubeconfig 文件 -
[kubelet-start]
生成 kubelet 的配置文件"/var/lib/kubelet/config.yaml" -
[control-plane]
使用/etc/kubernetes/manifests
目录中的 yaml 文件创建 apiserver、controller-manager、scheduler 的静态 pod -
[bootstraptoken]
生成 token 记录下来,后边使用kubeadm join
往集群中添加节点时会用到 -
下面的命令是配置常规用户如何使用 kubectl 访问集群:
-
最后给出了将节点加入集群的命令
kubeadm join 192.168.96.151:6443 --token uufqmm.bvtfj4drwfvvbcev \ --discovery-token-ca-cert-hash sha256:5814415567d93f6d2d41fe4719be8221f45c29c482b5059aec2e27a832ac36e6
查看一下集群状态,确认个组件都处于 healthy 状态,结果出现了错误:
集群初始化如果遇到问题,可以使用kubeadm reset
命令进行清理。
2.3 安装包管理器 helm 3
Helm 是 Kubernetes 的包管理器,后续流程也将使用 Helm 安装 Kubernetes 的常用组件。 这里先在 master 节点 node1 上安装 helm。
执行helm list
确认没有错误输出。
2.4 部署 Pod Network 组件 Calico
选择 calico 作为 k8s 的 Pod 网络组件,下面使用 helm 在 k8s 集群中安装 calico。
下载tigera-operator
的 helm chart:
查看这个 chart 的中可定制的配置:
定制的values.yaml
如下:
使用 helm 安装 calico:
等待并确认所有 pod 处于 Running 状态:
查看一下 calico 向 k8s 中添加的 api 资源:
这些 api 资源是属于 calico 的,因此不建议使用 kubectl 来管理,推荐按照 calicoctl 来管理这些 api 资源。 将 calicoctl 安装为 kubectl 的插件:
验证插件正常工作:
2.5 验证 k8s DNS 是否可用
进入后执行nslookup kubernetes.default
确认解析正常:
2.6 向 Kubernetes 集群中添加 Node 节点
下面将 node2, node3 添加到 Kubernetes 集群中,分别在 node2, node3 上执行:
node2 和 node3 加入集群很是顺利,在 master 节点上执行命令查看集群中的节点:
3.Kubernetes 常用组件部署
3.1 使用 Helm 部署 ingress-nginx
为了便于将集群中的服务暴露到集群外部,需要使用 Ingress。接下来使用 Helm 将 ingress-nginx 部署到 Kubernetes 上。 Nginx Ingress Controller 被部署在 Kubernetes 的边缘节点上。
这里将 node1(192.168.96.151)作为边缘节点,打上 Label:
下载 ingress-nginx 的 helm chart:
查看ingress-nginx-4.1.2.tgz
这个 chart 的可定制配置:
对 values.yaml 配置定制如下:
nginx ingress controller 的副本数 replicaCount 为 1,将被调度到 node1 这个边缘节点上。这里并没有指定 nginx ingress controller service 的 externalIPs,而是通过hostNetwork: true
设置 nginx ingress controller 使用宿主机网络。 因为 k8s.gcr.io 被墙,这里替换成 unreachableg/k8s.gcr.io_ingress-nginx_controller 提前拉取一下镜像:
测试访问[http://192.168.96.151](http://192.168.96.151/)
返回默认的 nginx 404 页,则部署完成。
3.2 使用 Helm 部署 dashboard
先部署 metrics-server:
修改 components.yaml 中的 image 为[docker.io/unreachableg/k8s.gcr.io_metrics-server_metrics-server:v0.5.2](http://docker.io/unreachableg/k8s.gcr.io_metrics-server_metrics-server:v0.5.2)
。 修改 components.yaml 中容器的启动参数,加入--kubelet-insecure-tls
。
metrics-server 的 pod 正常启动后,等一段时间就可以使用kubectl top
查看集群和 pod 的 metrics 信息:
接下来使用 helm 部署 k8s 的 dashboard,添加 chart repo:
查看 chart 的可定制配置:
对 values.yaml 定制配置如下:
先创建存放[k8s.example.com](http://k8s.example.com/)
ssl 证书的 secret:
使用 helm 部署 dashboard:
确认上面的命令部署成功。
创建管理员 sa:
创建集群管理员登录 dashboard 所需 token:
使用上面的 token 登录 k8s dashboard。