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

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

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