GitLab 9.1.2 (MySQL) を 11.4.0 (PostgreSQL) にアップグレード


弊社ではかなり前からGitLab(CE)を自社環境で運用しているのですが、ふと気付くと、バージョンがだいぶ先に行ってしまっていました。 とくに最近のバージョンでは Auto DevOps なども使えるようになっていたりするので、さすがにそろそろキャッチアップしたいと考えたわけです。

現行の環境は次の通りです:

  1. GitLab 9.1.2

  2. sameersbn/gitlab 使用

  3. MySQL 5.6

  4. Google CLoud SQL

  5. Cloud SQL Proxy Dockerを経由してGCP

  6. https://cloud.google.com/sql/docs/mysql/connect-docker

  7. Redis

  8. sameersbn/redis 使用

で、ある程度予想はしてたんですが、ただ単純にGitLabコンテナをバージョンアップしただけでは起動しなかったのです。 問題は結局次の7点ありました。

  1. PostgreSQLへ移行しなければならないパターンが発生

  2. PostgreSQLへの移行ツールの問題

  3. GitLab公式に記載された移行方法が実行できない

  4. PostgreSQL 10で起動に失敗する件

  5. GitLab 10.0でのDBマイグレーションで発生する問題

  6. DBマイグレーション実行後のGitLab起動失敗

  7. GitLab起動後にDBが初期化される

経緯を追うと長くなりそうですが、おそらくこれだけ見ると意味がわからないので、それぞれできるだけ短く記載していきます。

1. PostgreSQLへ移行しなければならないパターンが発生

GitLab 9.3 で、MySQLでのサブグループ機能が廃止されました。 https://docs.gitlab.com/ce/user/group/subgroups/index.html#database-requirements もともと対応環境として「PostgreSQL推奨/MySQLも可」とはなっていましたが、状況によってはMySQLでのDBマイグレーションが通らないようなので、あきらめてPostgreSQLへの移行を決意しました。

2. PostgreSQLへの移行ツールの問題

さてではどのようにPostgreSQLへ移行するか、ということですが、GitLab公式ドキュメントで pgloader を推奨しているようです。 https://docs.gitlab.com/ee/update/mysql_to_postgresql.html

2018-10月現在の最新版は 3.5.2 のようですが、これが Control stack exhausted とエラーが表示されて動作しませんでした。 同様のIssueがあり、3.5.1を使用することとします。 https://github.com/dimitri/pgloader/issues/810

3. GitLab公式に記載された移行方法が実行できない

さて、公式リファレンスに書かれた手順で pgloader をテスト実行してみましたが、どうやら WITH オプションのどれかが通らないようです。 リファレンスでは pgloader 3.4.1+ と書かれているので、3.4.1 では動くのかもしれません。 試行錯誤の結果、 WITH オプションは WITH preserve index names だけがあればとりあえず問題が無いようです。 (この点は保証がありません)

4. PostgreSQL 10で起動に失敗するパターンがある件

移行後のDBとしてPostgreSQLを用意し、GitLabと仮接続して確認してみたところ、 いくつかの操作でGitLab内のエラーが発生しました。 念のため確認してみたところ、PostgreSQL 10は対応環境外とされているようですね。 https://gitlab.com/gitlab-org/gitlab-ce/issues/42047 ということで、 PostgreSQLは9.6を使用することとしました。

5. GitLab 10.0でのDBマイグレーションで発生する問題

GitLab 9.1.2のデータをMySQLからPostgreSQLに入れ替え、GitLab 11.4.0でDBマイグレーションを実行してみたところ、失敗し中断しました。 エラーメッセージを追ってみたところ、9.x から 10.0 の間のDBマイグレーションに問題があるようです。 https://gitlab.com/gitlab-org/gitlab-ce/issues/38283

PostgreSQLにデータを移行しなおしてから、events テーブルのINDEXを見ると、確かにプライマリキーのINDEX名が idx_xxxxx_primary のようになっているので、PostgreSQL上で ALTER INDEX '(eventテーブルのプライマリキーのINDEX名)' RENAME TO 'events_pkey'; と実行すると、DBマイグレーションが通るようになりました。

6. DBマイグレーション実行後のGitLab起動失敗

