現状のインフラ構成とワーカーのオートスケール

現状のインフラ構成とワーカーのオートスケール

ロジクラでテックリードをしている高梨です! サービスが公式に公開される前から技術選定だったり、実際にコード書いたり、インフラやSRE的なことまで色々やってます。 最近は愛犬と遊ぶのにはまってます。

f:id:logikura:20211124171041j:plain

概要

ロジクラは今年、AzureからAWSへとインフラの移行を行いました 🎉

当初ロジクラはAzureを利用していました。利用していたAppServiceは十分要件を満たすことができ、Microsoftさんからのサポートも手厚かったことが主な理由で利用していたのですが、会社のフェーズが進み、今後さらに事業拡大し開発組織を大きくしようと考えたとき、リファレンスが充実しており、経験者が多いAWSに移行して採用につなげることを主な目的にインフラ移行を決定しました。 ここでは現状のロジクラのインフラ構成と、移行時に工夫した点などを紹介していきます!

今回移行したものはメインサービスである在庫管理のSaaSのロジクラです。

必要な仕組みとして大まかに説明すると、

  • メインのサービスを乗せているサーバー・DB
  • 非同期処理を行うためのサーバー
  • 非同期処理を行うためキューを貯めるRedis

というシンプルな構成になっています。

管理やスケールの容易さから今回メインのサービスを載せるサーバーについては、ECS・Fargateを利用することにしました。

構成紹介

載せきれない部分もあるのですが、大まかな構成としては以下のようなシンプルな構成になっています。

f:id:logikura:20211110165801p:plain

次にこの構成を作っていった中で、特に工夫していった点を紹介していきます。

デプロイについて

デプロイに関してはgithub actionをトリガーにしています。stagingとproductionでトリガーは異なるのですが、deploy処理に関しては以下のgithub actionの設定ファイル(不要な部分はカットしています)のように、buildしたimageを一度ECRに置き、そのimageを利用してdbのmigrationを行った後にdeployする流れとなります。

...
jobs:
  ...  
  build_image:
    runs-on: ubuntu-latest
    steps:
    - uses: nelonoel/branch-name@v1.0.1
    - name: Check out code
      id: checkout
      uses: actions/checkout@v2

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ secrets.AWS_REGION }}
    - name: Set environment
      id: set_environment
      run: {{環境変数を設定する処理}}

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1
    - name: Build Image
      run: {{deployするimageをbuild}}

  deploy:
    needs: [build_image]
    runs-on: ubuntu-latest
    env:
      IMAGE_TAG: ${{ needs.build_image.outputs.image_tag }}
    steps:
    - uses: kayac/ecspresso@v1
      with:
        version: latest
    - name: Check out code
      id: checkout
      uses: actions/checkout@v2
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ secrets.AWS_REGION }}

    - name: Database Migration
      run: {{DBのmigrate処理}}

    - name: Quiet Sidekiq Process
      run: {{Sidekiqプロセスの停止}}

    - name: deploy
      run: |
        ./deploy/ecs_deploy.sh -t web -e staging -i $IMAGE_TAG
        ./deploy/ecs_deploy.sh -t worker -e staging -i $IMAGE_TAG

実際のdpeloyに何しては、カヤック製のecspressoを利用しており、以下コマンドで $SERVICE_NAMEごとの設定(productionやstagingなどを入れています)を読み込んでいます。

ecspresso deploy --config ./deploy/ecs/${SERVICE_NAME}/${SERVICE_NAME}.yml --rollback-events DEPLOYMENT_FAILURE
ecspresso wait --config ./deploy/ecs/${SERVICE_NAME}/${SERVICE_NAME}.yml

詳しくはecspressoのレポジトリをご覧ください!

タスクに関してもgithub actionから実行したいコマンドと環境を指定して実行するよう設定しています。

以下がecspressoでの実行コマンドになります。

ecspresso --config ./deploy/ecs/${SERVICE_NAME}/${SERVICE_NAME}.yml run --overrides="{\"containerOverrides\":[{\"name\":\"logikura-ecs-container-web-${APP_ENV}\", \"command\":[\"./deploy/run_command.sh ${COMMAND}\"]}]}"

最後にdeployとタスク実行ともに、完了するとslack通知が流れてきます。

f:id:logikura:20211110171022p:plain

以上が基本的なdeploy周りの設定となります!

オートスケールについて

