第三个环境配置的模块是Rails使用的”Terraform”

首先

我将使用Terraform创建AWS (EC2,RDS)。

整体趋势

    1. 安装Terraform

 

    1. 创建IAM用户在AWS上

 

    1. 安装AWS CLI

在AWS CLI上注册IAM用户

什么是Terraform
安装Terraform

配置提供商
创建VPC
创建子网
创建互联网网关
创建路由表
创建EC2
创建安全组
创建RDS

* 10分钟内了解Terraform

安装Terraform

$ brew update
$ brew install terraform

在AWS中创建IAM用户。

* 欢迎访问 Identity and Access Management
* 使用 Terraform 构建 AWS


AdministratorAccessポリシー(管理者権限)を選択してください。

権限が足りないと
Error creating VPC: UnauthorizedOperation: You are not authorized to perform this operation.
とエラーが出ます。

安装 AWS CLI

参考文献
– 安装和配置AWS CLI
按顺序进行即可,但对我来说,在设置Python的路径和环境时遇到了一些问题
错误解决↓
– 在MacOS和Homebrew和pyenv上创建舒适的Python环境
– 确认Python和Python3的安装位置、路径等信息
– 从Python2.7切换到默认的Python3.6版本
– 安装Python3(适用于Mac)

我认为如果参考上述链接的话,就可以了。

curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli

如果安装没有错误并且版本正确地显示出来,那就是成功了。

pip --version
aws --version

将IAM用户注册到AWS CLI

aws configure
または、
aws configure --profile ユーザー名

依次填写

AWS CLI の設定

AWS-CLIの初期設定のメモ
それぞれ先ほど作成した、IAMユーザーをコピペします。
リージョンと出力形式はリンク先から選んでください。

AWS Access Key ID [None]: 
AWS Secret Access Key [None]: 
Default region name [None]: 
Default output format [None]: json
# Asia Pacific (Tokyo) ap-northeast-1

“terraform” 是什么意思?

通过将基础设施编写成代码的形式,可以直接对基础设施进行修改,实现代码的共享和重复利用,无需通过GUI界面。参考资料包括《自动化基础设施配置管理的入门指南:Terraform》和《使用Terraform创建AWS的VPC并启动EC2实例》。常用的文件格式为.tf和.tfvars。文件的分割可以延后,所有内容都写在main.tf中。

主要命令

# 初期化 Terraformで新しく設定を記述した場合、初期化を行う必要があります。
terraform init
# 確認(所謂dry-run)
terraform plan
# 適用 コードの状態をAWS上へ適用
terraform apply
# すべて消去するコマンド
terraform destroy
# リソースの閲覧
terraform show

备用

mkdir terraform
cd terraform
touch main.tf
touch terraform.tfvars

提供者的设置

需要首先指定provider。
由于可适用于多个环境,需声明“要使用哪个提供者?”

“提供者”是什么意思?

    • その名と通りプロバイダでAWSの他にherokuやGCPもできるらしい

 

    • profileでaws configでprofileを指定した場合はその名前、していない場合は”default”

region = “ap-northeast-1″で指定したリージョン内にVPCなどを作っていく


provider "aws" {
  profile = ユーザー名
  region  = "ap-northeast-1"
}

创建VPC

使用AWS_VPC资源

# VPC
resource "aws_vpc" "aws-tf-vpc" {
  cidr_block           = "10.1.0.0/16"
  instance_tenancy     = "default"

  tags = {
    Name = "aws-tf-vpc"
  }
}

执行

terraform init
terraform plan
terraform apply

# リソースの閲覧
terraform show

试着实际去验证

    実際にAWSにアクセスして確認してみましょう

只要有一个写有”aws-tf-vpc”的VPC,就算成功。

“资源”一词的意思

resourceはVPCやEC2のような起動したいリソースを定義
リソースの種類は、プロバイダーがAWSの場合はaws_*という名前でTerraformで予め定義されています。VPCであればaws_vpc、EC2であればaws_instanceです。

资源的语法

リソースはresourceブロックで設定します。resource "<リースの種類>" "<リソース名>" {}という構文です。

资源的定义和命名

