【AWSチュートリアル】Terraform用のDocker環境を作る!

トップ AWS
スポンサーリンク

本記事では、Terraformが実行できるDocker環境を作っていきたいと思います。

早速いってみましょう!

スポンサーリンク

前提

  1. Terraform実行用のIAMロールを作成していること。
  2. 1のIAMロールにスイッチできるIAMユーザーを用意していること。(また、そのIAMユーザーのアクセスキーとシークレットキーを事前に取得しておく。)
  3. TerraformのState管理用のS3バケットが作成されていること。

まだ準備ができていないようであれば、以下の記事を参照して準備してもらえたら!

■IAMロールの準備

【AWSチュートリアル】IAMロールを準備する。(AWS構築用のIAMロールにスイッチしてTerraformが実行できるようにする。)

■TerraformのState管理用のS3バケットを作成する。

【AWSチュートリアル】TerraformのState管理用のS3バケットを作成する。

今回の目標

  1. Terraform実行用のDockerイメージを作成する。
  2. 1で作成したイメージからコンテナを起動して、Terraformを実行してみる。

このような構成が目標です。(右下の小さい部分)

アーキテクチャ

なぜTerraformの実行環境にDockerを使用するのか?

Terraform自体は公式からバイナリファイルで提供されているため、ローカル環境でも簡単に環境構築することが可能です。

一方、Dockerを使用するとDockerfileを用意する必要があり一手間掛かります。それでもDockerを利用する理由としては2つあります。

1つ目は、「どこの環境でも同じTerraformが利用できるようにしたい。」です。

今後、CICD環境からTerraformを実行することになっても、Dockerを使っているため、ローカル環境とCICD環境を同じにすることができます。(「ローカルではTerraformが実行できるけど、CICD環境からは実行できないぞ?(もしくはバージョンが違うぞ?とか)」となるリスクを軽減することができます。)

2つ目は、「Dockerに慣れる。」です。

これからAWS上にリソースを構築していく上で、ECSなども使用します。ECSはコンテナサービスのため、Dockerとは切り離せません。そのため、学習量が軽い序盤から少しずつ使って、Dockerに慣れてもらえたらと思っています。

Terraform実行用のDockerイメージを作成する。

Docker自体のインストールは以下から行えます。

Get Started with Docker | Docker

Dockerfileを作成する。

まずは、Dockerfileを作成します。

$ touch Dockerfile

それでは編集していきます。

Dockerイメージ内では、Terraformさえ実行できればよいので、ベースイメージはなるべく軽量なalpineを使用しました。

FROM alpine:3.15.0

alpineのイメージは以下に記載されています。今回は最新のバージョンを使用します。

alpine Tags | Docker Hub

Terraformの実行には、AWSの認証情報が必要です。ただ、Dockerfileにそのまま秘密情報を記載することは情報漏洩時のリスクが高いため、ビルド時に環境変数で渡せるようにしておきます。

ビルド時の変数は ARG [変数名]で受け取ることができます。

...
ARG AWS_ACCESS_KEY
ARG AWS_SECRET_ACCESS_KEY
ARG ENV
...

※「ENV」について。今回サンプルのTerraformは、実行環境毎にフォルダを分割するように設計しています(開発はstaging、本番はproductionのように)。そのため、ここは何も考えずにコピペしてもらえると。

「共通で使用する値」や「後で変更しやすい」ように、いくつか変数を宣言します。

変数は ENV [変数名] [設定値] で使用することができます。

...
# Terraformをダウンロードしてくる公式サイトのURL
ENV TF_URL https://releases.hashicorp.com/terraform/1.0.11/terraform_1.0.11_linux_amd64.zip
ENV ROOT_PATH /root
# Terraformの作業ディレクトリ
ENV INFRA_ROOT /tf
...

これからコマンドをいくつか実行していくのですが、その中でTerraformのダウンロードを行ったりします。他のディレクトリを汚さないように、事前に作業ディレクトリを移動しておきたいと思います。移動は WORKDIR [ディレクトリ名] ですることができます。(移動先のディレクトリが無い時は、自動で作成してくれます。)

...
ENV ROOT_PATH /root
...
WORKDIR ${ROOT_PATH}
...

先程設定した変数を利用して、作業ディレクトリに移動しました。

それではコマンドを実行していきます。

コマンドは RUN [実行したいコマンド] で実行することができます。実行するコマンドはなるべく1行にまとめておいた方がよいため(キャッシュの関係で)、 && \でコマンド連結します。

...

RUN apk update && \ # インストール可能なパッケージ一覧の更新。※パッケージの更新は実施しません。(apk upgradeでパッケージ全体の更新を行います。)

    # Terraformの実行バイナリをダウンロードします。
    # -q:ダウンロードの進捗を表示しない。
    # -O:ダウンロードしたファイルの名前を指定。
    wget -q -O terraform.zip ${TF_URL} && \ 

    unzip terraform.zip && \
    rm -fr terraform.zip && \
    mv terraform /usr/local/bin/ && \

    # apkのキャッシュを削除します。少しでもイメージのサイズを小さくします。
    rm -fr /var/cache/apk/
...

AWS認証情報を設定していきます。AWSの秘密情報は、事前に設定したビルド時の引数を使用します。

