Skip to main content

2 posts tagged with "ci"

View All Tags

· 6 min read
Shunsuke Suzuki

AWS CodeBuild を検証しているんですが、結構良いですね。 現状 Jenkins や CircleCI で実行しているジョブや CI/CD を一部移行したいなと思いました。

一部と言っているのは、単純に全部いきなり移行するのは難しいから共存する前提で考えるくらいの意味です。

なお、これを書いている時点ではまだ軽く検証しているだけなので、CodeBuild の理解は浅いです。

特徴としては

  • Managed
  • AWS 以外のサービスに AWS の credential を登録しなくて良い
    • Secret を AWS Secrets Manager で管理できる
    • Secret を至るところに設定するのではなく、 AWS Secrets Manager か何かで一元管理するのが理想
    • Role 作って Build Project の Service Role として指定するだけなら credential を扱う必要がなくて楽で安心
  • VPC 内で実行できる
  • GitHub 連携も簡単
    • Webhook の設定で PR の細かなイベント(merge とか reopen とか)に対応しているのも良い
    • PR を merge したときも PR で変更されたファイルによって Webhook をフィルタできるのが良い
  • 変更されたファイルによって実行するBuild Project を変更するようなロジックを実現できる(monorepo で特に有効)

といった点が挙げられます。

変更検知について

上記の特徴についてはだいたい「まぁそうだね」というふうに思ってもらえるのではないかと思いますが、変更検知の部分について補足します。 monorepo をやっているとサービス A 関連のジョブはサービス A 関連のコードが変更された場合のみ実行したいというのがあります。 なのですが、 CircleCI だと自分の知る限りそれはできません。

https://circleci.com/docs/2.0/configuration-reference/

なので現状 Job を実行してからサービス A 関連のコードが変更されているかチェックし、変更されていなかったら skip ないし circleci step halt で Job を終了しています。 ただ、差分検知の部分を自分で実装しないといけないし、 circleci step halt で終了するにしても Job の起動自体にそこそこ時間がかかったりするし(これだけでも金銭的コストがかかっているはず)、 Job の実行時間や error rate のモニタリングでもノイズとして混じってきてしまいます。

CodeBuild の場合、1つのリポジトリに複数の Build Project を設定でき、 Build Project ごとに buildspec を指定できます。 Build Project の Webhook の FILE_PATH の設定で特定のファイルが変更された場合のみビルドを実行することもできます。 なのでサービス A 用の build spec 及び Build Project を作成し、サービス A のコードが変更されたときのみその Build Project が実行されるように Webhook を設定すれば良さそうです。

気になる点

  • FILE_PATH で 1 個の正規表現しか設定できないので、場合によっては複雑な正規表現を書かないといけない
  • Terraform で管理するのが結構面倒くさい
    • いい感じにモジュール化とかテンプレート化しないとだめかも
  • Pull Request のラベルがついていたらこのジョブを実行する、みたいな複雑なことは一工夫必要かも
    • Webhook の設定だと無理なので、 build は実行しつつラベルが設定されていなかったら skip とかしないといけない

おまけ: CodeBuild 関連のニュース

以前検証したときより良くなってる気がするなと思って更新をチェックしたらやっぱ色々更新があるみたいですね。

https://aws.amazon.com/jp/new/?whats-new-content-all.sort-by=item.additionalFields.postDateTime&whats-new-content-all.sort-order=desc&awsf.whats-new-developer-tools=general-products%23aws-codebuild

· 6 min read
Shunsuke Suzuki

以前 Graylog を Terraform で管理する記事を書きました。

https://suzuki-shunsuke.github.io/graylog-terraform/

今回はそれを CI/CD で実行できるようにした話です。

ただし、今回の内容は Graylog に限らず Terraform を CI/CD で実行する方法として使えると思います。

