深夜の怠惰な技術ブログ

日々の技術的な話題などを徒然なるままに

AWS CodeBuildにおけるGitHub Repositoryをソースプロバイダとしてアクセスする方法

はじめに

必要に迫られてAWS CodeBuildのソースプロバイダをGitHub Repositoryにしました。 その際に実施した内容を備忘のために記載したいと思います。なお、AWS CodeBuildの構築とアクセストークンの設定についてはTerraformを使用しました。

実施内容

GitHubにおけるPersonal Access Tokenの作成

まずは、AWS CodeBuildがソースプロバイダとしてGitHubへ接続するためのアクセストークンとしてPersonal Access Tokenの作成が必要になります。 以下の参考ドキュメントをもとに、Personal Access Tokenを作成しましたが、Scopeとしては以下の添付画像となります。これだけとなります。

参考ドキュメント

docs.aws.amazon.com

https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token

TerraformによるAWS CodeBuildの作成

次にAWS CodeBuild Projectを作成します。Terraformコードは以下の通りです。 ここでソースプロバイダとしてGitHubのRepositoryを指定している部分はsource内のtypelocationになります。

resource "aws_codebuild_project" "this" {
  name         = "github-integration-project"
  service_role = "<role_arn>"
  artifacts {
    type = "NO_ARTIFACTS"
  }
  environment {
    compute_type                = "BUILD_GENERAL1_SMALL"
    image                       = "<ecr_uri>"
    type                        = "LINUX_CONTAINER"
    image_pull_credentials_type = "SERVICE_ROLE"
  }
  source {
    type     = "GITHUB"
    location = "https://github.com/<organization_name>/<repository_name>.git"
    buildspec = jsonencode({
      phases = {
        build = {
          commands = [
            "ls -al"
          ]
        }
      }
      version = "0.2"
    })
  }
}

TerraformによるAWS CodeBuildへのアクセストークンの設定

最後にAWS CodeBuild Projectが先に作成したPersonal Access Tokenを使用して指定したGitHun Repositoryへアクセスするための設定です。 ここで注目するべきは、特にAWS CodeBuild Project自体を識別するための情報が存在しない点です。 理解してしまうとなんてことはないのですが、本設定はリージョンに対してサーバタイプ(GitHub)ごとに1種類しか登録できないのです。

resource "aws_codebuild_source_credential" "this" {
  auth_type   = "PERSONAL_ACCESS_TOKEN"
  server_type = "GITHUB"
  token       = "<personal_access_token_value>"
}

さいごに

いかがでしたでしょうか。これによりAWS CodeBuildはソースプロバイダをGitHub Repositoryとすることができます。 どこかの誰かの参考になれば幸いです。

GitLab CI/CDにおけるJobの手動実行について

はじめに

今回はGitLab CI/CDにおけるJobの手動実行について投稿したいと思います。 この手動実行の用途としては様々あると思います。例えば、Terraformを実行するCI/CDだとして、StageがTerraform PlanとTerraform Applyを実行するJobにそれぞれ分割されていた際に、Terraform Planの結果を確認した後、Terraform Applyを実行するなどではないでしょうか。このように、人手を介してJobの状況を確認して後続のJobを実行するか否か判断する場合に効果を発揮します。しかしながら、注意しなければならないのは、今回お伝えするのは手動実行であり、手動承認ではありません。そのため、Jobを許可や拒否するものでないということです。

Jobの手動実行

対象のJobに対して手動実行する適用するにはwhenにおいてmanualを指定するだけとなります。 manual以外にも指定可能な値は種々ありますが、そのご紹介は以下のリンクをご覧いただければと思います。 以下のコードはサンプルコードになります。

manual_approval:
  script:
    - echo 'Manual Execution'
  when: manual
  only:
    - main

gitlab-docs.creationline.com

さいごに

いかがでしたでしょうか。今回はピンポイントの技術検証をお伝えいたしました。 どこかの誰かのお役に立てれば幸いです。

GitLab CI/CDにおけるTerraform Moduleについて

はじめに

