TerraformでNGTのポータブル環境を作った

はじめまして、BASEでSREに所属している浜谷です。現在は主にAWSを使用したインフラ構築と運用を担当しています。
そこで今回は前回好評だったBASEビール部部長が語ってくれた「Yahoo!の近傍探索ツールNGTを使って類似商品APIをつくる」のインフラ環境の構築についてお話をしようかと思います。

1. 背景

BASEでは機械学習の環境以前に今本番で何が動作しているのか、又その全体を把握するにはAWSのコンソールにログインして調査する方法しかありませんでした。 AWSの運用をしているとよくある事かと思います。
そんな中BASEではシステム全体構成図の見直しやサーバの一覧を自動化したりとインフラの見える化を進めています。
そこで次はインフラの構成管理を行っていこうといった流れがあり、まずはData Strategyチームの環境をTerraformで構成管理しようと相成りました。

2. 機械学習の環境

f:id:jhamatani:20180912101224p:plain

環境をサクッと説明するとS3に画像がアップロードされたら、SNSにイベントを送付します。 SNSからSQSやLambdaに振り分けて情報を蓄積し、蓄積したデータを元にECSのDockerで機械学習した結果をAPIで返すといったインフラ環境となります。 類似商品APIって何と詳細が気になった人はBASEビール部部長の記事を読んでみてください。

3. そもそも構成管理は必要?

運用をしていく為に構成を把握する事は必要不可欠です。 ただ私自身構成管理ツールの必要性をあまり感じていませんでした。

というのはSIerの出身なので設計書、手順書、運用のドキュメントは納品物なので時間を掛けて作るのは当たり前でした。 SIerのエンジニアはoffice製品でのドキュメント作りや成果物の承認に時間を割くことが多く、その上構成管理のツールまで必要なのって感じている人は少なくないと思います。 またドキュメントでの構成管理は構築を始めるまでに時間が掛かるのは当然といった考え方が前提としてあります。

しかし、BASEの行動指針の一つに「MOVE FAST」があります。 このMOVE FASTを実現するためには、時間が掛かるのは当然といった考え方を捨てる必要があります。 そこで構成管理ツールは必要不可欠なのです! 構成管理ツールを使用するとインフラをコードで管理できるので設計から構築までを一気通貫に実現できます。

4. なぜTerraformなの?

現在BASEではAWSをメインに利用しているので、AWS CloudFormationの方が良いかもしれません。
機械学習の環境においてGCPのBigQueryを使用する場面が今後発生してくるかと考えています。
その際にマルチプラットフォームに対応した構成管理ツールを選ぶ必要がありました。

5. コードでのインフラ管理

AWSを管理コンソールで構築しているとGUIベースで確認するか、ドキュメントベースで環境を把握する必要があります。
しかし、Terraform等の構成管理ソフトを使用するとコードベースで管理できます。

VPCをTerraformでコード定義すると以下のようになります。

resource "aws_vpc" "ds-image-processing-vpc" {
  cidr_block = "10.1.0.0/16"

  tags {
    Name = "ds-image-processing-vpc"
  }

  # We explicitly prevent destruction using terraform. Remove this only if you really know what you're doing.
  lifecycle {
    prevent_destroy = true
  }
}

コードで管理することでGitHubを利用した管理が出来ます。
GitHubはアプリエンジニアだと日常的に使用しますが、インフラエンジニアにとっては少し敷居が高く感じます。 私もBASEに入社するまでは殆どGitHubは使用していませんでしたが、今では普通に使用してレビューなどの履歴も残すことが出来てとても便利に感じています。 今まではインフラ構築のレビューをシステム構成図や設計書ベースでのレビューをしていたので、別途レビュー票を起こしたり等の手間が大幅に減りました。

f:id:jhamatani:20180912101551p:plain

またインフラ構成の変更をAWSのコンソールでを漏れなくチェックするのは非常に困難です。
しかし、GitHubを使用することで差分の確認をすることで、何を変更したのかも一目瞭然です。

f:id:jhamatani:20180912101546p:plain

6. 実際にTerraformを使ってみよう!

それではいよいよ実際にTerraformを使用してみましょう。
今回はハンズオンとして、RDSのAuroraとEC2のLinuxインスタンスを実際に作ってみます。

