Kubernetes + ArgoCD+github搭建自动化个人站点服务部署系列(上)——安装kubernetes(原创)

前言

Kubernetes是当今广泛使用的开源容器编排平台,旨在自动化应用程序的部署、扩展和管理。当前有许多开源版本和商用版本如Openshift(OCP)、Rancher,以及各类云厂商原生支持的版本如阿里云ACK、腾讯云TKE、Google Kubernetes Engine (GKE)、Azure Kubernetes Service (AKS)、Amazon EKS (Elastic Kubernetes Service)等等。

想要入门k8s,自行搭建一个规范的k8s集群是非常好的学习方式,作者在工作学习中有多年的k8s操作使用经验,本文旨在用最简单的方式部署一套开源的kubernetes集群,并通过热门的ArgoCD工具结合github自动化部署服务。
P.S. 看本文的同学默认对linux已经有一些基础,所以我不会繁琐的提示一些基础操作,代码形式只展示重要一点的命令
K8S原理不在本文过多解释,可参考Kubernetes documents
实践永远大于理论,结合优质的文档上手做的学习效率远高于抱着PDF啃,"Action is greater than waiting."

资源准备

云原生的探索离不开服务器资源的准备,至少也需要本地物理机环境的支持,良好的解决方案是本地环境测试验证,再去服务器真实部署(类似于企业中的nonProd环境和Pord环境),但是这种方式有些许繁琐,而且本地如果使用虚拟机方案对个人的PC有一定要求,考虑到大部分朋友(尤其是学生)可能没有非常充足的硬件环境,采用租用虚拟云主机VPS的方案也很不错。