本投稿ではTerraform Moduleにおいて別GitLabリポジトリを参照する場合におけるTipsを記載していきたいと思います。 また、今回はTerraform Moduleの詳細については割愛させていただきますので、あらかじめご容赦下さい。

Terraform Moduleの設定

Terraform ModuleのsourceにてGitLabレポジトリを指定する必要がありますがサンプルは以下となります。 今回は例としてAWSリソースのVPCを作成するTerraform ResourceコードがGItLabリポジトリsample-terraform-vpc-moduleに格納されているとします。 また、該当リポジトリのcommitにはtagがふられており、refによって該当tagのcommitを参照するようになっています。

module "network" {
  source = "git::ssh://git@gitlab.com/<your_group>/sample-terraform-vpc-modules.git//terraform?ref=v0.0.1"
}

詳細は以下の公式ドキュメントをご覧ください。

www.terraform.io

対象リポジトリへのアクセス方法

GitLab CIにてTerraform Moduleを適用する際には、その参照先のリポジトリsample-terraform-vpc-moduleへのアクセスが必要となります(ダウンロードするために)。 そのため、権限が必要になるのですが、ここではその設定方法について説明していきたいと思います。 Terraform Moduleの設定では、対象sourceをsshによってアクセスするようにしています。しかしながら、GitLab CIではこれをhttpによるアクセスに変更してあげることで、GitLab CI上に定義された環境変数CI_JOB_TOKENを利用して権限の問題を解消することができます。GitLab CI/CDにおける定義済み環境変数については以下をご覧下さい。

gitlab-docs.creationline.com

以下が.gitlab-ci.ymlにおける該当部分のサンプルコードです。

before_script:
  - git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/<your_group>/sample-terraform-vpc-module.git".insteadOf ssh://git@gitlab.com/<your_group>/sample-terraform-vpc-module.git

今回はbefore_scriptにて設定を記述しているのですべてのJobで適用される形になりますが、ユースケースにより必要なJob内で個別に実行していただいても構わないと思います。

さいごに

いかがだったでしょうか。分かってしまえば簡単かもしれませんが、個人的には大変学びになりました。 誰かのお役に立てれば幸いです。

GitLab CI/CD PipelineにおけるAWS IAM Roleでのクレデンシャル取得の方法とJobでの継承について

はじめに

以前のブログでGitHub ActionsにてAWSリソースをIaC(Terraform、AWS CDK等々)によって構築する際のIAM Roleにおける権限付与の話を書きました。 詳しくは以下をご覧ください。 ymmryt.hatenablog.com

今回はGitLab CI/CD Pipelineにおいて、同様の観点からブログを記載していこうと思います。また、各Jobにおいて取得したクレデンシャルを継承していくことで都度取得する手間からも解放していきたいと思います。

Terraformによる必要リソースの作成

GItHub Actionsの時と同様に、IAM Roleに対するAssume Roleを可能にするためには大きく3つのコンポーネントが必要となります。

  • IAM OIDC Provider
  • IAM Role
  • IAM Policy

今回はIAM OICD ProviderとIAM Roleについて記載していきたいと思います。なぜならば、IAM Policyについては読者の方々が適切な権限を選定していただくことになります。また、IAM Policyの作成に関するTerraformの知見はインターネットに無数に転がっているため、ここでは割愛させていただきます。

IAM OIDC Providerの作成

ますは、ID Providerを作成します。

data "http" "gitlab_openid_configuration" {
  url = "https://gitlab.com/.well-known/openid-configuration"
}

data "tls_certificate" "gitlab" {
  url = jsondecode(data.http.gitlab_openid_configuration.body).jwks_uri
}

resource "aws_iam_openid_connect_provider" "gitlab" {
  client_id_list  = ["https://gitlab.com"]
  thumbprint_list = [data.tls_certificate.gitlab.certificates[0].sha1_fingerprint]
  url             = "https://gitlab.com"
}

まずは、OICD Providernいおけるサムプリントの取得を実施する必要があります。詳細については以下をご覧いただければと思いますが、Terraformコードにおける重要な部分はdata resourceで記述されている部分です。 基本的に、OIDCの規格は同じなので、上記のようにすればGitHub ActionsやCircle-ciでも同様の記述を行うことができるはずです。

