AWS ECS上に構築するSpringアプリケーション(3)

【連載】

AWSで作るクラウドネイティブアプリケーションの基本

【第6回】AWS ECS上に構築するSpringアプリケーション(3)

[2019/04/17 08:00]川畑 光平 ブックマーク ブックマーク

開発ソフトウェア

本連載では、以下のイメージ構成に沿ってアプリケーション開発を進めています。

開発するアプリケーションの構成イメージ

前回までに、VPC環境/アプリケーションロードバランサ(ALB)を構築しました。今回はECSコンテナで実行するSpringアプリケーションの実装方法について解説します。

Springを使用したコンテナアプリケーションの実装方法

ECSの実態はDockerコンテナなので、ECSで実行するSpringアプリケーションは、単純にLinuxベースのOSで実行するアプリケーションを「Spring Boot」を使って実装し、ExcutableJar形式で実行するコンテナイメージを作成する方法が簡易です。

ただ、ECSを用いると、単にDockerをEC2上で実行する場合に比べて、クラスタのポートの管理やコンテナ実行がAWSのマネージドサービスになり、コンテナアプリケーション間のサービス連携はALBを介して行うほうが良いという特徴があります。アプリケーションを実装する際は、こうした点を理解しておくことが必要です。

なお、実際に作成したアプリケーションはGitHub上にコミットしています。以降、解説で使用しているソースコードでは、import文などの記述を一部省略しているので、実行コードを作成する場合は、必要に応じて適宜GitHub上のソースコードも参照してください。

pom.xmlの記述

Spring Bootを使用してアプリケーションを構築するには、まず、Mavenプロジェクトのpom.xmlで必要なライブラリの依存性を定義します。今回は、プライベートサブネットに配置する「単純なAPIを持つアプリケーション(Backend)」と、パブリックサブネットに配置する「簡単なHTMLを返すWebアプリケーション(BFF:Backend For Frontend)」を作成するので、各アプリケーションプロジェクトには、以下のライブラリを定義します。

【プライベートサブネット(Backend)アプリケーションのpom.xml】

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>

【パブリックサブネット(BFF)アプリケーションのpom.xml】

<dependencies>
  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
  </dependency>
</dependencies>

どちらも「spring-boot-starter-web」が必須ですが、BFFアプリケーションはHTMLページを生成するので、テンプレートエンジンである「Thymeleaf」も含めておきましょう。また、BFFでは、ALBのDNS名をプロパティファイルに記述するので、「spring-boot-configuration-processor」も依存関係に含めておいてください。

さらに、アプリケーションをExcutableJar実行形式とするために、「spring-boot-maven-plugin」もpom.xmlのビルドオプションに追加しておく必要があります。

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

アプリケーションの実装

では、アプリケーションを実装していきます。まず、プライベートサブネットでバックエンドAPIサーバとして、「/api/v1/users」というURLのパスでリクエストを受け取り、ユーザのリストを返却する簡単なアプリケーションを作成しておきます。

SpringBootでこれを実装するには、Controllerクラスと起動/設定ファイルクラスが最低限必要です。

【Backendアプリケーションのリクエストを受け付けるControllerクラス】

package org.debugroom.mynavi.sample.ecs.backend.app.web;

import org.debugroom.mynavi.sample.ecs.backend.app.model.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1")
public class BackendRestController {

    @GetMapping("/users")
    public List<User> getUsers(){
        List<User> users = new ArrayList<>();
        users.add(User.builder().userId("1").userName("Taro").build());
        users.add(User.builder().userId("2").userName("Jiro").build());
        return users;
    }
}

【BackendアプリケーションのSpirngBoot起動クラス】

package org.debugroom.mynavi.sample.ecs.backend.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

また、Controllerクラスを読み取ってREST APIとして動作させるために、以下のように「WebMvcConfigurer」を実装し、「@ComponentScan」でコントローラのパッケージを指定したクラスを上述のSpirngBoot起動クラスと同じパッケージに配置しておきましょう。

【BackendアプリケーションのWebMVC設定クラス】

package org.debugroom.mynavi.sample.ecs.backend.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan("org.debugroom.mynavi.sample.ecs.backend.app.web")
public class MvcConfig implements WebMvcConfigurer {
}

ここまではSpringBootで作るシンプルなREST APIアプリケーションですが、Backendアプリケーションの「application.yml」にserver.servlet.context-pathプロパティを設定しておいてください。この設定を追加することで、URLが「http://localhost:8080/backend/api/v1/users」になり、前回設定したALBのパスベースのルーティングを考慮したかたちになります(以下参照)。

applicaiton.yml
server:
  servlet:
   context-path: /backend

