6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【AWS】用語を整理しながら学ぶAWS - 番外編-EC2上にRails6環境を構築(一部Terraform利用)

Last updated at Posted at 2021-02-08

はじめに

この記事では AWS Cloud Tech を通して IaC を学習して実践していく記事です。
主な内容としては実践したときのメモを中心に書きます。(忘れやすいことなど)
誤りなどがあれば書き直していく予定です。

※AWS Cloud Tech では CloudFormation が基礎から学習できます。
※今回チョットだけ扱う Terraform は AWS Cloud Tech で学習しません。(2021/02/08 Mon 現在)

※この記事で紹介する Rails 環境のパラメータ(パスワードやユーザ名、権限)などはご自身の環境に
合わせていただくようお願い致します。

また、今回は一度も使っていませんが
今後はプライベートネットワークにも何かしら置く予定です。

Terraform とは

HashiCorp 社 が提供する製品の名前
巷で話題のインフラをコード化するということが各クラウドでできます。
今回は AWS を題材に使いますが、Azure,GCP でもできます。

なぜ、Terraform なのか

私が思う Terraform を採用する理由

  • インフラをコードという形で実現できる
  • 他のクラウドでインフラを構築しようと思った際にコードがインフラの設計図になる
  • 他のクラウドにも対応しているので構築するインフラ毎にコードを書いてハイブリッドにインフラを構築することができる

AWS なら CloudFormation があるので最初の 2 つはあまり理由になりませんが

ハイブリッドにパブリッククラウドを繋ぐときに複数のクラウドサービスのIaCにも対応している為
一気通貫でインフラの柔軟な構築が可能になる。
極端なことを言えば、AWS,Azure,GCPの環境をコマンド1行で建てられる!

Terraform のここが難しい

  • HCL という前述の HashiCorp 社が提供する言語を多少学習する必要がある

  • 書こうと思って調べると古いドキュメントや記事が多くて惑わされる

    今回は VPC 構築からターミナルソフトで SSH ログインするところまで作成しましたが
    かなり Web 上をさまよいました。

実際に書いたコード

実際は環境変数を利用してアクセスキーを隠したりしますが
ローカル環境でコードを書いていた為
key.tf にまとめました。

アクセスキーの利用は慎重に

key.tf

variable "access_key" {
  default = "アクセスキー"
}
variable "secret_key" {
  default = "シークレットキー"
}

main.tf

terraform {
  required_version = "0.14.0"
  required_providers {
    aws = {
      version = ">= 3.21.0"
      source  = "hashicorp/aws"
    }
  }
}

## ユーザとリージョンの設定
variable "region" {
  default = "ap-northeast-1"
}

provider "aws" {
  region     = var.region
  access_key = var.access_key
  secret_key = var.secret_key

}

## VPC領域の作成
resource "aws_vpc" "rails_vpc" {
  cidr_block           = "10.0.0.0/21"
  instance_tenancy     = "default"
  enable_dns_support   = "true"
  enable_dns_hostnames = "true"
  tags = {
    Name = "VPC領域"
  }
}

## パブリックサブネットの作成
resource "aws_subnet" "PublicSubnetA" {
  vpc_id            = aws_vpc.rails_vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "PublicSubnetA"
  }
}

## プライベートサブネットの作成
resource "aws_subnet" "PrivateSubnetA" {
  vpc_id            = aws_vpc.rails_vpc.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "PrivateSubnetA"
  }
}

##ルートテーブルの追加(0.0.0.0/0)
resource "aws_route_table" "public-route" {
  vpc_id = aws_vpc.rails_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.yamada-web_GW.id
  }
}

##ルートテーブルの追加(1a)
resource "aws_route_table_association" "public-a" {
  subnet_id      = aws_subnet.PublicSubnetA.id
  route_table_id = aws_route_table.public-route.id
}

##ゲートウェイの設定
resource "aws_internet_gateway" "yamada-web_GW" {
  vpc_id = aws_vpc.rails_vpc.id
}

## Rails用セキュリティグループの設定
resource "aws_security_group" "rails-web" {
  name        = "rails-web"
  description = "rails-web"
  vpc_id      = aws_vpc.rails_vpc.id

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

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

  ingress {
    from_port   = 3000
    to_port     = 3000
    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"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "rails-web"
  }
}

## EC2 インスタンスの設定
variable "ami" {
  default = "ami-0992fc94ca0f1415a"
}

variable "instance_type" {
  default = "t2.micro"
}

variable "volume_size" {
  default = 8
}

