Slide 1

Slide 1 text

はじめてのIssueOps GitHub Actions で実現するコメント駆動オペレーション ノムラトモキ(@tmknom ) 1

Slide 2

Slide 2 text

ノムラトモキ(@tmknom ) フリーランス・GitHub CI/CD 実践ガイド著者・GitHub Stars 2

Slide 3

Slide 3 text

アジェンダ 1. IssueOps 概要 2. IssueOps の基本構造 3. IssueOps を使いやすくする設計 4. IssueOps の長期運用に向けた工夫 5. まとめ 3

Slide 4

Slide 4 text

IssueOps 概要 4

Slide 5

Slide 5 text

IssueOps とは? GitHub のコメントから、オペレーションを実行する仕組み ChatOps のような体験を、プルリクエストやIssue 上で提供する コメントを投稿するだけで、誰でもすぐに使える! GitHub Actions の標準機能だけで実現可能 5

Slide 6

Slide 6 text

ユースケース①:アプリケーションのデプロイ /deploy dev とコメントするだけで開発環境へデプロイ 本番に近い環境で、マージ前に動作確認できる 6

Slide 7

Slide 7 text

ユースケース②:Infrastructure as Code /apply dev とコメントするだけでTerraform を実行 レビュー前に、Apply でエラーが起きないか確認できる 7

Slide 8

Slide 8 text

IssueOps のメリット オペレーションの属人化を抑止 環境構築なしに、コメントするだけで誰でも実行可能 コード(プルリクエスト)とオペレーションが紐づく オペレーション実行時のコンテキストが明確に ログが共有されるため、問題発生時にチームでデバッグしやすい GitHub だけでオペレーションが完結 想像以上に心地よい体験を提供し、とくにIaC との相性は抜群 8

Slide 9

Slide 9 text

IssueOps の基本構造 9

Slide 10

Slide 10 text

ワークフローの全体像 コメントとして投稿されるコマンドで、オペレーションを実行 1. issue_comment : コメントでワークフローを発火するイベント 2. Parser: コメントに含まれるコマンドをパース 3. Worker: 任意のオペレーションを実行 10

Slide 11

Slide 11 text

1. issue_comment : トリガーの設定 GitHub へのコメント投稿を起点に、ワークフローを起動する on: # ワークフローのトリガーを設定 issue_comment: # デフォルトでは編集や削除でも発火 types: [created] # 新規投稿でのみ発火するよう、最低限のフィルタリング issue_comment イベントの注意点 プルリクエストとIssue のコメントを、区別できない トリガーの設定では、コメント本文でフィルタリングできない 11

Slide 12

Slide 12 text

2. Parser: コマンドのパース コメントに含まれる「コマンド」を解析し、パラメータを抽出 - id: parser env: # 環境変数へコメント本文をセット COMMENT: ${{ github.event.comment.body }} # 複数行の場合がある点に留意 run: | command="$(head -n 1 <<<"${COMMENT}" | tr -d '\r\n')" # コメント1行目のみ使用 IFS=$' ' read -ra tokens <<<"${command#/}" # "/"除去後、スペース区切りで分割 echo "operation=${tokens[0]}" >> "${GITHUB_OUTPUT}" # 操作名(例: plan) echo "environment=${tokens[1]}" >> "${GITHUB_OUTPUT}" # 環境名(例: dev) 例: /plan dev → operation= plan, environment= dev と抽出 コマンド体系(/plan dev の部分)は自由に設計 12

Slide 13

Slide 13 text

3. Worker: オペレーションの実行 パラメータを受け取り、任意のオペレーションを実行 - id: worker env: # Parserで抽出したパラメータを環境変数へセット OPERATION: ${{ steps.parser.outputs.operation }} ENVIRONMENT: ${{ steps.parser.outputs.environment }} run: | # 受け取ったパラメータを使って、自由にスクリプトを記述 terraform -chdir="stacks/${ENVIRONMENT}" "${OPERATION}" 例: /plan dev → terraform -chdir=stacks/dev plan を実行 Terraform だけでなく、他の処理も自由に実装可能 13