如果需求是部署一个自己使用的站点,那么拥有一台独立的服务器更是必不可少的过程,如何挑选合适自己的VPS在本文不再赘述,也不是文章的核心内容,本教程的操作结果通过观察ECS服务器的监控数据,大约使用3GB左右的内存,1C不到的CPU。(如果后续需要继续部署服务,请自行重新评估集群所需资源大小,上述资源仅保证基本服务的拉起
这里贴一个我使用过的VPS服务推广链接,他们家在黑五等节日优惠力度很不错,而且有官方的交易平台方便收鸡
Akile链接

目标:

  1. 通过kubeadm工具部署一个完整的单节点K8S集群,版本1.32,用官方标准的部署方式,简单的标准网络插件
  2. 部署官方的Dashboard,方便直观的查看管理集群
  3. 标准方式部署一套ArgoCD 集群,对接GitHub私有仓库,自动拉取K8S配置文件进行CD流程
  4. 部署一个简单的服务,跑通整个流程

服务器初始化

我使用的服务器为标准的linux服务器,操作系统版本为Debian 12.2 x64,地区所属为美国洛杉矶,机器我测试过到国内的延迟,大约在160ms~200ms左右,虽然相比国内服务器,香港这些服务器来说延迟较高,但是总体来说还算好用,上海这边ssh访问终端体验也还行(捡的破烂要求什么呢
服务器创建好之后,确认好安全组的策略,如果是服务商提供安全组设置,可以直接放开所有规则,通过云厂商控制台统一设置(新手推荐),如果没有这项功能,可以自行通过ufw或者iptables等方式后续自定义防火墙规则
建议在集群搭建结束之后再统一设置防火墙策略,防止部署过程中不必要的麻烦

条件准备

在开始之前参照Kubernetes官方的Kubeadm部署方式文档,需要做以下检查:

  1. 主机参数满足最低运行要求
  2. (仅针对多节点集群)节点之前的网络能够互相连通,最方便的方式是针对ip直接放开相互访问权限,如果做不到的话需要参考K8S的核心组件互相放开必要的端口访问,如80、443、6443、10250、10255、10256、2379、2380等等。
    本文方便测试和认识学习,部署目标是单节点的k8s集群,这一步不需要太注意
  3. 确保每个节点上 MAC 地址和 product_uuid 的唯一性:
ip link 以及 ifconfig -a #可以获取网络接口的MAC地址      
sudo cat /sys/class/dmi/id/product_uuid #可以检查 product_uuid是否唯一
  1. 网络适配器
ip addr show  
ipconfig  
# 默认网络适配器
ip route show
# 默认路由
# 新服务器不太会出现这里的问题,如果有特殊需要可以自行添加路由规则
  1. swap交换分区的配置
# 临时关闭         
sudo swapoff -a      
#查看效果     
free -h  # 如果swap那一行为0了就没问题   
# 永久关闭请编辑/etc/fstab或systemd.swap文件来实现   

安装容器运行时(Container Runtime)

Kubernetes从1.20版本开始声明将停止使用Docker为其容器运行时接口CRI(Container Runtime Interface),并且在1.24版本进一步取消对Docker的支持,如果依旧想用Docker为集群的CRI,必须安装一个额外的服务 cri-dockerd,而你的kubelet版本需要小于1.24来保证运行。

本文使用标准的主流部署方式,所以默认使用containerd作为CRI。
官方文档提供了源文件安装的方式,如果想方便的话apt包管理器也支持直接安装,我这里就用简单的方式安装

# 如果安装过容器运行时可以执行下这几步保证卸载干净,没有则跳过     
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done# 检查旧包,新服务器这一步大概率不需要    
sudo rm -rf /var/lib/docker     
sudo rm -rf /var/lib/containerd     
# 更新apt列表
sudo apt-get update     
sudo apt-get install \     
   ca-certificates \     
   curl \     
   gnupg \     
   lsb-release     
# 添加官方GPG key 
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# 将存储库添加到Apt源:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update  
# 安装
sudo apt-get install -y containerd.io
# 查看运行状态
systemctl enable containerd
systemctl status containerd

在你的 containerd 配置中, 你可以通过设置以下选项重载沙箱镜像:

[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.k8s.io/pause:3.2" 

安装好后,为保证集群运行的健壮性,k8s官方建议使用systemd作为 CgroupDriver 类型(而不是cgroupfs),systemd是Linux内核提供的一个特性,用于限制、记录和隔离进程的资源(如 CPU、内存、磁盘 I/O 等)使用,其系统集成性,一致性都更优秀。

#首先在这个路径下找到相应的toml文件  
cd /etc/containerd/config.toml  
#在文件中设置如下    
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true  
#设置好后重启containerd  
systemctl restart containerd  

这里引用一段kubernetes官方的说明,应对从软件包(例如,RPM 或者 .deb)中安装 containerd,发现其中默认禁止了 CRI 集成插件的问题:

你需要启用 CRI 支持才能在 Kubernetes 集群中使用 containerd。 要确保 cri 没有出现在 /etc/containerd/config.toml 文件中 disabled_plugins 列表内。如果你更改了这个文件,也请记得要重启 containerd。

如果你在初次安装集群后或安装 CNI 后遇到容器崩溃循环,则随软件包提供的 containerd 配置可能包含不兼容的配置参数。考虑按照 getting-started.md 中指定的 containerd config default > /etc/containerd/config.toml 重置 containerd 配置,然后相应地设置上述配置参数。

设置完成后不要忘了重启服务
systemctl restart containerd

安装kubeadm、kubelet 和 kubectl

万事俱备!现在我们可以开始安装kubernetes的核心组件了,k8s官方和三方都提供了许多种部署kubernetes集群的工具,比如kubeadm、k3s、minikube、microk8s等等,大部分发行版或工具旨在轻量化部署的方式和集群的大小,我这里选择标准的kubeadm主要是因为如下原因:

  • 更加深刻的理解kubernetes的服务运行架构
  • 更符合正式工作环境的部署方案
  • kubeadm部署熟悉之后,很方便切换使用其他方式按需部署
    你在这一切开始之前应当熟悉这些概念,但是这里重复一下来明确思考的脉络:kubeadm:用来初始化集群的指令;kubelet:在集群中的每个节点上用来启动 Pod 和容器等;kubectl:用来与集群通信的命令行工具

基于Debian的发行版 :

sudo apt-get update
# apt-transport-https 可能是一个虚拟包(dummy package);如果是的话,你可以跳过安装这个包
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
# 下载用于 Kubernetes 软件包仓库的公共签名密钥。所有仓库都使用相同的签名密钥,因此你可以忽略URL中的版本:
# 如果 `/etc/apt/keyrings` 目录不存在,则应在 curl 命令之前创建它,请阅读下面的注释。
# sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 添加 Kubernetes apt 仓库,此操作会覆盖 /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.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
# 更新 apt 包索引,安装 kubelet、kubeadm 和 kubectl,并锁定其版本:
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

还记得我们前面曾使用systemd作为containerd的CgroupDriver,这里也十分推荐使用systemd作为kubelet组件的驱动,具体需要指定修改KubeletConfiguration文件中的相应字段

不过在版本 1.22 及更高版本中,如果用户没有在 KubeletConfiguration 中设置 cgroupDriver 字段, kubeadm 会将它设置为默认值 systemd

使用Kubeadm创建集群

kubeadm init <args>         

kubernetes官方文档几乎只指定了这条命令,然而<args> 这条参数包含的内容十分复杂,并不是简单默认就可以解决所有场景,我这里用最简单的设置为例,如果想要进一步了解,建议参考官方文档kubeadm init

kubeadm init --pod-network-cidr=10.244.0.0/16       
# --pod-network-cidr 参数用于指定集群中 Pod 网络的 IP 地址范围。该参数的作用是定义 Kubernetes 集群中分配给 Pod 的 IP 地址范围,并且它与所使用的网络插件(如 Flannel)密切相关。10.244.0.0/16为Flannel网络插件默认的配置,如果想使用别的网络插件,建议需要更改参数的具体值
# --kubernetes-version参数可以指定k8s版本,如果不指定,默认为最新的稳定发行版
# --control-plane-endpoint如果你计划后续升级为多节点的高可用集群,记得设置这个参数!!

然而,当我们执行命令之后,却出现了如下报错

root@lrainmaster:~# kubeadm init --pod-network-cidr=10.244.0.0/16
[init] Using Kubernetes version: v1.31.3
[preflight] Running pre-flight checks
error execution phase preflight: [preflight] Some fatal errors occurred:
        [ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with --ignore-preflight-errors=...
To see the stack trace of this error execute with --v=5 or higher

这个报错是指,在 Kubernetes 初始化的前期检查过程中,/proc/sys/net/ipv4/ip_forward 的值没有设置为 1,而这是 Kubernetes 集群正常工作的必要条件之一。
如何解决呢?很简单 :

# 手动设置ip转发  
sysctl -w net.ipv4.ip_forward=1
# 自动设置ip转发
net.ipv4.ip_forward = 1
sysctl -p

再次执行kubeadm init --pod-network-cidr=10.244.0.0/16,命令执行正常,它会开始执行集群初始化的工作,包含以下几个步骤:

  • 配置控制平面组件(API Server、Controller Manager、Scheduler)
  • 设置证书和密钥。
  • 配置网络插件(根据–pod-network-cidr 参数设置)
  • 生成配置文件和 kubeconfig 文件

初始化完成后,控制台会输出一条 kubeadm join 命令,类似于:

kubeadm join <your-control-plane-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>

这条命令用于将工作节点加入集群。你需要将这条命令提供给你集群中其他工作节点,在工作节点上执行该命令来加入集群。

安装网络插件

如果你此时运行kubectl get pod --all-namespaces,你会发现coredns相关的资源并未正确启动,这是因为你必须部署一个基于 Pod 网络插件的容器网络接口(CNI), 以便你的 Pod 可以相互通信。在安装网络之前,集群 DNS (CoreDNS) 将不会启动。

主流的网络插件有很多种,它们之间的能力和使用场景也不尽相同,这里用最简单易懂的Flannel插件为例(这和前面init的–pod-network-cidr=10.244.0.0/16参数相关,如果想用别的插件需要针对性修改参数)

安装命令非常简单:

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

然而启动之后查看flannel相关pod发现并未正确拉起,使用k8s命令查看日志:

kubectl logs -n kube-flannel ${podname}
Defaulted container "kube-flannel" out of: kube-flannel, install-cni-plugin (init), install-cni (init)
I1203 12:50:39.361596       1 main.go:212] CLI flags config: {etcdEndpoints:http://127.0.0.1:4001,http://127.0.0.1:2379 etcdPrefix:/coreos.com/network etcdKeyfile: etcdCertfile: etcdCAFile: etcdUsername: etcdPassword: version:false kubeSubnetMgr:true kubeApiUrl: kubeAnnotationPrefix:flannel.alpha.coreos.com kubeConfigFile: iface:[] ifaceRegex:[] ipMasq:true ifaceCanReach: subnetFile:/run/flannel/subnet.env publicIP: publicIPv6: subnetLeaseRenewMargin:60 healthzIP:0.0.0.0 healthzPort:0 iptablesResyncSeconds:5 iptablesForwardRules:true netConfPath:/etc/kube-flannel/net-conf.json setNodeNetworkUnavailable:true}
W1203 12:50:39.361667       1 client_config.go:618] Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.
I1203 12:50:39.370276       1 kube.go:139] Waiting 10m0s for node controller to sync
I1203 12:50:39.370586       1 kube.go:469] Starting kube subnet manager
I1203 12:50:40.371239       1 kube.go:146] Node controller sync successful
I1203 12:50:40.371263       1 main.go:232] Created subnet manager: Kubernetes Subnet Manager - lrainmaster
I1203 12:50:40.371267       1 main.go:235] Installing signal handlers
I1203 12:50:40.371504       1 main.go:469] Found network config - Backend type: vxlan
E1203 12:50:40.371542       1 main.go:269] Failed to check br_netfilter: stat /proc/sys/net/bridge/bridge-nf-call-iptables: no such file or directory