resource "aws_vpc" "this" {

ここでは 「"aws_vpc"というリソースを"this"という名前」 で作成しています。
resource "aws_vpc" まではAWSのVPCを作成するという意味で、 "this" はTerraformで定義する他のリソースから参照する際に使用します。

参考他资源的属性

Terraformにはテンプレート内の他リソースの属性を参照する方法があります。
具体的には、<リソースの種類>.<リソース名>.<属性名>で他リソースの属性を参照することができます。

其他知识请点击下面的链接
* 学习如何在AWS上使用Terraform

将VSCode升级至支持Terraform v0.12版本。


下記のようなメッセージが出た人向け
For Terraform 0.12 support try enabling the experimental language server with the 'Terraform: Enable/Disable Language Server' command

コマンドパレットを開く(ctl/cmd+shift+p)
terraform: install/update language server -> 現在最新の v0.0.9 を選択
terraform: Enable/Disable Language Server を実行
一度vscodeを閉じたらHCL2記法の.tfファイルでもエラーが出なくなりました。

    • VSCodeでTerraformを書くときの設定(2019/11/07追記: HCL2対応)

 

    feat: Terraform 0.12 support (was hcl2 support) #157

添加不能上传到.gitignore的文件。

我会把以下文件添加到GitHub上,因为不能上传到GitHub。
* Terraform.gitignore

#  Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# .tfvars files
*.tfvars

创建子网

使用的资源aws_subnet


# サブネット2つ作成(publicとprivate)
resource "aws_subnet" "aws-tf-public-subnet-1a" {
  vpc_id            = aws_vpc.aws-tf-vpc.id
  cidr_block        = "10.1.1.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    Name = "aws-tf-public-subnet-1a"
  }
}

resource "aws_subnet" "aws-tf-private-subnet-1a" {
  vpc_id            = aws_vpc.aws-tf-vpc.id
  cidr_block        = "10.1.20.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    Name = "aws-tf-private-subnet-1a"
  }
}

创建互联网网关

使用资源aws_internet_gateway

resource "aws_internet_gateway" "aws-tf-igw" {
  vpc_id = aws_vpc.aws-tf-vpc.id
  tags = {
    Name = "aws-tf-igw"
  }
}

创建路由表

AWS 路由表资源

resource "aws_route_table" "aws-tf-public-route" {
  vpc_id = aws_vpc.aws-tf-vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.aws-tf-igw.id
  }
  tags = {
    Name = "aws-tf-public-route"
  }
}

将路由表与公共子网相关联

使用AWS路由表关联

resource "aws_route_table_association" "aws-tf-public-subnet-association" {
  subnet_id      = aws_subnet.aws-tf-public-subnet-1a.id
  route_table_id = aws_route_table.aws-tf-public-route.id
}

创建 EC2 实例(在公共网络中创建)。

使用的资源为aws_instance和aws_key_pair。

resource "aws_instance" "aws-tf-web" {
  ami                     = "ami-011facbea5ec0363b"
  instance_type           = "t2.micro"
  disable_api_termination = false
  key_name = aws_key_pair.auth.key_name
  vpc_security_group_ids  = [aws_security_group.aws-tf-web.id]
  subnet_id               = aws_subnet.aws-tf-public-subnet-1a.id

  tags = {
    Name = "aws-tf-web"
  }
}

# amiとはAmazon Linux 2 AMIです。今回は実際のamiの値を直接入れてますが、いつも最新版にできます。

variable "public_key_path" {}

resource "aws_key_pair" "auth" {
    key_name = "terraform-aws"
    public_key = file(var.public_key_path)
}
# ローカルに鍵がある場所を指定
public_key_path = "~/.ssh/terraform-aws.pub"

确保我始终使用最新版本的Ami。

    • Terraformでもいつでも最新AMIからEC2を起動したい

TerraformでAWS AMIの最新を常に使うようにする

关于实例的key_name。

在使用GUI创建时,在创建实例的同时,会使用新创建的ssh密钥或现有的密钥来访问AWS。但是在使用terraform创建时,将从.tfvars文件中引用并将公钥粘贴到实例的key_name中。
我创建了一个名为terraform-aws的密钥。

