|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在当今快速发展的软件开发领域,微服务架构已经成为构建复杂应用的主流方式。而Kubernetes作为容器编排的事实标准,为微服务部署、扩展和管理提供了强大的平台。本文将带你从零开始,逐步掌握Kubernetes的核心概念和操作技巧,帮助你解决在实际开发中遇到的微服务部署与管理问题。
无论你是初学者还是有一定经验的开发者,本文都将提供实用的指导和最佳实践,让你能够自信地在Kubernetes上部署和管理微服务应用。
Kubernetes基础
什么是Kubernetes?
Kubernetes(常简称为K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它最初由Google设计,现在由云原生计算基金会(CNCF)维护。
Kubernetes提供了以下核心功能:
• 自动化容器部署和复制
• 容器的弹性伸缩
• 容器间的负载均衡
• 跨节点调度
• 自愈能力(自动重启失败的容器)
• 滚动更新和回滚
• 配置和密钥管理
Kubernetes架构
Kubernetes由两个主要部分组成:控制平面(Control Plane)和工作节点(Worker Nodes)。
控制平面负责管理集群,它包含以下组件:
• kube-apiserver:API服务器,是Kubernetes控制平面的前端,所有组件都通过它进行交互。
• etcd:分布式键值存储,用于保存集群的所有配置数据和状态。
• kube-scheduler:调度器,负责决定将Pod放置在哪个节点上。
• kube-controller-manager:控制器管理器,运行控制器进程,处理集群中的常规任务。
• cloud-controller-manager:云控制器管理器,与云服务提供商交互。
工作节点是运行应用程序的机器,每个节点包含以下组件:
• kubelet:确保容器在Pod中运行。
• kube-proxy:维护节点上的网络规则,实现服务通信。
• 容器运行时:如Docker、containerd等,负责运行容器。
核心概念
在深入Kubernetes之前,我们需要了解一些核心概念:
• Pod:Kubernetes中最小的可部署单元,包含一个或多个容器。
• Service:为一组Pod提供统一的访问入口,实现服务发现和负载均衡。
• Deployment:管理Pod的部署和更新,提供声明式的更新方式。
• Namespace:将集群划分为多个虚拟集群,用于资源隔离。
• ConfigMap:存储非机密的配置数据。
• Secret:存储敏感数据,如密码、API密钥等。
• Ingress:管理集群外部访问集群内部服务的规则。
• PersistentVolume:持久化存储,独立于Pod的生命周期。
• StatefulSet:用于管理有状态应用的工作负载API对象。
环境搭建
本地开发环境
对于初学者,搭建本地Kubernetes开发环境是学习的第一步。以下是几种常见的选择:
Minikube是一个工具,可以在本地运行单节点Kubernetes集群。
安装Minikube:
在macOS上使用Homebrew安装:
在Windows上使用Chocolatey安装:
在Linux上下载二进制文件:
- curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
- sudo install minikube-linux-amd64 /usr/local/bin/minikube
复制代码
启动Minikube:
- minikube start --driver=docker
复制代码
验证Minikube状态:
Docker Desktop内置了Kubernetes支持,是Windows和macOS用户的便捷选择。
启用Kubernetes:
1. 打开Docker Desktop
2. 进入Settings > Kubernetes
3. 勾选”Enable Kubernetes”
4. 点击”Apply & Restart”
Kind是一个使用Docker容器作为节点的Kubernetes集群工具。
安装Kind:
- # 对于macOS
- brew install kind
- # 对于Windows
- choco install kind
- # 对于Linux
- curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64
- chmod +x ./kind
- sudo mv ./kind /usr/local/bin/kind
复制代码
创建集群:
云环境
除了本地环境,你也可以在云平台上搭建Kubernetes集群:
- # 安装gcloud CLI
- # 创建集群
- gcloud container clusters create my-cluster --zone us-central1-a --num-nodes 2
- # 获取凭证
- gcloud container clusters get-credentials my-cluster --zone us-central1-a
复制代码- # 安装eksctl
- # 创建集群
- eksctl create cluster --name my-cluster --region us-west-2 --node-type t3.medium --nodes 2
复制代码- # 安装az CLI
- # 创建资源组
- az group create --name myResourceGroup --location eastus
- # 创建集群
- az aks create --resource-group myResourceGroup --name myAKSCluster --node-count 2 --enable-addons monitoring --generate-ssh-keys
复制代码
安装kubectl
kubectl是Kubernetes的命令行工具,用于与Kubernetes集群交互。
安装kubectl:
在macOS上使用Homebrew:
在Windows上使用Chocolatey:
- choco install kubernetes-cli
复制代码
在Linux上:
- curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
- sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
复制代码
验证安装:
微服务容器化
在将微服务部署到Kubernetes之前,首先需要将应用容器化。容器化的过程通常涉及创建Dockerfile,然后构建Docker镜像。
创建Dockerfile
Dockerfile是一个文本文件,包含了构建Docker镜像的所有命令。以下是一个简单的Spring Boot应用的Dockerfile示例:
- # 使用官方OpenJDK镜像作为基础镜像
- FROM openjdk:11-jre-slim
- # 设置工作目录
- WORKDIR /app
- # 复制构建好的JAR文件到容器中
- COPY target/my-service-0.0.1-SNAPSHOT.jar app.jar
- # 暴露应用端口
- EXPOSE 8080
- # 设置JVM参数
- ENV JAVA_OPTS="-Xmx512m -Xms256m"
- # 启动命令
- ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
复制代码
对于Node.js应用,Dockerfile可能如下所示:
- # 使用官方Node.js镜像作为基础镜像
- FROM node:14-alpine
- # 设置工作目录
- WORKDIR /app
- # 复制package.json和package-lock.json
- COPY package*.json ./
- # 安装依赖
- RUN npm ci --only=production
- # 复制应用代码
- COPY . .
- # 暴露应用端口
- EXPOSE 3000
- # 启动命令
- CMD ["node", "index.js"]
复制代码
构建Docker镜像
创建好Dockerfile后,可以使用Docker命令构建镜像:
- # 构建镜像
- docker build -t my-username/my-service:0.0.1 .
- # 运行容器测试
- docker run -p 8080:8080 my-username/my-service:0.0.1
复制代码
推送镜像到镜像仓库
构建好的镜像需要推送到镜像仓库,以便Kubernetes可以拉取并使用。常用的镜像仓库包括Docker Hub、Google Container Registry (GCR)、Amazon Elastic Container Registry (ECR)等。
推送到Docker Hub:
- # 登录Docker Hub
- docker login
- # 标记镜像
- docker tag my-username/my-service:0.0.1 my-username/my-service:latest
- # 推送镜像
- docker push my-username/my-service:0.0.1
- docker push my-username/my-service:latest
复制代码
推送到GCR:
- # 配置gcloud CLI
- gcloud auth configure-docker
- # 标记镜像
- docker tag my-username/my-service:0.0.1 gcr.io/my-project/my-service:0.0.1
- # 推送镜像
- docker push gcr.io/my-project/my-service:0.0.1
复制代码
多阶段构建
为了减小镜像大小并提高安全性,可以使用多阶段构建。以下是一个Java应用的多阶段构建示例:
- # 第一阶段:构建应用
- FROM maven:3.6.3-openjdk-11 AS build
- WORKDIR /app
- COPY pom.xml .
- COPY src ./src
- RUN mvn clean package -DskipTests
- # 第二阶段:创建运行时镜像
- FROM openjdk:11-jre-slim
- WORKDIR /app
- COPY --from=build /app/target/my-service-0.0.1-SNAPSHOT.jar app.jar
- EXPOSE 8080
- ENTRYPOINT ["java", "-jar", "app.jar"]
复制代码
优化镜像大小
优化Docker镜像大小有几个好处:
• 减少存储空间占用
• 加快部署速度
• 减少安全漏洞的攻击面
以下是一些优化技巧:
1. 使用合适的基础镜像:选择alpine或slim版本的基础镜像。
2. 多阶段构建:如上所述,分离构建环境和运行环境。
3. 合并RUN命令:减少镜像层数。
4. 清理不必要的文件:在构建过程中删除临时文件。
5. 使用.dockerignore文件:排除不必要的文件。
示例.dockerignore文件:
- .git
- .gitignore
- node_modules
- npm-debug.log
- Dockerfile
- README.md
- .env
- target
复制代码
Kubernetes资源对象
Pod
Pod是Kubernetes中最小的可部署单元,包含一个或多个容器。Pod中的容器共享网络命名空间和存储卷。
Pod定义示例:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- labels:
- app: my-app
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:0.0.1
- ports:
- - containerPort: 8080
- env:
- - name: ENVIRONMENT
- value: "production"
- resources:
- requests:
- memory: "256Mi"
- cpu: "250m"
- limits:
- memory: "512Mi"
- cpu: "500m"
复制代码
创建Pod:
- kubectl apply -f pod.yaml
复制代码
查看Pod:
- kubectl get pods
- kubectl describe pod my-pod
复制代码
查看Pod日志:
进入Pod容器:
- kubectl exec -it my-pod -- /bin/bash
复制代码
删除Pod:
- kubectl delete pod my-pod
复制代码
Deployment
Deployment管理Pod的部署和更新,提供声明式的更新方式。它确保指定数量的Pod副本在运行,并支持滚动更新和回滚。
Deployment定义示例:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: my-app
- template:
- metadata:
- labels:
- app: my-app
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:0.0.1
- ports:
- - containerPort: 8080
- env:
- - name: ENVIRONMENT
- value: "production"
- resources:
- requests:
- memory: "256Mi"
- cpu: "250m"
- limits:
- memory: "512Mi"
- cpu: "500m"
复制代码
创建Deployment:
- kubectl apply -f deployment.yaml
复制代码
查看Deployment:
- kubectl get deployments
- kubectl describe deployment my-deployment
复制代码
扩展Deployment:
- kubectl scale deployment my-deployment --replicas=5
复制代码
更新Deployment:
- # 更新镜像版本
- kubectl set image deployment/my-deployment my-container=my-username/my-service:0.0.2
- # 或者直接编辑Deployment
- kubectl edit deployment my-deployment
复制代码
回滚Deployment:
- # 查看更新历史
- kubectl rollout history deployment/my-deployment
- # 回滚到上一个版本
- kubectl rollout undo deployment/my-deployment
- # 回滚到指定版本
- kubectl rollout undo deployment/my-deployment --to-revision=1
复制代码
Service
Service为一组Pod提供统一的访问入口,实现服务发现和负载均衡。
Service定义示例:
- apiVersion: v1
- kind: Service
- metadata:
- name: my-service
- spec:
- selector:
- app: my-app
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: LoadBalancer
复制代码
Service有几种类型:
• ClusterIP:默认类型,在集群内部暴露服务。
• NodePort:在每个节点的固定端口暴露服务。
• LoadBalancer:使用云提供商的负载均衡器暴露服务。
• ExternalName:将服务映射到外部名称。
创建Service:
- kubectl apply -f service.yaml
复制代码
查看Service:
- kubectl get services
- kubectl describe service my-service
复制代码
Ingress
Ingress管理集群外部访问集群内部服务的规则,通常用于暴露HTTP和HTTPS路由。
Ingress定义示例:
- apiVersion: networking.k8s.io/v1
- kind: Ingress
- metadata:
- name: my-ingress
- annotations:
- nginx.ingress.kubernetes.io/rewrite-target: /
- spec:
- rules:
- - http:
- paths:
- - path: /my-app
- pathType: Prefix
- backend:
- service:
- name: my-service
- port:
- number: 80
复制代码
创建Ingress:
- kubectl apply -f ingress.yaml
复制代码
查看Ingress:
- kubectl get ingress
- kubectl describe ingress my-ingress
复制代码
ConfigMap
ConfigMap用于存储非机密的配置数据,可以被Pod挂载为文件或环境变量。
ConfigMap定义示例:
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: my-config
- data:
- application.properties: |
- server.port=8080
- logging.level.root=INFO
- database_url: "jdbc:postgresql://db:5432/mydb"
复制代码
创建ConfigMap:
- kubectl apply -f configmap.yaml
复制代码
在Pod中使用ConfigMap:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:0.0.1
- envFrom:
- - configMapRef:
- name: my-config
- volumeMounts:
- - name: config-volume
- mountPath: /etc/config
- volumes:
- - name: config-volume
- configMap:
- name: my-config
复制代码
Secret
Secret用于存储敏感数据,如密码、API密钥等。
Secret定义示例:
- apiVersion: v1
- kind: Secret
- metadata:
- name: my-secret
- type: Opaque
- data:
- password: cGFzc3dvcmQ= # base64编码的"password"
- api-key: bXlfc2VjcmV0X2FwaV9rZXk= # base64编码的"my_secret_api_key"
复制代码
创建Secret:
- kubectl apply -f secret.yaml
复制代码
在Pod中使用Secret:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:0.0.1
- env:
- - name: DB_PASSWORD
- valueFrom:
- secretKeyRef:
- name: my-secret
- key: password
- volumeMounts:
- - name: secret-volume
- mountPath: /etc/secrets
- volumes:
- - name: secret-volume
- secret:
- secretName: my-secret
复制代码
PersistentVolume
PersistentVolume (PV) 是集群中的一块存储,已经由管理员预先配置或通过存储类动态配置。PV的生命周期独立于使用它的Pod。
PersistentVolume定义示例:
- apiVersion: v1
- kind: PersistentVolume
- metadata:
- name: my-pv
- spec:
- capacity:
- storage: 10Gi
- volumeMode: Filesystem
- accessModes:
- - ReadWriteOnce
- persistentVolumeReclaimPolicy: Retain
- storageClassName: slow
- mountOptions:
- - hard
- - nfsvers=4.1
- nfs:
- path: /tmp
- server: 172.17.0.2
复制代码
PersistentVolumeClaim
PersistentVolumeClaim (PVC) 是用户对存储的请求。PVC消耗PV资源,并可以请求特定的大小和访问模式。
PersistentVolumeClaim定义示例:
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: my-pvc
- spec:
- accessModes:
- - ReadWriteOnce
- volumeMode: Filesystem
- resources:
- requests:
- storage: 8Gi
- storageClassName: slow
复制代码
在Pod中使用PVC:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:0.0.1
- volumeMounts:
- - name: my-storage
- mountPath: /data
- volumes:
- - name: my-storage
- persistentVolumeClaim:
- claimName: my-pvc
复制代码
StatefulSet
StatefulSet用于管理有状态应用的工作负载API对象。它为Pod提供唯一的标识符、稳定的持久存储和有序的部署、扩展和删除。
StatefulSet定义示例:
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: my-statefulset
- spec:
- serviceName: "my-service"
- replicas: 3
- selector:
- matchLabels:
- app: my-app
- template:
- metadata:
- labels:
- app: my-app
- spec:
- containers:
- - name: my-container
- image: my-username/my-stateful-service:0.0.1
- ports:
- - containerPort: 8080
- volumeMounts:
- - name: my-storage
- mountPath: /data
- volumeClaimTemplates:
- - metadata:
- name: my-storage
- spec:
- accessModes: [ "ReadWriteOnce" ]
- storageClassName: "standard"
- resources:
- requests:
- storage: 10Gi
复制代码
微服务部署实战
微服务架构示例
假设我们有一个简单的电商系统,包含以下微服务:
• 用户服务:处理用户认证和用户信息
• 产品服务:管理产品目录
• 订单服务:处理订单创建和管理
• API网关:提供统一的API入口
我们将逐步将这些微服务部署到Kubernetes上。
部署用户服务
首先,我们创建用户服务的Deployment和Service:
user-service-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service-deployment
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: my-username/user-service:1.0.0
- ports:
- - containerPort: 8080
- env:
- - name: DB_HOST
- value: "postgres-service"
- - name: DB_PORT
- value: "5432"
- - name: DB_NAME
- value: "users"
- - name: DB_USER
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: username
- - name: DB_PASSWORD
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: password
- resources:
- requests:
- memory: "256Mi"
- cpu: "250m"
- limits:
- memory: "512Mi"
- cpu: "500m"
- livenessProbe:
- httpGet:
- path: /health
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /ready
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
复制代码
user-service.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: user-service
- spec:
- selector:
- app: user-service
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码
创建用户服务:
- kubectl apply -f user-service-deployment.yaml
- kubectl apply -f user-service.yaml
复制代码
部署产品服务
接下来,部署产品服务:
product-service-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: product-service-deployment
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: product-service
- template:
- metadata:
- labels:
- app: product-service
- spec:
- containers:
- - name: product-service
- image: my-username/product-service:1.0.0
- ports:
- - containerPort: 8080
- env:
- - name: DB_HOST
- value: "mongodb-service"
- - name: DB_PORT
- value: "27017"
- - name: DB_NAME
- value: "products"
- resources:
- requests:
- memory: "256Mi"
- cpu: "250m"
- limits:
- memory: "512Mi"
- cpu: "500m"
- livenessProbe:
- httpGet:
- path: /health
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /ready
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
复制代码
product-service.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: product-service
- spec:
- selector:
- app: product-service
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码
创建产品服务:
- kubectl apply -f product-service-deployment.yaml
- kubectl apply -f product-service.yaml
复制代码
部署订单服务
然后,部署订单服务:
order-service-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: order-service-deployment
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: order-service
- template:
- metadata:
- labels:
- app: order-service
- spec:
- containers:
- - name: order-service
- image: my-username/order-service:1.0.0
- ports:
- - containerPort: 8080
- env:
- - name: DB_HOST
- value: "postgres-service"
- - name: DB_PORT
- value: "5432"
- - name: DB_NAME
- value: "orders"
- - name: USER_SERVICE_URL
- value: "http://user-service"
- - name: PRODUCT_SERVICE_URL
- value: "http://product-service"
- - name: DB_USER
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: username
- - name: DB_PASSWORD
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: password
- resources:
- requests:
- memory: "256Mi"
- cpu: "250m"
- limits:
- memory: "512Mi"
- cpu: "500m"
- livenessProbe:
- httpGet:
- path: /health
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /ready
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
复制代码
order-service.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: order-service
- spec:
- selector:
- app: order-service
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码
创建订单服务:
- kubectl apply -f order-service-deployment.yaml
- kubectl apply -f order-service.yaml
复制代码
部署API网关
最后,部署API网关:
api-gateway-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: api-gateway-deployment
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: api-gateway
- template:
- metadata:
- labels:
- app: api-gateway
- spec:
- containers:
- - name: api-gateway
- image: my-username/api-gateway:1.0.0
- ports:
- - containerPort: 8080
- env:
- - name: USER_SERVICE_URL
- value: "http://user-service"
- - name: PRODUCT_SERVICE_URL
- value: "http://product-service"
- - name: ORDER_SERVICE_URL
- value: "http://order-service"
- resources:
- requests:
- memory: "256Mi"
- cpu: "250m"
- limits:
- memory: "512Mi"
- cpu: "500m"
- livenessProbe:
- httpGet:
- path: /health
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /ready
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
复制代码
api-gateway.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: api-gateway
- spec:
- selector:
- app: api-gateway
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: LoadBalancer
复制代码
创建API网关:
- kubectl apply -f api-gateway-deployment.yaml
- kubectl apply -f api-gateway.yaml
复制代码
部署数据库
我们的微服务需要数据库支持,这里我们部署PostgreSQL和MongoDB:
postgres-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: postgres-deployment
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: postgres
- template:
- metadata:
- labels:
- app: postgres
- spec:
- containers:
- - name: postgres
- image: postgres:13
- ports:
- - containerPort: 5432
- env:
- - name: POSTGRES_USER
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: username
- - name: POSTGRES_PASSWORD
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: password
- volumeMounts:
- - name: postgres-storage
- mountPath: /var/lib/postgresql/data
- volumes:
- - name: postgres-storage
- persistentVolumeClaim:
- claimName: postgres-pvc
复制代码
postgres-service.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: postgres-service
- spec:
- selector:
- app: postgres
- ports:
- - protocol: TCP
- port: 5432
- targetPort: 5432
- type: ClusterIP
复制代码
postgres-pvc.yaml:
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: postgres-pvc
- spec:
- accessModes:
- - ReadWriteOnce
- resources:
- requests:
- storage: 10Gi
复制代码
mongodb-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: mongodb-deployment
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: mongodb
- template:
- metadata:
- labels:
- app: mongodb
- spec:
- containers:
- - name: mongodb
- image: mongo:4.4
- ports:
- - containerPort: 27017
- volumeMounts:
- - name: mongodb-storage
- mountPath: /data/db
- volumes:
- - name: mongodb-storage
- persistentVolumeClaim:
- claimName: mongodb-pvc
复制代码
mongodb-service.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: mongodb-service
- spec:
- selector:
- app: mongodb
- ports:
- - protocol: TCP
- port: 27017
- targetPort: 27017
- type: ClusterIP
复制代码
mongodb-pvc.yaml:
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: mongodb-pvc
- spec:
- accessModes:
- - ReadWriteOnce
- resources:
- requests:
- storage: 10Gi
复制代码
创建数据库:
- kubectl apply -f postgres-pvc.yaml
- kubectl apply -f postgres-deployment.yaml
- kubectl apply -f postgres-service.yaml
- kubectl apply -f mongodb-pvc.yaml
- kubectl apply -f mongodb-deployment.yaml
- kubectl apply -f mongodb-service.yaml
复制代码
创建数据库Secret
我们需要创建一个Secret来存储数据库的凭据:
db-secret.yaml:
- apiVersion: v1
- kind: Secret
- metadata:
- name: db-secret
- type: Opaque
- data:
- username: cG9zdGdyZXM= # base64编码的"postgres"
- password: cG9zdGdyZXNfcGFzc3dvcmQ= # base64编码的"postgres_password"
复制代码
创建Secret:
- kubectl apply -f db-secret.yaml
复制代码
验证部署
部署完成后,我们可以验证所有服务是否正常运行:
- # 查看所有Pod
- kubectl get pods
- # 查看所有Service
- kubectl get services
- # 查看API网关的外部IP
- kubectl get service api-gateway
- # 查看某个Pod的日志
- kubectl logs -f deployment/user-service-deployment
- # 进入Pod进行调试
- kubectl exec -it deployment/user-service-deployment -- /bin/bash
复制代码
配置管理
在微服务架构中,配置管理是一个重要的方面。Kubernetes提供了多种方式来管理配置,包括ConfigMap、Secret和环境变量。
使用ConfigMap管理配置
ConfigMap允许我们将配置数据与容器镜像分离,使应用更具可移植性。
假设我们有一个应用配置文件application.properties:
- server.port=8080
- logging.level.root=INFO
- spring.datasource.url=jdbc:postgresql://postgres-service:5432/mydb
- spring.datasource.username=postgres
- spring.datasource.password=${DB_PASSWORD}
复制代码
我们可以使用以下命令创建ConfigMap:
- kubectl create configmap app-config --from-file=application.properties
复制代码- kubectl create configmap app-config \
- --from-literal=server.port=8080 \
- --from-literal=logging.level.root=INFO \
- --from-literal=spring.datasource.url=jdbc:postgresql://postgres-service:5432/mydb
复制代码
作为环境变量:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- env:
- - name: SERVER_PORT
- valueFrom:
- configMapKeyRef:
- name: app-config
- key: server.port
- - name: LOGGING_LEVEL_ROOT
- valueFrom:
- configMapKeyRef:
- name: app-config
- key: logging.level.root
复制代码
作为文件:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- volumeMounts:
- - name: config-volume
- mountPath: /etc/config
- volumes:
- - name: config-volume
- configMap:
- name: app-config
复制代码
使用Secret管理敏感数据
Secret用于存储敏感数据,如密码、API密钥等。
从文件创建Secret:
- kubectl create secret generic db-secret \
- --from-file=username=./username.txt \
- --from-file=password=./password.txt
复制代码
从字面量创建Secret:
- kubectl create secret generic db-secret \
- --from-literal=username=postgres \
- --from-literal=password=postgres_password
复制代码
使用YAML文件创建Secret:
- apiVersion: v1
- kind: Secret
- metadata:
- name: db-secret
- type: Opaque
- data:
- username: cG9zdGdyZXM= # base64编码的"postgres"
- password: cG9zdGdyZXNfcGFzc3dvcmQ= # base64编码的"postgres_password"
复制代码
作为环境变量:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- env:
- - name: DB_USERNAME
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: username
- - name: DB_PASSWORD
- valueFrom:
- secretKeyRef:
- name: db-secret
- key: password
复制代码
作为文件:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- volumeMounts:
- - name: secret-volume
- mountPath: /etc/secrets
- volumes:
- - name: secret-volume
- secret:
- secretName: db-secret
复制代码
使用配置管理工具
除了Kubernetes原生的ConfigMap和Secret,我们还可以使用专门的配置管理工具:
对于Spring Boot应用,可以使用Spring Cloud Config来集中管理配置:
config-server-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: config-server-deployment
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: config-server
- template:
- metadata:
- labels:
- app: config-server
- spec:
- containers:
- - name: config-server
- image: my-username/config-server:1.0.0
- ports:
- - containerPort: 8888
- env:
- - name: SPRING_PROFILES_ACTIVE
- value: "native"
- - name: SPRING_CLOUD_CONFIG_SERVER_NATIVE_SEARCH_LOCATIONS
- value: "file:/config"
- volumeMounts:
- - name: config-repo
- mountPath: /config
- volumes:
- - name: config-repo
- configMap:
- name: config-repo
复制代码
config-server-service.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: config-server
- spec:
- selector:
- app: config-server
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8888
- type: ClusterIP
复制代码
Consul是一个服务网格解决方案,提供服务发现、配置和分段功能:
consul-deployment.yaml:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: consul-deployment
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: consul
- template:
- metadata:
- labels:
- app: consul
- spec:
- containers:
- - name: consul
- image: consul:1.9
- ports:
- - containerPort: 8500
- args:
- - "agent"
- - "-server"
- - "-bootstrap-expect=1"
- - "-ui"
- - "-client=0.0.0.0"
- volumeMounts:
- - name: consul-data
- mountPath: /consul/data
- volumes:
- - name: consul-data
- emptyDir: {}
复制代码
consul-service.yaml:
- apiVersion: v1
- kind: Service
- metadata:
- name: consul
- spec:
- selector:
- app: consul
- ports:
- - protocol: TCP
- port: 8500
- targetPort: 8500
- type: ClusterIP
复制代码
配置热更新
Kubernetes允许我们在不重启Pod的情况下更新配置:
使用ConfigMap作为卷:
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- volumeMounts:
- - name: config-volume
- mountPath: /etc/config
- volumes:
- - name: config-volume
- configMap:
- name: app-config
复制代码
当ConfigMap更新时,Kubernetes会自动更新挂载的文件。应用需要能够检测这些变化并重新加载配置。
使用Reloader:
Reloader是一个Kubernetes控制器,可以监视ConfigMap和Secret的变化,并重启相关的Deployment:
- # 安装Reloader
- kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
- # 在Deployment中添加注解
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- annotations:
- reloader.stakater.com/auto: "true"
- spec:
- # ...
复制代码
服务发现与负载均衡
在微服务架构中,服务发现和负载均衡是关键组件。Kubernetes提供了内置的服务发现和负载均衡机制。
Kubernetes Service
Service是Kubernetes中用于服务发现和负载均衡的核心资源。它为一组功能相同的Pod提供统一的访问入口。
Kubernetes支持以下几种Service类型:
1. ClusterIP:默认类型,在集群内部暴露服务,只能在集群内部访问。
2. NodePort:在每个节点的固定端口暴露服务,可以从集群外部访问。
3. LoadBalancer:使用云提供商的负载均衡器暴露服务,提供外部访问。
4. ExternalName:将服务映射到外部名称,通常用于访问集群外部的服务。
- apiVersion: v1
- kind: Service
- metadata:
- name: my-service
- spec:
- selector:
- app: my-app
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码- apiVersion: v1
- kind: Service
- metadata:
- name: my-service
- spec:
- selector:
- app: my-app
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- nodePort: 30007 # 可选,默认范围30000-32767
- type: NodePort
复制代码- apiVersion: v1
- kind: Service
- metadata:
- name: my-service
- spec:
- selector:
- app: my-app
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: LoadBalancer
复制代码
服务发现
Kubernetes提供了两种主要的服务发现机制:
当Pod创建时,Kubernetes会为每个Service注入一组环境变量:
- # 在Pod中查看环境变量
- kubectl exec my-pod -- env | grep SERVICE
复制代码
例如,对于名为”my-service”的Service,Kubernetes会注入以下环境变量:
- MY_SERVICE_SERVICE_HOST=10.0.0.123
- MY_SERVICE_SERVICE_PORT=80
复制代码
Kubernetes提供了一个集群内部的DNS服务,允许通过Service名称解析到ClusterIP:
- # 在Pod中使用DNS解析Service
- kubectl exec my-pod -- nslookup my-service
复制代码
Kubernetes DNS为Service创建以下记录:
• my-service.namespace.svc.cluster.local:解析到Service的ClusterIP
• my-service.namespace.svc.cluster.local:解析到Service的端口
• _http._tcp.my-service.namespace.svc.cluster.local:SRV记录,包含Service名称、端口和协议
Headless Service
Headless Service是不分配ClusterIP的Service,用于直接暴露Pod的IP。它常用于StatefulSet或有状态应用。
- apiVersion: v1
- kind: Service
- metadata:
- name: my-headless-service
- spec:
- clusterIP: None # 这使得Service成为headless
- selector:
- app: my-app
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
复制代码
对于Headless Service,DNS会返回所有后端Pod的IP,而不是单个Service IP。
外部服务访问
Ingress是管理集群外部访问集群内部服务的规则,通常用于暴露HTTP和HTTPS路由。
- apiVersion: networking.k8s.io/v1
- kind: Ingress
- metadata:
- name: my-ingress
- annotations:
- nginx.ingress.kubernetes.io/rewrite-target: /
- spec:
- rules:
- - http:
- paths:
- - path: /app1
- pathType: Prefix
- backend:
- service:
- name: app1-service
- port:
- number: 80
- - path: /app2
- pathType: Prefix
- backend:
- service:
- name: app2-service
- port:
- number: 80
复制代码
Ingress资源需要Ingress Controller才能工作。常见的Ingress Controller包括:
1. NGINX Ingress Controller:
- kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml
复制代码
1. Traefik Ingress Controller:
- kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.5/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
- kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.5/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml
- kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.5/docs/content/reference/dynamic-configuration/kubernetes-deployment.yml
复制代码
另一种方法是使用hostNetwork,使Pod直接使用节点的网络命名空间:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: my-app
- template:
- metadata:
- labels:
- app: my-app
- spec:
- hostNetwork: true
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- ports:
- - containerPort: 8080
- hostPort: 8080
复制代码
服务网格
服务网格是处理服务间通信的基础设施层,提供可靠的服务间通信。常见的服务网格包括Istio、Linkerd和Consul Connect。
Istio是一个开源的服务网格,提供流量管理、安全性和可观察性。
安装Istio:
- # 下载Istio
- curl -L https://istio.io/downloadIstio | sh -
- # 进入Istio目录
- cd istio-*
- # 添加istioctl到PATH
- export PATH=$PWD/bin:$PATH
- # 安装Istio
- istioctl install --set profile=demo -y
复制代码
启用Sidecar注入:
- kubectl label namespace default istio-injection=enabled
复制代码
创建Gateway和VirtualService:
- apiVersion: networking.istio.io/v1alpha3
- kind: Gateway
- metadata:
- name: my-gateway
- spec:
- selector:
- istio: ingressgateway
- servers:
- - port:
- number: 80
- name: http
- protocol: HTTP
- hosts:
- - "*"
- ---
- apiVersion: networking.istio.io/v1alpha3
- kind: VirtualService
- metadata:
- name: my-virtualservice
- spec:
- hosts:
- - "*"
- gateways:
- - my-gateway
- http:
- - match:
- - uri:
- prefix: /service1
- route:
- - destination:
- host: service1
- - match:
- - uri:
- prefix: /service2
- route:
- - destination:
- host: service2
复制代码
Linkerd是一个轻量级的服务网格,专注于简单性和性能。
安装Linkerd:
- # 安装CLI
- curl -sL https://run.linkerd.io/install | sh
- # 验证集群
- linkerd check --pre
- # 安装控制平面
- linkerd install | kubectl apply -f -
- # 验证安装
- linkerd check
复制代码
注入Linkerd:
- # 注入到命名空间中的所有Pod
- kubectl get deploy -n my-namespace -o yaml | linkerd inject - | kubectl apply -f -
- # 或者使用注解注入到特定部署
- kubectl annotate deploy my-deployment linkerd.io/inject=enabled
复制代码
自动扩缩容
自动扩缩容是Kubernetes的一个重要特性,它允许根据负载自动调整应用实例数量。Kubernetes提供了多种自动扩缩容机制。
Horizontal Pod Autoscaler (HPA)
HPA根据CPU使用率或其他自定义指标自动调整Deployment、ReplicaSet或StatefulSet的Pod数量。
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: my-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-deployment
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 50
复制代码- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: my-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-deployment
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Resource
- resource:
- name: memory
- target:
- type: Utilization
- averageUtilization: 70
复制代码- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: my-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-deployment
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Pods
- pods:
- metric:
- name: requests_per_second
- target:
- type: AverageValue
- averageValue: 1k
复制代码- # 使用YAML文件创建HPA
- kubectl apply -f hpa.yaml
- # 或者使用kubectl autoscale命令
- kubectl autoscale deployment my-deployment --cpu-percent=50 --min=2 --max=10
复制代码- kubectl get hpa
- kubectl describe hpa my-hpa
复制代码
Vertical Pod Autoscaler (VPA)
VPA自动调整Pod的资源请求和限制,优化资源使用。
- # 下载VPA发布版本
- git clone https://github.com/kubernetes/autoscaler.git
- cd autoscaler/vertical-pod-autoscaler
- # 部署VPA
- ./hack/vpa-up.sh
复制代码- apiVersion: autoscaling.k8s.io/v1
- kind: VerticalPodAutoscaler
- metadata:
- name: my-vpa
- spec:
- targetRef:
- apiVersion: "apps/v1"
- kind: "Deployment"
- name: "my-deployment"
- updatePolicy:
- updateMode: "Auto"
复制代码- kubectl describe vpa my-vpa
复制代码
Cluster Autoscaler
Cluster Autoscaler根据集群中Pod的资源需求自动调整节点数量。
- # 创建带有Cluster Autoscaler的集群
- gcloud container clusters create my-cluster \
- --zone us-central1-a \
- --enable-autoscaling \
- --min-nodes 1 \
- --max-nodes 10 \
- --num-nodes 2
复制代码- # 安装Cluster Autoscaler
- kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
- # 设置环境变量
- kubectl -n kube-system set image deployment.apps/cluster-autoscaler cluster-autoscaler=us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v1.21.0
复制代码- # 创建带有Cluster Autoscaler的集群
- az aks create \
- --resource-group myResourceGroup \
- --name myAKSCluster \
- --node-count 2 \
- --enable-cluster-autoscaler \
- --min-count 1 \
- --max-count 10
复制代码
自定义指标自动扩缩容
除了CPU和内存,我们还可以使用自定义指标进行自动扩缩容。
Metrics Server是Kubernetes的资源指标收集器,HPA依赖它获取资源使用数据。
- # 安装Metrics Server
- kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
- # 验证安装
- kubectl top nodes
- kubectl top pods
复制代码
Prometheus Adapter允许使用Prometheus作为自定义指标的来源。
- # 安装Prometheus Adapter
- kubectl apply -f https://raw.githubusercontent.com/DirectXMan12/k8s-prometheus-adapter/master/deploy/manifests/
复制代码- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: adapter-config
- namespace: monitoring
- data:
- config.yaml: |
- rules:
- - seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
- resources:
- overrides:
- namespace: {resource: "namespace"}
- pod: {resource: "pod"}
- name:
- matches: "^(.*)_total"
- as: "${1}_per_second"
- metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)'
复制代码- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: my-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-deployment
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Pods
- pods:
- metric:
- name: http_requests_per_second
- target:
- type: AverageValue
- averageValue: 100
复制代码
预测性自动扩缩容
预测性自动扩缩容基于历史数据和预测模型,提前扩容以应对预期的负载增长。
KEDA (Kubernetes Event-driven Autoscaler) 是一个基于事件的自动扩缩器。
- # 安装KEDA
- kubectl apply -f https://github.com/kedacore/keda/releases/download/v2.4.0/keda-2.4.0.yaml
复制代码- apiVersion: keda.sh/v1alpha1
- kind: ScaledObject
- metadata:
- name: my-scaledobject
- spec:
- scaleTargetRef:
- name: my-deployment
- minReplicaCount: 0
- maxReplicaCount: 10
- triggers:
- - type: prometheus
- metadata:
- serverAddress: http://prometheus-server.monitoring.svc.cluster.local:80
- metricName: http_requests_total
- threshold: '100'
- query: sum(rate(http_requests_total{deployment="my-deployment"}[2m]))
复制代码
监控与日志
在微服务架构中,监控和日志管理是确保系统健康和快速排查问题的关键。Kubernetes提供了多种监控和日志解决方案。
监控
Prometheus是一个开源的监控和告警系统,特别适合Kubernetes环境。Grafana是一个开源的度量分析和可视化套件。
安装Prometheus Operator:
- # 安装Prometheus Operator
- kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/master/bundle.yaml
- # 安装Kube-Prometheus
- kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/master/manifests/setup/prometheus-operator-0servicemonitorCustomResourceDefinition.yaml
- kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/master/manifests/setup/prometheus-operator-0prometheusruleCustomResourceDefinition.yaml
- kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/master/manifests/
复制代码
访问Grafana:
- # 转发Grafana服务
- kubectl port-forward -n monitoring svc/grafana 3000:3000
- # 访问 http://localhost:3000
- # 默认用户名: admin
- # 默认密码: admin
复制代码
自定义监控指标:
- apiVersion: v1
- kind: ServiceMonitor
- metadata:
- name: my-service-monitor
- namespace: monitoring
- labels:
- app: my-app
- spec:
- selector:
- matchLabels:
- app: my-app
- endpoints:
- - port: web
- interval: 30s
- path: /metrics
复制代码
Kubernetes Dashboard是Kubernetes的官方Web UI。
安装Dashboard:
- kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
复制代码
创建访问令牌:
- # 创建ServiceAccount
- kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
- # 创建ClusterRoleBinding
- kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
- # 获取令牌
- kubectl describe secrets -n kubernetes-dashboard $(kubectl -n kubernetes-dashboard get secret | awk '/dashboard-admin/{print $1}')
复制代码
访问Dashboard:
- # 转发Dashboard服务
- kubectl proxy
- # 访问 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
复制代码
日志管理
EFK (Elasticsearch, Fluentd, Kibana) 是一个流行的日志管理解决方案。
安装Elasticsearch:
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: elasticsearch
- namespace: logging
- spec:
- serviceName: elasticsearch
- replicas: 1
- selector:
- matchLabels:
- app: elasticsearch
- template:
- metadata:
- labels:
- app: elasticsearch
- spec:
- containers:
- - name: elasticsearch
- image: docker.elastic.co/elasticsearch/elasticsearch:7.10.1
- ports:
- - containerPort: 9200
- name: rest
- protocol: TCP
- - containerPort: 9300
- name: inter-node
- protocol: TCP
- env:
- - name: discovery.type
- value: single-node
- resources:
- limits:
- cpu: 1000m
- requests:
- cpu: 100m
- volumeMounts:
- - name: data
- mountPath: /usr/share/elasticsearch/data
- volumeClaimTemplates:
- - metadata:
- name: data
- spec:
- accessModes: [ "ReadWriteOnce" ]
- storageClassName: "standard"
- resources:
- requests:
- storage: 10Gi
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: elasticsearch
- namespace: logging
- labels:
- app: elasticsearch
- spec:
- ports:
- - port: 9200
- name: rest
- - port: 9300
- name: inter-node
- selector:
- app: elasticsearch
复制代码
安装Kibana:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: kibana
- namespace: logging
- labels:
- app: kibana
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: kibana
- template:
- metadata:
- labels:
- app: kibana
- spec:
- containers:
- - name: kibana
- image: docker.elastic.co/kibana/kibana:7.10.1
- ports:
- - containerPort: 5601
- env:
- - name: ELASTICSEARCH_URL
- value: http://elasticsearch:9200
- resources:
- limits:
- cpu: 1000m
- requests:
- cpu: 100m
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: kibana
- namespace: logging
- labels:
- app: kibana
- spec:
- ports:
- - port: 5601
- protocol: TCP
- targetPort: 5601
- selector:
- app: kibana
复制代码
安装Fluentd:
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: fluentd
- namespace: logging
- labels:
- app: fluentd
- ---
- apiVersion: rbac.authorization.k8s.io/v1
- kind: ClusterRole
- metadata:
- name: fluentd
- namespace: logging
- labels:
- app: fluentd
- rules:
- - apiGroups:
- - ""
- resources:
- - pods
- - namespaces
- verbs:
- - get
- - list
- - watch
- ---
- kind: ClusterRoleBinding
- apiVersion: rbac.authorization.k8s.io/v1
- metadata:
- name: fluentd
- namespace: logging
- roleRef:
- kind: ClusterRole
- name: fluentd
- apiGroup: rbac.authorization.k8s.io
- subjects:
- - kind: ServiceAccount
- name: fluentd
- namespace: logging
- ---
- apiVersion: apps/v1
- kind: DaemonSet
- metadata:
- name: fluentd
- namespace: logging
- labels:
- app: fluentd
- spec:
- selector:
- matchLabels:
- app: fluentd
- template:
- metadata:
- labels:
- app: fluentd
- spec:
- serviceAccount: fluentd
- serviceAccountName: fluentd
- tolerations:
- - key: node-role.kubernetes.io/master
- effect: NoSchedule
- containers:
- - name: fluentd
- image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
- env:
- - name: FLUENT_ELASTICSEARCH_HOST
- value: "elasticsearch"
- - name: FLUENT_ELASTICSEARCH_PORT
- value: "9200"
- - name: FLUENT_ELASTICSEARCH_SCHEME
- value: "http"
- - name: FLUENTD_SYSTEMD_CONF
- value: disable
- resources:
- limits:
- memory: 512Mi
- requests:
- cpu: 100m
- memory: 200Mi
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- - name: varlibdockercontainers
- mountPath: /var/lib/docker/containers
- readOnly: true
- terminationGracePeriodSeconds: 30
- volumes:
- - name: varlog
- hostPath:
- path: /var/log
- - name: varlibdockercontainers
- hostPath:
- path: /var/lib/docker/containers
复制代码
Loki是一个轻量级的日志聚合系统,与Prometheus和Grafana集成良好。
安装Loki:
- # 安装Loki
- helm repo add grafana https://grafana.github.io/helm-charts
- helm repo update
- helm upgrade --install loki grafana/loki-stack --namespace=monitoring --set grafana.enabled=true,prometheus.enabled=true,prometheus.alertmanager.enabled=false,prometheus.pushgateway.enabled=false,prometheus.server.persistentVolume.enabled=false
复制代码
配置Promtail:
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: promtail-config
- namespace: monitoring
- data:
- promtail.yaml: |
- client:
- url: http://loki:3100/loki/api/v1/push
- positions:
- filename: /tmp/positions.yaml
- scrape_configs:
- - job_name: kubernetes-pods
- kubernetes_sd_configs:
- - role: pod
- pipeline_stages:
- - docker: {}
- relabel_configs:
- - source_labels:
- - __meta_kubernetes_pod_label_name
- target_label: __service__
- - source_labels:
- - __meta_kubernetes_pod_node_name
- target_label: __host__
- - action: labelmap
- regex: __meta_kubernetes_pod_label_(.+)
- - action: replace
- replacement: $1
- separator: /
- source_labels:
- - __meta_kubernetes_namespace
- - __service__
- target_label: job
- - action: replace
- source_labels:
- - __meta_kubernetes_namespace
- target_label: namespace
- - action: replace
- source_labels:
- - __meta_kubernetes_pod_name
- target_label: pod
- - action: replace
- source_labels:
- - __meta_kubernetes_pod_container_name
- target_label: container
- - replacement: /var/log/pods/*$1/*.log
- separator: /
- source_labels:
- - __meta_kubernetes_pod_uid
- - __meta_kubernetes_pod_container_name
- target_label: __path__
复制代码
安装Promtail:
- apiVersion: apps/v1
- kind: DaemonSet
- metadata:
- name: promtail
- namespace: monitoring
- spec:
- selector:
- matchLabels:
- app: promtail
- template:
- metadata:
- labels:
- app: promtail
- spec:
- serviceAccount: promtail
- containers:
- - name: promtail
- image: grafana/promtail:2.0.0
- args:
- - -config.file=/etc/promtail/promtail.yaml
- volumeMounts:
- - name: config
- mountPath: /etc/promtail
- - name: logs
- mountPath: /var/log
- - name: containers
- mountPath: /var/lib/docker/containers
- readOnly: true
- volumes:
- - name: config
- configMap:
- name: promtail-config
- - name: logs
- hostPath:
- path: /var/log
- - name: containers
- hostPath:
- path: /var/lib/docker/containers
复制代码
分布式追踪
分布式追踪是微服务架构中重要的可观察性组件,帮助理解请求在系统中的传播路径。
Jaeger是一个开源的分布式追踪系统。
安装Jaeger:
- # 安装Jaeger Operator
- kubectl create namespace observability
- kubectl apply -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.28.0/jaeger-operator.yaml -n observability
- # 创建Jaeger实例
- cat <<EOF | kubectl apply -f -
- apiVersion: jaegertracing.io/v1
- kind: Jaeger
- metadata:
- name: jaeger
- namespace: observability
- EOF
复制代码
访问Jaeger UI:
- # 转发Jaeger服务
- kubectl port-forward -n observability svc/jaeger-query 16686:16686
- # 访问 http://localhost:16686
复制代码
对于Spring Boot应用,可以添加以下依赖:
- <dependency>
- <groupId>io.opentracing.contrib</groupId>
- <artifactId>opentracing-spring-jaeger-cloud-starter</artifactId>
- <version>3.3.1</version>
- </dependency>
复制代码
配置application.properties:
- spring.jaeger.enabled=true
- spring.jaeger.service-name=my-service
- spring.jaeger.sampler-type=const
- spring.jaeger.sampler-param=1
- spring.jaeger.udp-sender.host=jaeger-agent.observability.svc.cluster.local
- spring.jaeger.udp-sender.port=6831
复制代码
故障排查
在Kubernetes环境中,故障排查是一项关键技能。本节将介绍常见的故障场景及其解决方案。
Pod状态问题
Pod处于Pending状态通常表示Kubernetes无法调度该Pod。
排查步骤:
1. 检查Pod详细信息:
- kubectl describe pod <pod-name>
复制代码
1. 检查事件部分,查找调度失败的原因。
2. 检查集群资源:
检查事件部分,查找调度失败的原因。
检查集群资源:
1. 检查是否有足够的资源:
常见原因及解决方案:
1. 资源不足:增加节点或减少Pod资源请求使用自动扩缩容
2. 增加节点或减少Pod资源请求
3. 使用自动扩缩容
4. 节点选择器或亲和性规则:检查Pod的nodeSelector或nodeAffinity规则确保有匹配的节点
5. 检查Pod的nodeSelector或nodeAffinity规则
6. 确保有匹配的节点
7. 污点和容忍度:检查节点的污点为Pod添加适当的容忍度
8. 检查节点的污点
9. 为Pod添加适当的容忍度
资源不足:
• 增加节点或减少Pod资源请求
• 使用自动扩缩容
节点选择器或亲和性规则:
• 检查Pod的nodeSelector或nodeAffinity规则
• 确保有匹配的节点
污点和容忍度:
• 检查节点的污点
• 为Pod添加适当的容忍度
- tolerations:
- - key: "key"
- operator: "Equal"
- value: "value"
- effect: "NoSchedule"
复制代码
Pod处于CrashLoopBackOff状态表示容器启动后崩溃,Kubernetes尝试重启但失败。
排查步骤:
1. 检查Pod日志:
- kubectl logs <pod-name>
- kubectl logs <pod-name> --previous
复制代码
1. 检查容器状态:
- kubectl describe pod <pod-name>
复制代码
1. 进入容器调试:
- kubectl exec -it <pod-name> -- /bin/bash
复制代码
常见原因及解决方案:
1. 应用错误:修复应用代码检查应用配置
2. 修复应用代码
3. 检查应用配置
4. 资源不足:增加Pod的资源限制优化应用资源使用
5. 增加Pod的资源限制
6. 优化应用资源使用
7. 依赖服务不可用:检查依赖服务的状态添加适当的健康检查和就绪探针
8. 检查依赖服务的状态
9. 添加适当的健康检查和就绪探针
应用错误:
• 修复应用代码
• 检查应用配置
资源不足:
• 增加Pod的资源限制
• 优化应用资源使用
依赖服务不可用:
• 检查依赖服务的状态
• 添加适当的健康检查和就绪探针
- livenessProbe:
- httpGet:
- path: /health
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /ready
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
复制代码
Pod处于ImagePullBackOff状态表示Kubernetes无法拉取容器镜像。
排查步骤:
1. 检查Pod事件:
- kubectl describe pod <pod-name>
复制代码
1. 检查镜像名称和标签是否正确。
2. 检查镜像仓库的访问权限。
检查镜像名称和标签是否正确。
检查镜像仓库的访问权限。
常见原因及解决方案:
1. 镜像名称或标签错误:修正Deployment中的镜像名称和标签
2. 修正Deployment中的镜像名称和标签
3. 镜像仓库认证问题:创建imagePullSecrets
4. 创建imagePullSecrets
镜像名称或标签错误:
• 修正Deployment中的镜像名称和标签
镜像仓库认证问题:
• 创建imagePullSecrets
- # 创建Docker registry secret
- kubectl create secret docker-registry my-registry-secret \
- --docker-server=DOCKER_REGISTRY_SERVER \
- --docker-username=DOCKER_USER \
- --docker-password=DOCKER_PASSWORD \
- --docker-email=DOCKER_EMAIL
- # 在Pod中使用secret
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-pod
- spec:
- containers:
- - name: my-container
- image: my-private-registry/my-image:tag
- imagePullSecrets:
- - name: my-registry-secret
复制代码
1. 网络问题:检查节点网络连接配置镜像代理
2. 检查节点网络连接
3. 配置镜像代理
• 检查节点网络连接
• 配置镜像代理
Service问题
Service无法访问Pod通常是由于标签选择器不匹配或网络问题。
排查步骤:
1. 检查Service定义:
- kubectl describe service <service-name>
复制代码
1. 检查Pod标签:
- kubectl get pods --show-labels
复制代码
1. 检查Endpoints:
- kubectl get endpoints <service-name>
复制代码
1. 从Pod内部测试连接:
- kubectl exec -it <pod-name> -- wget -qO- <service-name>.<namespace>.svc.cluster.local
复制代码
常见原因及解决方案:
1. 标签选择器不匹配:确保Pod的标签与Service的选择器匹配
2. 确保Pod的标签与Service的选择器匹配
3. Pod未就绪:检查Pod的就绪探针确保Pod处于Running状态
4. 检查Pod的就绪探针
5. 确保Pod处于Running状态
6. 网络策略阻止:检查网络策略配置允许Service和Pod之间的通信
7. 检查网络策略配置
8. 允许Service和Pod之间的通信
标签选择器不匹配:
• 确保Pod的标签与Service的选择器匹配
Pod未就绪:
• 检查Pod的就绪探针
• 确保Pod处于Running状态
网络策略阻止:
• 检查网络策略配置
• 允许Service和Pod之间的通信
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: allow-service-access
- spec:
- podSelector:
- matchLabels:
- app: my-app
- ingress:
- - from:
- - namespaceSelector:
- matchLabels:
- name: default
- ports:
- - protocol: TCP
- port: 8080
复制代码
外部无法访问Service通常是由于Service类型配置错误或负载均衡器问题。
排查步骤:
1. 检查Service类型:
- kubectl get service <service-name>
复制代码
1. 检查Ingress配置(如果使用):
- kubectl describe ingress <ingress-name>
复制代码
1. 检查云提供商的负载均衡器(如果使用):
- kubectl get service <service-name> -o yaml
复制代码
常见原因及解决方案:
1. Service类型错误:使用正确的Service类型(NodePort或LoadBalancer)
2. 使用正确的Service类型(NodePort或LoadBalancer)
3. Ingress配置错误:检查Ingress规则确保Ingress Controller正常运行
4. 检查Ingress规则
5. 确保Ingress Controller正常运行
6. 云提供商问题:检查云提供商的负载均衡器状态确保安全组配置正确
7. 检查云提供商的负载均衡器状态
8. 确保安全组配置正确
Service类型错误:
• 使用正确的Service类型(NodePort或LoadBalancer)
Ingress配置错误:
• 检查Ingress规则
• 确保Ingress Controller正常运行
云提供商问题:
• 检查云提供商的负载均衡器状态
• 确保安全组配置正确
存储问题
Pod无法挂载PersistentVolume通常是由于PVC未绑定或存储类配置错误。
排查步骤:
1. 检查PVC状态:
- kubectl get pvc
- kubectl describe pvc <pvc-name>
复制代码
1. 检查PV状态:
- kubectl get pv
- kubectl describe pv <pv-name>
复制代码
1. 检查存储类:
常见原因及解决方案:
1. PVC未绑定:确保有足够的PV资源检查PVC请求的资源是否与PV匹配
2. 确保有足够的PV资源
3. 检查PVC请求的资源是否与PV匹配
4. 存储类配置错误:确保使用正确的存储类检查存储类的provisioner是否正常工作
5. 确保使用正确的存储类
6. 检查存储类的provisioner是否正常工作
7. 权限问题:检查存储的访问权限确保Pod有权限访问存储
8. 检查存储的访问权限
9. 确保Pod有权限访问存储
PVC未绑定:
• 确保有足够的PV资源
• 检查PVC请求的资源是否与PV匹配
存储类配置错误:
• 确保使用正确的存储类
• 检查存储类的provisioner是否正常工作
权限问题:
• 检查存储的访问权限
• 确保Pod有权限访问存储
数据丢失通常是由于PV回收策略配置错误或存储故障。
排查步骤:
1. 检查PV回收策略:
- kubectl get pv <pv-name> -o yaml
复制代码
1. 检查Pod事件:
- kubectl describe pod <pod-name>
复制代码
1. 检查存储系统日志。
常见原因及解决方案:
1. PV回收策略错误:使用Retain回收策略保护数据
2. 使用Retain回收策略保护数据
• 使用Retain回收策略保护数据
- apiVersion: v1
- kind: PersistentVolume
- metadata:
- name: my-pv
- spec:
- capacity:
- storage: 10Gi
- persistentVolumeReclaimPolicy: Retain
- # ...
复制代码
1. 存储故障:使用高可用存储解决方案定期备份数据
2. 使用高可用存储解决方案
3. 定期备份数据
4. Pod被意外删除:使用StatefulSet管理有状态应用配置适当的PodDisruptionBudget
5. 使用StatefulSet管理有状态应用
6. 配置适当的PodDisruptionBudget
存储故障:
• 使用高可用存储解决方案
• 定期备份数据
Pod被意外删除:
• 使用StatefulSet管理有状态应用
• 配置适当的PodDisruptionBudget
- apiVersion: policy/v1
- kind: PodDisruptionBudget
- metadata:
- name: my-pdb
- spec:
- minAvailable: 2
- selector:
- matchLabels:
- app: my-app
复制代码
网络问题
Pod之间无法通信通常是由于网络插件配置错误或网络策略阻止。
排查步骤:
1. 检查网络插件状态:
- kubectl get pods -n kube-system | grep -E 'calico|flannel|weave|cilium'
复制代码
1. 检查网络策略:
- kubectl get networkpolicy
复制代码
1. 从Pod内部测试连接:
- kubectl exec -it <pod-name> -- ping <target-pod-ip>
- kubectl exec -it <pod-name> -- wget -qO- <target-service-url>
复制代码
常见原因及解决方案:
1. 网络插件问题:检查网络插件Pod的状态重新安装或修复网络插件
2. 检查网络插件Pod的状态
3. 重新安装或修复网络插件
4. 网络策略阻止:检查网络策略配置添加允许通信的网络策略
5. 检查网络策略配置
6. 添加允许通信的网络策略
7. CNI配置错误:检查CNI配置文件重新配置CNI
8. 检查CNI配置文件
9. 重新配置CNI
网络插件问题:
• 检查网络插件Pod的状态
• 重新安装或修复网络插件
网络策略阻止:
• 检查网络策略配置
• 添加允许通信的网络策略
CNI配置错误:
• 检查CNI配置文件
• 重新配置CNI
DNS解析失败通常是由于CoreDNS配置错误或网络问题。
排查步骤:
1. 检查CoreDNS状态:
- kubectl get pods -n kube-system | grep coredns
- kubectl logs -n kube-system <coredns-pod-name>
复制代码
1. 从Pod内部测试DNS解析:
- kubectl exec -it <pod-name> -- nslookup kubernetes.default
- kubectl exec -it <pod-name> -- nslookup <service-name>
复制代码
1. 检查CoreDNS配置:
- kubectl get configmap coredns -n kube-system -o yaml
复制代码
常见原因及解决方案:
1. CoreDNS Pod异常:重启CoreDNS Pod检查CoreDNS资源限制
2. 重启CoreDNS Pod
3. 检查CoreDNS资源限制
4. CoreDNS配置错误:修正CoreDNS配置添加必要的上游DNS服务器
5. 修正CoreDNS配置
6. 添加必要的上游DNS服务器
7. 网络问题:检查Pod网络连接确保可以访问kube-dns服务
8. 检查Pod网络连接
9. 确保可以访问kube-dns服务
CoreDNS Pod异常:
• 重启CoreDNS Pod
• 检查CoreDNS资源限制
CoreDNS配置错误:
• 修正CoreDNS配置
• 添加必要的上游DNS服务器
网络问题:
• 检查Pod网络连接
• 确保可以访问kube-dns服务
资源问题
节点资源不足会导致Pod无法调度或被驱逐。
排查步骤:
1. 检查节点资源使用情况:
- kubectl top nodes
- kubectl describe node <node-name>
复制代码
1. 检查被驱逐的Pod:
- kubectl get pods --all-namespaces -o wide --field-selector=status.phase=Failed
复制代码
1. 检查节点事件:
- kubectl get events --field-selector involvedObject.kind=Node
复制代码
常见原因及解决方案:
1. CPU或内存不足:增加节点资源使用自动扩缩容优化Pod资源请求和限制
2. 增加节点资源
3. 使用自动扩缩容
4. 优化Pod资源请求和限制
5. 磁盘空间不足:清理不必要的文件和镜像增加磁盘空间配置镜像垃圾回收
6. 清理不必要的文件和镜像
7. 增加磁盘空间
8. 配置镜像垃圾回收
CPU或内存不足:
• 增加节点资源
• 使用自动扩缩容
• 优化Pod资源请求和限制
磁盘空间不足:
• 清理不必要的文件和镜像
• 增加磁盘空间
• 配置镜像垃圾回收
- # kubelet配置
- apiVersion: kubelet.config.k8s.io/v1beta1
- kind: KubeletConfiguration
- imageGCHighThresholdPercent: 80
- imageGCLowThresholdPercent: 60
复制代码
1. Pod资源请求过高:调整Pod资源请求使用垂直Pod自动扩缩容
2. 调整Pod资源请求
3. 使用垂直Pod自动扩缩容
• 调整Pod资源请求
• 使用垂直Pod自动扩缩容
Pod资源限制问题会导致Pod被OOM杀死或性能下降。
排查步骤:
1. 检查Pod资源使用情况:
- kubectl top pod <pod-name>
复制代码
1. 检查Pod事件:
- kubectl describe pod <pod-name>
复制代码
1. 检查容器日志:
常见原因及解决方案:
1. 内存限制过低:增加Pod内存限制优化应用内存使用
2. 增加Pod内存限制
3. 优化应用内存使用
4. CPU限制过低:增加Pod CPU限制优化应用CPU使用
5. 增加Pod CPU限制
6. 优化应用CPU使用
7. 资源请求和限制不平衡:设置合理的资源请求和限制使用VPA自动调整资源
8. 设置合理的资源请求和限制
9. 使用VPA自动调整资源
内存限制过低:
• 增加Pod内存限制
• 优化应用内存使用
CPU限制过低:
• 增加Pod CPU限制
• 优化应用CPU使用
资源请求和限制不平衡:
• 设置合理的资源请求和限制
• 使用VPA自动调整资源
调试工具和技巧
kubectl debug命令可以创建调试容器来排查问题。
- # 创建调试容器
- kubectl debug -it <pod-name> --image=busybox -- /bin/sh
- # 复制节点上的调试工具
- kubectl debug -it <node-name> --image=alpine -- chroot /host
复制代码
创建临时Pod来测试网络和DNS。
- apiVersion: v1
- kind: Pod
- metadata:
- name: debug-pod
- spec:
- containers:
- - name: debug-container
- image: busybox
- command: ["sleep", "3600"]
复制代码- # 测试网络连接
- kubectl exec debug-pod -- wget -qO- http://<service-url>
- # 测试DNS解析
- kubectl exec debug-pod -- nslookup <service-name>
复制代码
使用端口转发来访问集群内部服务。
- # 转发Pod端口
- kubectl port-forward <pod-name> 8080:80
- # 转发Service端口
- kubectl port-forward svc/<service-name> 8080:80
复制代码
Ephemeral Containers是Kubernetes 1.16+中的特性,用于排查运行中的Pod。
- # 添加临时容器
- kubectl debug -it <pod-name> --image=busybox --target=<container-name> -- /bin/sh
复制代码
最佳实践
在Kubernetes上部署和管理微服务时,遵循最佳实践可以提高系统的可靠性、安全性和可维护性。本节将介绍一些重要的最佳实践。
安全最佳实践
命名空间提供了一种将集群资源划分为多个虚拟集群的方式,有助于资源隔离和管理。
- apiVersion: v1
- kind: Namespace
- metadata:
- name: production
- labels:
- name: production
- ---
- apiVersion: v1
- kind: Namespace
- metadata:
- name: staging
- labels:
- name: staging
- ---
- apiVersion: v1
- kind: Namespace
- metadata:
- name: development
- labels:
- name: development
复制代码
基于角色的访问控制(RBAC)允许精细控制用户和服务账户对资源的访问权限。
- # 创建ServiceAccount
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: my-service-account
- namespace: production
- # 创建Role
- apiVersion: rbac.authorization.k8s.io/v1
- kind: Role
- metadata:
- name: my-role
- namespace: production
- rules:
- - apiGroups: [""]
- resources: ["pods", "services"]
- verbs: ["get", "list", "watch"]
- # 创建RoleBinding
- apiVersion: rbac.authorization.k8s.io/v1
- kind: RoleBinding
- metadata:
- name: my-role-binding
- namespace: production
- subjects:
- - kind: ServiceAccount
- name: my-service-account
- namespace: production
- roleRef:
- kind: Role
- name: my-role
- apiGroup: rbac.authorization.k8s.io
复制代码
网络策略允许控制Pod之间的网络通信,提高安全性。
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: allow-database-access
- namespace: production
- spec:
- podSelector:
- matchLabels:
- app: database
- policyTypes:
- - Ingress
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: backend
- ports:
- - protocol: TCP
- port: 5432
复制代码
Secret用于存储敏感数据,如密码、API密钥等。
- apiVersion: v1
- kind: Secret
- metadata:
- name: database-credentials
- namespace: production
- type: Opaque
- data:
- username: cG9zdGdyZXM= # base64编码的"postgres"
- password: cG9zdGdyZXNfcGFzc3dvcmQ= # base64编码的"postgres_password"
复制代码
Pod安全策略(PodSecurityPolicy)控制Pod的安全配置。
- apiVersion: policy/v1beta1
- kind: PodSecurityPolicy
- metadata:
- name: my-psp
- spec:
- privileged: false
- allowPrivilegeEscalation: false
- requiredDropCapabilities:
- - ALL
- volumes:
- - 'configMap'
- - 'emptyDir'
- - 'projected'
- - 'secret'
- - 'downwardAPI'
- - 'persistentVolumeClaim'
- runAsUser:
- rule: 'MustRunAsNonRoot'
- seLinux:
- rule: 'RunAsAny'
- fsGroup:
- rule: 'RunAsAny'
复制代码
资源管理最佳实践
为Pod设置适当的资源请求和限制,确保应用有足够的资源运行,同时防止资源滥用。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- spec:
- template:
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- resources:
- requests:
- memory: "256Mi"
- cpu: "250m"
- limits:
- memory: "512Mi"
- cpu: "500m"
复制代码
资源配额限制命名空间中可以使用的资源总量。
- apiVersion: v1
- kind: ResourceQuota
- metadata:
- name: my-quota
- namespace: production
- spec:
- hard:
- requests.cpu: "4"
- requests.memory: "8Gi"
- limits.cpu: "8"
- limits.memory: "16Gi"
- pods: "10"
- persistentvolumeclaims: "5"
复制代码
LimitRange设置命名空间中Pod和容器的默认资源请求和限制。
- apiVersion: v1
- kind: LimitRange
- metadata:
- name: my-limit-range
- namespace: production
- spec:
- limits:
- - default:
- memory: "512Mi"
- cpu: "500m"
- defaultRequest:
- memory: "256Mi"
- cpu: "250m"
- type: Container
复制代码
使用HPA和VPA自动调整Pod数量和资源。
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: my-hpa
- namespace: production
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-deployment
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 50
复制代码
应用部署最佳实践
为应用配置适当的健康检查,确保Kubernetes可以正确管理Pod生命周期。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- spec:
- template:
- spec:
- containers:
- - name: my-container
- image: my-username/my-service:1.0.0
- livenessProbe:
- httpGet:
- path: /health
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /ready
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
复制代码
配置滚动更新策略,确保应用更新过程中不中断服务。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- spec:
- strategy:
- type: RollingUpdate
- rollingUpdate:
- maxUnavailable: 1
- maxSurge: 1
- # ...
复制代码
使用PodDisruptionBudget确保在维护期间应用的高可用性。
- apiVersion: policy/v1
- kind: PodDisruptionBudget
- metadata:
- name: my-pdb
- namespace: production
- spec:
- minAvailable: 2
- selector:
- matchLabels:
- app: my-app
复制代码
使用反亲和性规则将Pod分散到不同的节点,提高可用性。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- spec:
- template:
- spec:
- affinity:
- podAntiAffinity:
- requiredDuringSchedulingIgnoredDuringExecution:
- - labelSelector:
- matchExpressions:
- - key: app
- operator: In
- values:
- - my-app
- topologyKey: "kubernetes.io/hostname"
- # ...
复制代码
配置管理最佳实践
使用ConfigMap将配置与应用代码分离。
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: app-config
- namespace: production
- data:
- application.properties: |
- server.port=8080
- logging.level.root=INFO
- spring.datasource.url=jdbc:postgresql://postgres-service:5432/mydb
- database_url: "jdbc:postgresql://postgres-service:5432/mydb"
复制代码
为配置添加版本控制,便于追踪变更和回滚。
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: app-config-v1
- namespace: production
- labels:
- version: "1.0"
- data:
- # ...
复制代码
使用Reloader等工具在配置变更时自动重启应用。
- # 安装Reloader
- kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
- # 在Deployment中添加注解
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-deployment
- annotations:
- reloader.stakater.com/auto: "true"
- # ...
复制代码
监控和日志最佳实践
使用结构化日志格式,便于查询和分析。
- {
- "timestamp": "2023-01-01T12:00:00Z",
- "level": "INFO",
- "service": "user-service",
- "message": "User login successful",
- "userId": "12345",
- "ip": "192.168.1.100"
- }
复制代码
使用Jaeger或Zipkin等工具实现分布式追踪,了解请求在系统中的传播路径。
- # Jaeger配置
- apiVersion: jaegertracing.io/v1
- kind: Jaeger
- metadata:
- name: jaeger
- namespace: observability
- spec:
- strategy: allInOne
- allInOne:
- image: jaegertracing/all-in-one:latest
- options:
- log-level: info
复制代码
设置适当的告警规则,及时发现和解决问题。
- # Prometheus告警规则示例
- groups:
- - name: example
- rules:
- - alert: HighPodMemory
- expr: sum(container_memory_usage_bytes{pod!=""}) / sum(container_spec_memory_limit_bytes{pod!=""}) > 0.8
- for: 5m
- labels:
- severity: warning
- annotations:
- summary: "High memory usage detected"
- description: "Pod memory usage is above 80% for 5 minutes"
复制代码
CI/CD最佳实践
使用GitOps进行持续部署,通过Git管理应用状态。
- # Argo CD Application示例
- apiVersion: argoproj.io/v1alpha1
- kind: Application
- metadata:
- name: my-app
- namespace: argocd
- spec:
- project: default
- source:
- repoURL: https://github.com/my-org/my-app.git
- targetRevision: HEAD
- path: kubernetes
- destination:
- server: https://kubernetes.default.svc
- namespace: production
- syncPolicy:
- automated:
- prune: true
- selfHeal: true
复制代码
使用蓝绿部署策略减少部署风险。
- # 蓝环境部署
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-app-blue
- spec:
- replicas: 3
- # ...
- # 绿环境部署
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-app-green
- spec:
- replicas: 3
- # ...
- # 使用Service切换流量
- apiVersion: v1
- kind: Service
- metadata:
- name: my-app
- spec:
- selector:
- app: my-app-green # 切换到my-app-blue以回滚
- # ...
复制代码
使用金丝雀发布策略逐步推出新版本。
- # 使用Istio进行金丝雀发布
- apiVersion: networking.istio.io/v1alpha3
- kind: VirtualService
- metadata:
- name: my-app
- spec:
- hosts:
- - my-app.example.com
- http:
- - route:
- - destination:
- host: my-app
- subset: v1
- weight: 90
- - destination:
- host: my-app
- subset: v2
- weight: 10
复制代码
总结与展望
本文详细介绍了Kubernetes微服务部署的各个方面,从基础概念到实战技巧,再到最佳实践。通过学习这些内容,你应该能够:
1. 理解Kubernetes的核心概念和架构
2. 搭建和管理Kubernetes集群
3. 将微服务应用容器化并部署到Kubernetes
4. 管理微服务的配置和敏感数据
5. 实现服务发现和负载均衡
6. 配置自动扩缩容以应对负载变化
7. 设置监控和日志系统
8. 排查常见问题
9. 遵循最佳实践确保系统的安全性和可靠性
Kubernetes作为一个快速发展的项目,不断推出新功能和改进。未来,我们可以期待以下发展方向:
1. 服务网格的集成:Kubernetes与服务网格(如Istio、Linkerd)的集成将更加紧密,提供更强大的流量管理、安全性和可观察性。
2. GitOps的普及:GitOps作为一种持续部署方法,将成为Kubernetes应用部署的主流方式。
3. 无服务器架构的融合:Kubernetes与无服务器技术(如Knative)的结合,将提供更灵活的应用部署和管理方式。
4. 多集群管理:随着企业应用规模的扩大,多集群管理工具(如Karmada、Cluster API)将变得更加重要。
5. 边缘计算支持:Kubernetes在边缘计算场景的应用将更加广泛,支持更轻量级的部署和管理。
6. 安全性的增强:Kubernetes将继续加强安全性,提供更强大的身份验证、授权和网络策略功能。
服务网格的集成:Kubernetes与服务网格(如Istio、Linkerd)的集成将更加紧密,提供更强大的流量管理、安全性和可观察性。
GitOps的普及:GitOps作为一种持续部署方法,将成为Kubernetes应用部署的主流方式。
无服务器架构的融合:Kubernetes与无服务器技术(如Knative)的结合,将提供更灵活的应用部署和管理方式。
多集群管理:随着企业应用规模的扩大,多集群管理工具(如Karmada、Cluster API)将变得更加重要。
边缘计算支持:Kubernetes在边缘计算场景的应用将更加广泛,支持更轻量级的部署和管理。
安全性的增强:Kubernetes将继续加强安全性,提供更强大的身份验证、授权和网络策略功能。
作为开发者和运维人员,持续学习和实践是掌握Kubernetes的关键。希望本文能够帮助你建立坚实的Kubernetes基础,并在实际工作中应用这些知识和技能。
最后,记住Kubernetes是一个强大的工具,但也是一个复杂的系统。在实际应用中,始终保持简单和实用,根据团队和项目的需求选择合适的解决方案。随着经验的积累,你将能够更加自信地使用Kubernetes部署和管理微服务应用。 |
|