Kubernetes

Kubernetes(k8s) 部署应用(PV、PVC)

有个微信小程序的后端服务,原来托管在阿里云上,现在希望做成微服务发布在k8s上。

1.配置 nginx 容器,转发HTTPS 请求(配置有SSL证书)到k8s


docker run -d  --name nginx  -p 8081:8081  -v /mnt/nginx/conf.d:/etc/nginx/conf.d  -v /mnt/nginx/certs:/etc/nginx/certs  nginx:alpine

在 /mnt/nginx/certs 目录下放置SSL证书

在 /mnt/nginx/conf.d 目录下放置nginx配置文件

 

server {
    listen 8081 ssl;
    server_name 92it.top www.92it.top;  # 同时支持两种域名访问

    # 允许最大上传文件大小为 100MB
    client_max_body_size 100M;
    client_body_buffer_size 256k;


    # 代理超时配置
    proxy_connect_timeout 120s;  # 连接后端服务器的超时时间
    proxy_send_timeout 300s;     # 向后端服务器发送请求的超时时间
    proxy_read_timeout 600s;     # 从后端服务器读取响应的超时时间(关键参数)

    # SSL 证书配置
    ssl_certificate /etc/nginx/certs/ssl-cert.pem;
    ssl_certificate_key /etc/nginx/certs/ssl-cert.key;

    # 转发所有请求到目标主机
    location / {
        proxy_pass http://123.56.xxx.xxx:30080; 转发所有请求到这个ip地址
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 可选:保留所有请求头部(包括非标准字段)
        proxy_pass_request_headers on;
    }
}

 

2.在k8s 通过 kubectl 命令 做成pv


在 Kubernetes(K8S)里,PV(Persistent Volume,持久卷 )和 PVC(PersistentVolumeClaim,持久卷声明 )是实现容器持久化存储的核心概念,用于解耦存储资源的 “供给” 和 “使用”。

  • 定义:PV 是集群里的一块网络存储资源,由管理员创建或通过存储类动态创建,独立于 Pod 存在,可看作集群级别的 “存储资源池 。
    类比:把 PV 想成 “共享硬盘”,提前接入 K8S 集群,供 Pod 按需使用。
  • 作用:
    • 抽象底层存储细节(不管是云厂商存储、NFS、iSCSI 还是本地存储,对用户统一暴露为 PV )。
    • 作为 “公共存储资源”,被多个 Pod 共享或独占,生命周期独立于单个 Pod。
  • 关键属性:
    • 容量:如 10Gi,指定存储大小。
    • 访问模式:
      • ReadWriteOnce(RWO):只能被单个节点以读写方式挂载。
      • ReadOnlyMany(ROX):可被多个节点以只读方式挂载。
      • ReadWriteMany(RWX):可被多个节点以读写方式挂载(需存储后端支持,如 NFS )。
    • 存储类别(StorageClass):关联存储类,用于动态创建 PV 时选择存储后端。
    • 回收策略:PV 释放后如何处理(如 Retain 保留数据、Delete 删除数据、Recycle 清理数据 )。
# kubectl apply -f persistent-volume.yaml # 无需指定命名空间
apiVersion: v1
kind: PersistentVolume
metadata:
  name: wechat-pv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany  # 多节点读写
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: "/Users/xxx/Documents/k8s/pv/wechat"  # 宿主机路径
    type: DirectoryOrCreate      # 若目录不存在则创建

 

在这个 PersistentVolume (PV) 配置中,hostPath.path 字段定义的是 宿主机(Kubernetes 节点)上的物理路径,即 PV 实际存储数据的位置。具体来说:

 

path: "/Users/xxx/Documents/k8s/pv/wechat" 的含义

  • 宿主机路径:该路径指向 Kubernetes 节点(运行 Pod 的物理机或虚拟机)上的一个目录。当 Pod 通过 PVC 挂载这个 PV 时,容器内的数据会被实际存储到宿主机的 /data/volumes/my-pv 目录中。
  • 数据持久化:即使 Pod 被删除或迁移到其他节点,只要新节点上存在相同的 hostPath 路径,数据就可以被重新挂载,从而实现持久化存储。

 

