K3S轻量部署SpringBoot+Vue:云原生架构实战指南
2026/8/26 10:52:53 网站建设 项目流程

1. 项目概述:为什么选择K3S来部署SpringBoot+Vue?

最近在折腾一个内部用的数据看板,后端是SpringBoot,前端是Vue 3。项目不大,但涉及到几个微服务模块,本地开发调试没问题,一到部署环节就头疼:服务器资源有限,用完整的K8s集群感觉杀鸡用牛刀,维护成本太高;用传统的Docker Compose编排,服务发现、负载均衡、配置管理又得自己手动拼凑,不够优雅。

折腾了一圈,最后把目光锁定在了K3S上。K3S可以理解为Kubernetes的“轻量版”,由Rancher实验室出品,它把K8s的很多外部依赖(比如etcd)都打包或替换成了更轻量的组件,安装包就几十兆,对资源的要求极低,单节点也能跑起来,但该有的核心功能一个不少:Pod部署、Service暴露、Ingress路由、ConfigMap/Secret配置管理,全都能支持。

对于SpringBoot+Vue这种经典的前后端分离项目,K3S提供了一个近乎完美的部署平台。后端Java服务可以打包成Jar再通过Docker镜像运行,也可以直接用构建好的镜像;前端Vue项目通过npm run build生成静态文件,用Nginx镜像托管。K3S负责把这两者组织起来:后端服务可以水平扩展,前端通过Ingress统一对外提供访问入口,配置和密钥也能集中管理,安全性比直接扔服务器上高得多。

简单说,如果你正在寻找一种比裸机部署更可靠、比传统虚拟机更灵活、比完整K8s更轻量的应用部署方案,那么用K3S来部署SpringBoot+Vue项目,是一个非常务实且高效的选择。它特别适合中小型团队、个人开发者、边缘计算场景或者只是想学习云原生部署的伙计们。

2. 整体架构与核心组件选型

在动手之前,我们先得把部署的蓝图画清楚。一个典型的SpringBoot+Vue应用在K3S里的部署架构,主要包含以下几个核心部分:

2.1 后端服务(SpringBoot)SpringBoot应用是我们的业务核心。部署时,我们通常将其打包成一个可执行的Jar文件,然后基于OpenJDK或Alpine JDK等基础镜像,制作成Docker镜像。在K3S中,这个镜像会以Pod的形式运行。为了确保稳定性和可扩展性,我们至少需要部署2个副本(Replica)。服务之间的通信、以及前端对后端的API调用,都通过K3S的Service来实现内部负载均衡。

2.2 前端服务(Vue)Vue项目经过构建后,生成的是纯粹的HTML、CSS、JavaScript静态资源。我们不需要Node.js运行时,只需要一个Web服务器来托管这些文件。Nginx是最常见的选择,它的镜像小巧,配置灵活。我们将构建好的dist目录复制到Nginx镜像内,并配置好路由规则,将所有API请求代理到后端的SpringBoot Service。

