HashiCorpから最近発表されたサービスの1つであるOttoですが、Vagrantの後継と位置づけられているらしく、遅かれ早かれ業務で使うことになりそうな気がしたので、まずはどんなものなのか、ということで触ってみました。
Ottoでは、開発環境だけではなく、本番環境まで含め、otto コマンドだけで扱えるようになっており、内部的には、今までのHashiCorpのプロダクトであるVagrant, Packer, Consul, Terraformを組み合わせて利用しているようです。
Vagrantを含めた他のHashiCorpプロダクトを組み合わせて開発環境・本番環境の構築からデプロイまですべて1つで出来るようにしたもの、というイメージのプロダクトで、Vagrantの後継という印象から来るイメージとは少し違いました。
環境
以下の環境で動作確認を行いました。
- OS X yosemite
- Otto v0.1.2
インストール
以下からバイナリファイルをダウンロードし、適当なディレクトリへ配置します。
https://ottoproject.io/downloads.html
$ mv ~/Downloads/otto /usr/local/bin/
$ chmod +x /usr/local/bin/otto
オプションは以下となります。
ステータスとバージョンを確認するコマンドを除けば、5つしかオプションがなく、かなりシンプルなようです。
$ otto --help
usage: otto [--version] [--help] <command> [<args>]
Available commands are:
build Build the deployable artifact for the app
compile Prepares your project for being run.
deploy Deploy the application
dev Start and manage a development environment
infra Builds the infrastructure for the Appfile
status Status of the stages of this application
version Prints the Otto version
以下、公式サイト( https://ottoproject.io/intro/getting-started/dev.html ) を参考にしました。
流れとしては、上記のオプションでいうと、compileで準備、devで開発環境構築
、infraで本番環境構築、buildでビルド実行、deployでデプロイ実行という形です。
また、今回は公式に提供されているサンプルアプリケーションを利用します。
設定ファイルの作成
まずは、otto compileを実行します。
アプリケーションの環境を自動で判別して、それらのデータを基にOttoの設定ファイルが作成されます。
ApplicationがRuby、Projectがサンプルアプリケーション名、Infrastructureがawsとなっていることが分かります。
$ git clone https://github.com/hashicorp/otto-getting-started.git
$ cd otto-getting-started/
$ otto compile
==> Loading Appfile...
==> No Appfile found! Detecting project information...
No Appfile was found. If there is no Appfile, Otto will do its best
to detect the type of application this is and set reasonable defaults.
This is a good way to get started with Otto, but over time we recommend
writing a real Appfile since this will allow more complex customizations,
the ability to reference dependencies, versioning, and more.
==> Fetching all Appfile dependencies...
==> Compiling...
Application: otto-getting-started (ruby)
Project: otto-getting-started
Infrastructure: aws (simple)
Compiling infra...
Compiling foundation: consul
==> Compiling main application...
==> Compilation success!
This means that Otto is now ready to start a development environment,
deploy this application, build the supporting infrastructure, and
more. See the help for more information.
Supporting files to enable Otto to manage your application from
development to deployment have been placed in the output directory.
These files can be manually inspected to determine what Otto will do.
上記で判別したアプリケーション等の情報は以下のAppfileに記載されているようです。
(参考:https://ottoproject.io/intro/getting-started/appfile.html)
$ cat .otto/appfile/Appfile.compiled
(snip)
"Application": {
"Name": "otto-getting-started",
"Type": "ruby",
"Dependencies": null
},
"Project": {
"Name": "otto-getting-started",
"Infrastructure": "otto-getting-started"
},
"Infrastructure": [
{
"Name": "otto-getting-started",
"Type": "aws",
"Flavor": "simple",
"Foundations": [
{
"Name": "consul",
"Config": null
}
(snip)
このうち、Flavorというのが、自動で構築されるAWS環境のパターンを指します。
Flavorの種類については以下のページに記載されています。デフォルトではsimpleが指定されています。
https://ottoproject.io/docs/infra/aws.html
また、この時点で、.ottoidというファイルと、.ottoというディレクトリが新たに出来ていました。
ファイル名等から見ると、中では、Vagrant, Consul, Terraformといった他のHashicorpのプロダクトが使われているようです。
$ cat .ottoid
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
DO NOT MODIFY OR DELETE THIS FILE!
This file should be checked in to version control. Do not ignore this file.
The first line is a unique UUID that represents the Appfile in this directory.
This UUID is used globally across your projects to identify this specific
Appfile. This UUID allows you to modify the name of an application, or have
duplicate application names without conflicting.
If you delete this file, then deploys may duplicate this application since
Otto will be unable to tell that the application is deployed.
$ tree .otto
.otto
├── appfile
│ ├── Appfile.compiled
│ └── version
├── compiled
│ ├── app
│ │ ├── build
│ │ │ ├── build-ruby.sh
│ │ │ └── template.json
│ │ ├── deploy
│ │ │ └── main.tf
│ │ ├── dev
│ │ │ └── Vagrantfile
│ │ └── foundation-consul
│ │ ├── app-build
│ │ │ ├── main.sh
│ │ │ └── upstart.conf
│ │ ├── app-deploy
│ │ │ └── main.sh
│ │ ├── app-dev
│ │ │ ├── main.sh
│ │ │ └── upstart.conf
│ │ ├── app-dev-dep
│ │ │ └── main.sh
│ │ └── deploy
│ │ ├── main.tf
│ │ ├── module-aws
│ │ │ ├── join.sh
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ └── variables.tf
│ │ ├── module-aws-simple
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── setup.sh
│ │ │ └── variables.tf
│ │ └── variables.tf
│ ├── foundation-consul
│ │ ├── app-build
│ │ │ ├── main.sh
│ │ │ └── upstart.conf
│ │ ├── app-deploy
│ │ │ └── main.sh
│ │ ├── app-dev
│ │ │ ├── main.sh
│ │ │ └── upstart.conf
│ │ ├── app-dev-dep
│ │ │ └── main.sh
│ │ └── deploy
│ │ ├── main.tf
│ │ ├── module-aws
│ │ │ ├── join.sh
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ └── variables.tf
│ │ ├── module-aws-simple
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── setup.sh
│ │ │ └── variables.tf
│ │ └── variables.tf
│ └── infra-otto-getting-started
│ ├── main.tf
│ └── outputs.tf
└── data
└── dev_ip
24 directories, 41 files
内部では、Terraformを利用して、本番環境向けのAWS環境の構築が自動で行われます。
例えば、Terraformの一部のファイルを見てみると、以下のようになっています。
$ cat .otto/compiled/app/foundation-consul/deploy/main.tf
provider "aws" {
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
region = "${var.region}"
}
module "consul-1" {
source = "./module-aws-simple"
index = "1"
private-ip = "10.0.2.6"
ami = "${var.ami}"
key-name = "${var.key_name}"
subnet-id = "${var.subnet_public}"
vpc-id = "${var.vpc_id}"
vpc-cidr = "${var.vpc_cidr}"
}
output "consul_address" {
value = "${module.consul-1.address}"
}
開発環境はVagrantで構築されます。
Vagrantfileを見てみると、Virtualboxのboxファイルを指定していることや、private network内に独自のIPが振られていることなどが分かります。
(なぜ100.〜のIPなんだろう…)
$ cat .otto/compiled/app/dev/Vagrantfile
(snip)
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
# Host only network
config.vm.network "private_network", ip: "100.xxx.xxx.xxx"
# Setup a synced folder from our working directory to /vagrant
config.vm.synced_folder '/Users/hoge/otto-getting-started', "/vagrant",
(snip)
dir = "/otto/foundation-1"
config.vm.synced_folder '/Users/hoge/otto-getting-started/.otto/compiled/app/foundation-consul/app-dev', dir
config.vm.provision "shell", inline: "cd #{dir} && bash #{dir}/main.sh"
(snip)
また、上記で呼ばれているshell scriptを見てみると、apt-getと書かれています…
ということはDebian系のディストリビューションの利用が想定されているようです。
$ cat .otto/compiled/app/foundation-consul/app-dev/main.sh
(snip)
oe sudo apt-get update -y
oe sudo apt-get install -y unzip
cd /tmp
oe wget https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip -O consul.zip
oe unzip consul.zip
oe sudo chmod +x consul
oe sudo mv consul /usr/local/bin/consul
oe sudo mkdir -p /etc/consul.d
oe sudo mkdir -p /mnt/consul
oe sudo mkdir -p /etc/service
(snip)
ひとまず、自動で振られるPrivate IPを、自分の環境に合わせたかったので、以下のように変更しました。
$ sed -i.bak -e 's/100.xxx.xxx.xxx/192.168.33.100/g' .otto/compiled/app/dev/Vagrantfile
$ sed -i.bak -e 's/100.xxx.xxx.xxx/192.168.33.100/g' .otto/data/dev_ip
開発環境の構築
では、otto devを実行して開発環境を構築してみます。
hashicorpのboxファイルを取ってきて、それを用いて構築しているようです。
$ otto dev
==> Creating local development environment with Vagrant if it doesn't exist...
Raw Vagrant output will begin streaming in below. Otto does
not create this output. It is mirrored directly from Vagrant
while the development environment is being created.
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'hashicorp/precise64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'hashicorp/precise64' is up to date...
(snip)
==> default: Running provisioner: shell...
default: Running: inline script
==> default: stdin: is not a tty
==> default: [otto] Installing Consul...
==> default: [otto] Installing dnsmasq for Consul...
==> default: [otto] Configuring consul service: otto-getting-started
==> default: Running provisioner: shell...
default: Running: inline script
==> default: stdin: is not a tty
==> default: [otto] Setting locale to en_US.UTF-8...
==> default: Running provisioner: shell...
default: Running: inline script
==> default: [otto] Adding apt repositories and updating...
==> default: [otto] Installing Ruby 2.2 and supporting packages...
==> default: [otto] Configuring Ruby environment...
==> default: [otto] Installing Bundler...
==> default: [otto] Bundling gem dependencies...
==> default: [otto] Configuring Git to use SSH instead of HTTP so we can agent-forward private repo auth...
==> Caching SSH credentials from Vagrant...
==> Development environment successfully created!
IP address: 192.168.33.100
(snip)
作成した環境にログインしてみます。Ubuntuが起動してきたことが分かります。
$ otto dev ssh
==> Executing SSH. This may take a few seconds...
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)
* Documentation: https://help.ubuntu.com/
New release '14.04.3 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
Welcome to your Vagrant-built virtual machine.
Last login: Fri Sep 14 06:23:18 2012 from 10.0.2.2
vagrant@precise64:/vagrant$
続いてサンプルアプリケーションを起動してみます。
$ bundle && rackup --host 0.0.0.0
Using rack 1.6.4
Using rack-protection 1.5.3
Using tilt 2.0.1
Using sinatra 1.4.6
Using bundler 1.10.6
Bundle complete! 1 Gemfile dependency, 5 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
[2015-YY-MM 13:59:13] INFO WEBrick 1.3.1
[2015-YY-MM 13:59:13] INFO ruby 2.2.3 (2015-08-18) [x86_64-linux-gnu]
[2015-YY-MM 13:59:13] INFO WEBrick::HTTPServer#start: pid=6874 port=9292
その後、ブラウザから http://指定したIPアドレス:9292/ へアクセスし、サンプルアプリケーションが閲覧できることが確認できました。
現時点でのステータスは以下のようになっています。
開発環境だけがCREATEされた状態です。
$ otto status
==> Loading status...
Depending on your configured directory backend, this may require
network operations and can take some time. On a typical broadband
connection, this shouldn't take more than a few seconds.
==> App Info
Application: otto-getting-started (ruby)
Project: otto-getting-started
Infrastructure: aws (simple)
==> Component Status
Dev environment: CREATED
Infra: NOT CREATED
Build: NOT BUILT
Deploy: NOT DEPLOYED
本番環境構築
続いて、本番環境の構築を行います。
デフォルトでは、AWS環境のバージニア北部リージョン(us-east-1)にVPCが作成されます。
が、存在しないterraformのバージョンをダウンロードしようとして(status code 404)エラーになりました…
$ otto infra
==> Detecting infrastructure credentials for: otto-getting-started (aws)
Existing infrastructure credentials were not found! Otto will
now ask you for infrastructure credentials. These will be encrypted
and saved on disk so this doesn't need to be repeated.
IMPORTANT: If you're re-entering new credentials, make sure the
credentials are for the same account, otherwise you may lose
access to your existing infrastructure Otto set up.
AWS Access Key
AWS access key used for API calls.
Enter a value: xxxxxxxxxxxxxxxxxx
AWS Secret Key
AWS secret key used for API calls.
Enter a value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SSH Public Key Path
Path to an SSH public key that will be granted access to EC2 instances
Default: ~/.ssh/id_rsa.pub
Enter a value:
(snip)
==> Downloading terraform v0.6.7...
URL: https://dl.bintray.com/mitchellh/terraform/terraform_0.6.7_darwin_amd64.zip
Error occurred: Error downloading, status code 404
そのため、今回は手動で事前にインストールしました。
$ brew install terraform
その後、再度実行してみます。
$ otto infra
(snip)
==> Detecting infrastructure credentials for: otto-getting-started
==> Building main infrastructure...
==> Executing Terraform to manage infrastructure...
Raw Terraform output will begin streaming in below. Otto
does not create this output. It is mirrored directly from
Terraform while the infrastructure is being created.
Terraform may ask for input. For infrastructure provider
credentials, be sure to enter the same credentials
consistently within the same Otto environment.
aws_vpc.main: Creating...
cidr_block: "" => "10.0.0.0/16"
default_network_acl_id: "" => "<computed>"
default_security_group_id: "" => "<computed>"
dhcp_options_id: "" => "<computed>"
enable_dns_hostnames: "" => "1"
enable_dns_support: "" => "1"
main_route_table_id: "" => "<computed>"
tags.#: "" => "1"
tags.Name: "" => "otto"
aws_vpc.main: Creation complete
aws_internet_gateway.public: Creating...
vpc_id: "" => "vpc-xxxxxxxx"
aws_subnet.public: Creating...
availability_zone: "" => "<computed>"
cidr_block: "" => "10.0.2.0/24"
map_public_ip_on_launch: "" => "1"
tags.#: "" => "1"
tags.Name: "" => "public"
vpc_id: "" => "vpc-xxxxxxxx"
aws_key_pair.main: Creating...
fingerprint: "" => "<computed>"
key_name: "" => "otto-xxxxxxxx"
public_key: "" => "ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
aws_key_pair.main: Creation complete
aws_internet_gateway.public: Creation complete
aws_route_table.public: Creating...
route.#: "" => "1"
route.3593146892.cidr_block: "" => "0.0.0.0/0"
route.3593146892.gateway_id: "" => "igw-xxxxxxxx"
route.3593146892.instance_id: "" => ""
route.3593146892.network_interface_id: "" => ""
route.3593146892.vpc_peering_connection_id: "" => ""
tags.#: "" => "1"
tags.Name: "" => "public"
vpc_id: "" => "vpc-xxxxxxxx"
aws_subnet.public: Creation complete
aws_route_table.public: Creation complete
aws_route_table_association.public: Creating...
route_table_id: "" => "rtb-xxxxxxxx"
subnet_id: "" => "subnet-xxxxxxxx"
aws_route_table_association.public: Creation complete
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.
State path: /var/folders/xn/xxxxxxxxxxxxxxxxxxxxxxxx/T/otto-tf xxxxxxxx/state
Outputs:
infra_id = xxxxxxxx
key_name = otto-xxxxxxxx
region = us-east-1
subnet_public = subnet-xxxxxxxx
vpc_cidr = 10.0.0.0/16
vpc_id = vpc-xxxxxxxx
==> Terraform execution complete. Saving results...
==> Building infrastructure for foundation: consul
Get: file:///Users/hoge/otto-getting-started/.otto/compiled/foundation-consul/deploy/module-aws-simple
==> Terraform execution complete. Saving results...
module.consul-1.aws_security_group.consul: Creating...
description: "" => "Security group for Consul 1"
egress.#: "" => "1"
egress.482069346.cidr_blocks.#: "" => "1"
egress.482069346.cidr_blocks.0: "" => "0.0.0.0/0"
egress.482069346.from_port: "" => "0"
egress.482069346.protocol: "" => "-1"
egress.482069346.security_groups.#: "" => "0"
egress.482069346.self: "" => "0"
egress.482069346.to_port: "" => "0"
ingress.#: "" => "3"
ingress.2541437006.cidr_blocks.#: "" => "1"
ingress.2541437006.cidr_blocks.0: "" => "0.0.0.0/0"
ingress.2541437006.from_port: "" => "22"
ingress.2541437006.protocol: "" => "tcp"
ingress.2541437006.security_groups.#: "" => "0"
ingress.2541437006.self: "" => "0"
ingress.2541437006.to_port: "" => "22"
ingress.2547406835.cidr_blocks.#: "" => "1"
ingress.2547406835.cidr_blocks.0: "" => "10.0.0.0/16"
ingress.2547406835.from_port: "" => "1"
ingress.2547406835.protocol: "" => "udp"
ingress.2547406835.security_groups.#: "" => "0"
ingress.2547406835.self: "" => "0"
ingress.2547406835.to_port: "" => "65535"
ingress.3910776171.cidr_blocks.#: "" => "1"
ingress.3910776171.cidr_blocks.0: "" => "10.0.0.0/16"
ingress.3910776171.from_port: "" => "1"
ingress.3910776171.protocol: "" => "tcp"
ingress.3910776171.security_groups.#: "" => "0"
ingress.3910776171.self: "" => "0"
ingress.3910776171.to_port: "" => "65535"
name: "" => "consul 1"
owner_id: "" => "<computed>"
vpc_id: "" => "vpc-xxxxxxxx"
module.consul-1.aws_security_group.consul: Creation complete
module.consul-1.aws_instance.consul: Creating...
ami: "" => "ami-xxxxxxxx"
availability_zone: "" => "<computed>"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_type: "" => "t2.micro"
key_name: "" => "otto-xxxxxxxx"
placement_group: "" => "<computed>"
private_dns: "" => "<computed>"
private_ip: "" => "10.0.2.6"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "<computed>"
source_dest_check: "" => "1"
subnet_id: "" => "subnet-xxxxxxxx"
tags.#: "" => "1"
tags.Name: "" => "consul 1"
tenancy: "" => "<computed>"
vpc_security_group_ids.#: "" => "1"
vpc_security_group_ids.3442394215: "" => "sg-xxxxxxxx"
module.consul-1.aws_instance.consul: Provisioning with 'file'...
module.consul-1.aws_instance.consul: Provisioning with 'remote-exec'...
module.consul-1.aws_instance.consul (remote-exec): Connecting to remote host via SSH...
module.consul-1.aws_instance.consul (remote-exec): Host: 52.91.xxx.xxx
module.consul-1.aws_instance.consul (remote-exec): User: hoge
module.consul-1.aws_instance.consul (remote-exec): Password: false
module.consul-1.aws_instance.consul (remote-exec): Private key: false
module.consul-1.aws_instance.consul (remote-exec): SSH Agent: true
module.consul-1.aws_instance.consul (remote-exec): Connected!
module.consul-1.aws_instance.consul (remote-exec): consul stop/waiting
module.consul-1.aws_instance.consul (remote-exec): consul start/running, process 1349
module.consul-1.aws_instance.consul: Creation complete
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.
State path: /var/folders/xn/xxxxxxxxxxxxxxxxxxxxxxxx/T/otto-tf xxxxxxxx/state
Outputs:
consul_address = 10.0.2.6
==> Terraform execution complete. Saving results...
==> Infrastructure successfully created!
The infrastructure necessary to deploy this application
is now available. You can now deploy using `otto deploy`.
VPCとConsul Serverが作成されたことが確認出来ました。
$ aws ec2 describe-vpcs
{
"Vpcs": [
{
"VpcId": "vpc-xxxxxxxx",
"InstanceTenancy": "default",
"Tags": [
{
"Value": "otto",
"Key": "Name"
}
],
(snip)
$ aws ec2 describe-instances | jq -r '.Reservations[].Instances[]|{PrivateIpAddress}'
{
"PrivateIpAddress": "10.0.2.6"
}
ステータスを確認してみます。
InfraがREADYになっています。
$ otto status
==> App Info
Application: otto-getting-started (ruby)
Project: otto-getting-started
Infrastructure: aws (simple)
==> Component Status
Dev environment: CREATED
Infra: READY
Build: NOT BUILT
Deploy: NOT DEPLOYED
本番環境をビルド
otto buildを実行すると、PackerによってAWSのAMIが作成されます。
アプリケーションのデプロイはAWSのAMIからEC2インスタンスを作成し、それを入れ替える、という形で行われるようです。
尚、最初にotto infraを実行した際に指定したパスフレーズが聞かれますので、入力します。
$ otto build
==> Detecting infrastructure credentials for: otto-getting-started (aws)
(snip)
Encrypted Credentials Password
(snip)
==> otto: Prevalidating AMI Name...
==> otto: Inspecting the source AMI...
==> otto: Creating temporary keypair: packer xxx
==> otto: Creating temporary security group for this instance...
==> otto: Authorizing access to port 22 the temporary security group...
==> otto: Launching a source AWS instance...
otto: Instance ID: i-xxxxxxxx
==> otto: Waiting for instance (i-xxxxxxxx) to become ready...
==> otto: Waiting for SSH to become available...
==> otto: Connected to SSH!
==> otto: Provisioning with shell script: /var/folders/xn/xxxxxxxx/T/packer-shellxxxxxxxx
==> otto: Uploading /Users/hoge/otto-getting-started/.otto/compiled/app/foundation-consul/app-build/ => /tmp/otto/foundation-1
==> otto: Provisioning with shell script: /var/folders/xn/xxxxxxxx/T/packer-shellxxxxxxxx
otto: [otto] Installing Consul...
otto: [otto] Installing dnsmasq for Consul...
otto: [otto] Configuring consul service: otto-getting-started
==> otto: Uploading /var/folders/xn/xxxxxxxx/T/otto-slug-xxxxxxxx
=> /tmp/otto-app.tgz
==> otto: Provisioning with shell script: build-ruby.sh
otto: [otto] Waiting for cloud-config to complete...
otto: [otto] Adding apt repositories and updating...
otto: [otto] Installing Ruby, Passenger, Nginx, and other packages...
otto: [otto] Installing Bundler...
otto: [otto] Extracting app...
otto: [otto] Adding application user...
otto: [otto] Setting permissions...
otto: [otto] Configuring nginx...
otto: [otto] Bundle installing the app...
otto: Fetching gem metadata from https://rubygems.org/..........
otto: Fetching version metadata from https://rubygems.org/..
otto: Installing rack 1.6.4
otto: Installing rack-protection 1.5.3
otto: Installing tilt 2.0.1
otto: Installing sinatra 1.4.6
otto: Using bundler 1.10.6
otto: Bundle complete! 1 Gemfile dependency, 5 gems now installed.
otto: Gems in the groups development and test were not installed.
otto: Bundled gems are installed into ./vendor/bundle.
otto: [otto] ...done!
==> otto: Stopping the source instance...
==> otto: Waiting for the instance to stop...
==> otto: Creating the AMI: otto-getting-started xxxxxxxx
otto: AMI: ami-xxxxxxxx
==> otto: Waiting for AMI to become ready...
==> otto: Terminating the source AWS instance...
==> otto: Cleaning up any extra volumes...
==> otto: Deleting temporary security group...
==> otto: Deleting temporary keypair...
Build 'otto' finished.
==> Builds finished. The artifacts of successful builds are:
--> otto: AMIs were created:
us-east-1: ami-xxxxxxxx
==> Storing build data in directory...
==> Build success!
The build was completed successfully and stored within
the directory service, meaning other members of your team
don't need to rebuild this same version and can deploy it
immediately.
作成されたAMIを確認してみます。
AMIが作成されたことが確認できます。
$ aws ec2 describe-images --owners self | jq '.Images[] | {Name, ImageId}'
{
"Name": "otto-getting-started xxxxxxxx",
"ImageId": "ami-xxxxxxxx"
}
本番環境へデプロイ
続いて上記で作成したAMIを用いて、本番環境にデプロイします。
otto deployを実行します。
EC2インスタンスが作成され、パブリックDNSが割り当てられたことが確認できます。
$ otto deploy
(snip)
Enter a value:
aws_security_group.app: Creating...
description: "" => "Managed by Terraform"
egress.#: "" => "1"
egress.482069346.cidr_blocks.#: "" => "1"
egress.482069346.cidr_blocks.0: "" => "0.0.0.0/0"
egress.482069346.from_port: "" => "0"
egress.482069346.protocol: "" => "-1"
egress.482069346.security_groups.#: "" => "0"
egress.482069346.self: "" => "0"
egress.482069346.to_port: "" => "0"
ingress.#: "" => "1"
ingress.482069346.cidr_blocks.#: "" => "1"
ingress.482069346.cidr_blocks.0: "" => "0.0.0.0/0"
ingress.482069346.from_port: "" => "0"
ingress.482069346.protocol: "" => "-1"
ingress.482069346.security_groups.#: "" => "0"
ingress.482069346.self: "" => "0"
ingress.482069346.to_port: "" => "0"
name: "" => "otto-getting-started-xxxxxxxx"
owner_id: "" => "<computed>"
vpc_id: "" => "vpc-xxxxxxxx"
aws_security_group.app: Creation complete
aws_instance.app: Creating...
ami: "" => "ami-xxxxxxxx"
availability_zone: "" => "<computed>"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_type: "" => "t2.micro"
key_name: "" => "otto-xxxxxxxx"
placement_group: "" => "<computed>"
private_dns: "" => "<computed>"
private_ip: "" => "<computed>"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "<computed>"
source_dest_check: "" => "1"
subnet_id: "" => "subnet-xxxxxxxx"
tags.#: "" => "1"
tags.Name: "" => "otto-getting-started"
tenancy: "" => "<computed>"
vpc_security_group_ids.#: "" => "1"
vpc_security_group_ids.1219882143: "" => "sg-xxxxxxxx"
aws_instance.app: Creation complete
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
(snip)
Outputs:
url = http://ec2-52-91-XX-XX.compute-1.amazonaws.com/
成功したので、ブラウザより
http://ec2-52-91-XX-XX.compute-1.amazonaws.com/
へアクセスしてみます。
開発環境と同じアプリケーションが閲覧出来ることが確認できました。
尚、この時のステータスは以下のようになっています。
$ otto status
==> Loading status...
Depending on your configured directory backend, this may require
network operations and can take some time. On a typical broadband
connection, this shouldn't take more than a few seconds.
==> App Info
Application: otto-getting-started (ruby)
Project: otto-getting-started
Infrastructure: aws (simple)
==> Component Status
Dev environment: CREATED
Infra: READY
Build: BUILD READY
Deploy: DEPLOYED
これで、一通りの流れを実行したことになります。
まとめ
今回、チュートリアル通りにコマンドを実行すれば、とりあえずサンプルは簡単に動かすことが出来ました。
HashiCorpのプロダクトは、多くのものがリリースされており、それらを1つ1つ使いこなすのは割りと大変(と思っている)ですが、
Ottoを使えば、それらのすべてを詳しく理解していなくても動かすことができそうです。
ただ、中で何が行われているかの詳細を知りたい場合、使われているプロダクトが多い分、大変な印象を受けました。
また、上記で見た限りではRedHat系ディストリビューションへの対応が分からなかったので(Vagrantfileで指定するboxを変更してapt-getの部分を書き換えて動かしたケースもあるようですが、今回は未検証)、
例えばCentOSを使いたい、等の場合はどうなるのか、というところが気になります。
なんにせよ、まだ始まったばかりのプロダクトのため、今後も注目して見ていきたいと思います。