0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS 無料チュートリアルその6: Terraform を用いてサーバーに Nginx を自動で入れる

0
Posted at

AWS チュートリアル

AWSの無料枠で出来る範囲のチュートリアルがあったので試してみた経過を簡単にまとめてみました。
AWS等の実際の画面や操作はどんな感じか知りたい方を読者対象としているつもりです。

著者はAWS クラウドプラクティショナー、ソリューションアーキテクト アソシエイト という資格を取得済みで「AWSってなんぞや?」という概要を知識としてある程度理解しているが、実際にAWSの画面を触ったことが無いという状態でAWSのチュートリアルをこなしていくという状況です。

今回の内容としては、Terraform を用いて nginx の自動化をする、というものです。

何をやるのか

今は

EC2作る → 手動でSSH → nginx入れる

これを

terraform apply → すでにnginxが動いている

つまり、サーバーが完成状態で起動する

仕組み(重要)

EC2には「起動時に実行されるスクリプト」があります

→ それが user_data

実際のコード

前回作成した main.tf をこう書き換えます

main.tf
provider "aws" {
  region = "ap-northeast-1"
}

# セキュリティグループ
resource "aws_security_group" "web_sg" {
  name = "web-sg"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# EC2
resource "aws_instance" "web" {
  ami           = "ami-0c3fd0f5d33134a76"
  instance_type = "t3.micro"

  vpc_security_group_ids = [aws_security_group.web_sg.id]

  user_data = <<-EOF
              #!/bin/bash
              yum install -y nginx
              systemctl start nginx
              systemctl enable nginx
              EOF

  tags = {
    Name = "terraform-nginx"
  }
}

この1行の意味

main.tf
vpc_security_group_ids = [aws_security_group.web_sg.id]

aws_security_group.web_sg
→ 上で作ったセキュリティグループ
.id
→ そのID(sg-xxxx)

→ 作ったSGをEC2に紐づけている

実行手順

</> Bash
terraform apply
→ yes

悪戦苦闘ログ

「terraform apply」と打ってみたものの、

XXX@DESKTOP-KAKL1SL MINGW64 /D/Userdata/documents/terraform-test
$ terraform apply
╷
│ Error: Failed to load plugin schemas
│
│ Error while loading schemas for plugin components: Failed to obtain
│ provider schema: Could not load the schema for provider
│ registry.terraform.io/hashicorp/aws: failed to instantiate provider
│ "registry.terraform.io/hashicorp/aws" to obtain schema: timeout while
│ waiting for plugin to start..
╵

AWSプロバイダ(プラグイン)が起動できていない状態です

よくある原因(ほぼこのどれか)

① プラグインが壊れている(最有力)
ダウンロード途中で壊れることがあります

② Windows + Git Bash 特有の問題
TerraformはネイティブWindows前提なので:

👉 Git Bashだとプラグイン起動でコケることがあります

③ セキュリティソフト干渉
Defender
ウイルス対策

👉 プラグイン実行をブロックすることあり

解決方法 (順番にやればOK)

方法①:キャッシュ削除(まずこれ)
Terraformフォルダで

rm -rf .terraform
rm .terraform.lock.hcl

その後

terraform init
terraform apply

方法②:PowerShellで実行(かなり有効)

Git Bashではなく

PowerShell
コマンドプロンプト

方法③:Terraform再インストール
公式から再DL
zip展開し直し

つまづきポイント

パブリック IPv4 アドレス、パブリック DNS アドレスをブラウザで入れてもエラーになって表示されない。

image.png

image.png

可能性その5

色々試す中で、VPC 周りの設定が良くないのか?と思い

VPC → お使いの VPC → VPC を作成

image.png

「VPCなど」 → VPC を作成

image.png

このような画面で進捗を見て → VPC を表示

image.png

リソースマップ → サブネット

image.png

パブリック IPv4 アドレスを自動割り当て
→ いいえなら、

image.png

アクション → サブネットの設定を編集

image.png

「パブリック IPv4 アドレスの自動割り当てを有効化」にチェックを入れ、「保存」

image.png

サブネットID, VPC の名前をメモし、

image.png

コードに貼り付け

main.tf
provider "aws" {
  # 東京リージョン
  region = "ap-northeast-1"
}

# セキュリティグループ
resource "aws_security_group" "web_sg" {
  name = "web-sg"
  vpc_id = "vpc-0264525fb389542fc"

  #
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# EC2
resource "aws_instance" "web" {
  ami           = "ami-0c3fd0f5d33134a76"

  # 無料枠のものを選択
  instance_type = "t3.micro"

  subnet_id = "subnet-039e3387eace155c2"

  associate_public_ip_address = true

  vpc_security_group_ids = [aws_security_group.web_sg.id]

user_data = <<-EOF
#!/bin/bash
exec > /var/log/user-data.log 2>&1

# 初期化待ち
sleep 30

# Extras有効化してnginxインストール: nginx ではなく nginx1
amazon-linux-extras install -y nginx1

# 起動
systemctl start nginx
systemctl enable nginx
EOF

  tags = {
    Name = "terraform-nginx"
  }
}


するも、nginx 画面が出ず…

可能性その 6

VPC → ルートテーブル が

image.png

のようになり、正しいルートテーブルは

0.0.0.0/0 → igw-xxxx

のはずなのにターゲットがlocalになっているところが間違っているポイントのようで、
「ルートテーブルの関連付けを編集」

image.png

ルートテーブルIDを、ルートでターゲットが「igw」で始まるものが出てくるものを選択し、「保存」
image.png

…するもダメ…


「サブネットは正しい」
「ルートテーブルも正しい」
それでもダメ

原因として、「EC2のネットワークインターフェースが正しくパブリック経路に乗っていない」可能性

EC2 → Elastic IP → 「Elastic IP アドレスを割り振る」 → 「割り振る」

image.png

「アクション」 → 「関連付け」

image.png

「インスタンス」で対象インスタンスを選択 → 「関連付ける」

image.png

上記のようにElastic IP を設定し、http://Elastic IP に接続…も、タイムアウト状態は変わらず。(ダメ…)

再点検

セキュリティグループが本当に効いているかチェック

EC2 → インスタンス → 該当するインスタンスを選択 → 「接続」

image.png

「接続」

image.png

「パブリックIpv4アドレス」をコピーし、

image.png

先ほど接続で出した黒背景のターミナル(EC2)で

curl -I http://<自分のパブリックIPv4アドレス>

とすると

HTTP/1.1 200 OK

となった

→ セキュリティグループ or 外部経路の問題


nginxの待ち受け確認

黒背景のターミナル(EC2)で

sudo ss -tuln | grep 80

正常なら

0.0.0.0:80

→ 正常


nginx設定

EC2 で

sudo cat /etc/nginx/nginx.conf | grep listen

正常なら

listen 80;

→ 正常

セキュリティグループの実体確認

EC2コンソール(白背景)で

EC2 → インスタンス → 実行中のもの → セキュリティ → インバウンドルール →
ポート: 80
ソース: 0.0.0.0/0

image.png

正常なら

ポート80
0.0.0.0/0

→ 正常

OS Firewall

EC2(黒背景)で

sudo iptables -L

DROP があれば

sudo systemctl stop firewalld
sudo iptables -F

ローカルホスト、プライベートIP, パブリックIPの確認

EC2(黒背景)で

curl -I http://localhost
curl -I http://<プライベートIP>
curl -I http://<パブリックIP>
結果 原因
localhost OK / private NG OS
private OK / public NG AWS側
全部OK 外部経路

→ 全部OKだったので原因は外部経路


EC2 → 外部へ通信できる
EC2 → 自分のパブリックIPにも到達できる

→ AWS内のネットワークは完全に正常

→ インスタンス自体は完全に正常。問題は「VPCの外側(自分のPC側)」

つまり何が起きているか
PC → AWS への通信だけ失敗している

テスト 結果
EC2内部 localhost OK
EC2内部 public IP OK
自PC curl public IP OK
ブラウザ

→ AWS・EC2・nginxは「完全に正常」
→ 問題は「ブラウザ表示だけ」


  1. シークレットモードでアクセス
    → NG
  2. 別ブラウザで試す
    → NG
  3. URL確認(地味に多い)
    これになってないか確認
https://<IP>

正しくは

http://<IP>

ここが間違っていた!

ブラウザが Microsoft edge だったからか、パブリックIPv4アドレス、パブリックDNSのリンクをクリックすると

image.png

このように、http:// ではなく https:// でリンクに飛ばされるというのが罠だったのだ

image.png

現状で開いているのは http のポート 80 であって、HTTPSではないために、タイムアウトしてしまったということのようである。

httpの表示が隠れているが、http:// で繋いでみると、無事

image.png

このように、サーバーを表示することが出来た。
長かった…

最終的な 環境構築ファイル について

main.tf
############################################
# プロバイダー設定(AWS東京リージョン)
############################################
provider "aws" {
  region = "ap-northeast-1"
}

############################################
# VPC(ネットワークの土台)
############################################
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "terraform-vpc"
  }
}

