Terraformに関して（応用編）

# Terraformに関して（応用編）
入門編では簡単な使い方や設定ファイルの書き方を説明した。ここでは実際の要望に対してどのようにプログラムを構築すればいいかについて説明する。

# 使い方
## マイAMIを利用

環境構築したインスタンスをイメージとして保存し（マイAMI）、設定ファイルでそのAMIの番号を登録する
ことでイメージのままのインスタンスを簡単に生成することができる。

## **userdataを使って任意のシェルスクリプトを起動させる**

userdataという起動時に実行される機能を利用して起動時に実行したい処理を記入する。
具体的には、起動したいシェルスクリプトを準備したのちそれをbase64でエンコード化する。エンコード化した文字列を指定の場所に記載すれば完成。
(注意)user_dataの処理が終わっていなくてもインスタンスにアクセスできるため処理が完了したのがいつなのかよくわからない。

1. 必要なファイル群を外部ストレージに保存する例
    参考サイト：[**terraform で userdata を渡して ec2 インスタンスを起動し、ホスト名をつける**](https://qiita.com/satoshi_iwashita/items/5fd93d584faa0bbc8e76)
    この場合は事前に外部ストレージに必要なファイル群を保存しておく。それをダウンロードするようなシェルスクリプトを作成すればよい。
    外部ストレージも様々なので要検討
    [マイナス要素]
    S3を利用した際、データの転送に時間がかかった。別の外部ストレージを利用する方法を検討してもいい。
    
2. ECRを利用する例
    参考サイト：[**TerraformでECR上のDockerイメージをEC2にささっとデプロイ**](https://qiita.com/os1ma/items/31bfdea483f0c7f35cd3)
    ECRとはdockerイメージを保存しておくサービスのこと。dockerhubのようなもの。
    事前にECRに作成したイメージをプッシュしておく。
    [マイナス要素]
    イメージの容量にもよるが大きい場合、プッシュが遅いことがある。
## **ECSやFargateを利用**

ECSやFargateというdockerコンテナの管理サービスを利用する。
参考サイト：

- [**AWS FargateとTerraformで最強＆簡単なインフラ環境を目指す**](https://qiita.com/tarumzu/items/2d7ed918f230fea957e8)
- [TerraformでECSのService Discoveryを使う](https://christina04.hatenablog.com/entry/ecs-service-discovery)
- [TerraformでECS環境の構築](https://christina04.hatenablog.com/entry/2016/07/28/015718)

# 使用例
## マシンをterraformを使って作成。

必要なスペック

    - OS             : ubuntu=18.04
    - instance_type  : t2.micro
    - 開放ポート       : 8080, 22

**ファイル構造**

    ec2.tf
    security.tf
    terraform.tfvars
    variables.tfvars

手順

- resource “aws_key_pair”で使用する公開鍵を設定する。
- resource “aws_security_group”でSSH（ポート22）を開く。
- resource “aws_instance” で使用しているセキュリティーグループの指定はvpc_security_group_idsを使用。
    - セキュリティーグループの条件追加・削除する場合にインスタンスを一度削除し作り直すことをしたくない場合はvpc_security_group_idsを利用するといいそう。

**コード**

https://github.com/littletake/Terraform/tree/master/mount_test

## 推論サーバーの構築

EC2を用いてAPIサーバーと推論サーバーの２台を構築する。
**設定の方法**

1. インスタンス自体の設定 → terraform
2. 内部の設定　→ シェルスクリプト 
3. アプリケーション → dockerfile

**コード**

https://github.com/littletake/Terraform/tree/master/api_inference_server

# 注意点
## インスタンスにSSHで接続する方法とセキュリティーグループの設定

参考サイト：[Terraform でキーペア登録し起動した EC2 に SSH接続](http://kenzo0107.hatenablog.com/entry/2017/03/27/215941)
設定方法
**1.公開鍵、秘密鍵の生成**


    $ ssh-keygen -t rsa

保存先は指定する。passphraseは入力しなくてもよい。
これで指定した保存先に鍵が生成される。
アクセス方法は、

    $ ssh -i ~/.ssh/<名前> <ec2 user>@<ec2 public ip>

**2.terraform内の設定ファイル1**
重要な点

- resource “aws_key_pair”で使用する公開鍵を設定する。
- resource “aws_security_group”でSSH（ポート22）を開く。
- resource “aws_instance” で使用しているセキュリティーグループの指定はvpc_security_group_idsを使用。
    - セキュリティーグループの条件追加・削除する場合にインスタンスを一度削除し作り直すことをしたくない場合はvpc_security_group_idsを利用するといいそう。

ec2.tf

    # アカウントの設定
    provider "aws" {
      access_key = "${var.access_key}"
      secret_key = "${var.secret_key}"
      region     = "${var.region}"
    }
    
    # インスタンスの大まかな設定
    resource "aws_instance" "example" {
      ami           = "ami-09b68f5653871885f" # ubuntu-18.04
      instance_type = "t2.micro"
      key_name      = "${aws_key_pair.auth.id}"
      vpc_security_group_ids = ["${aws_security_group.only_ssh_http.id}"]
    }
    
    # 用いるSSHキーの設定
    resource "aws_key_pair" "auth" {
      key_name   = "${var.key_name}"
      public_key = "${file(var.public_key_path)}"
    }
    
    # セキュリティーグループの設定
    # この設定はsshとhttpのポートのみ解放
    resource "aws_security_group" "only_ssh_http" {
      name        = "terraform_security_group"
      description = "You can Only use ssh and http"
      ingress {
        from_port   = 22
        to_port     = 22
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
      ingress {
        from_port   = 8080
        to_port     = 8080
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
    }

variables.tf

    # 変数の設定
    
    # アカウントの設定
    # ここに詳細を記入してしまうとコンパイル時点で表示されてしまうため、別ファイルで設定
    variable "access_key" {}
    variable "secret_key" {}
    variable "region" {
      default = "ap-northeast-1"
    }
    
    # キーの名前
    variable "key_name" {
      description = "Desired name of AWS key pair"
    }
    
    # 公開鍵の設定（以下のように書くことで長文のコメントアウトが可能）
    variable "public_key_path" {
      description = <<DESCRIPTION
    Path to the SSH public key to be used for authentication.
    Ensure this keypair is added to your local SSH agent so provisioners can
    connect.
    
    Example: ~/.ssh/terraform.pub
    DESCRIPTION
    }


terraform.tfvars

    access_key      = <自分のアクセスキー>
    secret_key      = <自分のシークレットキー>
    
    # 秘密鍵の名前
    key_name        = ""
    # 公開鍵のパス
    public_key_path = ""

**3.実行**

- 実行計画確認

```$ terraform plan
```

- 実行

```$ terraform apply
```

- 確認
- 
```$ terraform show
```

# Tips
- [**Terraform職人入門: 日々の運用で学んだ知見を淡々とまとめる**](https://qiita.com/minamijoyo/items/1f57c62bed781ab8f4d7)
- [**Ansible と Terraform の違い**](https://qiita.com/yusukaaay/items/cd3bc067d2ad5d449bd1)

もしかしたら、terraformでインスタンスを設定して構築
その後、ansibleで各種ミドルウェアをインストール
という使い方がベストプラクティスかもしれない。


- [**packer と terraform と ansible でインフラを作る**](https://qiita.com/kanagi/items/6af87a3a59e70e7e06db#packer-%E3%81%A8-terraform-%E3%81%A8-ansible-%E3%81%A7%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9%E3%82%92%E4%BD%9C%E3%82%8B)