Gitea PVC 迁移方案(RWO → RWX / StorageClass 迁移)顺带解决Gitea SSH的clusterIP改为NodePort

场景说明

当前 Gitea 使用的 PVC:

  • AccessMode:ReadWriteOnce
  • StorageClass:nfs-csi

现在需要迁移为:

  • AccessMode:ReadWriteMany
  • StorageClass:nfs-client

由于 Kubernetes 的 PVC 以下字段创建后不可修改:

  • spec.accessModes
  • spec.storageClassName

因此不能直接 helm upgrade 修改,只能通过:

创建新 PVC → 数据迁移 → 切换 Gitea 使用的新 PVC

来完成。


一、迁移目标

项目旧 PVC新 PVC
PVC 名称gitea-shared-storagegitea-shared-storage-nfs
AccessModeRWORWX
StorageClassnfs-csinfs-client

二、迁移流程概览

停止 Gitea
    ↓
创建新 PVC
    ↓
创建迁移 Pod
    ↓
rsync 同步数据
    ↓
修改 Helm values 使用新 PVC
    ↓
删除冲突 Service
    ↓
Helm Upgrade
    ↓
验证数据
    ↓
清理旧 PVC

三、停止 Gitea

防止迁移过程中产生文件写入。

kubectl -n gitea scale deployment gitea --replicas=0

确认 Pod 已停止:

kubectl -n gitea get pod

四、创建新的 RWX PVC

1. 创建 PVC YAML

文件名:

gitea-new-pvc.yaml

内容:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: gitea-shared-storage-nfs
  namespace: gitea
spec:
  accessModes:
    - ReadWriteMany

  storageClassName: nfs-csi

  resources:
    requests:
      storage: 5Gi

2. 创建 PVC

kubectl apply -f gitea-new-pvc.yaml

3. 验证 PVC

kubectl -n gitea get pvc

应看到:

gitea-shared-storage-nfs   Bound

五、创建数据迁移 Pod

1. 创建迁移 Pod YAML

文件名:

pvc-migrate.yaml

内容:

apiVersion: v1
kind: Pod
metadata:
  name: pvc-migrate
  namespace: gitea
spec:
  restartPolicy: Never

  containers:
    - name: migrate
      image: alpine:3.20

      command:
        - sh
        - -c
        - |
          apk add --no-cache rsync
          sleep 36000

      volumeMounts:
        - name: old
          mountPath: /old

        - name: new
          mountPath: /new

  volumes:
    - name: old
      persistentVolumeClaim:
        claimName: gitea-shared-storage

    - name: new
      persistentVolumeClaim:
        claimName: gitea-shared-storage-nfs

2. 创建迁移 Pod

kubectl apply -f pvc-migrate.yaml

3. 进入迁移 Pod

kubectl -n gitea exec -it pvc-migrate -- sh

六、迁移数据

推荐 rsync 命令

rsync -aH --numeric-ids --info=progress2 /old/ /new/

参数说明

参数作用
-a保留权限、时间、软链接
-H保留硬链接
--numeric-ids保留 UID/GID
--info=progress2显示进度

查看数据大小

du -sh /old
du -sh /new

七、修改 Helm values

persistence:
  enabled: true
  existingClaim: gitea-shared-storage-nfs

八、处理 Helm ownership 问题

kubectl -n gitea label pvc gitea-shared-storage-nfs \
  app.kubernetes.io/managed-by=Helm --overwrite
kubectl -n gitea annotate pvc gitea-shared-storage-nfs \
  meta.helm.sh/release-name=gitea \
  meta.helm.sh/release-namespace=gitea \
  --overwrite

九、删除旧 SSH Service

kubectl -n gitea delete svc gitea-ssh

十、执行 Helm Upgrade

helm upgrade --install gitea gitea-charts/gitea \
  -n gitea \
  -f values.yaml

十一、启动 Gitea

kubectl -n gitea scale deployment gitea --replicas=1

十二、验证服务

查看日志

kubectl -n gitea logs -f deploy/gitea

生成SSH-KEY,并在Gitea后台添加ssh key的内容

ssh-keygen -t ed25519 -C "[email protected]"
chmod 0644 /root/.ssh/id_ed25519.pub
cat /root/.ssh/id_ed25519.pub  # 手动添加到web后台的ssh页面

配置SSH别名

Host mygitea
    HostName 192.168.31.30
    Port 30022
    User git
    IdentityFile ~/.ssh/id_ed25519

测试 SSH

ssh -T mygitea

十三、清理迁移资源

kubectl -n gitea delete pod pvc-migrate

确认新 PVC 正常后:

kubectl -n gitea delete pvc gitea-shared-storage

十四、常见问题

PVC immutable

spec is immutable after creation

原因:

K8s 不允许修改:

  • accessModes
  • storageClassName

Helm ownership

exists and cannot be imported into the current release

解决:

补 Helm labels + annotations。


NodePort Service 冲突

clusterIP None may not be set to 'None'

解决:

删除旧 Service 后重新创建。