在 PersistentVolume(PV)中使用 hostPath 类型时,path 字段是必须指定的,它用于明确宿主机上存储数据的具体位置。

  • 核心功能需求:hostPath 的本质是将宿主机的本地路径映射到 PV,因此必须明确指定宿主机上的目标路径,否则 PV 无法确定数据存储位置。
  • 配置合法性:Kubernetes 会校验 PV 配置的完整性,缺少 path 会导致配置无效,无法创建 PV。

 

在使用 kubectl apply -f pv.yaml 时,不需要指定 namespace,因为 PersistentVolume (PV) 是集群级资源,不属于任何命名空间。而 PersistentVolumeClaim (PVC) 是命名空间级资源,需要在特定命名空间中创建。

 

资源类型是否需要指定命名空间原因
PersistentVolume❌ 不需要集群级资源,全局可见,不隶属于任何命名空间。
PersistentVolumeClaim✅ 需要命名空间级资源,必须在某个命名空间中创建,默认在 default 命名空间。

  

PV 与 PVC 的绑定:PVC 只能绑定到访问模式和存储类匹配的 PV,且 PV 的容量必须 ≥ PVC 请求的容量。命名空间不影响绑定逻辑,但 PVC 只能在其所在命名空间内被 Pod 引用。

# 查看所有 PV(无命名空间限制)
kubectl get pv

# 查看特定命名空间的 PVC
kubectl get pvc -n my-namespace

  

3. kubectl 创建PVC


定义:PVC 是用户对存储资源的 “请求声明”,类似 Pod 对 CPU、内存的资源请求,描述 Pod 对存储的需求(要多大、以什么方式访问 )。

类比:PVC 是 “存储申请单”,用户填 “要 5Gi 存储、读写模式”,K8S 自动匹配 PV 满足需求。

  • 作用:
    • 解耦 Pod 与具体存储实现(Pod 只需声明 PVC,不用关心底层是 NFS 还是云存储 )。
    • 让存储资源 “按需分配”,用户无需提前了解 PV 细节,只需提需求。
  • 关键属性:
    • 存储容量:如 5Gi,请求需要的存储大小。
    • 访问模式:与 PV 匹配(如 ReadWriteOnce )。
    • 存储类别:指定需要的存储类,用于动态创建 PV(若静态 PV 不足时 )。
    • 标签选择器:通过标签匹配特定 PV(精细控制 PV 绑定 )。
  • 总结
    • PV 是集群里的 “存储资源池”,由管理员维护,抽象底层存储;
    • PVC 是用户的 “存储申请单”,描述 Pod 对存储的需求,自动匹配 PV;
    • 二者配合实现了 存储资源的解耦、按需分配和动态管理,让 K8S 里的持久化存储更灵活、更易用。

 

# kubectl apply -f persistent-volume-claim.yaml -n wechat-applet-services 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wechat-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi  # 请求的存储大小(必须小于等于 PV 的容量)
  storageClassName: manual  # 必须与 PV 的 storageClassName 匹配

 

 

ReadWriteOnce 是 Kubernetes 中 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 的一种 访问模式(Access Mode),用于定义存储卷的使用限制。具体含义如下:

ReadWriteOnce 的核心定义

  • 单节点读写:该卷可以被单个节点读写方式挂载。
  • 独占性:同一时间只能有一个节点(Node)挂载并读写该卷,其他节点无法同时访问。
  • Pod 迁移限制:若 Pod 从一个节点迁移到另一个节点,卷会跟随迁移,但原节点将失去访问权限。

 

Kubernetes 支持三种主要访问模式:

访问模式缩写含义
ReadWriteOnceRWO单节点读写(最常用,适用于多数数据库等需要独占访问的场景)。
ReadOnlyManyROX多节点只读(适用于静态资源共享,如网站静态文件)。
ReadWriteManyRWX多节点读写(需存储系统支持,如 NFS、Ceph 等分布式存储)。

  

ReadWriteOnce 的典型场景

  1. 数据库存储:
    • 如 MySQL、PostgreSQL 等数据库需要独占存储,避免多节点同时写入导致数据冲突。
  1. 本地存储依赖:
    • 某些应用依赖特定节点的本地文件系统(如 hostPath 类型的 PV),必须限制在单节点使用。
  2. 云存储卷:
    • AWS EBS、GCE PD 等云存储卷本身限制只能挂载到单个实例,对应 ReadWriteOnce 模式。

 

