GitLabの実践的な運用 #gitlabjp

（当日はesaのプレゼンテーションモードで発表しました）

（文字起こししてもらえました [ちゃんと復旧できる、GitLabのバックアップ運用方法 – GitLab meetup \#01レポート \- pixiv inside](http://inside.pixiv.blog/catatsuy/805)）

## 自己紹介

  * 各種SNSをcatatsuyでやっている
    * かたついと呼ばれることが多い
  * 会社のアドベントカレンダーで GitLabの運用方法をドーンと公開！！ - pixiv inside http://inside.pixiv.net/entry/2016/12/17/100000 を書きました
  * ピクシブ株式会社で開発基盤チームと広告チームの兼任
    * pixivの改善が主な業務
  * 単著『pixivエンジニアが教えるプログラミング入門（星海社新書）
    * ピクシブ社内の非エンジニア向けのプログラミング研修の書籍化
  * pixiv社内ISUCONやISUCON6本選の問題作成

## GitLabとは

  * プライベートなgitリポジトリの管理画面やレビュー画面などを提供するWebアプリケーション
  * GitHubやBitbucketに近いことを自社のサーバー上で行える
  * オープンソースなので自社のサーバーにインストールして動かすことが出来る
    * ソースコードも読むことが出来る
  * ソースコードはRuby on Railsで使用ミドルウェアはデータベース（PostgreSQLかMySQL）・Redis
    * インストール手順は詳細なドキュメントがある
    * https://github.com/gitlabhq/gitlabhq/tree/master/doc/install
    * Dockerイメージなど現在では複数のインストール方法がある
    * 今回はローカルにインストールする前提で説明します

## セットアップするサーバーについて

  * グローバルIPを持つサーバー上に立てることが前提
    * gitリポジトリをssh経由でcloneできるようにするために必要
    * sshはport forwardingして、httpもproxyすればGitLabを動かすサーバー自体にグローバルIPが必要ない構成にすることもできる
      * プライベートネットワーク内でしかsshを使わないのであれば、port forwardingは必要ない
    * オープンソースで設定を全て自前で管理できるので、各社のサーバー構成に合わせて柔軟な対応ができる
  * サーバーは1台であることが前提
    * gitリポジトリがアプリケーションサーバーと同じサーバーにある必要があるので複数台構成は現実的ではない
    * MySQL・PostgreSQLとRedisは設定でIPアドレスを渡せるので、別サーバーに立ててもよい
    * RailsのアプリケーションはCPUとメモリーを喰いやすいので強めのサーバーで動かした方が良い

## 最近話題になったGitLab.comのバックアップ体制

* 今回詳しく話しません
* 問題になったのはGitLab.comというサービスで、GitLabのソースコードやバックアップの仕組みに問題があるわけではない
* 基本的にはGitLab自体にbackupの仕組みがあるので、その仕組みを使えば問題ない

## GitLabが持っているデータ

* データベース
* gitリポジトリ
* uploadされたファイル
  * などなど他にもいくつかあります
* ちなみにRedisにはキャッシュとセッションとresqueのキューが入っているだけなので、最悪吹っ飛んでも問題なし
  * 社内ツールなのでログインし直せばセッションは再生成される
  * resqueのキューはGitLabを停止すればすぐにはける
  * Redisのデータをバックアップする仕組みは特に用意されてないし、する必要はない

## GitLabのデータベース

* GitLabはPostgreSQLを推奨、公式ドキュメントでも明記
  * そもそもRailsは事実上PostgreSQL推奨
  * MySQLも一応使えるが、非推奨であることが明記
* GitLabのブログでもPostgreSQLの話しかしていない
* 公式ドキュメントにMySQLからPostgreSQLに移行する手順も書かれている
  * 逆はない

## RailsとMySQL

* RailsとMySQLの相性問題は『Rails MySQL kamipo』で検索
  * MySQLを使う場合の注意点などは公式ドキュメントにも書かれている
    * [gitlabhq/doc/install at master · gitlabhq/gitlabhq](https://github.com/gitlabhq/gitlabhq/tree/master/doc/install)
    * MySQLでRailsのプロダクトを動かしたことがあれば、常識（だと思う）
    * utf8_mb4を使わないと絵文字などBMP外の文字（UTF-8で4バイトになる文字）は保存できない
    * MySQL 5.7.7より前の場合、デフォルトの設定ではRailsのマイグレーションを管理するテーブル`schema_migrations`のテーブルが作れない（インデックスサイズの問題）
      * my.cnfで設定を変えて、かつ必要なテーブルをBarracudaに変更すれば5.5以降でも問題無い
    * インストールの容易さを考えるとデフォルトをutf8_mb4にするのはGitLabとしては難しそう
      * デフォルトの設定はぶれてる
      * インストールの容易さを取るか、絵文字なども保存できる方を取るか、のトレードオフでオープンソースプロダクトとして選択が難しい
* RailsのMySQL周りのデフォルト設定は問題があるので、RailsでMySQLを使う知識が無いなら使ってはいけない
  * デフォルトの照合順序`utf8_unicode_ci`を使うと『ハハパパ問題』が起こる
     * GitLabは`utf8_general_ci`になっているので『ハハパパ問題』は起こらない
  * 社内にMySQLの知見があり、かつMySQLでRailsのプロダクトを動かす知見があるなら多分問題ない
  * ピクシブでは現在稼働中のRailsのサービスでMySQLを使用しているので、社内のGitLabにもMySQLを採用
    * 今回はMySQLで使う前提で話をします

## GitLabのバックアップ

* bundle exec rake gitlab:backup:create
  * MySQLの場合はmysqldump、PostgreSQLはpg_dump
  * gitの場合はgit bundle createでbundleファイルを作る
  * 基本的にGitLabのバックアップはコマンドを実行するだけなのでソースコードを読んだ方がよい
* バックアップファイルは1つのtarファイルにまとめられる
  * `config/gitlab.yml`の`backup:`以下の`upload:`以下に設定を書くと、s3など様々なストレージやサーバーへバックアップファイルを送ることができる
  * ファイルをバックアップサーバーにrsyncとかで送るだけでもよい
  * 定期実行はcronの設定をすればいい
  * 環境変数`CRON=1`を渡すとエラーが発生してない場合の標準出力・エラー出力を抑制してメールが来ないようにしてくれる

## MySQLのバックアップについて

* MySQLのバックアップはmysqldump以外にも色々ある
  * 停止してdata_dirをコピー（社内で利用）
     * slaveを用意すればmasterを停止する必要はない
  * InnoDB Hot Backup（有償）
  * Percona XtraBackup etc
* mysqldumpはデータサイズが大きいと時間がかなりかかる
  * ある程度大きくなったらデータベースだけは別の方法でバックアップするべき
  * 環境変数`SKIP=db`を渡せばskipできる

## リストア

  * バックアップファイルは1つのtarファイルにまとめられる
    * ファイル名にタイムスタンプと日付が入っている
    * 環境変数BACKUPにタイムスタンプと日付を渡して bundle exec rake gitlab:backup:restore
  * dbのバックアップを別にしている場合は環境変数SKIP=dbを渡す

## バージョンアップ

  * バージョンアップ時にバックアップを取るようにドキュメントに記述されている
    * バージョンアップ時にmigrationする必要があるのでDBのバックアップは必須
    * DB以外は基本的にいじらないので、DB以外のバックアップは無理して取らなくても良い
      * バージョンにより異なる可能性がある
      * GitLabはほぼすべてのバージョン間のバージョンアップ手順が公開されているので必ず確認
        * https://github.com/gitlabhq/gitlabhq/tree/master/doc/update
        * 手順通り行えば基本的に問題無い
      * とはいえディスク障害など、何が起こるか分からないのでバックアップをした方が良いのは当然
  * ある程度一気にバージョンを上げることもできる
    * 全てのドキュメントを確認して一部のイレギュラーな手順を忘れないこと

## バージョンアップ時に停止する必要はあるか

  * db:migrationがあるので無停止で行うのはほぼ無理
    * slaveでdb:migrationを行ってmaster昇格をする手もなくはないが、手間がかかる
  * ドキュメントのインストール方法ではシンボリックリンクを作らない
    * bundle installやassets:precompileなどでディレクトリ下のファイルを直接書き換える
      * アプリケーション起動中に行えない
    * Capistranoのデプロイでは別ディレクトリで上の作業を行ってから、シンボリックリンク先を切り替えて、サーバーをreloadする
    * 別ディレクトリで作業を行って、シンボリックリンクを切り替えるだけにすると、停止時間を短くできるはず
    * GitLabのドキュメントから外れた構成になるので、共有や引き継ぎが大変になりそう
  * ドキュメント通りにやるとある程度のダウンタイムは必ず発生するし、短くするのにも限界があるのでダウンタイムを許容して運用するしか現状はない

## 最後に

  * GitLabはドキュメントが多く、セットアップ・バージョンアップ・バックアップなどの手順のドキュメントも充実している
  * ソースコードもシンプルなので動きを追うことは比較的容易
  * 今回のスライドもドキュメントとソースコードを追うだけで作りました
  * 貧者のGHEと呼ばれた時代もありましたが、ソースコードが読める、柔軟なインフラ構成が取れる、など他にはないメリットがあります
  * GitLabを盛り上げていきましょう！