Hashicorp AtlasでVagrant, Packer, Terraformを連携させる
ども、大瀧です。
VagrantやPackerを開発するHashicorp社から、Atlasという新しいサービスがローンチしました。現在はtech previewとして触ることができます。今回はチュートリアルを試しつつ、その様子をレポートします。
Atlasとは?
Hashicorp AtlasはHashicorpが開発するDevOpsツールを連携させ、開発・デプロイの一連のワークフロー管理を実現するクラウドサービスです。以下がAtlasの概念図ですが、各フェーズの左下に"Powered by"のあとにツール名が示されているのがわかります。
ツールを軸に、今回のチュートリアルの範囲でAtlasの機能を示してみました。
Vagrant、Packer、Terraformが操作の軸になることがわかりますね。これ以外にも、仮想イメージ(Box)を共有する機能やConsulと連携する運用向けの機能もあるようです。各ツールについては、以下のブログ記事が詳しいです。
これまで各ツールはローカルマシンで独立して動作するものだったため、AWSやGCEなどクラウドとの連携は、"遠隔からのクラウドの一括操作"としての利用にとどまっていました。Atlasはローカルマシンで行う操作とクラウドコンポーネントの状態を共有することで、クラウドのチームでの管理を実現します。一人で使う場合も、Atlasのツール間連携機能を利用することで開発からデプロイまでの一連の処理をまとめて扱うことができます。
セットアップ
ツールのインストール/アップグレード
今回のチュートリアルでは、以下のツールを利用します。それぞれ最近バージョンをインストールないしアップグレードして用意しましょう。
ツールと動作確認したバージョン
動作確認したOS
- OS X Yosemite
Atlasアカウントの作成とトークンの取得
Atlasを利用するためには、アカウント登録が必要です。Atlasのトップページにある[SIGN UP >]リンクから作成します。
アカウントが作成できたら、各ツールからAtlasにアクセスするためのトークンを生成します。AtlasのWeb管理右上にあるユーザー名をクリックし、アカウント管理画面左側のメニューから[Tokens]をクリックします。[Generate Token]ボタンをクリックすると、トークンが生成されます。
画面に表示されたトークン文字列をコピーして控えましょう。
各ツールからは、環境変数ATLAS_TOKENで参照するので、Mac OS Xであれば~/.bash_profileファイルなどに設定しましょう。
export ATLAS_TOKEN=<トークン文字列>
これでセットアップ完了です!
サンプルコードの取得
チュートリアルにあるGitHubのリポジトリは本日現在まだ作成されていないようなので、今回の検証で使用したコードを私のGitHubリポジトリにアップしておきました。試してみたいという方は、git cloneしてお使いください。
ファイル構成はこんな感じです。
$ tree atlas-examples/ atlas-examples/ ├── README.md ├── app │ ├── Vagrantfile │ └── index.html └── ops ├── example-build.json └── example-infrastructure.tf 2 directories, 5 files $
ディレクトリ構成に特に制限はないようですが、各ツールはカレントディレクトリのファイルを読み込むので適宜cdコマンドで使用するファイルのあるディレクトリに移動しましょう。
今回は、AWSのEC2インスタンスとELBを組み合わせた簡単なWebシステムを、Atlasで以下の順に構成・管理していきます。
- ベースAWS構成の作成 : Ubuntuのインスタンス2台とELB1つをTerraformで作成します
- Build Configurationのアップロードと初回ビルド : UbuntuにApacheをインストールする構成を追加します
- Applicationのアップロード : サンプルのHTMLファイルをVagrantで追加します
1. ベースAWS構成の作成
まずは、TerraformでEC2インスタンス2台とELB1つを作成します。Atlasでは、Terraformによるインフラ構成をStatesとして追跡する機能があるため、あらかじめ*.tfファイルにAtlasアカウントのトークン文字列を追加しておきます。それ以外は、従来のTerraformの記述と変わりません。
provider "atlas" { token = "<ATLAS_TOKEN>" } provider "aws" { access_key = "<AWS_ACCESS_KEY>" secret_key = "<AWS_SECRET_KEY>" region = "us-east-1" } resource "aws_elb" "web" { name = "terraform-example-elb" # The same availability zone as our instances availability_zones = ["${aws_instance.web.*.availability_zone}"] listener { instance_port = 80 instance_protocol = "http" lb_port = 80 lb_protocol = "http" } # The instances are registered automatically instances = ["${aws_instance.web.*.id}"] } resource "aws_instance" "web" { instance_type = "t1.micro" ami = "ami-408c7f28" # This will create 2 instances count = 2 }
Atlasでの追跡を有効にする、terraform remoteコマンドを実行します。
$ terraform remote -name=<ユーザー名>/example-remote-state Initialized blank state with remote state enabled! $
では、terraform planおよびterraform applyを実行しましょう。
$ terraform plan : $ terraform apply : Apply complete! Resources: 2 added, 0 changed, 0 destroyed. $
AWSのManagement Consoleでは、作成したELBおよびEC2インスタンスが確認できます。
Atlasの管理画面では、[Runtime] - [STATES]に <ユーザー名>/example-remote-state と登録したStateが確認できます。
Terraformで構成を変更すると、この画面でStateのバージョンが上がっていく様子が見れます。履歴以外になにが追跡できるのかはわからなかったので、知っている方がいれば教えて下さい!
2. Build Configurationのアップロードと初回ビルド
続いて、UbuntuにApacheをインストールする構成をPackerで用意し、Build ConfigurationとしてAtlasにアップロードします。Packerテンプレートは以下の通りです。
pushでAtlasのBuild Configuration名、post-processorsでAtlasがビルド結果として生成するAMIを指定しているところが、従来のPackerの記述と異なります。AWSにアクセスするためのAPIキーをAtlasにアップロードするため、IAMユーザーの権限を絞ったものを利用しましょう。
{ "builders": [{ "type": "amazon-ebs", "access_key": "<AWS_ACCESS_KEY>", "secret_key": "<AWS_SECRET_KEY>", "region": "us-east-1", "source_ami": "ami-de0d9eb7", "instance_type": "t1.micro", "ssh_username": "ubuntu", "ami_name": "atlas-example {{timestamp}}" }], "push": { "name": "<atlas-username>/example-build-configuration" }, "provisioners": [ { "type": "shell", "inline": [ "sleep 30", "sudo apt-get update", "sudo apt-get install apache2 -y" ] }], "post-processors": [ { "type": "atlas", "artifact": "<atlas-username>/example-artifact", "artifact_type": "ami", "metadata": { "created_at": "{{timestamp}}" } } ] }
packer pushコマンドでPackerテンプレートをAtlasにアップロードします。
$ packer push -create example-build.json Push successful to 'takipone/example-build-configuration' $
Atlasの管理画面から[Operations] - [BUILD CONFIGURATIONS]に、作成したBuild Configurationが確認できます。
Build Configurationが作成されると、自動で初回のビルドが実行されます。ビルドは、アップロードしたPackerテンプレートの設定を元にAtlasからAWS APIにアクセスしビルド用EC2インスタンスの作成、Packerによるプロビジョニング、AMIの作成まで一気に実行します。ビルド中は、AWSの管理画面からビルド用EC2インスタンスが確認できます。
ビルドが完了すると、AMIも確認できます。
作成されたAMIは、AtlasではArtifactという抽象化された単位で取り扱います。Artifactはバージョン管理されるため、再度ビルドを実行してAMI IDが更新された場合も、同一のArtifactとしてTerraformから参照することができます。
では、作成したAMIからEC2インスタンスを作成するように、Terraformの構成を変更します。まずは、作成されたArtifactをTerraformの構成に追加し、Terraformを実行します。
resource "atlas_artifact" "web" { name = "<atlas-username>/example-artifact" type = "ami" }
$ terraform plan $ terraform apply
続いてEC2インスタンスの定義を変更し、AMIがArtifactを参照するようにします。また、インスタンスではApacheが起動するため、80番ポートに(ついでにSSH 22番も)アクセスできるようにセキュリティグループの追加も合わせて行います。
resource "aws_instance" "web" { instance_type = "t1.micro" ami = "${atlas_artifact.web.metadata_full.region-us-east-1}" security_groups = [ "${aws_security_group.allow_ssh.name}", "${aws_security_group.allow_http.name}" ] # This will create 2 instances count = 2 } resource "atlas_artifact" "web" { name = "<atlas-username>/example-artifact" type = "ami" } resource "aws_security_group" "allow_ssh" { name = "allow_ssh" description = "Allow ssh inbound traffic" ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_security_group" "allow_http" { name = "allow_http" description = "Allow http inbound traffic" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } }
再度Terraformを実行します。
$ terraform plan $ terraform apply
手元で実行したときはELBでのEC2インスタンスの扱いに不具合があるようで、1回目はエラーになりました。再度実行することで正常に完了することができました。AWSの管理画面を見ると、ELBのインスタンス一覧のステータスが[In Service]に変わり、EC2インスタンスでApacheが動作していることがわかりますね!
3. Applicationのアップロード
今度は、VagrantでEC2インスタンスにHTMLコンテンツをデプロイしてみます。HTMLコンテンツやアプリケーションコードは、AtlasのApplicationで管理します。Vagrantfileに、以下のようにApplicationの設定を追加します。
# config.vm.provision "chef_apply" do |chef| # chef.version = "11.16.4" # end config.push.define "atlas" do |push| push.app = "<atlas-username>/example-application" push.vcs = false end end
Applicationでは、Vagrantfileと同じディレクトリ配下のファイル・ディレクトリがAtlasにコピーされ、ビルド時にPackerから参照できます。今回はHTMLコンテンツとして、index.htmlを用意しました。
$ cat index.html Hello World $
では、vagrant pushコマンドでApplicationをアップロードします。
$ vagrant push Uploading takipone/example-application: 2.45 KB/2.45 KB Uploaded takipone/example-application v1 $
PackerからApplicationを参照するように、Build ConfigurationにApplicationをリンクします。Atlasの管理画面から[Operations] - [BUILD CONFIGURATIONS]からBuild Configurationを選択し、左側のメニューから[Linked Applications]をクリックします。ユーザー名とアップロードしたApplication名、Packerから参照するパスを入力し、[Create Link]で登録します。
続いて、PackerテンプレートにHTMLコンテンツを配置する処理を追加します。
"provisioners": [ { "type": "file", "source": "/packer/app", "destination": "/tmp" }, { "type": "shell", "inline": [ "sleep 30", "sudo apt-get update", "sudo apt-get install apache2 -y", "sudo mv /tmp/app/* /var/www/" ] }],
変更したPackerテンプレートをpacker pushコマンドでアップロードし、Build Configurationを更新します。
$ packer push example-build.json Push successful to 'takipone/example-build-configuration' $
Build Configurationを更新すると再度ビルドが実行され、新しいAMIが作成されます。Terraformでは、同一ArtifactとしてAMIを参照するので、Terraformの構成を変更せずterraform applyを実行するだけで、新しいAMIのEC2インスタンスに入れ替わります!
$ terraform apply : Apply complete! Resources: 0 added, 1 changed, 0 destroyed. : $
ELBのDNS Nameにアクセスしてみると、HTMLコンテンツが正しくEC2に配置されていることが確認できます。
まとめ
Atlasを利用することで、従来別々に利用していたHashicorpのツールを連携させ、複数のプロジェクトメンバーで開発・デプロイ環境を共有することができます。
運用周りはまだ確認できていないので、引き続きAtlasについて調べていきたいと思います。