第三个环境配置的模块是Rails使用的”Terraform”
首先
我将使用Terraform创建AWS (EC2,RDS)。
整体趋势
-
- 安装Terraform
-
- 创建IAM用户在AWS上
-
- 安装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 = ※※※※※※※※※
如果有任何问题,请在评论栏中留言。