docs.aws.amazon.com

IAM Roleの作成

次は、IAM Roleを作成します。

resource "aws_iam_role" "gitlab_assume_role" {
  name = "gitlab-assume-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["sts:AssumeRoleWithWebIdentity"]
        Principal = {
          Federated = aws_iam_openid_connect_provider.gitlab.arn
        }
        Condition = {
          StringLike = {
            "gitlab.com:sub" = "project_path:<my_group>/<my_project>:*"
          }
        }
      }
    ]
  })
}

GitHub Actionsの時とあまり変わらないのですが、念の為説明をしていきたいと思います。 まず、PrincipalにおけるFederatedの値は前セクションで作成したOICD ProviderのARNを指定しています。 これにより、該当OICD Providerが本IAM RoleへのAssume Roleを許可していることになります。 ただし、これだけですと他のGitLab CI/CD PipelineからもAssume Roleが許可されている状況となってしまうため、Conditionによる制限が必要になってきます。具体的には以下の部分です。

Condition = {
  StringLike = {
    "gitlab.com:sub" = "project_path:<my_group>/<my_project>:*"
  }
}

<my_group>と__<my_project>については各自の値になります。 これらのTerraformコードを記述してapplyを実施することにより、必要なリソースが作成されます。

.gitlab-ci.ymlの記述について

上記で必要なリソースが作成されたので、次はgitlab-ci.ymlについて書いていきたいと思います。 サンプルは以下のコードとなります。

image:
  name: hashicorp/terraform:1.1.9
  entrypoint: [""]

stages:
  - assume_role
  - plan

before_script:
  - apk update --no-cache && apk add --no-cache aws-cli jq

assume_role:
  stage: assume_role
  script:
    - >
      credentials=`aws sts assume-role-with-web-identity
      --role-arn ${ROLE_ARN}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token $CI_JOB_JWT_V2
      --duration-seconds 3600 | jq .Credentials`
    - export AWS_ACCESS_KEY_ID=`echo ${credentials} | jq -r .AccessKeyId`
    - export AWS_SECRET_ACCESS_KEY=`echo ${credentials} | jq -r .SecretAccessKey`
    - export AWS_SESSION_TOKEN=`echo ${credentials} | jq -r .SessionToken`
    - echo COMMON_AWS_ACCESS_KEY_ID=`echo ${credentials} | jq -r .AccessKeyId` >> assume_role.env
    - echo COMMON_AWS_SECRET_ACCESS_KEY=`echo ${credentials} | jq -r .SecretAccessKey` >> assume_role.env
    - echo COMMON_AWS_SESSION_TOKEN=`echo ${credentials} | jq -r .SessionToken` >> assume_role.env
    - aws sts get-caller-identity
  artifacts:
    reports:
      dotenv: assume_role.env

plan:
  stage: plan
  script:
    - export AWS_ACCESS_KEY_ID=`echo ${COMMON_AWS_ACCESS_KEY_ID}`
    - export AWS_SECRET_ACCESS_KEY=`echo ${COMMON_AWS_SECRET_ACCESS_KEY}`
    - export AWS_SESSION_TOKEN=`echo ${COMMON_AWS_SESSION_TOKEN}`
    - aws sts get-caller-identity
  dependencies:
    - assume_role

クレデンシャルの取得について

作成したIAM RoleにAssume Roleを実施して、クレデンシャルを取得し、環境変数へ格納する部分だけを抜粋すると以下の部分になります。${ROLE_ARN}はGitLab CI/CDのValiablesにて管理されている変数となります。その他の変数については予めGitLab側で用意されているものですので、特段気をつける必要はありません。 結局のところ、AWS CLIで必要な情報を取得しているだけですね。

script:
    - >
      credentials=`aws sts assume-role-with-web-identity
      --role-arn ${ROLE_ARN}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token $CI_JOB_JWT_V2
      --duration-seconds 3600 | jq .Credentials`
    - export AWS_ACCESS_KEY_ID=`echo ${credentials} | jq -r .AccessKeyId`
    - export AWS_SECRET_ACCESS_KEY=`echo ${credentials} | jq -r .SecretAccessKey`
    - export AWS_SESSION_TOKEN=`echo ${credentials} | jq -r .SessionToken`

