云原生二十篇|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 数据中心;
相关推荐
Chancezhou15 分钟前
【微服务】不同微服务之间用户信息的获取和传递方案
微服务·云原生
Lyqfor3 小时前
985研一学习日记 - 2024.11.9
java·数据结构·学习·docker·云原生·容器
lldhsds3 小时前
云原生安全解决方案NeuVector 5.X部署实践
安全·云原生
二进制杯莫停9 小时前
PaaS云原生:分布式集群中如何构建自动化压测工具
分布式·云原生·paas
心勤则明21 小时前
SpringCloudAlibabaSidecar整合异构微服务
微服务·云原生·架构
小聪不吃葱1 天前
面试总结!
云原生·容器·kubernetes
A ?Charis1 天前
Terraform-阿里云- ECS实验
阿里云·云原生·terraform
GJCTYU1 天前
阿里云多端低代码开发平台魔笔使用测评
低代码·阿里云·云原生·容器·serverless·云计算
YCyjs2 天前
K8S群集调度二
云原生·容器·kubernetes