TerraformによるConsulの導入の考察

これは、Goodpatchのアドベントカレンダー 18日目の記事です。

こんにちは、Goodpatchでエンジニアをしている@urapicoです。

先日、GoodpatchのサービスのProttのインフラを専用サーバーからAWSに全て移行しました。 特に骨が折れたのは、S3の引っ越しですが。。。

今回は、HashiCorpで有名な2つのプロダクトTerraformとConsulについてです。

Terraform と Consul

Terraform

まず、Terraformですが、こちらはインフラ構築に利用されるツールです。
Amazon Web Serviceのインフラ構築には、非常に親和性が高いと思います。

Amazon Web Serviceには、Terraformと同じ目的のサービスがあります。 AWS CloudFormationです。
AWSを利用する場合、CloudFormationのほうがいいと思われますが、Terraformの作成元のMitchell Hashimoto氏の インタビューで、"CloudFormationに先行して, さまざまな機能を追加することができた..."と答えています。 また、設定フォーマットもJSONライクな文法ですが、コメントなどが書けたり、非常に読みやすい形になっています。 CloudFormationは、標準のJSONのため、痒いところに手が届きにくいという印象があります。

Consul

consulは、Service Discoveryという名前でよく紹介されてるツールです。 今時のサービスのサーバー構成は、非常に柔軟に作られることが多々あり、 負荷によってサーバーを増減させたりなどを行います。

ただ、こうした自動でサーバーが増減した場合、サーバーのリストなどを手動で作成して管理するのは、限界があります。

こういった場合、Service Discoveryという機能が、そのサーバー郡に備わっていると非常に重宝します。 なぜなら、各サーバー同士(node)が定期的に通信を行って、生存の確認や、そのグループにjoinしたイベントなどを感知して サーバーリストの更新などを行ってくれるからです。

また、consulは、その他にもDNSやkey value storageの機能を有しているのも特徴の一つです。

サーバーの管理上、どうしてもちょっとしたサーバーの情報を保存しておきたい場合、 そのために他のミドルウェアをインストールしたりするのは、少々オーバースペックなところがありますので、 key value storageの機能などがあるのは、Mitchell氏わかってる!!って感じですね。

Terraformのインフラ構築 そしてConsul

弊社では、Terrafrom以外では、Ansibleなども利用していて、 Ansibleでは、サーバーにインストールするミドルウェアなどを管理させています。

Ansibleは、サーバーリストを知らないと利用できないので、 Terraformで構築した際に、同時にConsulもインストールして サーバーリストをConsulに管理させたいと考えました。

VPC上で、どのように構築するのか

AWSで、サーバーを構築する場合、VPCを利用します。 よくある構成としては、PrivateとPublicのサブネットを構築して、Natサーバーを経由して sshのアクセスなどをさせます。

Consulのインストール方法

Terraformでインストールさせる際、コマンドによる操作がいくつか必要になります。 Terraformでは、remote-execというリモートのサーバー上で 実行できる命令があります。

これを利用したら、TerraformにConsulをインストールさせたりできそうです。

ただ、ここで問題になるのは、Natサーバーを経由させた形で、対象のサーバーにアクセスしないといけません。

その場合、null_resourceというresourceを使って Natサーバーを踏み台にして、各サーバーに接続する方法を利用できます。

resource "null_resource" "nat" {

    connection {
        user = "ec2-user"
        host = "${aws_eip.nat.public_ip}"
        private_key = "path/private_key"
    }

    provisioner "file" {
        source = "file/setup.sh"
        destination = "/tmp/setup.sh"
    }

    provisioner "remote-exec" {
        inline = [
            "chmod +x /tmp/setup.sh",
            "mkdir /tmp/consul",
            "chmod 777 /tmp/consul",
            "/tmp/setup.sh ${join(" ", aws_instance.web.*.private_ip)}"
        ]
    }
}

この設定ファイルでは、Natサーバーに接続したあとに、fileを使って、 各サーバーにConsulの設定を行うシェルファイルを転送して、Natサーバー上で実行しています。

しかし、ここで問題になるのは、ローカルにしか、private key(pemファイル)が存在しないことです。

Natサーバーへの接続までは、問題なくできますが、そこから各サーバーに接続することができません。

ここで、私は、ec2のuser dataという機能を利用しました。 ec2のuser dataは、ec2のインスタンス起動時に、設定した処理を実行してくれる機能です。 ふと、ここで、このuser dataで、Consulをインストールなどを、行えばいいのでは?と思いますが、Consulは、Join先がないと、意味をなさないので、やはりサーバー群が作られたあとに、行うのが良さそうです。

この機能を使って、Terraformを実施する端末のpublic keyを登録しておきます。 私は、TerraformをTravis CI 上で実行させたかったので、 Travisのpublic keyも登録しました。

# Create a Web server
resource "aws_instance" "web" {
    ami = "${lookup(var.amis, var.region)}"
    count = 10
    instance_type = "${var.instance_type_web}"
    user_data = "${template_file.init.rendered}"

    tags {
        Name = "web"
    }
}

そして、もう一度、null_resourceの設定を見直します。

前回では、null_resource上では、connectionをprivate keyで行っていましたが、 各サーバーに端末のpublic keyを登録したので、何も指定しなくても 接続が可能になります。

ただ、踏み台にしたNatサーバーから、他のサーバーに接続するところが問題になります。

これに関しては、Terraformのconnectionは、ssh-agentを設定することができます。

書き換えると設定ファイルは、こんな感じになります。

resource "null_resource" "nat" {

    connection {
        user = "ec2-user"
        host = "${aws_eip.nat.public_ip}"
        agent = true
    }

    provisioner "file" {
        source = "file/setup.sh"
        destination = "/tmp/setup.sh"
    }

    provisioner "remote-exec" {
        inline = [
            "chmod +x /tmp/setup.sh",
            "mkdir /tmp/consul",
            "chmod 777 /tmp/consul",
            "/tmp/setup.sh ${join(" ", aws_instance.web.*.private_ip)}"
        ]
    }
}

そして、接続元のsshの設定のforward agentを有効にします。

このように設定することによって、Terraformを使って、Consulのインストールが可能になりました。

まとめ

Terraformでは、いまでも開発が非常に活発で、様々な解決方法を提供してくています。
今回のConsulのインストール方法ももっと、別のやり口もあると思います(是非、教えてください)。

ツールをシームレスに連携し、サーバーの状態をあるべき姿をいつでも再現可能にしておくというのは エンジニアとしての精神衛生的にも重要なことだと思います。

今後もいろいろと積極的に、先進的な技術・ツールを導入していきたいと思っています。
このような先進的な技術・ツールに興味があるエンジニアの方は、是非、wantedly 経由などで、気軽に遊びに来てください!!

https://www.wantedly.com/projects/37793?u=14754

明日は @inoino さんの投稿となります!!お楽しみに!!

17日目の記事 hi6484 さんのJNI JNA SWIG for Android