近期事情比较多,所以停更了半个月,非常抱歉,这半个月也在梳理一下自己的知识体系,寻找明年的一些规划。
今天还是继续《Kubernetes实践》,为了方便我和大家对一些知识点的理解,后续还是会在文章开始提出一些问题,然后在文章后面进行解答。
问题
(1)Kubernetes Replica Set 和 Replication Controller 之间有什么区别?
(2)kube-proxy iptables 原理是什么?
(3)Kubernetes 创建一个 Pod 的主要流程?
第一部分:安装
1、前提
(1)安装k8s要求
Master节点CPU和内存最低配置2C4G,Node节点建议4C16G。
(2)关闭防火墙:
systemctl disable firewalld
systemctl stop firewalld
为什么?防火墙是用于保护网络安全的重要组件,但在Kubernetes集群中,可能会干扰集群内部的网络通信,k8s集群内部有许多组件需要相互通信,例如节点之间的Pod通信、Master节点与Worker节点之间的通信等,如果防火墙设置不当,会阻止这些必要的通信,导致集群部署失败或者网络问题,关闭防火墙可以确保k8s集群内部的正常通信,同时需要在K8s的网络配置中设置适当的安全规则。
(3)禁用SELinux
setenforce 0
为什么?SELinux是Linux内核的安全模块,用于强化系统的安全性。然而,在Kubernetes环境中,SELinux可能干扰容器与宿主机之间的交互,导致意外的权限问题,K8s使用一种名为"Container Runtime"的组件来运行容器,而SELinux的策略可能会限制容器的正常操作,关闭SELinux可以减少由于安全策略冲突引起的问题,同时K8s本身已经提供了适当的隔离和安全机制。
(4)关闭Swap
swapon -s
swapoff -a
为什么?Swap是一种虚拟内存,当物理内存不足时,操作系统将数据转移到磁盘上,在Kubernetes集群中,应用程序的性能和稳定性对内存的需求很高,k8s的各个组件和容器都需要足够的内存来运行,而Swap的使用可能导致性能下降,关闭Swap可以确保集群的可预测性和稳定性,避免不必要的磁盘交换,具体可以参考(github.com/kubernetes/…
2、kubeadm
2.1 安装kubeadm
为什么要使用kubeadm?由于k8s安装其实非常繁琐,而且会有各种问题,直到2017年,在志愿者的推动下,社区才终于发起了一个独立的部署工具kubeadm,简化很多部署操作。
安装kubeadm命令(当前都在Centos下执行,如果是Ubuntu可以体寒一下安装命令):
yum install kubeadm
kubeadm init --image-repository registry.aliyuncs.com/google_containers # 启动master节点(使用国内镜像源)
输出:
[init] Using Kubernetes version: v1.28.4
[preflight] Running pre-flight checks
[WARNING FileExisting-tc]: tc not found in system path
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
...
2.2 kubeadm init流程
(1)在执行init后,会打印如下:
[root@VM-16-16-centos ~]# kubeadm init
[init] Using Kubernetes version: v1.28.4
[preflight] Running pre-flight checks
[WARNING FileExisting-tc]: tc not found in system path
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
这些就是Preflight Checks操作,实际kubeadm会做很多检查,比如:
Linux 内核的版本必须是否是 3.10 以上?
Linux Cgroups 模块是否可用?
机器的 hostname 是否标准?在 Kubernetes 项目里,机器的名字以及一切存储在 Etcd
中的 API 对象,都必须使用标准的 DNS 命名(RFC 1123)。
用户安装的 kubeadm 和 kubelet 的版本是否匹配?
机器上是不是已经安装了 Kubernetes 的二进制文件?
Kubernetes 的工作端口 10250/10251/10252 端口是不是已经被占用?
ip、mount 等 Linux 指令是否存在?
Docker 是否已经安装?
...
(2)执行完检查就是生成证书,可以查看/etc/kubernetes/pki
,同时kubeadm会为其他组件生成访问kube-apiserver
所需的配置文件,这些文件的路径是:/etc/kubernetes/xxx.conf。
(3)接下来kubeadm
会为Master
组件生成Pod
配置文件,包括Master组件的kube-apiserver、kube-controller-manager、kube-scheduler,它们都是被使用 Pod 的方式部署起来。
注意:k8s尚未启动,为什么能直接部署Pod呢?
在Kubernetes中,有一种特殊的容器启动方法叫做"Static Pod",它允许你把要部署的Pod的YAML文件放在一个指定的目录里,当这台机器上的kubelet启动时,它会 自动检查这个目录,加载所有的Pod YAML文件,然后在这台机器上启动它们,从这一点也可以看出,kubelet在Kubernetes项目中的地位非常高,在设计上它就是一个 完全独立的组件,而其他Master组件,则更像是辅助性的系统容器,在kubeadm中,Master组件的YAML文件会被生成在/etc/kubernetes/manifests路径下,具体的kubeadm的启动日志会打印这一条日志:
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[kubelet-check] Initial timeout of 40s passed.
(4)最后kubeadm还会生成一个Etcd的Pod YAML文件,用来通过同样的Static Pod的方式启动Etcd:
ls /etc/kubernetes/manifests/
etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
Master容器启动后,kubeadm会通过检查localhost:6443/healthz这个Master组件的健康检查URL,等待Master组件完全运行起来。
2.3 注意事项
(1)报错:[WARNING Service-Kubelet]: kubelet service is not enabled, please run 'systemctl enable kubelet.service',执行systemctl enable kubelet.service
。
(2)报错:[ERROR CRI]: container runtime is not running: output: E1125 11:02:07.582454 4004763 remote_runtime.go:616],容器没有起来,执行systemctl enable docker && systemctl start docker
。
(3)报错:validate service connection: CRI v1 runtime API is not implemented for endpoint,参考 blog.51cto.com/u_1264026/7… 这篇文章。
(4)如果kubeadm init
执行后,一直超时等待,可以检查一下是否镜像有问题,比如报错:kubeadm init:failed to pull image registry.k8s.io/pause:3.6
,可以尝试修改pause镜像地址,操作如下:
# 生成 containerd 的默认配置文件
containerd config default > /etc/containerd/config.toml
# 查看 sandbox 的默认镜像仓库在文件中的第几行
cat /etc/containerd/config.toml | grep -n "sandbox_image"
# 使用 vim 编辑器 定位到 sandbox_image,将 仓库地址修改成 k8simage/pause:3.6
vim /etc/containerd/config.toml
sandbox_image = " registry.aliyuncs.com/google_containers/pause:3.6"
# 重启 containerd 服务
systemctl daemon-reload
systemctl restart containerd.service
3、Node节点
kubeadm init
生成 bootstrap token
之后,就可以在任意一台安装完成 kubelet
和 kubeadm
的机器上执行 kubeadm join
,执行指令如下:
kubeadm join 172.27.0.11:6443 --token 生成的token --discovery-token-ca-cert-hash sha256:af3b235abdb899c07dc1487e94a36e57274e6425dc92f9a547367e110ce2682b
执行完成以后,可以在master节点上执行 kubectl get node
查看节点是否正常。
3.1 注意
(1)如果节点一直处于 NotReady
状态,如何处理?
通过 kubectl describe node 节点NAME
查看详情信息,然后查看日志,比如 Network plugin returns error: cni plugin not initialized
,这个时候就需要初始化网络插件,详细可以查看「网络配置」。
3.2 查看节点信息
执行 kubectl get nodes
,输出如下:
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 80m v1.28.2
k8s-node-1 Ready <none> 38m v1.28.2
4、安全设置
4.1 鉴权方式
Kubernetes 有以下几种鉴权方法:
- CA证书
- 不记名令牌
- 身份认证代理
- 通过鉴权插件的 HTTP 基本认证机制
具体证书列表可以查看 /etc/kubernetes/pki/ca.{crt,key}
,如下图。
CA证书
4.2 鉴权流程
(1)登录到身份服务(Identity Provider) (2)身份服务将为你提供 access_token、id_token 和 refresh_token (3)在使用 kubectl 时,将 id_token 设置为 --token 标志值,或者将其直接添加到 kubeconfig 中 (4)kubectl 将你的 id_token 放到一个称作 Authorization 的头部,发送给 API 服务器 (5)API 服务器将负责通过检查配置中引用的证书来确认 JWT 的签名是合法的 (6)检查确认 id_token 尚未过期 (7)确认用户有权限执行操作 (8)鉴权成功之后,API 服务器向 kubectl 返回响应 (9)kubectl 向用户提供反馈信息
5、网络配置
《云原生二十篇|Kubernetes核心原理》这篇文章中已经讲过关于网络插件的部分,同时在我安装过程中也出现了一些网络插件未初始化的问题,如何解决?(下面以安装flannel为例)
# 提前下载好镜像
docker pull quay.io/coreos/flannel:v0.14.0
# 执行
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
然后执行:kubectl get pods --all-namespaces
,查看:
[root@k8s-master ~]# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-flannel kube-flannel-ds-c5bzj 0/1 Init:0/2 0 19m
kube-flannel kube-flannel-ds-mp9pw 0/1 CrashLoopBackOff 8 (57s ago) 19m
发现flannel不能启动,这个时候可以使用 kubectl logs kube-flannel-ds-mp9pw -n kube-flannel
命令查看日志:
...
E1125 12:09:28.197917 1 main.go:335] Error registering network: failed to acquire lease: node "k8s-master" pod cidr not assigned
W1125 12:09:28.198004 1 reflector.go:347] github.com/flannel-io/flannel/pkg/subnet/kube/kube.go:491: watch of *v1.Node ended with: an error on the server ("unable to decode an event from the watch stream: context canceled") has prevented the request from succeeding
...
原来是安装kubeadm init
的时候,没有增加--pod-network-cidr
参数,重新设置以后正常。
第二部分:kubectl
上面说完用kubeadm安装k8s整个流程,其中k8s的cli kubectl
是我们查看集群信息的重要工具,其中用法如下:
kubectl [command] [TYPE] [NAME] [flags]
- command:具体的执行命令,如create,delete,describe,get,apply等
- TYPE:资源类型,包括pod,node,svc等
- NAME:资源对象名称
- flags:一些可选参数
1、基础操作
以下是常用一些k8s操作。
1.1 创建资源
创建service和rc:
kubectl create -f xxx-service.yaml -f xxx-rc.yaml
根据目录执行创建操作:
kubectl create -f <文件夹>
1.2 查看资源
查看所有pod:
kubectl get pods
查看rc和service列表:
kubectl get rc,service
1.3 描述资源
查看node详细信息:
kubectl describe nodes <node name>
显示pod的详细信息:
kubectl describe pods/<pod name>
1.4 删除资源
对yaml文件的pod进行删除:
kubectl delete -f <pod name>.yaml
删除所有包含某个label的pod和service:
kubectl delete pods,services -l name=<label-name>
删除所有的pod:
kubectl delete pods --all
1.5 执行容器命令
登陆某个pod:
kubectl exec -ti <pod name> -c <container name> /bin/bash
执行某个pod的echo命令:
kubectl exec <pod name> echo "test"
1.6 查看容器日志
查看容器的日志信息:
kubectl logs <pod name>
跟踪某个容器的日志,类似 tail -f
:
kubectl logs -f <pod name> -c <container name>
2、Pod
2.1 Pod格式
一个通用的Pod如下:
apiVersion: v1
kind: Pod
metadata:
labels:
run: xxx
name: xxx
spec:
containers:
- image: xxx
imagePullPolicy: IfNotPresent
name: xxx
resources: {}
ports:
- name: web
containerPort: 80
protocol: TCP
- image: xxx2
imagePullPolicy: Always
name: xxx2
resources: {}
initContainers:
... # 添加init container
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
imagePullPolicy有三个取值:
- Always:每次都下载最新镜像
- Never:不会尝试获取镜像,如果镜像已经以某种方式存在本地,kubelet 会尝试启动容器;否则,会启动失败
- IfNotPresent:只有当镜像在本地不存在时才会拉取
restartPolicy有三个取值:
- Always:总是重启
- OnFailure:失败了才重启
- Never:从不重启
2.2 ConfigMap管理
ConfigMap在k8s中通常用来管理pod的配置,其用法:
- pod执行的环境变量
- 设置容器启动命令的参数
- 以Volume形式挂载为容器的内部文件或者目录
具体命令可以通过编辑key-value结构来创建:
# 准备env-vars.env环境变量文件:
cat env-vars.env
MY_K8S_MASTER_IP=xxxx
MY_K8S_MASTER_HOSTNAME=k8s-b-master
# 从名为 env-vars.env 的环境变量文件中创建名为 my-cf 的 ConfigMap。
kubectl create cm my-cf --from-env-file=env-vars.env
configmap/my-cf created
2.3 Pod的生命周期
Pod的生命周期存在各种状态,如下:
- Pending:API Server已经创建Pod,但是Pod内还有一个或者多个容器的镜像没有创建
- Running:Pod内所有容器均已经创建成功,至少一个容器正在运行状态
- Succeeded:Pod内所有的容器均执行退出,且不会重启
- Failed:Pod内所有的容器均退出,至少一个容器退出为失败状态
- Unknown:由于某种原因无法获得Pod的状态,可能由于网络原因
2.4 其他
包括一些RC,批处理JOB,DaemonSet,滚动升级和回滚等由于篇幅原因就不介绍了,有兴趣的可以通过AI工具自动生成yaml文件,这里有个工具(github.com/sozercan/ku…
AI工具
问题解答
(1)Kubernetes Replica Set 和 Replication Controller 之间有什么区别?
Replica Set
和 Replication Controller
功能类似,都是在任何给定时间运行指定数量的 Pod 副本,不同之处在于 RS
使用基于集合的选择器,而 Replication Controller
使用基于权限的选择器。
(2)kube-proxy iptables 原理是什么?
iptables
核心功能:通过 API Server
的 Watch
接口实时跟踪 Service
与 Endpoint
的变更信息,并更新对应的 iptables
规则,Client的请求流量则通过 iptables
的 NAT
机制 "直接路由" 到目标Pod。
(3)Kubernetes 创建一个 Pod 的主要流程?
- kubectl提交 Pod 的配置信息(yaml 文件定义的信息)到 kube-apiserver;
- API server 收到指令后,通知给 controller-manager 创建一个资源对象;
- controller-manager 通过 api-server 将 pod 的配置信息存储到 ETCD 中;
- kube-scheduler 检测到 pod 信息会开始调度预选,会先过滤掉不符合 Pod 资源配置要求的节点,然后开始调度调优,主要是挑选出更适合运行 pod 的节点,然后将 pod 的资源配置单发送到 node 节点上的 kubelet 组件;
- kubelet 根据 scheduler 发来的资源配置信息运行 pod,运行成功后,将 pod 的运行信息返回给 scheduler,scheduler 将返回的 pod 运行状况的信息存储到 etcd 数据中心;