云原生二十篇|Kubernetes实践

近期事情比较多,所以停更了半个月,非常抱歉,这半个月也在梳理一下自己的知识体系,寻找明年的一些规划。

今天还是继续《Kubernetes实践》,为了方便我和大家对一些知识点的理解,后续还是会在文章开始提出一些问题,然后在文章后面进行解答。

问题

(1)Kubernetes Replica Set 和 Replication Controller 之间有什么区别?

(2)kube-proxy iptables 原理是什么?

(3)Kubernetes 创建一个 Pod 的主要流程?

第一部分:安装

1、前提

(1)安装k8s要求

Master节点CPU和内存最低配置2C4G,Node节点建议4C16G。

(2)关闭防火墙:

arduino 复制代码
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

css 复制代码
swapon -s
swapoff -a

为什么?Swap是一种虚拟内存,当物理内存不足时,操作系统将数据转移到磁盘上,在Kubernetes集群中,应用程序的性能和稳定性对内存的需求很高,k8s的各个组件和容器都需要足够的内存来运行,而Swap的使用可能导致性能下降,关闭Swap可以确保集群的可预测性和稳定性,避免不必要的磁盘交换,具体可以参考(github.com/kubernetes/...

2、kubeadm

2.1 安装kubeadm

为什么要使用kubeadm?由于k8s安装其实非常繁琐,而且会有各种问题,直到2017年,在志愿者的推动下,社区才终于发起了一个独立的部署工具kubeadm,简化很多部署操作。

安装kubeadm命令(当前都在Centos下执行,如果是Ubuntu可以体寒一下安装命令):

bash 复制代码
yum install kubeadm
kubeadm init --image-repository registry.aliyuncs.com/google_containers # 启动master节点(使用国内镜像源)

输出:

csharp 复制代码
[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后,会打印如下:

csharp 复制代码
[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会做很多检查,比如:

yaml 复制代码
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的启动日志会打印这一条日志:

vbnet 复制代码
[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:

bash 复制代码
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镜像地址,操作如下:

bash 复制代码
# 生成 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 之后,就可以在任意一台安装完成 kubeletkubeadm 的机器上执行 kubeadm join,执行指令如下:

sql 复制代码
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,输出如下:

css 复制代码
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为例)

bash 复制代码
# 提前下载好镜像
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,查看:

sql 复制代码
[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 命令查看日志:

vbscript 复制代码
...
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 是我们查看集群信息的重要工具,其中用法如下:

css 复制代码
kubectl [command] [TYPE] [NAME] [flags]
  • command:具体的执行命令,如create,delete,describe,get,apply等
  • TYPE:资源类型,包括pod,node,svc等
  • NAME:资源对象名称
  • flags:一些可选参数

1、基础操作

以下是常用一些k8s操作。

1.1 创建资源

创建service和rc:

lua 复制代码
kubectl create -f xxx-service.yaml -f xxx-rc.yaml

根据目录执行创建操作:

lua 复制代码
kubectl create -f <文件夹>

1.2 查看资源

查看所有pod:

arduino 复制代码
kubectl get pods

查看rc和service列表:

arduino 复制代码
kubectl get rc,service

1.3 描述资源

查看node详细信息:

sql 复制代码
kubectl describe nodes <node name>

显示pod的详细信息:

javascript 复制代码
kubectl describe pods/<pod name>

1.4 删除资源

对yaml文件的pod进行删除:

arduino 复制代码
kubectl delete -f <pod name>.yaml

删除所有包含某个label的pod和service:

ini 复制代码
kubectl delete pods,services -l name=<label-name>

删除所有的pod:

sql 复制代码
kubectl delete pods --all

1.5 执行容器命令

登陆某个pod:

bash 复制代码
kubectl exec -ti <pod name> -c <container name> /bin/bash

执行某个pod的echo命令:

bash 复制代码
kubectl exec <pod name> echo "test"

1.6 查看容器日志

查看容器的日志信息:

xml 复制代码
kubectl logs <pod name>

跟踪某个容器的日志,类似 tail -f :

xml 复制代码
kubectl logs -f <pod name> -c <container name>

2、Pod

2.1 Pod格式

一个通用的Pod如下:

yaml 复制代码
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结构来创建:

ini 复制代码
# 准备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 SetReplication Controller 功能类似,都是在任何给定时间运行指定数量的 Pod 副本,不同之处在于 RS 使用基于集合的选择器,而 Replication Controller 使用基于权限的选择器。

(2)kube-proxy iptables 原理是什么?

iptables 核心功能:通过 API ServerWatch 接口实时跟踪 ServiceEndpoint 的变更信息,并更新对应的 iptables 规则,Client的请求流量则通过 iptablesNAT 机制 "直接路由" 到目标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 数据中心;
相关推荐
RedCong3 小时前
如何在k8s中对接s3存储
云原生·容器·kubernetes
扣脚大汉在网络6 小时前
云原生安全渗透篇
安全·云原生·dubbo
csdn_aspnet7 小时前
使用 .NET 9 和 Azure 构建云原生应用程序:有什么新功能?
microsoft·云原生·azure
字节源流8 小时前
【spring cloud Netflix】Eureka注册中心
云原生·eureka
基哥的奋斗历程10 小时前
kubernetes configMap 存储
云原生·容器·kubernetes
阿里云云原生1 天前
LLM 不断提升智能下限,MCP 不断提升创意上限
云原生
阿里云云原生1 天前
GraalVM 24 正式发布阿里巴巴贡献重要特性 —— 支持 Java Agent 插桩
云原生
云上艺旅1 天前
K8S学习之基础七十四:部署在线书店bookinfo
学习·云原生·容器·kubernetes
云上艺旅2 天前
K8S学习之基础六十八:Rancher创建deployments资源
学习·云原生·容器·kubernetes·rancher