先日、長期間放置されたGitLab1のアップグレードを手掛ける機会がありました。本記事はその際に実施した内容を記録したものです。
GitLabのアップグレード方法自体は公式ドキュメントを読めば理解できるものですが、Docker Composeで構築されたセルフホスティングのGitLabという (有りそうで案外珍しい) 構成だったため、一事例として書き残すことにしました。
前提条件など
実施内容について紹介する前に、前提条件となる環境構成やGitLabバージョンについてまとめます。
環境構成
- セルフマネージド/コミュニティ版GitLab
- パブリッククラウドの仮想マシン2 (Ubuntu 22.04 LTS) 上にDocker Composeを利用してインストール
- プライベートネットワーク内に構築されており、インターネット公開されていない
- GitLabのバージョン: アップグレード前 15.11.4 → アップグレード後 18.0.2 (当時の最新バージョン)
Docker Composeの構成
docker-compose.yml
ファイルと、環境変数を記述する.env
ファイルで構成されます。
GitLabのバージョンを環境変数として.env
に括り出しており、.env
を書き換えることでバージョンアップできるようにしています。
services:
web:
image: 'gitlab/gitlab-ce:${GITLAB_VERSION}'
restart: always
hostname: '***MASKED***'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url '***MASKED***'
ports:
- '80:80'
volumes:
- '${GITLAB_HOME}/config:/etc/gitlab'
- '${GITLAB_HOME}/logs:/var/log/gitlab'
- '${GITLAB_HOME}/data:/var/opt/gitlab'
shm_size: '256m'
※ports
についての補足: GitLabへのアクセスはリバースプロキシを経由しておりリバースプロキシがTLS通信を終端するため、GitLabが受ける通信はHTTPとなります
GITLAB_VERSION=15.11.4-ce.0
GITLAB_HOME=/srv/gitlab
GitLabアップグレードに当たっての基礎知識
詳細な手順の説明の前に、GitLabのアップグレードに関して押さえておくべき以下2つの概念について説明します。
- アップグレードパス
- マイグレーション
アップグレードパス
一般に、GitLabのアップグレードは現行バージョンから目標バージョンまで一足飛びに実施することはできません。アップグレードパスと呼ばれる中継バージョンを経由する必要があります。
アップグレードパスは以下のUpgrade Path toolで調べることができます。
https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/
Currentに現行バージョン、Targetに目標バージョン (アップグレードしたいバージョン) をセットし、エディション、ディストリビューションを選択して「Go!」をクリックすると、経由するべきバージョンの一覧を示してくれます。
今回のケース (current=15.11.4&target=18.0.2&edition=ce&distro=docker
) では以下のような結果となりました。
https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/?current=15.11.4&target=18.0.2&edition=ce&distro=docker
中継バージョン:
15.11.4(current) > 15.11.13 > 16.3.9 > 16.7.10 > 16.11.10 > 17.1.8 > 17.3.7 > 17.5.5 > 17.8.7 > 17.11.4 > 18.0.2(target)
この場合、まず現行バージョンの15.11.4から15.11.13へのアップグレードを行います。成功したら、続いて16.3.9へのアップグレードを行います。…以下同様にして、目標バージョンである18.0.2までアップグレードに成功したら完了となります。
マイグレーション
マイグレーション (Background migrations) とは、GitLabのバージョン更新後に行われるデータベースの更新処理です。マイグレーションの正常終了を以て当該バージョンへのアップグレードが完了となります。
マイグレーションの処理状況はGitLabの管理者メニュー (Monitoring > Background migrations) で確認できます。
マイグレーションは幾つかのバッチ処理から構成されており、進行中の処理は「Queued」または「Finalizing」に進行状況とともに表示されます (下図)。
処理が正常終了したら「Finished」に移動し、ステータスがFinishedとなります (下図)。
「Queued」「Finalizing」に処理が残っておらず、すべての処理が「Finished」になっていればマイグレーション完了です。「Failed」となった処理がある場合は対処が必要です。
今回のようにアップグレードパスが複数バージョンに渡る場合は、途中の経由バージョンごとにマイグレーションが行われるため、必ずマイグレーションの完了を確認してから次のバージョンへのアップグレードに進みましょう。
アップグレード実施概要
今回実施したアップグレード作業フローを示します。ただし、関係者への連絡・調整や連携システムに関するタスクは省略し、GitLabに関する技術的な内容のみを記載しています。
- 事前作業
- アップグレードパスの特定
- リハーサルの実施
- 当日作業 (メイン作業)
- アップグレード前作業 (GitLabの停止とバックアップ)
- アップグレードの実施
- アップグレード後の動作確認
事前作業について、アップグレードパスの特定は既に説明しました。リハーサルについては、実際にアップグレードパスに従ってアップグレードが正常に完了することを確認します。今回はクラウド上の仮想マシンを使っていたため、仮想マシンインスタンスのイメージを取得してインスタンスの複製を作成し、複製インスタンス上で当日作業の内容をすべて実施しました。
当日作業については、次のアップグレード実施詳細で説明します。今回のケースでは、当日作業全体で3時間程度を要しました。
アップグレード実施詳細
以下、アップグレード当日に実施したメイン作業について順に説明します。
アップグレード前作業
GitLabの停止
docker-compose.yml
のあるディレクトリに移動し、コンテナを停止します。
$ docker compose down
$ docker ps ## 停止確認
※必要に応じてsudoを付けてください (以下同様)
バックアップ
環境構成等を考慮して、適切なバックアップ方法を採ります。
バックアップ方法の例:
-
$GITLAB_HOME
ディレクトリ (.env
ファイルで確認) のコピーを取得 - 仮想マシンインスタンスのイメージを取得
今回は、リストアの容易さから仮想マシンインスタンスのイメージを取得することにしました。アップグレード作業中に問題が生じてロールバックが必要になった場合は、取得したイメージを使ってインスタンスを復元します。
アップグレードの実施
先述のとおり、GitLabのアップグレードはアップグレードパスとして特定された全中継バージョンを経由する必要があります。
ここでは、最初のステップである15.11.4 → 15.11.13のアップグレードのみ記載します。以降、目標バージョンである18.0.2までのアップグレードも全く同様の方法で実行できます。
コンテナの更新
docker-compose.yml
に記述されたバージョン (イメージタグ) を書き換えます。今回は環境変数として.env
に切り出してあるため、実際に編集するのは.env
です
- GITLAB_VERSION=15.11.4-ce.0
+ GITLAB_VERSION=15.11.13-ce.0
GITLAB_HOME=/srv/gitlab
バージョンを書き換えたら、コンテナの再起動を行います。
$ docker compose down
$ docker compose up -d
コンテナの起動 (docker ps
でステータスがhealthyとなる) を待ちます。
$ docker ps
特に不備がなければ概ね数分でコンテナが起動します。
バージョンの確認
念のため、GitLabのコンソールでもバージョンアップが行われていることを確認しておきましょう。
GitLabに管理者としてログインし、以下の画面でバージョンを確認します(Overview > Dashboard)。
マイグレーション結果の確認
そのままマイグレーションの画面に移動します (Monitoring > Background migrations)。
マイグレーションが進行中の場合は、上図のように「Queued」に処理が残っています。すべての処理が「Finished」となるまで待ちます。
※マイグレーション処理はコンテナ起動後から実行されているため、画面を開いた時点で既に全部「Finished」になっている場合もあります
ホスト側のボリューム空き領域の確認
アップグレード処理自体はこれで完了ですが、構成によってはホスト側のボリュームの空き領域も確認した方がよいでしょう。というのも、GitLabのコンテナイメージのサイズは3~4GB程度あるため、アップグレードを繰り返す内にボリュームの容量不足となる可能性があるためです。そのため、必要に応じて空き容量の確認 (df -h
)、古いボリュームの削除を行いましょう。
イメージ削除の実施例:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
gitlab/gitlab-ce 17.11.4-ce.0 16a669762ef6 5 weeks ago 3.71GB
gitlab/gitlab-ce 18.0.2-ce.0 729c20e67a06 5 weeks ago 3.63GB
gitlab/gitlab-runner <none> 1d7700e174de 2 years ago 737MB
$ docker image rm 16a669762ef6 ## 17.11.4-ce.0 を削除
以上でアップグレードの1ステップが完了しました。以降はアップグレードパスに示された中継バージョンごとに、コンテナの更新~マイグレーション結果の確認 (+必要に応じてホスト側のボリューム空き領域の確認) を繰り返し、目標バージョンまでアップグレードを行います。
アップグレード後の動作確認
目標バージョンまでのアップグレードが完了したら、最後に動作確認を行います。
動作確認方法の例:
- ブラウザでGitLabに接続 (一般ユーザでログインし、幾つかのページを表示させる)
- 適当なリポジトリのクローンを実行
作業を効率化させるためのtips
- ホスト側のボリューム空き領域の確認については、空き容量が事前に予測できる場合は必ずしもバージョンアップごとに実施しなくてもよいでしょう。例えばアップグレード実施前の空き容量が25GBの場合、GitLabイメージ5個分程度の余裕があるため、「5バージョン上げるごとにイメージ5個をまとめて削除」などとすれば作業効率が上がります
- 事前作業としてコンテナイメージを予めpullしておくと作業時間の短縮になります(下の例を参照)。ただしこの場合も、ボリュームの空き領域に注意する必要があります
5個のGitLabイメージをpullするコマンド例:
$ docker pull gitlab/gitlab-ce:15.11.13-ce.0 \
&& docker pull gitlab/gitlab-ce:16.3.9-ce.0 \
&& docker pull gitlab/gitlab-ce:16.7.10-ce.0 \
&& docker pull gitlab/gitlab-ce:16.11.10-ce.0 \
&& docker pull gitlab/gitlab-ce:17.1.8-ce.0
おわりに
以上、GitLabのアップグレードの実施事例 (Docker Compose編) を紹介しました。
手順自体はさほど難しくないものの、今回のようにアップグレードを長い間怠ってしまうと、アップグレードパスが長大になり作業負荷も小さくないものになってしまいます。また、脆弱性が発覚したバージョンを利用し続けることのセキュリティリスクについては言うまでもありません。運用者は普段から速やかなアップデートを実践しましょう。
また本文中でも触れましたが、本記事ではGitLabと連携するシステムについては言及していません。実際のCI/CDは複数のシステムが連携している場合が少なくないでしょう (CodeBuild, Jenkinsなど)。実際にアップグレードの作業計画を立てる際はそれらの関連サービスへの影響も考慮する必要があります。
参考にした情報源
- Upgrading GitLab (GitLab Docs)