##EC2(rails-web01)
resource "aws_instance" "rails-web01" {
  ami               = var.ami
  availability_zone = "ap-northeast-1a"
  instance_type     = var.instance_type
  key_name          = aws_key_pair.key_pair.id
  private_ip        = "10.0.1.10"

  disable_api_termination = false
  vpc_security_group_ids  = [aws_security_group.rails-web.id]
  subnet_id               = aws_subnet.PublicSubnetA.id

  root_block_device {
    volume_type = "gp2"
    volume_size = var.volume_size
  }

  tags = {
    Name = "rails-web01"
  }
}

##EIP(rails-web01)
resource "aws_eip" "rails-web01" {
  instance = aws_instance.rails-web01.id
  vpc      = true
}

## EC2 key pairの名前を変数に保存
variable "key_name" {
  description = "keypair name"
  default     = "rails-web01"
}

## EC2 key pair の生成 PATH を指定
locals {
  public_key_file  = "./.ssh/id_rsa.pub"
  private_key_file = "./.ssh/id_rsa"
}

## 鍵の生成をRSAに設定
resource "tls_private_key" "keygen" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

## 秘密鍵ファイルを作成
resource "local_file" "private_key_pem" {
  filename = local.private_key_file
  content  = tls_private_key.keygen.private_key_pem
  directory_permission ="600"
  file_permission      = "0600"

}

## 公開鍵ファイルを作成
resource "local_file" "public_key_openssh" {
  filename = local.public_key_file
  content  = tls_private_key.keygen.public_key_openssh
  directory_permission ="600"
  file_permission      = "0600"

}

## EC2に登録するキーペア名を出力
output "key_name" {
  value = var.key_name
}

## 秘密鍵ファイルPATH(このファイルを利用してサーバへアクセスする。)
output "private_key_file" {
  value = local.private_key_file
}

## 秘密鍵内容
output "private_key_pem" {
  value = tls_private_key.keygen.private_key_pem
}

## 公開鍵ファイルPATH
output "public_key_file" {
  value = local.public_key_file
}

## 公開鍵内容(サーバの~/.ssh/authorized_keysに登録して利用する。)
output "public_key_openssh" {
  value = tls_private_key.keygen.public_key_openssh
}

## EC2にキーペアを登録
resource "aws_key_pair" "key_pair" {
  key_name   = var.key_name
  public_key = tls_private_key.keygen.public_key_openssh
}

各項目の説明

ユーザとリージョンの設定

ここで設定する情報

  • VPC のアベイラビリティゾーンをどのリージョンに置くか
  • アクセスキーの情報
  • シークレットキーの情報

ちなみにところどころで出ている「variable」というのは変数のことです。

VPC 領域の作成

VPC 領域という名前で VPC ネットワークを作成します。
※名前はなんでも構いません

プライベートサブネットの作成

データベースなどの重要情報を配置するいわゆる内部ネットワークを構築する。

パブリックサブネットの作成

インターネットの公開しても良いサブネットを作成します。

ルートテーブルの追加(0.0.0.0/0)

インターネット向けのルーティングを追加します。

ルートテーブルの追加(1a)

パブリックサブネットを「VPC 領域」に関連付けします。(サブネットの関連付け)

ゲートウェイの設定

VPC にインターネットゲートウェイを設定します。

Rails 用セキュリティグループの設定

rails server 実行時にはデフォルト 3000 番ポートが利用されるので 3000 番を開けておきます。
インターネット上にサーバを公開できているかを確認する為、nginx 用に 80 番を開けておきます。

EC2は自 PC からSSHと秘密鍵を利用して接続します。
※AWS には AWS SSM というサービスがあるので秘密鍵が無くても EC2 にアクセスできます。(IAM 権限が必要)

EC2 インスタンスの設定

ここで AMI、インスタンスタイプ、EBS ボリュームのサイズを変数にしておきます。
アベイラビリティゾーンやプライベート IP も変数にしたほうが見栄えが良いかも。。。。

EC2(rails-web01)

ami : AMI のイメージ ID を代入
availability_zone: アベイラビリティゾーンを設定
instance_type:インスタンスタイプを設定(今回は t2.micro)
key_name:秘密鍵の名前を設定
private_ip:EC2 のプライベート IP アドレスを設定

root_block_device : EBS を設定

tags:EC2 の名前を決定

EIP(rails-web01)

たぶん、ElasticIP の設定

EC2 key pair の名前を変数に保存

SSH にログインするときに必要な秘密鍵の名前を変数に保存する。

EC2 key pair の生成 PATH を指定

SSH にログインするときに必要な秘密鍵を変数に保存する。

鍵の生成を RSA に設定

RSA アルゴリズムでキーペアを作成するように設定する。

