OPS

インフラの管理をIaC化!AWSでOpenTofuを実行する方法

インフラの管理をIaC化!AWSでOpenTofuを実行する方法

2024.11.12

本記事のポイント

最近ではよく Infrastructure as Code(以後IaC)という単語を聞くようになりました。

本記事では、そんなIaCの中でも人気のTerraformからフォークされたOpenTofuの概要と、Dockerさえ入っていればどこでも実行できるOpenTofuの実行方法をご紹介します。



はじめに

皆様はIaC化していますか?最近ではインフラの管理をIaCで行うのが主流となっています。

そこで今回は、HashiCorp(ハシコープ)社が提供するTerraformからフォークされたオープンソースソフトウェア(OSS)であるOpenTofuについて解説していきたいと思います。

記事前半ではOpenTofuのご紹介を、後半では実際にOpenTofuでのAWSリソースの作り方をお伝えするので、ぜひじっくりとご覧ください。

OpenTofu(オープントーフ)とは?

2023年、IaCの中でも人気があったTerraformがOSSからのライセンスの変更を行いました。これに伴いOSSとしてTerraformからフォークされたものがOpenTofuになります。

OpenTofuはIaCとしての構文などはTerraformとほぼ同じなのでTerraformを触ったことのある方であれば楽に書けると思います。