4. kubectl 创建Deployment


# service-wechat-deployment.yaml
# kubectl apply -f service-wechat-deployment.yaml -n wechat-applet-services
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-wechat-deployment
  labels:
    app: service-wechat
spec:
  replicas: 1  # 创建1个Pod副本
  selector:
    matchLabels:
      app: service-wechat
  template:
    metadata:
      labels:
        app: service-wechat
    spec:
      containers:
      - name: service-wechat
        image: 123.57.xxx.xxx:5001/service-wechat:latest
        ports:
        - containerPort: 8081
        resources:
          limits:
            memory: "512Mi"
            cpu: "500m"
        volumeMounts:
        - name: service-wechat-volume
          mountPath: "/mnt"  # 容器内挂载路径,会把pvc挂到容器 /mnt目录下
      imagePullSecrets:
      - name: docker-registry-secret
      volumes:
      - name: service-wechat-volume
        persistentVolumeClaim:
          claimName: wechat-pvc # 用到了上面的pvc

  在宿主机上可以看到 Pod用到了上面绑定的pv和pvc,这个路径下面有了pod产生的文件。

进到k8s容器里面看一下

 

5. kubectl 创建Service 通过 nodePort 暴露服务


# wechat-service.yaml
# kubectl apply -f wechat-service.yaml -n wechat-applet-services
apiVersion: v1
kind: Service
metadata:
  name: wechat-service
spec:
  selector:
    app: service-wechat
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8081
      nodePort: 30080  # 指定 NodePort(范围 30000-32767)
  type: NodePort  # 暴露到集群外

 

在 Kubernetes 的 Service 配置中,porttargetPort 和 nodePort 是三个关键概念,它们分别对应不同层级的端口映射关系。以下是详细解释:

port:Service 自身的端口(集群内部访问)

  • 定义:Service 在集群内部 IP 上暴露的端口,用于集群内其他 Pod 或服务通过该端口访问此 Service。
ports:
  - protocol: TCP
    port: 80  # Service 在集群内部的端口为 80
  • 作用:当集群内的 Pod 访问 wechat-service:80 时,流量会被 Service 转发到后端 Pod 的 targetPort

 

targetPort:后端 Pod 的目标端口

  • 定义:Service 转发流量时指向的后端 Pod 的端口,需与 Pod 中容器的端口一致。
ports:
  - targetPort: 8081  # 转发到 Pod 中容器的 8081 端口
  • 作用:假设 Pod 中容器的端口为 8081(如 containerPort: 8081),则 Service 会将请求从 port 转发到 Pod 的 targetPort

 

nodePort:节点暴露的端口(集群外部访问)

  • 定义:当 type: NodePort 时,Kubernetes 会在集群所有节点上开放一个端口(nodePort),外部流量可通过节点 IP + nodePort 访问服务。
ports:
  - nodePort: 30080  # 节点上开放的端口为 30080
type: NodePort
  • 作用:外部用户可通过 http://<节点IP>:30080 访问服务,流量会被节点转发到 Service 的 port,再由 Service 转发到 Pod 的 targetPort
  • 端口范围nodePort 必须在 30000-32767 范围内,若不指定,Kubernetes 会自动分配一个可用端口。

 

三者的映射关系(以示例配置为例)

外部访问 → 节点 IP:30080(nodePort)
       ↓
Service 内部 IP:80(port)
       ↓
后端 Pod:8081(targetPort)

总结

端口类型作用范围示例值访问场景
port集群内部80集群内 Pod 通过 服务名:port 访问
targetPort后端 Pod8081Service 转发到 Pod 的目标端口
nodePort集群所有节点30080外部通过 节点IP:nodePort 访问

 

扩展说明

  • 为什么需要三层端口?
    • port 和 targetPort 解耦了 Service 与 Pod 的端口依赖(如 Pod 端口变更时,只需修改 targetPort)。
    • nodePort 提供了集群外部访问的统一入口,避免直接暴露 Pod 地址。
  • 与 Ingress 的区别
    NodePort 适合简单场景,但存在以下限制:
    • 每个 Service 占用一个节点端口,端口资源有限。
    • 无法基于域名、路径进行路由(需 Ingress 实现)。