オールアバウトTech Blog

株式会社オールアバウトのエンジニアブログです。

GKE(Google Kubernetes Engine)を1年間本番利用して

SREG@takkyです。

この記事は All About Group(株式会社オールアバウト) Advent Calendar 2017 8日目の記事です。 (kubernetes ... k8s の8に合わせて8日の08:08に投稿してみました)

12/02に公開した記事ではGCPを1年間利用してどうだったかについてまとめました。 allabout-tech.hatenablog.com

この記事ではGKE(Google Kubernetes Engine)を1年間利用して得られたノウハウについてまとめたいと思います。

前書き

GCPの東京リージョンは2016/11/08にオープンされました。

cloudplatform-jp.googleblog.com

その際にGoogle Container Engine(GKE) も東京リージョンで使えるようになりました。
社内ではまだDockerの導入事例は無かったのですが、本番以降に際して合わせてコンテナ化してKubernetesで動かそうという意図もあり GKEの採用に至っています。

GKEという略称について

本題に入る前にGKEという略称についての歴史を1つ。 GKEは2017/11/14にKubernetes適応認証プログラムに対応したことを受けて Google Container EngineからGoogle Kubernetes Engineへと名前が変わりました*1
略称はどちらもGKEです。 Google Container Engineの頭文字を取ってGCEと略すとGoogle Compute Engineとか被るからKubernetesのKをとってGKEって言っているんだよみたいなことを社内ハンズオンなどで何回も言った記憶があります。

Docker Imageの運用方針

Dockerリポジトリとしては、Google Container Registry(GCR)を使用しています。
GCRを利用するメリットとしては

  • プライベートなリポジトリが使用可能
  • 料金が安い (Google Cloud Storageの料金+ネットワーク下り)
  • Docker CLIと統合してpushやpullができる
  • GKEであれば特に認証いらずにイメージを使える

があります。 またDocker Imageのレジストリやタグの命名規則としては

アプリケーション名-[環境名]:GitCommitHash

というルールで統一しています。

アプリケーション名とGitCommitHashを付けることでデプロイ中のアプリケーションがどのコミットのものなのかひと目で分かるようになります。
(環境別にイメージを分けるかどうかは賛否両論あると思います。)

このGitCommitHashはCI/CDツールで付与しています。

また、実際の運用では社内の標準的なミドルウェア入りの共通DockerImage (PHP+Apache+etc...)を作成して毎回PHPのインストールからは行わないようにしています。

CI/CDツール

werckerというCI/CDツールを使っています。
Oracleに買収されたことで日本でも有名になったかと思います。

以下は PHP(Laravel)アプリケーション入りのDockerImageを作成して docker push / GKEへデプロイする一例になります。
(抽象化しているので実運用で使用しているものと一部異なります)

deploy_staging:
    box:
        id: gcr.io/project/allabout_common_image
        username: _json_key
        password: $PASSWORD
        registry: https://gcr.io
        tag: php56
    steps:
    - script:
      name: application placement
      code: |-
          cp -R $WERCKER_SOURCE_DIR /app/$WERCKER_APPLICATION_NAME
    # composerinstall
    - script:
        name: composer install
        code: |-
            cd /app/$WERCKER_APPLICATION_NAME
            php /usr/local/src/composer.phar install --no-interaction --no-dev
    # temporaryディレクトリに書き込み権限追加
    - script:
        name: chmod 777
        code: |-
            cd /app/$WERCKER_APPLICATION_NAME
            chmod -R 777 storage
    # docker push
    - internal/docker-push:
        registry: https://gcr.io/v2
        username: _token
        password: $GCR_AUTH_TOKEN
        repository: gcr.io/project/$WERCKER_APPLICATION_NAME-stg
        tag: $WERCKER_GIT_COMMIT
        cmd: /usr/sbin/httpd -D FOREGROUND
    - bash-template:
        cwd: /app/$WERCKER_APPLICATION_NAME/yaml_files/staging
    - kubectl:
        cwd: /app/$WERCKER_APPLICATION_NAME/yaml_files/staging
        debug: true
        command: "apply -f deployment-stg-${WERCKER_APPLICATION_NAME}.yaml"

werckerで特徴的なのはDockerfileのビルドができないという点です。 そのため、現在実行中のコンテナをinternal/docker-push というstepで pushする必要があります。
またエコシスステムとして werckerや一般ユーザが作ったstepも使用することが出来るので、使用しています。
bash-templatekubectlなどが上記の例にあたります。

DockerベースでBitbucketにも対応していますし、 GCRの継続的デリバリーツールの統合にも記載されているので良いCIツールであると思います。
欠点としてはVirtual Private Pipelines(VPP)だと $350/月で3並列実行と他のCI/CDツールとくらべ若干コストがかかる点やたまにVPPでもキューづまりが起きサポートに解決して貰う必要がある点など問題点もあります。

