使用 kubeadm 安装 Kubernetes 介绍
前言
k8s 各节点运行的服务说明:
- master(控制平面)
- etcd
- kube-apiserver
- kube-scheduler(port: 10251/10259)
- kube-controller-manager
- node(数据平面)
- kube-proxy(port: 10256/30080/30443)
- kubelet
- container runtime, like docker
- 每个阶段最多创建 110 个 Pod
kubectl describe nodes k8s-worker-1 | grep -i "Capacity\|Allocatable" -A 6- 配置
/var/lib/kubelet/config.yaml的maxPods: 500修改最大值
PS:控制平面的服务以静态 podstatic pod的形式运行。
高可用
所有节点安装前初始化
- 节点
- k8s-master 192.168.179.81
- k8s-node-1 192.168.179.82
- k8s-node-2 192.168.179.83
- CentOS 7.6,Kubernetes 中所有机器具有不同的 Mac 地址、product_uuid
ip link
cat /sys/class/dmi/id/product_uuid- 配置 ssh 免密登录
ssh-keygen
ssh-copy-id -i ~/.ssh/id_rsa.pub root@ip- 关闭 firewalld
systemctl stop firewalld
systemctl disable firewalld
# 查看状态
firewall-cmd --state
ufw disable
ufw status- 关闭 selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0PS: 也可以通过配置 KUBELET_KUBEADM_ARGS 规避
- 将桥接的 IPv4 流量传递到 iptables 的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
# 系统级别打开文件句柄的数量,达到限制时提示 `Too many open files` 或 `Socket/File: Can’t open so many files` 等错误
fs.file-max=1000000
# 以下三个参数,当内核维护的 arp 表过于庞大时候,可以考虑优化
# 存在于 ARP 高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是128。
net.ipv4.neigh.default.gc_thresh1=1024
# 保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512。
net.ipv4.neigh.default.gc_thresh2=4096
# 保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺省值是1024。
net.ipv4.neigh.default.gc_thresh3=8192
# 允许的最大跟踪连接条目,是在内核内存中netfilter可以同时处理的“任务”(连接跟踪条目)
net.netfilter.nf_conntrack_max=10485760
# 哈希表大小(只读)(64位系统、8G内存默认 65536,16G翻倍,如此类推)
net.netfilter.nf_conntrack_tcp_timeout_established=300
net.netfilter.nf_conntrack_buckets=655360
# 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
net.core.netdev_max_backlog=10000
# 指定了每一个real user ID可创建的inotify instatnces的数量上限,默认值: 128
fs.inotify.max_user_instances=524288
# 指定了每个inotify instance相关联的watches的上限,默认值: 8192
fs.inotify.max_user_watches=524288
EOF
sysctl --systemnf_conntrack(老版本为 ip_conntrack)是一个内核模块,用于跟踪一个连接的状态的。
- 时间同步
apt install chrony- 禁用 swap
swapoff -a并将 /etc/fstab 中 swap 行注释掉。
- 启用 ipvs 内核模块(参考)
CentOS:
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack_ipv4"
for kernel_module in \${ipvs_modules}; do
/sbin/modinfo -F filename \${kernel_module} > /dev/null 2>&1
if [ $? -eq 0 ]; then
/sbin/modprobe \${kernel_module}
fi
done
EOF启用
chmod 755 /etc/sysconfig/modules/ipvs.modules
modprobe nf_conntrack
bash /etc/sysconfig/modules/ipvs.modules
# 检查
lsmod | grep ip_vsUbuntu:
# 临时启用
$ for i in $(ls /lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i; done
# 永久启用,重启生效
$ ls /lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*" >> /etc/modules
# 检查
lsmod | grep ip_vs- 允许 iptables 检查桥接流量,需要显示加载此模块
# 加载
sudo modprobe br_netfilter
# 检测是否加载
lsmod | grep br_netfilter所有节点安装 Docker、kubeadm/kubelet/kubectl
Docker
- Centos/Linux 安装
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum install -y docker-ce
# Docker 1.13版本开始调整了默认的防火墙规则,禁用了iptables filter表中FOWARD链,会导致Kubernetes集群中跨Node的Pod无法通信,在[Service]中添加ExecStartPost,脚本如下:
sed -i "13i ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT" /usr/lib/systemd/system/docker.service- Ubuntu
apt update
apt -y install docker.io containerd- 配置加速
从 kubernetes v1.22 开始,为明确配置 kubelet 的 cgroup-driver 时,默认为 systemd,所以需要修改 docker 的 cgroupdriver
mkdir -p /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"registry-mirrors": [
"https://ghihfm4j.mirror.aliyuncs.com",
"https://registry.docker-cn.com"
],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "50m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
# "max-concurrent-downloads": 10
}
EOF
# 并配置加速
systemctl daemon-reload
systemctl enable docker
systemctl start docker
docker info | grep Cgroup安装 cir-dockerd
由于 k8s v1.24 起移除了对 dockershim 的支持,而 docker engine 默认不支持 k8s CRI 规范,需要安装 Mirantis cri-dockerd,请根据操作系统选择需要的版本
curl -LO https://github.com/Mirantis/cri-dockerd/releases/download/v0.2.5/cri-dockerd_0.2.5.3-0.ubuntu-focal_amd64.deb
dpkg -i cri-dockerd_0.2.5.3-0.ubuntu-focal_amd64.deb安装完成后,cri-docker.service 会自动启动
扩展:
- k8s Container Runtime Interface (CRI),Mirantis cri-dockerd 实现了这个兼容 docker 的 shim(垫片)
配置 cir-dockerd
由于 cri-dockerd 服务无法下载 k8s.gcr.io/pause:3.6 上的镜像,国内需要配置镜像源:
/lib/systemd/system/cri-docker.service
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image registry.aliyuncs.com/google_containers/pause:3.7
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image gcmirrors/pause:3.7systemctl daemon-reload
systemctl restart cri-docker.servicekubeadm/kubelet/kubectl
国内镜像源加速参考:https://developer.aliyun.com/mirror/kubernetes
- Centos
cat > /etc/yum.repos.d/k8s.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
yum install -y kubelet-1.19.0 kubeadm-1.19.0 kubectl-1.19.0
systemctl enable kubelet- Ubuntu
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
echo "deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt update
apt install -y kubelet kubeadm kubectl
systemctl enable kubelet安装
安装前,可以使用如下命令提前下载镜像:
# 方式一:配置文件
# default config
$ kubeadm config print init-defaults
$ kubeadm config print init-defaults --component-configs \
KubeProxyConfiguration,KubeletConfiguration > kubeadm-config.yaml
# 使用 ipvs 需要修改 mode: "ipvs"
# 验证
kubeadm init --config kubeadm-config.yaml --dry-run
# pull 镜像
kubeadm config images pull --config kubeadm-config.yaml
# 方式二:命令行方式
# pull k8s images
kubeadm config images list
# list k8s images
kubeadm config images pull
# 加速
kubeadm config images list --image-repository gcmirrors
kubeadm config images pull --image-repository gcmirrors --cri-socket unix:///var/run/cri-dockerd.sock
kubeadm config images list --image-repository registry.aliyuncs.com/google_containers
kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers --cri-socket unix:///var/run/cri-dockerd.sock说明:
KubeletConfiguration配置cgroupDriver- k8s v1.24(移除 Dockershim) 支持的 Container Runtimes
- containerd
- CRI-O
- Docker Engine
- Mirantis Container Runtime
- k8s 1.30 需要 Container Runtime Interface (CRI)
- 关于镜像加速,参考:Kubernetes 相关镜像国内加速
- 国内镜像源拉取,需要指定
--cri-socket路径- docker
--cri-socket unix:///var/run/cri-dockerd.sock - containerd
--cri-socket unix:///var/containerd/containerd.sock - CRI-o
--cri-socket unix:///var/run/crio/crio.sock- CRI-o 和 containerd 的容器管理机制不同,镜像文件不通用
- docker
- cgroup drivers
apiVersion: kubeadm.k8s.io/v1beta3
...
nodeRegistration:
# 修改为 containerd
criSocket: /run/containerd/containerd.sock # docker 配置为 unix:///var/run/cri-dockerd.sock
...
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
...
cgroupDriver: systemdKubernetes Master
在 Kubernetes Master 节点执行
--upload-certs在当前服务器上初始化一个新的 Kubernetes 控制平面节点,并且将生成的控制平面证书上传到集群内部的 Secret 中,以便后续其他控制平面节点加入时使用(实现高可用部署)
kubeadm init \
--apiserver-advertise-address=0.0.0.0 \
--apiserver-bind-port 6443 \
--cri-socket unix:///var/run/cri-dockerd.sock \
--image-repository gcmirrors \
--kubernetes-version v1.25.0 \
# --control-plane-endpoint="k8sapi.kb.cx" \
# --service-dns-domain "cluster.local" \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
# --ignore-preflight-errors=NumCPU \
--upload-certs \
--v 5输出如下命令:
- 加入节点命令
kubeadm token create --print-join-command- 使用 kubectl 工具配置
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
aliv2.kb.cx Ready master 2m21s v1.17.0- 修复 scheduler/controller-manager port 问题
$ kubectl get componentstatuses
$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health":"true"}组件状态异常,需要修改如下文件,注释--port=0:
- /etc/kubernetes/manifests/kube-apiserver.yaml
- /etc/kubernetes/manifests/kube-controller-manager.yaml
- /etc/kubernetes/manifests/kube-scheduler.yaml
ref: https://github.com/kubernetes/kubeadm/issues/2279
PS:/etc/kubernetes/manifests存放 K8s 对配置文件。
- 验证 API 状态
$ curl --cacert /etc/kubernetes/pki/ca.crt https://127.0.0.1:6443/livez
ok
$ curl --cacert /etc/kubernetes/pki/ca.crt https://127.0.0.1:6443/readyz
okPod 网络插件(CNI)
Flannel
Calico
添加 Node 节点
在Node执行,向集群添加新节点,执行在 master 执行kubeadm init时输出的kubeadm join命令:
kubeadm join 192.168.179.81:6443 --token u9079k.qhzueafydelowi05 \
--discovery-token-ca-cert-hash sha256:3f5c505110873644a0645f0037dacfebaeef99d671cd69ec3a5887bb0dc92c4e \
--cri-socket unix:///var/run/cri-dockerd.sock
# kubeadm join --config=<apiVersion: kubeadm.k8s.io/v1beta2\nkind: JoinConfiguration>u9079k.qhzueafydelowi05是 token,可以使用 kubeadm token,如下:
kubeadm token list
kubeadm token create # 可以生成新的token,替换 kubeadm join中的token就可以继续加入集群卸载指定节点
kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock测试 kubernetes 集群
- 查看服务是否正常
kubectl get componentstatus- 在 Kubernetes 集群中创建一个 pod,验证是否正常运行:
kubectl create deployment nginx --image=nginx:alpine
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc访问地址:http://NodeIP:Port
运维
重启
- 启动 kubelet
- 启动 docker 容器
docker ps -a | awk '{print $1}' | grep -v CONTAINER | xargs docker startkubeadm init phase certs
cd /etc/kubernetes/pki
rm apiserver.crt apiserver.key
kubeadm init phase certs apiserver --apiserver-cert-extra-sans *.xiexianbin.cn查看证书:
openssl x509 -text -noout -in apiserver.crt更新证书有效期
- 参考
- https://kubernetes.io/docs/tasks/tls/certificate-rotation/
- 或者修改 kubeadm 的代码,把证书有效期改成 10 年
- 查看
/etc/kubernetes/pki目录下的证书是否过期:
$ kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
W0220 14:50:39.905052 26453 utils.go:69] The recommended value for "resolvConf" in "KubeletConfiguration" is: /run/systemd/resolve/resolv.conf; the provided value is: /run/systemd/resolve/resolv.conf
CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Feb 20, 2023 05:57 UTC 364d ca no
apiserver Feb 20, 2023 05:57 UTC 364d ca no
apiserver-etcd-client Feb 20, 2023 05:57 UTC 364d etcd-ca no
apiserver-kubelet-client Feb 20, 2023 05:57 UTC 364d ca no
controller-manager.conf Feb 20, 2023 05:57 UTC 364d ca no
etcd-healthcheck-client Feb 20, 2023 05:57 UTC 364d etcd-ca no
etcd-peer Feb 20, 2023 05:57 UTC 364d etcd-ca no
etcd-server Feb 20, 2023 05:57 UTC 364d etcd-ca no
front-proxy-client Feb 20, 2023 05:57 UTC 364d front-proxy-ca no
scheduler.conf Feb 20, 2023 05:57 UTC 364d ca no
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Feb 20, 2032 05:57 UTC 9y no
etcd-ca Feb 20, 2032 05:57 UTC 9y no
front-proxy-ca Feb 20, 2032 05:57 UTC 9y no- 更新证书有效期 1 年(需要在所有的节点执行)
kubeadm certs renew all
kubeadm certs renew [ca|admin.conf|...]更新 admin.conf
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config说明:
- 若出现
KubeClientCertificateExpiration报警可能是因为 APIServer 服务没有正常重启导致(不要只从 kube-system 空间看,要使用ps -ef | grep xxx查看),参考?
更新 kube-proyx 代理模式
$ kubectl -n kube-system edit cm kube-proxy-config
...
ipvs:
scheduler: "sh"
syncPeriod: 30s
kind: KubeProxyConfiguration
mode: "ipvs"
...- 重启 pod
kubectl -n kube-system rollout restart ds kube-proxy更多 Addons
FQA
coredns Pending
解决方式:
kubectl taint nodes --all node-role.kubernetes.io/master-coredns CrashLoopBackOff
- kubectl edit cm coredns -n kube-system
- 删除掉那个 loop 并保存退出
- kubectl delete pod coredns-xxx-xxxx -n kube-system
cni config uninitialized
Nov 23 02:23:32 k8s-master kubelet: E1123 02:23:32.879492 5980 kubelet.go:2103] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized未安装 CNI 插件导致,安装见本文:Pod 网络插件(CNI)
Container runtime network not ready
openEuler 20.03 环境问题:
Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitializedyum install -y kubernetes-cni
yum install -y kubernetes-cni --nobestnetwork: error getting ClusterInformation
network: error getting ClusterInformation: connection is unauthorized: Unauthorized- 删除
kubectl -n kube-system delete pod calicoxxx,参考
failed to run Kubelet: misconfiguration
- 错误日志
"Failed to run kubelet” err="failed to run Kubelet: misconfiguration: kubelet cgroup driver: "systemd” is different from dock…er: "cgroupfs””- docker 和 kubernetes 所使用的 cgroup 不一致导致
cat > /etc/docker/daemon.json <<EOF
{"exec-opts": ["native.cgroupdriver=systemd"]}
EOF重启 docker
systemctl restart dockerflannel 网络配置错误
E0830 11:18:00.695429 1 main.go:330] Error registering network: failed to acquire lease: node "k8s-node-2" pod cidr not assignedkubeadm init --pod-network-cidr 必须指定,且和 flannel.yaml 中网段一致
kubeadm / kubelet 报 swap 错误
[ERROR Swap]: running with swap on is not supported. Please disable swap
[preflight] If you know what you are doing, you can make a check non-fatal with...- kubeadm
kubeadm init --ignore-preflight-errors=Swap- kubelet 服务,查看
systemctl cat kubelet找到对应的 ENV 文件,添加
KUBELET_EXTRA_ARGS="--fail-swap-on=false"k8s failed to get imageFs info: non-existent label “docker-images”
- 在
/lib/systemd/system/kubelet.service中添加
[Unit]
After=docker.servicecouldn’t get current server API group list: the server has asked for the client to provide credentials
kube 的证书到期,参考 更新证书有效期
/etc/kubernetes/manifests 目录作用
/etc/kubernetes/manifests目录是 Kubelet(在每个 Kubernetes 节点上运行的代理)默认监听的路径,用于创建和管理静态 Pod(Static Pods)。
- 静态 Pod 的定义位置:
- 放置在这个目录下的 YAML 或 JSON 格式的 Pod 清单文件会被该节点上的 Kubelet 自动读取。
- Kubelet 会直接在本地节点上创建和管理这些 Pod,而不经过 Kubernetes API Server 的调度。
- 核心组件的部署:
- 在许多 Kubernetes 集群部署工具(例如 kubeadm)初始化主节点(Control Plane 节点)时,这个目录被用来部署核心控制平面组件。
- 这些组件通常以静态 Pod 的形式运行,包括:
kube-apiserver.yamlkube-controller-manager.yamlkube-scheduler.yamletcd.yaml(如果 etcd 运行在控制平面节点上)
- 独立于控制平面:
- 静态 Pod 的主要特点是它们的生命周期由 Kubelet 直接管理。即使 Kubernetes API Server 出现故障,Kubelet 也会确保这些静态 Pod 持续运行或在失败时重新启动。这对于保证 Kubernetes 自身的控制平面组件的高可用性至关重要。
静态 Pod 的关键点
- 管理方式: 由节点上的 Kubelet 直接管理,绕过了标准的 API Server 调度流程。
- 可见性: 虽然静态 Pod 不经过 API Server 调度,但 Kubelet 会自动在 API Server 中创建一个对应的**
镜像 Pod**(Mirror Pod)对象,以便您可以使用kubectl get pods查看它们的状态。 - 管理限制: 不能通过
kubectl对静态 Pod 的镜像 Pod 进行修改或删除(例如kubectl delete)。要修改或删除静态 Pod,必须直接编辑或删除/etc/kubernetes/manifests目录下的原始清单文件。
kubelet 报错:with KillContainerError: rpc error: code = DeadlineExceeded desc = operation timeout: context deadline exceeded
containerd 执行命令有问题,重启机器。