ではそんなOpenTofu/Terraform ですがどのような魅力があるのでしょうか?私が思うOpenTofu/Terraformの利点は以下です。

  • 様々な環境で動作する(AWS、Google Cloud、Azure、VMwareなど)
  • コミュニティが活発である
  • 他にもありますがOpenTofu/Terraformを選択する上で1番の魅力はこの2つだと思っています。ここからは実践形式でOpenTofuについてご紹介していきたいと思います。

    OpenTofuの実行環境の種類

    OpenTofu/Terraformを実行する際には大きく分けて以下の2つの実行環境があります。

  • 直接インストールして実行する
  • インストールされたコンテナイメージ上で実行する
  • 「直接インストールして実行する」は実行する環境ごとにインストール手順を行う必要があります。

    そのためここではDockerさえ入っていればどこでも実行できる「インストールされたコンテナイメージ上で実行する」をご紹介します。

    「直接インストールして実行する」を行いたい方はOpenTofu公式サイトのこちらを参考にしてください。

    OpenTofuの実行環境を準備

    では、OpenTofuがインストールされたコンテナイメージを使っていきたいと思います。ここでは以下の環境での実行例を紹介します。

  • 動作環境: Dockerインストール済みのLinux

  • 以下のコマンドでOpenTofuの最新のコンテナイメージを取得します。

    
    docker pull ghcr.io/opentofu/opentofu:latest
    

    次に、最低限の設定を書いたmain.tfを作成します。

    
    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 5.70.0"
        }
      }
    }
    
    provider "aws" {
      region = "ap-northeast-1"
      default_tags {
        tags = {
          create = "terraform"
        }
      }
    }
    
    locals {
      name_prefix = "tofu-test"
    }
    
    data "aws_availability_zones" "all_az" {
      filter {
        name   = "zone-type"
        values = ["availability-zone"]
      }
    }
    
    # VPC作成
    resource "aws_vpc" "main" {
      cidr_block = "192.168.56.0/24"
    
      tags = {
        Name = "${local.name_prefix}-vpc"
      }
    }
    

    次に以下のコマンドを実行してください。

    
    docker run \
        --workdir=/srv/workspace \
        --mount type=bind,source=.,target=/srv/workspace \
        ghcr.io/opentofu/opentofu:latest \
        init
    

    実行すると、以下のファイルが実行ディレクトリに自動で生成されます。

  • terraform/
  • terraform.lock.hcl
  • AWSクレデンシャルの設定

    それでは次に、AWSの認証情報を設定する方法について説明します。

    コンテナ内でデプロイコマンドを実行するためAWS認証情報を渡すためには工夫が必要になります。今回はコンテナ実行時に環境変数として認証情報を渡す方式を採用します。

    IAMユーザのアクセスキー/シークレットアクセスキーを使用して認証を行っている方は以下のコマンドを実行します。

    
    docker run \
    --workdir=/srv/workspace \
    --env AWS_ACCESS_KEY_ID="〓アクセスキー〓" \
    --env AWS_SECRET_ACCESS_KEY="〓シークレットアクセスキー〓" \
    --mount type=bind,source=.,target=/srv/workspace \
    ghcr.io/opentofu/opentofu:latest \
    plan -out=main.plan
    

    IAM Identity Centerでの認証を使用している場合は以下のコマンドを実行します。

    
    docker run \ 
    --workdir=/srv/workspace \
    --env AWS_ACCESS_KEY_ID="〓アクセスキー〓" \
    --env AWS_SECRET_ACCESS_KEY="〓シークレットアクセスキー〓" \
    --env AWS_SESSION_TOKEN="〓セッショントークン〓" \
    --mount type=bind,source=.,target=/srv/workspace \
    ghcr.io/opentofu/opentofu:latest \
    plan  -out=main.plan
    

    以下のようなログが表示されます。

    OpenTofu ログ

    Webサーバの構築

    では最後に実際にOpenTofuを使ってリソースを作成してみましょう。今回はサンプルコードとしてAmazon EC2を使ったWebサーバを構築します。

    以下がサンプルコードの続きになります。

    
    # VPC作成
    resource "aws_vpc" "main" {
      cidr_block = "192.168.0.0/24"
    
      tags = {
        Name = "${local.name_prefix}-vpc"
      }
    }
    
    ## ここから下を追記してください
    
    # VPCからサブネットをさらに作成
    resource "aws_subnet" "main" {
    
      vpc_id     = aws_vpc.main.id
      cidr_block = "192.168.0.0/26"
      tags = {
        Name = "${local.name_prefix}-subnet"
      }
    }
    
    resource "aws_internet_gateway" "main" {
      vpc_id = aws_vpc.main.id
    
      tags = {
        Name = "${local.name_prefix}-igw"
      }
    }
    
    resource "aws_route_table" "main" {
      vpc_id = aws_vpc.main.id
    
      route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.main.id
      }
      route {
        cidr_block = aws_vpc.main.cidr_block
        gateway_id = "local"
      }
    }
    
    resource "aws_route_table_association" "main" {
      subnet_id      = aws_subnet.main.id
      route_table_id = aws_route_table.main.id
    }
    
    # EC2インスタンス用のパブリックAMIを取得
    data "aws_ami" "ubuntu" {
      most_recent = true
    
      filter {
        name   = "name"
        values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
      }
    
      filter {
        name   = "virtualization-type"
        values = ["hvm"]
      }
    
      owners = ["099720109477"] # Canonical
    }
    
    resource "aws_instance" "web" {
      ami                         = data.aws_ami.ubuntu.id
      instance_type               = "t3.micro"
      subnet_id                   = aws_subnet.main.id
      security_groups             = [aws_security_group.main.id]
      associate_public_ip_address = true
      # ユーザデータの内容は不要なスペースを入れないように左揃えにしてください
      user_data = < /var/www/html/index.html
    EOF
    
      tags = {
        Name = "${local.name_prefix}-ec2"
      }
    }
    
    # セキュリティグループを作成
    resource "aws_security_group" "main" {
      name   = "${local.name_prefix}-sg"
      vpc_id = aws_vpc.main.id
    
      tags = {
        Name = "${local.name_prefix}-sg"
      }
    }
    
    resource "aws_vpc_security_group_ingress_rule" "allow_http" {
    
      security_group_id = aws_security_group.main.id
      cidr_ipv4         = "〓WebサイトにアクセスするグローバルIPアドレス〓/32" # 誰でもアクセスできてよいのであれば0.0.0.0/0でも問題ないです
      ip_protocol       = "tcp"
      from_port         = 80
      to_port           = 80
    
      tags = {
        Name = "${local.name_prefix}-http-ingress-rule"
      }
    }
    
    resource "aws_vpc_security_group_egress_rule" "main" {
      security_group_id = aws_security_group.main.id
    
      cidr_ipv4   = "0.0.0.0/0"
      ip_protocol = -1
    
      tags = {
        Name = "${local.name_prefix}-egress-rule"
      }
    }
    
    # 画面表示用
    output "ec2_ip" {
      value = aws_instance.web.public_ip
    }
    

    上記のコードを保存した後に、以下のコマンドを実行します。

    
    # 変更内容を再度出力します
    docker run \
    --workdir=/srv/workspace \
    --env AWS_ACCESS_KEY_ID="〓アクセスキー〓" \
    --env AWS_SECRET_ACCESS_KEY="〓シークレットアクセスキー〓" \
    --mount type=bind,source=.,target=/srv/workspace \
    ghcr.io/opentofu/opentofu:latest \
    plan -out=main.plan
    
    # 上のコマンドで出力した内容をデプロイします
    docker run \
    --workdir=/srv/workspace \
    --env AWS_ACCESS_KEY_ID="〓アクセスキー〓" \
    --env AWS_SECRET_ACCESS_KEY="〓シークレットアクセスキー〓" \
    --mount type=bind,source=.,target=/srv/workspace \
    ghcr.io/opentofu/opentofu:latest \
    apply "/srv/workspace/main.plan"
    

    ※ IAM Identity Centerでの認証を使用している方はAWS_SESSION_TOKENを追加してください

    実行後に以下のようなログが出力されれば成功です。

    OpenTofu 実行後のログ出力

    ※ IPアドレス部分に関しては塗りつぶしております

    数分待ってから、ブラウザで出力されたIPアドレスにアクセスしてみます。以下のようなページが表示されれば成功です。

    OpenTofu ブラウザで出力されたIPアドレスにアクセス

    最後に、以下のコマンドで作成したリソースの削除を行います。

    
    # リソースの全削除を行います
    docker run \
    --workdir=/srv/workspace \
    --env AWS_ACCESS_KEY_ID="〓アクセスキー〓" \
    --env AWS_SECRET_ACCESS_KEY="〓シークレットアクセスキー〓" \
    --mount type=bind,source=.,target=/srv/workspace \
    ghcr.io/opentofu/opentofu:latest \
    destroy -auto-approve
    

    ※ IAM Identity Centerでの認証を使用している方はAWS_SESSION_TOKENを追加してください

    以下のようなログが出力されれば削除完了です。

    OpenTofu リソースの削除

    まとめ

    今回はOpenTofuについてご紹介しました。初めての方にもOpenTofuの概要が理解していただけたのではないでしょうか?

    使ったことはないけどIaCが気になっていた方やTerraformは使っているけどOpenTofuは使ったことのない方は、この機会にぜひ試してみてください。

    最後に宣伝にはなりますが、弊社では24時間365日の有人体制でAWSの監視・運用・管理をまとめてご依頼いただけるサービスをご提供しています。

    障害が発生した場合、原因の切り分けから実際の復旧作業まで実施することもできるため、夜間休日の障害でも安心です。

    JIG-SAW OPS AWS

    また、JIG-SAWからAWSをご契約いただくとAWSの利用料が割引でご利用いただく事も可能です。

    利用料の割引だけでなく様々な無料特典もつき、システム構築や監視・運用、セキュリティサポートなど各種オプションサービスもご用意しておりますので、ぜひお気軽にご相談ください。

    AWSが8%OFFになる請求代行