jarファイルをCloudFormationでEC2にデプロイ・実行する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Integrate Spring Boot and EC2 using Cloudformationという記事を参考に、Spring Bootでjarを作成し、CloudFormationでEC2にデプロイして実行してみました。

Spring Bootで作成するjarは、公式サイトにある5秒ごとにログを出力するアプリです。

CloudFormationではこのjarをEC2にデプロイ・実行するのですが、以下のことを行いました。

  • EC2インスタンスの起動
  • Javaのインストール
  • jarのデプロイ
  • jarの起動

以降、それぞれの手順となります。

5秒ごとにログを出力するjarを作成

先に書いたように、5秒ごとにログを出力するアプリを作成します。以下、その手順です。

1.build.gradle

Eclipse等でgradleのプロジェクトを作成し、build.gradleを以下のように記述します。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.3.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

jar {
    baseName = 'springBootEc2ScheduledTask'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter")
    testCompile("junit:junit")
}

2.タスクの作成

5秒ごとに実行するタスクを作成します。独立したクラスとして実装し、以下のようになります。

package hello;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTasks {

    private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() {
        log.info("The time is now {} on EC2.", dateFormat.format(new Date()));
    }
}

Scheduledアノテーションで定期的に実行するメソッドを定義しています。

3.main

アプリケーションのmainを持つクラスにEnableSchedulingアノテーションを付与することで、先のScheduledアノテーションが実行されるようにします。

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class Application {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class);
    }
}

ここまで作成したらアプリケーションを実行し、5秒ごとにログが標準出力されることを確認してください。

4.jarの作成、S3への配置

jarをgradleで作成したら、S3のバケット内にjarを配置します。このS3に配置したjarを、以降のCloudFormationでEC2にデプロイします。

CloudFormation

まずはCloudFormationのjsonです。

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "JarBucket": {
            "Type": "String",
            "Default": "jarを格納したS3バケット名",
            "Description" : "jar file bucket."
        },
        "KeyName": {
            "Type": "String",
            "Default": "EC2のキーペア名",
            "Description": "ec2 key pair name."
        },
        "JarName": {
            "Type": "String",
            "Default": "jarファイル名",
            "Description" : "execute jar file name."
        },
        "LogName": {
            "Type": "String",
            "Default": "ログファイル名",
            "Description": "log file name."
        },
        "ImageId": {
            "Type": "String",
            "Default": "ami-9f0c67f8",
            "Description": "ec2 image id."
        }
    },
    "Resources": {
        "RootRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": [
                                    "ec2.amazonaws.com"
                                ]
                            },
                            "Action": [
                                "sts:AssumeRole"
                            ]
                        }
                    ]
                },
                "Path": "/",
                "Policies": [
                    {
                        "PolicyName": "root",
                        "PolicyDocument": {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "s3:Get*",
                                        "s3:List*"
                                    ],
                                    "Resource": {
                                        "Fn::Join": [
                                            "",
                                            [
                                                "arn:aws:s3:::",
                                                {
                                                    "Ref": "JarBucket"
                                                },
                                                "/*"
                                            ]
                                        ]
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "RootInstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Path": "/",
                "Roles": [
                    {
                        "Ref": "RootRole"
                    }
                ]
            }
        },
        "Ec2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {"Ref" : "ImageId"},
                "InstanceType": "t2.nano",
                "KeyName": {
                    "Ref": "KeyName"
                },
                "IamInstanceProfile": {
                    "Ref": "RootInstanceProfile"
                },
                "UserData": {
                    "Fn::Base64": {
                        "Fn::Join": [
                            "",
                            [
                                "#!/bin/bash\n",
                                "aws s3 cp s3://", {"Ref" : "JarBucket"}, "/", {"Ref" : "JarName"}, " ", "/home/ec2-user/", {"Ref" : "JarName"}, "\n",
                                "sudo yum -y install java-1.8.0\n",
                                "sudo yum -y remove java-1.7.0-openjdk\n",
                                "cd /home/ec2-user/\n",
                                "sudo nohup java -jar ", {"Ref" : "JarName"}, " >> ", {"Ref" : "LogName"}, "\n"
                            ]
                        ]
                    }
                }
            }
        }
    }
}

先にも書いたようにCloudFormationでは以下のことを行います。

  • EC2インスタンスの起動
  • Javaのインストール
  • jarのデプロイ
  • jarの起動

このうち

  • Javaのインストール
  • jarのデプロイ
  • jarの起動

はUserDataを使用し、EC2の起動時にコマンドを実行することで行います。

Parametersでは

  • jarを格納したS3バケット名
  • EC2のキーペア名
  • jarファイル名
  • ログファイル名
  • EC2にImage ID

を指定します。

このjsonをテンプレートとしてCloudFormationを起動すると、EC2インスタンスが作成され、jarが実行されてログが出力されるはずです。

まとめ

以上でCloudFormationを利用したEC2の作成〜jarの実行までができました。jarファイル1つで構成される単純なバッチ処理の実行には十分ではないでしょうか? また今回はjarでしたが、別の言語でもUserDataを使用したデプロイに応用できると思います。

参考サイト

Integrate Spring Boot and EC2 using Cloudformation
Scheduling Tasks