K8S
一、认识
Kubernetes
(简称 K8s
) 是由 Google
开源的、用于容器化应用的自动化部署、扩展和管理的平台。它被设计用于管理大量容器化服务,通过集群的方式协调和编排容器资源,提供高可用性和可扩展性。Kubernetes
是现代应用部署和管理的首选方案。
1.1 Kubernetes 工作机制
Kubernetes
的工作机制涉及到其多个核心组件和资源
一、Kubernetes
架构: Kubernetes
的架构是由多个组件组成的,这些组件协调合作,提供容器的部署、管理和运维功能。
1.1 集群架构:
-
Master
节点(控制平面):控制集群的状态并提供API
服务。Master
节点主要管理以下组件:-
API Server
:是Kubernetes
的控制入口,负责接收和处理API
请求,集群所有的操作都通过API Server
与其他组件进行交互。 -
Controller Manager
:负责执行集群的控制循环(如Pod
的副本控制、节点管理等),确保集群的目标状态与实际状态一致。 -
Scheduler
:负责将Pod
调度到合适的节点上,依据资源需求、节点的状态等条件来选择最优节点。 -
etcd
:Kubernetes
的分布式键值存储,存储集群的所有配置和状态信息,是集群的核心数据存储。
-
-
Node
节点:是集群中运行容器的工作机器,每个节点都有以下组件:-
Kubelet
:负责维护节点上Pod
的生命周期,确保容器运行在节点上,并且与API Server
保持同步。 -
Kube Proxy
:负责实现集群内的网络负载均衡,帮助Pod
之间进行通信。 -
Container Runtime
:负责实际运行容器,常见的容器运行时有Docker
、Containerd
等。
-
1.2 资源对象: Kubernetes
中的所有工作都基于资源对象进行管理,常见的资源对象包括:
-
Pod
:是Kubernetes
的最小部署单元,一个Pod
可以包含一个或多个容器。Kubernetes
通过Pod
来管理容器的生命周期。 -
Service
:为一组Pod
提供统一的网络访问入口,通过负载均衡和服务发现将流量路由到合适的 Pod。 -
Deployment
:控制Pod
的副本数和版本,支持滚动更新和回滚。 -
ConfigMap
和Secret
:分别用于存储非敏感配置和敏感信息,如数据库密码。 -
Namespace
:提供了一个逻辑上的隔离,可以在一个集群中创建多个 Namespace,避免资源冲突。
二、Kubernetes
的工作机制: Kubernetes
的工作机制依赖于声明式的配置和控制循环,核心理念是通过 控制器(Controller
) 确保集群的实际状态和期望状态一致。
声明式配置: Kubernetes
采用声明式配置,用户描述期望的集群状态(例如:部署多少个 Pod
、使用多少个副本),然后 Kubernetes
根据这些期望的状态自动进行调整。例如,通过创建一个 Deployment
来指定希望运行的 Pod
副本数,Kubernetes
会确保实际运行的 Pod
数量与期望的副本数保持一致。
控制循环: Kubernetes
的 控制器(Controller
)是一个不断运行的后台进程,它监视集群的状态并确保系统的实际状态符合期望状态。控制器通过读取集群的状态,判断是否满足用户指定的目标,若不满足则进行相应的调整。
-
ReplicaSet Controller
:如果实际的Pod
副本数低于期望的副本数,ReplicaSet
会自动启动新的Pod
;如果副本数过多,它会删除多余的Pod
。 -
Deployment Controller
:管理应用程序的部署过程,当更新时,Kubernetes
会按顺序滚动更新Pod
,以确保无缝地迁移到新版本。
调度与资源分配: Kubernetes
使用调度器(Scheduler
)来根据集群资源(如 CPU
、内存)和节点的状态将 Pod
调度到合适的节点上。调度器考虑以下因素来选择最合适的节点:
-
资源请求与限制:每个 · 会请求特定数量的资源(如 · 和内存),调度器会根据节点的资源可用性进行调度。
-
节点亲和性与反亲和性:通过配置
Node Affinity
和Pod Affinity
,Kubernetes
可以确保Pod
部署在合适的节点上。 -
Taints
和Tolerations
:用于节点和Pod
之间的约束,确保Pod
不会调度到某些特定的节点上。
自动化管理:
-
滚动更新:
Kubernetes
支持滚动更新,可以确保在更新应用时不会造成服务中断。例如,使用Deployment
更新一个应用时,Kubernetes
会先启动新的Pod
实例,等其就绪后再停止旧的实例,保证应用持续可用。 -
Pod
自动恢复:Kubernetes
通过健康检查(LivenessProbe
和ReadinessProbe
)来确保容器健康。如果容器崩溃或无法响应,Kubernetes
会自动重启容器或替换故障Pod
。 -
自动扩展:
Kubernetes
提供Horizontal Pod Autoscaler(HPA)
和Cluster Autoscaler
,能够根据CPU
、内存使用率等自动扩展Pod
数量或节点数量。
1.2 如何使用 Kubernetes 部署 Node 服务?
本文基于 Kubernetes
部署 Node.js
服务,具体方案如下:
-
基于
Jenkins
来触发Node
服务构建, 拉取代码、安装依赖、构建Docker
镜像,推送镜像到镜像仓库。并且,在测试环境针对构建流水线进行优化,基于WebHook
和Jenkins Pipeline
代码提交后自动触发构建,减少人工操作。 -
Secret/ConfigMap
: 配置分离,ConfigMap
用于存储服务端非敏感配置数据,Secret
安全管理敏感信息,如数据库密码。在Deployment template spec
中通过env valueFrom
将Secret/ConfigMap
映射为环境变量或者通过volumeMounts
将配置以文件形式挂载到容器内。 -
Service
: 使用NodePort
或LoadBalancer
将服务暴露给外部,并结合ReadinessProbe
确保Service
仅将流量分发给健康的Pod
, 保证服务稳定和服务高可用。ClusterIP
仅集群内访问,适合内部服务。NodePort
暴露服务给外部,但端口范围有限。LoadBalancer
结合云厂商实现外部访问的负载均衡。Pod
启动后,Kubernetes
会开始执行ReadinessProbe
。如果检查成功,Pod
被标记为Ready
,并被加入到Service
的Endpoints
列表中,开始接收流量。如果ReadinessProbe
检查失败,Pod
会从Endpoints
列表中移除,Service
不再将流量路由到该Pod
,直到探针成功。一旦ReadinessProbe
成功,Pod
会被重新添加到Endpoints
列表,开始接收流量。 -
Ingress
: 基于NGINX Ingress Controller
部署服务,通过路径和域名规则进行流量分发,并结合cert-manager
自动化申请TLS
证书,实现安全的HTTPS
访问。基于路径(如/api
转发到API
服务)。基于域名(如api.example.com
转发到后端服务)。使用cert-manager
自动化管理TLS
证书,保障HTTPS
安全通信。 -
Deployment
: 配置replicas
使用多副本部署,保证服务不会因单个Pod
故障而中断。配置LivenessProbe
自动检测不健康的容器并重启, 使服务具有故障恢复的功能。配置ReadinessProbe
确保服务准备好接收流量, 做好负载准备。设置resources
限制资源使用,防止资源耗尽。基于Pod Anti-Affinity
和nodeAffinity
将副本分布在不同节点,避免单点故障,做到服务容灾和高可用。Pod
启动后,Kubernetes
会开始执行ReadinessProbe
。如果检查成功,Pod
被标记为Ready
,并被加入到Service
的Endpoints
列表中,开始接收流量。如果ReadinessProbe
检查失败,Pod
会从Endpoints
列表中移除,Service
不再将流量路由到该Pod
,直到探针成功。一旦ReadinessProbe
成功,Pod
会被重新添加到Endpoints
列表,开始接收流量。ReadinessProbe
不等同于LivenessProbe
:ReadinessProbe
是用来检查Pod
是否准备好接收流量,而LivenessProbe
用来检查Pod
是否仍然存活。如果LivenessProbe
失败,Pod
会被重新启动,但它仍然可能处于Not Ready
状态,直到ReadinessProbe
成功。 -
Horizontal Pod Autoscaler (HPA)
: 通过HPA
基于CPU
和内存使用率动态扩展Pod
,并结合Prometheus Adapter
支持获取Prometheus
自定义指标,HPA
使用这些自定义指标来自动扩展Pod
,提升资源利用率。对于突发流量,可与Cluster Autoscaler
根据Pod
扩容自动增加或减少节点,联动扩展节点资源以解决节点资源不足的问题。以下是一些Prometheus
自定义的监控指标:QPS
:监控每秒请求数,查看是否达到了扩容阈值。内存使用量:确保在Pod
扩容后,内存使用量在可控范围内,避免内存泄漏或资源过度使用。节点资源:监控节点的CPU
和内存使用情况,确保节点资源在扩容时得以充分利用。通过这些监控,可以调整Prometheus Adapter
和HPA
配置,确保扩容逻辑符合业务需求,并避免资源浪费。 -
日志管理、监控、调优: 使用
Prometheus
和Grafana
监控服务性能指标,如CPU
、内存、响应时间 等。同时通过EFK
日志管理方案,集中存储和分析日志,快速定位问题。自定义指标(如CPU
、内存使用率、响应时间、请求错误率)接入Prometheus
, 通过Grafana
仪表盘实时监控服务状态。Fluentd
采集日志,过滤、转换后发送到Elasticsearch
。Kibana
用于搜索和可视化日志。
1.3 为什么使用 Kubernetes 部署 Node 服务?
使用 Kubernetes
部署 Node.js
服务,主要是因为它解决了传统服务部署中面临的 资源管理、弹性伸缩、可用性、容器编排 等问题。具体原因包括:
-
高可用与自动恢复:
Kubernetes
提供 自愈机制,如LivenessProbe
和ReadinessProbe
,当Node
服务出现异常时,可以自动重启容器,确保服务持续运行,避免人工干预。 -
弹性伸缩: 通过
HPA(Horizontal Pod Autoscaler)
和自定义指标(如QPS
、CPU
/内存使用率),可以实现对Node
服务的 自动扩容与缩容,满足突发流量需求并提升资源利用率。 -
负载均衡与流量管理: 使用
Kubernetes Service
和Ingress
可以轻松实现服务的负载均衡和流量分发,保证服务高可用,同时支持基于路径或域名的流量转发。 -
配置管理:
Kubernetes
提供ConfigMap
和Secret
,将服务的配置与代码分离,使Node.js
服务的敏感信息和非敏感配置更加安全、灵活地进行管理。 -
容器编排与管理:
Kubernetes
可以统一管理多个容器化的Node
服务,确保其在不同节点上分布均匀,同时提供Pod Anti-Affinity
避免单点故障,提升服务可靠性。 -
自动部署与持续集成/持续部署(
CI/CD
): 结合Jenkins
、Helm
等工具,可以实现Node
服务的自动构建、打包、部署和更新,提高发布效率,降低手动操作的出错率。 -
资源管理与优化:
Kubernetes
提供了 资源请求和限制 的功能,可以合理分配CPU
和内存资源,防止Node.js
服务耗尽节点资源,导致服务崩溃。Kubernetes
通过 资源限制(Limits
) 与 资源请求(Requests
) 确保资源分配合理,Pod
可以根据节点资源动态调度。 -
统一监控与日志管理: 使用
Prometheus
、Grafana
、EFK
等工具,可以轻松实现对Node
服务的监控和日志收集,帮助运维人员快速定位和解决问题。
1.4 Kubernetes 部署 Node Vs PM2 部署 Node
PM2
是一个流行的进程管理工具,专门用于管理 Node.js
应用程序。虽然 PM2
对于 Node.js
应用的部署与管理非常有效,但相比于 Kubernetes
,PM2
更适用于单机环境或者较小的服务集群。以下是二者的主要区别和优势对比:
PM2
:PM2
主要用于单节点的进程管理,虽然支持多进程模式(通过 pm2 scale
命令),但其本质上是管理本地机器上的 Node.js
进程,不能自动扩展到多个机器,也无法进行跨节点的服务管理。
Kubernetes
:Kubernetes
是一个分布式系统平台,能够管理跨多个节点的服务部署、扩展和管理。通过 Pods
、Deployments
和 ReplicaSets
,可以轻松实现自动扩容、滚动更新、负载均衡等功能,适用于大规模分布式应用。
如果你的应用规模较小,PM2
是一个简单有效的进程管理工具,而如果你面临的是大规模、分布式的 Node
服务部署,Kubernetes
提供的自动化管理、高可用性、资源管理和扩展性优势将显得更加突出。
二、构建镜像
构建 Node.js
服务镜像
2.1 目录结构
backend-server
│── node_modules
│── .dockerignore
│── Dockerfile
│── index.js
└── package.json
2.2 index.js
const Koa = require("koa");
const KoaRouter = require("koa-router");
const port = 3000;
const app = new Koa();
const router = new KoaRouter();
const PORT = process.env.APP_PORT || 3000;
const DB_PASSWORD = process.env.DB_PASSWORD;
console.log("------PORT------", PORT);
console.log("-------DB_PASSWORD--------", DB_PASSWORD);
router.get("/", async (ctx) => {
ctx.body = {
code: 200,
message: "Hello Koa Server 001",
};
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(port, () => {
console.log(`Koa HTTP Server is running on port ${port}`);
});
访问环境变量: 通过 process.env
可以访问 Dockerfile
以及 Deployment env
环境变量。在 Kubernetes
部署中,环境变量的优先级如下:
-
ConfigMap
和Secret
注入的环境变量(最高优先级) -
容器镜像(
Dockerfile
)中的ENV
默认值 -
应用程序代码中的默认值(如 ||
3000
)
2.3 Dockerfile
FROM registry.cn-hangzhou.aliyuncs.com/bolawen/node:22.7.0-linux-arm64
WORKDIR /server
COPY package*.json /server
RUN npm install --registry=https://registry.npmmirror.com
COPY . /server
ENV APP_ENV=test
ENV APP_PORT=3000
ENV DB_PASSWORD=defaultpassword
EXPOSE 3000
CMD ["node","index.js"]
ENV
: ENV
指令设置镜像的默认环境变量值。在 Kubernetes
中运行时,Deployment env
的环境变量会覆盖 Dockerfile
中的默认值。
2.4 .dockerignore
dist
node_modules
2.5 构建并推送镜像
# 构建镜像
docker build -t backend-server:1.0.0 .
# 推送镜像
docker tag backend-server:1.0.0 registry.cn-hangzhou.aliyuncs.com/bolawen/backend-server:1.0.0
docker push registry.cn-hangzhou.aliyuncs.com/bolawen/backend-server:1.0.0
三、部署服务
3.1 Service
创建 backend-server-service.yaml
文件
apiVersion: v1
kind: Service
metadata:
name: backend-server-service
spec:
type: NodePort
selector:
app: backend-server
ports:
- protocol: TCP
port: 3000
targetPort: 3000
流量分发:Service
会自动将流量分发给多个 Pod
,保证高可用。
对外访问:NodePort
允许外部访问服务。
端口映射:将外部请求端口映射到容器内部服务端口。
3.2 Ingress
创建 backend-server-ingress.yaml
文件
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nodejs-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: nodejs.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nodejs-service
port:
number: 80
域名管理:通过域名(nodejs.example.com
)访问服务,更加友好。
负载均衡:Ingress
可以处理负载均衡,分发流量给多个 Pod
。
灵活路由:支持路径规则,例如将 /api
路径转发到特定服务。
3.3 Deployment
创建 backend-server-deployment.yaml
文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-server-deployment
spec:
replicas: 2
selector:
matchLabels:
app: backend-server
template:
metadata:
labels:
app: backend-server
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: In
values:
- worker
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nodejs
topologyKey: "kubernetes.io/hostname"
containers:
- name: backend-server
image: registry.cn-hangzhou.aliyuncs.com/bolawen/backend-server:1.0.3
ports:
- containerPort: 3000
env:
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: backend-server-config-map
key: APP_ENV
- name: APP_PORT
valueFrom:
configMapKeyRef:
name: backend-server-config-map
key: APP_PORT
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: backend-server-secret
key: DB_PASSWORD
resources:
requests:
cpu: "250m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
高可用:使用多副本部署,保证服务不会因单个 Pod
故障而中断。
故障恢复:LivenessProbe
自动检测不健康的容器并重启。
负载准备:ReadinessProbe
确保服务准备好接收流量。
资源管理:设置 resources
限制资源使用,防止资源耗尽。
容灾:Pod Anti-Affinity
将副本分布在不同节点,避免单点故障。
3.4 Development Secret
创建 backend-server-secret.yaml
文件
apiVersion: v1
kind: Secret
metadata:
name: backend-server-secret
type: Opaque
data:
DB_PASSWORD: cm9vdA==
使用 echo -n "your_value" | base64
将值编码成 base64
。
3.5 Development ConfigMap
创建 backend-server-config-map.yaml
文件
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-server-config-map
data:
APP_PORT: "3000"
APP_ENV: "test"
3.6 Horizontal Pod Autoscaler (HPA)
通过 HPA
基于 CPU
和内存使用率动态扩展 Pod
,并结合 Prometheus Adapter
支持自定义指标扩展,提升资源利用率。对于突发流量,可与 Cluster Autoscaler
联动扩展节点资源。使用 Prometheus Adapter
实现自定义监控指标(如 QPS
、内存 等)的 HPA
扩展。结合 Cluster Autoscaler
扩展节点,解决 Pod
扩容后节点资源不足的问题。
1. 配置 HPA
基于 CPU
和内存使用率动态扩展 Pod
创建 backend-server-hpa.yaml
配置文件
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: my-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend-server-deployment
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
2. 安装和配置 Prometheus Adapter
: Prometheus Adapter
允许 Kubernetes Horizontal Pod Autoscaler (HPA)
基于自定义指标(如 QPS
、内存等)进行扩容。它将 Prometheus
中收集到的自定义指标映射到 Kubernetes
内部指标,供 HPA
使用。Prometheus Adapter
将会将 Prometheus
中的监控指标暴露给 HPA
使用。配置 prometheus-adapter
以便它能够获取 Prometheus
中的自定义指标。你可以通过修改 prometheus-adapter
的 ConfigMap
来指定 Prometheus
查询规则(PromQL
),并将这些指标暴露给 Kubernetes API
。
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 安装 Prometheus Adapter
helm install prometheus-adapter prometheus-community/prometheus-adapter \
--namespace monitoring
创建 backend-server-prometheus-adapter-config-map.yaml
文件
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-adapter-config
namespace: monitoring
data:
config.yaml: |
rules:
- seriesQuery: 'http_requests_total{job="api"}'
resources:
overrides:
namespace:
resource: namespace
pod:
resource: pod
name:
matches: "^http_requests_total$"
as: "qps"
metricsQuery: 'sum(rate(http_requests_total{job="api"}[1m])) by (pod)'
- seriesQuery: 'container_memory_usage_bytes{container!="",pod!="",job="kubelet"}'
resources:
overrides:
pod:
resource: pod
name:
matches: "^container_memory_usage_bytes$"
as: "memory_usage_bytes"
metricsQuery: 'sum(container_memory_usage_bytes{job="kubelet",pod=~".*"}) by (pod)'
在上面的配置中,我们定义了两个指标:
qps
:基于 http_requests_total
度量计算每秒请求数。
memory_usage_bytes
:获取 Pod
内存使用量。
3. 为 HPA
配置自定义指标: 在 Prometheus Adapter
配置好之后,你可以在 HPA
的配置中引用这些自定义指标。下面是一个 HPA
配置示例,基于 qps
和 memory_usage_bytes
来调整 Pod
副本数。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: node-service-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: node-service
minReplicas: 1
maxReplicas: 10
metrics:
- type: External
external:
metric:
name: qps
selector:
matchLabels:
pod: "node-service"
target:
type: AverageValue
averageValue: "100" # 设置 QPS 达到 100 时扩容
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80 # 内存使用率达到 80% 时扩容
在上面的示例中:
qps
:当 QPS
达到 100
时,HPA
会触发扩容。
memory
:当内存使用率达到 80%
时,HPA
会触发扩容。
- 安装和配置
Cluster Autoscaler
:Cluster Autoscaler
是一个Kubernetes
集群组件,用于自动增加或减少集群中的节点数。如果HPA
扩容导致资源需求超过当前节点的容量,Cluster Autoscaler
会自动扩展节点以满足新增加的Pod
的资源需求。
Cluster Autoscaler
可以通过 Helm
安装或直接使用 Kubernetes
的 YAML
配置进行部署。
helm repo add autoscaler https://kubernetes.github.io/autoscaler
helm repo update
helm install cluster-autoscaler autoscaler/cluster-autoscaler \
--namespace kube-system \
--set autoDiscovery.clusterName=<your-cluster-name> \
--set awsRegion=<your-region> # 根据你的云提供商和区域配置
Cluster Autoscaler
根据节点资源和 Pod
的需求来决定是否需要扩展集群。你需要确保集群节点支持扩容,且各节点具备合适的资源限制和配额。Cluster Autoscaler
的配置会根据以下规则自动扩展集群:
-
当
HPA
扩容Pod
时,如果现有节点无法满足新增Pod
的资源需求,Cluster Autoscaler
会自动添加更多节点。 -
当某些
Pod
被缩减时,如果某些节点上的Pod
不再需要资源,Cluster Autoscaler
会自动删除空闲节点以节省资源。
3.7 应用以上配置文件
kubectl apply -f backend-server-config-map.yaml
kubectl apply -f backend-server-secret.yaml
kubectl apply -f backend-server-service.yaml
kubectl apply -f backend-server-deployment.yaml
四、访问服务
4.1 检测资源状态
# 查看 Pod 状态
kubectl get pods
# 查看 Deployment 状态
kubectl get deployments
# 查看 Service 状态
kubectl get services
4.2 NodePort 访问服务
1. 通过 kubectl describe pod [Pod Name]
获取 NodeIP
kubectl describe pod [Pod Name]
# 输出
Name: backend-server-deployment-64df744d7c-mcns7
Namespace: default
Priority: 0
Service Account: default
Node: k8s-node1/192.168.105.133
Start Time: Wed, 04 Dec 2024 20:16:41 +0800
Labels: app=backend-server
2. 通过 kubectl get services
获取 NodePort
端口
kubectl get services
# 输出
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
node-app-service NodePort 10.108.73.245 <none> 80:30007/TCP 2m
3. 使用集群节点的 IP
地址访问服务
http://<Node-IP>:<NodePort>
# 比如:
http://192.168.105.133:32490/