秘密鍵ファイルを作成

EC2 に SSH 接続時に利用する秘密鍵を作成する。

公開鍵ファイルを作成

EC2 に SSH 接続時に利用する公開鍵を作成する。

EC2 にキーペアを登録

EC2 に公開鍵を登録

Ruby on Rails の環境を構築(準備)

せっかくなので Ruby on Rails の環境を構築する。
その前に nginx でパブリック IP の接続確認
まずは管理者ログインを行い 、yum update -y

sudo su -
sudo yum update -y

必要なパッケージをダウンロード

sudo yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel sqlite-devel git wget gem

git config の user.name と user.email を変更

git config --global user.name "じぶんのアカウント名"
git config --global user.email "じぶんのメールアドレス"

今のままだと時刻が UTC なので
時刻を JST に合わせる。

sudo cp -r /usr/share/zoneinfo/Japan /etc/localtime

vi で JST に設定できるように中身を編集

sudo vim /etc/sysconfig/clock

記載内容

ZONE="Asia/Tokyo"
UTC=true

確認がてら date コマンドを打つ

date
 Sun Feb  7 15:24:27 JST 2021

日本標準時で返ってくれば OK

次に EC2 がインターネットと接続されているかを nginx で確認する。

sudo amazon-linux-extras install -y nginx1
sudo systemctl list-unit-files -t service |grep "ngin*"

sudo systemctl start nginx.service
sudo systemctl enable nginx.service

nginx を止める。
今回作成した EC2 を再起動して使いまわす場合は disable も忘れずに


sudo systemctl stop nginx.service
sudo systemctl list-unit-files -t service |grep "ngin*"

## disable 確認
sudo systemctl disable nginx.service
sudo systemctl list-unit-files -t service |grep "ngin*"

Ruby on Rails の環境を構築(構築)

rbenv を git コマンドでクローンしてくる。


sudo git clone https://github.com/sstephenson/rbenv.git ~/.rbenv

rbenv 用にシェルファイルを作成する。

sudo vim /etc/profile.d/rbenv.sh

記載内容


export RBENV_ROOT="$HOME/.rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"

ruby-build を git clone


sudo git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

ec2-user のグループを wheel グループに変更してファイルのアクセス権限を変更
※人によってはここで別のユーザを作成して環境構築に入りますが工程が増えるので興味のある方は調べてみてください。

sudo usermod -G wheel ec2-user | grep wheel /etc/group
sudo chown -R ec2-user:wheel ~/.rbenv
sudo chmod -R 775 ~/.rbenv

権限とグループの確認

ls -la

rbenv を用いて ruby をインストール
自分の PC とバージョンを合わせる為、バージョンは 2.5.8 を選択

※ちなみに Ruby on Rails を動かす為の Ruby のバージョンは 2.5 以上とのこと

source /etc/profile.d/rbenv.sh
rbenv --version
rbenv install -l
rbenv install -v 2.5.8
rbenv rehash
rbenv global 2.5.8

バージョン確認

ruby -v
 ruby 2.5.8p224 (2020-03-31 revision 67882) [x86_64-linux]

次に NVM
ザックリ言えば Nodejs のバージョン管理ツールを導入

git clone https://github.com/creationix/nvm.git ~/.nvm
source ~/.nvm/nvm.sh

bash_profile の設定

vi .bash_profile

記載内容

# nvm
if [[ -s ~/.nvm/nvm.sh ]] ; then
  source ~/.nvm/nvm.sh ;
fi

Node.js のバージョンは自分の PC と合わせる為
v12.19 を選択

バージョンがあるかを確認する。

nvm ls-remote | grep "v12.19.*"

Node.js のインストールとデフォルトバージョンの設定

nvm install v12.19.0
nvm use v12.19.0

Node.js のバージョン確認

node -v

Rails6 あたりから yarn というパッケージマネージャが必要になったので導入する。
実は yarn って npm より高速に動くらしい。

sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
sudo curl --silent --location https://rpm.nodesource.com/setup_12.x | bash -
sudo yum -y install -y nodejs yarn
yarn install --check-files

Rails の DB には mariadb を採用
理由としては今後、RDS で MySQL を利用する為

※gem インストールを忘れずに!!

sudo yum -y install mariadb-server
sudo systemctl start mariadb
sudo yum -y install mysql-devel
gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'

仕上げに bundler と 大本命の Rails をインストール

gem install bundler
gem install rails -v 6.0.3

そしてお待ちかねの起動コマンド

rails new app
cd app
bundle install
rails server -p 80 -b 0.0.0.0
# 起動はOK

