コネヒト開発者ブログ

コネヒト開発者ブログ

開発体験向上のためのプラットフォームエンジニアリング事例 - カナリアリリースをアプリケーションエンジニアだけで完結できるように改善した話

こんにちは。コネヒトの開発部プラットフォームグループでインフラエンジニアをしている @sasashuuu です。本日は私の所属するチームが最近興味・関心を持って取り組んでいるプラットフォームエンジニアリングの話題について取り上げたいと思います。弊社で行っていたカナリアリリースの運用改善の話になります。

はじめに

はじめに本記事の中心となるプラットフォームエンジニアリングとカナリアリリースの概要について簡単に触れておきます。

プラットフォームエンジニアリングとは、誤解を恐れずに端的に言えばアプリケーション開発者のためのプラットフォームの開発と提供を行うアプローチのことで、Gartner 社の プラットフォーム・エンジニアリングとは何か? の記事では下記のように解説されています。

「プラットフォーム・エンジニアリング」とは、アプリケーションのデリバリとビジネス価値の創出を加速させるための、テクノロジに対する新しいアプローチです。

  • プラットフォーム・エンジニアリングは、再利用可能なツールとセルフサービス機能を実装し、インフラストラクチャ・オペレーションを自動化することで、開発者のエクスペリエンスと生産性を向上させる
  • 新たなテクノロジのアプローチであるプラットフォーム・エンジニアリングは、アプリケーションの再利用可能で構成可能なコンポーネントとサービスを活用する
  • ユーザーにとっては、標準化されたツールとコンポーネント、そして自動化されたプロセスを利用できるというメリットがある

カナリアリリースとは、アプリケーションをユーザー全体に公開するのではなく、配信対象者を一部に絞った形で公開する手法の1つです。

なぜ今プラットフォームエンジニアリングなのか

弊社では会社設立とサービスの公開から10周年の節目を迎え、プロダクトの成長を考える上でも重要な局面を迎えています。 そのような中、プロダクト開発の前線で働く社内のエンジニアのボトルネックになっている部分を解消し、開発体験を上げることで、開発力の向上を図りたいと考え、この領域に力を入れていきたいと考えています。その取り組みの一環として、開発体験を下げる要因の1つであった弊社のカナリアリリースの運用課題に向き合いました。

前提となる環境

今回の事例では主に下記の技術スタックなどから構成される内容がメインとなっております。

  • インフラ環境
    • AWS
    • Docker
  • アプリケーション環境
    • PHP
    • CakePHP
  • CI/CD
    • GitHub Actions

改善の全体像

ざっくりと改善内容のイメージを掴んでいただくために、改善前の状態と改善後の状態を図で表したものを紹介します。詳細は追って解説していきます。

背景・課題感

弊社でもランタイムやフレームワークのバージョンアップ作業など、アプリケーションにおいて影響度の大きいリリースに関しては、カナリアリリースを用いてリリース作業を行なっています。しかし、運用面で抱える課題感がありました。

元々行なっていたカナリアリリースの流れは下記のようなものです。

上記のフローにはそれぞれ課題感がありました。

チームを跨いだ調整コストや反映漏れのリスク

最初にアプリケーションエンジニアからインフラエンジニアへカナリアリリースの対応依頼が来ます。互いにスケジュールなどを調整し、リリースの日時などを決めていましたが、チームを跨いだ調整コストなどがかかっていました。

さらに、アプリケーションエンジニアからコードフリーズ の確認や連絡を受けてからインフラエンジニアが手動で ECR 用の Docker イメージを build し、 push していたので、調整コストの発生や反映漏れ発生のリスクなどがありました。

作業時の人的リソースやコミュニケーションコスト

リリース当日は、基本的に上記のような作業をインフラエンジニアが行い、アプリケーションエンジニアがアプリケーションの状況を監視しつつトラフィック割合の変更に関する意思決定を行い、インフラエンジニアがトラフィック割合を調整していくというような連携を取っていました。リリース作業ではアプリケーションエンジニアとインフラエンジニア数名が同期的に集まり作業を行なっていましたが、作業内容に対する人的リソースやコミュニケーションコストが少なくない印象でした。またリリース作業自体のオペレーションに関しては、高度なインフラ技術が求められるものではなく、権限さえあれば手順に沿ってインフラエンジニア以外も行えるような内容でした。

改善によりもたらされた効果

改善後は下記のようになりました。改善前のフローも再度併せて並べておきます。

before

after

上記のような運用に改善したことで抱えていた課題感などが解消されました。

手動作業の自動化を図り作業をインフラエンジニアから手離れ

GitHub Actions のワークフローを実行するとカナリアリリース用 Docker イメージの ECR への push から ECS のタスク定義およびサービスの更新を一貫して行なってくれるため、カナリア環境の立ち上げにインフラエンジニアが干渉することなく、アプリケーションエンジニアに独力でやってもらえるようになりました。 Manually running a workflow に記載のように、ブランチ指定をしワークフローを手動実行できるようにしたことで、アプリケーションエンジニアの任意のタイミングでカナリア環境を立ち上げられるようにしました。 ワークフローでは ECR 用のイメージの build ~ push を自動化した他、デプロイツールに kayac/ecspresso を使用することで、カナリア環境へのデプロイを簡素化しました。