$ cd .ssh
$ ssh-keygen -t rsa
terraform-aws 今回の場合の名前
ここでエンターキーを2連打
$ ls
ここでterraform-aws  terraform-aws.pubができていることを確認

参考:
* 资源:aws_key_pair
* 通过Terraform注册并启动EC2并进行SSH连接

有关Terraform变量的信息

Terraform的变量通过variable块来定义。可以使用var.<变量名>的格式进行引用。如果将值定义在外部文件中,例如terraform.tfvars,它将自动被读取并赋值给变量。而.tfvars的重要性在于不需要将其上传至GitHub。参考【Terraform 再入门】,让我们一键通过命令行来构建由EC2和RDS组成的最小化AWS环境。

创建安全组

使用AWS安全组和AWS安全组规则

resource "aws_security_group" "aws-tf-web" {
  name        = "aws-tf-web"
  description = "aws-tf-web_sg"
  vpc_id      = aws_vpc.aws-tf-vpc.id
  tags = {
    Name = "aws-tf-web"
  }
}

# 80番ポート許可のインバウンドルール
resource "aws_security_group_rule" "inbound_http" {
  type      = "ingress"
  from_port = 80
  to_port   = 80
  protocol  = "tcp"
  cidr_blocks = [
    "0.0.0.0/0",
  ]

  # ここでweb_serverセキュリティグループに紐付け
  security_group_id = aws_security_group.aws-tf-web.id
}

# 22番ポート許可のインバウンドルール
resource "aws_security_group_rule" "inbound_ssh" {
  type      = "ingress"
  from_port = 22
  to_port   = 22
  protocol  = "tcp"
  cidr_blocks = [
    "0.0.0.0/0",
  ]

  # ここでweb_serverセキュリティグループに紐付け
  security_group_id = aws_security_group.aws-tf-web.id
}

# アウトバウンドルール
resource "aws_security_group_rule" "outbound_all" {
  type      = "egress"
  from_port = 0
  to_port   = 0
  protocol  = -1
  cidr_blocks = [
    "0.0.0.0/0",
  ]

  # ここでweb_serverセキュリティグループに紐付け
  security_group_id = aws_security_group.aws-tf-web.id
}

安全组详细信息

    • Terraform でセキュリティグループを管理

 

    • Terraformで1つのセキュリティグループに複数のルールを設定する

 

    TerraformでSecurity Groupを作ったら上手くいかなかった

创建弹性IP

使用亚马逊弹性 IP 资源

resource "aws_eip" "aws-tf-eip" {
  instance = aws_instance.aws-tf-web.id
  vpc      = true
}
output "example-public-ip" {
    value = "${aws_eip.aws-tf-eip.public_ip}"
}

关于输出

弹性IP等可以通过GUI进行确认,但如果在输出块中进行描述,则在运行terraform apply时将输出以下内容。

Apply complete! 

Outputs:

example-public-ip = ElasticIP

创建 RDS

由于RDS需要两个子网,所以我们将从另一个可用区创建一个子网。
我们将使用aws_subnet和aws_db_subnet_group这两个资源。

# RDS用のサブネットを作成
resource "aws_subnet" "aws-tf-private-subnet-1c" {
  vpc_id = aws_vpc.aws-tf-vpc.id
  cidr_block = "10.1.3.0/24"
  availability_zone = "ap-northeast-1c"
  tags = {
    Name = "aws-tf-private-subnet-1c"
  }
}
# 使用する2つを指定します。
resource "aws_db_subnet_group" "rdb-tf-db" {
    name        = "rdb-tf-db-subnet"
    description = "It is a DB subnet group on tf_vpc."
    subnet_ids  = [aws_subnet.aws-tf-private-subnet-1a.id,aws_subnet.aws-tf-private-subnet-1c.id]
    tags = {
        Name = "rdb-tf-db"
    }
}

创建用于数据库的安全性

为了仅允许Web服务器访问DB服务器,我们将创建安全性措施。
使用的资源是aws_security_group和aws_security_group_rule。

# Security Group
resource "aws_security_group" "aws-tf-db" {
    name        = "aws-tf-db"
    description = "aws-tf-db-sg"
    vpc_id      = aws_vpc.aws-tf-vpc.id
    tags = {
      Name = "aws-tf-db"
    }
}

