Terraformでロードバランサーを使ったCMSの設定

ロードバランシングとは、異なるリソースにワークロードを分散させるための手段です。このチュートリアルでは、**ロードバランサー**と**RDS**を使用して、3つのECSインスタンスをアタッチした状態で、**Alibaba Cloud**上にCMS（この場合はBolt）をセットアップする方法を学びます。

[Alibaba Cloud Tech Share](https://www.alibabacloud.com/campaign/techshare?spm=a2c65.11461447.0.0.47fc313c3GW4db)執筆者Alberto Roura。

このチュートリアルでは、[ロードバランサー](https://www.alibabacloud.com/product/server-load-balancer?spm=a2c65.11461447.0.0.47fc313c3GW4db)と[RDS](https://www.alibabacloud.com/product/apsaradb-for-rds?spm=a2c65.11461447.0.0.47fc313c3GW4db)を使って、[ECS](https://www.alibabacloud.com/product/ecs?spm=a2c65.11461447.0.0.47fc313c3GW4db)インスタンスを3つアタッチした状態で、Alibaba Cloud上にCMS（この場合はBolt）を設定する方法を紹介します。TerraformとAlibaba Cloud（Alicloud）の公式プロバイダーを使ったDevOpsアプローチに基づいて行います。

[ロードバランサー](https://www.alibabacloud.com/product/server-load-balancer?spm=a2c65.11461447.0.0.47fc313c3GW4db)という言葉を聞いたことはあるが、その概念がよくわからないという方は、もう少し詳しく説明しますので、ご安心ください。

#ロードバランシングとは何ですか？
ロードバランシングとは、異なるリソースにワークロードを分散させるための手段です。例えば、非常に忙しいウェブサイトを所有しているとしましょう。その代わりに、追加のサーバーを用意してリクエストに対応することができます。

最も一般的なアプローチは、[ウェブホスティングサーバー](https://www.alibabacloud.com/product/swas?spm=a2c65.11461447.0.0.47fc313c3GW4db)をクローンし、ロードバランサーの後ろに置くことです。ロードバランサーは、単に負荷を分散する別のサーバーであり、訪問者からのリクエストを1つのサーバーまたは別のサーバーに送信します。ロードバランサーを使用することで冗長性も高まるので、データの安全性を確保するのにも便利です。

###ロードバランサはどのように負荷を分散するのか？
これにはさまざまなスケジューリング方法がありますが、最もポピュラーな方法はラウンドロビン(RR)で、これは非常にシンプルで効果的です。もう一つの方法は、RRの微調整版であるWRR(Weighted Round Robin)と呼ばれる類似のアプローチを使用する方法です。

**ラウンドロビンバランシング（RR)**

サッカーの大会などのスポーツイベントでラウンドロビンという言葉を聞いたことがあるかもしれません。このテクニックの名前は、「リーダーが特定できないように、円形の順番で請願書に署名する」という意味の元の用語に由来しています。これは、ロードバランサーが一度に1つずつ、接続されたサーバーを回転させるという、コンピューティング用語で現在の意味につながります。

最大の利点は、そのシンプルさです。負荷はまた、ネットワーク内のすべてのサーバーに均等に分散されます。

**重み付きラウンドロビン(WRR)**

このアルゴリズムは、標準的なラウンドロビンをベースにしていますが、リソースがどのように異なるかを「念頭に置いている」という違いがあります。WRRでは、リソースは容量に基づいてキューの中で優先順位(重み)を与えられます。例えば、100GBのサーバは20GBのサーバよりも大きなウェイトが与えられます。このアプローチにより、ネットワーク管理者は、どのサーバを先に使用し、どのサーバを後に使用するかをより制御できるようになります。WRRは、ハイブリッドクラウド環境などの複雑なネットワークではRRよりも優れています。

**重み付き最小接続（WLC)**

WRRと同様に、WLCはネットワーク内のサーバに異なる重みを割り当てるアプローチです。しかし、RRやWRRとは異なり、WLCは動的です。このスケジューリングアルゴリズムは、重み付けされたリソースリストの中で、最もアクティブな接続が少ないサーバにリクエストを送ります。これは、各サーバにパフォーマンスの重みを割り当てることとは別に、ネットワーク上のリソースがどれだけビジーになるかを制御したい場合に便利です。このアプローチの欠点は、効果的に動作させるためにはより多くの計算を必要とすることです。

###Terraformの設定
Alibaba Cloud（Alicloud）公式Terraformプロバイダでは、重み付きラウンドロビン（WRR）と重み付き最小接続（WLC）のどちらかを選択することができます。どちらを使うかはあなた次第です。ここではWRRを使用していますが、特に理由はありません。

**Terraformのインストール**

TerraformはHomebrewを使って簡単にインストールできます。Homebrewがインストールされていない場合は、[こちら](https://brew.sh/?spm=a2c65.11461447.0.0.47fc313c3GW4db)を参照してください。

ターミナルで以下のコマンドで brew install terraf を実行し、Terraform をインストールします。

terraformのインストールを確認するには、terraformのバージョンを入力してください。

**アリババクラウド公式プロバイダーのインストール**
Hashicorpはプロバイダーを積極的に更新していないため、Alibaba Cloudには、公式プロバイダーの非常に優れたアクティブな開発済み[GitHubリポジトリ](https://github.com/alibaba/terraform-provider?spm=a2c65.11461447.0.0.47fc313c3GW4db)があります。これは、取得してインストールする必要があります。[リリースタブ](https://github.com/alibaba/terraform-provider/releases?spm=a2c65.11461447.0.0.47fc313c3GW4db)に移動して、プラットフォームの最新のものを入手してください。 

ダウンロードした後、バイナリファイルをterraformのpluginsフォルダに配置します。Windowsの場合は、ユーザーの "Application Data "ディレクトリの下にあるterraform.d/pluginsに置いてください。その他のシステム（Linux や Mac など）では、ユーザのホームディレクトリの ~/.terraform.d/plugins に置いてください。また、バイナリのバージョンを変更するのも良い習慣ですので、terraform-provider-alicloud_v1.8.2 にリネームしてください。

###Alibaba Cloudのアクセスキーを取得
Alibaba Cloudコンソールにログインしたら、上部のメニューからメールアドレスの直下にある「accessskeys」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/b5cf0fce-921d-aabe-4ccb-0ccc538d4c87.png)

鍵の画面が表示されたら、アクセスキーIDとアクセスキーの秘密を安全な場所にコピーしてください。秘密鍵を表示するには、「表示」をクリックする必要があります。このデータは非常に機密性の高いデータなので、保存先には注意してください。また、ポリシーを使用して、より限定された鍵を作成することも検討してください。

###Terraformファイルの準備
この例では、すべてのコンフィグを一つのファイルにまとめますが、コンフィグの異なる部分をそれぞれの .tf ファイルに分けておくことをお勧めします。これは良い習慣で、時間が経つにつれて保守性と可読性が向上します。

フォルダを作成し、その中に main.tf というファイルを作成して、次のステップで編集します。

**main.tf**

```
provider "alicloud" {
  access_key = "KEY"
  secret_key = "SECRET"
  region = "ap-southeast-2"
}

variable "vswitch" {
  type = "string"
  default = "vsw-xxxxxxxxx"
}

variable "sgroups" {
  type = "list"
  default = [
    "sg-xxxxxxxxxxx"
  ]
}

variable "app_name" {
  type = "string"
  default = "my_app"
}

variable "ecs_password" {
  type = "string"
  default = "Test1234!"
}

resource "alicloud_db_instance" "default" {
  engine = "MySQL"
  engine_version = "5.6"
  instance_type = "rds.mysql.t1.small"
  instance_storage = 5
  vswitch_id = "${var.vswitch}"
  security_ips = [
    "0.0.0.0/0"
  ]
}

resource "alicloud_db_database" "default" {
  instance_id = "${alicloud_db_instance.default.id}"
  name = "bolt_site"
  character_set = "utf8"
}

resource "alicloud_db_account" "default" {
  instance_id = "${alicloud_db_instance.default.id}"
  name = "bolt_user"
  password = "boltdb1234"
}

resource "alicloud_db_account_privilege" "default" {
  instance_id = "${alicloud_db_instance.default.id}"
  account_name = "${alicloud_db_account.default.name}"
  privilege = "ReadWrite"
  db_names = [
    "${alicloud_db_database.default.name}"
  ]
}

resource "alicloud_db_connection" "default" {
  instance_id = "${alicloud_db_instance.default.id}"
  connection_prefix = "bolt-app"
  port = "3306"
}

data "template_file" "user_data" {
  template = "${file("user-data.sh")}"
}

data "alicloud_images" "default" {
  name_regex = "^ubuntu_16.*_64"
}

data "alicloud_instance_types" "default" {
  instance_type_family = "ecs.xn4"
  cpu_core_count = 1
  memory_size = 1
}

resource "alicloud_instance" "app" {
  count = 3
  instance_name = "${var.app_name}-${count.index}"
  image_id = "${data.alicloud_images.default.images.0.image_id}"
  instance_type = "${data.alicloud_instance_types.default.instance_types.0.id}"

  vswitch_id = "${var.vswitch}"
  security_groups = "${var.sgroups}"
  internet_max_bandwidth_out = 100

  password = "${var.ecs_password}"

  user_data = "${data.template_file.user_data.template}"
}

resource "alicloud_slb" "default" {
  name = "${var.app_name}-slb"
  vswitch_id = "${var.vswitch}"
  internet = true
}

resource "alicloud_slb_listener" "http" {
  load_balancer_id = "${alicloud_slb.default.id}"
  backend_port = 80
  frontend_port = 80
  health_check_connect_port = 80
  bandwidth = -1
  protocol = "http"
  sticky_session = "on"
  sticky_session_type = "insert"
  cookie = "testslblistenercookie"
  cookie_timeout = 86400
}

resource "alicloud_slb_attachment" "default" {
  load_balancer_id = "${alicloud_slb.default.id}"
  instance_ids = [
    "${alicloud_instance.app.*.id}",
  ]
}

output "app_id" {
  value = "${alicloud_instance.app.*.public_ip}"
}


output "slb_ip" {
  value = "${alicloud_slb.default.address}"
}

output "rds_host" {
  value = "${alicloud_db_instance.default.connection_string}"
}
```

**user-data.sh**

この例では、我々は、Ubuntuにバンドルされており、リソースの作成の瞬間に渡すために任意のスクリプトを実行するcloud-initプログラムに依存しようとしています。この場合、スクリプトは必要なソフトウェアパッケージをインストールしてDockerコンテナを実行し、アプリを適切なデータベースに接続します。user-data.shファイルは、main.tfの隣の同じパスにある必要があります。MYSQL_HOST変数に注意して、データベースインスタンスのインターネットホストに合わせて調整する必要があります。

```
#!/bin/bash -v

export MYSQL_HOST=bolt-app.mysql.australia.rds.aliyuncs.com

apt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update && apt-get install -y docker-ce docker-compose
curl -L https://github.com/docker/compose/releases/download/1.20.1/docker-compose-`uname -s`-`uname -m` -o /usr/bin/docker-compose

cd ~/
curl https://raw.githubusercontent.com/roura356a/bolt/master/with-mysql/docker-compose.yml -o docker-compose.yml
sed -i "s/=db/=$MYSQL_HOST/g" docker-compose.yml

docker-compose up -d    
```

###Terraformを起動
**terraform init**

飛び立つ準備が整いました。Terraformのinitコマンドを入力して、プロジェクトを適用する準備をします。

`terraform init`

**terraform plan**

問題がないことを確認するためには、planコマンドを実行しておくと、実際に適用しなくてもジョブの概要を知ることができます。

`terraform plan`

**terraform apply**

シートベルト着用 これでマシンをデプロイしました! applyコマンドを実行し、終了するまで待ちます。インターネットの接続状況や接続先のデータセンターの状況にもよりますが、3分～5分ほどかかります。

`terraform apply`

ジョブが終了すると、新しいECSインスタンス、RDSホスト、ロードバランサーのIPアドレスを確認するメッセージがターミナルに表示されます。

```
Apply complete! Resources: 11 added, 0 changed, 0 destroyed.

Outputs:

app_id = [
    xx.xx.xx.xx,
    xx.xx.xx.xx,
    xx.xx.xx.xx
]
rds_host = rm-xxxxxxxxxxx.mysql.australia.rds.aliyuncs.com
slb_ip = xx.xx.xx.xxx
```

選択したセキュリティグループがポート80を開いている場合は、今、ブラウザでバランサーのIPを入力して、新しいWebサイトをカスタマイズするためにボルトのWebベースのインストールがどのように出てくるかを確認することができます。


###結論
これであなたは正常にロードバランサーとRDSを使用してAlibaba Cloud ECS上の　Boltを設定しました。それらを使って何か楽しいことをしてみてください。これは新しいBoltのインストールなので、手動でインスタンスの1つ（slbではない）を訪問し、最初のユーザーを作成する必要があります。セルフチェックは3つのバックエンドサーバーで通過できます。その後、SLBのIPを直接訪問したり、ドメインを考えたりするだけで十分なはずです。

新しく作成されたSLBでバックアップされたBoltのWebアプリケーションをお楽しみください。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*