Spring in Summer 〜 夏なのにSpring で登壇してきました

【求人のご案内】Javaアプリ開発エンジニア募集

よく訓練されたアップル信者、都元です。ちょっと時間があいてしまいましたが、先週金曜日、2015年8月28日、東京駅のリクルートテクノロジーズ様ご提供会場において日本Springユーザ会主催のSpring in Summer 〜 夏なのにSpringというイベントが催されました。

そこでSpring BootアプリケーションをAmazon Elastic Beanstalkに一発でデプロイしてみようと題して1セッションお話させて頂きました。

大人気だったJosh Long氏 *1によるセッションの裏番組であるにもかかわらず、ご参加いただいた皆様、ありがとうございました。正直私は、Josh Long氏のセッションを聞きに行きたかったですw

さておき。

要約

システム(≠アプリケーション)は、そのデプロイ方法・起動方法が全て記述されている(Full Described)ことが望ましいです。

「リポジトリからコードをチェックアウトし、必要に応じて環境固有の設定をした後、コマンド1つでシステムの起動・デプロイができるべき」だと常に思っています。それを体現すべく、

ことを実現しました。

これらの仕組みを丁寧に作っていくことにより、本番環境と開発環境、ステージング環境等、必要に応じてシステム全体を簡単に複数構築することができるようになり、それぞれの運用コストが低下します。また、開発者個人に完全に閉じた環境も即座に用意できるため、開発時にも便利です。

さらに、別のAWSリージョンにシステムを展開することも可能にしておくことにより、DRの視点からも有益であると考えます。

最も大事なことは、システムのデプロイの手続きが全て記述されている状態が保たれることです。特定の人しかシステムの運用手続きを知らないという状況の回避、つまり属人性排除にも一役買うでしょう。

発表資料

デモの詳説

セッション中に、1つデモを行いました。上記の通り、「リポジトリからコードをチェックアウトし、必要に応じて環境固有の設定をした後、コマンド1つでシステムの起動・デプロイができる」プロジェクトを作成し、実際にデプロイを行ってみました。

あらためて手順を説明しますので、皆さんも是非やってみてください。

デモ実行における前提条件

細かい抜け漏れはあるかもしれませんが、概ね下記の通りです。

  • インターネット接続回線があること
  • 作業環境にJDK 8が導入済みであること
  • AWSアカウントを持っていること
  • EC2のキーペア作成、及び登録がしてあること
  • S3のバケットが1つ作ってあること(ここにファイルを1つアップロードします)
  • アクセスキーを ~/.aws/credentials に、下記のように記述してあること
[default]
aws_access_key_id = AKIAXXXX
aws_secret_access_key = xxxxxxxxxxxxxxxx

あとは、100円程度のAWS課金の覚悟はしておいてくださいw 無料枠が有効な方は、恐らく無料枠の範囲で対応できる内容だとは思います。が、保証はできませんので。。。ビタ一文払いたくない人にはオススメしません。

デモ実行

では早速。

リポジトリからコードをチェックアウトし

$ git clone https://github.com/classmethod-aws/berserker.git
$ cd berserker
$ git checkout 12.0

プロジェクトはGitHubに上げてあります。このプロジェクトをcloneし、デモ用のブランチをcheckoutしておきます。

必要に応じて環境固有の設定をした後

$ cp env/_sample.gradle env/personal.gradle
$ sed -i '' -e 's/templateBucket:.*$/templateBucket: "cf-templates-1r72h3gknbax2-ap-northeast-1",/' env/personal.gradle
$ sed -i '' -e 's/KeyName:.*$/KeyName: "miyamoto-kp1",/' env/personal.gradle

ここは環境に応じて異なるポイントです。サンプルの設定ファイル _sample.gradle をコピーして、personal.gradle を作成します。サンプルファイルは下記のような感じなので、

