
こんにちは。クラウドワークス SRE チームの田中(@kangaechu)です。
12月はアドベントカレンダーで重めの記事を書いたので、今回は軽いネタです。
手動での削除が手間だったTerraform/OpenTofuの import/moved/removed ブロックをGitHub Actionsを活用して効率化しました。その具体的な仕組みをご紹介します。
背景と課題
Terraform/OpenTofuでは、tfstateに対する処理を行うために、import/moved/removed ブロックを使用します。
例えば、以下は AWSで作成済みのEC2インスタンス i-abcd1234 を aws_instance.example リソースとしてインポートするための記述です。
# TODO: apply後に削除する import { to = aws_instance.example id = "i-abcd1234" } resource "aws_instance" "example" { name = "hashi" # (other resource arguments...) }
このような記述を行うことで、terraform plan でimportの状態を確認し、 terraform apply でtfstateにリソースを追加することができます。
import以外にも、movedブロックを使用してリソースの移動、removedブロックを使用してリソースの削除を行うことができます。
各ブロックのドキュメントです。
| import | moved | removed | |
|---|---|---|---|
| Terraform | import | moved | removed |
| OpenTofu | import | moved | removed |
以前は terraform state import/mv/rm コマンドを使用してtfstateにリソースを追加する必要がありましたが、
これらのブロックを使用することで、tfstateの変更時にCIやレビューのプロセスを通して変更を行うことができるようになりました。
クラウドワークスでは、TerraformのCI/CDにAtlantisを使用しています。
AtlantisをCI/CDで使用すると、GitHubにPull Requestを作成したりpushしたタイミングで terraform plan を実行し、plan結果をPull RequestのコメントにPostしてくれます。また、Pull Requestに atlantis apply とコメントすると、Atlantisは terraform apply を実行し、成功したらPull Requestをマージします。
import/moved/removed ブロックも同様に行われるため、マージ後はこれらのブロックは不要となります。
ただ、わざわざ手動で削除するのは面倒ですよね。
解決策
そこで、GitHub Actionを使用してこれらのブロックを自動で削除するGitHub Actionを作成しました。
name: cleanup-state-block permissions: contents: write pull-requests: write on: schedule: - cron: '0 22 * * 0' # JST 07:00 on Monday workflow_dispatch: jobs: cleanup-state-block: runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout code uses: actions/checkout@v4 - name: Download HCLEdit run: | hcledit_version=0.2.15 case $(uname -m) in x86_64) arch=amd64 ;; aarch64) arch=arm64 ;; esac url="https://github.com/minamijoyo/hcledit/releases/download/v${hcledit_version}/hcledit_${hcledit_version}_linux_${arch}.tar.gz" echo "Downloading HCLEdit from $URL" curl -sSL $url | tar -xvzf - -C /usr/local/bin hcledit version shell: bash - name: remove state blocks run: | # HCLEditでstate blockを削除 target_block_names=(import removed moved) for block_name in "${target_block_names[@]}"; do find . -type f -name "*.tf" -execdir hcledit block rm "$block_name" -f {} -u \; done # 変更がなかったら終了 change_file_count=$(git diff --name-only --ignore-blank-lines | wc -l) if [ $change_file_count -eq 0 ]; then echo "No changes" exit 0 fi git config --global user.email "github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" # HCLEdit block rmは空行も修正してしまうため、空行のみの変更を無視してステージング branch_name=cleanup-state-blocks git switch -c $branch_name git diff --ignore-blank-lines | git apply --cached git commit -m "Remove state block" -m "This PR is generated by GitHub Actions" git push -f origin $branch_name echo 'CREATE_PR=true' >> $GITHUB_ENV shell: bash - uses: actions/create-github-app-token@v1 if: env.CREATE_PR == 'true' id: app-token with: app-id: ${{ secrets.GHA_APP_ID }} private-key: ${{ secrets.GHA_PRIVATE_KEY }} - name: Create a pull request if: env.CREATE_PR == 'true' run: | echo -e "apply済みで不要なimport/removed/movedブロックを削除します。\nこのPRはcleanup-state-blockワークフローから実行されています。" > body.txt gh pr create --title "[cleanup] 不要なimport/removed/movedブロックを削除" --body-file body.txt --base ${{ github.ref_name }} --head cleanup-state-blocks env: GH_TOKEN: ${{ steps.app-token.outputs.token }} shell: bash
実装
hcledit
hcleditは、HCLファイルを編集するためのツールです。
今回は、hcledit block rm コマンドを使用して、指定したブロックを削除しています。
hcleditはHCLファイルの構造も見ているため、ブロックの前の行にブロックに対するコメントが書かれている場合、# TODO: apply後に削除する のようなコメントもあわせて削除されます。
また、ブロック間の空行も削除します。とても便利ですね。
git diff --ignore-blank-lines
hcledit block rm は修正対象のファイルの連続した空行も削除してしまうため、空行のみの変更を無視してステージングするために git diff --ignore-blank-lines を使用しています。
これにより、空行のみの変更を無視してステージングすることができます。
Pull Requestの作成
Pull Requestの作成にはGitHub Appを使用しています。 GitHub Appの作成時には、以下の権限を付与します。
- Contents: read
- Pull requests: read and write
- Metadata: read
また、GitHub AppのApp IDとPrivate KeyをリポジトリのActions secrets and variablesに指定します。
動作結果とメリット
GitHub Actions Workflowで指定した時刻(例だと毎週月曜日 7:00 JST)に削除のPull Requestが作成されます。 また、GitHub Actionsの画面からも手動で実行が可能です。
GitHub Actionsによって作成されたPull Requestはこのようになります。


Pull Requestが作成されたらレビューしてマージするだけ。かんたんな作業でリポジトリが綺麗な状態を保てて最高ですね。
まとめ
hcleditとGitHub Actionsを使用して、Terraform/OpenTofuの import/moved/removed ブロックの削除を自動化するGitHub Actionを作成しました。
クラウドワークスではSREを含むエンジニアを募集しています。興味のある方は以下のリンクからご応募ください。