根据日志内容,Flannel 启动失败的原因是内核模块 br_netfilter 没有正确加载,或者系统没有启用 bridge-nf-call-iptables 设置。这是 Flannel 网络插件启动过程中常见的问题,因为 Flannel 需要通过 br_netfilter 模块来管理跨主机的网络流量。

所以我们需要加载 br_netfilter 模块

# 执行以下命令以加载 br_netfilter 模块:  
modprobe br_netfilter   
# 验证模块是否加载成功: 
lsmod | grep br_netfilter 
# 如果以上命令没有输出,说明模块未加载或内核不支持。 

为了在系统重启后也加载 br_netfilter 模块,可以将其添加到 /etc/modules-load.d/k8s.conf 文件中:

echo "br_netfilter" > /etc/modules-load.d/k8s.conf    
systemctl restart systemd-modules-load.service    
# 启用 bridge-nf-call-iptables 设置  
sysctl -w net.bridge.bridge-nf-call-iptables=1  
sysctl -w net.bridge.bridge-nf-call-ip6tables=1  
# 设置永久生效,编辑 /etc/sysctl.conf 文件  
net.bridge.bridge-nf-call-iptables = 1  
net.bridge.bridge-nf-call-ip6tables = 1  
# 再加载配置   
sysctl -p   