環境変数の継承について

Job間では基本的には環境変数は共通化されていません。そのため、Job1で設定した環境変数はJob2では利用できなくなっています。今回のクレデンシャルの場合、各Jobで都度取得してもいいのですが、せっかくなら継承していきたいと思いまして調べました。 まずは、環境変数を別のJobでも利用できるようにするめの格納からですが、該当コードは以下の部分となります。

    - echo COMMON_AWS_ACCESS_KEY_ID=`echo ${credentials} | jq -r .AccessKeyId` >> assume_role.env
    - echo COMMON_AWS_SECRET_ACCESS_KEY=`echo ${credentials} | jq -r .SecretAccessKey` >> assume_role.env
    - echo COMMON_AWS_SESSION_TOKEN=`echo ${credentials} | jq -r .SessionToken` >> assume_role.env
  artifacts:
    reports:
      dotenv: assume_role.env

artifacts以下の記述によって、envファイルが他のJobでも参照できるようになります。 そして、環境変数を参照する場合、その処理を記述しているのは以下のコードとなります。

  script:
    - export AWS_ACCESS_KEY_ID=`echo ${COMMON_AWS_ACCESS_KEY_ID}`
    - export AWS_SECRET_ACCESS_KEY=`echo ${COMMON_AWS_SECRET_ACCESS_KEY}`
    - export AWS_SESSION_TOKEN=`echo ${COMMON_AWS_SESSION_TOKEN}`
 dependencies:
    - assume_role

継承にはdependenciesキーワードを利用する方法とneedsキーワードを利用する方法の2パターンがあるようですが、今回は前者を利用しました。 詳細については以下の公式ドキュメントを参考にしてください。

gitlab-docs.creationline.com

さいごに

いかがでしたでしょうか。GitLab CI/CDを利用している方も多いのではないでしょうか。そういった方々へAWSリソースの構築の一助になれば幸いです。

GitHub Actionsの実行に向けたTerraformによるAWS IAM Roleの作成について

はじめに

GitHub ActionsにてAWSリソースをIaC(Terraform、AWS CDK等々)によって構築する際、従来はGitHub Actions用のIAM Userを作成して、権限を付与する方法が一般的であったかと思います。 しかしながら、現在はIAM Roleによる権限付与の方法が確立されました。このIAM Roleの作成をTerraformによってどのように記述するのかをポイントに本投稿を記載します。

TerraformによるIAM Roleの作成

GitHub Actions用のIAM Roleを作成する際に必要となるコンポーネントは以下の3つとなります。

  • IAM ID Provider
  • IAM Role
  • IAM Policy

    IAM ID Provider

    まずは、ID Providerを作成します。これにより、AWSの外部ユーザIDにアカウント内のAWSリソースに対するアクセス許可を与えることができます。

resource "aws_iam_openid_connect_provider" "github" {
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["a031c46782e6e6c662c2c87c76da9aa62ccabd8e"]
  url             = "https://token.actions.githubusercontent.com"
}

client_id_list は対象者もしくはaudienceとも呼ばれるものを指定します。 ここでは、sts.amazonaws.com と記述しています。 これは、GitHub Actionsで利用する actions/configure-aws-credentials@v1 の要求からくるものです。

thumprint_listOpenID Connect Providerがキーを利用できるようにするドメインで使用されるX.509証明書の16進エンコードされたSHA-1ハッシュ値です。 AWSマネジメントコンソールからID Providerを作成する際には、ProviderのURLを入力すると動的に設定してくれますが、今回はTerraformによる設定のため記述が必要になります。

IAM Role

先にID ProviderのTerraformコードができたので、次にIAM Roleを作成します。 このIAM Roleの信頼関係では、先のID ProviderからのAssume Roleを許可する必要があります。 また、特定のGitHubリポジトリからのGitHub Actionsのみを許可するための設定も必要となります。 これらの設定を反映したTerraformコードが以下となります。