①まずはTerraformを実行出来る環境の準備をします。
 Terraformのダウンロード(URL:https://www.terraform.io/downloads.html
  ※バージョンは適時ダウンロードしたファイルに読み替えてください。
 ダウンロードしたファイルを展開して、環境変数にパスを通す。

$ mv terraform_0.11.4_linux_amd64.zip /usr/local/bin
$ unzip terraform_0.11.4_linux_amd64.zip
$ ls -l terraform 
 ※実行権限があることを確認
$ env | grep PATH 
 ※PATHに/usr/local/binが通っていることを確認
$ mkdir -p <作業ディレクトリ> 
$ cd <作業ディレクトリ> 

②GitHubにサンプルを用意しましたので、ダウンロードします。
 GitHubのリポジトリ:https://github.com/baseinc/Hands-on-Terraform
 Terraformのドキュメント:https://www.terraform.io/docs/providers/aws/

$ git clone git@github.com:baseinc/Hands-on-Terraform.git
$ terraform init
$ vi terraform.tfvars

 必要に応じて以下の内容を書き換えてください。

aws_access_key = "<AWSのアクセスキー>"
aws_secret_key = "<AWSのシークレットキー>"
aws_region = "ap-northeast-1"

main_aurora_root_user = "<auroraへのアクセスユーザ>"
main_aurora_root_password = "<auroraへのアクセスパスワード>"

external_ip = "<EC2にアクセス出来るIP>"
host_ssh_key = "<EC2にアクセスする際のキーペア名>"

③準備ができたので、Terraformを実行するだけです。

  • 実行前の動作確認(DryRun): $ terraform plan
Plan: 20 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

 上記の様に「20 to add」と表示されればOKです。
 20個のリソースがコマンド一つで作成されます。

  • 実行:$ terraform apply
Plan: 20 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

 「yes」と回答します。

aws_iam_role.db-main-aurora-monitoring: Creating...

 リソースの作成が開始します。

④リソース作成完了までは少し待ちます。

aws_rds_cluster_instance.db-main-aurora-instance.0: Still creating... (12m50s elapsed)
aws_rds_cluster_instance.db-main-aurora-instance[0]: Creation complete after 12m57s (ID: db-main-aurora-instance-0)

Apply complete! Resources: 20 added, 0 changed, 0 destroyed.

 これでAWS上にAuroraとLinuxのインスタンスが立ち上がりました。  どうですか、サクッと作れてしまいましたね。
 リソースが出来たかどうか、実際にAWSコンソールにログインして確認してみましょう!

f:id:jhamatani:20180912101538p:plain f:id:jhamatani:20180912101543p:plain

6. リソースを作った後は。。。

こんなに簡単に作れてしまうと、次から次へとリソースを作ってしまいますね。
そして放置なんてことになったら、AWSに多大な貢献をしてしまうことになりかねません。
ですので不要になったらきちんとお片付けを実施します。

  • 削除 :$ terraform destroy

コマンドを実行して削除完了と思ったら。。。。

Error: Error running plan: 1 error(s) occurred:

aws_route.db-vpc-route-external: aws_route.db-vpc-route-external: 
the plan would destroy this resource, but it currently has lifecycle.prevent_destroy set to true. 
To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or adjust the scope of the plan using the -target flag.

あれ?なんでだろう。。。エラーが出てしまいます。
理由は削除保護が有効になっていたからです。 VPCやDB等は間違えて消してしまうと想定外の影響が出てしまう可能性がある為、簡単に消せない様に削除保護prevent_destroy = trueをリソースに定義していました。
ただ、今回は消してしまいたいのでリソース上の定義を全てprevent_destroy = falseに変更して再度実行してみましょう。

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

「全てのリソースを削除しますが、良いですか」と聞かれます。
「yes」と回答します。

…
aws_subnet.db-vpc-subnet-d1: Destroying... (ID: subnet-0bae4cb4032d56f93)
aws_subnet.db-vpc-subnet-a1: Destroying... (ID: subnet-0a9d2118812674f12)
aws_subnet.db-vpc-subnet-c1: Destruction complete after 0s
aws_subnet.db-vpc-subnet-d1: Destruction complete after 1s
aws_subnet.db-vpc-subnet-a1: Destruction complete after 1s
aws_security_group.db-main-aurora-security-group: Destruction complete after 2s
aws_vpc.db-vpc: Destroying... (ID: vpc-0790adf505d9e6ac3)
aws_vpc.db-vpc: Destruction complete after 0s

Destroy complete! Resources: 20 destroyed.

今度は消えましたね。 また必要になったら、$ terraform applyで作り直しましょう。

まとめ

Terraformを使用することで新規作成から削除までコマンドで簡単に出来るようになりました。 今後、既存の本番環境のTerraform化や新規にプロダクトを開発している子会社のBASE BANKもTerraformを利用したりしているので、また機会があれば続きを書ければなぁと思います。