ext {
 berserker = [
  aws: [
   profileName: "default",
   region: "ap-northeast-1",

   cfn: [
    templateBucket: "cf-templates-xxxxxxxxxxxxx-ap-northeast-1",
    stackName: "berserker",

    stackParams : [
     KeyName: "keypair",
     CIDRPrefix: "10.241",
     DBUsername: "root",
     DBPassword: "passW0rd",
     EnvironmentType: "development",
    ]
   ]
  ],
  local: [
   // アプリケーションがローカル環境から利用する、DBの接続情報
   database: [
    connectionString: "jdbc:mysql://localhost:3306/berserker?useLegacyDatetimeCode=false&serverTimezone=Universal",
    user: "root",
    password: ""
   ],
   // アプリケーションがローカルで起動する際の Spring profile名
   springProfile: "development,local",
   // アプリケーションがローカルで起動する際の logback 設定ファイル
   logbackConfigurationFile: "/path/to/berserker.xml"
  ]
 ]
}

最低限編集が必要なのは2つ。前提で準備したS3のバケット名を templateBucket に、前提で準備したEC2の鍵名を KeyName に設定してください。

私の環境では、バケット名は cf-templates-1r72h3gknbax2-ap-northeast-1 、鍵名は miyamoto-kp1 でした。

コマンド1つでシステムの起動

アプリケーションのローカル起動は、セッション中のデモで行いませんでしたが、オマケで説明しておきます。

ローカル起動については、前提条件がもうひとつありまして。ローカルにMySQLをインストールしておき、CREATE DATABASE berserker; しておく必要があります。その上で、

$ ./gradlew -is bootRun

でローカル起動ができます。起動後、下記のようにHTTPのレスポンスがあれば成功です。

$ curl -s http://localhost:8080/
User(username=miyamoto),User(username=yokota)

と、デプロイができる

さて、このシステムをAWSにデプロイします。コマンドは

$ ./gradlew -is awsFullDeploy

です。このコマンドを起動すると、AWS上にシステムの構築が始まります。さすがに、システムを一式展開する必要があるため、完了には私の環境で約20分ほど時間が掛かりました。ただ、初回実行時には依存ライブラリ等々、諸々のダウンロードも必要です。初回だけは、多く見積もって1時間くらいは覚悟して望みましょう。二度目以降は20分でいけるはずです。

さて、AWS上の環境構築が始まると間もなく、

Status of stack berserker is CREATE_IN_PROGRESS...
Status of stack berserker is CREATE_IN_PROGRESS...
Status of stack berserker is CREATE_IN_PROGRESS...

というログが流れ始めると思うので、じっと待ちましょう。これが始まれば「あと20分」です。

Status of stack berserker is CREATE_IN_PROGRESS...
Status of stack berserker is now CREATE_COMPLETE.
==== Outputs ====
BerserkerEnvironmentEndpoint (hostname to access berserker) = http://awseb-e-u-AWSEBLoa-************-**********.ap-northeast-1.elb.amazonaws.com/
:awsCfnWaitStackComplete (Thread[Daemon worker,5,main]) completed. Took 19 mins 17.62 secs.
:awsCfnMigrateStackAndWaitCompleted (Thread[Daemon worker,5,main]) started.
:awsCfnMigrateStackAndWaitCompleted
Skipping task ':awsCfnMigrateStackAndWaitCompleted' as it has no actions.
:awsCfnMigrateStackAndWaitCompleted (Thread[Daemon worker,5,main]) completed. Took 0.001 secs.
:awsFullDeploy (Thread[Daemon worker,5,main]) started.
:awsFullDeploy
Skipping task ':awsFullDeploy' as it has no actions.
:awsFullDeploy (Thread[Daemon worker,5,main]) completed. Took 0.0 secs.

BUILD SUCCESSFUL

Total time: 19 mins 41.701 secs

という感じで、BUILD SUCCESSFULが表示されたらデプロイ完了です。ログにある ==== Outputs ==== の直下に、URLが表示されているので、ここにアクセスしてみます。

$ curl -s http://awseb-e-u-AWSEBLoa-************-**********.ap-northeast-1.elb.amazonaws.com/
User(username=miyamoto),User(username=yokota)

このようなレスポンスがあれば、正常に動作しています。

ついでに撤収も1コマンドで

さて、展開した環境は、安価ですがお金を消費し続けます。これをきちんと撤去しましょう。撤去は、

$ ./gradlew -is awsFullUndeploy

です。こちらも時間が15分程度かかるので、じっと待ちましょう。

次回は

このプロジェクトのAWSデプロイの仕組みを解説したいと思います。お楽しみに。

脚注

  1. その前のセッションを聞いていたのですが、非常にトークが面白かった。