resource "aws_iam_role" "github" {
  name = "GithubActionRole"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["sts:AssumeRoleWithWebIdentity"]
        Principal = {
          Federated = aws_iam_openid_connect_provider.github.arn
        }
        Condition = {
          StringLike = {
            "token.actions.githubusercontent.com:sub" = "repo:<GitHub Organization>/<Repository Name>:*"
          }
        }
      }
    ]
  })
}

特定のGitHubリポジトリからのGitHub Actionsのみを許可する設定は、以下の部分に該当します。

Condition = {
  StringLike = {
    "token.actions.githubusercontent.com:sub" = "repo:<GitHub Organization>/<Repository Name>:*"
  }
}

ただし、これだと特定の単一GitHubリポジトリのみが対象となります。 そのため、例えば複数のGitHubリポジトリを指定したい場合には配列による指定が可能です。

Condition = {
  StringLike = {
    "token.actions.githubusercontent.com:sub" = [
      "repo:<GitHub Organization>/<Repository Name A>:*",
      "repo:<GitHub Organization>/<Repository Name B>:*",
    ]
  }
}

また、特定のGitHub Organizationの任意のリポジトリを指定することも可能となります。

Condition = {
  StringLike = {
    "token.actions.githubusercontent.com:sub" = "repo:<GitHub Organization>/*:*"
  }
}

いずれにせよ、上記のような Condition句 の記載がない場合にはどのようなリポジトリからのGitHub Actionsも対象となってしまうのでご注意ください。

IAM Policy

先に作成したIAM Roleに付与するIAM Policyを作成します。つまり、GitHub Actionsに許可するPolicyを設定するということです。 IAM Policyを作成するためのTerraformコードについてはTerraformのドキュメントや他ブログなどでも詳細な記述があると思いますので、ここでは割愛します。

GitHub Actionsの実行について

最後に、GitHub Actionsにて先に作成したIAM RoleへどのようにAssume Roleするのかをyamlファイルで記載します。

name: 'Sample'
on:
  push:
    branches:
      - main
env:
  AWS_REGION: 'ap-northeast-1'
jobs:
  cdk:
    name: 'Sample Action'
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ secrets.ROLE_ARN }}
          aws-region: ${{ env.AWS_REGION }}
      - name: AWS STS Get Caller Identity
        run: aws sts get-caller-identity

今回のようにID Providerを利用する場合には、permission: 以下の内容がまずは必要となります。 そして、要の部分は aws-actions/configure-aws-credentials@v1 です。 このモジュールの引数として role-to-assumeaws-region が必要となります。 この role-to-assume は先に作成したIAM RoleのARNを指定します。 ここでは、GitHubのSecretsに該当ARNを設定しているため、それを呼び出す記述になっています。

さいごに

いかがだったでしょうか。最近ではこれらの内容を紹介するブログが増えているように感じますが、それぞれの設定などを理解するのに少々時間が掛かりました。 また、IAM Role関連の作成はCloudFormationでの紹介が多く、Terraformユーザに少しでも役に立てれば幸いです。

CloudWatch AlarmをAWS ChatbotによりSlackに通知する方法

はじめに

今回は表題通り、CloudWatch AlarmSNSAWS Chatbotを利用したSlack通知の実現方法を記載していきます。 私自身はIaC(Infrastructure as Code)としてはTerraformを利用します。ただし、現在TerraformはAWS Chatbotに対応しておりません。 そのため、AWS ChatbotだけはAWS マネジメントコンソールで作成していきます。また、通知先となるSlack Channelについてはすでに作成済みであることとします。

アーキテクチャ

f:id:ymyuta:20211204145251p:plain
CloudWatch AlarmからSlack ChannelへのAWS Chatbotを利用した通知

CloudWatch Alarmの作成

まずは、CloudWatch Alarmの作成となります。 ここでは、ALB(Application Loadbalancer)TargetgroupにおけるHealthyHostCountに対して、しきい値を設けていきます。 なお、Targetgroupでは1つのHost(ECSにおけるTask)が実行されている状況が正常とします。

