インフラをTerraformで一元管理する
はじめに
このスクラップは、私が所属している会社のインフラを、Terraformで一元管理するようにした際に、躓いた箇所やメモを記録するためのものです。
参考
Terraform とは
Terraform とは、HashiCorp社が提供しているオープンソースの「Infrastructure as Code (IaC)
」ツールです。インフラストラクチャ(サーバー、ネットワーク、ストレージ、DNSなど)をコードとして記述し、自動化と再現性を持って管理・デプロイすることができます。
開発環境の構築
今回は WSL2 + Ubuntu + DevContainer + Docker
を使用して、開発環境を構築します。
Dockerイメージは公式のものがあるようなので、それを使用します。
Terraformのバージョンは最新のものを使用します。
最新のバージョンは以下から確認しましょう。
AWS CLI v2とHashiCorp Terraform公式Dockerイメージの相性問題
AWS CLI v2はglibc
環境が必要ですが、AlpineベースのTerraform公式Dockerイメージでは適切に構築できず、多くの課題がありました。その際に以下の記事を発見しました。
該当Issue
- GitHub Issue: glibcとAlpineの互換性問題について
結論
Terraform公式イメージで環境を構築しようと試みましたが、AlpineベースのOSではglibc
の依存関係などの問題が多く、最終的にDebian Slim
かUbuntu
の選択に至りました。
TerraformやAWS CLIの使用頻度と公式ガイドの採用例を考慮した結果、Ubuntu 22.04
を採用して環境を構築することにしました。
以下はそれぞれのファイルです。
Dockerfile
FROM ubuntu:22.04
# 環境変数
ENV LANG=ja_JP.UTF-8 \
TF_VERSION=1.9.8 \
AWS_CLI_URL=https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip \
HADOLINT_VERSION=v2.12.0
# システムのアップデートと基本ツールのインストール
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
less \
vim \
curl \
unzip \
git \
make \
locales \
ca-certificates \
openssh-client && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# ロケールの設定
RUN locale-gen ${LANG} en_US.UTF-8 && \
update-locale LANG=${LANG} && \
update-ca-certificates
# AWS CLI v2 のインストール
WORKDIR /tmp/awscli
RUN curl --silent --show-error --fail "$AWS_CLI_URL" -o "awscliv2.zip" && \
unzip -q awscliv2.zip && \
./aws/install && \
rm -rf awscliv2.zip aws
# Terraform のインストール
WORKDIR /tmp/terraform
RUN curl --silent --show-error --fail -L "https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip" -o "terraform.zip" && \
unzip -q -d /usr/local/bin/ terraform.zip && \
rm terraform.zip
# git-secrets のインストール
WORKDIR /tmp/git-secrets
RUN git clone https://github.com/awslabs/git-secrets.git . && \
make install && \
rm -rf /tmp/git-secrets
# hadolint のインストール
WORKDIR /tmp/hadolint
RUN curl --silent --show-error --fail -L "https://github.com/hadolint/hadolint/releases/download/${HADOLINT_VERSION}/hadolint-Linux-x86_64" -o /usr/local/bin/hadolint && \
chmod +x /usr/local/bin/hadolint
# vscode ユーザー作成と初期設定
WORKDIR /workspace
RUN adduser --disabled-password --gecos "" vscode && \
mkdir -p /home/vscode/.aws /workspace && \
chown -R vscode:vscode /home/vscode /workspace
# 初期化スクリプトのコピー
COPY .docker/terraform/init.sh /usr/local/bin/init.sh
RUN chmod +x /usr/local/bin/init.sh
# 作業ディレクトリ設定
USER vscode
WORKDIR /workspace
# エントリーポイントの設定
ENTRYPOINT ["/usr/local/bin/init.sh"]
compose.yml
services:
terraform:
container_name: 'terraform'
image: local/terraform
build:
context: .
dockerfile: .docker/terraform/Dockerfile
volumes:
- .:/workspace
- ./.docker/terraform/.aws/config.default:/home/vscode/.aws/config
- ./.docker/terraform/.aws/credentials.default:/home/vscode/.aws/credentials
environment:
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
tty: true
init.sh
#!/bin/bash
# AWS Config の設定
if [[ ! -f /home/vscode/.aws/config ]]; then
mv /home/vscode/.aws/config.default /home/vscode/.aws/config
fi
# AWS Credentials の設定
if [[ ! -f /home/vscode/.aws/credentials ]]; then
mv /home/vscode/.aws/credentials.default /home/vscode/.aws/credentials
sed -i "s/<access-key>/\${AWS_ACCESS_KEY_ID}/g" /home/vscode/.aws/credentials
sed -i "s/<secret-key>/\${AWS_SECRET_ACCESS_KEY}/g" /home/vscode/.aws/credentials
fi
# シェルを起動
exec bash
テストについて
以下のリポジトリはAWS LambdaのHello Worldプロジェクトで、TerraformとGitHub Actionsを使用したCI/CDパイプラインの構築例が含まれている
既存リソースの一括インポート
以下の記事を参考に行っていきます
一括インポートできない
次のエラーが発生し、一括インポートができない問題に直面しました
aws error initializing resources in service accessanalyzer, err: operation error AccessAnalyzer: ListAnalyzers, failed to resolve service endpoint, an AWS region is required, but was not found
そこで次のようにしてみたところインポート自体は成功した
$ terraformer import aws -r="ec2_instance,s3" --regions=ap-northeast-1
リージョンを明記するのも大事そう(明記しなかった場合s3が正しくインポートできなかった)
結論
いくつかのリソースで同時にインポートしようとするとエラーを吐くものがあったので、ひとつずつインポートすることにしました。
ただ、Cloud Map
のリソースがうまく取得できなかったので、これはterraform import
コマンドでインポートしました
ディレクトリ構造の検討
将来的にCloudflareやGCPも同じリポジトリで管理する予定のため、以下を参考にします
インポートしたリソースの整理
以下を参考に整理していきます
調査を進めると、どうやらterrraformerは銀の弾丸ではなかった模様・・・
結局インポートしたリソースを"使って"構築するという認識が正しいのかもしれない
そのままでは使えないですね
さらに、terraformerでインポートすると Terraform 0.12 環境の tfstate になるため、Terraform 1.0 までアップグレードする必要があるようです
まずはインポートしたすべてのリソースのバージョンを、最新の1.9.8にアップグレードしていきます
tfenv を利用し適宜 Terraform のバージョンを変更していますが、下位ディレクトリに .terraform-version ファイルがある場合にはそのバージョンに引っ張られるため、.terraform-version を変更し、作業前に意図したバージョンになっているかを $ terraform version で確認することをオススメします。
0.12 -> 0.13
$ cd generated/aws/ec2_instance
$ tfenv use 0.13.7
$ terraform 0.13upgrade
$ terraform init
$ terraform plan
$ terraform apply
Warning で非推奨の書き方をしている場合があるのでそれを修正しましょう。
Warning: Interpolation-only expressions are deprecated
on outputs.tf line 6, in output "aws_instance_tfer--i-06ab3a2a9cffebacd_hoge_id":
6: value = "${aws_instance.tfer--i-06ab3a2a9cffebacd_hoge.id}"
これは
value = aws_instance.tfer--i-06ab3a2a9cffebacd_hoge.id
と書き換えるだけです。
なお、このエラーの修正作業には以下のGPTs等を活用しました
0.13 -> 0.14
$ tfenv use 0.14.11
$ terraform init
$ terraform plan
$ terraform apply
0.14 -> 1.9.8
$ tfenv use 1.9.8
$ terraform init
$ terraform plan
$ terraform apply
これで 0.12 から最新のバージョンへアップグレードできます。
ローカルにある tfstate の terraform_version が 1.9.8 になっているはずです。
続けて、以下を参考にリソースを一つずつterraformで構築していく