【GitHub Actions】TerraformでデプロイするCI/CDパイプラインの構築手順
公開日時:2022年09月11日 / 最終更新日時:2022年09月24日
GitHub でソースコードを管理しているとして、複数人で Terraform を利用する場合、それぞれが terraform plan、terraform apply コマンドを実行することになります。
今回は GitHubActions を利用して、Terraform でデプロイをする CI/CD パイプライン環境を構築したので解説します。
GitHub Actions を選んだ理由
GitHub でソースコードを管理している。
terraform plan、terraform apply コマンドを実行するだけのシンプルなフロー。
月2,000分までは無料で使える。
AWS CodeCommit、AWS CodeBuild、AWS Pipeline で構成すると複雑で属人化しそう。
ざっくりとした流れ
ざっくりとした流れは以下のようになるかと思います。
それぞれがローカルでブランチを切ってコードを作成していきます。
そしてリモートブランチにコミット・プッシュします。
コミットしたコードをmainブランチにプルリクを出すところから CI/CD が稼働します。
一度レビュアーのチェックを入れて承認をさせたいので、プルリクの段階で terraform plan コマンドを実行してコメントとして残します。
(terraform plan コマンドの結果を特にコメントとして残さなくてもいいですが、レビュアーがわざわざコードを見たり terraform plan の結果をいろんなページを廻って閲覧するのは面倒かなと思ってコメントにまとめた方がいいかと思いました。)
レビュアーがレビューして問題なければmainブランチにマージをします。マージをすると自動的に terraform apply が実行されます。
ただ terraform の場合、terraform plan が OK でも terraform apply でエラーになることがあるので、そこをどうするか。
フロー図
構成図としては以下のようになると思います。
各ブランチにプッシュし、レビュアーがレビューして問題なければ main ブランチにマージする。マージすると自動的に terraform apply コマンドを実行され、AWS 上にリソースがデプロイされるという構成です。
GitHubの公式サイトには以下のフロー図があります。
https://learn.hashicorp.com/tutorials/terraform/github-actions
GitHub Actionsの料金
GitHub Actions はプライベートリポジトリの場合は 1か月 2,000分までは無料 で使えます。
1か月を20営業日と計算すると、1日あたり 100分(1時間40分)使える計算になります。
1デプロイ1分と計算すると、1日100デプロイが無料でできる計算となります。
そこそこの企業で利用してもなんとか無料枠で行ける範囲となりますでしょうか。
まずはシンプルなサンプルワークフローを試す
まずは GitHub Actions のシンプルなサンプルワークフローを試してみます。
新規の GitHub リポジトリを作成する
GitHub にログインしてリポジトリの画面に移動し「New」 ボタンをクリックします。
「Create new repository」 画面で下図のように設定します。
最初に「Add .gitignore」 で .gitignore ファイルを追加しておくことをお勧めします。
設定に問題がなければ下にスクロールして「Create repository」 ボタンをクリックします。
リポジトリが作成されることを確認します。
ローカルにリポジトリをクローンする
次にローカル(私の場合は Cloud9)にリポジトリをクローンします。
■ローカルにリポジトリをクローンする
$ git clone git@github.com:xxxxxxx/test_demo.git
Cloning into 'test_demo'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
■リポジトリの確認
$ ls -l | grep test_demo
drwxrwxr-x 3 ec2-user ec2-user 36 Sep 11 15:02 test_demo
■リポジトリの確認
$ cd test_demo/
$ ls -la
total 4
drwxrwxr-x 3 ec2-user ec2-user 36 Sep 11 15:02 .
drwxrwxr-x 6 ec2-user ec2-user 69 Sep 11 15:02 ..
drwxrwxr-x 8 ec2-user ec2-user 163 Sep 11 15:02 .git
-rw-rw-r-- 1 ec2-user ec2-user 716 Sep 11 15:02 .gitignore
シンプルな GitHub Actions を作成する
ここまで来たらデモ用のシンプルな GitHub Actions のワークフローを作って動かしてみます。
「Actions」 をクリックします。
「set up a workflow yourself」 をクリックします。
ファイル名(/.github/workflows/test_demo.yml)を入力し「Start commit」 ボタンをクリックします。
ソースコードはデフォルトのままです。
以下のように .github/workflows ディレクトリに「test_demo.yml」 ファイルが作成されることを確認します。
ちなみに GitHub Actions のサンプルソースコード「test_demo.yml」 ファイルの中身は以下のようになっています。
■デモ用のソースコード(デフォルトのまま)
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3
# Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world!
# Runs a set of commands using the runners shell
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.
コードの内容は main ブランチに push か pull request を実行すると GitHub Actions のワークフローが自動的に実行されます。
実行されると echo コマンドで「Hello word!」 が出力されます
ブランチを切ってコードを作成し git commit git push をする
次にブランチを切ってテスト用コードを作成し git commit、git push をします。
まずは最初に git pull を実行します。
■git pull を実施
$ git pull
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (5/5), 1.28 KiB | 657.00 KiB/s, done.
From github.com:xxxxxxxx/test_demo
fdb7857..402c5b3 main -> origin/main
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/ demo_20220911
■ブランチを切ってコードを作成しリモートリポジトリに push まで実行する
(main) $ git branch demo_20220911
(main) $ git checkout demo_20220911
Switched to branch 'demo_20220911'
(demo_20220911) $ touch test.txt
(demo_20220911) $ echo "test" > test.txt
(demo_20220911) $ cat test.txt
test
(demo_20220911) $ ls
test.txt
sasagawam@gmail.com:~/environment/test/test_demo (demo_20220911) $ git status
On branch demo_20220911
Untracked files:
(use "git add ..." to include in what will be committed)
test.txt
nothing added to commit but untracked files present (use "git add" to track)
(demo_20220911) $ git add .
(demo_20220911) $ git status
On branch demo_20220911
Changes to be committed:
(use "git restore --staged ..." to unstage)
new file: test.txt
(demo_20220911) $ git commit -m "demo_01"
[demo_20220911 1603f9a] demo_01
Committer: EC2 Default User <ec2-user@ip-172-31-44-157.ap-northeast-1.compute.internal>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:
git config --global user.name "Your Name"
git config --global user.email you@example.com
After doing this, you may fix the identity used for this commit with:
git commit --amend --reset-author
1 file changed, 1 insertion(+)
create mode 100644 test.txt
(demo_20220911) $ git push origin demo_20220911
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 314 bytes | 314.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:xxxxxxxxx/test_demo.git
fdb7857..1603f9a demo_20220911 -> demo_20220911
この段階ではまだブランチ(demo_20220911 )上に push しているだけなので GitHub Actions は反応しません。
main ブランチにマージして GitHub Actions のワークフローを実行する
ここまで環境が出来上がったら次に main ブランチにマージして GitHub Actions のワークフローを実行してみます。
「Pull request」 をクリックして「New pull request」 ボタンをクリックします。
ブランチを選択して「Create pull request」 ボタンをクリックします。
必要ならコメントを記載し「Create pull request」 ボタンをクリックします。
GitHub Actions のワークフローが実行されたことを確認します。
Hello Worldが表示されていることを確認します。
以上が、GitHub Actions の一番最初のサンプルコード実行でした。
OIDC を作成する
次に Terraform の CI/CD パイプラインを構築する前に事前準備をします。
今回は AWS 環境でリソースをデプロイします。
セキュリティを考慮して AWS のアクセスキーとシークレットアクセスキーを使わずに GitHub Actions から AWS 認証をして AWS API へセキュアにリクエストをする為に OIDC を作成します。
OIDC は Terraform で作成します。
■OIDC 作成のコード
$ vi iam.tf
#============================================================================
# Github Actions 用ロール
#============================================================================
# -----------------------------------------------------------------------------
# GitHub Actions プロバイダー設定
# -----------------------------------------------------------------------------
resource "aws_iam_openid_connect_provider" "terra_cicd_demo" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
# このコードは固定値
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
# -----------------------------------------------------------------------------
# GitHub Actions 用ロール作成
# -----------------------------------------------------------------------------
resource "aws_iam_role" "terra_cicd_demo_oidc_role" {
name = "TerraCICDDemoOIDCRole"
path = "/"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRoleWithWebIdentity"
Principal = {
Federated = aws_iam_openid_connect_provider.terra_cicd_demo.arn
}
Condition = {
StringLike = {
"token.actions.githubusercontent.com:sub" = [
# リポジトリ制限
# リポジトリに複数のブランチを作成している場合は特定のブランチを絞ることができる。リスト化もできる。
"repo:xxxxx/test_demo:ref:refs/heads/demo_20220911",
]
}
}
}]
})
}
# -----------------------------------------------------------------------------
# ポリシーのアタッチ(AdministratorAccess_attachment)
# -----------------------------------------------------------------------------
resource "aws_iam_role_policy_attachment" "AdministratorAccess_attachment" {
role = aws_iam_role.terra_cicd_demo_oidc_role.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
ロール名を「TerraCICDDemoOIDCRole」 にしてポリシー「AdministratorAccess」 を割り当てます。
今回は IAM ロールを作成するので「AdministratorAccess」 を割り当てましたが、適宜必要最低限のポリシーを割り当てます。
6938fd4d98bab03faadb97b34396831e3780aea1 はどこから来た数値なのか?
6938fd4d98bab03faadb97b34396831e3780aea1 の数値は何でしょうか?
調べてみると OIDC ID プロバイダーのサムプリントのようです。
GitHub Actions – Update on OIDC based deployments to AWS
https://github.blog/changelog/2022-01-13-github-actions-update-on-oidc-based-deployments-to-aws/
OpenID Connect ID プロバイダーのサムプリントの取得
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html
初期段階で作成した terraform の各 tf ファイル
以下のように各 tf ファイルを作成します。
■main.tf ファイル
provider "aws" {
region = "ap-northeast-1"
}
■terraform.tf ファイル
terraform {
backend "s3" {
bucket = "terraform-tfstate-file-demo"
key = "terraform.tfstate"
region = "ap-northeast-1"
}
}
■iam.tf ファイル
#============================================================================
# Github Actions 用ロール
#============================================================================
# -----------------------------------------------------------------------------
# GitHub Actions プロバイダー設定
# -----------------------------------------------------------------------------
resource "aws_iam_openid_connect_provider" "terra_cicd_demo" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
# このコードは固定値
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
# -----------------------------------------------------------------------------
# GitHub Actions 用ロール作成
# -----------------------------------------------------------------------------
resource "aws_iam_role" "terra_cicd_demo_oidc_role" {
name = "TerraCICDDemoOIDCRole"
path = "/"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRoleWithWebIdentity"
Principal = {
Federated = aws_iam_openid_connect_provider.terra_cicd_demo.arn
}
Condition = {
StringLike = {
"token.actions.githubusercontent.com:sub" = [
# リポジトリ制限
# リポジトリに複数のブランチを作成している場合は特定のブランチを絞ることができる。リスト化もできる。
"repo:xxxxx/test_demo:ref:refs/heads/demo_20220911",
]
}
}
}]
})
}
# -----------------------------------------------------------------------------
# ポリシーのアタッチ(AdministratorAccess_attachment)
# -----------------------------------------------------------------------------
resource "aws_iam_role_policy_attachment" "AdministratorAccess_attachment" {
role = aws_iam_role.terra_cicd_demo_oidc_role.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
terraform init コマンドを実行する
各 tf ファイルが準備出来たところで terraform init コマンドを実行してみます。
■terraform init コマンド実行
$ terraform init
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v4.30.0...
- Installed hashicorp/aws v4.30.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
terraform plan コマンドを実行する
terraform plan コマンドを実行してみます。
■terraform plan コマンド実行
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
+ create
Terraform will perform the following actions:
# aws_iam_openid_connect_provider.terra_cicd_demo will be created
+ resource "aws_iam_openid_connect_provider" "terra_cicd_demo" {
+ arn = (known after apply)
+ client_id_list = [
+ "sts.amazonaws.com",
]
+ id = (known after apply)
+ tags_all = (known after apply)
+ thumbprint_list = [
+ "6938fd4d98bab03faadb97b34396831e3780aea1",
]
+ url = "https://token.actions.githubusercontent.com"
}
# aws_iam_role.terra_cicd_demo_oidc_role will be created
+ resource "aws_iam_role" "terra_cicd_demo_oidc_role" {
+ arn = (known after apply)
+ assume_role_policy = jsonencode(
{
+ Statement = [
+ {
+ Action = "sts:AssumeRoleWithWebIdentity"
+ Condition = {
+ StringLike = {
+ "token.actions.githubusercontent.com:sub" = [
+ "repo:xxxxx/test_demo:ref:refs/heads/demo_20220911",
]
}
}
+ Effect = "Allow"
+ Principal = {
+ Federated = "arn:aws:iam::xxxxxxxx:oidc-provider/token.actions.githubusercontent.com"
}
},
]
+ Version = "2012-10-17"
}
)
+ create_date = (known after apply)
+ force_detach_policies = false
+ id = (known after apply)
+ managed_policy_arns = (known after apply)
+ max_session_duration = 3600
+ name = "TerraCICDDemoOIDCRole"
+ name_prefix = (known after apply)
+ path = "/"
+ tags_all = (known after apply)
+ unique_id = (known after apply)
+ inline_policy {
+ name = (known after apply)
+ policy = (known after apply)
}
}
# aws_iam_role_policy_attachment.AdministratorAccess_attachment will be created
+ resource "aws_iam_role_policy_attachment" "AdministratorAccess_attachment" {
+ id = (known after apply)
+ policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
+ role = "TerraCICDDemoOIDCRole"
}
Plan: 3 to add, 0 to change, 0 to destroy.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run
"terraform apply" now.
terraform apply コマンドを実行する
terraform plan で問題がなければ terraform apply コマンドを実行します。
■terraform apply コマンド実行
エラーがなければロールが作成されていることを確認します。
すでにOIDCプロバイダが存在していてエラーになった場合
すでに OIDC プロバイダが他のタイミングで作成されていて存在している場合は以下のようなエラーになります。
■エラー
╷
│ Error: error creating IAM OIDC Provider: EntityAlreadyExists: Provider with url https://token.actions.githubusercontent.com already exists.
│ status code: 409, request id: 4b363ff7-928c-41b2-80b5-xxxxxxx
│
│ with aws_iam_openid_connect_provider.terra_cicd_demo,
│ on iam.tf line 7, in resource "aws_iam_openid_connect_provider" "terra_cicd_demo":
│ 7: resource "aws_iam_openid_connect_provider" "terra_cicd_demo" {
│
╵
その場合は既存のOIDCプロバイダを直接記載して再度実行します。
IAMダッシュボードより「ID プロバイダ」 を選択します。
対象のIDプロバイダを選択します。
下図の OIDC プロバイダの ARN をコピーします。
更に以下のように OIDC プロバイダの部分をコメントアウトします。
■修正後のコード
#============================================================================
# Github Actions 用ロール
#============================================================================
# -----------------------------------------------------------------------------
# GitHub Actions プロバイダー設定
# -----------------------------------------------------------------------------
/*
resource "aws_iam_openid_connect_provider" "terra_cicd_demo" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
# 固定値
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
*/
# -----------------------------------------------------------------------------
# GitHub Actions 用ロール作成
# -----------------------------------------------------------------------------
resource "aws_iam_role" "terra_cicd_demo_oidc_role" {
name = "TerraCICDDemoOIDCRole"
path = "/"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRoleWithWebIdentity"
Principal = {
#Federated = aws_iam_openid_connect_provider.terra_cicd_demo.arn
Federated = "arn:aws:iam::xxxxxxxx:oidc-provider/token.actions.githubusercontent.com"
}
Condition = {
StringLike = {
"token.actions.githubusercontent.com:sub" = [
# リポジトリ制限
"repo:xxxxxx/test_demo:*",
]
}
}
}]
})
}
# -----------------------------------------------------------------------------
# ポリシーのアタッチ(AdministratorAccess_attachment)
# -----------------------------------------------------------------------------
resource "aws_iam_role_policy_attachment" "AdministratorAccess_attachment" {
role = aws_iam_role.terra_cicd_demo_oidc_role.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
再度 terraform apply を実行してエラーにならないことを確認します。
■再度 terraform apply コマンドを実行する
以上で、GitHub Actions から AWS に対して構築・設定作業が実行できる権限を持ったロールが作成されました。
GitHub Actions より Terraform コマンドを実行する環境を構築する
次にいよいよ GitHub Action より Terraform のコマンド(init, plan, apply)を実行する環境を構築します。
リポジトリを作成する
GitHub Actions から terraform コマンドを実行するためのリポジトリを作成します。
今回はすでに作成してある test_demo リポジトリを流用します。
新しいブランチを作成する
terraform コマンドを実行する環境を構築するために新しいブランチを切ります。
■新しいブランチを作成
(main) $ git pull
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (2/2), 699 bytes | 699.00 KiB/s, done.
From github.com:xxxx/test_demo
402c5b3..9d78560 main -> origin/main
Updating fdb7857..9d78560
Fast-forward
.github/workflows/test_demo.yml | 36 ++++++++++++++++++++++++++++++++++++
.terraform.lock.hcl | 21 +++++++++++++++++++++
iam.tf | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
main.tf | 3 +++
terraform.tf | 7 +++++++
5 files changed, 116 insertions(+)
create mode 100644 .github/workflows/test_demo.yml
create mode 100644 .terraform.lock.hcl
create mode 100644 iam.tf
create mode 100644 main.tf
create mode 100644 terraform.tf
(main) $ git branch demo_test_20220918
(main) $ git checkout demo_test_20220918
Switched to branch 'demo_test_20220918'
(demo_test_20220918) $
デモ用の tf ファイルを作成する
デモ用の tf ファイルを作成します。
EC2 インスタンス構築の tf ファイルを作成します。
■デモ用の EC2 インスタンス作成用 tf ファイル
$ vi demo-ec2.tf
resource "aws_instance" "demo-ec2" {
ami = "ami-0f36dcfcc94112ea1"
instance_type = "t2.micro"
subnet_id = "subnet-01890002cc54da77b"
tags = {
Name = "demo-ec2-01"
}
}
terraform plan 用のファイルを作成する
terraform plan コマンド用のファイルを作成します。
■terraform_plan.ymlの内容
$ vi terraform_plan.yml
name: TerraformPlan
on:
pull_request:
branches:
- main
env:
TF_VERSION: 1.1.2
AWS_DEFAULT_REGION: ap-northeast-1
AWS_ROLE_ARN: arn:aws:iam::xxxxxxxx:role/TerraCICDDemoOIDCRole
permissions:
id-token: write
contents: read
actions: read
pull-requests: write
jobs:
Terraform_plan_and_Comment:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
# リポジトリのチェックアウトをする。
- name: Check out repository code
uses: actions/checkout@v3
# OICDでAssumeRoleをする。
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_DEFAULT_REGION }}
role-to-assume: ${{ env.AWS_ROLE_ARN }}
- name: Setup Terraform
# バージョン2を使用する。
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Exec Terraform fmt check
id: fmt
run: terraform fmt -check -recursive
# exit code 3でエラーになり終了してしまうため
# continue-on-error: true で後続の処理も続ける。
continue-on-error: true
- name: Exec Terraform init
id: init
run: terraform init
- name: Exec Terraform plan
id: plan
run: terraform plan -no-color
# terraform plan の結果をコメント欄に出力する。
- name : comment
uses: actions/github-script@v4
env:
# ここのstdoutでterraform planの結果をPLANに保存している。
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
with:
script: |
const output = `### terraform cicd demo
#### Terraform Format and Style \`${{ steps.fmt.outcome }}\`
#### Terraform Initialization \`${{ steps.init.outcome }}\`
#### Terraform Plan \`${{ steps.plan.outcome }}\`
#### Terraform Validation \`${{ steps.validate.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`terraform\n
${process.env.PLAN}
\`\`\`
</details>
*Action: \`${{ github.event_name }}\`*`;
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
git add、git commit、git push を実行する
ここまで準備が出来たら実際に git add、git commit、git push コマンドを実行してみます。
■git add、git commit、git push コマンドを実行
(demo_test_20220918) $ git status
On branch demo_test_20220918
Changes not staged for commit:
(use "git add/rm ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
deleted: .github/workflows/test_demo.yml
Untracked files:
(use "git add ..." to include in what will be committed)
.github/workflows/terraform_plan.yml
demo-ec2.tf
no changes added to commit (use "git add" and/or "git commit -a")
(demo_test_20220918) $ git add .
(demo_test_20220918) $ git status
On branch demo_test_20220918
Changes to be committed:
(use "git restore --staged ..." to unstage)
new file: .github/workflows/terraform_plan.yml
deleted: .github/workflows/test_demo.yml
new file: demo-ec2.tf
(demo_test_20220918) $ git commit -m "demo_test_20220918"
[demo_test_20220918 384e1d1] demo_test_20220918
Committer: EC2 Default User <ec2-user@ip-172-31-44-157.ap-northeast-1.compute.internal>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:
git config --global user.name "Your Name"
git config --global user.email you@example.com
After doing this, you may fix the identity used for this commit with:
git commit --amend --reset-author
3 files changed, 98 insertions(+), 36 deletions(-)
create mode 100644 .github/workflows/terraform_plan.yml
delete mode 100644 .github/workflows/test_demo.yml
create mode 100644 demo-ec2.tf
(demo_test_20220918) $ git push origin demo_test_20220918
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 1.58 KiB | 811.00 KiB/s, done.
Total 6 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote:
remote: Create a pull request for 'demo_test_20220918' on GitHub by visiting:
remote: https://github.com/xxx/test_demo/pull/new/demo_test_20220918
remote:
To github.com:xxxxxxxx/test_demo.git
* [new branch] demo_test_20220918 -> demo_test_20220918
(demo_test_20220918) $
GitHub 上でプルリクエストを投げる
ブランチに push したら GitHub 上でプルリクエストを投げます。
必要事項を入力して「Create pull request」 ボタンをクリックします。
エラーなく terraform plan のパイプラインが完了したことを確認します。
GitHub Actions での terraform plan コマンドの実行結果をコメントに出力しているのでコメントを確認します。
コメントの「Show Plan」 をクリックします。
以下のように terraform plan の実行結果を確認します。
terraform fmt -check -recursive コマンドでエラーになる場合
パイプラインのコマンド実行に「terraform fmt -check -recursive」 を入れると下図のようにエラーになる場合があります。
展開すると以下のようなエラーが確認できます。
■エラー内容
Error: Terraform exited with code 3.
Error: Process completed with exit code 1.
原因は terraform fmt -check -recursive コマンドが exit code 3で終了しているからです。
正常コマンドが終了した場合は、通常、exit code 0 で終了します。
しかしなぜか terraform fmt -check -recursive を実行すると exit code 3 で終了してしまいます。
■Linux 上で terraform fmt -check -recursive コマンドを実行
$ terraform fmt -check -recursive
demo-ec2.tf
$ echo $?
3
しかし terraform fmt コマンドなら exit code は 0 で終了します。
■terraform fmt コマンドは exit code 0 になる
$ terraform fmt
demo-ec2.tf
$ echo $?
0
GitHub Actions の場合、各コマンドの exit code が「0」 の場合、次に進みます。
しかし exit code が「0」 以外だとそこでパイプラインが終了してしまいます。
そのため、exit code 3 になっても後続の処理を続けるために「continue-on-error: true」 の設定を入れます。
■continue-on-error: true の設定を入れる
- name: Exec Terraform fmt check
id: fmt
run: terraform fmt -check -recursive
# exit code 3でエラーになり終了してしまうため
# continue-on-error: true で後続の処理も続ける。
continue-on-error: true
GitHub Actions で terraform apply コマンドを実行する環境を構築する
先ほどは terraform plan コマンドを実行する環境を構築しましたが、次は terraform apply コマンドを実行する環境を構築します。
terraform apply コマンドはプルリクエストが承認され、マージされたタイミングで実行されます。
terraform_apply.yml ファイルを作成する
先ほどの「terraform_plan.yml」 ファイルと同様に「terraform_apply.yml」 ファイルを作成します。
■terraform_apply.yml ファイル
name: TerraformApply
on:
pull_request:
branches:
- main
types: [closed]
env:
TF_VERSION: 1.1.2
AWS_DEFAULT_REGION: ap-northeast-1
AWS_ROLE_ARN: arn:aws:iam::xxxxxxxxx:role/TerraCICDDemoOIDCRole
permissions:
id-token: write
contents: read
actions: read
pull-requests: write
jobs:
Terraform_Apply:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
# リポジトリのチェックアウトをする。
- name: Check out repository code
uses: actions/checkout@v3
# OICDでAssumeRoleをする。
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_DEFAULT_REGION }}
role-to-assume: ${{ env.AWS_ROLE_ARN }}
- name: Setup Terraform
# バージョン2を使用する
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Exec Terraform fmt check
id: fmt
working-directory: '${{ env.WORK_DIR }}'
run: terraform fmt -recursive -check
# exit code 3でエラーになり終了してしまうため
# continue-on-error: true で後続の処理も続ける。
continue-on-error: true
- name: Exec Terraform init
id: init
working-directory: '${{ env.WORK_DIR }}'
run: terraform init
- name: terraform apply
id: apply
working-directory: '${{ env.WORK_DIR }}'
run: terraform apply -auto-approve
git add、git commit、git push を実行する
ここまで準備が出来たら実際に git add、git commit、git push コマンドを実行してみます。
■git add、git commit、git push コマンドを実行
(demo_test_20220918) $ git add .
(demo_test_20220918) $ git commit -m "demo_test_20220918"
[demo_test_20220918 c31e9d1] demo_test_20220918
Committer: EC2 Default User <ec2-user@ip-172-31-44-157.ap-northeast-1.compute.internal>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:
git config --global user.name "Your Name"
git config --global user.email you@example.com
After doing this, you may fix the identity used for this commit with:
git commit --amend --reset-author
2 files changed, 64 insertions(+), 1 deletion(-)
create mode 100644 .github/workflows/terraform_apply.yml
(demo_test_20220918) $ git push origin demo_test_20220918
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 1.32 KiB | 675.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:xxxxxxxxx/test_demo.git
a6e05c3..c31e9d1 demo_test_20220918 -> demo_test_20220918
プルリクエスト作成しマージする
上記のようにプルリクエストを作成後、マージをします。
GitHub上のプルリクエストをクリックします。
「Merge pull request」 ボタンをクリックします。
「Confirm merge」 ボタンをクリックします。
「Actions」 タブをクリックします。
パイプラインが問題なく終了したことを確認します。
動作確認をする
最後に動作確認をします。
AWS 管理コンソールより EC2 のダッシュボードに移動し EC2 インスタンスを確認します。
今後やりたいこと
複数人で運用する場合、デプロイでバッティングしないようにしたい。
現状、1つのリポジトリで1パイプラインになっている。1つのリポジトリで複数のパイプラインを運用したい。
terraform apply の結果を Slack に通知したい。
参考サイト
https://learn.hashicorp.com/tutorials/terraform/github-actions
Posted by 100%レンタルサーバーを使いこなすサイト管理人
Secured By miniOrange
コメントを残す