resource "aws_cloudwatch_metric_alarm" "sample" {
  alarm_name          = "SampleAlarm"
  alarm_description   = "Sample Alarm Verify For Slack Notification"
  comparison_operator = "LessThanThreshold"
  evaluation_periods  = 1
  datapoints_to_alarm = 1
  metric_name         = "HealthyHostCount"
  namespace           = "AWS/ApplicationELB"
  dimensions = {
    "LoadBalancer" = "app/<alb_name>/exmaple8e4b2d09"
    "TargetGroup"  = "targetgroup/<targetgroup_name>/exampled7739b8e7"
  }
  period        = 60
  statistic     = "Average"
  threshold     = 1
  alarm_actions = [var.cloudwatch_alarm_sns_topic_arn] // 後ほど作成するSNS Topicに対するARNとなります。 
  ok_actions    = [var.cloudwatch_alarm_sns_topic_arn] // 後ほど作成するSNS Topicに対するARNとなります。 
}

上記は、該当のCloudWatch Alarmを作成する上でのTerraformコードになります。ここで重要なポイントにしぼって説明します。

対象となるCloudWatch Metricsの指定方法

今回は先述の通り、対象のCloudWatch MetricsはALB(Application Loadbalancer)TargetgroupにおけるHealthyHostCountとなります。 これらを指定するのに必要な設定値としては、namespacedimensionsmetric_nameです。

しきい値の指定方法

しきい値を指定する設定はthresholdcomparison_operatorになります。 正常なHost数は1であるため、Host数が1未満となったら異常状態とするために、comparison_operatorはLEssThanThresholdとしています。

SNSとの連携

CloudWatch Alarmが取り得る状態としては、異常(Alarm)正常(OK)No Dataの3種類です。 それぞれの状態に遷移した際に、SNSへトピックを発行することができます。 状態ごとに発行先のSNSを指定することができますが、今回はすべて同じSNSを指定しています。 Terraformコードでは対象SNSのARNを記述することになります。

SNSの作成

CloudWatch Alarmがトピックを発行するためのSNSを作成します。

resource "aws_sns_topic" "sample" {
  name = "cloudwatch-alarm-topic"
}

resource "aws_sns_topic_policy" "sample" {
  arn = aws_sns_topic.sample.arn
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["sns:Publish"]
        Principal = {
          Service = "cloudwatch.amazonaws.com"
        }
        Resource = aws_sns_topic.sample.arn
        Condition = {
          ArnLike = {
            "aws:SourceArn" = "arn:aws:cloudwatch:<region>:<account_id>:alarm:<alarm_name>"
          }
        }
      }
    ]
  })
}

AWS Chatbotの作成

AWS Chatbotの設定については先述の通りAWS マネジメントコンソールにて実施していきます。 まずは、チャットクライアントの設定にてSlackを指定します。

SlackのPrivate Channelにおける対応について

ひとつだけ、対象のSlack ChannelがPublicの場合には設定はAWS Chatbotのみで完結します。 ただし、Private Channelの場合には対象のChannelに対してAWSユーザをInviteする必要があります。

f:id:ymyuta:20211205144847p:plain
AWS Chatbotにおけるチャットクライアントの設定
f:id:ymyuta:20211205144929p:plain
チャットクライントにおけるSlackの指定
設定を実施すると、Slackへのアクセス許可を求められるので、問題なければ承認を実施します。 問題無く連携が完了したら、新たなChannelを追加することで連携することができます。

さいごに

いかがだったでしょうか。シンプルな内容で学びもそれほど多くはないかもしれませんが、備忘のために記載しました。 引き続き、よろしくお願い致します。

This is Leanを読んで~その2~

はじめに

前回の投稿では、This is Leanを読んで~その1~と題して、リソース効率とフロー効率の概要をScrumの文脈で書いていきました。 今回はリソース効率におけるパフォーマンスへの影響を挙げ、フロー効率との完全なる両立が困難な理由を書いていければと思います。

リソース効率におけるパフォーマンスへの影響

まずは前回の投稿でのリソース効率について簡単に振り返ります。 Scrumを例にとった場合に、リソース効率を高めようとすると以下の図のような状態が予想されます。