resource "aws_security_group_rule" "db" {
    type                     = "ingress"
    from_port                = 5432
    to_port                  = 5432
    protocol                 = "tcp"
    source_security_group_id = aws_security_group.aws-tf-web.id
    security_group_id        = aws_security_group.aws-tf-db.id
}

# source_security_group_idとはアクセスを許可するセキュリティグループIDつまりWeb側のセキュリティグループを指します。

创建RDS实例

使用AWS的DB实例



variable "aws-td-db-username" {}
variable "aws-td-db-password" {}

resource "aws_db_instance" "aws-td-db" {
  identifier              = "aws-td-db"
  allocated_storage       = 20
  name = "db11"
  engine                  = "postgres"
  engine_version          = "11.5"
  instance_class          = "db.t2.micro"
  storage_type            = "gp2"
  username                = var.aws-td-db-username
  password                = var.aws-td-db-password
  vpc_security_group_ids  = [aws_security_group.aws-tf-db.id]
  db_subnet_group_name    = aws_db_subnet_group.rdb-tf-db.name
}


public_key_path = "~/.ssh/terraform-aws.pub"
aws-td-db-username = ※※※※※※※※※※
aws-td-db-password = ※※※※※※※※※
それぞれ指定してください。

执行

terraform plan
terraform apply
# 確認
terrafom show

关于在创建RDS实例时遇到的错误

DBName must begin with a letter and contain only alphanumeric characters

これはRDSインスタンスのnameについてのエラーです。私の場合は`name = "db11"`と書きましたが、文字で初めて英数字両方を書かないといけないらしいです。

AWS aws_db_instance 数据库名称问题

Error creating DB Instance: InvalidParameterValue: Invalid DB engine

これはRDSインスタンスの`engine`の名前の書き方でエラーが出ました。今回は`engine = "postgres"`と書きました。

创建AWS/RDS PostgreSQL实例时出现”无效的DB引擎”错误。
请查看引擎部分。

以下内容有中文版本。

provider "aws" {
  profile = プロフィール名
  region  = "ap-northeast-1"
}

# VPC作成
resource "aws_vpc" "aws-tf-vpc" {
  cidr_block           = "10.1.0.0/16"
  instance_tenancy     = "default"
  enable_dns_support   = "true"
  enable_dns_hostnames = "true"
  tags = {
    Name = "aws-tf-vpc"
  }
}

# サブネット2つ作成(publicとprivate)
resource "aws_subnet" "aws-tf-public-subnet-1a" {
  vpc_id            = aws_vpc.aws-tf-vpc.id
  cidr_block        = "10.1.1.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    Name = "aws-tf-public-subnet-1a"
  }
}

resource "aws_subnet" "aws-tf-private-subnet-1a" {
  vpc_id            = aws_vpc.aws-tf-vpc.id
  cidr_block        = "10.1.20.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    Name = "aws-tf-private-subnet-1a"
  }
}

# インターネットゲートウェイの作成
resource "aws_internet_gateway" "aws-tf-igw" {
  vpc_id = aws_vpc.aws-tf-vpc.id
  tags = {
    Name = "aws-tf-igw"
  }
}

# ルートテーブルの作成
resource "aws_route_table" "aws-tf-public-route" {
  vpc_id = aws_vpc.aws-tf-vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.aws-tf-igw.id
  }
  tags = {
    Name = "aws-tf-public-route"
  }
}

# サブネットの関連付けでルートテーブルをパブリックサブネットに紐付け
resource "aws_route_table_association" "aws-tf-public-subnet-association" {
  subnet_id      = aws_subnet.aws-tf-public-subnet-1a.id
  route_table_id = aws_route_table.aws-tf-public-route.id
}

# EC2作成(public側)
resource "aws_instance" "aws-tf-web" {
  ami                     = "ami-011facbea5ec0363b"
  instance_type           = "t2.micro"
  disable_api_termination = false
  key_name = aws_key_pair.auth.key_name
  vpc_security_group_ids  = [aws_security_group.aws-tf-web.id]
  subnet_id               = aws_subnet.aws-tf-public-subnet-1a.id

  tags = {
    Name = "aws-tf-web"
  }
}
variable "public_key_path" {}