...
ARG AWS_ACCESS_KEY
ARG AWS_SECRET_ACCESS_KEY
...
WORKDIR ${ROOT_PATH}/.aws
RUN echo '[default]' >> config && \
    echo 'region = ap-northeast-1' >> config && \
    echo 'output = json' >> config && \
    echo '[default]' >> credentials && \
    echo "aws_access_key_id = ${AWS_ACCESS_KEY}" >> credentials && \
    echo "aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}" >> credentials
...

ローカルのTerraformコードをコンテナ内にコピーします。コピーは COPY [コピーしたいファイルやディレクトリ] [コピー先のパス] を使います。

...
COPY ./modules ${INFRA_ROOT}/modules
COPY ./staging ${INFRA_ROOT}/staging
...

コンテナに接続したときにデフォルトでTerraformのディレクトリに移動したいので、作業ディレクトリを移動します。

...
WORKDIR ${INFRA_ROOT}/${ENV}
...

ここまで作業が完了すると、以下のようなファイルが作成されているかと思います。

(コメントは省いています。)

FROM alpine:3.15.0

ARG AWS_ACCESS_KEY
ARG AWS_SECRET_ACCESS_KEY
ARG ENV

ENV TF_URL https://releases.hashicorp.com/terraform/1.0.11/terraform_1.0.11_linux_amd64.zip
ENV ROOT_PATH /root
ENV INFRA_ROOT /tf

WORKDIR ${ROOT_PATH}
RUN apk update && \
    wget -q -O terraform.zip ${TF_URL} && \
    unzip terraform.zip && \
    rm -fr terraform.zip && \
    mv terraform /usr/local/bin/ && \
    rm -fr /var/cache/apk/

WORKDIR ${ROOT_PATH}/.aws
RUN echo '[default]' >> config && \
    echo 'region = ap-northeast-1' >> config && \
    echo 'output = json' >> config && \
    echo '[default]' >> credentials && \
    echo "aws_access_key_id = ${AWS_ACCESS_KEY}" >> credentials && \
    echo "aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}" >> credentials

COPY ./modules ${INFRA_ROOT}/modules
COPY ./staging ${INFRA_ROOT}/staging

WORKDIR ${INFRA_ROOT}/${ENV}

Dockerfileをビルドしてイメージを作成してみる。

Dockerfileができたので、ビルドしてイメージを作成してみます。

まずはDockerfileがあるディレクトリまで移動します。

$ pwd
→「study-infra-aws-tutorial/001/infra」に移動していること。

それではDockerイメージをビルドします。ビルド時に必要な環境変数は --build-argで設定します。AWSの認証情報は各自のものを入力してください。

$ docker build \
  -t study-infra-tf:1.0.0 \
  --build-arg AWS_ACCESS_KEY=[AWSアクセスキー] \
  --build-arg AWS_SECRET_ACCESS_KEY=[AWSシークレットキー] \
  --build-arg ENV=staging \

これでビルドが完了です。作成したイメージを確認します。

$ docker images
REPOSITORY         TAG              IMAGE ID       CREATED          SIZE
study-infra-tf     1.0.0            40b4b4907eb6   14 minutes ago   64.7MB

イメージが作成されていますね。

Dockerイメージを起動して接続してみる。

先程作成したイメージからコンテナを作成し、起動させます。

起動させる際にシェル(alpineなのでシェルはashです)でコンテナ内に接続します。

$ docker run --rm -v $PWD:/tf -it [IMAGE ID] ash
/tf/staging #
オプション解説
—rmコンテナからログアウトすると自動で削除する。
-vローカルディレクトリをコンテナ内にマウントする。(ローカルの変更がコンテナにリアルタイムに反映されるように。)
-itコンテナにアタッチしてコンテナ内でコマンドが実行できるようにする。

これで、コンテナ内からTerraformを実行することができます。

Terraform実行のための下準備をする。

Terraformの解説は後日するため、今回は理解しなくても大丈夫です。

1.「example.tfbackend」を変更する。

bucket   = "sample-bucket" ★変更対象
region   = "ap-northeast-1"
key      = "study-infra-tutorial/staging.tfstate"
encrypt  = true
role_arn = "arn:aws:iam::111111111:role/study-infra-terraform-role" ★変更対象
キー説明
bucketTerraformのState管理用のS3バケット名を記載する。
role_arnスイッチ先のIAMロール(Terraform実行用ロール)のARNを記載する。

2.「example.tfvars」を変更する。

iam_role_for_terraform = "arn:aws:iam::111111111:role/study-infra-terraform-role" ★変更対象
tags = {
  "Env"    = "staging"
  "System" = "study-infra-tutorial"
}

「iam_role_for_terraform」にスイッチ先のIAMロール(Terraform実行用ロール)のARNを記載してください。

Terraformを実行してみる。

それでは試しにコンテナ内でTerraformを実行してみましょう。

まずは terraform init から。

$ docker run --rm -v $PWD:/tf -it [IMAGE ID] ash
/tf/staging # terraform init -backend-config=example.tfbackend 
Initializing modules...
- network in ../modules/network

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 v3.67.0...
- Installed hashicorp/aws v3.67.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.
/tf/staging #

次はterraform plan を実行してみましょう。

$ terraform plan -var-file=example.tfvars

...

Plan: 1 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.
/tf/staging #

問題なく実行できましたか?

できた人は、この記事でやることは終了です。できていない人は、原因を調査してみましょう。(スイッチロール周りが怪しいんじゃないかなーと思っています。)

これにて本記事は終了です。

コメント

タイトルとURLをコピーしました