使用 Velero 备份和恢复 GitLab
本指南演示如何使用 Velero,一款开源的云原生灾难恢复工具,实现 GitLab 的备份和恢复操作。
目录
适用范围
本方案适用于运行 17.8 版本及以上 的 GitLab 实例。
GitLab 数据主要包含三个部分:PostgreSQL 数据库、Git 仓库和上传的制品(包括用户头像、评论附件等)。本方案仅支持 Git 仓库和上传制品的备份。PostgreSQL 数据库需根据您的数据库服务商备份策略,单独进行备份。
DANGER
本方案不支持使用 HostPath 存储部署的 GitLab 实例。
术语说明
术语 | 定义 |
---|
Source Instance | 备份前的 GitLab 实例 |
Target Instance | 恢复后的 GitLab 实例 |
Source Namespace | 源实例所在的命名空间 |
Target Namespace | 目标实例所在的命名空间 |
GitLab CR Resource | 描述 GitLab 实例部署配置的资源,由 Operator 用于部署 GitLab 实例 |
前置准备
- 部署 MinIO 对象存储:当前备份恢复方案依赖对象存储保存备份数据,需预先部署 MinIO 实例。ACP 提供了
MinIO Object Storage
,可通过 进行部署。
- 部署 Velero:Velero 是备份和恢复工具。ACP 提供了
Alauda Container Platform Data Backup for Velero
,您可以在 Administrator
视图的 Marketplace
-> Cluster Plugins
页面搜索 Velero
并部署。
- 安装 mc 命令行工具:mc 是 MinIO 的命令行工具,用于管理 MinIO 实例。安装说明请参考 MinIO 官方文档。
- 安装 kubectl 命令行工具:kubectl 是 Kubernetes 的命令行工具,用于管理 Kubernetes 集群。安装说明请参考 Kubernetes 官方文档。
为方便后续操作,请先设置环境变量:
export MINIO_HOST=<MinIO 实例访问地址> # 例如:http://192.168.1.100:32008
export MINIO_ACCESS_KEY=<MinIO 实例访问密钥> # 例如:minioadmin
export MINIO_SECRET_KEY=<MinIO 实例访问密钥密码> # 例如:minioadminpassword
export MINIO_ALIAS_NAME=<MinIO 实例别名> # 例如:myminio
export VELERO_BACKUP_BUCKET=<Velero 备份桶名称> # 例如:backup
export VELERO_BACKUP_REPO_NAME=<Velero 备份仓库名称> # 例如:gitlab-backup-repo
export GITLAB_NAMESPACE=<待备份 GitLab 实例所在命名空间>
export GITLAB_NAME=<待备份 GitLab 实例名称>
执行以下命令配置 mc 命令行工具并测试连接:
mc alias set ${MINIO_ALIAS_NAME} ${MINIO_HOST} ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY}
mc ping ${MINIO_ALIAS_NAME}
# 输出示例:
# 1: http://192.168.131.56:32571:32571 min=98.86ms max=98.86ms average=98.86ms errors=0 roundtrip=98.86ms
# 2: http://192.168.131.56:32571:32571 min=29.57ms max=98.86ms average=64.21ms errors=0 roundtrip=29.57ms
# 3: http://192.168.131.56:32571:32571 min=29.57ms max=98.86ms average=52.77ms errors=0 roundtrip=29.88ms
若能成功 ping 通 MinIO 实例,说明 mc 配置正确。
备份
准备工作
备份准备包含两步:
- 创建 Bucket
- 配置 Velero 备份仓库
创建 Bucket
执行以下命令创建用于存储备份数据的 Bucket:
mc mb ${MINIO_ALIAS_NAME}/${VELERO_BACKUP_BUCKET}
# 输出示例:
# Bucket created successfully `myminio/backup`.
配置 Velero 备份仓库
执行以下命令创建 Velero 备份仓库,用于存储备份数据:
gitlab_backup_repo_credentials_secret_name="gitlab-backup-repo-credentials"
minio_gitlab_backup_bucket="${VELERO_BACKUP_BUCKET:-backup}"
minio_gitlab_backup_bucket_directory="gitlab"
kubectl apply -f - <<EOF
apiVersion: v1
stringData:
cloud: |
[default]
aws_access_key_id = ${MINIO_ACCESS_KEY}
aws_secret_access_key = ${MINIO_SECRET_KEY}
kind: Secret
metadata:
labels:
component: velero
cpaas.io/backup-storage-location-repo: ${VELERO_BACKUP_REPO_NAME}
name: ${gitlab_backup_repo_credentials_secret_name}
namespace: cpaas-system
type: Opaque
---
apiVersion: velero.io/v1
kind: BackupStorageLocation
metadata:
name: ${VELERO_BACKUP_REPO_NAME}
namespace: cpaas-system
spec:
config:
checksumAlgorithm: ""
insecureSkipTLSVerify: "true"
region: minio
s3ForcePathStyle: "true"
s3Url: ${MINIO_HOST}
credential:
key: cloud
name: ${gitlab_backup_repo_credentials_secret_name}
objectStorage:
bucket: ${minio_gitlab_backup_bucket}
prefix: ${minio_gitlab_backup_bucket_directory}
provider: aws
EOF
# 输出示例:
# secret/gitlab-backup-repo-credentials created
# backupstoragelocationrepo.ait.velero.io/gitlab-backup-repo created
执行备份
手动备份包含六个步骤:
- 给资源打备份标签
- 停止 GitLab 服务
- 创建备份 Pod
- 创建备份计划
- 执行备份
- 恢复 GitLab 服务
给资源打备份标签
执行以下脚本:
if [ -z "${GITLAB_NAMESPACE}" ] || [ -z "${GITLAB_NAME}" ]; then
cat <<EOF
请设置正确的命名空间和实例名称:
export GITLAB_NAME=<原 GitLab 实例名称>
export GITLAB_NAMESPACE=<原命名空间名称>
EOF
return
fi
kubectl label gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} release=${GITLAB_NAME} --overwrite
secrets_to_label=()
root_password_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.initialRootPassword.secret}')
secrets_to_label+=(${root_password_secret_name})
rails_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.railsSecrets.secret}')
if [ -n "${rails_secret_name}" ]; then
echo "发现 rails secret: ${rails_secret_name}"
secrets_to_label+=(${rails_secret_name})
fi
pg_connect_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.psql.password.secret}')
secrets_to_label+=(${pg_connect_secret_name})
ingress_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.ingress.tls.secretName}')
if [ -n "${ingress_secret_name}" ]; then
echo "发现 ingress secret: ${ingress_secret_name}"
secrets_to_label+=(${ingress_secret_name})
fi
redis_connect_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.redis.auth.secret}')
if [ -n "${redis_connect_secret_name}" ]; then
echo "发现 redis auth secret: ${redis_connect_secret_name}"
secrets_to_label+=(${redis_connect_secret_name})
fi
redis_sentinel_connect_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.redis.sentinelAuth.secret}')
if [ -n "${redis_sentinel_connect_secret_name}" ]; then
echo "发现 redis sentinel connect secret: ${redis_sentinel_connect_secret_name}"
secrets_to_label+=(${redis_sentinel_connect_secret_name})
fi
object_store_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.appConfig.object_store.connection.secret}')
if [ -n "${object_store_secret_name}" ]; then
echo "发现对象存储连接 secret: ${object_store_secret_name}"
kubectl label secret ${object_store_secret_name} -n ${GITLAB_NAMESPACE} release=${GITLAB_NAME}
fi
for secret_name in "${secrets_to_label[@]}"; do
echo "为 secret 添加标签: ${secret_name}"
kubectl label secret ${secret_name} -n ${GITLAB_NAMESPACE} release=${GITLAB_NAME} --overwrite
done
kubectl get pvc -n ${GITLAB_NAMESPACE} --no-headers | grep ${GITLAB_NAME} | awk '{print $1}' | xargs -I {} kubectl label pvc {} release=${GITLAB_NAME} -n ${GITLAB_NAMESPACE}
kubectl get secret -n ${GITLAB_NAMESPACE} --no-headers | grep ${GITLAB_NAME} | awk '{print $1}' | xargs -I {} kubectl label secret {} release=${GITLAB_NAME} -n ${GITLAB_NAMESPACE}
# 输出示例:
# secret/sh.helm.release.v1.xxx-gitlab.v9 未打标签
如果需要备份其他资源,请参考给额外资源打备份标签部分。
停止 GitLab 服务
备份期间必须停止所有 GitLab 组件:
kubectl annotate statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync="true"
kubectl scale statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=0
kubectl annotate deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync="true"
kubectl scale deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=0
kubectl delete pod -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --ignore-not-found
# 输出示例:
# statefulset.apps/xxxx-gitlab-gitaly annotated
# deployment.apps/xxxx-gitlab-webservice-default annotated
# deployment.apps/xxxx-gitlab-toolbox scaled
# deployment.apps/xxxx-gitlab-webservice-default scaled
创建备份 Pod
该步骤创建一个挂载 GitLab PVC 的 Pod,供 Velero 完成 PVC 数据备份。
image=''
if [ -z "${IMAGE}" ]; then
image=$(kubectl get deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME},app=gitlab-shell -o jsonpath='{range .items[0].spec.template.spec.containers[]}{.image}{"\n"}{end}' | head -n1)
fi
PVC_NAMES=($(kubectl get pvc -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} -o jsonpath='{range .items[*]}{.metadata.name}{" "}{end}'))
VOLUME_MOUNTS=""
VOLUMES=""
INDEX=0
for pvc in ${PVC_NAMES[@]}; do
VOLUME_MOUNTS="${VOLUME_MOUNTS}
- name: data-${INDEX}
mountPath: /mnt/data-${INDEX}"
VOLUMES="${VOLUMES}
- name: data-${INDEX}
persistentVolumeClaim:
claimName: ${pvc}"
INDEX=$((INDEX+1))
done
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: ${GITLAB_NAME}-backup-pod
namespace: ${GITLAB_NAMESPACE}
labels:
release: ${GITLAB_NAME}
spec:
containers:
- name: backup
image: ${image}
command: ["/bin/sh", "-c", "sleep 86400"]
resources:
limits:
cpu: 1
memory: 1Gi
volumeMounts:${VOLUME_MOUNTS}
volumes:${VOLUMES}
restartPolicy: Never
EOF
kubectl wait --for=condition=ready pod -n ${GITLAB_NAMESPACE} ${GITLAB_NAME}-backup-pod
# 输出示例:
# pod/xxxx-gitlab-backup-pod created
# pod/xxxx-gitlab-backup-pod condition met
创建备份卷策略
卷策略用于指定 PVC 的备份方式,默认策略是使用 fs-backup
方式备份 PVC。
export BACKUP_POLICY_NAME=${BACKUP_POLICY_NAME:-gitlab-backup}
export VELERO_BACKUP_REPO_NAME=${VELERO_BACKUP_REPO_NAME:-backup}
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: ${BACKUP_POLICY_NAME}-volume-policy
namespace: cpaas-system
data:
resourcepolicies: |
version: v1
volumePolicies:
- conditions:
csi: {}
action:
type: fs-backup
- conditions:
csi: {}
action:
type: fs-backup
EOF
# 输出示例:
# configmap/gitlab-backup-volume-policy created
如果 PVC 支持快照,可以使用快照方式备份 PVC 以加快备份速度。需要修改卷策略 ConfigMap,指定存储类使用快照备份。例如,若 ceph
存储类支持快照备份,需要添加以下配置(新增条件应放在最前以获得更高优先级):
如何判断 PVC 是否支持快照?
WARNING
如果使用 PVC 快照备份,恢复时不能更改存储类,请根据实际情况调整存储类。
apiVersion: v1
kind: ConfigMap
metadata:
name: ${BACKUP_POLICY_NAME}-volume-policy
namespace: cpaas-system
data:
resourcepolicies: |
version: v1
volumePolicies:
+ - conditions:
+ storageClass:
+ - ceph
+ action:
+ type: snapshot
- conditions:
csi: {}
action:
type: fs-backup
- conditions:
csi: {}
action:
type: fs-backup
WARNING
如果 Velero 未启用 CSI 快照功能,备份时会出现如下错误:
Skip action velero.io/csi-pvc-backupper for resource persistentvolumeclaims:xxx, because the CSI feature is not enabled.
解决方法是在 Velero 部署中添加 --features=EnableCSI
参数。
apiVersion: apps/v1
kind: Deployment
metadata:
name: velero
spec:
template:
spec:
containers:
- args:
- server
- --uploader-type=restic
+ - --features=EnableCSI
- --namespace=cpaas-system
command:
- /velero
name: velero
执行备份
执行以下命令创建备份计划并触发备份任务:
export BACKUP_POLICY_NAME=${BACKUP_POLICY_NAME:-gitlab-backup}
export VELERO_BACKUP_REPO_NAME=${VELERO_BACKUP_REPO_NAME:-backup}
kubectl apply -f - <<EOF
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: ${BACKUP_POLICY_NAME}
namespace: cpaas-system
spec:
schedule: '@every 876000h'
template:
defaultVolumesToFsBackup: true
hooks: {}
includedNamespaces:
- ${GITLAB_NAMESPACE}
includedResources:
- '*'
resourcePolicy:
kind: configmap
name: ${BACKUP_POLICY_NAME}-volume-policy
orLabelSelectors:
- matchLabels:
release: ${GITLAB_NAME}
storageLocation: ${VELERO_BACKUP_REPO_NAME}
ttl: 720h0m0s
EOF
kubectl create -f - <<EOF
apiVersion: velero.io/v1
kind: Backup
metadata:
labels:
velero.io/schedule-name: ${BACKUP_POLICY_NAME}
velero.io/storage-location: ${VELERO_BACKUP_REPO_NAME}
generateName: ${BACKUP_POLICY_NAME}-
namespace: cpaas-system
spec:
csiSnapshotTimeout: 10m0s
defaultVolumesToFsBackup: true
includedNamespaces:
- ${GITLAB_NAMESPACE}
includedResources:
- "*"
itemOperationTimeout: 4h0m0s
resourcePolicy:
kind: configmap
name: ${BACKUP_POLICY_NAME}-volume-policy
orLabelSelectors:
- matchLabels:
release: ${GITLAB_NAME}
snapshotMoveData: false
storageLocation: ${VELERO_BACKUP_REPO_NAME}
ttl: 720h0m0s
EOF
# 输出示例:
# schedule.velero.io/gitlab-backup created
# backup.velero.io/gitlab-backup-r6hht created
查看备份日志:
kubectl logs -f -n cpaas-system -l app.kubernetes.io/instance=velero | grep gitlab-backup
# 输出示例:
# time="2025-07-01T07:29:54Z" level=info msg="PodVolumeBackup completed" controller=PodVolumeBackup logSource="pkg/controller/pod_volume_backup_controller.go:244" pvb=gitlab-backup-xxx-q7prc
检查任务进度,若状态为 Completed,说明备份成功。
kubectl get backup -n cpaas-system -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.phase}{'\t'}{.status.startTimestamp}{'\n'}{end}"
# 输出示例:
# Completed
恢复 GitLab 服务
删除备份 Pod 并恢复所有 GitLab 组件。
kubectl delete pod -n ${GITLAB_NAMESPACE} ${GITLAB_NAME}-backup-pod
kubectl annotate statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync-
kubectl scale statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=1
kubectl annotate deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync-
kubectl scale deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=1
所有组件恢复完成后,访问 GitLab 实例,确保其正常运行。
恢复
准备工作
恢复准备包含四步:
- 恢复 PostgreSQL 数据库(可选)
- 选择要恢复的备份
- 确定恢复目标命名空间
- 卸载 Gitlab CE Operator
恢复 PostgreSQL 数据库(可选)
若新实例仍使用相同的 PostgreSQL 实例和数据库,无需恢复 PostgreSQL 数据库。
若新实例使用与旧实例不同的 PostgreSQL 实例或数据库,则需先恢复 PostgreSQL 数据库。请参考您的 PostgreSQL 服务商备份恢复文档。
选择要恢复的备份数据
执行以下命令查看成功备份记录列表,根据开始时间选择所需备份。
kubectl get backup -n cpaas-system -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.phase}{'\t'}{.status.startTimestamp}{'\n'}{end}" | grep Completed
# 输出示例:
# gitlab-backup-xxx Completed 2025-07-01T07:29:19Z
设置 BACKUP_NAME 环境变量:
export BACKUP_NAME=<选择的备份记录名称>
确定目标命名空间
建议将实例恢复到新命名空间。设置以下环境变量:
export NEW_GITLAB_NAMESPACE=<新命名空间名称>
kubectl create namespace ${NEW_GITLAB_NAMESPACE}
卸载 Gitlab CE Operator
执行以下命令卸载 GitLab CE Operator:
kubectl get subscription --all-namespaces | grep gitlab-ce-operator | awk '{print "kubectl delete subscription "$2" -n "$1}' | sh
# 输出示例:
# subscription.operators.coreos.com "gitlab-ce-operator" deleted
为什么要卸载 GitLab operator?
恢复过程中,Velero 需要启动备份 Pod 来恢复 PVC 中的数据,耗时较长。若恢复时不卸载 operator,可能导致:
- operator 根据 GitLab CR 重新创建工作负载资源,导致恢复的 Pod 重启或被重新创建,最终导致恢复中断或失败。
- 部分恢复的资源可能冲突,例如 operator 根据恢复的 GitLab CR 创建的 ingress 资源与旧实例的 ingress 资源冲突。
卸载 Gitlab CE Operator 的影响
卸载 operator 后,修改 GitLab CR 资源将不生效,例如调整资源或存储大小。
卸载 operator 不会导致已有实例异常。
恢复操作
恢复操作包含五步:
- 创建恢复配置文件
- 创建恢复任务
- 清理资源
- 修改 GitLab CR 资源
- 部署 Gitlab CE Operator
创建恢复配置文件
请仔细阅读 YAML 中的注释,根据实际情况(如更改存储类)进行修改,然后创建修改后的 YAML。
# 如果需要更改存储类,设置以下两个环境变量
OLD_STORAGECLASS_NAME='' # 原存储类名称
NEW_STORAGECLASS_NAME='' # 新存储类名称
if [ -n "${OLD_STORAGECLASS_NAME}" ] && [ -n "${NEW_STORAGECLASS_NAME}" ] && [ ${NEW_STORAGECLASS_NAME} != ${OLD_STORAGECLASS_NAME} ]; then
kubectl apply -f - <<EOF
apiVersion: v1
data:
resourcemodifier: |
version: v1
resourceModifierRules:
- conditions:
groupResource: persistentvolumeclaims
resourceNameRegex: .*
namespaces:
- "*"
patches: &a1
- operation: test
path: /spec/storageClassName
value: ${OLD_STORAGECLASS_NAME}
- operation: replace
path: /spec/storageClassName
value: ${NEW_STORAGECLASS_NAME}
- conditions:
groupResource: persistentvolume
resourceNameRegex: .*
namespaces:
- "*"
patches: *a1
- conditions:
groupResource: persistentvolumeclaims
resourceNameRegex: .*
namespaces:
- "*"
patches:
- operation: test
path: "/metadata/annotations/meta.helm.sh~1release-namespace"
value: ${GITLAB_NAMESPACE}
- operation: replace
path: "/metadata/annotations/meta.helm.sh~1release-namespace"
value: ${NEW_GITLAB_NAMESPACE}
kind: ConfigMap
metadata:
labels:
component: velero
name: gitlab-restore-modifier
namespace: cpaas-system
EOF
else
kubectl apply -f - <<EOF
apiVersion: v1
data:
resourcemodifier: |
version: v1
resourceModifierRules:
- conditions:
groupResource: persistentvolumeclaims
resourceNameRegex: .*
namespaces:
- "*"
patches:
- operation: test
path: "/metadata/annotations/meta.helm.sh~1release-namespace"
value: ${GITLAB_NAMESPACE}
- operation: replace
path: "/metadata/annotations/meta.helm.sh~1release-namespace"
value: ${NEW_GITLAB_NAMESPACE}
kind: ConfigMap
metadata:
labels:
component: velero
name: gitlab-restore-modifier
namespace: cpaas-system
EOF
fi
创建恢复任务
执行以下命令创建恢复任务:
kubectl create -f - <<EOF
apiVersion: velero.io/v1
kind: Restore
metadata:
generateName: ${GITLAB_NAME}-restore-
namespace: cpaas-system
spec:
backupName: ${BACKUP_NAME}
hooks: {}
includedNamespaces:
- ${GITLAB_NAMESPACE}
includedResources:
- persistentvolumeclaims
- persistentvolumes
- secrets
- pods
- gitlabofficials.operator.alaudadevops.io
- volumesnapshots
- volumesnapshotcontents
itemOperationTimeout: 10h0m0s
namespaceMapping:
${GITLAB_NAMESPACE}: ${NEW_GITLAB_NAMESPACE}
resourceModifier:
kind: configmap
name: gitlab-restore-modifier
EOF
查看恢复日志:
kubectl logs -f -n cpaas-system -l app.kubernetes.io/instance=velero | grep gitlab-restore
# 输出示例:
# time="2025-07-01T08:01:41Z" level=info msg="Async fs restore data path completed" PVR=xxxx-gitlab-restore-mv6l5-sc4pk controller=PodVolumeRestore logSource="pkg/controller/pod_volume_restore_controller.go:275" pvr=xxxx-gitlab-restore-mv6l5-sc4pk
# time="2025-07-01T08:01:41Z" level=info msg="Restore completed" controller=PodVolumeRestore logSource="pkg/controller/pod_volume_restore_controller.go:327" pvr=xxxx-gitlab-restore-mv6l5-sc4pk
检查任务进度,若状态为 Completed
,说明恢复成功。
kubectl get restore -n cpaas-system -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.phase}{'\t'}{.status.startTimestamp}{'\n'}{end}"
# 输出示例:
# xxx-gitlab-restore-xxx InProgress 2025-07-01T10:18:17Z
清理资源
确保恢复操作完成后再执行!
执行以下命令完成资源清理。
kubectl get pod -n ${NEW_GITLAB_NAMESPACE} | grep ${GITLAB_NAME} | awk '{print $1}' | xargs kubectl delete pod -n ${NEW_GITLAB_NAMESPACE}
kubectl get secret -n ${NEW_GITLAB_NAMESPACE} | grep sh.helm.release.v1.${GITLAB_NAME} | awk '{print $1}' | xargs kubectl delete secret -n ${NEW_GITLAB_NAMESPACE}
修改 GitLab CR 资源
kubectl edit gitlabofficial ${GITLAB_NAME} -n ${NEW_GITLAB_NAMESPACE}
新实例 CR 资源可能需要以下修改,请根据实际情况调整。
- 域名:
- 适用场景:原实例通过域名部署
- 修改原因:旧、新实例创建的 ingress 资源域名相同会冲突,导致新实例 ingress 资源创建失败
- 修改建议:
- (推荐)将原实例域名改为临时域名,新实例保持不变
- 保持原实例域名不变,新实例改为新域名
- 修改方式:请参考配置实例网络访问修改实例访问域名。
- NodePort:
- 适用场景:原实例通过 NodePort 部署
- 修改原因:旧、新实例创建的 service 资源 NodePort 相同会冲突,导致新实例 service 资源创建失败
- 修改建议:
- (推荐)将原实例 NodePort 改为临时端口,新实例保持不变
- 保持原实例 NodePort 不变,新实例改为新端口
- 修改方式:请参考配置实例网络访问修改实例访问配置。
- 存储类:
- 适用场景:原实例部署时使用存储类,且新旧实例存储类不同(如原用 NFS,新用 Ceph)
- 修改原因:不修改时,operator 仍使用旧存储类创建 PVC,导致与恢复的 PVC 冲突
- 修改建议:修改为正确的存储类
- 修改方式:请参考配置实例存储修改实例存储配置。
- PostgreSQL 连接信息:
- 适用场景:新实例与旧实例计划使用不同的 PostgreSQL 实例或数据库
- 修改原因:不修改时,新实例仍连接旧的 PostgreSQL 实例或数据库
- 修改建议:修改为正确的 PostgreSQL 连接信息
- 修改方式:请参考配置 PostgreSQL 访问凭证配置修改 PostgreSQL 访问凭证配置。
部署 Gitlab CE Operator
进入 Administrator
视图,打开 Marketplace -> OperatorHub
页面,重新部署 Alauda Build of Gitlab
operator。
部署 Operator 后,operator 会根据 GitLab CR 部署新实例。您可在实例详情页查看实例部署进度。
等待实例状态恢复正常后,登录 GitLab 检查数据是否恢复成功。检查项包括但不限于:
常见问题解答
给额外资源打备份标签
此步骤为可选操作。如果您希望备份同一命名空间下的其他资源,可为对应资源添加 release 标签,标签值为原 GitLab 实例名称,例如:
metadata:
labels:
release: gitlab-g6zd4
如何判断 PVC 是否支持快照?
判断 PVC 是否支持快照,需要查看其底层 StorageClass 是否支持快照功能。若集群中存在 VolumeSnapshotClass,其 driver
与 StorageClass 的 provisioner
匹配,则该 StorageClass(及其 PVC)支持快照功能。
示例配置:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ceph
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
clusterID: rook-ceph
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
fsName: cephfs
pool: cephfs-data0
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: csi-cephfs-snapshotclass
deletionPolicy: Delete
driver: rook-ceph.cephfs.csi.ceph.com
parameters:
clusterID: rook-ceph
csi.storage.k8s.io/snapshotter-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/snapshotter-secret-namespace: rook-ceph
关键点:
- StorageClass 的
provisioner
必须与 VolumeSnapshotClass 的 driver
完全匹配
- 两者资源均需存在于集群中
- CSI 驱动必须支持快照操作