Миграция данных из GitLab 14.0.12 в 17.8.z
Решаемая проблема
Версии 3.16 и 3.18 поддерживают версии GitLab, которые отстают от официальных версий. Обновление GitLab до последней официальной версии требует более 10 обновлений для завершения. После обновления до 4.0 продукт не предоставляет автоматические обновления до 17.8.z. В этом решении описывается, как выполнить миграцию данных с 14.0.12 на 17.8.z.
Учитывая большой разрыв между версиями, для обновления применяется подход миграции данных.
Терминология
Обзор процесса
Путь миграции данных
Согласно официальной документации по пути обновления, путь миграции данных следующий:
- 14.0.12 -> 14.3.6
- 14.3.6 -> 14.9.5
- 14.9.5 -> 14.10.5
- 14.10.5 -> 15.0.5
- 15.0.5 -> 15.4.6
- 15.4.6 -> 15.11.13
- 15.11.13 -> 16.3.8
- 16.3.8 -> 16.7.9
- 16.7.9 -> 16.11.10
- 16.11.10 -> 17.3.6
- 17.3.6 → 17.5.5
- 17.5.5 → 17.8.1
В конце сделайте резервную копию данных из 17.8.1 и импортируйте её в экземпляр platform-deployed 17.8.z для завершения миграции данных.
Процесс миграции данных
Сделайте резервную копию platform-deployed GitLab и восстановите её в GitLab, развернутом с помощью all-in-one образа, затем обновите до 17.8.1 с помощью all-in-one образа и, наконец, восстановите резервную копию данных в экземпляр platform-deployed 17.8.z.
- Сделайте резервную копию экземпляра
platform-deployed GitLab 14.0.12.
- Восстановите резервную копию в развертывание GitLab 14.0.12 с помощью
all-in-one.
- Выполните поэтапное обновление развертывания
all-in-one до GitLab 17.8.1.
- Сделайте резервную копию обновленного экземпляра
all-in-one GitLab 17.8.1.
- Восстановите резервную копию из
all-in-one 17.8.1 в экземпляр platform-deployed GitLab 17.8.z.
TIP
Для последних версий GitLab и оператора смотрите Release Note.
Время миграции
Процесс миграции включает операции резервного копирования и восстановления базы данных и репозиториев:
- Чем больше база данных, тем дольше миграция.
- Большое количество репозиториев или крупные отдельные репозитории значительно увеличивают время.
- Производительность хранилища также влияет на эффективность — рекомендуется использовать topolvm для лучшей производительности.
Тестовая конфигурация:
- Один большой репозиторий (~600 МБ), остальные — маленькие начальные репозитории
- Экземпляр GitLab: 6,700 задач, 3,600 merge request
Предварительные требования
-
Установите kubectl (>=1.30.0) и yq (>=4.45.0) на хосте выполнения.
kubectl version --client
yq --version
# Вывод:
# Client Version: v1.30.0
# Kustomize Version: v5.4.2
# yq (https://github.com/mikefarah/yq/) version v4.45.4
-
Настройте переменные окружения:
# Замените на имя старого CR GitLab
export GITLAB_NAME=<old gitlab name>
export GITLAB_NAMESPACE=<gitlab deploy namespace>
-
Подготовьте PVC, необходимые для обновления. Они должны быть созданы в том же namespace, что и старый экземпляр GitLab:
TIP
Простой способ оценить необходимый размер хранилища для исходного экземпляра — сложить размеры PVC, используемых базой данных и компонентами Gitaly.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: backup-pvc
namespace: ${GITLAB_NAMESPACE}
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 40Gi
storageClassName: ceph
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: upgrade-pvc
namespace: ${GITLAB_NAMESPACE}
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 20Gi
storageClassName: ceph
volumeMode: Filesystem
- backup-pvc: Используется для хранения архивов резервных копий. Рекомендуемый объем — вдвое больше размера исходного экземпляра.
- Замените на имя storage class в вашем кластере.
- upgrade-pvc: Используется для хранения данных GitLab во время поэтапного обновления. Рекомендуется выделять объем, равный суммарному объему исходного экземпляра плюс тройной размер базы данных.
- Замените на имя storage class в вашем кластере.
-
Подготовьте образы, необходимые для обновления. Скачайте каждый образ из приложений и загрузите их в репозиторий образов, из которого кластер с GitLab сможет их подтягивать. Ссылки для скачивания образов:
# amd образы
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-0-12-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-3-6-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-9-5-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-10-5-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-15-0-5-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-15-4-6-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-15-11-13-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-16-3-8-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-16-7-9-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-16-11-10-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-17-3-6-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-17-5-5-amd.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-17-8-1-amd.tgz
# arm образы
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-0-12-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-3-6-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-9-5-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-14-10-5-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-15-0-5-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-15-4-6-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-15-11-13-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-16-3-8-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-16-7-9-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-16-11-10-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-17-3-6-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-17-5-5-arm.tgz
https://cloud.alauda.cn/attachments/knowledge/242090509/gitlab-ce-17-8-1-arm.tgz
# amd образы
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-0-12-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-3-6-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-9-5-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-10-5-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-15-0-5-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-15-4-6-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-15-11-13-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-16-3-8-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-16-7-9-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-16-11-10-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-17-3-6-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-17-5-5-amd.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-17-8-1-amd.tgz
# arm образы
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-0-12-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-3-6-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-9-5-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-14-10-5-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-15-0-5-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-15-4-6-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-15-11-13-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-16-3-8-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-16-7-9-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-16-11-10-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-17-3-6-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-17-5-5-arm.tgz
https://cloud.alauda.io/attachments/knowledge/242090509/gitlab-ce-17-8-1-arm.tgz
-
Подготовьте скрипты, необходимые для обновления.
Выполните следующую команду для генерации четырёх скриптов:
check_gitlab.sh: Проверка готовности pod GitLab.
finalize_migrations.sql: Завершение миграций.
monitor_gitlab.sh: Мониторинг pod GitLab для проверки завершения миграции данных.
rolling_upgrade.sh: Поэтапное обновление экземпляров GitLab один за другим.
cat << 'EOF' > check_gitlab.sh
#!/bin/bash
gitlab_pod=$1
port=${2:-30855}
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log "Запуск скрипта мониторинга для pod GitLab: ${gitlab_pod} на порту: ${port}"
while true; do
curl_result=$(kubectl -n $GITLAB_NAMESPACE exec ${gitlab_pod} -- curl -s localhost:${port} | grep "You are being")
if [[ -z "${curl_result}" ]]; then
log "HTTP не готов. Повтор через 10 секунд..."
sleep 10
continue
fi
log "GitLab готов"
break
done
EOF
cat << 'EOF' > finalize_migrations.sql
select concat(
'gitlab-rake gitlab:background_migrations:finalize[',
job_class_name, ',',
table_name, ',',
column_name, $$,'$$,
REPLACE(cast(job_arguments as text), ',', $$\,$$),
$$']$$
)
from batched_background_migrations WHERE status NOT IN(3, 6);
EOF
cat << 'EOF' > monitor_gitlab.sh
#!/bin/bash
gitlab_pod=$1
port=${2:-30855}
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log "Запуск скрипта мониторинга для pod GitLab: ${gitlab_pod} на порту: ${port}"
while true; do
curl_result=$(kubectl -n $GITLAB_NAMESPACE exec ${gitlab_pod} -- curl -s localhost:${port} | grep "You are being")
if [[ -z "${curl_result}" ]]; then
log "HTTP проверка не готова. Повтор через 10 секунд..."
sleep 10
continue
fi
migration_result=$(kubectl -n $GITLAB_NAMESPACE exec ${gitlab_pod} -- gitlab-psql -c "SELECT job_class_name, table_name, column_name, job_arguments FROM batched_background_migrations WHERE status NOT IN(3, 6);" | grep "(0 rows)")
if [[ -z "${migration_result}" ]]; then
log "Миграция базы данных выполняется. Повтор через 10 секунд..."
sleep 10
continue
fi
log "GitLab готов, все миграции завершены"
break
done
EOF
cat << 'EOF' > rolling_upgrade.sh
#!/bin/bash
image=$(kubectl -n $GITLAB_NAMESPACE get deployment gitlab -o jsonpath='{.spec.template.spec.containers[?(@.name=="gitlab")].image} ')
versions=(
14.0.12-ce.0
14.3.6-ce.0
14.9.5-ce.0
14.10.5-ce.0
15.0.5-ce.0
15.4.6-ce.0
15.11.13-ce.0
16.3.8-ce.0
16.7.9-ce.0
16.11.10-ce.0
17.3.6-ce.0
17.5.5-ce.0
17.8.1-ce.0
)
STATE_FILE="upgrade_state.log"
touch "$STATE_FILE"
is_done() {
grep -Fxq "$1" "$STATE_FILE"
}
mark_done() {
echo "$1" >> "$STATE_FILE"
}
for version in "${versions[@]}"; do
if is_done "$version"; then
echo "Версия ${version} уже обработана, пропускаем..."
continue
fi
echo "Обновление до ${version}..."
new_image="${image%:*}:${version}"
kubectl -n $GITLAB_NAMESPACE set image deployment/gitlab gitlab=$new_image
echo "Ожидание запуска pod GitLab..."
sleep 10
kubectl -n $GITLAB_NAMESPACE wait deploy gitlab --for condition=available --timeout=3000s
sleep 10
kubectl -n $GITLAB_NAMESPACE wait pod -l deploy=gitlab --for=condition=Ready --timeout=3000s
new_pod_name=$(kubectl -n $GITLAB_NAMESPACE get po -l deploy=gitlab --sort-by=.metadata.creationTimestamp --field-selector=status.phase=Running -o jsonpath='{.items[-1].metadata.name}')
echo "Ожидание готовности GitLab..."
bash check_gitlab.sh $new_pod_name
echo "Ожидание завершения миграций..."
kubectl -n $GITLAB_NAMESPACE cp finalize_migrations.sql $new_pod_name:/tmp/finalize_migrations.sql
for i in {1..10}; do
echo "Выполнение миграционных задач (попытка $i/10)..."
if kubectl -n $GITLAB_NAMESPACE exec -ti $new_pod_name -- bash -c "gitlab-psql -t -A -f /tmp/finalize_migrations.sql > /tmp/run_migration_tasks.sh && xargs -d \"\n\" -P 3 -I {} bash -c \"{}\" < /tmp/run_migration_tasks.sh"; then
echo "Миграционные задачи успешно выполнены"
break
fi
sleep 30
done
bash monitor_gitlab.sh $new_pod_name
echo "Обновление до ${version} успешно завершено"
mark_done "$version"
done
echo "Все обновления успешно завершены!"
EOF
├── check_gitlab.sh
├── finalize_migrations.sql
├── monitor_gitlab.sh
└── rolling_upgrade.sh
-
Включите компонент task-runner в GitLab 14 для выполнения команд резервного копирования
# сформировать имя репозитория и тег для task-runner на основе образа gitaly
image=$(kubectl get pod ${GITLAB_NAME}-gitaly-0 -n $GITLAB_NAMESPACE -o jsonpath='{.spec.containers[0].image}')
tag=${image##*:}
registry=${image%%/*}
echo "registry: ${registry}"
echo "tag: ${tag}"
kubectl patch gitlabofficials.operator.devops.alauda.io "${GITLAB_NAME}" \
-n "$GITLAB_NAMESPACE" \
--type=merge \
-p "$(cat <<EOF
{
"spec": {
"helmValues": {
"gitlab": {
"task-runner": {
"enabled": "true",
"image": {
"repository": "${registry}/devops/gitlab-org/build/cng/gitlab-task-runner-ce",
"tag": "${tag}"
},
"resources": {
"limits": {
"cpu": "2",
"memory": "4G"
}
}
}
}
}
}
}
EOF
)"
# Ожидание доступности развертывания task-runner
echo "Ожидание доступности развертывания task-runner..."
sleep 60
# Проверка существования развертывания ${GITLAB_NAME}-task-runner
kubectl wait deploy ${GITLAB_NAME}-task-runner -n $GITLAB_NAMESPACE --for condition=available --timeout=3000s
kubectl get deploy -n $GITLAB_NAMESPACE ${GITLAB_NAME}-task-runner
kubectl patch gitlabofficials.operator.devops.alauda.io ${GITLAB_NAME} -n $GITLAB_NAMESPACE --type='merge' -p='
{
"spec": {
"helmValues": {
"gitlab": {
"task-runner": {
"enabled": "true",
"resources": { "limits": { "cpu": "2", "memory": "4G" } }
}
}
}
}
}'
# Ожидание доступности развертывания task-runner
echo "Ожидание доступности развертывания task-runner..."
sleep 60
# Проверка существования развертывания ${GITLAB_NAME}-task-runner
kubectl wait deploy ${GITLAB_NAME}-task-runner -n $GITLAB_NAMESPACE --for condition=available --timeout=3000s
kubectl get deploy -n $GITLAB_NAMESPACE ${GITLAB_NAME}-task-runner
# gitlabofficial.operator.devops.alauda.io/xxx patched
# Ожидание доступности развертывания task-runner...
# deployment.apps/xxx-task-runner condition met
# NAME READY UP-TO-DATE AVAILABLE AGE
# high-sc-sso-ingress-https-task-runner 1/1 1 1 178m
-
Переведите GitLab 14 в режим только для чтения
kubectl patch deploy ${GITLAB_NAME}-webservice-default -n $GITLAB_NAMESPACE --type='merge' -p='{"metadata":{"annotations":{"skip-sync":"true"}}}'
kubectl patch deploy ${GITLAB_NAME}-sidekiq-all-in-1-v1 -n $GITLAB_NAMESPACE --type='merge' -p='{"metadata":{"annotations":{"skip-sync":"true"}}}'
kubectl scale deploy ${GITLAB_NAME}-webservice-default -n $GITLAB_NAMESPACE --replicas 0
kubectl scale deploy ${GITLAB_NAME}-sidekiq-all-in-1-v1 -n $GITLAB_NAMESPACE --replicas 0
# deployment.apps/gitlab-old-webservice-default patched
# deployment.apps/gitlab-old-sidekiq-all-in-1-v1 patched
# deployment.apps/gitlab-old-webservice-default scaled
# deployment.apps/gitlab-old-sidekiq-all-in-1-v1 scaled
-
Примените патч к backup PVC для task-runner GitLab 14. PVC должен называться backup-pvc.
kubectl patch deploy ${GITLAB_NAME}-task-runner -n $GITLAB_NAMESPACE --type='json' -p='
[
{
"op": "add",
"path": "/metadata/annotations/skip-sync",
"value": "true"
},
{
"op": "replace",
"path": "/spec/template/spec/volumes/1",
"value": {"name": "task-runner-tmp", "persistentVolumeClaim": {"claimName": "backup-pvc"}}
}
]'
echo "Ожидание доступности развертывания task-runner..."
sleep 60
# Проверка существования развертывания ${GITLAB_NAME}-task-runner
kubectl wait deploy ${GITLAB_NAME}-task-runner -n $GITLAB_NAMESPACE --for condition=available --timeout=3000s
kubectl get deploy -n $GITLAB_NAMESPACE ${GITLAB_NAME}-task-runner
# deployment.apps/xxx-task-runner patched
# Ожидание доступности развертывания task-runner...
# deployment.apps/gitlab-14-task-runner condition met
# NAME READY UP-TO-DATE AVAILABLE AGE
# gitlab-14-task-runner 1/1 1 1 4m6s
-
Сделайте резервную копию данных GitLab 14
pod_name=$(kubectl get po -n $GITLAB_NAMESPACE -l app=task-runner,release=${GITLAB_NAME} -o jsonpath='{.items[0].metadata.name}')
kubectl exec -ti -n "$GITLAB_NAMESPACE" $pod_name -- gitlab-rake gitlab:backup:create SKIP=repositories
# Добавьте права на файл резервной копии.
kubectl exec -ti -n "$GITLAB_NAMESPACE" $pod_name -- bash -c '
chmod 777 /srv/gitlab/tmp/backups/*_gitlab_backup.tar
ls -lh /srv/gitlab/tmp/backups
'
# 2024-11-01 06:16:06 +0000 -- Dumping database ...
# Dumping PostgreSQL database gitlabhq_production ... [DONE]
# 2024-11-01 06:16:18 +0000 -- done
# ....
# done
# Deleting old backups ... skipping
# Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
# and are not included in this backup. You will need these files to restore a backup.
# Please back them up manually.
# Backup task is done.
# total 300K
# -rwxrwxrwx 1 git git 300K Sep 15 09:15 1757927758_2025_09_15_14.0.12_gitlab_backup.tar
Сохраните rails-secret, выполнив следующую команду, которая сохранит rails-secret в файл gitlab14-rails-secret.yaml в текущем каталоге.
kubectl get secrets -n ${GITLAB_NAMESPACE} ${GITLAB_NAME}-rails-secret -o jsonpath="{.data['secrets\.yml']}" | base64 --decode | yq -o yaml > gitlab14-rails-secret.yaml
-
Удалите компонент task-runner после завершения резервного копирования.
kubectl patch gitlabofficials.operator.devops.alauda.io ${GITLAB_NAME} -n $GITLAB_NAMESPACE --type='merge' -p='
{
"spec": {
"helmValues": {
"gitlab": {
"task-runner": null
}
}
}
}'
echo "Ожидание удаления развертывания task-runner..."
sleep 30
kubectl get po -n "$GITLAB_NAMESPACE" -l app=task-runner,release=${GITLAB_NAME}
# Ожидание удаления развертывания task-runner...
# No resources found in xxxx namespace.
Восстановление резервной копии в развертывание all-in-one 14.0.12
-
Используйте образ all-in-one для развертывания GitLab 14.0.12.
Сначала установите переменную окружения NODE_IP для доступа к экземпляру all-in-one GitLab через этот IP и порт NodePort.
export NODE_IP=<node_ip>
export GITLAB_IMAGE=<registry-host>/gitlab/gitlab-ce:14.0.12-ce.0
Создайте экземпляр all-in-one GitLab.
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: gitlab-http-nodeport
namespace: ${GITLAB_NAMESPACE}
spec:
ports:
- appProtocol: tcp
name: web
port: 30855
protocol: TCP
targetPort: 30855
nodePort: 30855
selector:
deploy: gitlab
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitlab
namespace: ${GITLAB_NAMESPACE}
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
deploy: gitlab
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
deploy: gitlab
spec:
affinity: {}
containers:
- env:
# Внешний адрес доступа all-in-one gitlab, замените на IP и порт nodeport узла кластера
- name: GITLAB_OMNIBUS_CONFIG
value: external_url 'http://${NODE_IP}:30855'
image: ${GITLAB_IMAGE} # Можно заменить на доступный для загрузки образ
imagePullPolicy: IfNotPresent
name: gitlab
ports:
- containerPort: 30855
name: http
protocol: TCP
- containerPort: 2424
name: ssh
protocol: TCP
resources:
limits:
cpu: "8"
memory: 8Gi
requests:
cpu: 4
memory: "4Gi"
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /dev/shm
name: dshm
- mountPath: /var/opt/gitlab/backups
name: backup
subPath: backups
- mountPath: /etc/gitlab
name: gitlab-upgrade-data
subPath: config
- mountPath: /var/log/gitlab
name: gitlab-upgrade-data
subPath: logs
- mountPath: /var/opt/gitlab
name: gitlab-upgrade-data
subPath: data
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: dshm
emptyDir:
medium: Memory
sizeLimit: 512Mi
- name: backup
persistentVolumeClaim:
claimName: backup-pvc
- name: gitlab-upgrade-data
persistentVolumeClaim:
claimName: upgrade-pvc
EOF
# service/gitlab-http-nodeport created
# deployment.apps/gitlab created
Проверьте, успешно ли запустился экземпляр all-in-one GitLab.
pod_name=$(kubectl get po -l deploy=gitlab -n $GITLAB_NAMESPACE -o jsonpath='{.items[0].metadata.name}')
bash check_gitlab.sh $pod_name
# 2024-11-01 16:02:47 - Запуск скрипта мониторинга для pod GitLab: gitlab-7ff8d674bd-m65nz на порту: 30855
# 2024-11-01 16:12:59 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:09 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:19 - HTTP не готов. Повтор через 10 секунд...
# ...
# 2024-11-01 16:13:29 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:40 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:50 - GitLab готов
-
Измените содержимое rails secret в all-in-one GitLab. Замените поля secret_key_base, otp_key_base, db_key_base, openid_connect_signing_key, ci_jwt_signing_key соответствующими полями из сохранённого rails secret GitLab 14.
# Скопируйте gitlab-secrets.json локально
pod_name=$(kubectl get po -l deploy=gitlab -n $GITLAB_NAMESPACE -o jsonpath='{.items[0].metadata.name}')
kubectl -n $GITLAB_NAMESPACE cp $pod_name:/etc/gitlab/gitlab-secrets.json all-in-one-gitlab-secrets.json
# Замените данными из gitlab 14 rails-secret.
KEYS=(secret_key_base otp_key_base db_key_base openid_connect_signing_key ci_jwt_signing_key)
for key in "${KEYS[@]}"; do
echo "Заменяем ${key} ..."
export KEY_VALUE=$(yq eval -r --unwrapScalar=false ".production.${key}" gitlab14-rails-secret.yaml)
yq eval ".gitlab_rails.${key} = env(KEY_VALUE)" all-in-one-gitlab-secrets.json -i
done
# Скопируйте gitlab-secrets.json обратно в pod
kubectl -n $GITLAB_NAMESPACE cp all-in-one-gitlab-secrets.json $pod_name:/etc/gitlab/gitlab-secrets.json
# tar: Removing leading `/' from member names
# Заменяем secret_key_base ...
# Заменяем otp_key_base ...
# Заменяем db_key_base ...
# Заменяем openid_connect_signing_key ...
# Заменяем ci_jwt_signing_key ...
Отключите ненужные компоненты.
cat <<EOF >> gitlab.rb
prometheus['enable'] = false
gitlab_kas['enable'] = false
redis_exporter['enable'] = false
gitlab_exporter['enable'] = false
postgres_exporter['enable'] = false
sidekiq['enable'] = false
EOF
# Скопируйте gitlab.rb в pod
kubectl -n $GITLAB_NAMESPACE cp gitlab.rb $pod_name:/etc/gitlab/gitlab.rb
-
Синхронизируйте данные Gitaly с all-in-one GitLab
Tip
Этот шаг необходимо выполнять на узле, где запущен pod all-in-one GitLab.
Сначала определите пути монтирования на узле для PVC компонента Gitaly исходного GitLab (названного repo-data-${GITLAB_NAME}-gitaly-0) и PVC обновления (названного upgrade-pvc), используемого all-in-one GitLab.
Используйте команду rsync для эффективного копирования данных Gitaly с исходного PVC в upgrade-pvc экземпляра all-in-one GitLab.
Tip
Используйте rsync вместо scp — это значительно быстрее и эффективнее для такого типа передачи данных.
Получите тип хранилища исходного экземпляра
persistence_type=$(kubectl get GitlabOfficial.operator.devops.alauda.io -n $GITLAB_NAMESPACE $GITLAB_NAME -o jsonpath='{.spec.persistence.type}')
echo "Тип persistence gitlab: $persistence_type"
origin_gitaly_local_mount_path=$(kubectl get GitlabOfficial.operator.devops.alauda.io -n $GITLAB_NAMESPACE $GITLAB_NAME -o jsonpath='{.spec.persistence.location.path}')/gitlab
origin_gitaly_node_ip=<origin_gitaly_node_ip>
all_in_one_upgrade_pvc_mount_path=<all_in_one_gitaly_mount_path>
# Выполните эту команду на узле, где находится pod all-in-one.
rsync -avh --chown=998:998 ${origin_gitaly_node_ip}:${origin_gitaly_local_mount_path}/ ${all_in_one_upgrade_pvc_mount_path}/data/git-data/repositories/
# Проверьте владельца данных репозитория.
ls -alh ${all_in_one_upgrade_pvc_mount_path}/data/git-data/repositories
origin_gitaly_pvc_mount_path=<origin_gitaly_mount_path>
origin_gitaly_node_ip=<origin_gitaly_node_ip>
all_in_one_upgrade_pvc_mount_path=<all_in_one_gitaly_mount_path>
# Выполните эту команду на узле, где находится pod all-in-one.
rsync -avh --chown=998:998 ${origin_gitaly_node_ip}:${origin_gitaly_pvc_mount_path}/ ${all_in_one_upgrade_pvc_mount_path}/data/git-data/repositories/
# Проверьте владельца данных репозитория.
ls -alh ${all_in_one_upgrade_pvc_mount_path}/data/git-data/repositories
Перезапустите pod и дождитесь его запуска.
# Перезапуск pod
kubectl delete po -l deploy=gitlab -n $GITLAB_NAMESPACE
echo "Ожидание запуска pod..."
sleep 10
pod_name=$(kubectl get po -l deploy=gitlab -n $GITLAB_NAMESPACE -o jsonpath='{.items[0].metadata.name}')
bash check_gitlab.sh $pod_name
# pod "gitlab-xxxx" deleted
# Ожидание запуска pod...
# 2024-11-01 16:02:47 - Запуск скрипта мониторинга для pod GitLab: gitlab-7ff8d674bd-m65nz на порту: 30855
# 2024-11-01 16:12:59 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:09 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:19 - HTTP не готов. Повтор через 10 секунд...
# ...
# 2024-11-01 16:13:29 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:40 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:50 - GitLab готов
-
Восстановите резервные данные.
TIP
Во время восстановления могут возникать ошибки, связанные с базой данных, например:
ERROR: role "xxx" does not exist
ERROR: function xxx does not exist
ERROR: permission denied to create extension "pg_stat_statements"
ERROR: could not open extension control file
Эти ошибки можно игнорировать, подробности доступны по ссылке (https://gitlab.com/gitlab-org/gitlab/-/issues/266988).
# Перевод gitlab в режим только для чтения
pod_name=$(kubectl get po -l deploy=gitlab -n $GITLAB_NAMESPACE -o jsonpath='{.items[0].metadata.name}')
kubectl -n $GITLAB_NAMESPACE exec -ti $pod_name -- gitlab-ctl stop puma
kubectl -n $GITLAB_NAMESPACE exec -ti $pod_name -- gitlab-ctl stop sidekiq
# Подтвердите остановку puma и sidekiq
kubectl -n $GITLAB_NAMESPACE exec -ti $pod_name -- gitlab-ctl status
# Выполните восстановление
backup_id=$(kubectl -n $GITLAB_NAMESPACE exec -ti $pod_name -- bash -c 'ls /var/opt/gitlab/backups/*14.0.12_gitlab_backup.tar | head -n1 | sed "s|.*/\([0-9_]*_14\.0\.12\)_gitlab_backup\.tar|\1|"')
echo "ID резервной копии: ${backup_id}"
echo "На этом шаге вам будет предложено несколько раз подтвердить продолжение. \nПожалуйста, выбирайте \"yes\" для продолжения."
kubectl -n $GITLAB_NAMESPACE exec -ti $pod_name -- bash -c 'gitlab-backup restore BACKUP=${backup_id}'
# ok: down: puma: 666s, normally up
# ok: down: sidekiq: 660s, normally up
# ...
# run: prometheus: (pid 1142) 1043s; run: log: (pid 680) 1092s
# down: puma: 695s, normally up; run: log: (pid 536) 1128s
# down: sidekiq: 687s, normally up; run: log: (pid 551) 1124s
# run: sshd: (pid 42) 1171s; run: log: (pid 41) 1171s
# command terminated with exit code 6
# ...
# Эта задача сейчас перестроит файл authorized_keys.
# Вы потеряете все данные, хранящиеся в файле authorized_keys.
# Хотите продолжить (yes/no)? yes
#
# Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
# and are not included in this backup. You will need to restore these files manually.
# Restore task is done.
Перезапустите pod и дождитесь запуска, затем выполните gitlab-rake gitlab:check SANITIZE=true для проверки целостности GitLab.
# Перезапуск pod
kubectl delete po -l deploy=gitlab -n $GITLAB_NAMESPACE
# Ожидание запуска pod
sleep 10
pod_name=$(kubectl get po -l deploy=gitlab -n $GITLAB_NAMESPACE -o jsonpath='{.items[0].metadata.name}')
bash check_gitlab.sh $pod_name
kubectl -n $GITLAB_NAMESPACE exec -ti $pod_name -- gitlab-rake gitlab:check SANITIZE=true
# pod "gitlab-xxxx" deleted
# 2024-11-01 16:02:47 - Запуск скрипта мониторинга для pod GitLab: gitlab-7ff8d674bd-m65nz на порту: 30855
# 2024-11-01 16:12:59 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:09 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:19 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:29 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:40 - HTTP не готов. Повтор через 10 секунд...
# 2024-11-01 16:13:50 - GitLab готов
# ...
# GitLab настроен для хранения новых проектов в хэшированном хранилище? ... да
# Все проекты в хэшированном хранилище? ... да
# Проверка GitLab App ... Завершена
# Проверка подзадач GitLab ... Завершена
Войдите в GitLab и проверьте успешность восстановления экземпляра (пароль пользователя root остаётся прежним), выполните команду для получения адреса доступа к экземпляру all-in-one.
kubectl -n $GITLAB_NAMESPACE get pod -l deploy=gitlab -o yaml | grep external_url
# value: external_url 'http://192.168.xxx.xxx:30855'
Поэтапное обновление all-in-one GitLab до 17.8.1
Выполните скрипт rolling_upgrade.sh, который по шагам обновит экземпляр all-in-one до версии 17.8.1 согласно пути обновления.
bash -x rolling_upgrade.sh
Tip
Во время поэтапного обновления база данных может автоматически перезапускаться. В результате скрипт может показывать ошибки вида:
connections on Unix domain socket "/var/opt/gitlab/postgresql/.s.PGSQL.5432"
Это ожидаемо — скрипт автоматически повторит попытку и продолжит работу.
После завершения скрипта зайдите в веб-интерфейс GitLab, проверьте, что версия экземпляра 17.8.1 и данные целы, включая репозитории кода, пользователей, задачи, merge request и т.д.
Резервное копирование данных из экземпляра all-in-one 17.8.1
Остановите сервис экземпляра all-in-one и сделайте резервную копию данных. Файлы резервной копии будут сохранены в директории /var/opt/gitlab/backups/.
pod_name=$(kubectl get po -l deploy=gitlab -n $GITLAB_NAMESPACE -o jsonpath='{.items[0].metadata.name}')
kubectl -n $GITLAB_NAMESPACE exec -ti $pod_name -- bash -c '
gitlab-ctl stop puma
gitlab-ctl stop sidekiq
gitlab-ctl status
gitlab-rake gitlab:backup:create
'
# ok: down: puma: 0s, normally up
# ok: down: sidekiq: 0s, normally up
# ...
# 2025-09-15 03:24:37 UTC -- Deleting backups/tmp ...
# 2025-09-15 03:24:37 UTC -- Deleting backups/tmp ... done
# 2025-09-15 03:24:37 UTC -- Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
# and are not included in this backup. You will need these files to restore a backup.
# Please back them up manually.
# 2025-09-15 03:24:37 UTC -- Backup 1757906670_2025_09_15_17.8.1 is done.
# 2025-09-15 03:24:37 UTC -- Deleting backup and restore PID file at [/opt/gitlab/embedded/service/gitlab-rails/tmp/backup_restore.pid] ... done
Остановите сервис экземпляра all-in-one.
kubectl scale deploy gitlab -n $GITLAB_NAMESPACE --replicas 0
# deployment.apps/gitlab scaled
Namespace нового экземпляра gitlab
Namespace нового экземпляра gitlab должен совпадать с namespace старого экземпляра.
-
Следуйте GitLab Deployment Guide для развертывания нового экземпляра GitLab 17.8.z с помощью оператора.
Tip
- Новый экземпляр должен быть в том же namespace, что и старый
- Метод доступа к новому экземпляру не должен конфликтовать со старым, например, доменное имя, nodeport и т.д.
После развертывания нового экземпляра установите переменную окружения с именем нового экземпляра:
export NEW_GITLAB_NAME=<name of the new GitLab instance>
-
Включите компонент toolbox для нового экземпляра GitLab.
kubectl patch gitlabofficial.operator.alaudadevops.io ${NEW_GITLAB_NAME} -n $GITLAB_NAMESPACE --type='merge' -p='
{
"spec": {
"helmValues": {
"gitlab": {
"toolbox": {
"enabled": true,
"resources": {
"limits": {
"cpu": 2,
"memory": "4G"
}
}
}
}
}
}
}'
Дождитесь завершения повторного развертывания экземпляра.
kubectl get po -l app=toolbox,release=${NEW_GITLAB_NAME} -n $GITLAB_NAMESPACE
# NAME READY STATUS RESTARTS AGE
# xx-gitlab-toolbox-xxxx-xxxx-xxxx-xxxx 1/1 Running 0 178m
-
Восстановите резервную копию в GitLab 17.8.z, развернутый оператором
TIP
Во время восстановления могут возникать ошибки, связанные с базой данных, например:
ERROR: role "xxx" does not exist
ERROR: function xxx does not exist
ERROR: must be owner of extension
Эти ошибки можно игнорировать, подробности доступны по ссылке (https://gitlab.com/gitlab-org/gitlab/-/issues/266988).
Закройте внешний доступ к новому экземпляру gitlab 17.8.z и примените патч к компоненту toolbox для монтирования backup pvc.
kubectl patch deploy ${NEW_GITLAB_NAME}-webservice-default -n $GITLAB_NAMESPACE --type='merge' -p='{"metadata":{"annotations":{"skip-sync":"true"}}}'
kubectl patch deploy ${NEW_GITLAB_NAME}-sidekiq-all-in-1-v2 -n $GITLAB_NAMESPACE --type='merge' -p='{"metadata":{"annotations":{"skip-sync":"true"}}}'
kubectl scale deploy ${NEW_GITLAB_NAME}-webservice-default -n $GITLAB_NAMESPACE --replicas 0
kubectl scale deploy ${NEW_GITLAB_NAME}-sidekiq-all-in-1-v2 -n $GITLAB_NAMESPACE --replicas 0
# Измените toolbox, смонтируйте backup pvc в toolbox
kubectl patch deploy ${NEW_GITLAB_NAME}-toolbox -n $GITLAB_NAMESPACE -p='{"metadata":{"annotations":{"skip-sync":"true"}}}'
kubectl patch deploy ${NEW_GITLAB_NAME}-toolbox -n $GITLAB_NAMESPACE --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/volumes/1", "value": {"name": "toolbox-tmp", "persistentVolumeClaim": {"claimName": "backup-pvc"}}}]'
# deployment.apps/xxxx-xxxx-toolbox patched
Дождитесь готовности pod toolbox, затем восстановите резервную копию в новый экземпляр GitLab.
toolbox_pod_name=$(kubectl get po -n $GITLAB_NAMESPACE -l release=$NEW_GITLAB_NAME,app=toolbox -o jsonpath='{.items[0].metadata.name}')
# Сделайте резервную копию старого файла резервной копии
kubectl -n $GITLAB_NAMESPACE exec -ti $toolbox_pod_name -- bash -c '
mkdir -p /srv/gitlab/tmp/backup_tarballs
mv /srv/gitlab/tmp/backups/*gitlab_backup.tar /srv/gitlab/tmp/backup_tarballs || true
'
backup_file=$(kubectl -n $GITLAB_NAMESPACE exec -ti $toolbox_pod_name -- bash -c "ls /srv/gitlab/tmp/backup_tarballs/*17.8.1_gitlab_backup.tar | head -n1 | tr -d '\r\n'")
echo "Файл резервной копии 17.8.1: ${backup_file}"
kubectl -n $GITLAB_NAMESPACE exec -ti $toolbox_pod_name -- backup-utility --restore --skip-restore-prompt -f "file://${backup_file}"
# Файл резервной копии 17.8.1: 1757906670_2025_09_15_17.8.1_gitlab_backup.tar
# 2025-09-15 06:59:21 UTC -- Восстановление репозиториев ... выполнено
# 2025-09-15 06:59:21 UTC -- Удаление PID файла резервного копирования и восстановления [/srv/gitlab/tmp/backup_restore.pid] ... выполнено
# 2025-09-15 06:59:41 UTC -- Восстановление сборок ...
# 2025-09-15 06:59:41 UTC -- Восстановление сборок ... выполнено
# 2025-09-15 06:59:41 UTC -- Удаление PID файла резервного копирования и восстановления [/srv/gitlab/tmp/backup_restore.pid] ... выполнено
# Backup tarball не из установки на основе Helm chart. Файлы в объектном хранилище не обрабатываются.
-
Замените rails-secret для нового экземпляра GitLab.
kubectl get secrets -n ${GITLAB_NAMESPACE} ${NEW_GITLAB_NAME}-rails-secret -o jsonpath="{.data['secrets\.yml']}" | base64 --decode | yq -o yaml > gitlab17-rails-secret.yaml
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' gitlab17-rails-secret.yaml gitlab14-rails-secret.yaml > final-rails-secret.yml
kubectl create secret generic rails-secret -n ${GITLAB_NAMESPACE} --from-file=secrets.yml=final-rails-secret.yml
kubectl patch gitlabofficials.operator.alaudadevops.io ${NEW_GITLAB_NAME} -n $GITLAB_NAMESPACE --type='merge' -p='
{
"spec": {
"helmValues": {
"global": {
"railsSecrets": {
"secret": "rails-secret"
}
}
}
}
}'
kubectl patch deploy ${NEW_GITLAB_NAME}-webservice-default -n $GITLAB_NAMESPACE --type='json' -p='[{"op":"remove","path":"/metadata/annotations/skip-sync"}]'
kubectl patch deploy ${NEW_GITLAB_NAME}-sidekiq-all-in-1-v2 -n $GITLAB_NAMESPACE --type='json' -p='[{"op":"remove","path":"/metadata/annotations/skip-sync"}]'
kubectl patch deploy ${NEW_GITLAB_NAME}-toolbox -n $GITLAB_NAMESPACE --type='json' -p='[{"op":"remove","path":"/metadata/annotations/skip-sync"}]'
kubectl delete pod -lrelease=${NEW_GITLAB_NAME} -n $GITLAB_NAMESPACE
kubectl scale deploy ${NEW_GITLAB_NAME}-webservice-default -n $GITLAB_NAMESPACE --replicas 1
kubectl scale deploy ${NEW_GITLAB_NAME}-sidekiq-all-in-1-v2 -n $GITLAB_NAMESPACE --replicas 1
# secret/rails-secret created
# gitlabofficial.operator.alaudadevops.io/xxxx-xxxx patched
Оператор автоматически повторно развернёт новый экземпляр GitLab. Дождитесь завершения повторного развертывания.
-
Проверьте, что данные после обновления корректны.
- Зайдите в UI GitLab в режиме администратора и проверьте, что репозитории и данные пользователей в порядке.
- Выберите несколько репозиториев и проверьте, что код, ветки и merge request работают корректно.
-
Очистите неиспользуемые ресурсы:
- При необходимости удалите старый экземпляр GitLab и старый оператор.
- При необходимости удалите экземпляр
all-in-one GitLab.
FAQ
Восстановление данных Uploads
Мигрированные данные не включают аватары и вложения, поэтому новый экземпляр GitLab не может отображать этот контент. Чтобы решить эту проблему, можно заменить PVC uploads GitLab 17.8.z на PVC, используемый 14.0.12.
Установите переменную окружения с именем PVC uploads:
export UPLOADS_PVC_NAME=<name of the uploads pvc>
Примените патч к новому экземпляру GitLab для использования PVC uploads:
kubectl patch gitlabofficials.operator.alauda.io ${NEW_GITLAB_NAME} -n $GITLAB_NAMESPACE --type='json' -p='
{
"spec": {
"helmValues": {
"global": {
"uploads": {
"persistence": {
"enabled": true,
"existingClaim": "${UPLOADS_PVC_NAME}"
}
}
}
}
}
}'
Если ваш старый экземпляр GitLab использует хранилище HostPath, необходимо вручную скопировать данные из каталога uploads старого экземпляра в путь /srv/gitlab/public/uploads компонента webservice нового экземпляра.
Как найти путь монтирования PVC на узле
Выполните следующие шаги, чтобы определить путь монтирования PersistentVolumeClaim (PVC) на узле Kubernetes:
-
Получите IP узла, на котором запущен pod
kubectl -n $GITLAB_NAMESPACE get pod <pod-name> -o jsonpath='{.status.hostIP}'
# Вывод:
# 192.168.xxx.xxx
-
Получите имя тома, связанного с PVC
kubectl get pvc -n $GITLAB_NAMESPACE <pvc-name> -o jsonpath='{.spec.volumeName}'
# Вывод:
# pvc-359bb8d2-841e-406c-a5e7-e48bc701f610
-
Найдите путь монтирования PVC на узле
Войдите на узел (используя IP из шага 1), затем выполните:
df -h | grep <pv-name>
# Вывод:
# 192.168.xx.xx:6789:/volumes/csi/csi-vol-4661bd66-a68f-42f6-b995-53bd5c3f79a8/ede3ffa1-0f77-4f44-b0e6-41ec7384484f 10G 216M 9.8G 3% /var/lib/kubelet/pods/7772096f-9b81-4698-8369-34689e36fc3a/ volumes/kubernetes.io~csi/pvc-359bb8d2-841e-406c-a5e7-e48bc701f610/mount
Путь, указанный в последнем столбце, например:
/var/lib/kubelet/pods/7772096f-9b81-4698-8369-34689e36fc3a/volumes/kubernetes.io~csi/pvc-359bb8d2-841e-406c-a5e7-e48bc701f610/mount
является директорией монтирования вашего PVC на узле.