Slide 14

Slide 14 text

IssueOps を使いやすくする設計 14

Slide 15

Slide 15 text

使いやすさを向上させる3 つのポイント 1. 無駄なジョブ実行の抑制 必要なコマンドでのみ起動し、コストを最小限に抑えよう 2. コメントした人へのフィードバック 開始時や終了時に状況を伝え、利用者に安心感を与えよう 3. ブランチの自動切り替え コメント時点のブランチで実行し、直感的な挙動を実現しよう 15

Slide 16

Slide 16 text

1. 無駄なジョブ実行の抑制 16

Slide 17

Slide 17 text

見落としがちなGitHub Actions の課金ルール ワークフローの実行時間による従量課金 1 秒でも動くと、課金対象の実行時間は分単位で計上される 例: 1 秒のジョブを毎日100 回実行 → 毎月3000 分が計上 17

Slide 18

Slide 18 text

無に課金される問題 コメントのたびに、課金対象の実行時間が積み上がる! 1. プルリクエストやIssue で、普通にコミュニケーション 大半のコメントは、IssueOps と無関係 2. しかし、すべてのコメントでワークフローが起動 issue_comment イベントは、無関係のコメントでも発火 3. 無意味なワークフローの起動で、実行時間が分単位で加算 GitHub は笑顔になり、我々は真顔になる 18

Slide 19

Slide 19 text

無関係なジョブをスキップする 「最初のジョブ」で、コメント本文による条件分岐を定義しよう すべてのジョブをスキップできれば、課金がゼロになる IssueOps 用のコマンドに、命名規則を導入しよう 例: コマンドは「 / で始める」と決め、それをチェックする jobs: dispatch: # コメントが「/」で始まる場合のみジョブを実行し、それ以外はスキップ if: ${{ startsWith(github.event.comment.body, '/') }} 19

Slide 20

Slide 20 text

2. コメントした人へのフィードバック 20

Slide 21

Slide 21 text

プルリクエストページの挙動(理想形) pull_request イベントなら、ステータスチェックで状態を確認可能 IssueOps でも望まれるプルリクエストページの挙動 21

Slide 22

Slide 22 text

不安にさせる issue_comment イベントの挙動 issue_comment イベントは、PR ページへのフィードバックがない コメントしても「無反応」で、本当に動いているか不安になる 22

Slide 23

Slide 23 text

不安を解消する3 つのGitHub API GitHub API 情報量 概要 ステータスチェック ○ ワークフローの成功・失敗・実行中を PR ページ下部に表示 リアクション △ ワークフロー起動時などに 絵文字で最低限のフィードバック コメント投稿 ◎ 実行結果やエラー詳細などを ログページへ行き来せずに把握可能 各GitHub API はそれぞれ情報量が異なる フィードバックしたい情報の重要度に応じて使い分ける 23

Slide 24

Slide 24 text

コメントした人へのフィードバック例 起動時にリアクションで合図し、終了時に結果をコメントで投稿 24

Slide 25

Slide 25 text

実装例(リアクションの場合) 各種GitHub API の実行には、GitHub CLI の利用が手軽 # Reaction APIを実行し、コメントへ絵文字でリアクションする - env: COMMENT_ID: ${{ github.event.comment.id }} GITHUB_TOKEN: ${{ github.token }} run: | set -x gh api --method POST \ -f content="eyes" \ # 絵文字はココで切り替え "/repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}/reactions" ※ GitHub CLI はランナーにデフォルトでインストールされているため、すぐに使える 25

Slide 26

Slide 26 text

3. ブランチの自動切り替え 26

Slide 27

Slide 27 text