完成上述步骤后,可以删除原有的故障pod,让它重新拉起 :

kubectl delete pod -n kube-flannel -l app=flannel   

最后收尾

我们的kubernetes集群已经基本完全拉起了,这时候如果你满怀信心的取拉起一个简单的nginx服务测试,会发现拉起还是失败,而报错大概率和节点健康度有关

这是因为kubernetes的设计有节点污点概念,pod是不会去往带有污点标签的节点上调度,而默认情况下,master节点是带有污点标签的,因为健康的集群不太建议在重要的主节点调度服务pod。

而我们这里为了学习测试,只有一个节点部署单节点集群,所以我们需要做的就是去除主节点的污点标签:

kubectl taint nodes --all node-role.kubernetes.io/master-

这样,一个可用的单节点集群就创建完毕了 。

如果你将来希望加入新的节点到集群中,需要在待加入节点上执行一边完整的安装kubeadm、kubelet、kubectl组件步骤,并且通过join命令带着token认证加入
由于当前部署单节点集群,--control-plane-endpoint参数在init时并未指定,后续如果需要添加集群,为了稳定性可能需要修改/etc/kubernetes/manifests/kube-apiserver.yaml文件,这里不再再赘述具体细节,感兴趣的朋友可以自行查找资料或者期待后续本人的更多文章
你现在可以启用一个简单的服务,nodeport暴露出来验证集群可用性,也可以测试各种kubectl的命令,学习在于不断地折腾,不要嫌麻烦

后续步骤请移驾系列文章的第二部 :

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