Docker Run GitLab-EE on VirtualBox

## はじめに

![GitLabSignin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51783/2e62ab57-3643-d23f-7724-6a3b9e352952.png)

GitLabやPlantUML Serverをパソコンで起動するためのWindows、Linux（Ubuntu）、VirtualBox、Dockerの環境構築について、試行錯誤した結果を記録しておく。でも本当は、普通にGitHubを使いたい、Dockerやるならクラウドサービスを使いたい、と書いておく。

### 環境選定

目的と経緯は次のとおりである。

1. 最終ゴールは「オンプレミスにGitLabを起動して、GitHubの代替サービスとして利用する」ことである。
1. GitLabを実行するには、Linux環境にさまざまなアプリケーション（Nginx、PostgreSQL、Redis、Ruby…）のセットアップが必要になる。この作業をすれば貴重な勉強ができるが、便利なツールがあれば積極的に使いたい。
1. 上記の理由から、Dockerを利用してGitLabイメージ（GitLabのDockerイメージ）を起動することで、実現までのプロセスを大幅に簡略化する。

ソフトウェアの課題解決には、ほとんどの場合に複数のアプローチが存在する。LinuxとDockerの組み合わせやGitLabの起動方法についても、先達の経験と知識を踏襲していく。

1. Linux環境を使う場合

    実行環境はホストOSだけなので、Dockerのインストールから作業を開始できる。スキルや環境の面でLinuxが使えるなら、もっとも簡単な方法である。実際にLinuxMintを使って環境構築したところ、スムーズにGitLabを起動できた。

