现阶段版本迭代较快,本文的安装方式可能与最新版有所差异,请以产品文档的安装说明为准。

1. Kubernetes(K8S) 架构

首先,我们先了解下K8S的架构

Kubernetes遵循客户端-服务器架构。其中,分为master节点和node节点。

1.1 master节点组件

  • API Server
    对外提供RESTful API 接口,集群管理事件的统一入口,负责集群的监听,认证,授权,准入控制。对内负责controller-manager,scheduler,kubelet,proxy,所有对象资源的增删改查都交给APIServer处理后续,给etcd做持久化存储。
  • Controller Manager
    从逻辑上讲,每个控制器都是一个单独的进程,但是为了降低复杂性,他们都被编译到同一个可执行文件,并在一个进程中负责管理集群各种资源,保证资源处于预期的状态。controller manager由多种controller组成,包括node controller,job controller,endpoints controller,service account & token controllers 等。
  • Scheduler(调度器) (预选/优选)
    在预选阶段首先过滤掉不满足当前Pod请求的nodes,在优选阶段。根据一系列函数对剩余可承接度的Nodes评分,评选出得分最高的node,并将调度决定告知APIserver,这个过程叫做绑定
  • etcd(数据库)(CNCF独立项目)(可以放在master或独立部署)
    etcd是一个高可用的分布式键值数据库,可用于服务发现。etcd采用raft一致性算法,基于Go语言实现。etcd作为一个高可用的键值储存系统,天生就是为集群化而设计的。用于保存k8s资源状态数据

1.2 node节点组件

  • kubelet(容器运行时代理)
    每个nodes都以systemd服务的形式运行着软件包安装的kubelet。kubelet是kube-apiserver在node上容器的运行时代理,当scheduler确定在某个node上运行pod后,会将pod的具体配置信息(image(镜像),volume(磁盘)等)发送给该节点的kubelet,kubelet会根据这些信息调用该节点上的容器运行时创建和维护容器的生命周期,并默认每隔10s向apiserver报告当前节点的运行状态。
  • proxy(路由条目和路由规则)
    集群出厂使用DaemonSet控制器在每个Nodes上运行Kube-proxy pod,proxy配合service做服务发现,负责维护每个Nodes上iptables NAT表的自定义链或LVS的路由规则表。将访问的Service的TCP/UDP数据流转发到后端Pod的真实私有IP地址。
  • docker(容器运行时)
    容器运行时是负责运行容器的软件。例如docker,containerd(当前主流,兼容性好,稳定),CRI-O(未来,安全,轻量)

2. 集群主机规划

按照上面的架构,对集群主机进行规划

RolesHostnameFQDNIP addressComponents
Clientclientclient.lab.example.com192.168.126.99kubectl
Mastermastermaster.lab.example.com192.168.126.100kube-apiserver、kube-controller-manager、kube-scheduler、etcd、kube-proxy 、calico-kube-controllers、calico-node
Workernode1node1.lab.example.com192.168.126.101--
Workernode2node2.lab.example.com192.168.126.102--
Workernode3node3.lab.example.com192.168.126.103--
OCI Registryregistryregistry.lab.example.com192.168.126.55备用 image registry

3. 安装K8S

考虑到为实验环境,没有那么多真实的服务器,本文将用虚拟机进行安装演示。

本文实例采用的组件为:
Kubernetes:1.31.6
CRI:containerd(因为新版本 K8s 已经不再直接支持 Docker)
OS:ubuntu

部署大致步骤分为:
规划集群 > 根据规划写入host > 设置内核参数 > 关闭内存交换 > 安装containerd(容器运行时) > 安装kubeadm,kubectl,kubelet >指定容器运行时 > 配置IP和hostname > 使用
kubeadm init 初始化K8S > 使用kubeadm join 加入集群 > 配置 kubeconfig ,用kubectl控制集群 > 完成

3.1 规划集群

详情见 2. 集群主机规划

3.2 根据规划写入host 【所有节点】

candidate@k8s:~$ sudo -i [sudo] password for candidate: 
root@k8s:~# apt-get upgrade -y 
root@k8s:~# cat > /etc/hosts << EOF
    127.0.0.1 localhost
    192.168.126.199 client client.lab.example.com
    192.168.126.200 master master.lab.example.com
    192.168.126.201 node1 node1.lab.example.com
    192.168.126.202 node2 node2.lab.example.com
    192.168.126.203 node3 node3.lab.example.com
    192.168.126.155 registry registry.lab.example.com 
EOF

3.3 设置内核参数并允许 iptables 进行桥接流量 【所有节点】

root@k8s:~# cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
vm.swappiness = 0
EOF
root@k8s:~# echo br_netfilter >> /etc/modules && modprobe br_netfilter # 加载模块
root@k8s:~# sysctl --system 

3.4 关闭内存交换 【所有节点】

root@k8s:~# swapoff -a
root@k8s:~# sed -ir 's/.*swap/#&/g' /etc/fstab
root@k8s:~# rm -Rf /swap.img
root@k8s:~# free -m

3.5 安装containerd(容器运行时)【所有节点,Client节点可忽略】

