COS(コンテナ最適化OS)でDockerの利用できるディスク容量を増やす

## はじめに

GCPだと`create-with-container`を使う事でCOS(Container-Optimized OS)を利用したコンテナ用のインスタンスを作る事ができます。
イメージ名とかも指定できるので、小規模なコンテナ運用ならGKEでやるより簡単かと思います。

ただデフォルトのdiskサイズが10GBなので大きめのDocker Imageをビルドすると下記のように容量不足のエラーが出ます。

```bash
Error processing tar file(exit status 1): write .... : no space left on device
```

なので、今回はビルドの容量を確保するためにCOSに永続化ディスクを追加したのでそのやり方のメモになります。

## 戦略

- boot diskのサイズ変更ではなく新規ディスクの追加
- `/var/lib/docker`の上書きではなく`daemon.js`でイメージの置き場所を変える

まずboot diskのサイズ変更では無く新規ディスクの追加をしているのは、その方が後からDocker領域だけ容量変更がしやすいのとインスタンスを作り直してもイメージ領域を使いまわせるからです。
特に、実験的にパラメータを変更してインスタンスを作り直すのを頻繁にやってるのでboot diskとは分けておく方が便利そうです。

また、/var/lib/dockerに上書きマウントしても良いのですが、予期せぬ問題が起こっても嫌なので設定ファイルを真っ当に変更します。

## 永続化ディスクの作成とマウント

まずは永続化ディスクを作ります。

```bash
$ gcloud compute disks create disk4docker \
     --size 20 --type pd-standard --zone asia-northeast1-b
```

続いてマシンにアタッチします。

```bash
$ gcloud compute instances attach-disk instance001 \
     --disk disk4docker --zone asia-northeast1-b
```

SSHでサーバに入って`lsblk`コマンドでアタッチされたディスクを確認します。sdbとかsdcとかが追加されているはずです。

```bash
$ sudo lsblk
```

最後にフォーマットしてマウントします。

```bash
$ sudo mkfs.ext4 -m 0 -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/sdb
$ sudo mkdir -p /mnt/disks/docker_data
$ sudo mount -o discard,defaults /dev/sdb /mnt/disks/docker_data
$ df /mnt/disks/docker_data
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/sdb        20511312 45080  20449848   1% /mnt/disks/docker_data
```

これで追加したディスクがOS上からアクセスできるようになりました。

## Dockerイメージの置き場所を変更する

Dockerイメージの置き場所は通常は`/var/lib/docker`ですがこちらを`/mnt/disks/docker_data`に変更します。

`daemon.json`がDockerの設定ファイルになるのでこちらに`data-root`を追加します。

```/etc/docker/daemon.json
{
        ...
        "data-root": "/mnt/disks/docker_data"
}
```

設定を反映させるためにDokcerデーモンを再起動します。

```bash
$ sudo systemctl restart docker
$ ls -l /mnt/disks/docker_data
```

`/mnt/disks/docker_data`に`overlay2`や`volumes`などが追加されていれば成功です。

## 起動スクリプトに設定を反映する

COSでは/etcの設定は再起動時に毎回初期化されます。なので、起動スクリプトに修正を入れて起動時マウントなどをしなおします。

まず、起動スクリプトは以下のように書きます。

```config.sh
#!/bin/bash

mount -o discard,defaults /dev/sdb /mnt/disks/docker_data
cat <<EOF > /etc/docker/daemon.json
{
    "data-root": "/mnt/disks/docker_data",
    "live-restore": true,
    "storage-driver": "overlay2",
    "mtu": 1460
}
EOF
systemctl restart docker
```

続いて起動スクリプトを追加して、インスタンスを再起動します。

```bash
$ gcloud compute instances add-metadata instance001 \
    --metadata-from-file startup-script=config.sh  \
    --zone=asia-northeast1-b 
$ gcloud compute instances stop instance001 --zone asia-northeast1-b 
$ gcloud compute instances start instance001 --zone asia-northeast1-b 
$ df -h /mnt/disks/docker_data/
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdc         20G  650M   19G   4% /mnt/disks/docker_data
```

これで無事Dockerのビルド時に利用するディスクサイズを増やせました

## Diskをリサイズしてみる

せっかくなのでディスクのリサイズも試してみます。

まずgcloudコマンドでディスクサイズを増やします。なお減らすことは出来ないのでコストを考えると小刻みに増やす方が良いかもしれないです。

```bash
$ gcloud compute disks resize disk-theia-docker --size 100 --zone=asia-northeast1-b 
```

これだけではOSから見える領域としては増えていないのでサーバにログインしてファイルシステムサイズを変更します。

```bash
$ sudo resize2fs /dev/sdb
$ df -h /mnt/disks/docker_data/
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb         99G  6.4G   92G   7% /mnt/disks/docker_data
```

## まとめ

さて、COS上でディスク容量を増やす方法を試してみました。
ただ、コンテナのボリュームにディスクを追加する場合はもう少しシンプルに出来ますし、あまりする必要がない作業な気がします。これ。
この作業が必要なのはCOS上で`docker build`をガッツリやるときだけです。それであればローカルビルドは捨ててcloud-buildを使ってしまうと言うのも手かなと思うので、その辺のもう少しクラウドネイティブな方法を考えていきたいです。

それではHappy Hacking!

## 参考

- [ゾーン永続ディスクの追加またはサイズ変更](https://cloud.google.com/compute/docs/disks/add-persistent-disk?hl=ja)
- [起動スクリプトの実行](https://cloud.google.com/compute/docs/startupscript?hl=ja#startupscriptrunninginstances)
- [Docker イメージの置き場所の変更](https://qiita.com/elm200/items/43497f76cbdd19c47d8b)