1. WindowsでWSLによるLinux環境を使う場合

    Linux環境はWSL（Windows Subsystem for Linux）で構築して、GitLabイメージをDocker for Windowsで起動する。DockerはWSL環境で実行するが、リソース管理はWindows環境に依存するため、どうしてもオーバーヘッドが発生してしまう。また、Dockerアプリケーションもフロントエンドツールの域を出ず、使いやすいとは言えない。実際にUbuntuをサブシステムとして環境構築したところ、メモリ不足でDockerイメージの展開に失敗するなどの問題が発生したため、Windowsのプロセスを制限することでGitLabを起動できたが、動作はかなり重かった。

    別のアプローチとして、アップグレードしたWSL2のメモリ設定を変更する方法や、WSL2にDockerを直接インストールする方法もあるようだが、オーバーヘッドの問題はあまり変わらないのかもしれない。（参考：[Zenn「WSL2 + Docker をメモリを節約しながら使えるか」](https://zenn.dev/takajun/articles/4f15d115548899)）

1. WindowsでVirtualBoxによるLinux環境を使う場合

    VirtualBoxの仮想マシンにLinux環境を構築すれば、以後はLinux環境を使う場合と同じ手順でGitLabを起動できる。VirtualBoxアプリケーションは、仮想マシンの作成や環境設定が明瞭で使いやすい。実際にUbuntu ServerをゲストOSとして環境構築したところ、CPU1コア+メモリ4GBのリソース設定にもかかわらず、WSLの場合より動作が軽く、スムーズにGitLabを起動できた。**この手順を以下に記す。**

    VirtualBox以外にも仮想化アプリケーションの選択肢はあるが、ライセンスと性能から今回のソリューションはVirtualBoxの一択となった。（参考：[ITIGIC「VirtualBox vs VMware vs Hyper-V：違いと最良のプログラム」](https://itigic.com/ja/virtualbox-vs-vmware-vs-hyper-v-differences-best-program/)）

### 使用機材

* ハードウェア

  * Intel Pentium 1.60GHz（1Socket, 2Core, 4Logical）
  * Cache L1:128KB L2:512KB L3:2MB, Memory 8GB, SSD

* ソフトウェア

  * Microsoft Windows 10 Home（ホストOS）
  * Oracle VM VirtualBox 6.1（Windows版、拡張機能なし）
  * Ubuntu Server 20.04 LTS（ゲストOS）
  * Docker 20.10.7（Linux版）
  * GitLab Enterprise Edition 14.1.2-ee（Dockerイメージ、無料機能のみ）
  * PlantUML Server 20210601-0946 / version 1202107（Dockerイメージ）

## 仮想マシンのセットアップ

WindowsにVirtualBoxをインストールして、Ubuntu Serverの仮想マシンを作ってから、必要なセットアップをする。

### VirtualBoxのインストール

1. VirtualBoxのダウンロードページから最新版のVirtualBoxインストーラをダウンロードする。（参考：[ORACLE VirtualBox「Download VirtualBox」](https://www.virtualbox.org/wiki/Downloads)）
1. VirtualBoxインストーラを実行する。設定はデフォルトのままでよい。

### 仮想マシンの作成

1. VirtualBoxを起動して、メニュー「仮想マシン」→「新規」から「仮想マシンの作成」ダイアログを表示する。
1. 「名前とオペレーティングシステム」では、仮想マシンの名前とゲストOSの種類を設定する。今回は「Ubuntu Server」「Linux」「Ubuntu（64-bit）」とする。
1. 「メモリーサイズ」では、仮想マシンのメモリーサイズを決定する。今回は「4096MB」とする。
1. 「ファイルサイズ」では、仮想ハードディスクのファイルサイズを決定する。今回は「20GB」とする。
1. ボタン「作成」により、ホストOSに仮想マシンのイメージファイルが作成される。

![仮想マシン設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51783/d0221801-e65b-b5db-34e9-1096d4a609a4.png)

### Ubuntu Serverのインストール

1. Ubuntuのダウンロードページから、最新版のUbuntu Serverディスクイメージをダウンロードする。（参考：[CANONICAL Ubuntu Japan Team「Ubuntuを入手する」](https://jp.ubuntu.com/download)）
1. VirtualBoxで作成した仮想マシンを選択して、メニュー「仮想マシン」→「起動」→「通常起動」により、仮想マシンを電源オン状態にする。
1. ロゴ画面の後、起動ディスクイメージを選択するダイアログが表示されるので、ボタン「キャンセル」でそのまま起動させる。ブートメディアがないので仮想マシンが停止するが、問題はない。
1. 仮想マシンウィンドウのメニュー「デバイス」→「光学ドライブ」→「ディスクファイルを選択」でUbuntu Serverディスクイメージを選択して、仮想マシンウィンドウのメニュー「仮想マシン」→「リセット」を実行する。
1. Ubuntu Serverの起動後、インストールシーケンスが開始する。最初にいくつか設定があるので注意して入力する。
    1. 【ロケール】「Japanese」は存在しないので、素直に「**English**」を選択する。
    1. 【キーボードレイアウト】Ubuntu Desktopのように自動認識してくれないので「**Japanese**」を選択する。
    1. 【ネットワーク】デフォルト設定でよい。
    1. 【プロキシ】デフォルト設定でよい。
    1. 【アーカイブミラー】デフォルト設定でよい。
    1. 【パーティション】すべてデフォルト設定でよい。
    1. 【プロファイル】PC名とアカウントを設定する。パスワードはsudoコマンドで使用する。
    1. 【OpenSSH】チェックしてインストールする。ポート22はここで使用する。
    1. 【追加アプリケーション】後でインストールするので、ここでは選択しない。
1. 仮想マシン画面上部が「**Installing system**」から「**Install complete !**」に変わるまでしばらく待つ。「*downloading and installing security updates*」のクルクルが終わるまで待つと安心感が増す。
1. 仮想マシンウィンドウのメニュー「デバイス」→「光学ドライブ」→「仮想ドライブからディスクを除去」により、強制マウント解除をする。
1. 仮想マシン画面下部の「**Reboot Now**」により、仮想マシンをリブートさせる。
1. 仮想マシン上でUbuntu Serverが起動するので、ログインプロンプトが出るのを待つ。尚、最初のプロンプトを表示して数秒間、起動プロセスの名残が出力されるので驚かない。
1. 【プロファイル】で設定したアカウントを使ってログインする。

### Ubuntu Serverのカスタマイズ

ホストOSとゲストOSを連携させるために、VirtualBoxが用意した追加パッケージをインストールする必要がある。（参考：[Linuxize「How to Install VirtualBox Guest Additions on Ubuntu 18.04」](https://linuxize.com/post/how-to-install-virtualbox-guest-additions-in-ubuntu/)）

1. `sudo apt update && sudo apt upgrade`を実行して、Ubuntu Serverを最新の状態にする。
1. `sudo apt install build-essential dkms linux-headers-$(uname -r)`を実行して、カーネルのコンパイルに必要なツールをインストールする。
1. 仮想マシンウィンドウのメニュー「デバイス」→「Guest Additions CDイメージの挿入…」で、VirtualBoxが用意した追加パッケージのディスクイメージを光学ドライブにセットする。
1. `sudo mkdir -p /mnt/cdrom`でマウント先フォルダを作成して、`sudo mount /dev/cdrom /mnt/cdrom`でマウントする。
1. `cd /mnt/cdrom`でマウント先フォルダに移動して、`sudo sh ./VBoxLinuxAdditions.run --nox11`でインストーラを実行する。
1. 仮想マシンウィンドウのメニュー「デバイス」→「光学ドライブ」→「仮想ドライブからディスクを除去」により、強制マウント解除をする。
1. `sudo shutdown -r now`により、Ubuntu Serverを再起動する。
1. 再起動したら`lsmod | grep vboxguest`で「vboxguest」モジュールが追加されていることを確認する。

```text
daisukeh@ubuntu-server:~$ cd /mnt/cdrom
daisukeh@ubuntu-server:/mnt/cdrom$ ls
AUTORUN.INF  OS2                      VBoxDarwinAdditionsUninstall.tool  VBoxWindowsAdditions.exe
autorun.sh   runasroot.sh             VBoxLinuxAdditions.run             VBoxWindowsAdditions-x86.exe
cert         TRANS.TBL                VBoxSolarisAdditions.pkg
NT3x         VBoxDarwinAdditions.pkg  VBoxWindowsAdditions-amd64.exe
daisukeh@ubuntu-server:/mnt/cdrom$ sudo sh ./VBoxLinuxAdditions.run --nox11
Verifying archive integrity... All good.
Uncompressing VirtualBox 6.1.26 Guest Additions for Linux........
VirtualBox Guest Additions installer
Copying additional installer modules ...
Installing additional modules ...
VirtualBox Guest Additions: Starting.
VirtualBox Guest Additions: Building the VirtualBox Guest Additions kernel
modules.  This may take a while.
VirtualBox Guest Additions: To build modules for other installed kernels, run
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup <version>
VirtualBox Guest Additions: or
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup all
VirtualBox Guest Additions: Building the modules for kernel 5.4.0-81-generic.
update-initramfs: Generating /boot/initrd.img-5.4.0-81-generic
VirtualBox Guest Additions: Running kernel modules will not be replaced until
the system is restarted
daisukeh@ubuntu-server:~$ sudo shutdown -r now

(再起動)

daisukeh@ubuntu-server:~$ lsmod | grep vboxguest
vboxguest             348160  1
daisukeh@ubuntu-server:~$
```

### ポートフォワーディングの設定

ホストOSからGitLabとPlantUML ServerのDockerコンテナにアクセスするには、Docker起動時の「Dockerコンテナ - ゲストOS」間のポートフォワーディングと、VirtualBox側の「ゲストOS - ホストOS」間のポートフォワーディングが必要になる。Docker起動時の設定はそれぞれ説明するとして、VirtualBox側でGitLabとPlantUML Serverのすべてのサービスにアクセスする場合の設定例を示す。（ゲストOSのSSHとGitLabのDockerコンテナのSSHで、ポート22が重複していることに注意）

1. 仮想マシンをシャットダウンする。
1. メニュー「仮想マシン」→「設定」で開くダイアログの、「ネットワーク」→「高度」→「ポートフォワーディング」にルールを追加する。
1. Windowsファイアーウォールの警告が出るので、アプリケーションのアクセスを許可する。

![ポートフォワーディング設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51783/17d96777-8bdb-2b74-9e9f-3a697cf2b9a1.jpeg)

### 共有フォルダの設定

ホストOSーゲストOS間の共有フォルダを作成するには、仮想マシンウィンドウのメニュー「仮想マシン」→「設定」で開くダイアログの、「共有フォルダー」の「共有フォルダーの追加」に設定する。（参考：[日々のいろいろ「VirtualBoxで共有フォルダーをマウントする方法」](https://legendimposter.hatenablog.jp/entry/2020/08/26/170022)）

1. 「共有フォルダーの追加」が完了したら、仮想マシンを起動する。
1. ゲストOS側の共有フォルダは *vboxsf* グループの *root* ユーザー所有になるため、`sudo gpasswd -a ユーザー名 vboxsf`によりアクセスするユーザーをグループに追加する。
1. `sudo mount -t vboxsf share /media/sf_share`により、共有フォルダをゲストOSにマウントする。 *share* は「共有フォルダーの追加」で指定した「フォルダー名」を指す。また、ルールを追加するとゲストOSに */media/sf_share* フォルダが自動で作成される。（*temp* なら */media/sf_temp* となる。）

![共有フォルダ設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51783/8268f48a-77af-e2e2-f792-dbcf5e37f09a.jpeg)

## アプリケーションのセットアップ

アプリケーションのインストールは難しくない。一点、GitLabのroot設定だけは注意が必要である。

### Dockerのインストール

インストールは`sudo apt install docker docker.io`で完了する。Docker Composeは扱わない。

### GitLabの起動

起動するDockerイメージがプールされていなければ、Dockerは自動的に最新版をロード（＝`docker pull`）してくれる。また、起動にはDockerコンテナのパラメータを指定する必要があるので、スクリプト化しておくと便利である。スクリプト例ではGitLabコンテナが提供するSSH（ポート22）は使用せず、HTTPS（ポート443）はいずれ使用する予定である。マッピング先フォルダ（*/srv/gitlab/config* など）がない場合、Dockerが自動作成してくれる。

```bash:gitlab.run
sudo docker run \
    --detach \
    --hostname localhost \
    --publish 80:80 \
    --publish 443:443 \
    --name gitlab \
    --restart always \
    --volume /srv/gitlab/config:/etc/gitlab \
    --volume /srv/gitlab/logs:/var/log/gitlab \
    --volume /srv/gitlab/data:/var/opt/gitlab \
    gitlab/gitlab-ee
sudo docker ps -a
```

* GitLabの初回ロードは1GB超あるので、Dockerイメージの展開に時間がかかる。また、条件によっては起動に10分程度かかることがあるので、`watch -n 3 "sudo docker logs gitlab | tail -n 5"`で観察するのもいい。
* GitLabコンテナの起動確認は、*http://localhost/* をアクセスすることで確認できる。

### root@GitLabのパスワード変更

起動したGitLabにアクセスするとサインイン画面が表示される。ユーザーは **Register now** リンクからアカウント登録ができるが、通常はrootユーザーによる承認が必要になる。そのrootユーザーのパスワードがわからずネットを調べると、公式ブログなどを含めいくつか候補があるのだが、どれも有効ではなかった。また、あるサイトでは初期起動時にrootユーザーのパスワード設定画面が表示されるとあるが、Dockerで起動したGitLabでは確認できなかった。これでは使えないので、rootユーザーのパスワードを直接変更する方法で対応する。（参考：[Qiita @crnls1985「GitLabのrootパスワード変更方法」](https://qiita.com/crnls1985/items/4fb42d803b0685eff092)）

1. `sudo docker exec -it gitlab /bin/sh`により、GitLabのDockerコンテナのシェルを起動する。これによりDockerコンテナを直接操作できるようになる。
1. `gitlab-rails console -e production`でGitLabを実行しているRailsサーバーの中に入る。プロンプトが出てくるまでしばらく時間がかかる。
1. `user = User.find(1)`でrootユーザーのオブジェクトを取得する。
1. `user.password = 'パスワード'`および`user.password_confirmation='パスワード'`でパスワードを設定する。
1. `user.save!`で設定を保存する。
1. `exit`してgitlab-railsとDockerコンテナから抜け出す。

```text
daisukeh@ubuntu-server:~$ sudo docker exec -it gitlab /bin/sh
# gitlab-rails console -e production
--------------------------------------------------------------------------------
 Ruby:         ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux]
 GitLab:       14.1.3-ee (77e6fa75d55) EE
 GitLab Shell: 13.19.1
 PostgreSQL:   12.6
--------------------------------------------------------------------------------
Loading production environment (Rails 6.1.3.2)
irb(main):001:0> user = User.find(1)
=> #<User id:1 @root>
irb(main):002:0> user.password = 'password'
=> "password"
irb(main):003:0> user.password_confirmation = 'password'
=> "password"
irb(main):004:0> user.save!
Enqueued ActionMailer::MailDeliveryJob (Job ID: 56bdf4d5-867b-4709-8520-147e0c14cd1a) to Sidekiq(mailers) with arguments:
"DeviseMailer", "password_change", "deliver_now", {:args=>[#<GlobalID:0x00007f6ccced78b8 @uri=#<URI::GID gid://gitlab/User/1>>]}
=> true
irb(main):005:0> exit
# exit
daisukeh@ubuntu-server:~$
```

ブラウザに戻りrootユーザーでサインインすると、サンプルプロジェクト（＝リポジトリ）が表示されて、利用可能な状態になる。

![GitLabProjects.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51783/48bf1204-c1f5-8420-cd59-126cbbd60c6d.png)

### GitLabの停止

`sudo docker rm -f gitlab`により停止する。`sudo docker ps -a`で起動中のDockerコンテナを確認できる。

### PlantUML Serverの起動

GitLabと同様だが、PlantUMLのDockerコンテナはHTTPにポート8080を使っている点に注意する。

```bash:plantuml-server.run
sudo docker run \
    --detach \
    --publish 8080:8080 \
    --name plantuml-server \
    --restart always \
    plantuml/plantuml-server
sudo docker ps -a
```

### PlantUML Serverの停止

`sudo docker rm -f plantuml-server`により停止する。`sudo docker ps -a`で起動中のDockerコンテナを確認できる。

## おわりに

* テスト環境が貧弱にもかかわらず、Dockerが起動したのは感動だった。
* VirtualBoxは設定したメモリ容量をキッチリ使う律儀なヤツだった。
* Docker Composeを使った方が便利なのだが、まずは基本を押さえたい。
* GitLabが想定外に高機能なので、使いこなすまで時間がかかりそう。
* GitLabのメール通知やCI/CD機能などの設定も今後確認していきたい。

以上