k8s部署微服务项目

目录

简介K8s

k8s集群架构

搭建一个k8s集群

打包并上传镜像

k8s中编写使用yaml文件

部署实战

[1. Nacos 单节点(使用轩辕加速镜像)](#1. Nacos 单节点(使用轩辕加速镜像))

2.MySQL(支持持久化)

3.Redis

4.RabbitMQ:

[5. user-service 微服务](#5. user-service 微服务)

[6. order-service 微服务](#6. order-service 微服务)



简介K8s


Kubernetes(简称 K8s)是一个容器编排平台,它负责把你用 Docker 打包的应用(容器)放到多台机器上运行、自动重启、伸缩、负载均衡和发现服务。换句话说:把"单机 docker run"提升成"分布式可用、可扩缩、可管理"的平台。

  • Pod:K8s 最小调度单位,通常一个 Pod 里跑一个容器(或紧密耦合的多个容器)。

  • Deployment:管理一组副本 Pod 的控制器(负责滚动更新、回滚)。

  • StatefulSet:有状态服务(比如数据库、有持久名)的部署方式。

  • Service:把一组 Pod 暴露成稳定的网络入口(ClusterIP / NodePort / LoadBalancer)。

  • ConfigMap / Secret:配置与密钥注入(避免把配置写死在镜像里)。

  • PersistentVolume(PV) / PersistentVolumeClaim(PVC):持久化存储(容器重建数据不丢)。

  • Ingress:HTTP/HTTPS 入口路由,可绑定域名与 TLS。

  • Namespace:逻辑隔离(不同环境或团队用不同 namespace)。

  • Node:运行 Pod 的物理/虚拟机(工作节点)。

  • kube-apiserver / kube-scheduler / kube-controller-manager / etcd:控制平面组件(通常由集群管理员维护)。


k8s集群架构


Kubernetes 安装都是 集群模式,部署完 Kubernetes, 即拥有了一个完整的集群。

Kubernetes Cluster = N 主节点 + N 工作节点 ( N >= 1)

  • 控制平面组件:管理集群的整体状态(不重要,部署应用不需要和这些组件打交道,了解即可):
    1. kube-apiserver: 公开 Kubernetes HTTP API 的核心组件服务器;
    2. etcd: 具备一致性和高可用性的键值存储,用于所有 API 服务器的数据存储;
    3. kube-scheduler: 查找尚未绑定到节点的 Pod,并将每个 Pod 分配给合适的节点;
    4. kube-controller-manager: 运行控制器来实现 Kubernetes API 行为。
    5. cloud-controller-manager: 与底层云驱动集成
  • Node 组件 :在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行时环境:
    1. kubelet: 确保 Pod 及其容器正常运行;
    2. kube-proxy: 维护节点上的网络规则以实现 Service 的功能;
    3. 容器运行时(Container runtime);

我们所有的应用和中间件都是运行在 node 组件的容器运行时中,通过 kube-proxy 向集群内外提供网络访问。使用命令查看节点(在主节点运行):

复制代码
kubectl get nodes

k8s 主要有容器、Pod、Deployment、Service等四个核心概念,学过docker就会明白,它主要是起到了资源隔离,而资源隔离主要只指**进程隔离、文件隔离、网络隔离。**一个容器进程本质上是一个运行在沙盒中的隔离进程,由 Linux 系统本身负责隔离,Docker 只是提供了一系列工具,帮助我们设置好隔离环境后,启动这个进程。容器就是运行你 Java 服务的最底层实例,来自 Docker 镜像,例如:

复制代码
image: user-service:1.0

所有的应用和中间件都是运行在容器运行时中的,那么我们应如何管理容器运行时呢?这个时候就可以通过 pod,在上面提到过,pod 是 K8s 最小调度单位,通常一个 Pod 里跑一个或多个容器,能够共享网络(同一IP),共享存储(volumes):

复制代码
Pod → Container (user-service.jar)

可以使用命令去查看所有的 pod:

复制代码
kubectl get pods -A

查看详细 pod:

复制代码
kubectl describe pod pod-name

集群中的每个 Pod 都会获得自己的、独一无二的集群范围 IP 地址。Pod 网络(也称为集群网络)处理 Pod 之间的通信。它确保所有 Pod 可以与所有其他 Pod 进行通信, 无论它们是在同一个节点还是在不同的节点上。但是 **Pod 不可靠,会随时被重启、删除、迁移,**所以不能用 Pod 做高可用,必须使用 Deployment 来管理 Pod。

Deployment 才是真正部署微服务的地方,一个 Deployment 为 Pod 提供声明式的更新能力,也就是 服务更新和扩缩容的能力。所谓的声明式,就是说用户可以通过 Deployment 声明 Pod 的期望状态,Deployment 会自动帮你把 Pod 保持在期望状态。而期望状态,一般是指你需要这个 Pod 有几个副本,如何更新,如何定义 Pod 的健康状态的信息。

复制代码
kubectl get deploy -A

kubectl describe deploy deploy-name

而由于 Pod IP 会变化(Pod 会重启),所以不能直接访问 Pod,这个时候就要使用 Service,它是 Pod 的 稳定访问入口

  • Service API 允许我们为由一个或多个后端 Pod 实现的服务提供一个稳定(长效)的 IP 地址或主机名, 其中组成服务的各个 Pod 可以随时变化。

Service主要是为了解决两个问题:

  1. 对集群外暴露访问入口;
  2. 对集群内提供稳定的服务访问地址;

Service 主要有 4 种:

类型 作用
ClusterIP 微服务内部访问(最常用)
NodePort 暴露到宿主机端口
LoadBalancer 云厂商自动分配公网 IP
Headless (clusterIP: None) 给 StatefulSet 用的,例如 MySQL 集群

可以使用命令查看 Service:

复制代码
kubectl get svc -A

kubectl describe svc svc-name

搭建一个k8s集群


这里我们创建了三台虚拟机(主机名分别为:node1,node2,node3),其中 node1 是主节点,而 node2、node3 是工作节点。

三台机器都需装上 Docker、Kubelet、Kubectl、Kubeadm,一般主节点与工作节点需要安装如下:

安装教程可以参考如下:Kubenetes

我们可以使用 minikube,它是一个本地Kubernetes,提供和 k8s 一样的交互命令,安装更加简单并且占用的资源也更少。k8s部署SpringCloud微服务集群k8s部署SpringCloud微服务集群 ,简要介绍 kubernetes( - 掘金


打包并上传镜像


首先去编写 Dockerfile(不会的朋友可以点击下面链接学习在Linux系统上使用DockerFile以及Dockercompose部署项目_linux,docker部署java项目-CSDN博客

bash 复制代码
# 1. 使用基础镜像
FROM eclipse-temurin:17-jdk
 
# 2. 设置工作目录
WORKDIR /app
 
# 3. 将 jar 包复制进容器
COPY target/user-service.jar app.jar
 
# 4. 暴露端口(可选,给文档用)
EXPOSE 8081
 
# 5. 启动命令
ENTRYPOINT ["java","-jar","/app/app.jar"]

随后执行 docker build 完成镜像打包:

bash 复制代码
docker build -t user-service:1.0

然后执行下面命令查看镜像信息:

bash 复制代码
docker images | grep user-service:1.0

接下来需要我们去上传这个镜像,一般会使用阿里镜像服务:容器镜像服务 ACR 控制台

登录 阿里云镜像服务 申请免费试用,进入 命名空间 创建一个自己的命名空间就可以开始使用了。

我们在打包镜像的服务器和运行k8s的服务器中登录镜像服务,随后执行下面命令:【换成自己的用户名】

bash 复制代码
# 登录阿里云Docker Registry,用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。
docker login --username=<username> registry.cn-hangzhou.aliyuncs.com

随后在打包镜像的服务器中将镜像推送到镜像中心:【换成自己的命名空间】

bash 复制代码
# 标记镜像(注意将推送地址更换为你自己的命名空间(namespace)) 
docker tag mall-frontend:latest registry.cn-hangzhou.aliyuncs.com/namsapce01/user-service:1.0

# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/namsapce01/user-service:1.0

最后我们就可以尝试使用命令去拉取我们的镜像了:

bash 复制代码
# 拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/namsapce01/user-service:1.0

k8s中编写使用yaml文件


YAML 是 Kubernetes 的"配置文件格式",主要用于告诉 K8s:我要创建什么资源?如何运行?运行多少?暴露哪些端口?使用哪个镜像?等关键信息。

比如:

  • 部署一个 Java 微服务? → 写 Deployment.yaml

  • 创建一个访问入口? → 写 Service.yaml

  • 创建域名入口? → 写 Ingress.yaml

  • 创建 MySQL 集群? → 写 StatefulSet.yaml

  • 设置环境变量? → 写 ConfigMap.yaml

  • 设置密码? → 写 Secret.yaml

而使用它非常简单,我们只需要编写一个 yaml 文件,随后去使用下面命令去运行即可:【例如我构建了一个名为 user-service.yaml 文件】

bash 复制代码
kubectl apply -f user-service.yaml

那么下面我们就要讲解如何去编写 YAML 文件 ->

K8s 的 YAML 基本结构总共 4 部分,不管你部署啥都是这结构:

bash 复制代码
apiVersion: 
kind:
metadata:
spec:
字段 含义
apiVersion 资源所属的 API 版本
kind 资源类型,例如 Deployment、Service
metadata 名称、标签等
spec 核心配置(最重要)

比如下面的 YAML 文件:

bash 复制代码
apiVersion: apps/v1            # 使用 Deployment 所在的 API 版本
kind: Deployment               # 声明资源类型为 Deployment(部署)
metadata:
  name: user-service           # Deployment 名称,在运行 kubectl get deploy 时会看到它,Pod 会自动继承这个名称的前缀
spec:
  replicas: 2                  # 副本数量,表示运行 2 个 Pod(负载均衡)【如果挂了 1 个 → 自动拉起新 Pod;如果你手动删 1 个 → 2 秒后自动补上】
  selector:                    # Deployment 如何找到需要管理的 Pod
    matchLabels:
      # Deployment 只会管理那些 app=user-service 的 Pod,后面 template 里的 label 必须一致,否则 Pod 不会被管理
      app: user-service        # 通过 Pod 标签 app=user-service 进行匹配 【Deployment 用这个 label 找它管理的 Pod】
  # K8s 会根据 template 的内容来创建 Pod
  template:                    # Pod 模板(Deployment 会根据这里创建 Pod)
    metadata:
      labels:
        # label 是 K8s 中资源关联的唯一方式
        app: user-service      # 给 Pod 设置标签,必须与 selector 匹配
    # Pod 的运行配置
    spec:
      containers:              # Pod 中运行的容器列表
        - name: user-service   # 容器名称
          image: user-service:1.0   # 使用的镜像,来自本地或镜像仓库
          ports:
            - containerPort: 8081    # 容器对外暴露的端口(应用内部端口)
          env:                       # 注入环境变量
            - name: MYSQL_HOST
              value: mysql           # MYSQL 主机名(ClusterIP 服务名)
            - name: NACOS_ADDR
              value: nacos:8848      # Nacos 地址(服务名 + 端口)

---
# 下面是为 user-service Pod 提供访问方式的 Service
apiVersion: v1                 # Service 属于 core/v1
kind: Service                  # 声明资源类型为 Service(服务)
metadata:
  name: user-service           # Service 名称,应与 Deployment 名相同(常见约定)
spec:
  type: ClusterIP              # 默认类型:仅集群内部访问
  selector:
    app: user-service          # 选择带标签 app=user-service 的 Pod
  ports:
    - port: 8081               # Service 对外暴露的端口(集群内部访问)
      targetPort: 8081         # Pod 内部容器端口(containerPort),通常一致

当我们去运行这份 YAML 文件,K8s 自动创建:

资源 作用
Deployment 启动 user-service
Pod 运行 user-service.jar
Service 提供集群内部访问入口

另外我们还需要去知道常用 YAML 的种类:

类型 作用 微服务中用来干啥?
Deployment 启动微服务(多副本) 运行 Java 服务
Service 暴露端口、让服务互相访问 user-service 调 order-service
Ingress 域名访问入口 给前端提供网关入口
ConfigMap 配置文件(不放镜像里) 代替 application.yml
Secret 敏感数据 MySQL 密码、JWT 密钥
StatefulSet 有状态应用 MySQL、Redis、Nacos
PV / PVC 持久化存储 MySQL 数据目录

详细教学可以看:Kubernetes


部署实战


首先我们先介绍项目架构:

服务名 类型 说明
gateway-service SpringCloud Gateway 微服务入口
user-service 微服务 用户模块
order-service 微服务 订单模块
mysql 数据库 使用 PVC 持久化
redis 缓存 缓存/分布式锁
nacos 注册中心 + 配置中心
rabbitmq MQ 消息队列

1. Nacos 单节点(使用轩辕加速镜像)

对于微服务开发环境,一般1节点足够。

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  name: nacos
spec:
  ports:
    - port: 8848
      targetPort: 8848
  selector:
    app: nacos

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nacos
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nacos
  template:
    metadata:
      labels:
        app: nacos
    spec:
      containers:
        - name: nacos
          image: dockerproxy.cn/nacos/nacos-server:v2.2.3
          env:
            - name: MODE
              value: standalone
          ports:
            - containerPort: 8848

2.MySQL(支持持久化)

K8s 部署 MySQL 时,如果你希望:

  • MySQL 第一次启动时自动运行 SQL 文件(建库、建表、插入初始数据)

那么只需要使用 Init Container + ConfigMap(或 PVC 文件)。

将 SQL 文件挂载到 /docker-entrypoint-initdb.d

原理:

只要 SQL 文件在该目录下,并且数据目录是空的,MySQL 第一次启动时会自动执行它。

Docker Compose 用的是 volume,让 SQL 落到这个目录,Kubernetes 同理,也可以做到。

首先创建 ConfigMap 存放 SQL:

bash 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-mysql-init
data:
  init.sql: |
    CREATE DATABASE IF NOT EXISTS demo;

    USE demo;

    CREATE TABLE user (
      id INT AUTO_INCREMENT PRIMARY KEY,
      username VARCHAR(50),
      password VARCHAR(100)
    );

**好处:**SQL 改项目自动更新,不需要打包镜像。

随后将 MySQL Deployment 引用这个 SQL

重点:把 ConfigMap 挂载到 /docker-entrypoint-initdb.d

bash 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-mysql
  template:
    metadata:
      labels:
        app: demo-mysql
    spec:
      containers:
        - name: mysql
          image: xxx.xuanyuan.run/library/mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "root"
            - name: MYSQL_DATABASE
              value: "demo"
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: mysql-data
              mountPath: /var/lib/mysql
            - name: mysql-init
              mountPath: /docker-entrypoint-initdb.d   # ⭐ 初始化 SQL 自动执行
      volumes:
        - name: mysql-data
          emptyDir: {}   # 或者用 PVC,如果你要持久化
        - name: mysql-init
          configMap:
            name: demo-mysql-init

3.Redis

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  ports:
    - port: 6379
  selector:
    app: redis

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: dockerproxy.cn/library/redis:6.2
          ports:
            - containerPort: 6379

4.RabbitMQ:

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  name: rabbitmq
spec:
  ports:
    - port: 5672
    - port: 15672
      name: http
  selector:
    app: rabbitmq

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rabbitmq
spec:
  selector:
    matchLabels:
      app: rabbitmq
  template:
    metadata:
      labels:
        app: rabbitmq
    spec:
      containers:
        - name: rabbitmq
          image: dockerproxy.cn/library/rabbitmq:3.12-management
          ports:
            - containerPort: 5672
            - containerPort: 15672

5. user-service 微服务

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  ports:
    - port: 8081
  selector:
    app: user-service

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
        - name: user-service
          image: dockerproxy.cn/library/openjdk:17
          args:
            - "java"
            - "-jar"
            - "/app/user-service.jar"
          env:
            - name: NACOS_ADDR
              value: nacos:8848
            - name: MYSQL_HOST
              value: mysql
            - name: REDIS_HOST
              value: redis
          ports:
            - containerPort: 8081

6. order-service 微服务

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  ports:
    - port: 8082
  selector:
    app: order-service

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: dockerproxy.cn/library/openjdk:17
          args:
            - "java"
            - "-jar"
            - "/app/order-service.jar"
          env:
            - name: NACOS_ADDR
              value: nacos:8848
            - name: MQ_HOST
              value: rabbitmq
          ports:
            - containerPort: 8082

7. SpringCloud Gateway

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  name: gateway-service
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30080
  selector:
    app: gateway-service

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gateway-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gateway-service
  template:
    metadata:
      labels:
        app: gateway-service
    spec:
      containers:
        - name: gateway-service
          image: dockerproxy.cn/library/openjdk:17
          args:
            - "java"
            - "-jar"
            - "/app/gateway.jar"
          env:
            - name: NACOS_ADDR
              value: nacos:8848
          ports:
            - containerPort: 8080

随后统一执行命令:

bash 复制代码
 kubectl apply -f nacos.yaml
 kubectl apply -f mysql.yaml
 kubectl apply -f redis.yaml
 kubectl apply -f rabbitmq.yaml. 
 kubectl apply -f user-service.yaml
 kubectl apply -f order-service.yaml
 kubectl apply -f gateway.yaml
相关推荐
勇气要爆发3 小时前
Docker:软件开发的“标准集装箱”
运维·docker·容器
想学后端的前端工程师5 小时前
【Docker容器化部署实战指南:从入门到生产实践】
运维·docker·容器
zs宝来了6 小时前
Spring Cloud+Redis+Kafka高并发电商微服务系统源码深度解读
spring boot·redis·spring cloud·微服务·kafka·高并发·电商
北欧人写代码6 小时前
K8s 限制节点内存使用率,内存不足时自动驱逐POD
云原生·容器·kubernetes
冷雨夜中漫步6 小时前
Kubernetes入门笔记 ——(4)Windows搭建k8s测试集群
windows·笔记·kubernetes
竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。6 小时前
docker配置镜像Docker pull时报错:https://registry-1.docker.io/v2/
运维·docker·容器
塔能物联运维7 小时前
K8s IoT设备自动扩缩容实战
物联网·云原生·容器·kubernetes
syounger7 小时前
从本地到云:如何做出正确的 SAP ERP 云化选择
运维·微服务
hgz07109 小时前
Docker Compose
运维·docker·容器