sameersbn/gitlab のドキュメントにあるように、GitLabコンテナを稼働させる前に、rake:migrate を実行してDBマイグレーションを実行したところ、GitLabコンテナが起動中しなくなりました。 条件・原因がいまいちパっとわからない状況ではあったのですが、 sameersbn/gitlab の起動時の挙動を追うと、起動時に自動的にDBマイグレーションも走るようだったので、事前に実行せず、起動時処理に任せることにしました。

7. GitLab起動後にDBが初期化される

GitLabコンテナを起動したところ、「管理者パスワードの変更画面」が表示されました。 これはGitLabをクリーンインストールした場合の状態のはずですので、PostgreSQLのデータを確認してみると、やはりデータが初期化されています。

ソースを追ってみたところ、GitLab起動時に毎回、「(PostgreSQLの場合)public スキーマ内のテーブルの数をカウントし0である場合はクリーンインストール」する挙動となっていることがわかりました。

ということはつまり、 pgloader でのデータ移行時に、テーブルが public スキーマ以外に作成されているということになります。 改めてPostgreSQLを初期状態に戻し、 pgloader でデータ移行しなおしてからPostgreSQL内を見てみると、データベース名と同じスキーマ名になっています。

ということでどうやら、pgloaderのデフォルト挙動では、データベース名と同名のスキーマを新規追加するようです。 この状況を防ぐためには、 pgloader のオプションとして ALTER schema '(データベース名)' rename to 'public' が必須となります。 https://github.com/dimitri/pgloader/issues/645

ということで、手順ベースでまとめると:

  1. MySQLからPostgreSQLへ、pgloaderでデータ移行

  2. events テーブルのINDEX名を手動で変更

  3. 11.4.0のGitLabコンテナを起動

ずいぶんシンプルになってしまいますね…。

なお、実際にアップグレードを実行する際には、いくつか注意が必要です。

既存GitLabのディレクトリ(gitレポジトリなどが配置されている)はまるごと全てバックアップしておく必要があります。 (マイグレーションの一環として、このディレクトリの構造が変化してしまうため) こういうとき、GCPなどスナップショットが保存できる環境だと楽ですね。

当然ながら、既存DBのバックアップは、絶対にx3必須です。

実際にPostgreSQLにデータを入れる際は、安全のため次のような手順で実施しています。

  1. ローカルにDockerコンテナ環境を構築

  2. 本番環境からMySQLのダンプを取得

  3. コンテナ間でデータ移行

  4. PostgreSQLコンテナで完全に確認できたらダンプを取得

  5. 本番環境のPostgreSQLにインポート

弊社ではGitLabのようなツール・ミドルウェアなどの導入設置・運用なども承っております。 今回のように、なかなか手間のかかるものなど、お気軽にお問い合わせください。

最新記事

すべて表示

SQLite(sqlite3)で “no such table”

小ネタです。 SQLiteを使っていて "no such table" とエラーが出た場合、 DBファイル名の指定が空になっている、という凡ミスを起こしていないかを確認してみましょう。 ・・・ そういう凡ミスをしてしばし悩んだので… ファイル名の指定が空になっている場合、一時的なインメモリDBとして保存されます(※1)。 つまりDB接続を切断すると中身は消えます。 なので接続

アプリケーションサーバにポートを指定せずに起動すると?

最近、 Goで書かれたアプリケーションサーバが起動しない! ->原因: .env ファイルが欠けていた というドタバタがありました。 結局Goと関係ないですが、この時、 「あまりGoに慣れてないのでGoの問題かと…」「DockerまだよくわかってなくてDockerの問題かと…」 というような声があったのて、あえてGoで検証してみようと思ったわけです。 さて、Goでサーバサイドのシステムを作

Go のフレームワーク echo でCSRFミドルウェアを使う(3)CSRFトークンの送出にFormを指定する

「Go のフレームワーク echo でCSRFミドルウェアを使う」シリーズ第3弾です。 今回はソースを追いません。オマケ的な回です。 リファレンスのサンプルではHTTPヘッダで送出するパターンを想定していますが、リファレンス下部に header / form / query が使える旨の解説があります。 https://echo.labstack.com/middleware/csrf#conf