k8s分享
# 一. Kubernetes 简介和背景
传统部署
无法为物理服务器中的应用程序定义资源边界
当一个服务器部署多个应用时,可能存在一个应用大量占用资源而导致另一个应用运行受影响
当每台服务器运行一个应用时,存在资源浪费以及物理服务器维护成本很高
虚拟化部署
● 缺点:增加了操作系统,浪费了部分资源
容器化部署
一个容器故障停机了,无法做到立刻启动另一个容器修复
当应用的并发访问量变大的时候,横向扩展容器数量麻烦
Kubernetes(常简称为K8s)是一个开源的容器编排和管理平台,用于自动化应用程序的部署、扩展和操作。它可以管理跨多个主机的容器化应用,提供了一种简化和自动化容器化应用程序的管理方式。
在容器部署的基础上,有下面的一些特殊功能
● (1)自我修复:一旦某个容器崩溃,能够再1秒中左右迅速启动新的容器 ● (2)弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整 ● (3)服务发现:服务可以通过自动发现的形式找到它所依赖的服务 ● (4)负载均衡:如果一个服务启动了多个容器,能够自动实现请求的负载均衡 ● (5)版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本 …………
# 二. Kubernetes 架构:
# 1. Master
kube-apiserver(API Server): kube-apiserver 是 Kubernetes 的 API 入口,接收来自用户、客户端和其它组件的 API 请求,并将其分发到适当的组件进行处理。它是集群的控制中心。
kube-controller-manager(Controller Manager): kube-controller-manager 监控集群中的资源状态,并根据定义的期望状态来自动调整系统状态。例如,ReplicaSet、Deployment、Service 等控制器都属于这个组件的管理范畴。
kube-scheduler(Scheduler): kube-scheduler 负责将未分配的 Pod 调度到适当的 Worker 节点上,考虑到资源需求、硬件约束和亲和性等因素,以确保集群的均衡和高效。
etcd: etcd 是一个高可用的分布式键值存储,用于存储 Kubernetes 集群的所有配置数据、状态信息和元数据。所有 Master 节点共享同一个 etcd 集群。
cloud-controller-manager:主要目的是将云服务提供商相关的逻辑与 Kubernetes 核心代码进行分离。这样做的好处是,可以将云特定的操作和资源管理与 Kubernetes 的核心逻辑隔离开来,使 Kubernetes 的核心代码更加稳定和通用。同时,它也允许云提供商根据其平台的特性进行定制和优化。
# 2. node
kubelet: kubelet 是每个 Worker 节点上的代理,负责监控该节点上的 Pod,并确保 Pod 的容器处于预期的状态。它会与 Master 节点中的 kube-apiserver 通
信以获取分配给它的 Pod。
kube-proxy: kube-proxy 负责维护节点上的网络代理,它管理集群中的网络规则,以便允许集群内的 Pod 与外部网络和其它 Pod 进行通信。
容器运行时(如 Docker): Worker 节点上的容器运行时负责启动和管理容器。它负责拉取容器镜像、创建容器、监控容器状态,并处理容器生命周期。
Pod: Pod 是 Kubernetes 中最小的可调度单元,一个 Pod 中可以包含一个或多个容器。Worker 节点托管这些 Pod 的容器,保证它们在正确的节点上运
行。
# 三. Kubernetes 核心概念:
# 1. Pod
是 Kubernetes 中最小的可部署的计算单元。它可以包含一个或多个容器,这些容器共享相同的网络命名空间、存储和其他资源。
一个node可以包含多个Pod,一个Pod里可以运行多个容器
资源清单
apiVersion: v1 # 指定 Kubernetes API 版本,这里是 v1,表示使用的是 Kubernetes 的核心 API 版本。
kind: Pod #资源类型:可以指定Pod、Service、deployment、ingress等等
metadata: # 当前属性的一些元数据
name: nginx-demo
labels:
type: "1"
version: "1"
namespace: default # 指定所属的命名空间
spec: # 对象规约
containers: # 定义容器
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent # Always、Never 、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 #将容器的80端口映射到主机的一个随机端口
protocol: TCP
env: # 定义容器的环境变量
- name: JVM_OPTS
value: "-Xms128m -Xms128m"
restartPolicy: OnFailure # Aways、Never、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
探针:
- startupProbe
- livenessProbe
- readinessProbe
探测方式:
httpGet方式
tcpSocket方式
exec方式
startupProbe:
httpGet:
path: /index.html
port: 80
failureThreshold: 3
successThreshold: 1
periodSeconds: 10
timeoutSeconds: 5
2
3
4
5
6
7
8
# 2. 控制器
- 副本
在 Kubernetes 中,"副本"(Replica)是指具有相同配置和功能的 Pod 的集合。副本的引入是为了增加应用程序的可用性和容错性。通过创建多个相同配置的 Pod 副本,即使某个 Pod 发生故障或不可用,其他副本仍然可以继续提供服务。
控制器是一种用于管理和维护副本数目的对象,以确保所需的副本数一直保持在集群中运行。控制器是为了简化管理和维护多个副本的任务而引入的概念。
控制器与 Pod 之间的关系是,控制器是用来管理 Pod 副本的。它负责确保指定的副本数一直保持在运行状态,如果有副本数量不足,则会自动创建新的副本,反之如果超过了指定的副本数,则会停止多余的副本。这样可以实现自动的容错和扩展。
# ①ReplicaSet
确保一定数量的 Pod 副本在运行中,支持根据标签选择器来管理 Pod 副本。
主要的作用就是确保容器应用的副本数量始终保持一个定义的副本数。
# ②Deployment
在 ReplicaSet 的基础上提供了滚动更新和回滚能力,以便对应用进行升级和降级。
如果对yaml文件进行了修改,Deployment会自动通过滚动更新的方式去更新pod
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
namespace: default
spec:
replicas: 3
revisionHistoryLimit: 10 # 历史保留数,即更新的pod可以进行回滚
selector:
matchLabels:
app: nginx-deploy
strategy:
rollingUpdate:
maxSurge: 25% # 表示在滚动更新过程中,可以超出指定的 replicas 数量的新副本数量,即允许“超出”预期的副本数。
maxUnavailable: 25% # 表示在滚动更新过程中,可以同时不可用的副本数量,即允许“不可用”的副本数。
type: RollingUpdate # RollingUpdate 、 Recreate
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.7.9
imagePullPolicy: IfNotPresent
name: nginx
ports: # Add ports section here
- containerPort: 80 # Define the container port
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
30
31
暂停与恢复:
kubectl rollout pause deployment <name>
暂停
kubectl rollout deployment <name>
恢复
滚动更新
# ③StatefulSet
用于管理有状态应用,确保每个 Pod 都有唯一的标识和稳定的网络标识。
# ④DaemonSet
用于在每个节点上运行一个副本,确保每个节点都有一个副本在运行。
# ⑤Job 和 CronJob
用于管理批处理任务,Job 确保任务完成,CronJob 基于时间表周期性地运行任务。
# 3. Service
- 负载均衡:Service 可以在一组运行相同应用的 Pod 之间进行负载均衡,将传入的请求分发到各个 Pod 上,从而实现请求的分流。
- Pod 发现:Service 提供了一个稳定的虚拟 IP 地址和端口,用于访问一组后端 Pod。这使得应用无需关心 Pod 的 IP 地址和端口号的变化,而只需使用 Service 的虚拟 IP 地址来访问后端服务。
- 外部访问:Service 可以将集群内部的服务暴露给集群外部,通过 NodePort、LoadBalancer 或 Ingress 等方式。这使得外部用户能够访问集群中的应用。
- 跨命名空间访问:Service 可以在同一集群内的不同命名空间之间进行通信。这允许不同命名空间中的应用之间相互访问。
Service如何定义
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx-deploy # 匹配哪些pod会被该service进行代理
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
2
3
4
5
6
7
8
9
10
11
12
type有4种类型:
- ClusterIP
只能在集群内部使用,不配置类型的话默认就是ClusterIP。只是东西流量
- ExternalName
返回定义的CNAME别名和,可以配置为域名
- NodePort
(随机开启一个端口进行映射,该端口是直接绑定在node上的,且集群中的每一个node都会绑定在这个端口【相当于可以将pod服务暴露给外部进行访问,但是实际生产不会使用,效率较低,而且是四层负载】)
NodePort 是一种 Service 类型,它允许你将应用程序暴露到集群节点的特定端口上。当你创建一个 NodePort 类型的 Service 时,Kubernetes 会在每个节点上打开一个随机的端口,然后将该端口映射到 Service 中定义的目标端口(通常是 Pod 中容器的端口)。这样,你可以通过访问集群节点的 IP 地址和映射的端口来访问 Service。
举个例子,如果你创建了一个 NodePort 类型的 Service,并将目标端口设置为 80,Kubernetes 会为每个节点打开一个随机的端口(比如 30000-32767 范围内的端口),然后将该端口映射到 Pod 中容器的 80 端口。这样,你可以通过访问任何节点的 IP 地址和映射的端口(例如
http://node-ip:node-port
)来访问 Service 中的应用程序。
- LoadBalancer
使用云服务商提供的负载均衡器服务
- 相关命令
kubectl get svc <name>
# pod之间进行访问
是怎么运作的呢?
通过kubectl找到了server-api,再通过server-api找到对应的service,再通过service找到挂在的nginx。
通过wget在本地的iptables找到service
当然,跨命名空间也是可以访问的,可以在servicename的后面加上对应的命名空间的名字:例如http://nginx-service.default 也可以.
# pod访问外部网络
以上都是实现的集群内部的各个pod之间通过服务名进行访问,那可以实现集群内部pod访问k8s集群外的其他服务吗?【理解:内部的pod是可以访问互联网,比如访问www.baidu.com,这个是可以的。但是如果是我们自己的mysql服务,这时候我们就需要在pod的java项目里面写上对应的ip。但是肯定不能写ip吧,我们希望写一个服务名,这样以后ip地址变了,但是服务名就不用更改,现在我们的需求就是通过服务名,pod能不能访问到集群外部的服务】
实现具体方式
- 编写service配置文件时,不指定selector属性
- 自己来创建endpoint配置【为什么自己创建endpoint呢,因为当使用selector时,自动创建的是内部ip与服务名的绑定,现在我们想让外部ip与服务名绑定,我们需要自己写endpoint才行】
创建成功后,我们可以通过kubectl get svc
kubectl get ep
查看相应的信息
然后会发现,我们新创建的svc没有对应的ep,所以我们这个时候来创建对应的ep
ep也是一种对应的资源,也需要写相应的yaml文件
apiVersion: v1
kind: Endpoints
metadata:
labels:
app: nginx
name: nginx-svc-external
namespace: default
subsets:
- addresses:
- ip: 120.78.159.117
ports:
- name: web
port: 80
protocal: TCP
2
3
4
5
6
7
8
9
10
11
12
13
14
15
然后进行创建,然后我们查看详细信息,就可以对应了。
测试,进入pod容器,使用wget http://nginx-svc-external, 就可以访问成功
# 外部网络访问Pod
需要使用特殊的应用Ingress