扣丁狼k8s(一)
# 一. k8s整体架构
# 1. kubectl
kubectl是与Kubernetes集群进行交互的主要方式之一,它允许用户通过命令行界面执行各种操作,如创建、删除和管理容器、Pod、服务、部署等。
kubectl主要与Kubernetes中的kube-apiserver
组件进行交互。kube-apiserver
是Kubernetes的控制平面组件之一,它充当了Kubernetes API 的前端,处理所有对Kubernetes集群的API请求。
当您在kubectl中运行命令时,例如创建、更新、删除资源或者获取集群状态,kubectl会将请求发送到kube-apiserver
。kube-apiserver
负责验证请求、执行相应的操作,并返回结果给kubectl。这种方式使得kubectl可以通过统一的命令行界面与整个Kubernetes集群进行交互。
除了与kube-apiserver
进行交互之外,kubectl还可能与其他组件进行通信,如kube-controller-manager
、kube-scheduler
、kubelet
等,但这些组件通常是在集群内部自动进行通信和协调的,而不是直接通过kubectl进行操作的。
# 2. Kubernetes Dashboard
Kubernetes Dashboard是一个用于可视化和管理Kubernetes集群的Web用户界面。它提供了一个用户友好的界面,通过它,用户可以查看集群中的各种资源、进行部署、监视应用程序状态、调试问题以及执行其他与集群相关的任务,而无需使用命令行工具
当用户在dashboard上面进行操作时,会将相关的指令交给kube-apiServer,在由apiServer进行其他操作的传输。
# 3. Master节点
k8s master节点【控制面板】
# Api-server
# kube-Controller-manager
管理各个类型的控制器,针对k8s中的各种资源进行管理
# cloud-controller-manager
云控制器管理器,第三方云平台提供的控制器api对接管理控制【第三方云平台】
# kube-schedule
调度器 负责将pod基于一定的算法,将其调用到更合适的节点(服务器)上。举例:我现在有一个mysql的容器,而mysql需要存储能力比较强的机器,schedule就来决定这个mysql容器会分配到哪个服务器上。
# etcd
k8s自己的数据库kv,分布式数据库。提供基于raft算法实现自主的集群高可用。【老版本:基于内存;新版本:持久化存储】
# 4. node节点
# kubelet
kubelet是Kubernetes集群中的一个关键组件,它运行在每个节点上,负责管理该节点上的容器和Pod。kubelet确保在节点上创建、启动、停止和监视Pod,以及与控制平面组件交互以维持所需的状态。负责Pod的声明周期和存储管理、网络
# kube-proxy
kube-proxy
是Kubernetes集群中的一个网络代理组件,它运行在每个节点上,负责处理网络流量的路由和负载均衡。kube-proxy
的主要作用是维护节点上的网络规则,以确保从集群外部或集群内部访问服务时能够正确地将请求路由到正确的Pod。
网络代理,负责server的服务发现和负载均衡(4层:网络层,iptables)
# container-runtime
容器的运行时环境 :docker、containerd、CRI-O【可以从多个当中选一个容器方案】
# pod
运行了容器1、容器2、容器3。至少要有一个容器。【一台服务器是一个节点,一个节点下有多个pod,每一个pod下可以运行多个容器】
一个master、多个节点
apiServer、pod是核心
# 附加的一些组件
kube-dns 为整个集群提供DNS服务
Ingress Controller 让外部网络可以访问一个节点里的pod
heapster 资源监控(也可以用普罗米修斯)
dashboard
federation 跨集群
es 日志存储
以上可参考官方文档:Kubernetes Components (opens new window)
# 二.k8s的分层架构
核心层:Kubernetes 最核心的功能,对外提供 API 构建高层的应用,对内提供插件式应用执行环境。
核心层里面放的是最最核心的那些对象,提供最核心的API,比如 POD、NODE、 SERVICE、NAMESPACE等,就是运行一个应用的一些最基本对象
应用层:部署(无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS 解析 等)。
主要解决面向不同的应用。我应该去怎么样去抽象它的部署和服务发现?
对于无状态应用来说就 deployment
对于有状态应用来说是 statefulSet
批处理作业 job
。。。
管理层:系统度量(如基础设施、容器和网络的度量)、自动化(如自动扩展、动态 Provision 等)、 策略管理(RBAC、Quota、PSP、NetworkPolicy 等)。
主机解决更高级的需求, 如 隔离需求,安全需求,配额控制需求,自动的扩缩容的能力等
接口层:Kubectl 命令行工具、客户端 SDK 以及集群联邦。
生态系统:在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴:
- Kubernetes 外部:日志、监控、配置管理、CI、CD、Workflow、FaaS、OTS 应用、 ChatOps 等;
- Kubernetes 内部:CRI、CNI、CVI、镜像仓库、Cloud Provider、集群自身的配置和管理等。
# 三. 服务分类
# 有状态服务
对本地的存储系统会有依赖,如果要进行扩容,则还需要拷贝存储系统才行。
有状态服务是需要保持状态的应用,它们可能保存会话信息、数据库状态或其他需要持久化的状态数据。每个实例可能具有唯一标识或状态。有状态服务的特点包括:
- 固定标识: 每个实例有一个唯一的标识,如稳定的网络名称或主机名。这是因为有状态服务需要在实例之间保持一致的状态。【例如标识mysql主库和从库】
- 持久化存储: 有状态服务通常需要持久化存储来保存状态数据。这可以是网络存储、分布式数据库等。
- 有序扩展: 有状态服务的扩展可能需要考虑数据一致性和顺序,因此扩展和管理可能相对复杂。
常见的有状态服务包括数据库、缓存存储、消息队列等。
总之,在Kubernetes中,根据应用的状态要求,您可以选择部署无状态服务或有状态服务。无状态服务更容易扩展和管理,而有状态服务通常需要考虑更多的数据一致性和持久性问题。Kubernetes提供了适应这两种服务类型的机制和资源,以便满足不同应用的需求。
# 无状态服务
无状态服务也称为无状态应用,它们不依赖于特定的节点或实例来存储会话或状态信息。每个请求可以独立地处理,无需了解之前的请求状态。无状态服务的特点包括:
- 水平扩展: 由于无状态服务不保存状态,可以简单地通过增加实例数量来实现水平扩展,从而应对更高的负载。
- 易于替换和管理: 无状态服务的实例可以随时替换,因为它们没有持久化的状态。这使得部署、更新和管理变得更加容易。
- 不需要持久化存储: 由于没有需要持久化的状态,无状态服务通常不需要长期存储数据。
常见的无状态服务包括 Web 应用程序、API 服务和微服务。
# 四. 基础概念
# 1. 资源与对象
Kubernetes 中的所有内容都被抽象为“资源”,如 Pod、Service、Node 等都是资源。“对象”就是“资源”的实例,是持久化的实体。如某个具体的 Pod、某个具体的 Node。Kubernetes 使用这些实体去表示整个集群的状态。 对象的创建、删除、修改都是通过 “Kubernetes API”,也就是 “Api Server” 组件提供的 API 接口,这些是 RESTful 风格的 Api,与 k8s 的“万物皆对象”理念相符。命令行工具 “kubectl”,实际上也是调用 kubernetes api。 K8s 中的资源类别有很多种,kubectl 可以通过配置文件来创建这些 “对象”,配置文件更像是描述对象“属性”的文件,配置文件格式可以是 “JSON” 或 “YAML”,常用 “YAML”。
# 2. 对象规约spec和状态status
对象是用来完成一些任务的,是持久的,是有目的性的,因此 kubernetes 创建一个对象后,将持续地工作以确保对象存在。当然,kubernetes 并不只是维持对象的存在这么简单,kubernetes 还管理着对象的方方面面。每个Kubernetes对象包含两个嵌套的对象字段,它们负责管理对象的配置,他们分别是 “spec” 和 “status” 。
“spec” 是 “规约”、“规格” 的意思,spec 是必需的,它描述了对象的期望状态(Desired State)—— 希望对象所具有的特征。当创建 Kubernetes 对象时,必须提供对象的规约,用来描述该对象的期望状态,以及关于对象的一些基本信息(例如名称)。以 Pod 为例,如下是一个简单的创建 Pod 的 yaml 文件模板:
apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
1
2
3
4
5
6
7
8
9
10
11
上面的模板描述了一个对象,对象的类型是 “Pod”,对象名为 “myapp-pod”,包含一个 “app: myapp” 标签。“spec” 指定了该 Pod 对象的特征——对象包含一个名为 “myapp-container” 的容器,容器根据 “busybox” 镜像生成,容器运行的命令是 “ ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600'] ”。
除 “spec” 字段外,在创建一个Pod及Pod的控制器对象时,还要像上面模板所示一样,还要有这三个字段: “apiVersion”——“创建该对象所使用的 Kubernetes API 的版本”; “kind”——“想要创建的对象的类型”; “metadata”——“帮助识别对象唯一性的数据,包括一个 name 字符串、UID 和可选的 namespace。”
- status 描述了对象的 实际状态(Actual State) ,它是由 Kubernetes 系统提供和更新的。在任何时刻,Kubernetes 控制面一直努力地管理着对象的实际状态以与期望状态相匹配。
上面的内容参考:Kubernetes资源与对象简述 (opens new window)
# 3.资源的分类
# 元数据
对于资源的元数据描述,每个资源都可以使用元空间的数据
Horizontal Pod Autoscalar (HPA) 【pod自动伸缩】
PodTemplate
LimitRange
如通过HPA进行自动伸缩时,根据podTemplate进行pod的创建,并通过limitrange来限制pod资源的使用
# 集群
集群资源的空间,作用于集群之上,集群下的所有的资源都是可以共享使用的。就例如一个进程,进程下的资源线程都可以享用
namespace
node
clusterRole 对集群权限进行管理
ClusterRolebing 绑定角色与资源进行绑定,都是集群集群上的权限管理
# 命名空间
一个集群下可以有多个命名空间,命名空间内的资源可以共享,不同命名空间之间的数据不能进行共享
- 工作负载型
Pod:
pod控制器
用来控制pod怎么来创建
无状态
ReplicationController RC【新版本已经废除】
可以帮助我们动态的去完成pod的扩容和缩容。根据用于定义的副本数量
缺点:需要rc与pod进行绑定,很麻烦
ReplicaSet(RS)
可以通过selector来选择对哪些pod生效,即可以选择多个不通话的pod
label
selector
Deployment
RC和RS只有扩容和缩容,这是不够的。
对RS进行了再次的封装。提供了更多部署的特性。
- 创建rs,pod
用户可以根据dm创建pod,dm会自动帮助我们创建rs
- 平滑扩容和缩容
原来的rs控制的为APP2两个,当我们进行升级的服务时,dy会创建自动创建一个新的rs2,rs2复制一个app2并启动,同时关掉rs1的一个APP2,实现平滑更新
- 暂停和恢复
- 回滚
有状态
statefulSet
- headless Service
DNS管理
- volumeClaimTemplate
用于持久化卷的模版
守护进程
DaemonSet
任务/定时
job
cronJob
在Kubernetes中,"元数据"、"集群"和"命名空间"是三个重要的概念,用于管理和组织集群中的资源。
- 元数据(Metadata): 在Kubernetes中,元数据是关于各种资源(如Pods、Services、Deployments等)的描述性信息。这些信息包括资源的名称、标签、注释、创建时间、命名空间等。元数据帮助用户和系统理解资源的属性和上下文,有助于对资源进行管理、查询和监控。
- 集群(Cluster): Kubernetes集群是由多个物理或虚拟计算机(节点)组成的集合,用于运行容器化应用程序。这些节点可以分布在不同的主机上,并且由Kubernetes进行管理和编排。集群包括控制平面(主节点)和工作节点。控制平面负责管理和控制集群中的资源,而工作节点负责运行实际的容器和应用程序。
- 命名空间(Namespace): 命名空间是Kubernetes中用于对资源进行隔离和分组的机制。通过将资源放置在不同的命名空间中,可以将不同的团队、项目或应用程序隔离开来,以避免冲突和资源干扰。同一种类型的资源(如Pods、Services等)可以在不同的命名空间中具有相同的名称,而不会产生冲突。命名空间还有助于对资源进行权限控制和资源配额设置。
总之,元数据是描述性信息,集群是由节点组成的容器化应用程序环境,命名空间是用于隔离和组织资源的分组机制。这些概念共同帮助Kubernetes用户有效地管理和操作他们的应用程序和服务。
可参考:k8s资源的分类 (opens new window)
# 五. K8S集群搭建
集群搭建:
此次搭建方案使用 kubeadm方式:
# 1. 初始操作
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 关闭selinux
set -i 's/enforcing/disable' /etc/selinux/config # 永久
setenforce 0 #临时
# 关闭swap
swapoff -a #临时
sed -ri 's/.*swap.*/#&/' /etc/fstab #永久
# 关闭完swap后,一定要重启下虚拟机
# 根据规划设置主机名
hostnamectl set-hostname <hostname>
# 在master添加hosts
cat >> /etc/hosts << EOF
192.168.113.120 k8s-master
192.168.113.121 k8s-node1
192.168.113.122 k8s-node2
EOF
# 将桥接的IPV4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system # 生效
# 时间同步
yum install ntpdate -y
ntpdate time.windows.com
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 2. 安装基础软件 基于ubuntu 20.04.1
# 安装docker
# 添加阿里云yum源
# 安装kubeadm、kubelet、kubectl
kubeadm
:用来初始化集群的指令。kubelet
:在集群中的每个节点上用来启动 Pod 和容器等。kubectl
:用来与集群通信的命令行工具。
snap install kubectl --classic
snap install kubelet --classic
snap install kubeadm --classic
2
3
# 初始化集群
kubeadm init \
--apiserver-advertise-address=122.228.207.18 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.28.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
2
3
4
5
6
使用kubeadm的踩坑记录
docker version 24.0.5
kubeadm kubectl kubelet 1.28.1-00
当使用kubeadm初始化集群时出现问题:
validate service connection: CRI v1 runtime API is not implemented for endpoint
从网上翻阅资料:
https://serverfault.com/questions/1118051/failed-to-run-kubelet-validate-service-connection-cri-v1-runtime-api-is-not-im
似乎是在k8s的1.26版本,k8s需要对应的容器提供CRI版本,而如果使用最新版本的k8s,而最新版的docker并没有提供合适的CRI接口,所以就会出现上述的问题
查询gpt
kubeadm init 报错container runtime is not running: output: time="2023-08-28T10:19:21+08:00" level=fatal msg="validate service connection: CRI v1 runtime API is not implemented for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"
怎么解决
2
检查 CRI 版本和配置: 确保 kubeadm init 与容器运行时的 CRI 版本兼容。不同的 Kubernetes 版本可能需要特定版本的 CRI。同时,确保 Kubernetes 集群配置中指定了正确的 CRI 配置。
所以需要确定k8s的版本和docker的版本合适才行,通过一下的命令将版本进行更换
首先需要查看当前的组件的版本
apt-get list --installed | grep kubectl
apt-get list --installed | grep kubelet
apt-get list --installed | grep kubeadm
docker version
2
3
4
5
6
7
我当时以上的版本为
docker version 24.0.5
kubeadm kubectl kubelet 1.28.1-00
2
3
现在我根据相关的文档查看k8s需要哪个docker
https://blog.csdn.net/M82_A1/article/details/98872734
并借鉴了下面的安装文档
https://blog.csdn.net/yy8623977/article/details/124685772
最终决定使用k8s版本:1.23.6
docker版本:20.10
卸载原有版本
sudo apt-get remove kubeadm kubectl kubelet
sudo apt-get install kubeadm=1.23.6 kubectl=1.23.6 kubelet=1.23.6
sudo apt-mark hold kubeadm
2
3
如何降级docker
https://blog.csdn.net/hunter1000/article/details/122872247
以上都成功后,我们需要安装kubeadm的镜像
kubeadm config images list
k8s.gcr.io/kube-apiserver:v1.23.6
k8s.gcr.io/kube-controller-manager:v1.23.6
k8s.gcr.io/kube-scheduler:v1.23.6
k8s.gcr.io/kube-proxy:v1.23.6
k8s.gcr.io/pause:3.6
k8s.gcr.io/etcd:3.5.1-0
k8s.gcr.io/coredns/coredns:v1.8.6
2
3
4
5
6
7
调用k8s.gcr.io的连通性,发现我发联通,我们看看官网的解释
https://kubernetes.io/zh-cn/blog/2023/03/10/image-registry-redirect/
apt install kubectl=1.28.0-00 kubelet=1.28.0-00 kubeadm=1.28.0-00
apt-cache madison kubeadm
crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps -a | grep kube | grep -v pause
crictl --runtime-endpoint unix:///run/containerd/containerd.sock logs 3fa3f5bb43aa9
crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps -a
export KUBECONFIG=/etc/kubernetes/admin.conf 主节点
2
3
4
5
6
7
8
9
10
11
12
13
14
# minikube 方式
直接看官网:https://minikube.sigs.k8s.io/docs/start/ (opens new window)
kubectl命令:https://kubernetes.io/docs/reference/kubectl/
https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands
kubectl get pod 获取相关的pod信息
Kubectl get pod -o wide
kubectl get deploy 获取deploy相关信息
kubectl scale --help 扩容命令的帮助
kubectl scale --replicas=3 pod名字 创建某个pod的三个副本
kubectl get namespace 获得命名空间
kubectl get deploy 名字 -o yaml
kubectl get pods 获取所有pod
k8s api概述
![image-20230828164141639](/Users/zhengjian/Library/Application Support/typora-user-images/image-20230828164141639.png)
api版本规则
# 六.Pod深入解析
资源清单的编写:https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/assign-memory-resource/
apiVersion: 指定资源对象所属的 API 版本。它决定了 Kubernetes 如何解析和处理资源清单。例如,apiVersion: v1 表示使用的是 Kubernetes 的核心 API。
kind: 定义资源对象的类型。它指示 Kubernetes 要创建的资源类型,例如 kind: Pod、kind: Service 等。
metadata: 元数据字段包含了关于资源的信息,如名称、命名空间、标签等。
name: 资源的名称。
namespace: 资源所属的命名空间(Namespace)。如果未指定,默认为 default 命名空间。
labels: 标签用于标识资源,并可用于筛选和分组。
annotations: 注解用于添加描述性信息,通常用于记录额外的元数据。
spec: spec 部分是资源的规格,包含了资源配置的详细信息。
根据资源类型的不同,spec 部分的内容也不同,例如:
Pod: spec 包含容器和卷的配置。
Service: spec 定义了服务的类型、端口和选择器等。
Deployment: spec 定义了部署的副本数、容器映像、卷等。
status: status 部分包含了关于资源当前状态的信息。这是 Kubernetes 控制器设置的字段,用于记录资源的实际状态,通常由 Kubernetes 自己管理。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
创建好了过后使用kubectl create -f 文件
进行创建
后我们可以使用kubectl get po 查看相关的pod信息,还可以使用kubectl describe po po名字查看具体的信息。
apiVersion: v1
kind: Pod
metadata:
name: nginx-demo
labels:
type: "1"
version: "1"
namespace: default
spec:
containers:
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
command:
- nginx
- -g
- "daemon off;"
workingDir: "/usr/share/nginx/html"
ports:
- name: http
containerPort: 80
protocol: TCP
env:
- name: JVM_OPTS
value: "-Xms128m -Xms128m"
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
restartPolicy: OnFailure
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
使用kubectl get pod -o wide 查看更加详细的信息
# 1. 探针技术
Pod 探针。一种监控技术,判断pod一些的运行状态
例如我们在Pod中配置了一个镜像,是一个微服务,当我们微服务因为一些原因服务挂掉过后,我们的pod是否还存在,怎么知道他存不存在呢?这里就要使用到探针。
# livenessProbe
Liveness Probe(存活探针):这种探针用于检查容器是否在运行中。如果 Liveness Probe 失败,Kubernetes 认为容器不健康,会触发容器的重启。当我们创建了一个pod后,会对应创建一个探针来监控我们的镜像,当镜像挂掉后,对应的探针就会检查我们的资源清单中是否配置了restartPolicy相关的配置。
所以我们通过配置livenessProbe来进行配置相关的特性:
# readinessProbe
Readiness Probe(就绪探针):Readiness Probe 用于检查容器是否已经准备好接收流量。如果容器不就绪,Kubernetes 将不会将流量发送给该容器,直到探针成功为止。如果我们现在有一个pod,里面我们还需要做一些初始化的操作,在初始结束之前,我们不希望外界可以访问这个pod,这个时候我们就需要readinessProbe探针来监测我们的初始化服务是否有初始化完成,完成后才开启我们的pod,接收外部的流量
# startupProbe
Startup Probe(启动探针,从 Kubernetes 1.16 版本引入):Startup Probe 用于检查应用程序是否已经启动完成。在容器启动时,可能需要较长时间来准备应用程序,此时 Liveness Probe 可能会导致频繁的重启。Startup Probe 允许容器在启动期间进行探测,只有在启动完成后才开始检查 Liveness。启动探针(判断pod是否是否已经) 只有当startupProbe,后面的探针才会起作用
# 2. 探测方式
每个探针都可以使用下面三种方式进行探测
# execAction
Exec:在容器内部执行指定的命令,根据命令的退出状态来判断探针的成功与否。
在镜像中以命令的方式去探测,如果探测成功,则返回0
# TCPSocketAction
TCP Socket:尝试与容器内指定的端口建立 TCP 连接,如果连接成功则认为探针成功。
通过tcp的形式发送网络请求看是否能够成功
# HTTPGETAction
HTTP Get:向容器内的特定 HTTP 端点发送 GET 请求,根据响应状态码来判断容器的状态。
kubectl get po -n 命名空间名字
列举出对应的命名空间下有哪些pod
怎么编辑一个pod
kubectl edit pod pod名字
一个pod可以使用上面的语句进入资源清单的界面,但是这个时候,如果我们更改资源清单的值,并保存退出的时候,会报下面所示的错误提示:
因为pod本身是一个很普通的pod,他不想deploy等具有自动更新的功能,所以这里是不允许更新的。
看看gpt的解释:
这个错误消息表明,在编辑 Pod 的资源清单时,你只能修改指定的字段,而其他字段是不允许进行更改的。错误消息中提到的允许修改的字段包括:
spec.containers[*].image
spec.initContainers[*].image
spec.activeDeadlineSeconds
- 对现有
spec.tolerations
的添加- 对
spec.terminationGracePeriodSeconds
的修改,允许将其从负值修改为1换句话说,你只能编辑容器镜像的版本、活动截止时间、容忍设置等特定的字段。这是为了防止在运行中的 Pod 上进行不兼容的更改,确保修改不会导致不可预测的行为或潜在的问题。
如果你的编辑内容涉及到上述列出的字段之外的部分,那么在保存时就会遇到类似的错误。如果你需要更改其他字段,通常的做法是创建一个新的 Pod 模板,应用你的修改,并通过替换旧的 Pod 来进行更新。这样可以避免对正在运行中的 Pod 进行不兼容的修改。
如何删除pod
kubectl delete pod pod名字
# 3. 示例
# startupProbe:
在 Kubernetes 的
StartupProbe
中,你可以设置以下属性来配置容器启动探针:
exec
: 通过在容器内部执行一个命令来进行探测。你需要提供一个命令列表。如果命令成功退出(返回状态码为0),则探测成功。startupProbe: exec: command: - cat - /tmp/healthy
1
2
3
4
5
httpGet
: 通过发送 HTTP GET 请求来进行探测。你需要提供一个路径、端口和可选的主机信息。如果返回的状态码在成功范围内(默认为200至399),则探测成功。startupProbe: httpGet: path: /healthz port: 8080
1
2
3
4
tcpSocket
: 通过建立 TCP 套接字连接来进行探测。你需要提供一个端口号。如果连接成功,则探测成功。startupProbe: tcpSocket: port: 8080
1
2
3
initialDelaySeconds
: 定义容器启动后等待多少秒后开始首次探测。这可以确保容器有足够的时间来启动并准备好接受探测。startupProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 10
1
2
3
4
5
periodSeconds
: 定义探测之间的时间间隔。这是在首次探测成功后开始的,用于检查容器是否已经完全启动。startupProbe: httpGet: path: /healthz port: 8080 periodSeconds: 5
1
2
3
4
5
failureThreshold
: 定义连续失败的探测次数,达到此次数后容器将被认为启动失败。startupProbe: httpGet: path: /healthz port: 8080 failureThreshold: 3
1
2
3
4
5
timeoutSeconds
: 定义每次探测的最大时间。如果在这段时间内没有获得响应,探测将被视为失败。startupProbe: httpGet: path: /healthz port: 8080 timeoutSeconds: 2
1
2
3
4
5这些属性一起构成了
StartupProbe
的配置,可以根据你的应用程序的特定需求进行调整,以确保容器在启动时得到适当的探测和等待时间。
现在我们来编写nginx资源清单,并在里面加上启动探针,通过httpGet的方式(如果返回的是404这种错误编码,就表示这次探测失败)
apiVersion: v1
kind: Pod
metadata:
name: nginx-demo
labels:
type: "1"
version: "1"
namespace: default
spec:
containers:
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
startupProbe:
httpGet:
path: /api/path
port: 80
failureThreshold: 3
successThreshold: 1
periodSecondes: 10
timeoutSeconds: 5
command:
- nginx
- -g
- "daemon off;"
workingDir: "/usr/share/nginx/html"
ports:
- name: http
containerPort: 80
protocol: TCP
env:
- name: JVM_OPTS
value: "-Xms128m -Xms128m"
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
restartPolicy: OnFailure
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
通过kubectl get pod
会发现一直在创建当中,这个时候我们使用kubectl describe pod 名字
来查看详细的信息
可以看到重启的信息不仅展示了startup的信息,还展示了startup probe指针是成功还是失败的信息。
通过get命令,还可以看到对应的容器失败了几次,最终的效果是怎么样的
这里为什么重启了4次呢?
因为我们在startup探针中设置失败3次才算真正失败。所以算起来会重启4次
那我们尝试将资源文件中的path改成存在的路径试试呢?
apiVersion: v1
kind: Pod
metadata:
name: nginx-demo
labels:
type: "1"
version: "1"
namespace: default
spec:
containers:
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
startupProbe:
httpGet:
path: /index.html
port: 80
failureThreshold: 3
successThreshold: 1
periodSeconds: 10
timeoutSeconds: 5
command:
- nginx
- -g
- "daemon off;"
workingDir: "/usr/share/nginx/html"
ports:
- name: http
containerPort: 80
protocol: TCP
env:
- name: JVM_OPTS
value: "-Xms128m -Xms128m"
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
restartPolicy: OnFailure
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
之后再启动容器:
这个时候因为路径path是存在返回200的,所以容器就可以很成功的启动了。
我们再来试试对应的tcpsocket方式,这种方式只要与对应的端口建立成功3次握手就可以了。
apiVersion: v1
kind: Pod
metadata:
name: nginx-demo
labels:
type: "1"
version: "1"
namespace: default
spec:
containers:
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
startupProbe:
tcpSocket:
port: 80
failureThreshold: 3
successThreshold: 1
periodSeconds: 10
timeoutSeconds: 5
command:
- nginx
- -g
- "daemon off;"
workingDir: "/usr/share/nginx/html"
ports:
- name: http
containerPort: 80
protocol: TCP
env:
- name: JVM_OPTS
value: "-Xms128m -Xms128m"
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
restartPolicy: OnFailure
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
对应80端口,我们是可以建立连接的,预期可以成功启动
如图建立成功。
那么假如我们换成端口8080呢,这个端口可能没有开放:
如上提所示,确实展示了探针检测失败了。
exec 尝试:
命令执行成功,就表示成功。如果命令执行失败,则表示失败。
但是我们这个命令时间超过了5s,所以会有探针失败,会进行相应的重启
这个可以在容器当中执行一个具体的指令。我们通过这个指令查看我们的指令是否有执行成功
# 2. LivesessProbe
如果容器不满足某种规则,则进行重启
当startup探针执行后,会接着执行liveness探针。
创建pod后,我们看描述情况:
执行期间可以使用这个命令,让liveness探针检测成功
# 3. readinessProbe
执行成功之前,外界流量不能访问。
# pod生命周期
初始化阶段:
startup 启动探针
# preStop钩子函数
最常用的一个生命周期
每个容器都可以配置一个对应的生命周期
lifecycle:
postStart:
exec:
command:
- sh
- -c
- "echo '<h1>pre stop</h1>' > /usr/share/nginx/html/prestop.html"
preStop:
exec:
command:
- sh
- c
- "sleep 50; echo 'sleep finished...' >> /usr/share/nginx/html/prestopp
.html"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
持续监听pod的状态
kubectl get po -w
# 七.资源调度
对于pod的话,其资源使用方法,比如无法动态扩容,无法进行配置文件的修改,然后对于这种情况,k8s给我们提供了很多的控制器。
举例
回顾:什么是Deployment、什么是RS
- ReplicaSet(RS): ReplicaSet 是 Kubernetes 中的一个控制器,它用于确保指定数量的 Pod 副本在任何时候都在运行。ReplicaSet 通过与声明式的方式定义的 Pod 模板来创建和维护 Pod 副本数量。如果由于某种原因导致副本数量不足或超出预期,ReplicaSet 将自动调整以恢复所需的副本数量。ReplicaSet 可以用于静态副本数量的管理,但不支持滚动更新等功能。
- Deployment: Deployment 是一个更高级别的资源对象,用于管理 Pod 的发布和更新。它使用 ReplicaSet 来管理副本数量,并通过滚动更新策略来升级应用程序。Deployment 允许你在不中断应用程序的情况下进行滚动更新,逐步替换旧版本的 Pod 为新版本。通过 Deployment,你可以方便地指定应用程序的期望状态,以及如何从旧版本过渡到新版本。
两者之间的关系在于,Deployment 使用 ReplicaSet 来实现副本数量的管理和滚动更新。当你创建一个 Deployment 时,Kubernetes 会同时创建一个 ReplicaSet,然后根据 Deployment 的定义来创建 Pod。当你对 Deployment 进行滚动更新时,Deployment 会创建一个新的 ReplicaSet 来管理新版本的 Pod,然后逐步停止旧版本的 ReplicaSet 管理的 Pod。
# 1. selector
在 Kubernetes 中,Selector(选择器)是一个用于标识和匹配特定资源的标签集合。它被用于选择哪些资源应该由某个控制器(如 Deployment、ReplicaSet)来管理。
Selector 是 Kubernetes 控制器与资源之间的桥梁,它允许控制器选择和管理一组特定的资源,这些资源的标签匹配了 Selector 中定义的标签。通过这种方式,控制器可以确保它管理的资源符合特定的条件。
- Deployment: Deployment 使用标签选择器来确定哪些 Pod 是属于它的。在 Deployment 的定义中,你可以指定一个标签选择器,以选择哪些 Pod 将由该 Deployment 来管理。Deployment 会根据定义的 Pod 模板和滚动更新策略来创建和更新 Pod,只选择满足标签选择器条件的 Pod。
- ReplicaSet: ReplicaSet 也使用标签选择器来管理一组 Pod。在 ReplicaSet 的定义中,你同样可以指定一个标签选择器,以选择要管理的 Pod。ReplicaSet 的主要目标是确保副本数量与定义的数量保持一致,它会创建和删除 Pod 来实现这一目标。
# 标签定义常见语法
首先需要给我们对应的pod打上标签:
- 在资源清单上面进行打标签
Metadata.labels上面打标签
- 命令行模式
新增kubectl label po <节点名称> key=value -n 命名空间
给哪个命名空间下的label打上对应的标签
修改: kubectl label po <节点名称> key=value --overwrite
查看所有节点的labels
kubectl get po -n 命名空间 --show-labels
注意上面的操作都是临时操作,如果一个pod关闭了,后面就这些标签就会丢失。使用kubectl edit更改可以永久保存
# 选择器语法
在 Kubernetes 中,标签选择器(Selector)的语法使用 Label Selector 表达式来定义,它用于筛选资源(如 Pod、Service、ReplicaSet 等)并将其与特定的标签进行匹配。以下是一些常见的 Label Selector 语法示例:
- 选择器的使用
kubectl get po -A -l app=hello
-A: 在 kubectl
命令中,-A
选项是一个缩写,表示 --all-namespaces
,它用于在所有命名空间中执行操作。通过使用 -A
,你可以让 kubectl
命令在所有命名空间中进行操作,而不仅限于特定的命名空间。
-l: -l
参数用于指定一个或多个标签选择器,以便只获取具有特定标签的 Pod。在你的命令中,app=hello
表示你正在筛选拥有标签 app=hello
的 Pod。这意味着只有带有这个标签的 Pod 会被列出。
kubectl get pod -l 'test in (1.0.0,1.1.0,1.2.0)'
表示 test 是否匹配对应的多个label
kubectl get po -l version!=1.0.0,type=app
多个条件,这是&的关系
相关的语法:
等于匹配: 使用
=
来表示等于匹配。app = nginx
1不等于匹配: 使用
!=
来表示不等于匹配。environment != production
1存在匹配: 使用
key
来表示键存在。key
1不存在匹配: 使用
!key
来表示键不存在。!key
1多个匹配: 使用逗号
,
分隔多个匹配条件,表示这些条件之间是逻辑与关系。app = nginx, environment = production
1逻辑 OR 匹配: 使用逗号
,
分隔多个条件,并用逗号前的空格和逗号后的空格来表示逻辑 OR 关系。app = nginx, app = apache
1逻辑 NOT 匹配: 使用逗号
,
分隔多个条件,并在条件前加上!
来表示逻辑 NOT 关系。!app = nginx
1带括号的复杂匹配: 可以使用括号来创建复杂的匹配条件,以控制匹配的优先级。
(app = nginx, environment = production) OR (app = apache, environment != staging)
1
# 2. Deployment
不知道怎么写资源清单,那我们直接通过一个快速的方式建立一个Deployment
kubectl create deploy nginx-deploy --image=nginx:1.7.9
命令解析
你使用的命令
kubectl create deploy nginx-deploy --image=nginx:1.7.9
是创建一个名为nginx-deploy
的 Deployment,它会使用nginx:1.7.9
镜像作为 Pod 的容器镜像。这个命令会在默认的命名空间中创建一个 Deployment 对象。如果你想在特定的命名空间中创建,可以通过
--namespace
参数指定。运行这个命令后,Kubernetes 会创建一个包含一个 Pod 模板的 Deployment。这个 Deployment 将负责管理副本数量,并确保指定数量的 Pod 使用
nginx:1.7.9
镜像运行。可以使用类似
kubectl get deploy nginx-deploy
的命令来查看创建的 Deployment。如果你想查看相关的 Pod 信息,可以运行类似kubectl get po -l app=nginx-deploy
的命令,这将使用标签选择器来获取与该 Deployment 相关的 Pod。
成功创建之后,我们看一下对应的deploy
kubectl get deploy
kubectl get replicaset
获取对应的rs
可以看到对应的rs在deploy的末尾名字加上了对应的随机字符串
那我们再看看pod呢?
可以看到对应的pod在rs的基础上也在名字的后面加上了对应的字符串,所以就有一个很清晰的层级关系:dp-> rs-pod
共同的还有一个pod-template-hash,这个就是我们拿来创建pod的模板
# 怎么获取一个deploy的yaml信息
kubectl get deploy nginx-deploy -o yaml
-o yaml
:这部分表示你想要以 YAML 格式来输出获取到的资源信息。-o
是 kubectl
命令的选项,用于指定输出格式。在这里,你选择了 yaml
格式。
# 如何自己写一个deploy yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
namespace: default
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx-deploy
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.7.9
imagePullPolicy: IfNotPresent
name: nginx
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
重点解释下spec下面的定义:
spec
: 定义资源的规格,包含关于资源如何配置的信息。
replicas
: 指定所需的副本数量,这里是 1 个副本。revisionHistoryLimit
: 指定保存的历史版本数量,这里是 10。例如我们要回滚,最多可以混滚到前10个podselector
: 选择器用于关联 Deployment 与 Pod,这里选择了标签app: nginx-deploy
的 Pod。strategy
: 策略定义了更新 Deployment 的方法。
rollingUpdate
1: 定义滚动更新策略。
maxSurge
: 允许超出所需副本数量的数量或百分比,这里是 25%。更新的个数最多可以超过期望副本的比例maxUnavailable
: 允许不可用的数量或百分比,这里是 25%。
type
: 更新策略的类型,这里是滚动更新。
template
1: 定义 Pod 模板,包含了容器和其他配置。
metadata
: 定义模板的标签,这里定义了app: nginx-deploy
。spec
1: 定义 Pod 的规格,包括容器等。
containers
1: 定义容器的列表。
image
: 容器使用的镜像,这里是nginx:1.7.9
。imagePullPolicy
: 镜像拉取策略,这里是IfNotPresent
。name
: 容器的名称,这里是nginx
。restartPolicy
: 容器的重启策略,这里是Always
,表示出现故障时会自动重启。terminationGracePeriodSeconds
: 容器终止前的优雅关闭等待时间,这里是 30 秒。
# 怎么编辑一个deploy
kubectl edit deploy nginx-deploy
注意:编辑template下面的才会生效(即改pod模板才会进行一个更新的操作),更新其他东西,比如更新deploy自己的metadata,是不能进行更新的,虽然用get deploy --show-labels可以看到对应的label改变了,但是在底层,使用describe可以看到其实并没有更新
现在我们想要通过deploy来增加我们的pod副本数
更改掉对应的replicas就可以了,这里我们更改为5.
退出保存后,查看deploy信息,再查看rs和pod信息
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 5/5 5 5 37m
NAME DESIRED CURRENT READY AGE
nginx-deploy-58dcf5bbfb 5 5 5 38m
NAME READY STATUS RESTARTS AGE
nginx-deploy-58dcf5bbfb-bxj5k 1/1 Running 0 67s
nginx-deploy-58dcf5bbfb-sg2jr 1/1 Running 0 38m
nginx-deploy-58dcf5bbfb-tvszv 1/1 Running 0 67s
nginx-deploy-58dcf5bbfb-x6z5q 1/1 Running 0 67s
nginx-deploy-58dcf5bbfb-z7pdw 1/1 Running 0 67s
2
3
4
5
6
7
8
9
10
11
12
可以看到扩容的时候,最终会让pod创建为5个
顺便看看每个节点的ip地址
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-58dcf5bbfb-bxj5k 1/1 Running 0 2m4s 10.244.0.13 minikube <none> <none>
nginx-deploy-58dcf5bbfb-sg2jr 1/1 Running 0 39m 10.244.0.11 minikube <none> <none>
nginx-deploy-58dcf5bbfb-tvszv 1/1 Running 0 2m4s 10.244.0.12 minikube <none> <none>
nginx-deploy-58dcf5bbfb-x6z5q 1/1 Running 0 2m4s 10.244.0.14 minikube <none> <none>
nginx-deploy-58dcf5bbfb-z7pdw 1/1 Running 0 2m4s 10.244.0.15 minikube <none> <none>
2
3
4
5
6
这个时候,我们就来触发我们的滚动更新
# 滚动更新
我们修改template中的nginx版本号,
nginx:1.7.9 改为 nginx:1.9.1
除了通过edit进行修改,我们还可以通过另一种方式进行修改
kubectl set image deployment/nginx-depoly nginx=nginx:1.9.1
kubectl set image deployment/nginx-deploy nginx=nginx:1.9.1
是一个kubectl
命令,用于更新名为nginx-deploy
的 Deployment 中的容器镜像。具体来说,它将 Deployment 中名为nginx
的容器的镜像更新为nginx:1.9.1
。这个命令的各个部分含义如下:
set image deployment/nginx-deploy
:这部分表示你正在使用kubectl
的set image
子命令来更新 Deployment 中的容器镜像。deployment/nginx-deploy
表示你要更新的 Deployment 的名称。nginx=nginx:1.9.1
:这部分表示要将名为nginx
的容器的镜像更新为nginx:1.9.1
。等号前的nginx
是容器的名称,等号后的nginx:1.9.1
是新的镜像名称。运行这个命令后,Kubernetes 将自动更新 Deployment,创建一个新的 ReplicaSet,并逐步将 Pod 更新为使用新的镜像。这使你能够在不中断服务的情况下,将应用程序升级到新的容器镜像版本。
更改保存过后,我们可以立即通过kubectl get deploy
来查看我们的up to date的变化。
还可以通过命令kubectl rollout status deploy nginx-depoly
kubectl rollout status deploy nginx-deploy
是一个kubectl
命令,用于检查 Deployment 的滚动更新状态。具体来说,它会显示有关名为nginx-deploy
的 Deployment 的滚动更新进度和状态信息。这个命令的各个部分含义如下:
rollout status deploy nginx-deploy
:这部分表示你正在使用kubectl
的rollout status
子命令来检查名为nginx-deploy
的 Deployment 的滚动更新状态。deploy
表示你要检查的资源类型是 Deployment。nginx-deploy
:这部分是 Deployment 的名称,指定了要检查的 Deployment。运行这个命令后,Kubernetes 将显示有关指定 Deployment 的滚动更新状态的信息。你可以看到正在进行的更新以及更新的进度,以便了解升级的情况。这在管理应用程序升级过程中非常有用,可以帮助你确认更新是否成功并且没有出现问题。
我们也可以通过describe命令直接看
即进行更新的时候,deploy会创建一个新的rs,然后在rs中创建一个新的pod并启动,同时关闭原rs的一个pod,然后新的rs又创建一个新的pod,依次类推,实现滚动更新。
Gpt:
滚动更新是一种应用程序升级和部署的策略,允许你在不中断服务的情况下,逐步替换旧版本的应用程序为新版本。在 Kubernetes 中,滚动更新是通过逐步替换 ReplicaSet 中的 Pod 来实现的,而 ReplicaSet 则是由 Deployment(或其他控制器)来管理的。
以下是滚动更新的一般原理:
- 创建新的 ReplicaSet: 首先,你创建一个新的 ReplicaSet,该 ReplicaSet 包含了新版本的应用程序的 Pod 模板。
- 增加副本数量: 新的 ReplicaSet 会开始逐步增加 Pod 的副本数量,以便将新版本的 Pod 逐步引入集群。
- 监控滚动更新: Kubernetes 会监控滚动更新的进度,确保新版本的 Pod 正确启动并准备好接收流量。
- 逐步删除旧的 Pod: 当新版本的 Pod 开始运行并且就绪后,Kubernetes 会逐步减少旧版本的 ReplicaSet 中的 Pod 副本数量。
- 完成滚动更新: 当旧版本的 Pod 副本数量减少到零,滚动更新就完成了,此时所有流量都转移到了新版本的应用程序。
滚动更新的优点包括:
- 零停机时间: 滚动更新允许在应用程序升级过程中保持服务可用,不会中断现有的流量。
- 逐步回滚: 如果在滚动更新过程中出现问题,你可以逐步回滚到旧版本,以确保应用程序的稳定性。
- 逐步稳定: 通过逐步引入新版本的 Pod,你可以逐步验证新版本的稳定性和正确性。
总之,滚动更新是 Kubernetes 中一种强大的应用程序管理策略,允许你在不中断服务的情况下进行应用程序的升级和部署。
创建了一个新的RS?我们可以通过get rs来查看一下,果然有一个rs里面没有可用的pod,另外一个新的创建了3个可用的pod,而且rs的name都不一样。当然相应的pod对应的name也会更新。
并行滚动更新问题:
加入我们现在rs1里面有5个pod,现在我们对deploy的yaml文件进行更新,也就是滚动更新的流程。他会创建一个rs2,假如此时已经更新了2个pod。然后,此时突然用户又来更新这个deploy的yaml,此时为了保证一些并发的安全问题,dp首先会创建一个rs3,并认为正在更新的rs2可能没有用了,会弃用掉rs2,并在rs3里面建立2个pod,后续rs1和rs3进行相应的滚动更新。
个人记录:
前:
中:
可以看到滚动更新的流程
命令
Scaled up replica set nginx-deploy-6d5979b84b to 2
是 Kubernetes 控制器发出的日志消息,表示已经将名为nginx-deploy-6d5979b84b
的 ReplicaSet 的副本数量扩展到 2 个。命令
Scaled down replica set nginx-deploy-58dcf5bbfb to 4 from 5
是 Kubernetes 控制器发出的日志消息,表示已经将名为nginx-deploy-58dcf5bbfb
的 ReplicaSet 的副本数量从 5 个减少到 4 个。后:
这里可以看到rs新创建了一个,另一个老版本仍然保存着,可用于回滚
# 回滚
例如我们写nginx版本写错了,1.9.1我们写成了1.91,这个时候从网上拉取镜像是拉不下来的,这个时候新的rs2在创建第一个pod的时候就会一直卡死,例如:
通过describe获取更加详细的信息:
通过describe查看最新的信息:
现在卡主了,或者你更新了一些错误的数据,我们就需要进行回退,具体的回退,首先我们需要拿到对应的历史版本的信息。
kubectl rollout history delpoyment/nginx-deploy
查看具体的历史修改版本:
这里有一些为none的信息,我们可以在进行修改定位时候指定我们的修改的信息,以提示对应的修改做了哪些操作:
我们可以查看具体某一个版本号的信息:例如我们要查看版本2的信息:
kubectl rollout history deployment/nginx-deploy --revision=2
我们可以看到一些修改过的信息
回退到指定的版本:
kubectl rollout undo deployment/nginx-deploy --to-revision=2
然后我们通过edit进行yaml文件,可以看到具体的版本已经修改了。
也是滚动更新
# 扩容缩容
怎么扩容缩容?
方案一:修改deploy paml文件里面的replicas实现扩容缩容
方案二:使用命令的方式:
kubectle scale --replicas=6 deploy nginx-depoly
# 暂停与恢复
这里的暂停与恢复是指对deploy的滚动更新进行暂停和恢复,外界还是依然可以进行访问的。
kubectl rollout pause deployment <name>
暂停
kubectl rollout deploy <name>
恢复
# 3. StatefulSet 有状态应用
案例示意图
配置文件:
---这种语法指的是在yaml文件里嵌套另一个yaml文件
---
apiVersion: v1
kind: Service # 端口映射,绑定
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.alpha.kubernetes.io/storage-class: anything
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
然后我们使用kubectl create -f 文件.yaml
启动成功后:
kubectl get sts
kubectl get svc
kubectl get pvc
怎么替换一个statefulset
的配置文件,kubectl replace sts sts名字 -f 新文件名
这个时候我们还可以看一下sts下的pod
root@openstackTest-3:~/zhengjian/k8s/sts# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 5m50s
web-1 1/1 Running 0 5m46s
2
3
4
我们的主机可以ping到pod的服务吗?目前是不能的,但是我们可以在default下面创建一个pod,在pod中ping对应的web服务
kubectl run -it --image busybox dns-test --restart=Never --rm /bin/sh
这个命令的含义是在 Kubernetes 集群中运行一个临时的 BusyBox 容器,用于进行 DNS 测试。让我解释一下命令中的各个部分:
kubectl run
: 这是一个用于创建和管理 Kubernetes 资源的命令。-it
: 这两个选项表示在交互模式下运行容器,并将标准输入绑定到容器的终端,以便你可以与容器进行交互。--image busybox
: 这个选项指定了要使用的容器镜像,这里使用了 BusyBox 镜像,它是一个小巧的 Linux 发行版,用于执行基本的命令。dns-test
: 这是你为创建的 Pod 指定的名称。--restart=Never
: 这个选项表示 Pod 的重启策略是 "Never",意味着一旦该容器退出,Pod 就会被删除。--rm
: 这个选项表示在容器退出后自动删除相关的 Pod。/bin/sh
: 这是你要在容器内运行的命令,这里是启动 BusyBox 容器后进入其 shell。总之,该命令的目的是在 Kubernetes 集群中创建一个短暂的 BusyBox 容器,以便你可以在容器内部进行交互式的命令行操作。通常,这种操作常用于调试、测试或获取有关 Kubernetes 环境的信息,比如测试 DNS 解析是否正常。
BusyBox 是一个精简的、适用于嵌入式系统和轻量级容器的开源工具集合。它被设计为一个单一可执行文件,包含了许多常用的 Unix 工具和命令,如 shell、文件操作工具、文本处理工具、网络工具等。BusyBox 的目标是提供一个小巧但功能齐全的工具集,适用于资源有限的环境。
以下是 BusyBox 的一些特点和用途:
- 小巧而高效: BusyBox 的主要特点之一是其小巧的体积,它将许多标准 Unix 命令集成到一个单一的可执行文件中。这使得 BusyBox 成为嵌入式系统、网络设备和轻量级容器等资源受限环境中的理想选择。
- 多功能工具集: BusyBox 包含了许多常用的命令和工具,如 shell(通常是
ash
)、ls、cp、mv、grep、sed、awk、ping、ifconfig 等。这使得在资源受限的环境中执行各种任务变得容易。- 适用于容器: BusyBox 经常用于容器中,尤其是在创建临时性的容器用于测试、调试、数据挖掘等场景时。它可以提供基本的命令行工具,帮助用户在容器内部执行各种操作。
- 嵌入式系统: BusyBox 也常用于嵌入式系统中,例如嵌入式 Linux 发行版中。在资源有限的嵌入式设备上,BusyBox 可以充当一个小型命令行界面。
- 开源: BusyBox 是开源的,它的源代码可以被自由访问、修改和分发,符合开源社区的理念。
在容器里面我们执行以下命令,发现是可以ping通的
ping web-0.nginx
ping web-1.nginx
2
查看映射dns
nslookup web-0.nginx
nslookup web-1.nginx
/ # nslookup web-0.nginx
Server: 10.96.0.10
Address: 10.96.0.10:53
** server can't find web-0.nginx: NXDOMAIN
** server can't find web-0.nginx: NXDOMAIN
2
3
4
5
6
7
8
9
10
这是在 BusyBox 容器中使用
nslookup
命令进行 DNS 查询的结果。让我解释一下输出的含义:
/ #
: 这是命令行提示符,表示你正在 BusyBox 容器的根目录下执行命令。nslookup web-0.nginx
: 这是你运行的nslookup
命令,用于查询名为web-0.nginx
的主机的 DNS 信息。Server: 10.96.0.10
: 这是 DNS 查询的结果。Server
字段指示用于执行 DNS 查询的 DNS 服务器的 IP 地址。在这个结果中,查询是通过 IP 地址10.96.0.10
的 DNS 服务器进行的。Address: 10.96.0.10:53
: 这表示 DNS 服务器的地址和端口号。10.96.0.10
是 DNS 服务器的 IP 地址,而53
是 DNS 协议的默认端口号。总之,输出表示你查询了一个名为
web-0.nginx
的主机的 DNS 信息,并且该查询是通过 IP 地址为10.96.0.10
的 DNS 服务器进行的。这对于了解容器内部的 DNS 解析以及它如何与集群中的 DNS 服务器交互是很有用的。
以上的工具似乎拿不到所有的信息,我们换一个busybox进行工具获取
kubectl run -it --image busybox:1.28.4 dns-test /bin/sh
在使用刚刚命令进行查看:
/ # nslookup web-0.nginx
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx
Address 1: 10.244.0.26 web-0.nginx.default.svc.cluster.local
2
3
4
5
6
# 扩容与缩容
kubectl scale statefulset web --replicas=5
kubectl patch statefulset web -p '{"spec":{"replicas":3}}'
2
扩容和缩容是安装顺序进行的
# 镜像的更新
更新的分类:
- RollingUpdate: 可以实现灰度发布
当一部分更改了过后,另一部分还没有进行更新,那我们怎么进行继续更新呢?
通过descirbe继续去sts中将partition继续降低继续到更改0。
灰度发布和滚动更新有什么区别
滚动更新(Rolling Update)和灰度发布(Canary Deployment)都是在更新应用程序时常见的部署策略,但它们有一些区别。
滚动更新(Rolling Update):
滚动更新是一种常见的应用程序更新策略,它的目标是将旧版本应用逐步替换为新版本,以确保在更新过程中应用程序的可用性。在滚动更新中,新版本的实例逐步逐个地替换旧版本的实例,直到所有实例都被更新为止。这种方式可以减少应用程序的停机时间,并且在更新过程中保持应用的高可用性。
灰度发布(Canary Deployment):
灰度发布是一种更为谨慎的部署策略,它通过逐步引入新版本的部分流量来测试和验证新版本。在灰度发布中,只有一小部分流量会被路由到新版本,而大部分流量仍然会发送到旧版本。这允许团队在生产环境中逐步测试新版本,以确保它们稳定和可靠,然后再逐步增加流量直到完全部署新版本。
区别:
- 更新策略: 滚动更新是逐步替换所有实例的过程,而灰度发布是逐步引入新版本的一部分流量。
- 流量分配: 在滚动更新中,新旧版本之间的流量逐步切换。而在灰度发布中,只有一小部分流量会发送到新版本。
- 风险管理: 滚动更新通常更适合那些有信心在更新过程中保持应用程序的稳定性的情况。灰度发布可以用于更谨慎地测试新版本,以减少风险。
- 测试范围: 灰度发布通常用于测试新版本的性能和稳定性,因为它允许在生产环境中以较小的规模进行测试。滚动更新可能更适合只是简单的版本更新。
总之,滚动更新和灰度发布都是根据应用程序的需求和风险承受能力来选择的部署策略。滚动更新适合较小的更新,而灰度发布适合需要更谨慎测试新版本的情况。
- OnDelete
我们通过edit在yaml文件修改保存后,对应的pod并不会立即更新。仅当我们删除了一个pod后,对应的pod会立即重启,并替换为新的pod
# 删除
首先需要明白几个概念,sts是没有rs的,sts会直接关联pod,sts还会关联pvc、svc
当我们对sts进行删除时,pod不一定会删除,k8s给我们提供了删除和级联删除
# 4. DaemonSet 为每一个匹配的Node都部署一个守护进程
就如这几个节点所示,节点1、节点2、节点3,3个节点他们都有自己对应的日志,而且他们之间形成了一种微服务的调用关系,当我们的服务出现bug时,我们总不可能去每一个节点中去查询日志吧?所以这个时候就有一个daemonSet的概念,他可以在指定的node上去执行相应的指定的pod。
在 Kubernetes 中,DaemonSet 是一种用于确保每个节点上都运行一个实例的 Pod 的控制器。它用于在集群的每个节点上运行一组副本,以确保在每个节点上都有相同数量的 Pod 实例。DaemonSet 主要用于运行需要在每个节点上运行的系统级别服务,如日志收集、监控代理、网络代理等。
以下是一些 DaemonSet 的特点和用途:
- 节点上的唯一实例: 每个节点上只会运行一个 DaemonSet 的 Pod 实例,这与其他控制器(如 Deployment 或 StatefulSet)不同,后者可能在多个节点上运行多个 Pod 副本。
- 节点的动态调整: 当你添加或删除节点时,DaemonSet 会自动在新节点上启动新的 Pod 实例,或者在节点删除时删除相应的 Pod 实例,以保持每个节点上都有相同数量的 Pod。
- 系统级别任务: DaemonSet 通常用于运行系统级别的任务,这些任务需要在每个节点上都有一个实例,以确保集群的正常运行和监控。
- 日志、监控、网络代理: 一些常见的使用情景包括在每个节点上运行日志收集代理(如 Fluentd 或 Filebeat)、监控代理(如 Prometheus Node Exporter)或网络代理(如 Cilium 或 Calico)。
- 节点标签选择: 你可以使用标签选择器来定义哪些节点应该有相应的 DaemonSet Pod 实例。这可以让你根据节点的标签来选择性地部署这些任务。
daemonset怎么选择在对应的节点上呢?
- nodeSelector:只调度到匹配指定label的Node上
- nodeAffinity:功能更丰富的Node选择器,比如支持集合的操作
- podAffinity: 调度到满足条件的pod所在的Node上
# 配置文件的创建
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
selector:
matchLabels:
app: Togging
template:
metadata:
labels:
app: Togging
id: fluentd
name: fluentd
spec:
containers:
- name: fluentd-es
image: agilestacks/fluentd-elasticsearch:v1.3.0
env:
- name: FLUENTD_ARGS
value: "-qq"
volumeMounts:
- name: containers
mountPath: "/var/lib/docker/containers"
- name: varlog
mountPath: "/var/log"
volumes:
- hostPath:
path: "/var/lib/docker/containers"
name: containers
- hostPath:
path: "/var/log"
name: varlog
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apiVersion
和kind
:这是 Kubernetes 资源的 API 版本和类型。在这里,我们定义了一个 DaemonSet 资源。metadata
:这里定义了 DaemonSet 的元数据,其中name
指定了资源的名称为 "fluentd"。selector
:这是用于选择目标节点的标签选择器。在这个配置中,我们希望 DaemonSet 在匹配app: logging
标签的节点上运行。template
:这是要在每个节点上运行的 Pod 的模板。模板中的metadata
定义了 Pod 的标签,用于选择匹配的节点。spec
定义了 Pod 的规格,包括容器和卷等信息。containers
:这里定义了在 Pod 内运行的容器。在这个例子中,我们定义了一个名为 "fluentd-es" 的容器,使用了agilestacks/fluentd-elasticsearch:v1.3.0
镜像。env
部分定义了容器的环境变量,用于配置 Fluentd。在这里,FLUENTD_ARGS 环境变量被设置为 "-qq"。volumeMounts
:这里定义了容器的挂载点,用于将主机上的目录挂载到容器中。在这个例子中,挂载了两个主机路径:/var/lib/docker/containers
和/var/log
。volumes
:这是为 Pod 定义的卷,这些卷将被挂载到容器中。在这个例子中,我们定义了两个主机路径的卷:containers
和varlog
。
创建,然后用kubectl get ds
需要生产的环境节点:后续再进行学习。https://www.bilibili.com/video/BV1MT411x7GH?p=45&spm_id_from=pageDriver&vd_source=a05a4698720267eb93bab07197b4276c
# 5. HPA 【待学习】
Horziontal Pod AutoScaler(HPA)
HPA(Horizontal Pod Autoscaler)是 Kubernetes 中的一个功能,用于自动根据应用程序的负载情况来调整 Pod 副本的数量。它通过监测指标(例如 CPU 使用率或自定义指标)来判断是否需要增加或减少 Pod 的数量,以适应流量的变化。HPA 使得应用程序可以根据负载的变化自动进行扩展或缩减,以确保应用的可用性和性能。
以下是 HPA 的一些关键特点和用途:
- 自动扩展和缩减: HPA 可以根据定义的指标自动增加或减少 Pod 的数量。例如,当 CPU 使用率超过一定阈值时,HPA 可以自动增加 Pod 数量来处理更多的流量,当流量减少时,可以自动减少 Pod 数量以节省资源。
- 水平扩展: HPA 实现的是水平扩展,即增加 Pod 的数量,而不是在现有 Pod 上增加资源。这有助于保持应用程序的高可用性和负载均衡。
- 指标监测: HPA 可以根据不同的指标来进行扩展和缩减,例如 CPU 使用率、内存使用率、网络流量等。你也可以定义自己的自定义指标。
- 自定义阈值: 你可以设置不同的阈值来触发自动扩展和缩减。例如,当 CPU 使用率达到 80% 时扩展,降到 20% 时缩减。
- 适用于不同的工作负载: HPA 可以应用于各种不同类型的工作负载,包括 Web 应用、API 服务、批处理作业等。
现在我们拿deploy的情况来看:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
namespace: default
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx-deploy
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.7.9
imagePullPolicy: IfNotPresent
name: nginx
restartPolicy: Always
terminationGracePeriodSeconds: 30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
这个当中只有一个replicas。
我们在配置文件中加上相应的内容:
# 集群搭建 step by step
sudo swapoff -a
将暂时禁用交换分区。要使此更改在重启后保持不变,请确保在如/etc/fstab
、systemd.swap
等配置文件中禁用交换分区,具体取决于你的系统如何配置。使用
ip link
查看各个节点之间的mac地址,必须保证不同
什么是ipvs
IPVS(IP Virtual Server)是一种在Linux操作系统上运行的负载均衡技术。它允许将网络流量分发到多个后端服务器,以提高系统的可用性、性能和可扩展性。IPVS通常用于构建高可用性和高性能的网络服务,例如Web服务器集群、数据库服务器集群等。
IPVS的工作原理如下:
- 客户端发送请求到负载均衡器,这是一个中间节点,通常拥有一个虚拟IP地址。
- 负载均衡器接收请求后,根据预定义的负载均衡算法(如轮询、加权轮询、最小连接数等),选择一个后端服务器来处理请求。
- 负载均衡器将请求转发到选定的后端服务器。
- 后端服务器处理请求并将响应发送回负载均衡器。
- 负载均衡器将响应返回给客户端。
IPVS支持多种负载均衡算法,可以根据需求进行配置。此外,它还具有自动检测和处理后端服务器的故障的功能,以确保请求在发生故障时能够被正确重定向到正常运行的服务器上。
总之,IPVS是一种用于构建高可用性和高性能网络服务的负载均衡技术,它能够有效地分发网络流量以提高系统的可靠性和性能。它在Linux环境中广泛使用,通常与其他软件组件(如Keepalived、HAProxy等)一起使用,以构建可扩展的网络架构。