サービスをAWS EBからGKEに移行したハナシ

はじめに

こんにちは!ノハナでGKEをアレしてる野村です。
暑くなってきましたね。暑いので転職したいなあと思う方はお問い合わせください

背景

ノハナフォトブックアプリのバックエンドは機能ごとにサービスが別れています。
そのうち決済サービスがAWS EBに置かれていたのですが、この決済サービスがGCPリソースへはグローバルにアクセスしており、インターナルにアクセスしたいよねという要件があったのと、コンテナオーケストレーション化したいという思いがあり、GKEに構築することにしました。

新旧構成

移行するサービスについて

Rubyでバックエンド、nodejsでフロントエンドを書いたコードを同じリポジトリに置いています。
それを丸ごとEBにwebサーバとして置いていました。

また、決済確定処理などの非同期バッチ処理も同じリポジトリのコードで書かれています。
それはwebとは違うEBに置き、定期的にcron実行するような構成でした。

やったこと

Docker化

なにはともあれDocker化です。実はここら辺はすんなり行きました。
なぜならEBにある時点でステートレスだったからです。

基本的には、Rubyとnodejsのビルド処理を含めたDockerfileを作り、docker-composeでローカルでの確認を進めていった形です。

Dockerfileはこのような感じです。 multi stage build で最終的なコンテナイメージにはnodeのコードは載らないようにしイメージサイズを小さくする努力をしています。

FROM node AS build-node-env

RUN mkdir /work
WORKDIR /work
COPY . .

RUN npm install
RUN npm run build

FROM ruby

RUN mkdir ./work
WORKDIR ./work
COPY . .

COPY --from=build-node-env /work/public /work/public

RUN bundle install

ENTRYPOINT bundle exec rackup -o 0.0.0.0

docker-compose.ymlはこんな感じです。
基本的にはEBに設定する環境変数をまるっとenvironmentに記述していくだけで済みました。

version: '3'
services:
  web:
    image: gcr.io/hogehoge/hogehoge
    build: .
    links:
      - redis
    environment:
      - SOME_ENV: hogehoge
      - ..
  redis:
    image: redis
    ports:
      - 6379:6379

AWSリソースに依存する処理の解消

旧環境では、メール送信サービスとしてSES, セッションなどの保存先としてElastic Cache for memcachedを使っていました。
SESは弊社のメール基盤に向けましたが、memcacheはGCP側にマネージドなサービスが無かったので、memcache -> Redis(MemoryStore)に切り替えました。

非同期処理の移行

一番気を使ったのはここかもしれません。
旧環境の非同期処理は全てEBの単一インスタンスでcronで動かしていました。
つまり、そのインスタンスに依存したステートレスではない環境だった可能性があったのです。

非同期処理はk8sリソースのcronjobsに置き換えました。

環境構築のコード化

サーバアプリケーションに依存する箇所と、依存しないGKE,他GCPサービスの環境を構築するコードはリポジトリを分けました。

GKE,ネットワーク周りの設定などは、Terraformで記述しました。
deployment,ingress,cronjobsなどのk8sリソースはサーバアプリケーションのリポジトリに記述しました。

CI/CD

特定ブランチへのpushでCircleCIのジョブをトリガーし、テスト〜デプロイまで行うようにしています。
ブランチによってステージング、本番環境いずれかにデプロイされるようにしています。

CircleCIのバージョン2.1では記述を省略できる仕様が増えていて便利です。
特に便利だと思ったのが、orbs, commandsです。

orbsを使うと、汎用的に使うslack通知などの記述を開発者自ら書くことなく呼び出せます。

orbs:
  slack: circleci/slack@2.5.1

  :

workflows:
 version: 2
 test:
   jobs:
       - slack/approval-notification:
         message: hoge

commandsは登録した処理を関数のように使い回しすることができます。
下記はdockerのキャッシュをリストアする例です。

commands:
  restore_docker_cache:
    steps:
      - restore_cache:
          keys:
            - app-{{ .Branch }}-{{ .Revision }}
            - app-{{ .Branch }}-
            - app-
      - run:
          name: load docker cache
          command: |
            set +o pipefail
            docker load -i /caches/app.tar | true
jobs:
  build:
    executor:
      name: gcloud

    steps:
      - checkout
      - setup_remote_docker
      - restore_docker_cache

最後に

EB->GKE移行をやってみた所感です。

  • EB、GAEなどもともとステートレスな環境であれば比較的移行は楽
  • 逆にステートのあるもの(orあるかどうかわからないもの)の移行は辛い
  • web & バッチなどの機能が混在するモノシリックなリポジトリの移行は辛い
  • PF依存のミドルウェア、Saasがある場合は代替するコストがある
  • k8sやっぱすごいわ…

こちらからは以上です。