構成の中で工夫した点としては、workerのオートスケールの仕組みを導入したことです。

ロジクラは、利用者の性質上、例えば商品登録や出荷データの登録など、大量のデータを一度に処理したいと言う要望が多く、非同期処理を行うことが必要になっています。

ただ、処理が集中した場合jobが詰まってしまうと言うことが発生し得ます。顧客も増えている ⇒ 安定的に全てのお客さんにシステムを使ってもらうために、job数に応じてオートスケールする仕組みを取り入れています。

credentials = Aws::Credentials.new(ENV["AWS_ACCESS_KEY_ID"], ENV["AWS_SECRET_KEY"])
client = Aws::CloudWatch::Client.new(region: EMV["AWS_REGION"], credentials: credentials)
client.put_metric_data({
    namespace: "SidekiqJobCount",
  metric_data: [
    {
       metric_name: "job_count",
       dimensions: [
          {
            name: "app_env",
            value: ENV["RAILS_ENV"],
          },
        ],
        value: Sidekiq::Stats.new.enqueued,
        unit: "Count",
    },
  ],
})

落ち着いたらスケールインしたくなりますが、処理の途中で落としてしまうと設計によっては問題が生じる場合があるかと思います。

https://github.com/mperham/sidekiq/wiki/Signals#tstp

SidekiqはTSTPシグナルを送ると新しいジョブの取得を停止し、処理が終わると停止します。

この仕組を利用して、TERMをtrapしてSidekiqを安全に停止するようにしました。

function trap_term() {
  SIDEKIQ_PID=`ps -ef  | grep -v grep | grep sidekiq | awk '{ print $2 }'`
  kill -TSTP $SIDEKIQ_PID
  while :
  do
    SIDEKIQ_STATUS=`ps axu  | grep -v grep | grep sidekiq`
    echo $SIDEKIQ_STATUS
    if [[ $SIDEKIQ_STATUS =~ stopping ]]; then
      echo "stopped sidekiq"
      exit
    else
      sleep 1
    fi
  done
}

trap trap_term TERM

これで解決したように思えたのですが、処理に時間のかかるjobの場合stopTimeout(最大120秒)を超えるとKILLされてしまう問題が起こりました。

stopTimeoutはFargate環境では現状これ以上伸ばせないので、結局スケールインはできていません。

何か良い方法あれば教えて下さい 🙏

参考

https://aws.amazon.com/jp/blogs/news/graceful-shutdowns-with-ecs/

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html

まとめ

toBのサービスだと同じような課題を抱えている会社は多いと思います。ぜひ参考にしてみてください!

ロジクラではこの他にもインフラ面で工夫している点がいくつもあるので、また別の記事でも紹介していきます!

最後に

ロジクラでは一緒に開発してくれるメンバーを募集しています!

興味がある方はぜひ こちら をご覧ください!

開発チームのマネジメント層を置かないことに決めた話

こんにちは!ロジクラでプロダクトチームの統括をしている榊間です。
初記事なのでまずは会社紹介から、、

僕が所属している株式会社ロジクラはSaasの在庫管理アプリ「ロジクラ」を提供しており、モノを扱う全ての企業が持つ在庫問題の解決を通して、お客様の事業の基盤・インフラとなる存在になるために事業を展開しています!

 

会社組織としては拡大中で、僕が入った当初の数人しかいなかった時期から仲間も増え、会社らしくなってきたなというふうに感じてます笑

そんなロジクラですが、外部で手伝っていただいている方を含めると開発チームは現在7名で、主にロジクラのiOSアプリとWEBアプリを開発しています(各メンバーの紹介はこちら)

 

通常このくらいの規模になるとマネージャー層を作って組織マネジメントの準備を考える会社が多いと思いますが、ロジクラの開発チームではあえてマネジメント層を置かないという判断をしました。

この記事ではその背景と運用に関して紹介します!

 

背景

まずそもそもマネジメントがなぜ必要か考えた時、理由の一部を挙げると以下になります

  • チームの目標と方向性決め、全社目標とのすり合わせ
  • メンバーの管理
  • メンバーの評価

...などなど(他にもたくさんある)

 

マネジメント職が担う役割は多岐に渡り、その機能は会社を動かしていく上でどれも必要です。

ただ、機能は必要だとしてもそれを個人が担う必要はあるでしょうか。

 

会社の成長のボトルネックになる