resource "aws_key_pair" "auth" {
    key_name = "terraform-aws"
    public_key = file(var.public_key_path)
}
# Security Group
resource "aws_security_group" "aws-tf-web" {
  name        = "aws-tf-web"
  description = "aws-tf-web_sg"
  vpc_id      = aws_vpc.aws-tf-vpc.id
  tags = {
    Name = "aws-tf-web"
  }
}

# 80番ポート許可のインバウンドルール
resource "aws_security_group_rule" "inbound_http" {
  type      = "ingress"
  from_port = 80
  to_port   = 80
  protocol  = "tcp"
  cidr_blocks = [
    "0.0.0.0/0",
  ]

  # ここでweb_serverセキュリティグループに紐付け
  security_group_id = aws_security_group.aws-tf-web.id
}

# 22番ポート許可のインバウンドルール
resource "aws_security_group_rule" "inbound_ssh" {
  type      = "ingress"
  from_port = 22
  to_port   = 22
  protocol  = "tcp"
  cidr_blocks = [
    "0.0.0.0/0",
  ]

  # ここでweb_serverセキュリティグループに紐付け
  security_group_id = aws_security_group.aws-tf-web.id
}

# アウトバウンドルール
resource "aws_security_group_rule" "outbound_all" {
  type      = "egress"
  from_port = 0
  to_port   = 0
  protocol  = -1
  cidr_blocks = [
    "0.0.0.0/0",
  ]

  # ここでweb_serverセキュリティグループに紐付け
  security_group_id = aws_security_group.aws-tf-web.id
}

# ElasticIP
resource "aws_eip" "aws-tf-eip" {
  instance = aws_instance.aws-tf-web.id
  vpc      = true
}
output "example-public-ip" {
    value = aws_eip.aws-tf-eip.public_ip
}

####RDSの作成
# RDS用のサブネットを作成
resource "aws_subnet" "aws-tf-private-subnet-1c" {
  vpc_id = aws_vpc.aws-tf-vpc.id
  cidr_block = "10.1.3.0/24"
  availability_zone = "ap-northeast-1c"
  tags = {
    Name = "aws-tf-private-subnet-1c"
  }
}
# DB用のセキュリティーを作成
# Security Group
resource "aws_security_group" "aws-tf-db" {
    name        = "aws-tf-db"
    description = "aws-tf-db-sg"
    vpc_id      = aws_vpc.aws-tf-vpc.id
    tags = {
      Name = "aws-tf-db"
    }
}

resource "aws_security_group_rule" "db" {
    type                     = "ingress"
    from_port                = 5432
    to_port                  = 5432
    protocol                 = "tcp"
    source_security_group_id = aws_security_group.aws-tf-web.id
    security_group_id        = aws_security_group.aws-tf-db.id
}

resource "aws_db_subnet_group" "rdb-tf-db" {
    name        = "rdb-tf-db-subnet"
    description = "It is a DB subnet group on tf_vpc."
    subnet_ids  = [aws_subnet.aws-tf-private-subnet-1a.id,aws_subnet.aws-tf-private-subnet-1c.id]
    tags = {
        Name = "rdb-tf-db"
    }
}

variable "aws-td-db-username" {}
variable "aws-td-db-password" {}

resource "aws_db_instance" "aws-td-db" {
  identifier              = "aws-td-db"
  allocated_storage       = 20
  name = "db11"
  engine                  = "postgres"
  engine_version          = "11.5"
  instance_class          = "db.t2.micro"
  storage_type            = "gp2"
  username                = var.aws-td-db-username
  password                = var.aws-td-db-password

  vpc_security_group_ids  = [aws_security_group.aws-tf-db.id]
  db_subnet_group_name    = aws_db_subnet_group.rdb-tf-db.name
}

public_key_path = "~/.ssh/terraform-aws.pub"
aws-td-db-username = ※※※※※※※※※※
aws-td-db-password = ※※※※※※※※※

如果有任何问题,请在评论栏中留言。

bannerAds