学习路径概览
本指南按照从简单到复杂的路径设计,让您从Docker基础开始,逐步掌握Kubernetes和CI/CD,最终具备生产环境云原生应用部署能力。
第一步: Docker基础 → 第二步: K8s体验 → 第三步: CI/CD → 第四步: K8s进阶
(1-2周) (1-2周) (2-3周) (3-4周)
第一步:掌握Docker (1-2周)
目标
- 熟练使用Docker基本命令
- 能够将Spring Boot应用打包成镜像
- 理解容器化的核心概念
1.1 环境准备
Docker安装(Ubuntu为例)
# 更新包管理器
sudo apt update
# 安装Docker
sudo apt install docker.io
# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker
# 将用户添加到docker组
sudo usermod -aG docker $USER
newgrp docker
# 验证安装
docker --version
docker run hello-world
Java环境准备
# 安装OpenJDK 11
sudo apt install openjdk-11-jdk
# 安装Maven
sudo apt install maven
# 验证安装
java --version
mvn --version
1.2 创建Spring Boot示例应用
项目结构
spring-boot-demo/
├── pom.xml
├── src/
│ └── main/
│ └── java/
│ └── com/
│ └── example/
│ └── demo/
│ ├── DemoApplication.java
│ └── controller/
│ └── HelloController.java
└── Dockerfile
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>spring-boot-demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
DemoApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
HelloController.java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/")
public String hello() {
return "Hello, Cloud Native World!";
}
@GetMapping("/health")
public String health() {
return "OK";
}
@GetMapping("/info")
public String info() {
return "Spring Boot Demo v1.0.0";
}
}
1.3 创建Dockerfile
Dockerfile (多阶段构建)
# 第一阶段:构建应用
FROM maven:3.8.5-openjdk-11 AS builder
WORKDIR /app
COPY pom.xml .
# 下载依赖(利用Docker缓存)
RUN mvn dependency:go-offline -B
COPY src ./src
# 构建应用
RUN mvn package -DskipTests
# 第二阶段:运行应用
FROM openjdk:11-jre-slim
# 创建非root用户
RUN addgroup --system app && adduser --system --group app
# 设置工作目录
WORKDIR /app
# 从构建阶段复制jar文件
COPY --from=builder /app/target/*.jar app.jar
# 更改文件所有者
RUN chown app:app app.jar
# 切换到非root用户
USER app
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
1.4 Docker核心命令实践
构建镜像
# 进入项目目录
cd spring-boot-demo
# 构建镜像
docker build -t spring-boot-demo:1.0.0 .
docker build -t spring-boot-demo:latest .
# 查看构建的镜像
docker images
# 查看镜像详细信息
docker inspect spring-boot-demo:latest
# 查看镜像构建历史
docker history spring-boot-demo:latest
运行容器
# 基本运行
docker run -p 8080:8080 spring-boot-demo:latest
# 后台运行
docker run -d -p 8080:8080 --name demo-app spring-boot-demo:latest
# 测试应用
curl http://localhost:8080/
curl http://localhost:8080/health
curl http://localhost:8080/info
# 查看容器
docker ps
docker ps -a
# 查看容器日志
docker logs demo-app
docker logs -f demo-app # 实时查看
# 进入容器
docker exec -it demo-app bash
# 查看容器资源使用
docker stats demo-app
容器管理
# 停止容器
docker stop demo-app
# 启动容器
docker start demo-app
# 重启容器
docker restart demo-app
# 删除容器
docker rm demo-app
# 删除镜像
docker rmi spring-boot-demo:latest
1.5 第一步总结与练习
必掌握技能检查单
-
\] 能独立编写Dockerfile
-
\] 熟练使用docker run命令及常用参数
-
\] 理解镜像分层和缓存机制
- 修改HelloController,添加一个返回当前时间的API
- 重新构建镜像,使用新的版本标签
- 同时运行多个容器实例,映射到不同端口
第二步:体验托管K8s (1-2周)
目标
- 体验Kubernetes托管服务
- 掌握kubectl基本操作
- 理解Pod、Service等基础概念
2.1 选择云服务商
阿里云容器服务ACK
# 1. 登录阿里云控制台
# 2. 搜索"容器服务Kubernetes版"
# 3. 点击"免费试用"
# 4. 创建托管版集群(选择最小规格节省费用)
腾讯云TKE
# 1. 登录腾讯云控制台
# 2. 搜索"容器服务TKE"
# 3. 点击"免费试用"
# 4. 创建托管集群
2.2 kubectl安装和配置
Linux安装kubectl
# 下载最新版本
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
# 安装kubectl
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# 验证安装
kubectl version --client
配置访问凭证
# 从云服务商控制台下载kubeconfig文件
# 通常保存在 ~/.kube/config
# 验证连接
kubectl cluster-info
kubectl get nodes
2.3 推送镜像到镜像仓库
使用阿里云容器镜像服务
# 1. 在阿里云控制台创建容器镜像服务命名空间
# 2. 创建镜像仓库
# 登录阿里云镜像仓库
docker login --username=your-username registry.cn-hangzhou.aliyuncs.com
# 给镜像打标签
docker tag spring-boot-demo:latest registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-boot-demo:latest
# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-boot-demo:latest
使用Docker Hub
# 登录Docker Hub
docker login
# 给镜像打标签
docker tag spring-boot-demo:latest your-dockerhub-username/spring-boot-demo:latest
# 推送镜像
docker push your-dockerhub-username/spring-boot-demo:latest
2.4 通过控制台部署应用
控制台操作步骤
- 进入K8s集群控制台
- 选择"工作负载" -> "无状态"
- 点击"使用镜像创建"
- 配置如下参数:
- 应用名称:
spring-boot-demo
- 镜像:
your-registry/spring-boot-demo:latest
- 端口:
8080
- 副本数:
2
- 应用名称:
2.5 kubectl基本操作实践
查看资源
# 查看所有命名空间
kubectl get namespaces
# 查看Pod
kubectl get pods
kubectl get pods -o wide
kubectl get pods -n kube-system
# 查看部署
kubectl get deployments
kubectl get deploy
# 查看服务
kubectl get services
kubectl get svc
# 查看所有资源
kubectl get all
查看详细信息
# 描述Pod详细信息
kubectl describe pod <pod-name>
# 描述部署详细信息
kubectl describe deployment spring-boot-demo
# 查看Pod日志
kubectl logs <pod-name>
kubectl logs -f <pod-name> # 实时查看
kubectl logs <pod-name> -c <container-name> # 多容器情况
Pod操作
# 进入Pod
kubectl exec -it <pod-name> -- bash
kubectl exec -it <pod-name> -- sh
# 在Pod中执行命令
kubectl exec <pod-name> -- ls /app
kubectl exec <pod-name> -- curl http://localhost:8080/health
# 端口转发
kubectl port-forward <pod-name> 8080:8080
kubectl port-forward service/spring-boot-demo 8080:8080
2.6 YAML配置文件部署
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-demo
labels:
app: spring-boot-demo
spec:
replicas: 2
selector:
matchLabels:
app: spring-boot-demo
template:
metadata:
labels:
app: spring-boot-demo
spec:
containers:
- name: spring-boot-demo
image: registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-boot-demo:latest
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-Xmx512m -Xms256m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 200m
memory: 256Mi
service.yaml
apiVersion: v1
kind: Service
metadata:
name: spring-boot-demo-service
spec:
selector:
app: spring-boot-demo
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer # 或者 ClusterIP, NodePort
使用YAML部署
# 部署应用
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# 或者一次性部署
kubectl apply -f deployment.yaml -f service.yaml
# 查看部署状态
kubectl rollout status deployment/spring-boot-demo
# 获取服务访问地址
kubectl get service spring-boot-demo-service
2.7 第二步总结与练习
必掌握技能检查单
-
\] 能使用kubectl连接到K8s集群
-
\] 理解Pod、Deployment、Service的基本概念
练习作业
- 尝试扩容和缩容应用副本数
- 修改应用配置,体验滚动更新
- 使用不同的Service类型访问应用
第三步:搭建简易CI/CD (2-3周)
目标
- 搭建GitLab和Jenkins环境
- 实现代码提交自动触发构建
- 完成自动部署到K8s的完整流程
3.1 环境准备
使用Docker搭建GitLab
# 创建GitLab目录
mkdir -p /opt/gitlab/{config,logs,data}
# 运行GitLab容器
docker run -d \
--hostname gitlab.example.com \
-p 80:80 -p 443:443 -p 22:22 \
--name gitlab \
--restart always \
-v /opt/gitlab/config:/etc/gitlab \
-v /opt/gitlab/logs:/var/log/gitlab \
-v /opt/gitlab/data:/var/opt/gitlab \
--shm-size 256m \
gitlab/gitlab-ce:latest
# 查看初始密码
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
使用Docker搭建Jenkins
# 创建Jenkins数据目录
mkdir -p /opt/jenkins_home
sudo chown -R 1000:1000 /opt/jenkins_home
# 运行Jenkins容器
docker run -d \
-p 8080:8080 -p 50000:50000 \
--name jenkins \
--restart always \
-v /opt/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
jenkins/jenkins:lts
# 获取初始管理员密码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
3.2 GitLab配置
创建项目
-
访问 http://localhost (GitLab)
-
使用root账户登录
-
创建新项目:
spring-boot-demo
-
上传代码到GitLab仓库
配置Git(如果未配置)
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"初始化本地仓库
cd spring-boot-demo
git init
git add .
git commit -m "Initial commit"关联远程仓库
git remote add origin http://localhost/root/spring-boot-demo.git
git push -u origin master
创建GitLab CI配置
# .gitlab-ci.yml
stages:
- build
- test
- deploy
variables:
IMAGE_NAME: "registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-boot-demo"
IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"
build:
stage: build
image: maven:3.8.5-openjdk-11
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- mvn clean package -DskipTests
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker build -t $IMAGE_NAME:latest .
- docker push $IMAGE_NAME:$IMAGE_TAG
- docker push $IMAGE_NAME:latest
artifacts:
paths:
- target/*.jar
expire_in: 1 hour
test:
stage: test
image: maven:3.8.5-openjdk-11
script:
- mvn test
dependencies:
- build
deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- echo $KUBECONFIG | base64 -d > /tmp/kubeconfig
- export KUBECONFIG=/tmp/kubeconfig
- kubectl set image deployment/spring-boot-demo spring-boot-demo=$IMAGE_NAME:$IMAGE_TAG
- kubectl rollout status deployment/spring-boot-demo
only:
- master
3.3 Jenkins配置
安装必需插件
- 访问 http://localhost:8080 (Jenkins)
- 安装建议的插件
- 额外安装以下插件:
- Git Plugin
- Docker Plugin
- Kubernetes Plugin
- Pipeline Plugin
创建Pipeline任务
-
新建Item -> Pipeline
-
配置Git仓库地址
-
创建Jenkinsfile
// Jenkinsfile
pipeline {
agent anyenvironment { DOCKER_REGISTRY = 'registry.cn-hangzhou.aliyuncs.com' IMAGE_NAME = 'your-namespace/spring-boot-demo' KUBECONFIG_CREDENTIAL = 'kubeconfig' } stages { stage('Checkout') { steps { checkout scm } } stage('Build') { steps { sh 'mvn clean package -DskipTests' } } stage('Test') { steps { sh 'mvn test' } post { always { junit 'target/surefire-reports/*.xml' } } } stage('Docker Build') { steps { script { def imageTag = "${env.BUILD_NUMBER}-${env.GIT_COMMIT[0..7]}" def image = docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${imageTag}") docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry-credential') { image.push() image.push('latest') } env.IMAGE_TAG = imageTag } } } stage('Deploy to K8s') { steps { withKubeConfig([credentialsId: KUBECONFIG_CREDENTIAL]) { sh """ kubectl set image deployment/spring-boot-demo \ spring-boot-demo=${DOCKER_REGISTRY}/${IMAGE_NAME}:${env.IMAGE_TAG} kubectl rollout status deployment/spring-boot-demo """ } } } } post { always { cleanWs() } success { echo 'Pipeline succeeded!' } failure { echo 'Pipeline failed!' } }
}
3.4 完整部署YAML文件
k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: demo
k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-demo
namespace: demo
labels:
app: spring-boot-demo
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: spring-boot-demo
template:
metadata:
labels:
app: spring-boot-demo
version: v1
spec:
containers:
- name: spring-boot-demo
image: registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-boot-demo:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
env:
- name: JAVA_OPTS
value: "-Xmx512m -Xms256m -Dspring.profiles.active=prod"
- name: TZ
value: "Asia/Shanghai"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
imagePullSecrets:
- name: registry-secret
k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: spring-boot-demo-service
namespace: demo
labels:
app: spring-boot-demo
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
name: http
selector:
app: spring-boot-demo
k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: spring-boot-demo-ingress
namespace: demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: demo.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: spring-boot-demo-service
port:
number: 80
3.5 自动化部署脚本
deploy.sh
#!/bin/bash
set -e
# 配置变量
NAMESPACE="demo"
APP_NAME="spring-boot-demo"
IMAGE_TAG=${1:-latest}
echo "Deploying $APP_NAME with image tag: $IMAGE_TAG"
# 创建命名空间(如果不存在)
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
# 部署应用
kubectl apply -f k8s/
# 更新镜像
kubectl set image deployment/$APP_NAME \
$APP_NAME=registry.cn-hangzhou.aliyuncs.com/your-namespace/$APP_NAME:$IMAGE_TAG \
-n $NAMESPACE
# 等待部署完成
kubectl rollout status deployment/$APP_NAME -n $NAMESPACE
# 获取服务信息
echo "Deployment completed successfully!"
kubectl get pods -n $NAMESPACE
kubectl get svc -n $NAMESPACE
3.6 第三步总结与练习
必掌握技能检查单
-
\] 能搭建GitLab和Jenkins环境
-
\] 能编写Jenkinsfile或.gitlab-ci.yml
练习作业
- 添加代码质量检查阶段(如SonarQube)
- 实现多环境部署(开发、测试、生产)
- 添加部署失败自动回滚功能
第四步:深入学习K8s核心概念 (3-4周)
目标
- 掌握K8s核心资源对象
- 理解声明式API理念
- 具备生产环境K8s应用管理能力
4.1 核心概念深入理解
声明式API理念
# 传统命令式
kubectl run nginx --image=nginx --port=80
kubectl expose deployment nginx --type=LoadBalancer
# 声明式
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
4.2 Deployment深入学习
高级Deployment配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-demo
namespace: production
labels:
app: spring-boot-demo
tier: backend
version: v2
spec:
# 副本数量
replicas: 5
# 选择器
selector:
matchLabels:
app: spring-boot-demo
tier: backend
# 更新策略
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 更新时最多不可用的Pod数量
maxSurge: 2 # 更新时最多超出期望副本数的Pod数量
# 修订历史限制
revisionHistoryLimit: 10
# 进度截止时间
progressDeadlineSeconds: 600
# Pod模板
template:
metadata:
labels:
app: spring-boot-demo
tier: backend
version: v2
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/actuator/prometheus"
spec:
# 优雅停止时间
terminationGracePeriodSeconds: 30
# 重启策略
restartPolicy: Always
# 调度相关
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- spring-boot-demo
topologyKey: kubernetes.io/hostname
containers:
- name: spring-boot-demo
image: registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-boot-demo:v2.0.0
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
protocol: TCP
- name: management
containerPort: 8081
protocol: TCP
# 环境变量
env:
- name: JAVA_OPTS
value: "-Xmx1g -Xms512m -Dspring.profiles.active=prod"
- name: SERVER_PORT
value: "8080"
- name: MANAGEMENT_SERVER_PORT
value: "8081"
# 资源限制
resources:
limits:
cpu: 2000m
memory: 2Gi
ephemeral-storage: 1Gi
requests:
cpu: 1000m
memory: 1Gi
ephemeral-storage: 500Mi
# 健康检查
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8081
initialDelaySeconds: 90
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8081
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
# 启动探针
startupProbe:
httpGet:
path: /actuator/health
port: 8081
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 30
# 安全上下文
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# 挂载卷
volumeMounts:
- name: tmp
mountPath: /tmp
- name: app-config
mountPath: /app/config
readOnly: true
- name: app-logs
mountPath: /app/logs
# 定义卷
volumes:
- name: tmp
emptyDir: {}
- name: app-config
configMap:
name: spring-boot-demo-config
- name: app-logs
emptyDir: {}
# 镜像拉取密钥
imagePullSecrets:
- name: registry-secret
Deployment管理命令
# 部署应用
kubectl apply -f deployment.yaml
# 查看部署状态
kubectl get deployments -n demo
kubectl describe deployment spring-boot-demo -n demo
# 查看副本集
kubectl get replicasets -n demo
kubectl get rs -n demo
# 扩容缩容
kubectl scale deployment spring-boot-demo --replicas=5 -n demo
# 滚动更新
kubectl set image deployment/spring-boot-demo \
spring-boot-demo=registry.cn-hangzhou.aliyuncs.com/your-namespace/spring-boot-demo:v2.1.0 \
-n demo
# 查看更新状态
kubectl rollout status deployment/spring-boot-demo -n demo
# 查看更新历史
kubectl rollout history deployment/spring-boot-demo -n demo
# 回滚
kubectl rollout undo deployment/spring-boot-demo -n demo
kubectl rollout undo deployment/spring-boot-demo --to-revision=2 -n demo
# 暂停和恢复更新
kubectl rollout pause deployment/spring-boot-demo -n demo
kubectl rollout resume deployment/spring-boot-demo -n demo
4.3 Service深入学习
ClusterIP Service
apiVersion: v1
kind: Service
metadata:
name: spring-boot-demo-clusterip
namespace: demo
labels:
app: spring-boot-demo
spec:
type: ClusterIP
selector:
app: spring-boot-demo
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
- name: management
port: 8081
targetPort: 8081
protocol: TCP
NodePort Service
apiVersion: v1
kind: Service
metadata:
name: spring-boot-demo-nodeport
namespace: demo
spec:
type: NodePort
selector:
app: spring-boot-demo
ports:
- name: http
port: 80
targetPort: 8080
nodePort: 30080
protocol: TCP
LoadBalancer Service
apiVersion: v1
kind: Service
metadata:
name: spring-boot-demo-lb
namespace: demo
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
service.beta.kubernetes.io/alicloud-loadbalancer-spec: slb.s1.small
spec:
type: LoadBalancer
selector:
app: spring-boot-demo
ports:
- name: http
port: 80
targetPort: 8080
externalTrafficPolicy: Local
Headless Service
apiVersion: v1
kind: Service
metadata:
name: spring-boot-demo-headless
namespace: demo
spec:
clusterIP: None
selector:
app: spring-boot-demo
ports:
- name: http
port: 8080
targetPort: 8080
4.4 Ingress配置
Nginx Ingress Controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: spring-boot-demo-ingress
namespace: demo
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
# 限流配置
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
spec:
tls:
- hosts:
- demo.example.com
secretName: demo-tls
rules:
- host: demo.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: spring-boot-demo-service
port:
number: 80
- path: /api/v1
pathType: Prefix
backend:
service:
name: spring-boot-demo-service
port:
number: 80
SSL证书配置
apiVersion: v1
kind: Secret
metadata:
name: demo-tls
namespace: demo
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi... # base64编码的证书
tls.key: LS0tLS1CRUdJTi... # base64编码的私钥
4.5 ConfigMap和Secret
ConfigMap示例
apiVersion: v1
kind: ConfigMap
metadata:
name: spring-boot-demo-config
namespace: demo
data:
# 属性文件格式
application.properties: |
server.port=8080
management.server.port=8081
management.endpoints.web.exposure.include=health,info,metrics,prometheus
spring.datasource.url=jdbc:mysql://mysql-service:3306/demo
spring.datasource.username=app_user
logging.level.com.example=DEBUG
# YAML格式
application.yml: |
server:
port: 8080
management:
server:
port: 8081
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
spring:
datasource:
url: jdbc:mysql://mysql-service:3306/demo
username: app_user
logging:
level:
com.example: DEBUG
# 普通文本配置
nginx.conf: |
upstream backend {
server spring-boot-demo-service:80;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
Secret示例
apiVersion: v1
kind: Secret
metadata:
name: spring-boot-demo-secret
namespace: demo
type: Opaque
data:
# base64编码的值
database-password: cGFzc3dvcmQxMjM= # password123
api-key: YWJjZGVmZ2hpams= # abcdefghijk
stringData:
# 明文值,会自动base64编码
jwt-secret: "my-super-secret-jwt-key"
redis-password: "redis123456"
在Pod中使用ConfigMap和Secret
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
spec:
containers:
- name: app
image: spring-boot-demo:latest
# 环境变量方式
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: spring-boot-demo-secret
key: database-password
- name: API_KEY
valueFrom:
secretKeyRef:
name: spring-boot-demo-secret
key: api-key
# 环境变量组
envFrom:
- configMapRef:
name: spring-boot-demo-config
- secretRef:
name: spring-boot-demo-secret
# 文件挂载方式
volumeMounts:
- name: config-volume
mountPath: /app/config
- name: secret-volume
mountPath: /app/secrets
readOnly: true
volumes:
- name: config-volume
configMap:
name: spring-boot-demo-config
items:
- key: application.yml
path: application.yml
- name: secret-volume
secret:
secretName: spring-boot-demo-secret
defaultMode: 0400
ConfigMap和Secret管理命令
# 创建ConfigMap
kubectl create configmap app-config --from-file=config/
kubectl create configmap app-config --from-literal=key1=value1 --from-literal=key2=value2
# 创建Secret
kubectl create secret generic app-secret --from-file=secret-file.txt
kubectl create secret generic app-secret --from-literal=password=123456
# 查看ConfigMap和Secret
kubectl get configmaps -n demo
kubectl get secrets -n demo
# 查看详细内容
kubectl describe configmap spring-boot-demo-config -n demo
kubectl get secret spring-boot-demo-secret -o yaml -n demo
# 编辑ConfigMap
kubectl edit configmap spring-boot-demo-config -n demo
# 删除
kubectl delete configmap spring-boot-demo-config -n demo
kubectl delete secret spring-boot-demo-secret -n demo
4.6 水平自动扩缩容(HPA)
HPA配置
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: spring-boot-demo-hpa
namespace: demo
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: spring-boot-demo
minReplicas: 2
maxReplicas: 10
metrics:
# CPU使用率
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# 内存使用率
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
# 自定义指标(需要metrics-server)
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"
# 扩缩容行为
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
selectPolicy: Min
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
HPA管理命令
# 查看HPA状态
kubectl get hpa -n demo
kubectl describe hpa spring-boot-demo-hpa -n demo
# 手动测试扩容(压力测试)
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh
# 在容器内执行
while true; do wget -q -O- http://spring-boot-demo-service.demo.svc.cluster.local/; done
# 查看扩容过程
kubectl get pods -n demo -w
4.7 数据持久化
PersistentVolume和PersistentVolumeClaim
# PV定义
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: standard
hostPath:
path: /data/mysql
---
# PVC定义
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: demo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
使用动态存储
# StorageClass定义
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
fsType: ext4
allowVolumeExpansion: true
---
# 使用StorageClass的PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data-pvc
namespace: demo
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 20Gi
MySQL有状态应用示例
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: demo
spec:
serviceName: mysql
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
- name: MYSQL_DATABASE
value: "demo"
- name: MYSQL_USER
value: "app_user"
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: user-password
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
- name: mysql-config
mountPath: /etc/mysql/conf.d
livenessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
command:
- mysql
- -h
- localhost
- -u
- root
- -p$MYSQL_ROOT_PASSWORD
- -e
- "SELECT 1"
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
volumes:
- name: mysql-config
configMap:
name: mysql-config
volumeClaimTemplates:
- metadata:
name: mysql-storage
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: fast-ssd
resources:
requests:
storage: 20Gi
4.8 命名空间和资源配额
命名空间管理
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: production
team: backend
---
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
environment: staging
team: backend
ResourceQuota配置
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: production
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
persistentvolumeclaims: "10"
pods: "50"
services: "10"
secrets: "20"
configmaps: "20"
LimitRange配置
apiVersion: v1
kind: LimitRange
metadata:
name: default-limit-range
namespace: production
spec:
limits:
- default:
cpu: 1000m
memory: 1Gi
defaultRequest:
cpu: 200m
memory: 256Mi
type: Container
- max:
cpu: 2000m
memory: 4Gi
min:
cpu: 100m
memory: 128Mi
type: Container
4.9 高级调度策略
节点选择器
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
spec:
nodeSelector:
disktype: ssd
zone: us-west1-a
containers:
- name: app
image: spring-boot-demo:latest
节点亲和性
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-demo
spec:
replicas: 3
selector:
matchLabels:
app: spring-boot-demo
template:
metadata:
labels:
app: spring-boot-demo
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- spring-boot-demo
topologyKey: kubernetes.io/hostname
containers:
- name: spring-boot-demo
image: spring-boot-demo:latest
污点和容忍
# 给节点添加污点
kubectl taint nodes node1 key1=value1:NoSchedule
# 查看节点污点
kubectl describe node node1
# 删除污点
kubectl taint nodes node1 key1=value1:NoSchedule-
# Pod容忍配置
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
spec:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
containers:
- name: app
image: spring-boot-demo:latest
4.10 监控和可观测性
Prometheus监控配置
apiVersion: v1
kind: ServiceMonitor
metadata:
name: spring-boot-demo
namespace: demo
labels:
app: spring-boot-demo
spec:
selector:
matchLabels:
app: spring-boot-demo
endpoints:
- port: management
path: /actuator/prometheus
interval: 30s
scrapeTimeout: 10s
日志收集配置
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
namespace: demo
data:
filebeat.yml: |
filebeat.inputs:
- type: container
paths:
- /var/log/containers/*spring-boot-demo*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"
resource_type: "container"
output.elasticsearch:
hosts: ["elasticsearch:9200"]
setup.kibana:
host: "kibana:5601"
4.11 安全配置
RBAC配置
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: spring-boot-demo-sa
namespace: demo
---
# Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: demo
name: demo-role
rules:
- apiGroups: [""]
resources: ["pods", "configmaps", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: demo-rolebinding
namespace: demo
subjects:
- kind: ServiceAccount
name: spring-boot-demo-sa
namespace: demo
roleRef:
kind: Role
name: demo-role
apiGroup: rbac.authorization.k8s.io
NetworkPolicy配置
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: spring-boot-demo-netpol
namespace: demo
spec:
podSelector:
matchLabels:
app: spring-boot-demo
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
- podSelector:
matchLabels:
app: nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: mysql
ports:
- protocol: TCP
port: 3306
- to: []
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
4.12 完整的生产环境部署示例
kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- configmap.yaml
- secret.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
- hpa.yaml
images:
- name: spring-boot-demo
newTag: v2.1.0
namespace: production
commonLabels:
app: spring-boot-demo
environment: production
version: v2.1.0
replicas:
- name: spring-boot-demo
count: 5
使用Kustomize部署
# 查看生成的YAML
kubectl kustomize overlays/production
# 部署到生产环境
kubectl apply -k overlays/production
# 查看部署状态
kubectl get all -n production -l app=spring-boot-demo
4.13 故障排除和调试
常用调试命令
# 查看Pod详细信息
kubectl describe pod <pod-name> -n demo
# 查看Pod日志
kubectl logs <pod-name> -n demo
kubectl logs <pod-name> -c <container-name> -n demo
kubectl logs -f <pod-name> -n demo # 实时日志
kubectl logs --previous <pod-name> -n demo # 查看上一次的日志
# 进入Pod调试
kubectl exec -it <pod-name> -n demo -- bash
kubectl exec -it <pod-name> -n demo -c <container-name> -- sh
# 端口转发调试
kubectl port-forward pod/<pod-name> 8080:8080 -n demo
kubectl port-forward service/spring-boot-demo-service 8080:80 -n demo
# 查看事件
kubectl get events -n demo --sort-by=.metadata.creationTimestamp
kubectl get events --field-selector involvedObject.name=<pod-name> -n demo
# 查看资源使用情况
kubectl top nodes
kubectl top pods -n demo
# 调试DNS解析
kubectl run test-pod --image=busybox --rm -it --restart=Never -- nslookup spring-boot-demo-service.demo.svc.cluster.local
常见问题排查
Pod无法启动
# 1. 查看Pod状态
kubectl get pods -n demo
# 2. 查看Pod详细信息
kubectl describe pod <pod-name> -n demo
# 3. 常见原因和解决方法
# - ImagePullBackOff: 检查镜像地址、拉取权限
# - CrashLoopBackOff: 检查应用日志、健康检查配置
# - Pending: 检查资源限制、节点调度条件
服务无法访问
# 1. 检查Service配置
kubectl get svc -n demo
kubectl describe svc spring-boot-demo-service -n demo
# 2. 检查EndPoints
kubectl get endpoints spring-boot-demo-service -n demo
# 3. 测试服务连通性
kubectl run test-pod --image=busybox --rm -it --restart=Never -n demo -- wget -qO- http://spring-boot-demo-service:80
4.14 最佳实践总结
资源管理最佳实践
# 1. 始终设置资源请求和限制
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
# 2. 使用合适的健康检查
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
# 3. 设置安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
命名和标签最佳实践
metadata:
name: spring-boot-demo
labels:
app.kubernetes.io/name: spring-boot-demo
app.kubernetes.io/instance: demo-instance
app.kubernetes.io/version: "v2.1.0"
app.kubernetes.io/component: backend
app.kubernetes.io/part-of: demo-application
app.kubernetes.io/managed-by: kustomize
environment: production
team: backend
4.15 学习验证和下一步
技能验证检查单
-
\] 理解K8s声明式API理念
-
\] 能配置HPA自动扩缩容
-
\] 掌握基本的故障排除技能
综合练习项目
创建一个完整的微服务应用,包含:
- 前端服务(Nginx + React)
- 后端API服务(Spring Boot)
- 数据库服务(MySQL)
- 缓存服务(Redis)
- 配置管理(ConfigMap/Secret)
- 服务发现(Service/Ingress)
- 自动扩缩容(HPA)
- 持久化存储(PVC)
进阶学习方向
- 服务网格:学习Istio或Linkerd
- 云原生存储:学习Rook、Longhorn
- 多集群管理:学习ArgoCD、Flux
- 可观测性:深入学习Prometheus、Grafana、Jaeger
- 安全加固:学习Falco、OPA Gatekeeper