今回実現したのは以下のことです。

  • PR時にテストをする
  • plan/* tag を push すると terraform plan が実行される
  • apply/* tag を push すると terraform apply が実行され、tfstate がコミット、プッシュされる

ソースコード

https://github.com/suzuki-shunsuke/example/tree/master/graylog-terraform に置いておきました。

CI/CD用の user, role を作成する

まずは role を作成します。

resource "graylog_role" "terraform" {
name = "terraform"
description = "terraform"

permissions = [
"dashboards:*",
"indexsets:*",
"inputs:*",
"roles:*",
"streams:*",
"users:*",
]
}

permission は terraform で管理するリソースのみ付与しますが、 それでも結構強い権限を付与するので取扱に注意してください。

よりちゃんと権限管理するのであれば project ごとに role, user を分けるという手もありそうですが、そうすると管理も大変そうです。

次に user を作成します。

resource "graylog_user" "terraform" {
username = "terraform"
email = "terraform@example.com"
full_name = "terraform"

roles = [
"terraform",
"Reader",
]
}

Reader か Admin は必須らしいのでReaderを付与しています。

http://docs.graylog.org/en/2.5/pages/users_and_roles/permission_system.html

Every user needs to at least have the standard “Reader” permissions but those do not provide any access to data or maintenance functionalities.

次にこのユーザーの token を発行します。

http://docs.graylog.org/en/2.5/pages/configuration/rest_api.html#creating-and-using-access-token

$ curl -u <username>:<password> -H 'Accept: application/json' -X POST 'https://graylog.example.com/api/users/<username>/tokens/<tokenname>?pretty=true'

発行したトークンを CI/CD にクレデンシャルとしてセットします。 やり方は利用するCI/CDによって変わります。

以降は drone ci という CI/CD プラットフォームを前提に書きますが、 travis ci や circle ci, jenkins など他のCI/CDでも考え方は一緒だと思います。

.drone.yml は 以下のようになります。

---
pipeline:
envsubst:
image: suzukishunsuke/alpine-envsubst:0.1.0
commands:
- envsubst < terraform.tfvars.tpl > terraform.tfvars
secrets:
- source: terraform_token_prod
target: graylog_auth_name
when:
event: tag
plan:
image: &terraform_image "suzukishunsuke/terraform-graylog:0.1.2"
commands:
- terraform init
- terraform validate
- terraform fmt -check
- terraform plan
when:
event: tag
ref: refs/tags/plan/*
apply:
image: *terraform_image
commands:
- terraform init
- terraform validate
- terraform plan
- terraform fmt -check
- terraform apply -auto-approve
when:
event: tag
ref: refs/tags/apply/*
git:
image: plugins/git
commands:
- sh drone_pipeline_commands/git.sh
when:
event: tag
ref: refs/tags/apply/*
validate:
image: *terraform_image
environment:
- "TF_VAR_auth_name=dummy"
- "TF_VAR_auth_password=token"
- "TF_VAR_web_endpoint_uri=https://graylog.example.com/api"
commands:
- terraform init
- terraform validate
- terraform fmt -check
when:
event: pull_request

まずは terraform を実行するための Docker Image を用意しました。

https://hub.docker.com/r/suzukishunsuke/terraform-graylog/

PR時のテストでは terraform validate と terraform fmt を実行します。

  validate:
image: *terraform_image
environment:
- "TF_VAR_auth_name=dummy"
- "TF_VAR_auth_password=token"
- "TF_VAR_web_endpoint_uri=https://graylog.example.com/api"
commands:
- terraform init
- terraform validate
- terraform fmt -check
when:
event: pull_request

TF_VAR_ で始まるのが terraform の変数です。

https://www.terraform.io/docs/configuration/variables.html#environment-variables

token は適当な文字列をセットしてください。PR時には実際にgraylog の API を呼ばないので適当なので問題ありません。

次に plan/* と tag を push すると terraform plan が実行されます。 この結果を見て terraform apply を実行します。

これは drone の secrets の都合なのですが、secrets の環境変数は全部大文字になってしまうため TF_VAR_auth_name という環境変数をセットできません。そのため envsubst を使って terraform.tfvars に token を書き込んでいます。

  envsubst:
image: suzukishunsuke/alpine-envsubst:0.1.0
commands:
- envsubst < terraform.tfvars.tpl > terraform.tfvars
secrets:
- source: terraform_token_prod
target: graylog_auth_name
when:
event: tag

terraform.tfvars.tpl はこんな感じです。

web_endpoint_uri = "https://graylog.example.com/api"
auth_name = "$GRAYLOG_AUTH_NAME"
auth_password = "token"

plan を実行する step です。

  plan:
image: &terraform_image "suzukishunsuke/terraform-graylog:0.1.2"
commands:
- terraform init
- terraform validate
- terraform fmt -check
- terraform plan
when:
event: tag
ref: refs/tags/plan/*

apply/* と tag を push すると terraform apply が実行されます。

  apply:
image: *terraform_image
commands:
- terraform init
- terraform validate
- terraform plan
- terraform fmt -check
- terraform apply -auto-approve
when:
event: tag
ref: refs/tags/apply/*

terraform.tfstate をコミット, プッシュします。

  git:
image: plugins/git
commands:
- sh drone_pipeline_commands/git.sh
when:
event: tag
ref: refs/tags/apply/*

drone_pipeline_commands/git.sh はこんな感じです。

git status --porcelain || exit 1
if `git diff --exit-code --quiet terraform.tfstate`; then
echo "terraform.tfstate isn't changed"
exit 0
else
git config user.name drone
git config user.email drone@example.com
git add . || exit 1
git commit -m "build: commit by drone" || exit 1
git push origin HEAD:master || exit 1
fi

terraform.tfstate に変化があった場合のみ コミット・プッシュするようにしています。 この辺のやり方はもっとうまいやり方があるかもしれません (自分のシェルスクリプト力が低いため)。

terraform plan-detailed-exitcode オプションを使うのが良い気がします。

  -detailed-exitcode  Return detailed exit codes when the command exits. This
will change the meaning of exit codes to:
0 - Succeeded, diff is empty (no changes)
1 - Errored
2 - Succeeded, there is a diff

以上 Graylog の Terraform を CI/CD で実行する方法を紹介しました。 Graylog に限らず、 Terraform を CI/CD で実行する方法として使えると思うので参考になれば幸いです。