Kubernetes 部署实战:kubeadm + containerd
使用 kubeadm + containerd 从零部署生产级 Kubernetes 集群的完整记录,含网络插件和核心插件配置。
ops-install-service-kubernetes_by_kubeadmin_new
学习新技术提升自我价值,Kubernetes 是 Google 开源的容器集群管理系统,对于容器运行时、编排、常规服务都抽象设计出标准完整的 API。
简介
跟着官方文档学习使用 Kubeadm 安装 Kubernetes。由于中文文档和英文文档有差别,选择使用英文文档进行学习安装。
由于官方文档较复杂,跟着【K8S 笔记 - 使用 kubeadm 安装 k8s】学习了部分内容,做了部分修改。修改的原因是在搭建学习 kubernets 过程中了解到 kubernetes 已经在高版本移除了 dockershim 且,containerd 运行时是 docker 项目拆分出来的容器运行时,所以直接选择 containerd 作为容器运行时。
其他参考文档:
以下是本文档使用到的服务和对应的信息
| 序号 | 服务 | 版本 | 描述 |
|---|---|---|---|
| 1 | containerd.io | 1.7.22 | 容器运行时 |
| 2 | runc | 1.1.14 | 是一个命令行工具端,根据OCI(开放容器组织)的标准来创建和运行容器。 |
| 3 | flannel | 1.0.1 | 网络插件 |
| 5 | Calico | 3.28.2 | 网络插件 |
| 4 | kubeadm | 1.28.15 | kubernetes 安装工具 |
| 5 | kubectl | 1.28.15 | kubernetes 命令行工具 |
| 6 | kubelet | 1.28.15 | 一个在集群中每个节点(node)上运行的代理。 |
准备 linux 环境
本文档使用的是 ubuntu-24.04.1-live-server。
- 为了方便识别,将主机名称修改,修改的信息参考下方的列表信息。
hostnamectl set-hostname k8s-master
hostnamectl set-hostname k8s-slave-1
hostnamectl set-hostname k8s-salve-2
并将IP和hostname信息添加至 hosts 中
cat >> /etc/hosts << EOF
128.196.66.10 k8s-master
128.196.66.11 k8s-slave-1
128.196.66.12 k8s-slave-2
EOF
-
将准备完成的虚拟机根据官方要求,将虚拟机硬件配置进行调整
- CPU 修改为 2 核
- 内存修改为 2GB
-
关闭 firewalld
由于是学习环境,直接关闭防火墙。生产环境建议开启系统防火墙保证安全性,根据官方文档检查所需端口,开启必要的端口。systemctl stop firewalld systemctl disable firewalld -
关闭交换分区
为了保证 kubelet 正常工作,你 必须 禁用交换分区。 在 Kubernetes 1.22 之前,节点不支持使用交换内存,并且默认情况下, 如果在节点上检测到交换内存配置,kubelet 将无法启动。 在 1.22 以后,可以 逐个节点地启用交换内存支持。但这还在 alpha 阶段。# 查看swap分区情况 swapon free -h # 关闭所有 swap 分区 # 临时关闭 swapoff -a # 永久关闭 vim /etc/fstab # 将 swap 行注释,保存退出。然后重启服务器。 # sed -i '/swap/s/^/#/g' /etc/fstab -
环境详情
IP 服务器名称 安装服务 128.196.66.10 k8s-master containerd.io
kubeadm
kubectl
kubelet
caclico
128.196.66.11 k8s-slave-1 containerd.io
kubeadm
kubectl
kubelet
calico
128.196.66.12 k8s-slave-2 containerd.io
kubeadm
kubectl
kubelet
calico
环境准备完成后使用 Xshell (官方家庭版本),进行SSH连接。可使用另一个开源工具 WindTerm 连接,此客户端是由于办公时网络限制且不能安装软件, 通过此软件进行 SSH 连接。
安装
安装过程中,若没有指出仅在 slave 端安装,默认所有服务器上都需要安装对应的服务。本文使用的是 root 用户进行安装的,如果是其他用户安装需要 su。
安装容器运行时
本文档安装的是 containerd 容器运行时,参考文档 【Getting started with containerd】。本文档使用的是 1.7.22。使用 apt 的安装方式进行安装。
安装前准备
-
转发 IPv4 并使 iptables 可以桥接流量
cat <<EOF | tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter # sysctl params required by setup, params persist across reboots cat <<EOF | tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF # Apply sysctl params without reboot sudo sysctl --system -
Cgroup 驱动
本文档使用的是 Cgroup V1 版本,在运行中的 POD 修改 Cgroup 驱动是不明智的,因为重新修改后仍然可能会出现问题。 kubernetes 仅支持相同版本的 cgroup 驱动,因此建议在搭建集群的时候就需要考虑使用 Cgroup V1 还是 V2。 修改配置文件,设置为 SystemdCgroup = true,此操作会在安装配置中修改对应的内容。 -
移除旧版本
apt remove -y containerd.io -
配置镜像,通过阿里云开源镜像站配置
# step 1: 安装必要的一些系统工具 sudo apt update sudo apt -y install apt-transport-https ca-certificates curl software-properties-common # step 2: 安装GPG证书 # 国内环境 # curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - # Step 3: 写入软件源信息 # 国内环境 # sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" # Step 4: 更新并安装Docker-CE sudo apt -y update -
安装 containerd.io 并启动
# 安装 containerd.io,由于此脚本会有docker相关的,仅复制安装了一个内容 apt -y install containerd # 此包包含 runc -
生成配置文件,并将 Cgroup 开启
# 生成默认的配置文件 [ ! -d /etc/containerd ] && mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml # 修改配置文件中的内容,将 SystemdCgroup 开启,Ubuntu 22.04 默认的 cgroup 版本是 v2。 sed -i '/SystemdCgroup/s/SystemdCgroup =.*/SystemdCgroup = true/' /etc/containerd/config.toml # 修改配置文件中的内容,将 *sandbox_image* 源修改为 阿里云,针对国内环境 # sed -i 's#registry.k8s.io#registry.cn-hangzhou.aliyuncs.com/google_containers#' /etc/containerd/config.toml # 重启服务 systemctl restart containerd
安装 kubeadm kubelet kubectl
- 安装kubernetes 1.28
# 配置 阿里云 kubernetes 源 # sudo apt-get update # sudo apt-get install -y apt-transport-https ca-certificates curl gpg # curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/deb/Release.key | # gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg # echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/deb/ /" | # tee /etc/apt/sources.list.d/kubernetes.list # sudo apt-get update # sudo apt-mark hold kubelet kubeadm kubectl sudo apt-get update # apt-transport-https may be a dummy package; if so, you can skip that package sudo apt-get install -y apt-transport-https ca-certificates curl gpg curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg # This overwrites any existing configuration in /etc/apt/sources.list.d/kubernetes.list echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubeadm=1.28.15* kubectl=1.28.15* kubelet=1.28.15* sudo apt-mark hold kubelet kubeadm kubectl # kubelet 会在安装完成后处于 'auto-restart' 的状态,这是由于在陷入了一个等待 `kubeadm` 指令的死循环。
安装其他工具(可选)
初始化 kubeadm(master)
-
初始化前准备
# 生成 bootstrapTokens 的 token 值 ## bootstrapTokens 是由 [a-z0-9](6位)+ '.' + [a-z0-9](16位) 组成的17位字符串 token_value=$(kubeadm token generate) # 创建配置文件,详细如下 mkdir /app/data/k8s/ -p cat > /app/data/k8s/kubeadm.yaml << EOF apiVersion: kubeadm.k8s.io/v1beta3 bootstrapTokens: - groups: - system:bootstrappers:kubeadm:default-node-token token: ${token_value} ttl: 24h0m0s usages: - signing - authentication kind: InitConfiguration localAPIEndpoint: advertiseAddress: 128.196.66.10 bindPort: 6443 nodeRegistration: criSocket: unix:///run/containerd/containerd.sock imagePullPolicy: IfNotPresent name: k8s-master taints: - effect: NoSchedule key: node-role.kubernetes.io/master --- apiServer: timeoutForControlPlane: 4m0s apiVersion: kubeadm.k8s.io/v1beta3 certificatesDir: /etc/kubernetes/pki clusterName: kubernetes controllerManager: {} dns: {} etcd: local: dataDir: /var/lib/etcd kind: ClusterConfiguration kubernetesVersion: v1.28.15 networking: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 scheduler: {} EOF # 查看可用镜像 kubeadm config images list --config /app/data/k8s/kubeadm.yaml # 下载镜像 kubeadm config images pull --config /app/data/k8s/kubeadm.yaml # 初始化 master kubeadm init --config /app/data/k8s/kubeadm.yaml # 初始过程比较慢 # 安装完成后 kube-system 命名空间会启动 'coredns' 和 'kube-proxy' pod -
输出如下表示初始化成功
[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 128.196.66.10:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:a917905179990bb84d948f6b0e3592dfeae3d4400a10b03de7f5760717328e10最后一行也显示了 slave 加入master 的详细命令。后续 slave 加入master 输入此内容即可。
-
根据输出的内容操作
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config export KUBECONFIG=/etc/kubernetes/admin.conf >> ~/.bash_profile source ~/.bash_profile -
查看 node
# 由于还未安装网络组件,状态都为 NotReady # kubectl get node 同样可以sudo kubectl get nodes # 使用以下命令也可以查看 node 详细信息 kubectl describe node k8s-master | grep network
slave 加入集群
# 根据kubeadm master 安装成功后提示的内容进行操作 kubeadm join 128.196.66.10:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:a917905179990bb84d948f6b0e3592dfeae3d4400a10b03de7f5760717328e10master 查看集群
# 查看 node 信息 kubectl get node # kubectl get nodes 相同信息 # 查看 pods 信息 kubectl get pods -n kube-systemcoredns 状态为 Pending,这为正常情况,因为网络组件还未安装。 kube-proxy 使用的是默认的 iptables 模式,如果需要使用 ivps 模式请参考 https://docs.tigera.io/calico/3.28/networking/configuring/use-ipvs
NAME READY STATUS RESTARTS AGE coredns-7f74c56694-pq8hb 0/1 Pending 0 2m19s coredns-7f74c56694-xrzvv 0/1 Pending 0 2m19s etcd-k8s-master 1/1 Running 0 2m33s kube-apiserver-k8s-master 1/1 Running 0 2m32s kube-controller-manager-k8s-master 1/1 Running 0 2m32s kube-proxy-87wtl 1/1 Running 0 2m2s kube-proxy-klxr8 1/1 Running 0 109s kube-proxy-xn69c 1/1 Running 0 2m20s kube-scheduler-k8s-master 1/1 Running 0 2m32s安装网络组件-CNI
网络是 kubernetes 的核心组成部分。
参考文档: https://zhuanlan.zhihu.com/p/513231562 https://developer.aliyun.com/article/1245323
flannel
由于是学习部署阶段,选择 flannel 作为 k8s 的网络组件。后期考虑单独学习 calico,由于此组件有更多的配置项,可以更容易满足生产条件。
- 下载配置文件
# 国内网络可能无法下载,下文会将详细的内容贴出 wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml - 修改配置文件
根据注释内容进行修改,主要为添加网卡信息。--- apiVersion: policy/v1beta3 # 将v1beta1 修改为 v1beta3,不然会有警告,不修改也不影响使用。 kind: PodSecurityPolicy metadata: name: psp.flannel.unprivileged annotations: seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default spec: privileged: false volumes: - configMap - secret - emptyDir - hostPath allowedHostPaths: - pathPrefix: "/etc/cni/net.d" - pathPrefix: "/etc/kube-flannel" - pathPrefix: "/run/flannel" readOnlyRootFilesystem: false # Users and groups runAsUser: rule: RunAsAny supplementalGroups: rule: RunAsAny fsGroup: rule: RunAsAny # Privilege Escalation allowPrivilegeEscalation: false defaultAllowPrivilegeEscalation: false # Capabilities allowedCapabilities: ['NET_ADMIN', 'NET_RAW'] defaultAddCapabilities: [] requiredDropCapabilities: [] # Host namespaces hostPID: false hostIPC: false hostNetwork: true hostPorts: - min: 0 max: 65535 # SELinux seLinux: # SELinux is unused in CaaSP rule: 'RunAsAny' --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: flannel rules: - apiGroups: ['extensions'] resources: ['podsecuritypolicies'] verbs: ['use'] resourceNames: ['psp.flannel.unprivileged'] - apiGroups: - "" resources: - pods verbs: - get - apiGroups: - ""
-