起動はできるが開いてみるとエラーになる。
どうやらデータベース周りのようだ。
RailsSQLiteエラー.JPG

エラーの原因を探す

mariadb の生存確認

sudo systemctl status mariadb

実行結果

[root@ip-10-0-1-10 app]# sudo systemctl status mariadb
mariadb.service - MariaDB database server
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
Active: active (running) since Mon 2021-02-08 21:09:46 JST; 14min ago
Process: 28789 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=exited, status=0/SUCCESS)

mariadb はダイジョブ

Rails Server で読み込まれるデータベースはどうやら SQLite が標準みたいなので
./config/database.yml を編集する。

書き間違えて戻せなくなると怖いのでコピーを取る

$ [root@ip-10-0-1-10 /app] # pwd
/root/app
$ [root@ip-10-0-1-10 /app] cp ./config/database.yml ./config/sqlite3_database.yml
$ [root@ip-10-0-1-10 /app] rm -f ./config/database.yml
$ [root@ip-10-0-1-10 /app] vi ./config/database.yml

database.yml の中身

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  timeout: 5000
  username: root
  password: test
  socket: /var/lib/mysql/mysql.sock

development:
  <<: *default
  database: rails_todo_tutorial_development

test:
  <<: *default
  database: rails_todo_tutorial_test

production:
  <<: *default
  database: rails_todo_tutorial_production

注意点:socket のパスを間違えると mariadb が起動できなくなります。(Socket エラー)

各環境ごとにテーブルの名前をつけてください。
今回はわかりやすいように末尾に環境名を付けました。

また、当然ですが
実際にはパスワードは厳密に決める必要があります。
加えて、root 権限でアプリをデプロイすることなどしません。
適切な権限を持ったアカウントを作成してコンフィグに載せましょう。

コンフィグを変更したので起動したいところですが
この時点では gem が SQLite になっていますので mysql2 に変更

変更後の Gemfile

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.5.8'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3'

# Use sqlite3 as the database for Active Record
# gem 'sqlite3', '~> 1.4'
  gem 'mysql2'

# Use Puma as the app server
gem 'puma', '~> 4.1'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

そしてもう一度、bundle install

$ [root@ip-10-0-1-10 /app] bundle install

Don t run Bundler as root. Bundler can ask for sudo if it is needed, and installing your bundle as root will break this application
for all non-root users on this machine.
Fetching gem metadata from https://rubygems.org/............
Resolving dependencies...
.
.
.

Using method_source 1.0.0
Using mysql2 0.5.3
Using puma 4.3.7
.
.
.

特にバージョン指定はしませんでしたが
バンドルされましたね。

Using mysql2 0.5.3

これでようやく起動かと思いきや
今度はデータベースのパスワード決めていません。
Railsデータベースアクセスのエラー.JPG

root 権限にパスワードを設定してあげましょう。

$ [root@ip-10-0-1-10 /app] mysql
MariaDB [(none)]> show databases;
MariaDB [(none)]> use mysql;
MariaDB [(none)]>  show tables;
MariaDB [(none)]> SET PASSWORD FOR root@localhost = password('test');
MariaDB [(none)]> select user,password from user;

まだまだやることがあります。
今起動するとこんなエラーが表示されるはずです。

Railsテーブルエラー.JPG

最後にやることは 3 つ

  • yarn との依存関係を解決する
  • DB を作成する
  • DB をマイグレーション
$ [root@ip-10-0-1-10 /app] yarn install --check-files
$ [root@ip-10-0-1-10 /app] rails db:create
$ [root@ip-10-0-1-10 /app] rails db:migrate

何度目かの正直

rails server -p 80 -b 0.0.0.0

Railsの画面.JPG

宣伝

AWS Cloud Tech では AWS の知識を幅広く学習することが可能です。
一緒に学習できるメンバーもいるので
「一人で学習して挫折する」ということをうまく避けながら学習ができます。

一緒に勉強できる仲間を募集中です。
最近ですが、Yamada 主催のもくもく会を
AWS Cloud Tech 内で随時開催する予定ですので
もし、ご興味がございましたらAWS Cloud Techの門を叩いていただけたらと思います。

リンクはこちら

おわり

Terraform で EC2 を建てるところまでできたなら
他のデータベースのセットアップなども自動でやりたい感じがする。
まぁ、データベースに関しては素直に Amazon RDS を使えば良いんですけどね。
とりあえず、環境構築はこの手順でできるとわかったので最後に「terraform destory」

これだけ書いたけど用語がありすぎて。。。アリストテレスになりそうなので用語集を書きたいですね。

あ^全部コード化したいんじゃあ^

6
4
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
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?