なぜブランチを自動で切り替えるのか? 利用者は「コメントした時の状態」で実行されると期待 PR がオープン状態なら → プルリクエストブランチで実行 PR がマージ済みなら → デフォルトブランチで実行 利用者の直感に沿う挙動にしよう 無用な混乱やトラブルを防ぎ、心地よい体験を提供する 27

Slide 28

Slide 28 text

ブランチ切り替えのメリット 「動くかどうか分からないけど、とりあえずマージ」の抑制 プルリクエスト段階での検証が簡単になる コードレビューなどによる手戻りを削減できる とくに自動テストが難しい領域で役立つ IaC: 実際にApply し、エラーが発生しないか確認 E2E テスト: システム全体の挙動をマージ前に確認 28

Slide 29

Slide 29 text

PR の状態に応じてブランチを切り替える例 PR が「オープン状態」なら、そのPR ブランチでチェックアウト - id: branch env: PULL_REQUEST: ${{ github.event.issue.number }} # プルリクエスト番号を取得 run: | # プルリクエストの「状態」と「ブランチ名」をGitHub CLIで取得 json="$(gh pr view "${PULL_REQUEST}" --json state,headRefName)" # プルリクエストが「オープン状態」の場合、プルリクエストブランチを使う if [[ "$(jq -r .state <<<"${json}")" == "OPEN" ]]; then branch="$(jq -r .headRefName <<<"${json}")" fi # プルリクエストがマージ済みまたはクローズ済みの場合は、mainブランチを使う(後続のステップでは、この値でチェックアウト) echo "target=${branch:-main}" >> "${GITHUB_OUTPUT}" ※ スペースの都合から、actions/checkout アクションの呼び出し部分は省略しています 29

Slide 30

Slide 30 text

IssueOps の長期運用に向けた工夫 30

Slide 31

Slide 31 text

安定した運用を実現する3 つのポイント 1. コマンド体系はシンプルに 利用者にとって使いやすく、覚えやすいコマンドを目指そう 2. Parser とWorker を別々のワークフローに 役割ごとにワークフローを分け、メンテナンス性を向上させよう 3. セキュリティ対策は徹底的に 本番環境でも安全に使える仕組みを用意しよう 31

Slide 32

Slide 32 text

コマンド体系はシンプルに 複雑なコマンドを提供しても、結局使われなくなってしまう 覚えやすさを重視し、入力する単語数を増やしすぎない 単語数は3 〜4 個ぐらいに留めよう(例: /plan dev app ) 大量のコマンドを一気に導入せず、利用者の慣れを待つ 本当に必要な、少数のコマンドだけ提供しよう ヘルプコマンド(例: /help )の提供もオススメ 利用者の自己解決を促そう 32

Slide 33

Slide 33 text

Parser とWorker を別々のワークフローに ワークフローを用途別に分離すると、メンテナンス性が格段に上がる Worker はユースケース単位での分離もオススメ ログも分離されるため、問題発生時のデバッグがしやすい 33

Slide 34

Slide 34 text

セキュリティ対策は徹底的に IssueOps は利便性が高い反面、セキュリティにも配慮が必要 基本的なセキュリティ対策を漏れなく実施しよう インジェクション対策・最小権限・OIDC など 本番環境向けのガードレールを導入し、安全な運用を実現しよう 必ずデフォルトブランチのコードを利用する Environments のデプロイメントプロテクションルールを導入する 詳細は書籍「GitHub CI/CD 実践ガイド」の15 章を参考にしよう 静的解析ツール「actionlint 」 「ghalint 」なども活用する 34

Slide 35

Slide 35 text

まとめ 35

Slide 36

Slide 36 text

本日学んだこと IssueOps はGitHub のコメントから、オペレーションを実行する 属人化を抑制し、開発効率を向上させる IssueOps を使いやすくする3 つの工夫 ジョブ実行の抑制・フィードバック・ブランチの自動切替 まずは開発環境などで小さくはじめよう IssueOps の心地よさを、ぜひ体感してみてほしい! 36

Slide 37

Slide 37 text

ご清聴ありがとうございました 37