############################################
# インターネットゲートウェイ(外部通信)
############################################
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "terraform-igw"
  }
}

############################################
# パブリックサブネット(インターネット接続用)
############################################
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "ap-northeast-1a"

  # EC2起動時にパブリックIP自動付与
  map_public_ip_on_launch = true

  tags = {
    Name = "terraform-public-subnet"
  }
}

############################################
# ルートテーブル(通信経路の定義)
############################################
resource "aws_route_table" "public_rt" {
  vpc_id = aws_vpc.main.id

  # インターネットへのルート
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }

  tags = {
    Name = "terraform-public-rt"
  }
}

############################################
# サブネットとルートテーブルの関連付け
############################################
resource "aws_route_table_association" "public_assoc" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public_rt.id
}

############################################
# セキュリティグループ(通信制御)
############################################
resource "aws_security_group" "web_sg" {
  name   = "web-sg"
  vpc_id = aws_vpc.main.id

  # HTTP(Webアクセス)
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # SSH(接続用)※本番では制限推奨
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 全通信許可(外向き)
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "terraform-web-sg"
  }
}

############################################
# EC2インスタンス(Webサーバー)
############################################
resource "aws_instance" "web" {
  ami           = "ami-0c3fd0f5d33134a76" # Amazon Linux 2
  instance_type = "t3.micro"

  subnet_id                   = aws_subnet.public.id
  vpc_security_group_ids      = [aws_security_group.web_sg.id]
  associate_public_ip_address = true

  ##########################################
  # user_data(起動時に自動実行されるスクリプト)
  ##########################################
  user_data = <<-EOF
#!/bin/bash
exec > /var/log/user-data.log 2>&1

# 少し待つ(初期化安定のため)
sleep 30

# nginxインストール(Amazon Linux 2)
amazon-linux-extras install -y nginx1

# nginx起動
systemctl start nginx

# 自動起動設定
systemctl enable nginx
EOF

  tags = {
    Name = "terraform-nginx"
  }
}

############################################
# 出力(IPを表示)
############################################
output "public_ip" {
  value = aws_instance.web.public_ip
}

output "public_dns" {
  value = aws_instance.web.public_dns
}

このファイルを用意し、そのフォルダで

terraform destroy
 → yes
terraform apply
 → yes

とすることで、環境をコードから構築することができるようになります。
※ 初期化安定のため sleep が入っているので、起動したように見えてから1~2分ほど待つ必要があります。

パブリックDNSを表示させる

main.tfファイルで terraform apply から起動したものの、パブリックDNSが非表示になっている

image.png

これを表示させるには、以下の手順を踏む。

VPC → お使いのVPC → 該当のVPCを選択 → アクション → VPCの設定を編集

image.png

DNS設定 → DNS解決を有効化・DNSホスト名を有効化に両方チェック → 保存

image.png

EC2 → インスタンスに戻り、上部の更新マークを選択することで、パブリックDNSが表示されるようになります。

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?