また、GNU Make とシェルスクリプトで実装したタスクランナーを導入しました。 カナリア環境へのトラフィックを ALB の加重ルーティングで調整するツールとなっており、実装内容は AWS CLI のコマンドを make コマンドのインターフェースで実行するというものです。

こちらはイメージがつきにくいかもしれないので、サンプルコードの一部を載せておきます。

Makefile

.PHONY: {カナリアリリース対象のプロダクト名}_modify_weighted_routing
{カナリアリリース対象のプロダクト名}_modify_weighted_routing:
    bash utils/modify_weighted_routing.sh {カナリアリリース対象のプロダクト名}

modify_weighted_routing.sh

#!/bin/bash

set -eu

# カナリアリリース対象のプロダクト名
TARGET_PRODUCT_NAME=$1
# カナリア・本番環境の加重ルーティング割合(%)
CANARY_PERCENTAGE=1
PRD_PERCENTAGE=99
# HTTP・HTTPSのリスナーのarn
HTTP_LISTNER_ARN=
HTTPS_LISTNER_ARN=
# カナリア・本番環境のターゲットグループのarn
CANARY_TARGET_GROUP_ARN=
PRD_TARGET_GROUP_ARN=

# メイン関数
function main () {
    echo "${TARGET_PRODUCT_NAME}の加重ルーティング割合変更開始。"
        # 対象プロダクト固有の設定情報読み込み
    source ./env/${TARGET_PRODUCT_NAME}
        # 加重ルーティング割合のセット
    set_weight_percentage
        # リスナーのデフォルトアクション変更
    modify_default_actions $HTTP_LISTNER_ARN $HTTPS_LISTNER_ARN
    echo "加重ルーティング変更完了。"
    ./utils/describe_weighted_routing.sh $TARGET_PRODUCT_NAME
}

# 加重ルーティング割合(%)のセット
function set_weight_percentage () {
    read -p "カナリア環境へdeployする割合(%)を入力してください: " P
    if [[ ! $P =~ ^([0-9]|1[0-9]|2[0-9]|30)$ ]]; then
        echo "半角数字0から30の間で設定してください。"
        set_weight_percentage
    fi
    TMP_PERCENTAGE=$P
    read -p "${TMP_PERCENTAGE}%で投入します。よろしいですか?(y/N): " YN
    if [[ $YN = y ]]; then
        CANARY_PERCENTAGE=$TMP_PERCENTAGE
        PRD_PERCENTAGE=$(( 100 - $CANARY_PERCENTAGE))
    else
        set_weight_percentage
    fi
}

# リスナーのデフォルトアクション変更
function modify_default_actions () {
    # 引数(リスナー)の数だけ変更をかける
    for i in $@
    do
# aws cli利用時の--cli-input-json指定のためのパラメータを別ファイルで作成
cat << EOF > utils/parameter.json
{
"DefaultActions": [
    {
        "Type": "forward",
        "ForwardConfig": {
            "TargetGroups": [
                {
                    "TargetGroupArn": "${PRD_TARGET_GROUP_ARN}",
                    "Weight": ${PRD_PERCENTAGE}
                },
                {
                    "TargetGroupArn": "${CANARY_TARGET_GROUP_ARN}",
                    "Weight": ${CANARY_PERCENTAGE}
                }
            ]
        }
    }
]
}
EOF
    aws elbv2 modify-listener --listener-arn $i --cli-input-json file://utils/parameter.json
    trap "rm utils/parameter.json" 0 1 2 3 15
    done
}

# 全体処理の実行
main

コマンド実行例

% make {カナリアリリース対象のプロダクト名}_modify_weighted_routing
bash utils/modify_weighted_routing.sh {カナリアリリース対象のプロダクト名}
{カナリアリリース対象のプロダクト名}の加重ルーティング変更開始。
カナリア環境へdeployする割合(%)を入力してください:

かつてインフラエンジニアが AWS コンソールから手動で調整していたカナリアリリースの割合を調整する作業をタスクランナーに落とし込みました。これにより、カナリア環境へのトラフィックの調整作業がアプリケーションエンジニアで手軽にできるようになりました。

作業時の人的リソースやコミュニケーションコスト削減

リリース作業時にアプリケーションエンジニアとインフラエンジニアが同期的に集まって行なっていたやり方を改善することができ、アプリケーションエンジニア主導のもとカナリアリリースの加重調整の判断と調整作業を一貫して行えるようになりました。これにより、作業にかかる人的リソースやコミュニケーションコストを削減することができました。アプリケーションエンジニア主導で作業を進めてもらいつつ、何か問題があった際にインフラエンジニアがフォローに入るという効率的な運用を行える体制をつくることができました。

開発体験の向上

先述していた改善効果により、チームを跨いだ調整コストや人的リソースを削減し、アプリケーションエンジニアがカナリアリリースを行うハードルを下げることで開発体験の向上をもたらせたと感じています。

おわりに

コネヒトでは現在、プラットフォームグループと呼ばれるプラットフォームエンジニアリング促進しようとするインフラエンジニアのチームが存在しており、アプリケーションの安定稼働や障害対応はもちろんのこと、プラットフォームエンジニアリングにも注力していこうという動きが盛んです。社内のエンジニアの開発体験を向上すべく日々奮闘中ですので、ご興味のある方は今後の私たちの動きなどにもぜひ注目してもらえると嬉しいです。