GCP の Container-Optimized OS でサイトを運用するときの tips
Google Cloud Platform (以下 GCP )の Container-Optimized OS で Docker を使ってサイトを構築・運用するときの tips 集です。
Container-Optimized OS を使うようになってしばらく経ったので利用時の小ネタをかんたんにまとめました。 利用イメージとしては、単一のインスタンスで Docker または Docker Compose を使ってサイトを運用する場合を想定しています( Kubernetes に関する tips はここには含まれていません)。
Container-Optimized OS の利用に興味のある方は参考にしてみてください。
Container-Optimized OS とは
Container-Optimized OS とはコンテナ利用に最適化された Google 社製 OS です。 GCP ユーザーは無料で使用することができ(もちろんインスタンス使用料は別途かかります)、 Ubuntu や CentOS 等と並んで Compute Engine のインスタンス作成時に選べる選択肢のひとつになっています。
Container-Optimized OS について Google 社の公式サイトでは次のように説明されています。
Google が厳選したコンテナ用 OS
Container-Optimized OS は、Google Cloud Platform 上でのコンテナのホスティングと実行を目的とした、Google が推奨する OS です。この OS は、Google が設計・維持管理し、GCP とシームレスに統合されています。
- コンテナ向けに最適化
- スケーラブルに構築
- 最小サイズの OS、最大のセキュリティ
- オープンソース
CONTAINER-OPTIMIZED OS の機能
- コンテナ サポート
- 自動更新
- Compute Engine メタデータ フレームワーク
- cloud-init
- リリース チャネル
以下に tips をあげていきます。
Container-Optimized OS の tips
- Docker Compose を使う
- Docker のログに Cloud Logging を使う
- インスタンスの起動時に Docker Compose でコンテナを起動する
- cron 風に処理を定期実行する
- コンテナイメージのビルドを別のマシンで行う
- 悪質なアクセスの多い国をブロックする
1. Docker Compose を使う
Container-Optimized OS 上で Docker Compose を使いたいときは Docker Compose のコンテナイメージを使用します。
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PWD:$PWD" \
-w="$PWD" \
docker/compose:1.27.4
-v
オプションでホストと /var/run/docker.sock
を共有することで、あたかもホスト側で直接実行しているかのように docker-compose
コマンドを使用することができます。
docker-compose
をよく使う場合は次のようにエイリアスを作っておくと便利です。
~/.bashrc
:
alias docker-compose='docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PWD:$PWD" \
-w="$PWD" \
docker/compose:1.27.4'
このことは公式のドキュメントでも言及されています。
補足:
Container-Optimized OS ではユーザーが実行するすべての処理は原則コンテナ上で実行する形になっています。
docker
コマンドは最初から利用できますが docker-compose
コマンドは入っていないためにこのような対応が必要になります。
2. Docker のログに Cloud Logging を使う
Docker のログの出力先に Cloud Logging を使いたい場合は、 Docker daemon の設定でログドライバーを gcplogs
に設定します。
Docker daemon の設定ファイルは /etc/docker/daemon.json
にあります。
/etc/docker/daemon.json
:
{
"log-driver": "gcplogs"
}
もともと設定が入っている場合はそれらを誤って消さないように注意してください。
log-opts
でログプションを設定することもできます。
{
"log-driver": "gcplogs",
"log-opts": {
"gcp-meta-name": "mysite"
}
}
他にもさまざまなオプションが用意されています。 利用できるログオプションについて詳しくは Docker の公式ドキュメントを参照してください:
注意が必要な点として、 /etc/docker/daemon.json
に対して加えた変更はマシンを再起動すると元に戻ってしまいます。
そのため、再起動後も設定を維持したい場合は、ファイル /etc/docker/daemon.json
を直接編集するのではなく cloud-init
等の初期化の仕組みを利用する必要があります。
cloud-init
は、さまざまなクラウドプロバイダが採用している標準的なインスタンス初期化方法です。
Container-Optimized OS でも採用されています。
参考:
- cloud-init Documentation — cloud-init documentation
- GitHub - canonical/cloud-init: Official upstream for the cloud-init: cloud instance initialization
Container-Optimized OS における cloud-init
の使い方としては、 Compute Engine インスタンスの Custom metadata を使用します。
Custom metadata に user-data
というキーを追加してその値のところに所定の書式で指示を記述しておくと、マシン起動時に特定の処理を自動実行することができます。
Custom metadata は対象の Compute Engine インスタンスの編集ページで編集できます( gcloud
コマンドでもセットできます)。
たとえば、 Docker daemon の設定ファイル /etc/docker/daemon.json
の中身を指定したい場合は次のような内容を user-data
の値にセットします。
user-data
:
#cloud-config
write_files:
- path: /etc/docker/daemon.json
content: '{ "log-driver": "gcplogs", "log-opts": {"gcp-meta-name": "mysite"}, "live-restore": true, "storage-driver": "overlay2", "mtu": 1460 }'
runcmd:
- systemctl restart docker
Docker Compose で起動するコンテナのログの出力先を Cloud Logging にしたい場合は、設定ファイル docker-compose.yml
で logging
指定すれば OK です。
version: "3"
services:
mysite:
# (省略)
logging:
driver: gcplogs
options:
gcp-meta-name: mysite
参考:
- Using cloud-init with the Cloud config format | Creating and configuring instances | Container-Optimized OS
logging
| Compose file version 3 reference | Docker Documentation
3. インスタンスの起動時に Docker Compose でコンテナを起動する
Compute Engine のマシンの起動時に自動的に Docker Compose を使ってコンテナを立ち上げたい場合は、次の 2 つのアプローチが使えます。
- a) Custom metadata の
user-data
で daemon を登録して起動する - b) Custom metadata の
startup-script
でコマンドを実行する
a) は、上述の user-data
を使って /etc/systemd/system/
以下にサービス定義ファイルを作成しそれを systemctl
で起動する方法です。
公式ドキュメントに busybox:latest
イメージを実行するサンプルが紹介されています:
#cloud-config
users:
- name: cloudservice
uid: 2000
write_files:
- path: /etc/systemd/system/cloudservice.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Start a simple docker container
[Service]
ExecStart=/usr/bin/docker run --rm -u 2000 --name=mycloudservice busybox:latest /bin/sleep 3600
ExecStop=/usr/bin/docker stop mycloudservice
ExecStopPost=/usr/bin/docker rm mycloudservice
runcmd:
- systemctl daemon-reload
- systemctl start cloudservice.service
これを Docker Compose 用にアレンジすれば OK です(……とは思いますが、私自身はこの a) のやり方は使っていないので、実際に使えるかどうかは未検証です)。
b) は、 Custom metadata を使う点は a) と同じですが、こちらは startup-script
というキーを使用します。
Custom metadata は上述のとおり Compute Engine インスタンスの編集ページでセットできます。
キー startup-script
を登録して、値のところに実行したいスクリプトの中身をセットします。
たとえば、 /home/username/myapp/
ディレクトリにある docker-compose.yml
ファイルを使って docker-compose up -d
を実行したいような場合は次のように書けば OK です。
startup-script
:
#! /bin/bash
cd /home/username/myapp/ && \
/usr/bin/docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PWD:$PWD" \
-w="$PWD" \
docker/compose:1.27.4 \
up -d
私は Bash しか実行したことがありませんが、公式ドキュメントによると shebang で指定すれば Python 等他のスクリプト言語の実行もできるようです。
参考:
- Running startup scripts | Creating and configuring instances | Container-Optimized OS
- 起動スクリプトの概要 | Compute Engine ドキュメント | Google Cloud
4. cron 風に処理を定期実行する
Container-Optimized OS で cron 風に特定の処理を定期的に実行するのは、やることがシンプルなわりに手間がかかります。 ホストで cron サービスが動いていないため、別の方法で処理を定期実行する仕組みを作る必要があるからです。
実際にどのような方法が一般的なのかわかりませんが、私が考えるおそらく最もよく使われている方法は次の 2 つです。
- a) 処理を定期実行するコンテナを作る
- b) GCP のサービスを組み合わせる
a) の方法は、たとえば Python の schedule
のようなパッケージを使って決まった時間に所定の処理を実行するプログラムを書いておいて、それを実行するコンテナを起動するというものです。
ただし、多くの場合定期実行したい処理というのは他のコンテナの中で実行する必要があるので、このアプローチを採る場合はコンテナ間で volume を共有する等のプラスアルファの工夫が必要になります。
b) の方法は、 GCP の次の 3 つのサービスを使って定期実行を実現するものです。
- Cloud Scheduler
- Cloud Pub/Sub
- Cloud Functions
Cloud Scheduler は cron 風の設定で定期的に HTTP リクエストや Cloud Pub/Sub のメッセージ送信ができるサービスです。 Cloud Pub/Sub はシステム間連携のための非同期メッセージングサービスです。 Cloud Functions は小さな処理を実行するための FaaS サービスです。
Cloud Scheduler → Cloud Pub/Sub → Cloud Functions という流れで Cloud Functions を起動してその中で対象の Compute Engine インスタンスにログインして処理を実行すると、 Container-Optimized OS 上での処理の定期実行が実現できます。 こちらは実行したい処理がほんのささいなものでもこの一連の組み合わせが必ず必要になってしまってじゃっかん大がかりになるのが難点です。 このアプローチを使うぐらいなら Container-Optimized OS はやめて cron が手軽に使える使い慣れた OS を使おうと考える人も一定割合いるのではないかと思います。
5. コンテナイメージのビルドを別のマシンで行う
これは Container-Optimized OS にかぎらず Compute Engine 全般のお話ですが、コンテナイメージのビルドを Compute Engine のインスタンス上ではなくどこか別の場所で実行したい場合は GCP の Cloud Build を利用します。 Cloud Build は GitHub との連携がかんたんにできるので、リポジトリに変更があったときに自動的にビルドを走らせるようにしておけば、後は Compute Engine インスタンスの方では Cloud Build で生成されたイメージを pull してくるだけで済みます。
6. 悪質なアクセスの多い国をブロックする
これも Container-Optimized OS にかぎらず Compute Engine 全般のお話です。 悪意のあるアクセスが多い国をブロックするには、 VPC firewall 設定を使用します。 こちらの具体的な方法は以前記事に書いたのでここでは説明しません。
ということで、 GCP の Container-Optimized OS でサイトを運用するときの tips 集でした。