続いて、パブリックサブネットに配置するBFFアプリケーションを実装します。アプリケーションの完成イメージは下記の通り、index.htmlページにある、ボタンを押下すると、BackendアプリケーションのGET API(/backend/api/v1/users)を呼び出し、結果をHTMLページに埋め込んで返す処理を行います。

アプリケーションの完成イメージ

index.htmlページから送信したリクエストを受けてBackendのAPIを呼び出し、戻った結果をusers.htmlに出力して、クライアントにHTMLページを返却するBFFアプリケーションのControllerは、次の通りです。

package org.debugroom.mynavi.sample.ecs.backendforfrontend.app.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.client.RestOperations;

@Controller
public class BackendForFrontendController {

    @Autowired
    RestOperations restOperations;

    @RequestMapping(method = RequestMethod.GET, value = "users")
    public String getUsers(Model model){
        String service = "/backend/api/v1/users";
        model.addAttribute("users",
            restOperations.getForObject(service, User[].class));
        return "users";
    }
}

SpringBoot起動クラスの構成はBackendとほぼ同じです。ただし、Controllerでは、Backendアプリケーションを呼び出し、結果をThymeleafのテンプレートに渡してHTMLページを返却する点が異なります。

このControllerでは、RestTemplateのインタフェースである「org.springframework.web.client.RestOperations」を使用してBackendサービスを呼び出しています。ここで実装を工夫して、ALBのDNSドメインをプロパティファイルから取得して設定するかたちにしておけば、Javaソースコード上でAWS環境に依存しないアプリケーション実装にすることが可能です。具体的には、BFFアプリケーションのapplicaiton.ymlに以下のように記述しておきます。

service:
  dns: http://internal-mynavi-sample-private-alb-XXXXXXX.ap-northeast-1.elb.amazonaws.com

プロパティの取得は「org.springframework.boot.context.properties.ConfigurationProperties」などを使って、ymlに定義したプロパティ定義を自動でBeanにインジェクションするようにしておくと良いでしょう。

 package org.debugroom.mynavi.sample.ecs.backendforfrontend.app.web;

 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;

 @Component
 @ConfigurationProperties(prefix="service")
 public class ServiceProperties {

   private String dns;

}

また、「RestOpearations」の生成時に設定クラス上で「org.springframework.boot.web.client.RestTemplateBuilder」のrootUri()メソッドで、下記のように、ALBのルートとなるURLをプロパティから取得して設定しておけば、URL設定の記述も1カ所で済みます。

package org.debugroom.mynavi.sample.ecs.backendforfrontend.config;

import org.debugroom.mynavi.sample.ecs.backendforfrontend.app.web.ServiceProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestOperations;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@ComponentScan("org.debugroom.mynavi.sample.ecs.backendforfrontend.app.web")    
@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Autowired
    ServiceProperties properties;

    @Bean
    public RestOperations restOperations(RestTemplateBuilder restTemplateBuilder){
       return restTemplateBuilder.rootUri(properties.getDns()).build();
    }
 }

上記のポイントを踏まえ、アプリケーションを実装しておけば、パブリックサブネットのBFFアプリケーションからプライベートサブネット内のBackendのAPIの呼び出しをごく少量のコーディングで実装できます。また、AWS環境に依存した内容は設定ファイルのALBのURL1カ所に限定されるので、ポータリビリティの高いアプリケーションにすることが可能です。

これで、アプリケーションを実装できました。次回は、実装したSpringアプリケーションのDockerコンテナイメージを作り、レジストリへプッシュします。

著者紹介


川畑 光平(KAWABATA Kohei)

某システムインテグレータにて、金融機関システム業務アプリケーション開発・システム基盤担当を経て、現在はソフトウェア開発自動化関連の研究開発・推進に従事。

Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professionalなどの資格を持ち、アプリケーション基盤・クラウドなどさまざまな開発プロジェクト支援にも携わる。

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

もっと知りたい!こちらもオススメ

[講演資料] 一休のクラウド移行/SRE、6領域の具体策

[講演資料] 一休のクラウド移行/SRE、6領域の具体策

システムの安定性と俊敏性(アジリティ)を高めるために、インフラやソフトウェア、運用方法について常に検討を重ねていく――「SRE(Site Reliability Engineering)」という名の下に、先進企業のエンジニアが取り組んでいる活動だ。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で IT Search+ の人気記事をお届けします

会員登録(無料)

注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
知りたい! カナコさん 皆で話そうAIのコト
教えてカナコさん! これならわかるAI入門
対話システムをつくろう! Python超入門
Kubernetes入門
AWSで作るクラウドネイティブアプリケーションの基本
ソフトウェア開発自動化入門
PowerShell Core入門
徹底研究! ハイブリッドクラウド
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

ページの先頭に戻る