GCP の Container-Optimized OS でサイトを運用するときの tips

Google Cloud Platform

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

  1. Docker Compose を使う
  2. Docker のログに Cloud Logging を使う
  3. インスタンスの起動時に Docker Compose でコンテナを起動する
  4. cron 風に処理を定期実行する
  5. コンテナイメージのビルドを別のマシンで行う
  6. 悪質なアクセスの多い国をブロックする

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 でも採用されています。

参考:

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.ymllogging 指定すれば OK です。

version: "3"

services:
  mysite:
    # (省略)
    logging:
      driver: gcplogs
      options:
        gcp-meta-name: mysite

参考:

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 等他のスクリプト言語の実行もできるようです。

参考:

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 集でした。

参考


アバター
後藤隼人 ( ごとうはやと )

Python や PHP を使ってソフトウェア開発やウェブ制作をしています。詳しくはこちら