我目前是直接在dockers desktop上面直接使用的k8s环境,通过在左侧的"Kubernetes"选项开启,这里我们不用直接去生成Deployments和Pods,因为我们会在配置文件里配置对应的deployment和pod,执行命令后会自动生成,在执行kubectl命令之前,我们必须使用docker命令生成对应的镜像,不然在执行kubectl的时候找不到镜像文件也会报错,我们看下最终的整个显示


我们先看下后端的配置,这里分为了2个配置文件,分别为backend-configmap.yaml和backend-deployment.yaml文件,其中backend-configmap.yaml是用来配置非密码之类的公共配置,backend-deployment.yaml用来配置deployment和pod等相关信息,我们先看下backend-configmap.yaml的配置如下:
XML
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-config
data:
# Spring Boot 标准配置(注意命名规则)
SPRING_DATASOURCE_URL: "jdbc:mysql://host.docker.internal:3306/smart_cs?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true"
SPRING_DATASOURCE_USERNAME: "root"
这里的SPRING_DATASOURCE_URL对应到我们代码里的配置是spring.datasource.url,命名规则就是把application.yml里面的配置换成大写,并用下划线代替点号,自定义的变量也是一样,
Spring Boot 有一套宽松的绑定(Relaxed Binding) 规则,它会自动将大写带下划线 的环境变量转换为驼峰命名的 application.properties 配置。
| application.properties 配置 | 环境变量名 | 说明 |
|---|---|---|
spring.datasource.url |
SPRING_DATASOURCE_URL |
✅ 自动映射 |
spring.datasource.username |
SPRING_DATASOURCE_USERNAME |
✅ 自动映射 |
spring.redis.host |
SPRING_REDIS_HOST |
✅ 自动映射 |
spring.cloud.nacos.discovery.server-addr |
SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR |
✅ 支持中划线转下划线 |
app.custom.timeout |
APP_CUSTOM_TIMEOUT |
✅ 自定义参数同样适用 |
也就是说,你在 ConfigMap 中写 SPRING_DATASOURCE_URL,Spring Boot 就能自动识别为 spring.datasource.url,无需任何额外配置!
定义好后首先启动它,
XML
kubectl apply -f backend-configmap.ymal
启动后我们可以在"config maps and secrets"模块看到启动的服务"backend-config",然后我们需要定义密码,这个时候因为密码不能手动配置到文件里面,防止密码泄露,因此我们一般是通过命令的方式在终端执行,命令如下:
XML
kubectl create generic db-secret --from-literal=SPRING_DATASOURCE_PASSWORD=123456
命令执行完成后我们也可以在"config maps and secrets"模块看到启动的服务"db-secret",如果在配置密码的时候写错了,我们还可以通过以下命令重新设置
XML
kubectl create secret generic db-secret `
--from-literal=SPRING_DATASOURCE_PASSWORD=你的新密码 `
--dry-run=client -o yaml | kubectl apply -f -
重新设置密码后我们需要重启服务
XML
kubectl rollout restart deployment/backend-service
在新的pod启动完成后,我们可以查看密码是否设置正确
XML
kubectl exec -it <新Pod名称> -- env | findstr SPRING_DATASOURCE_PASSWORD
到此我们就完成了配置,接下来我们看backend-deployment.yaml配置,如下:
XML
# API 版本:定义使用的 K8s API 版本
# apps/v1 是 Deployment 的稳定版本
apiVersion: apps/v1
# 资源类型:Deployment(无状态应用部署控制器)
# Deployment 负责管理 Pod 的副本数、滚动更新、回滚等
kind: Deployment
# 元数据:描述该 Deployment 自身的信息
metadata:
name: backend-service # Deployment 的名称,集群内唯一
labels: # 标签(键值对),用于分类和选择
app: backend # 定义该资源属于 "backend" 应用组
# 规格:定义 Deployment 的期望状态
spec:
# 副本数:期望运行的 Pod 数量
# 设置为 1 表示只运行 1 个实例;生产环境可设为 3 或更多
replicas: 1
# 选择器:定义该 Deployment 管理哪些 Pod
# 必须匹配下面 template 中定义的 labels
selector:
matchLabels:
app: backend # 只管理带有 app=backend 标签的 Pod
# 模板:定义 Pod 的蓝图(类似于 Docker 的容器配置)
template:
metadata:
labels: # Pod 的标签,必须匹配上面的 selector
app: backend
spec: # Pod 规格
containers: # 容器列表(Pod 可以包含多个容器)
- name: client-agent-backend-pod # 容器名称,在 Pod 内唯一
image: client-agent-backend # 容器镜像名(本地镜像,不带仓库地址)
# 镜像拉取策略:
# - Always:每次都从远程仓库拉取
# - IfNotPresent:本地没有才拉取(开发环境推荐)
# - Never:只使用本地镜像
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8090 # 容器内部监听的端口
# protocol: TCP # 默认 TCP,可以省略
# 环境变量(可选):传递给容器的配置
# env:
# - name: SPRING_PROFILES_ACTIVE
# value: "prod"
# - name: NACOS_SERVER_ADDR
# value: "nacos-service:8848"
# 资源限制(可选):CPU 和内存限制
# resources:
# requests: # 最低保证资源
# memory: "512Mi"
# cpu: "250m"
# limits: # 最大可用资源
# memory: "1Gi"
# cpu: "500m"
# ========== 通过 ConfigMap 和 Secret 注入配置 ==========
envFrom:
# 1. 从 ConfigMap 读取非敏感配置(数据库地址、Redis 地址等)
- configMapRef:
name: backend-config
# 2. 从 Secret 读取敏感信息(密码)
- secretRef:
name: db-secret
---
# --- 分隔符:表示这是一个独立的资源 ---
# API 版本:Service 的 API 版本
apiVersion: v1
# 资源类型:Service(服务发现与负载均衡)
# Service 为 Pod 提供一个稳定的访问入口(IP 和 DNS 名称)
kind: Service
metadata:
name: backend-service # Service 名称
# 重要:这个名称就是前端 Nginx 中 proxy_pass 要填的地址!
# 例如:http://backend-service:8090
spec:
# 选择器:将流量转发给带有 app=backend 标签的 Pod
selector:
app: backend
ports:
- protocol: TCP # 协议类型
port: 8090 # Service 暴露的端口(其他服务访问时用的端口)
targetPort: 8090 # 转发到 Pod 的端口(必须匹配 containerPort)
# Service 类型:
# - ClusterIP(默认):仅在集群内部可访问
# - NodePort:在每个节点的固定端口上暴露,外部可通过 <NodeIP>:<NodePort> 访问
# - LoadBalancer:云环境下提供外部负载均衡器
type: ClusterIP
这里我们需要注意的是Deployment配置下面的image参数配置,这个一定是你的通过docker打的镜像名称,不然找不到的话,启动不了,其他的配置详情参考配置里面的说明,启动完成后如果我们想看看后端你接口是否正常启动,有可能直接通过http://localhost:8090访问不了,这里我使用的是临时方案:
XML
kubectl port-forward service/backend-service 8090:8090
命令执行后,我们就可以正常访问后端接口了,启动完成后我们可以在Deployments和Pods分别看到backend-service和backend-service-866....的服务,如果服务没有正常启动我们可以去查看日志的方式看看是什么原因
XML
# 获取当前启动的所有pod
kubectl get pods
# 查看后端pod的日志
kubectl logs backend-service-8667b65b6f-ttvvl
亦或者通过这个命令的Event参数查看
XML
kubectl describe pod <pod-name>
这个命令将会看到类似这样的具体报错,这才是解决问题的钥匙:
• Failed to pull image "xxx": rpc error: code = NotFound(镜像不存在)
• Failed to pull image "xxx": rpc error: code = Unauthenticated(私有仓库认证失败)
• Failed to pull image "xxx": network timeout(网络超时)
如果是因为backend-deployment.ymal配置的原因出现错误,我们可以先删除pods中配置文件生成的pod,如下:
XML
# 删除配置文件
kubectl delete -f backend-deployment.ymal
# 再次生成pod
kubectl apply -f backend-deployment.ymal
或者我们重启一个新pod代替老的pod
XML
kubectl rollout restart deployment\backend-service
接下来我们看前端的部署,在前端我们也配置了2个配置,分别是frontend-configmap.yaml和frontend-deployment.yaml,frontend-configmap.yaml主要用于配置nginx,配置如下:
XML
# API 版本
apiVersion: v1
# 资源类型:ConfigMap(配置管理)
# ConfigMap 用于存储非敏感配置数据,可以挂载到 Pod 中
kind: ConfigMap
metadata:
name: frontend-nginx-config # ConfigMap 名称
# data:存储配置数据(键值对)
# 键名 default.conf 会成为挂载后的文件名
data:
default.conf: | # | 表示多行字符串(保留换行)
# Nginx 服务器配置
server {
# 监听端口
listen 80;
# 服务器域名(可以填实际域名,开发环境用 localhost)
server_name localhost;
# 静态文件根目录
root /usr/share/nginx/html;
# 默认首页文件
index index.html;
# ========== 反向代理配置:处理 API 请求 ==========
# location /api/ 匹配所有以 /api/ 开头的请求路径
location /api/ {
# proxy_pass:将请求转发到后端服务
# 注意:http://backend-service:8090 中的 backend-service
# 是 K8s 中 Service 的名称,K8s 内置 DNS 会解析它
# 末尾的 / 很重要:表示保留 /api/ 前缀
# 例如:/api/login -> http://backend-service:8090/api/login
proxy_pass http://backend-service.default.svc.cluster.local:8090/api/;
# 代理请求头设置(保证后端能拿到真实信息)
# 传递原始 Host 头
proxy_set_header Host $host;
# 传递真实客户端 IP
proxy_set_header X-Real-IP $remote_addr;
# 传递代理链上的所有 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 传递原始协议(http/https)
proxy_set_header X-Forwarded-Proto $scheme;
}
# ========== SPA 路由配置 ==========
# location / 匹配所有未被上面 location 匹配的请求
location / {
# try_files:按顺序尝试处理请求
# $uri -> 尝试作为文件(如 /about 找 about.html)
# $uri/ -> 尝试作为目录(如 /about/ 找 about/index.html)
# /index.html -> 如果都找不到,返回 index.html
# 这样前端路由(Vue Router/React Router)就能接管页面渲染
try_files $uri $uri/ /index.html;
}
# ========== 静态资源缓存优化 ==========
# 匹配常见静态资源文件(js, css, 图片等)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
# 设置缓存过期时间为 1 年(因为静态资源通常带 hash)
expires 1y;
# 设置缓存头为 public(允许 CDN 缓存)和 immutable(内容不变)
add_header Cache-Control "public, immutable";
}
}
这里需要注意的是proxy_pass代理的配置,我们这里不能使用backend-service服务,因为只是这样配置的话,前端是没有办法访问后端接口的,它在k8s中有特定访问路径,这通常是因为 Pod 的 /etc/resolv.conf 中只配置了 default.svc.cluster.local 作为搜索域,而没有 svc.cluster.local 和 cluster.local,因此这个地方的配置是http://backend-service.default.svc.cluster.local:8090/api/,再看下frontend-deployment.ymal
XML
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-service
labels:
app: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: nginx-frontend
image: client-agent-front:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80 # Nginx 默认监听 80 端口
# ========== 挂载 ConfigMap 覆盖 Nginx 配置 ==========
# 将 ConfigMap 中的 default.conf 挂载到容器内的配置文件
volumeMounts:
- name: nginx-config-volume # 引用的 volume 名称
mountPath: /etc/nginx/conf.d/default.conf # 容器内的目标路径
subPath: default.conf # 只挂载这个文件,不覆盖整个目录
# ========== 定义 Volume ==========
volumes:
- name: nginx-config-volume
configMap:
name: frontend-nginx-config # 引用前面创建的 ConfigMap
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend
ports:
- protocol: TCP
port: 80 # Service 端口
targetPort: 80 # 转发到 Pod 的端口
# NodePort 端口(可选,不指定则自动分配,范围 30000-32767)
nodePort: 31322
type: NodePort # 对外暴露(宿主机可访问)
这里需要注意的是client-agent-front镜像一定要存在,这里分别启动这2个配置文件
XML
kubectl apply -f frontend-configmap.ymal
kubectl apply -f front-deployment.ymal
启动后我们通过浏览器访问前端地址http://localhost:31322,这个时候你可能也没有办法访问到这个端口号,
✅ 解决方案(按推荐程度排序)
方案一:直接使用 port-forward(最省心,适合日常开发)
既然 port-forward 已经能用,你完全可以继续用这种方式访问前端。它的优点是:
-
不需要额外的网络配置。
-
端口可自定义(例如
8080)。 -
不受防火墙限制。
使用方法:在终端执行(保持窗口打开):
powershell
kubectl port-forward service/frontend-service 8099:80
然后访问 http://localhost:8080 即可。
提示 :你可以把
8080换成任意未被占用的端口(如8888)。这个方式适合本地开发调试,如果关掉终端窗口,转发会中断。
方案二:修复 NodePort 访问(一次性解决,以后直接用 localhost:30080)
① 确认 NodePort 端口号
先查看 Service 实际分配的端口:
powershell
kubectl get svc frontend-service
输出示例:
text
NAME TYPE CLUSTER-IP PORT(S) AGE
frontend-service NodePort 10.96.xxx.xxx 80:30080/TCP 10m
右边 30080 就是你的 NodePort 端口。如果你在 YAML 里固定写死了 30080,则就是它。
② 检查 Windows 防火墙(最常见原因)
Windows 默认会阻止外部访问未授权的端口。你需要手动放行该端口:
-
打开 Windows Defender 防火墙 -> 高级设置。
-
点击 入站规则 -> 新建规则。
-
选择 端口 -> TCP -> 特定本地端口 (填你的 NodePort,如
30080)。 -
选择 允许连接,下一步,勾选所有配置文件(域、专用、公用)。
-
取名(如
K8s NodePort),完成。
完成后,再次尝试 http://localhost:30080。
③ 如果防火墙放行后仍不行
尝试重启 Docker Desktop(它会重启 Kubernetes 集群):
-
右键 Docker Desktop 托盘图标 -> Restart。
-
等待 Kubernetes 重新变为
Running(查看左下角状态)。 -
重新部署应用(
kubectl apply -f ...),然后再次尝试访问。
④ 终极方案:改用 hostNetwork(不推荐生产)
如果实在解决不了,可以将 Deployment 的 Pod 直接使用宿主机网络(但会占用宿主机端口,且不适用于生产):
yaml
spec:
hostNetwork: true
containers:
- name: nginx-frontend
image: frontend:latest
ports:
- containerPort: 80
然后访问 http://localhost:80。但这样会与宿主机上其他服务端口冲突,需谨慎。
🧩 长期建议
-
开发阶段 :直接用
port-forward,简单高效。 -
团队协作或需要局域网访问:修复 NodePort + 防火墙规则。
-
未来生产环境:使用 Ingress 或云厂商的 LoadBalancer,不在本地暴露 NodePort。
有时候我们在访问后端接口的时候会出现502错误,这个时候你需要进入前端容器确定下后端服务是否已经能够正常访问
XML
# 进入前端容器内部
kubectl exec -it deployment/frontend-service -- sh
# 在容器内执行(测试 DNS 解析 + 端口连通性)
curl -v http://backend-service:8090/actuator/health
-
如果返回 200 OK 或 JSON 数据 :说明网络是通的,问题出在 Nginx 的
proxy_pass写法上(比如路径末尾少了/)。 -
如果返回
curl: (6) Could not resolve host:说明 DNS 解析失败(Service 名字拼写错误或不在同一个 Namespace)。 -
如果返回
curl: (7) Failed to connect:说明后端 Service 的端口(8090)映射错误,或者 Pod 没监听这个端口。
退出容器命令 :输入
exit回车。
这个错误在前面也提到,可能就是因为DNS解析出错,需要在frontend-deployment.ymal上的nginx proxy_pass配置替换为http://backend-service.default.svc.cluster.local:8090/api/。
在这里基本上就能完成正常的前后端访问了,我们可以通过下面命令查询容器的最终状态
XML
# 查看所有的pod
kubectl get pods
# 查看service对外提供的ip和端口
kubectl get svc
看下提供的对外信息

因为我们手动更改提供了对外的接口访问,因此我们对外的前端访问地址是http://localhost:8099。
还有一些常用命令
XML
# 对容器进行扩容
kubectl scale deployment/backend-service --replicas=3