マネジメント層をつくるデメリットとして、意思決定がマネージャーに集中します。もちろんメンバーに裁量持たせてチームをうまく回せるマネージャーであれば問題ないですが、個人のスキルに依存するので、構造的に意思決定の集中を誘発しやすいです。

全ての意思決定のたびに許可が必要になると、多数の意思決定を行わなければならないスタートアップではボトルネックになることがあります。

 

主体性の抑制

意思決定の集中により、

  • マネージャー個人で方針が合わないと却下され、多様な意見が取り入れにくくなる
  • メンバーが意思決定に関わる場が設けられない

といった現象も起こります。

その結果、メンバーそれぞれが意思決定か関わるアイデアを考えたり、行動をそもそも起こさず、マネージャーから与えられた役割をこなすことに収束し、主体性の抑制が起きてしまいます。

 

業務環境の変化によりマネジメントがさらに難しくなった

コロナの影響でロジクラも全社員フルリモートになりました。

同じ悩みを持っている会社も多いと思いますが、それぞれのメンバーとコミュニケーションをとったり、パフォーマンスを管理するということ自体が以前より難しくなったの感じています。

このような状況下において、あえて難易度の高いマネジメントをするよりは、メンバーそれぞれがある種セルフマネジメントができるような環境を作っていくことが重要だと考えています。

 

組織の方針を決めれたきっかけ

実際このような方針に転換できたのは、もともといる開発メンバーがセルフマネジメントを行えていたという部分が大きいです。

会社としても、ロジクラでは全社の数値や方針が公開・説明されているので、全員が共通認識を持ちやすく、会社の目標達成のために個人、チームでどのような意思決定を行うべきか考える機会が多い文化がありました。

採用活動においてもセルフマネジメントの部分は強調しており、実際以前の会社でマネジメント職を行っていた方が共感して入社を決断してくださるなど、同様の課題感を抱えている開発者は多いのを感じています。

 

運用上の問題点とその解決策

マネージャーが担うはずの機能は誰がやるの?

まず評価制度構築、組織事務管理、技術支援など、チームで必要だが本来マネジャーが担うような機能を洗い出し、それぞれの機能に担当者を設定しました。

こうすることで意思決定のスピードを担保しつつ、意思決定の機能が個人に集中するのを防ぐことができます。

ただ、各機能が本当に必要か、うまくワークしてるかなどは確認が必要で、チームとしてガバナンスミーティングというものを設定し、役割交代も含め定期的に見直しをはかっています。

ガバナンスミーティングとは

役割を新たにつくったり、修正したり、なくしたりする必要があると感じている人(「提案者」と呼ばれる)は、だれでも議題に自分の案を加えることができる。このようなチームのガバナンスに関わる問題が順に一つずつ取り上げられ、次のプロセスに従って採決に至る。
1提案が発表される
2問題点の明確化
3反応ラウンド
4修正と明確化
5異議申し立てラウンド
6統合ラウンド

*1

みんな平等ということ?

違います。各メンバーが担う機能の重みや量などはバラバラなので、評価もそれに合わせて変えています。

あくまで主体性の抑制をしないことが目的なので、全員同等の評価をするということではありません。

 

意思決定が遅くなるのでは? 

この取り組みをメンバーの権限を完全に平等にすることだと捉えると意思決定のたびに全員の承認が必要なのではないかという発想になり、意思決定のスピードが下がると思われる方もいると思います。

ただ、あくまで意思決定は各機能の担当者が行い、必要なのは関係者に対する事前の共有と相談のみです。

現状は人数も少なく、開発チームに関する決定はデイリースクラムなどで全体に共有できるのですが、規模が大きくなった場合はティール組織にある助言プロセスを導入しようと計画中です。(助言プロセスについては詳しく説明しませんが、ティール組織ぜひ読んでみてください!)

 

今後も自己成長を継続

以上が今ロジクラの開発チームで行っている取り組みです。

チームの規模によって問題も変わってくると思いますが、今後うまくいった・いかなかったことも随時公開していければと思ってます!

 

最後に、、

ロジクラでは一緒に開発、組織づくり手伝ってくれる人を募集してます!

ぜひカジュアルに組織・技術のことを話しましょう!

=> 応募はこちら 

*1:引用: フレデリック・ラルー ティール組織 - マネジメントの常識を覆す次世代型組織の出現