安装 containerd,可以用二进制也可以用包,下文以包举例。
配置apt仓库

root@k8s:~# apt-get remove docker docker.io containerd runc -y
root@k8s:~# apt-get install ca-certificates curl gnupg lsb-release -y
root@k8s:~# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
root@k8s:~# echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
root@k8s:~# apt-get update

安装

root@k8s:~# apt-get install containerd.io docker-ce docker-ce-cli -y //顺路带上docker

配置 containerd
更新配置文件内容: 使用 systemd 作为 cgroup 驱动,并且替代 pause 镜像地址

sed -i 's/SystemdCgroup\ =\ false/SystemdCgroup\ =\ true/' /etc/containerd/config.toml
sed -i 's/k8s.gcr.io\/pause/k8s-gcr.m.daocloud.io\/pause/g' /etc/containerd/config.toml 
sed -i 's/registry.k8s.io\/pause/k8s-gcr.m.daocloud.io\/pause/g' /etc/containerd/config.toml
sudo systemctl daemon-reload
sudo systemctl restart containerd
sudo systemctl enable containerd

添加在配置文件中加入私有镜像源并跳过TLS验证(可选)

[plugins."io.containerd.grpc.v1.cri".registry.configs."registry.lab.example.com".tls]
 insecure_skip_verify = true

3.6 安装kubeadm,kubectl,kubelet【所有节点】

这里使用阿里云镜像站
配置apt仓库

  root@k8s:~#  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
   root@k8s:~# 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

安装(版本需对应)

root@k8s:~# apt-get update
root@k8s:~# apt-cache madison kubelet
root@k8s:~# apt-get install kubelet=1.28.15-00 kubeadm=1.28.15-00 kubectl=1.28.15-00 -y
root@k8s:~# systemctl enable kubelet

3.7 指定容器运行时 【所有节点,Client节点可忽略】

root@k8s:~# crictl config runtime-endpoint unix:///var/run/containerd/containerd.sock
root@k8s:~# crictl config image-endpoint unix:///var/run/containerd/containerd.sock

3.8 配置IP和hostname 【所有节点】

登录虚拟机按照主机规划清单分别设置主机名,修改网卡 IP 地址。

sudo hostnamectl set-hostname client
sudo hostnamectl set-hostname master
sudo hostnamectl set-hostname node1
sudo hostnamectl set-hostname node2
sudo hostnamectl set-hostname node3

vim /etc/netplan/00-installer-config.yaml
sudo netplan apply
init 0

3.9 使用kubeadm init 初始化K8S 【master节点】

sudo kubeadm init --kubernetes-version=v1.28.15 --apiserver-advertise-address=192.168.126.100 --image-repository=registry.aliyuncs.com/google_containers --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12

参数解释:
--kubernetes-version k8s发行版本
--apiserver-advertise-address api地址监听
--image-repository 镜像源
--pod-network-cidr pod地址段
--service-cidr pod负载均衡地址段
注:忘记token或者token过期,可以使用命令kubeadm token generate生成随机token,使用命令kubeadm token create xtokenx --print-join-command --ttl 过期时间,生成加入命令

经过十几分钟,你能看到打印成功的信息如下:

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) $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.126.100:6443 --token 3guatc.nzrxmvl3yppxcl7u \
        --discovery-token-ca-cert-hash sha256:7d5a528aa5f3f4a9e86ea87efad584b6fbf10414de03b28d52f564a8842e5ea4

请记住最后打印出的 kubeadm join 命令和相应 token,后续会用到

注:配置过程中出现问题,可以用kubeadm reset重置从头开始

3.10 使用kubeadm join 加入集群 【node节点】

sudo kubeadm join 192.168.126.100:6443 --token 3guatc.nzrxmvl3yppxcl7u \
            --discovery-token-ca-cert-hash sha256:7d5a528aa5f3f4a9e86ea87efad584b6fbf10414de03b28d52f564a8842e5ea4

成功加入后会显示:

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.

3.11 配置kubectl 登录凭证,kubectl、kubeadm 命令行补齐【master节点】

candidate@master:~$ sudo bash -c "echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> /root/.bash_profile"
candidate@master:~$ sudo bash -c "echo 'source <(kubeadm completion bash)' >> /root/.bash_profile"
candidate@master:~$ sudo bash -c "echo 'source <(kubectl completion bash)' >> /root/.bash_profile"

3.12 配置客户端kubectl 登录凭证,kubectl、kubeadm 命令行补齐【client,master节点】

mkdir ~/.kube
sudo cp /etc/kubernetes/admin.conf /home/$USER/.kube/config
sudo cp /etc/kubernetes/pki/ca.crt /home/$USER/.kube/
sudo chown $USER.$USER ~/.kube/*
for x in node1 node2 node3 client;do scp ~/.kube/* $x:~/.kube/;done 
for client in node1 node2 node3;do ssh $client "echo 'source <(kubeadm completion bash)' >> ~/.bash_profile";done
for client in node1 node2 node3;do ssh $client "echo 'source <(kubectl completion bash)' >> ~/.bash_profile";done
source ~/.bash_profile 

3.13 测试

kubectl get node
----- END -----