f:id:ymyuta:20210923144016p:plain
リソース効率による状態
つまり、開始から完了までの時間が徐々に長くなる、また複数Itemに対するタスクが並列で処理されていくなどの事象が発生します。 これらの事象がパフォーマンスにどのように影響していくかを書いていきます。

長いスループット時間の影響

今までは開始から完了までの時間と書いていましたが、これをスループット時間と言います。 スループット時間とは、フローユニットに対する処理が開始してから完了するまでの時間を指します。 Scrumにおいては、ひとつのPBIをフローユニットといい、そのPBIへの処理が開始されてから完了するまでをスループット時間と呼ぶこととなると思います。 完了が何を指すのかは、Scrumチームにおける完了の定義(Definition of Done)によると思いますが、今回の投稿ではプロダクトを利用しているユーザに対して、PBIによる機能がリリースされたこととします。

スループット時間が長くなるとはどのようなことを意味するのでしょうか。 例えば、開発開始からリリースまでの時間が長くなります。すると、リリース対象の実装がどのようなものだったのかを思い出すことが必要になってくるかもしれません。 この思い出す作業が発生することにより、副次的なタスクとして、リリース対象の実装を別途ドキュメントとして書き出しておいたりといったものが追加される可能性もあります。 このような本来必要のないニーズ(上記の例でいえば、思い出す作業をスムーズにする)といったものを、本書では二次ニーズと呼び、スループット時間が長くなることで二次ニーズが発生しやすくなると書いてあります。 そして、このような二次ニーズにより不要なタスクが発生することも示唆しています。

不要なタスクが発生することで、本来注力すべきタスクに割く時間が減少してしまうのは、Scrumチームのパフォーマンス低下に結びつくのではないでしょうか。

多すぎるフローユニットの影響

リソース効率を高めようとした際には、上図からもわかるように、各engineerに対してフローユニットに関連するタスクに連続的に取り組んでいかなければなりません。つまり、フローユニットが多くなるのが常です。 そのため、Scrumチーム内で様々フローユニットに対するタスクが並列で実施されている状態となります。このような状態において発生する事象はどのようなものがあるでしょうか。

例えば、各engineerが並列するタスクにおいて、ひとつのGit Repositoryの各々のブランチで作業を実施していたとします。そのような場合にはコンフリクトやリベース作業などが発生しやすくなります。 コンフリクトの解消やリベース作業は本来不要なタスクだったかもしれません。並列するタスクを実施することにより、ムダなタスクが発生する可能性が高まることになります。 また、あるengineerが別のengineerが実施したタスクに対して質問したとします。しかし、質問されたengineerは現在はまた別のタスクを実施しており、その質問を答えるために頭の切り替えをしなければならなくなります。 このように、スイッチングコストが高まる可能性もでてきてしまいます。

つまり、フローユニットが多くなると、長いスループット時間の影響と同様にムダなタスクが発生することに加えて、スイッチングコストが高まることによるパフォーマンス低下が生まれてしまうかもしれません。

リソース効率とフロー効率の両立は困難

上記ではリソース効率を高めることで発生し得るパフォーマンスの低下について書きました。 これらの原因としては、長いスループット多すぎるフローユニットなどが挙げられます。 この原因を解消するためのアプローチがフロー効率を高めることとなります。 そのため、フロー効率を高めようとすると必然的にリソース効率は低くなるのです。

f:id:ymyuta:20211004090947p:plain
リソース効率とフロー効率のマトリックス
上図のように、理想はリソース効率とフロー効率がお互いに高い星印の部分にチームの効率を近づけようとする。しかしながら、それぞれの効率における両立は理論上困難なため、現実的には点線で記載してある部分を目指します。

さいごに

いかがでしたでしょうか。リソース効率を高めた際の影響については、読んでいただいた皆さまにも覚えがあることだったではないでしょうか。 また、リソース効率を高めた際のパフォーマンス低下を避けるための方法としてのフロー効率についても書きました。これによって、リソース効率とフロー効率の両立が困難なことも記載しました。