2.3 配置与路由中枢(K3S原生对象)这是K3S发挥威力的地方,我们主要用到三类资源:

  • ConfigMap & Secret:用来管理配置。例如,SpringBoot的application.yml中数据库连接信息、Vue项目中可能用到的环境变量,都可以从代码中抽离,通过ConfigMap注入。而数据库密码、API密钥等敏感信息,则必须使用Secret来存储,以密文形式挂载到Pod中。
  • Service:定义一组Pod的访问策略。它为后端的SpringBoot Pods提供一个稳定的内部域名(比如springboot-svc)和端口,前端Nginx通过这个内部域名就能访问到后端,无需关心后端Pod的具体IP地址。
  • Ingress:管理外部访问。它是集群的入口,我们通过定义Ingress规则,将不同的HTTP请求路径(例如,/api/*转发到后端Service,/转发到前端Nginx Service)路由到对应的后端服务。通常还需要一个Ingress Controller(如Nginx Ingress Controller)来具体实现这些规则。

2.4 存储与数据库(可选,按需引入)对于有状态服务,比如MySQL或Redis,虽然也可以部署在K3S内,但对于生产环境,我个人更倾向于使用云托管的数据库服务(如RDS)或独立的数据库服务器。这主要是出于数据持久化、备份和性能的考虑。如果坚持在K3S内部署,则需要妥善配置PersistentVolume(PV)和PersistentVolumeClaim(PVC)来保证数据不丢失。

整个数据流是这样的:用户访问网站域名 -> 请求到达K3S集群的Ingress Controller -> Ingress规则将/路径的请求路由到前端Nginx Service -> Nginx Pod返回静态页面 -> 页面中的JavaScript发起API调用(路径为/api/...) -> 请求再次经过Ingress,被路由到后端SpringBoot Service -> SpringBoot Pod处理请求并返回数据。

3. 实战部署:从零搭建K3S环境

理论讲完,我们进入实战环节。假设你有一台干净的Linux服务器(Ubuntu 20.04/22.04或CentOS 7/8),下面是一步步的操作指南。

3.1 K3S服务器安装与初始化K3S的安装简单到令人发指。使用官方的一键安装脚本即可。这里我们安装一个单节点集群(同时包含server和agent角色),这对于学习和测试环境足够了。

# 使用国内镜像加速安装,避免网络问题 curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -

安装完成后,K3S服务会自动启动。检查安装状态:

sudo systemctl status k3s

获取管理集群所需的配置文件:

sudo cat /etc/rancher/k3s/k3s.yaml

将这个文件的内容复制到你本地机器的~/.kube/config,并修改其中的server地址为你的K3S服务器IP(例如https://192.168.1.100:6443)。然后安装kubectl命令行工具,就可以远程管理集群了。

注意:生产环境或多节点集群的安装会更复杂一些,需要指定K3S_URLK3S_TOKEN。单节点模式默认的--cluster-init参数会使用内置的sqlite代替etcd,牺牲了一些高可用性,但换来了极致的简洁。

3.2 必备工具安装与配置光有K3S还不够,我们还需要一些“脚手架”工具。

  1. Helm:K8s的包管理工具,我们用它来安装Nginx Ingress Controller。
    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
  2. Nginx Ingress Controller:这是实现Ingress规则的关键组件。
    # 添加Helm仓库 helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update # 安装ingress-nginx helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx \ --create-namespace \ --set controller.service.type=NodePort # 暂时用NodePort方式暴露,方便测试
    安装后,执行kubectl get svc -n ingress-nginx,可以看到一个类型为NodePort的服务,记下它的端口(例如80:32688/TCP),后面我们会用服务器的IP加这个端口(32688)来访问服务。

3.3 构建与推送应用镜像这是承上启下的关键一步。我们需要为SpringBoot和Vue项目分别制作Docker镜像,并推送到一个镜像仓库。这里以Docker Hub为例。

  • SpringBoot Dockerfile示例

    # 使用多阶段构建,减少最终镜像体积 FROM maven:3.8.6-eclipse-temurin-11 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline -B COPY src ./src RUN mvn clean package -DskipTests FROM eclipse-temurin:11-jre-alpine WORKDIR /app COPY --from=build /app/target/*.jar app.jar # 建议通过环境变量传入JVM参数,而非写死在镜像里 ENTRYPOINT ["java", "-jar", "/app/app.jar"]

    构建并推送:

    docker build -t yourdockerhub/springboot-app:latest . docker push yourdockerhub/springboot-app:latest
  • Vue Dockerfile示例

    # 构建阶段 FROM node:18-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build # 运行阶段 FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html # 复制自定义的nginx配置,用于代理API请求 COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80

    其中,nginx.conf是关键,它定义了如何将API请求转发到后端:

    server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } # 代理所有以/api开头的请求到后端服务 location /api/ { proxy_pass http://springboot-svc:8080/; # 注意这里用的是K3S Service名 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

    同样,构建并推送Vue镜像:

    docker build -t yourdockerhub/vue-app:latest . docker push yourdockerhub/vue-app:latest

实操心得:镜像标签(Tag)不要永远用latest。建议使用Git提交哈希或版本号,如v1.0.0-gitabc123。这样部署时可以精确回滚。在K3S的YAML文件中引用带版本的镜像,是走向持续部署的第一步。

4. 编写K3S部署清单(YAML)

一切准备就绪,现在用K3S能读懂的语言——YAML文件,来描述我们的整个应用。通常我们会为每个组件创建独立的YAML文件,但为了方便管理,也可以放在一个文件里用---分隔。

4.1 部署后端SpringBoot应用创建一个文件叫deploy-springboot.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: springboot-deployment spec: replicas: 2 # 启动两个Pod实例 selector: matchLabels: app: springboot-app template: metadata: labels: app: springboot-app spec: containers: - name: springboot-container image: yourdockerhub/springboot-app:latest # 替换为你的镜像 ports: - containerPort: 8080 env: - name: SPRING_PROFILES_ACTIVE value: "prod" # 可以从ConfigMap或Secret中注入更多环境变量 # resources: # requests: # memory: "512Mi" # cpu: "250m" # limits: # memory: "1Gi" # cpu: "500m" --- apiVersion: v1 kind: Service metadata: name: springboot-svc # 这个名称很重要,前端Nginx和Ingress会用到 spec: selector: app: springboot-app ports: - protocol: TCP port: 80 # Service对集群内暴露的端口 targetPort: 8080 # 容器内部的端口

这个文件定义了两件事:1. 一个Deployment,确保始终有2个SpringBoot应用的Pod在运行;2. 一个Service,为这组Pod提供一个统一的内部访问入口springboot-svc:80

4.2 部署前端Vue应用创建文件deploy-vue.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: vue-deployment spec: replicas: 2 selector: matchLabels: app: vue-app template: metadata: labels: app: vue-app spec: containers: - name: vue-container image: yourdockerhub/vue-app:latest # 替换为你的镜像 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: vue-svc spec: selector: app: vue-app ports: - protocol: TCP port: 80 targetPort: 80

前端部署相对简单,核心是保证Nginx容器运行并暴露80端口。

4.3 配置Ingress统一入口这是将内外网打通的关键。创建文件ingress.yaml

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-ingress annotations: kubernetes.io/ingress.class: "nginx" # 指定使用nginx ingress controller spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: vue-svc port: number: 80 - path: /api pathType: Prefix backend: service: name: springboot-svc port: number: 80

这个Ingress规则告诉Nginx Ingress Controller:当访问根路径/时,把流量导向前端的vue-svc;当访问/api或任何以/api/开头的路径时,把流量导向后端的springboot-svc

重要提示:这里后端Service的端口是80,而不是SpringBoot容器的8080。这是因为我们在springboot-svc的定义中,将port: 80映射到了targetPort: 8080。Ingress规则中引用的是Service的端口。

5. 部署上线与验证

YAML文件准备就绪,现在将它们应用到K3S集群。

# 应用所有配置 kubectl apply -f deploy-springboot.yaml kubectl apply -f deploy-vue.yaml kubectl apply -f ingress.yaml

应用后,使用以下命令观察部署状态:

# 查看所有Pod是否都进入Running状态 kubectl get pods -w # 查看Service kubectl get svc # 查看Ingress kubectl get ingress

如果一切顺利,你现在可以通过两种方式访问你的应用:

  1. 通过Ingress Controller的NodePort:还记得安装Ingress时记下的端口吗(例如32688)?在浏览器访问http://<你的服务器IP>:32688,应该能看到Vue前端页面,并且前端发起的API请求(如http://<你的服务器IP>:32688/api/hello)能正确到达SpringBoot后端并返回结果。
  2. 配置域名(推荐):修改你本地机器的hosts文件(C:\Windows\System32\drivers\etc\hosts/etc/hosts),将某个域名(如myapp.local)指向你的K3S服务器IP。然后修改ingress.yaml,在spec.rules下添加host: myapp.local字段。重新应用Ingress后,就可以通过http://myapp.local访问了(如果Ingress Controller配置了LoadBalancer或有了公网IP,则可以直接用真实域名)。

验证要点

  • 前端页面能否正常加载静态资源(JS, CSS)?
  • 前端页面发起的API请求(打开浏览器开发者工具,查看Network标签)是否返回200状态码和正确数据?
  • 尝试kubectl scale deployment springboot-deployment --replicas=3,将后端扩容到3个实例,观察请求是否被均匀分配(可以在SpringBoot的日志中打印Pod主机名来验证)。
  • 模拟一个Pod故障:kubectl delete pod <springboot-pod-name>,K3S是否会立即创建一个新的Pod来替代?

6. 进阶配置与优化技巧

基础部署跑通后,我们可以让它更健壮、更专业。

6.1 配置管理:告别硬编码永远不要将数据库连接字符串、API密钥等写死在代码或镜像里。使用ConfigMap和Secret。

# configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: app-config data: application.yml: | spring: datasource: url: jdbc:mysql://${DB_HOST}:${DB_PORT}/mydb username: ${DB_USER} app: api-key: placeholder # 真实值从环境变量或Secret注入 --- # secret.yaml (注意:数据需要是base64编码) apiVersion: v1 kind: Secret metadata: name: app-secret type: Opaque data: db-password: c3VwZXJzZWNyZXRwYXNzd29yZA== # 示例:supersecretpassword

然后在SpringBoot的Deployment中,通过环境变量或卷挂载的方式使用它们:

env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: app-secret key: db-password - name: SPRING_DATASOURCE_PASSWORD value: $(DB_PASSWORD) # 在容器内引用环境变量

6.2 资源限制与健康检查不给Pod设置资源限制,就像开车不系安全带。在Deployment的spec.template.spec.containers下添加:

resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "512Mi" cpu: "200m" livenessProbe: httpGet: path: /actuator/health/liveness # Spring Boot Actuator端点 port: 8080 initialDelaySeconds: 60 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 5

requests是调度依据,limits是硬性上限。健康检查能让K3S知道你的应用是否活着(liveness)以及是否准备好接收流量(readiness)。

6.3 日志与监控K3S默认使用containerd,容器日志在/var/log/containers/目录下。对于集中式日志收集,可以考虑部署轻量的EFK(Elasticsearch, Fluentd, Kibana)栈或Loki。监控方面,可以安装Prometheus Stack(通过Helm安装kube-prometheus-stack),它能自动发现并监控K3S集群和所有Pod的性能指标。

6.4 持久化存储如果SpringBoot应用需要上传文件,或者你决定在集群内部署MySQL,就需要持久化存储。K3S自带一个本地路径存储类(local-path)。

# pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc spec: storageClassName: local-path accessModes: - ReadWriteOnce resources: requests: storage: 5Gi

然后在Deployment中挂载这个PVC即可。注意,local-path通常只适用于单节点集群,多节点集群需要配置网络存储(如NFS)。

7. 常见问题与故障排查实录

在实际操作中,你几乎一定会遇到下面这些问题。我把踩过的坑和解决方法整理出来,希望能帮你节省几个小时甚至几天的时间。

7.1 镜像拉取失败(ImagePullBackOff)这是最常见的问题。Pod状态显示ImagePullBackOffErrImagePull

  • 原因1:镜像名称或标签错误。仔细检查YAML文件中的image字段,确保和Docker Hub或你的私有仓库里的完全一致,包括大小写。
  • 原因2:私有仓库需要认证。你需要创建一个docker-registry类型的Secret。
    kubectl create secret docker-registry regcred \ --docker-server=<你的仓库地址> \ --docker-username=<用户名> \ --docker-password=<密码> \ --docker-email=<邮箱>
    然后在Deployment的spec.template.spec下添加:
    imagePullSecrets: - name: regcred
  • 原因3:网络问题。如果是海外镜像(如gcr.io),国内网络可能无法拉取。可以尝试寻找国内镜像源,或者先docker pull到本地,再docker tagdocker push到你能访问的仓库。

7.2 Pod启动失败(CrashLoopBackOff)Pod反复启动又崩溃。

  • 排查日志:这是最重要的手段。kubectl logs <pod-name>查看当前容器的日志,如果Pod之前有崩溃过的容器,加-p参数查看上一个容器的日志:kubectl logs <pod-name> -p。日志里通常会直接告诉你错误原因,比如“数据库连接失败”、“配置文件找不到”、“端口被占用”等。
  • 常见原因
    • 应用配置错误:检查通过ConfigMap或环境变量传入的配置是否正确。特别是数据库连接字符串、Redis地址等。
    • 依赖服务未就绪:比如SpringBoot应用启动时需要连接MySQL,但MySQL的Pod还没启动好。可以通过在Deployment中配置readinessProbe,并在依赖项上使用initContainers或调整启动顺序来缓解。
    • 资源不足:检查Pod是否因为内存或CPU超出limits而被系统杀死(OOMKilled)。kubectl describe pod <pod-name>查看事件。

7.3 Ingress访问404或502前端能打开,但API请求报错。

  • 检查Ingress规则kubectl describe ingress app-ingress,查看Events事件和Rules规则是否正确映射到了后端Service。
  • 检查Service和Pod的Selector:确保Service的selector(如app: springboot-app)和Pod的labels完全匹配。一个字母都不能差。
  • 检查后端服务本身:直接通过kubectl port-forward命令将后端服务的端口映射到本地测试。
    kubectl port-forward svc/springboot-svc 8080:80
    然后在本地访问http://localhost:8080/actuator/health,看服务是否正常。如果这里都不通,问题就在后端应用或Service配置上。
  • 检查Nginx配置:回顾前端Nginx配置文件中的proxy_pass地址,必须是K3S内部的Service名和端口(如http://springboot-svc:8080)。在Vue的Pod里执行kubectl exec -it <vue-pod-name> -- sh,然后cat /etc/nginx/conf.d/default.conf确认配置已正确注入。

7.4 节点资源紧张,Pod处于Pending状态执行kubectl get pods发现Pod状态一直是Pending

  • 查看详情kubectl describe pod <pod-name>,在Events部分,通常会看到提示“Insufficient cpu”或“Insufficient memory”。
  • 解决方法
    1. 给节点增加资源(加内存、CPU)。
    2. 优化Pod的资源requests,降低其申请值。
    3. 清理不必要的Pod或部署。使用kubectl top nodeskubectl top pods查看资源使用情况。

7.5 如何更新应用?最简单的更新方式是修改Deployment的镜像标签,然后重新应用。

kubectl set image deployment/springboot-deployment springboot-container=yourdockerhub/springboot-app:v1.1.0

K3S会启动新的Pod,等待其通过readinessProbe后,逐步替换旧的Pod,实现零停机更新。你可以通过kubectl rollout status deployment/springboot-deployment来观察更新过程。如果新版本有问题,可以快速回滚:kubectl rollout undo deployment/springboot-deployment

部署完成后,别急着关终端。养成习惯,先看Pod状态,再查服务端点,最后通过Ingress访问。日志(kubectl logs)和事件(kubectl describe)是你最好的朋友。对于复杂问题,学会使用kubectl get events --sort-by=.metadata.creationTimestamp来按时间顺序查看集群事件,往往能发现问题的根源。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询