在当今快速变化的科技景观中,学习Kubernetes(K8s)已经变得至关重要。作为容器编排平台的领军者,K8s为现代应用开发和部署带来了变革性的改进。它不仅简化了复杂的应用程序管理,还提供了强大的自动化和伸缩性能。
今年黑色星期五,购入了一个张CKA的考试券,打算准备在今年的把这个CKA拿下,于是,在自己的本地上搭建学习环境,为了更加贴近考试的环境,特意采用Ubuntu系统重新部署了一个Kubernetes。
环境准备
机器规划
三台机器都是采用Ubuntu最新22.04的版本,内核版本是5.15.0-91-generic
,三台机器具体的分布如下:
角色 |
主机名称 |
IP |
kueernetes版本 |
master |
k8s-master |
192.168.1.17 |
v1.28.2 |
node1 |
k8s-node1 |
192.168.1.18 |
v1.28.2 |
node2 |
k8s-node2 |
192.168.1.19 |
v1.28.2 |
Docker Engine 没有实现 CRI, 而这是容器运行时在 Kubernetes 中工作所需要的。 为此,必须安装一个额外的服务 cri-dockerd。 cri-dockerd 是一个基于传统的内置 Docker 引擎支持的项目, 它在 1.24 版本从 kubelet 中移除。
环境配置
- 确保每个节点上的
MAC
地址和product_uuid
的唯一性。
- 你可以使用命令
ip link
或ifconfig -a
来获取网络接口的 MAC 地址 - 可以使用
sudo cat /sys/class/dmi/id/product_uuid
命令对product_uuid
校验
root@k8s-master:~# ansible k8s -m shell -a 'cat /sys/class/dmi/id/product_uuid' 192.168.1.19 | CHANGED | rc=0 >> 438473e8-8505-496b-940f-d82d00ce0622 192.168.1.18 | CHANGED | rc=0 >> 9ccfa185-bd89-40b8-9c6a-b62fb469bd46 192.168.1.17 | CHANGED | rc=0 >> 16142df0-765e-4b36-9c4e-81c299332d42 root@k8s-master:~#
一般来讲,硬件设备会拥有唯一的地址,但是有些虚拟机的地址可能会重复。 Kubernetes 使用这些值来唯一确定集群中的节点。 如果这些值在每个节点上不唯一,可能会导致安装失败。
设置主机名
根据机器的规划,分布设置三台主机名为k8s-master、k8s-node1和k8s-node2,目的是为了方便识别。
#修改配置文件方式 root@k8s-master:~# cat /etc/hostname k8s-master root@k8s-node1:~# cat /etc/hostname k8s-node1 root@k8s-node2:~# cat /etc/hostname k8s-node2 #命令行方式,临时修改 # 设置 master 主机名 hostnamectl set-hostname k8s-master && bash # 设置 worker 主机名 hostnamectl set-hostname k8s-node1 && bash hostnamectl set-hostname k8s-node2 && bash
修改国内镜像源地址
先把Ubuntu系统的软件源修改成国内的镜像源,我这里以修改为华为的镜像源为例。
- 备份配置文件
sudo cp -a /etc/apt/sources.list /etc/apt/sources.list.bak
- 修改sources.list文件,将http://archive.ubuntu.com和http://security.ubuntu.com替换成http://repo.huaweicloud.com,可以参考如下命令:
sudo sed -i "s@http://.*archive.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list sudo sed -i "s@http://.*security.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list
配置时间同步
安装完Ubuntu系统时,系统的时区是有问题的,我们需要对系统的时区进行修改。可以常用timedatectl
进行临时修改,但是,系统重启后会失效。修改配置文件。关键配置如下:
timedatectl set-time Asia/Shanghai #临时改变,重启失效 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime #修改配置文件,重启不失效
采用ntpdate
命令进行时间校对,最小化安装,系统没有安装这个命令,需要自行安装,执行如下命令
sudo apt install ntpdate
安装好ntpdate软件后,执行如下命令进行时间校对:
ntpdate time1.aliyun.com
并且,通过计划任何实现时间同步。如下命令是每个一个小时向阿里云时间服务器进行校对时间。
0 */1 * * * ntpdate time1.aliyun.com
配置内核转发及网桥过滤
- 添加配置文件
cat << EOF | tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF
- 加载模块
modprobe overlay modprobe br_netfilter
- 添加网桥过滤及内核转发配置文件
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
- 安装Ipset及ipvsadm
sudo apt -y install ipset ipvsadm
- 配置ipvsadm模块,添加需要添加的模块
cat << EOF | tee /etc/modules-load.d/ipvs.conf ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack EOF
- 编写脚本,加载模块
cat << EOF | tee ipvs.sh modprobe -- ip_vs modprobe -- ip_vs_rr modprobe -- ip_vs_wrr modprobe -- ip_vs_sh modprobe -- nf_conntrack EOF ./ipvs.sh
关闭swap分区
swapoff -a #临时关闭
容器运行时准备
获取二进制安装文件
本案例中采用二进制方式安装Containerd。通过github获取Containerd的二进制版本。如下图:
https://github.com/containerd/containerd
安装配置Containerd
通过下面的命令进行解压
tar -xf cri-containerd-1.7.12-linux-amd64.tar.gz -C /
-C:是指定解压的目录,通过-C /
参数,会把 Containerd的文件解压到对于的文件夹中。
通过以命令生成Containerd的配置文件,生成配置文件之前需要新建目录。关键命令如下:
mkdir /etc/containerd containerd config default > /etc/containerd/config.toml
修改 /etc/containerd/config.toml
- 第65行
sanbox_image
的内容,从原来的registry.k8s.io/pause:3.8
修改成registry.aliyuncs.com/google_containers/pause:3.9
- 第137行
SystemdCgroup
的内容,从原来的false
改成true
。
Containerd配置镜像加速
修改Config.toml文件。如下:
[plugins."io.containerd.grpc.v1.cri".registry] config_path = "/etc/containerd/certs.d" # 镜像地址配置文件 [plugins."io.containerd.grpc.v1.cri".registry.auths] [plugins."io.containerd.grpc.v1.cri".registry.configs] [plugins."io.containerd.grpc.v1.cri".registry.headers] [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
- 创建相应的目录
mkdir /etc/containerd/certs.d/docker.io -pv
- 配置加速
cat > /etc/containerd/certs.d/docker.io/hosts.toml << EOF server = "https://docker.io" [host."https://x46sxvnb.mirror.aliyuncs.com"] capabilities = ["pull", "resolve"] EOF
启动并设置开机启动
systemctl enable --now containerd #验证版本信息 containerd --veriosn
K8S集群部署
K8S集群软件apt源准备
使用阿里云镜像源,执行如下命令:
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF
添加完源件源后,执行下面命令进行更新源:
apt-get update
执行完后可能会报如下错误,原因是因为公钥的问题。
解决方法请参考这篇文章
K8S集群软件的安装
通过以下命令查看可以安装的软件列表,查询到最新版本是1.28.2的版本。
apt-cache madison kubeadm
安装指定的版本,本案例以安装最新版本是1.28.2为例。执行如下命令进行安装:
apt-get install -y kubelet=1.28.2-00 kubeadm=1.28.2-00 kubectl=1.28.2-00
节点上可以不用安装kubectl
启动kueblet,并设置开机自启动。
systemctl enable --now kubelet
防止k8s软件自动升级,通过以下命令进行锁定定版本
apt-mark hold kubelet kubeadm kubectl
K8S集群初始化
通过如下命令生成一个默认的配置文件:
kubeadm config print init-defaults > /home/k8s/init/kubeadm-init.yaml
执行完上述的命令会在对应的目录下生成一个kubeadm-init.yaml
文件,需要对这个文件的一些参数进行修改。
apiVersion: kubeadm.k8s.io/v1beta3 bootstrapTokens: - groups: - system:bootstrappers:kubeadm:default-node-token token: abcdef.0123456789abcdef ttl: 24h0m0s usages: - signing - authentication kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.17 #修改了master IP地址 bindPort: 6443 nodeRegistration: criSocket: unix:///var/run/containerd/containerd.sock imagePullPolicy: IfNotPresent name: k8s-master #修改了master节点主机名称 taints: null --- apiServer: timeoutForControlPlane: 4m0s apiVersion: kubeadm.k8s.io/v1beta3 certificatesDir: /etc/kubernetes/pki clusterName: kubernetes controllerManager: {} dns: {} etcd: local: dataDir: /var/lib/etcd imageRepository: registry.aliyuncs.com/google_containers #修改了镜像源 kind: ClusterConfiguration kubernetesVersion: 1.28.2 #修改了版本信息 networking: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 #添加了Pod网段信息 serviceSubnet: 10.96.0.0/12 scheduler: {}
可以通过以下命令列举出需要拉取的镜像。
kubeadm config images list --config /home/k8s/init/kubeadm-init.yaml
可以提前把需求的镜像拉取下来,通过下面命令进行拉取:
kubeadm config images list --config /home/k8s/init/kubeadm-init.yaml
拉取成功之后,通过下面的命令进行k8s集群的初始化。
kubeadm init --config=/home/k8s/init/kubeadm-init.yaml --v=6
出现以下信息,代表K8S初始成功了。
按照上述的提示,进行如下的操作:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
执行上述的命令,就可以通过kubectl进行查看k8s集群的状态信息。如下图:
节点加入到集群中
在节点上通过如下命令,获取加入集群的token值。
kubeadm token create --print-join-command
执行成功后,会出现如下信息,复制如下信息在需求加入集群的node节点上执行。
如果执行完命令后,出现如下信息,表示已经加入成功。
也可以通过在master节点上执行如下命令查看是否加入成功。
root@k8s-master:~# kubectl get node NAME STATUS ROLES AGE VERSION k8s-master NotReady control-plane 50m v1.28.2 k8s-node1 NotReady <none> 2m16s v1.28.2 k8s-node2 NotReady <none> 2m16s v1.28.2
由于还没安装网络插件的原因,所以,节点显示NotReady状态。
K8S集群网络插件Calico部署
在安装到calico网络组件的时候或多或少都会因为国内外网络的问题一直卡在pull镜像的阶段无法完成安装,本案例通过离线方式安装Calico网络插件。
在线安装
如果能科学上网的可以考虑在线安装,详细安装步骤可以查阅官方文档,找到Quickstart for Calico on Kubernetes
中的Install Calico
,如下图
离线安装
下载calico离线包
首先去github全局搜索calico,点击进入项目,在Releases下下载自己需要的calico版本的离线包(本案例3.27版本为例)。项目下载地址如下:
https://github.com/projectcalico/calico
解压calico离线包并将所需文件上传至服务器
把下载的文件上传服务器并进行解压,如下:
root@k8s-master:~# tar -zxf release-v3.27.0.tgz root@k8s-master:~/release-v3.27.0# ls bin images manifests
然后,进入到manifests
文件夹,查看calico.yml
文件,查看需要的镜像内容,如下:
root@k8s-master:~/release-v3.27.0/manifests# cat calico.yaml |grep image: image: docker.io/calico/cni:v3.27.0 image: docker.io/calico/cni:v3.27.0 image: docker.io/calico/node:v3.27.0 image: docker.io/calico/node:v3.27.0 image: docker.io/calico/kube-controllers:v3.27.0
这里显示安装calico需要三个镜像,去解压的离线包imgaes文件夹中找到对应的三个离线镜像包文件,这里对应的分别是calico-cni.tar,calico-kube-controllers.tar和calico-node.tar三个离线包,将这三个离线镜像上传至服务器。
离线镜像导入containerd的k8s命名空间中
可以使用 ctr namespace ls
命令查看containerd
的命名空间。k8s的命名空间为k8s.io
root@k8s-master:~/release-v3.27.0/manifests# ctr namespace ls NAME LABELS k8s.io
使用containerd的导入镜像命令将calico的离线镜像包导入到k8s的命名空间中
root@k8s-master:~/release-v3.27.0/images# ls calico-cni.tar calico-dikastes.tar calico-flannel-migration-controller.tar calico-kube-controllers.tar calico-node.tar calico-pod2daemon.tar calico-typha.tar root@k8s-master:~/release-v3.27.0/images# root@k8s-master:~/release-v3.27.0/images#ctr -n k8s.io images import calico-cni.tar root@k8s-master:~/release-v3.27.0/images#ctr -n k8s.io images import calico-kube-controllers.tar root@k8s-master:~/release-v3.27.0/images#ctr -n k8s.io images import calico-node.tar
安装calico
进入到manifests/
文件夹中,执行如下命令,安装calico
kubectl create -f calico.yml
执行完上述的命令后,即可完成calico的部署。如下:
root@k8s-master:~# kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-5fc7d6cf67-9vnct 1/1 Running 0 81m kube-system calico-node-hzfvr 1/1 Running 0 81m kube-system calico-node-jbdkk 1/1 Running 0 81m kube-system coredns-66f779496c-gqgb9 1/1 Running 0 24h kube-system coredns-66f779496c-p2f5g 1/1 Running 0 24h kube-system etcd-k8s-master 1/1 Running 0 24h kube-system kube-apiserver-k8s-master 1/1 Running 0 24h kube-system kube-controller-manager-k8s-master 1/1 Running 0 24h kube-system kube-proxy-44n5b 1/1 Running 0 24h kube-system kube-proxy-vf5b4 1/1 Running 0 23h kube-system kube-scheduler-k8s-master 1/1 Running 0 24h
部署应用级访问
通过上述的步骤已经完成了K8S集群的部署,下面以部署一个Nginx应用为例,简单讲解一个K8S部署应用方法。K8s部署方式分为两种一个可以直接命令行的方式,另外一个是写资源清单的方式。
下面是一个部署Nginx的资源清单案例:
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本 kind: Deployment #该配置的类型,我们使用的是 Deployment metadata: #译名为元数据,即 Deployment 的一些基本属性和信息 name: nginx-deployment #Deployment 的名称 labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解 app: nginx #为该Deployment设置key为app,value为nginx的标签 spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用 replicas: 1 #使用该Deployment创建一个应用程序实例 selector: #标签选择器,与上面的标签共同作用,目前不需要理解 matchLabels: #选择包含标签app:nginx的资源 app: nginx template: #这是选择或创建的Pod的模板 metadata: #Pod的元数据 labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod app: nginx spec: #期望Pod实现的功能(即在pod中部署) containers: #生成container,与docker中的container是同一种 - name: nginx #container的名称 image: nginx:1.7.9 #使用镜像nginx:1.7.9创建container,该container默认80端口可访问 --- apiVersion: v1 kind: Service metadata: name: nginx-service #Service 的名称 labels: #Service 自己的标签 app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签 spec: #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问 selector: #标签选择器 app: nginx #选择包含标签 app:nginx 的 Pod ports: - name: nginx-port #端口的名字 protocol: TCP #协议类型 TCP/UDP port: 80 #集群内的其他容器组可通过 80 端口访问 Service nodePort: 32600 #通过任意节点的 32600 端口访问 Service targetPort: 80 #将请求转发到匹配 Pod 的 80 端口 type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
上述的资源清单创建了两种类型一个Deployment
,一个Service
。通过下面的命令执行部署。
kubectl apply -f nginx.yaml
执行成功后,如下图:
然后,通过curl命令进行访问,或者任意node节点IP+32600的方式进行访问。