GKEクラスタ自体の管理

GKEクラスタを立てる方法として、Webコンソールで行う方法やgcloudコマンドで行う方法などがありますが弊社では基本的に作成はterraformで行っています。
現在約10-20クラスタ稼働しており、クラスタ当たりのNode数は4-5程度にしています。サービスや開発G毎にクラスタを分けているイメージです。
1クラスタあたりのNode数を5以下にしていたのはクラスタ管理料金として6Node以上は課金対象だったという背景があるのですが、 2017/11/28の発表クラスタ管理料金がかからなくなったので気にする必要がなくなりました。
また、一部クラスタではMulti-Available Zoneとして配置している物もあります。

Replication Controller(RC)とDeployments

Podの配置方法としてRCとDeployments2種類方法があるかと思います。
導入当初はRCで行っていたのですが、Deploymentsでデプロイしている記事も多くGoogleのサンプルなどでもDeploymentsが用いられているためDeploymentsにしています。

DeploymentsにすることでmaxSurgeやmaxUnavailableなどにより複数podを一気にrolling update出来るのでデプロイ速度の向上が行えています。

ServiceとLB

本来であればIngressで行いたいところですが、現状外部に公開する際にはService:NodePort でPortをマッピングして
その上にGoogle Load Balancerを紐付けて公開する形を取っています。
ここはあまり良くないところなので改善したい所ですね。

監視について

ログは全て標準出力に出力しGoogle fluentdでStackDriverLoggingに転送しています。
StackDriverLoggingにはエクスポートの機能があるため、BigQueryとGoogle Cloud Storage(GCS)へ転送しています。
BigQueryは主に開発者がログを確認する用途として使用しています。
また、StackDriverLoggingはGKE標準のものをoffにして、別途 daemonsetsでデプロイしたgoogle fluentdを使用しています。
主にアクセスログをAppEngine風にしたり、アプリケーションのログレベルをStackDriver上で判別しやすくするように付与したりする用途で使用しています。
GKE自体のリソース監視はStackDriverを使っています。

1年間運用して改善が必要だと感じた所 / 改善した所

Docker Image肥大化

最初はDockerに関して0ベースから始めたので、オンプレ環境で使用していたchefのレシピをそのままDockerfile化して作ったようなイメージでした。
そのため不要なパッケージやライブラリなどが多く、DockerImageとしては3GBとかなり大きくデプロイ時間やポータビリティという面で問題がありました。
また1コンテナ1プロセスではなく、起動用scriptを叩きその中で apache,cron,fluentdなどなど起動していたため開発時にも使いにくいイメージとなっていました。
2017年の4月に刷新し、不要なパッケージの削除やyumのcache削除,ソースインストール時の中間ファイルの削除などを行い1GB程度のイメージにすることができました。
php:7-apacheが約400MB程度とまだまだ大きいイメージですが、依存ライブラリなどを考えるとちょうど良いぐらいのイメージなのかなと思います。

werckerの安定性

3ヶ月に1回度ぐらいキューづまりが発生し、サポートに問い合わせつつ手動でコマンドでデプロイするような運用が発生するので、CI/CDツールの移行は考えるべきなのかなと思っています。
少なくてもDockerfileのBuildはGoogle Container Builderに移譲して、後はコマンドでデプロイ出来るようにしておくような体制を整えておくことが必要なのかなと思います。

社内標準Docker Image

公式のCentOSをベースにPHPApacheをインストールしたイメージになっているのでPHPのバージョンアップの度にイメージの作成を行うのは運用負荷が高いのかなと思います。
最近では新規案件に関しては公式のPHPのDocker Imageを使用して検証を行いたいと考えています。

まとめ

Kubernetes自体概念がちょっと複雑なので学習コストは高いです。 しかしながら、DockerがKubernetesをネイティブでサポートし始めたり、2017/11/30にAmazon Elastic Container Service for Kubernetes(EKS)が発表されるなど、
今後の開発者にとってKubernetesは必須スキルになってくるのかなと思います。
そのためワークショップやハンズオンを通して社内には広めていきました。
また、GKEのようなマネジメントサービスを利用することで、MasterNodeの管理はGoogleに任せてWorker Nodeのみに集中することができます。
Nodeの自動アップグレードや自動復旧等を上手く使えばインフラ運用の手間を低減することができます。
その他にもログをtailするwercker/sternやkubectlコマンドを補完するkube-promptなどのツールを使うことで開発・運用工数が上がるのかなと思います。

来年にかけてkubernetes周りは更に盛り上がっていくと思うので今から楽しみにしています。