Slide 1

Slide 1 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Application Prototyping Solutions Architect Fumihiko Shiroyama September 20, 2019 Spring BootをKotlinで作成し Amazon Elastic Container Service (ECS) で稼働させる JSUG 勉強会 2019 その9 Spring&AWS

Slide 2

Slide 2 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. スライドURL http://bit.ly/2lW4MTT

Slide 3

Slide 3 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. ⾃⼰紹介 名前:⽩⼭ ⽂彦(しろやま ふみひこ) 所属:アマゾン ウェブ サービス ジャパン株式会社 アプリケーションプロトタイピングソリューションアーキテクト 経歴:インフラエンジニア、バックエンド開発者 モバイルアプリ開発者、クラウドアーキテクト 趣味:⼦育て!、懸垂、⾃動テスト#

Slide 4

Slide 4 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. ⾃動テスト⼤好きです! • Androidテスト全書という本を出しました • ⾃動テストの種類やカバーする範囲、モック (テストダブル)の考え⽅、CI/CDとの統合 など、Androidに限らずJava/Kotlin開発全般 に使える知識を解説しました ☞テストコードは全編Kotlinで解説しています!

Slide 5

Slide 5 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Why Kotlin?

Slide 6

Slide 6 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. What’s Kotlin • いわゆる”AltJava” • 2011年に登場した⽐較的新しい⾔語 • 完結で強⼒な記法 • Null安全 • Javaとの相互運⽤性が⾼い • JetBrains製でIntelliJとの相性も良い

Slide 7

Slide 7 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. public class Task { final long id; final String content; final boolean done; public Task(long id, String content, boolean done) { this.id = id; this.content = content; this.done = done; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Task task = (Task) o; return id == task.id && done == task.done && Objects.equals(content, task.content); } @Override public int hashCode() { return Objects.hash(id, content, done); } @Override public String toString() { return "Task{" + "id=" + id + ", content='" + content + '\'' + ", done=" + done + '}'; } }

Slide 8

Slide 8 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task(val id: Long, val content: String, val done: Boolean) データクラス

Slide 9

Slide 9 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task(val id: Long, val content: String, val done: Boolean)

Slide 10

Slide 10 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task(val id: Long, val content: String, val done: Boolean)

Slide 11

Slide 11 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task(val id: Long, val content: String, val done: Boolean)

Slide 12

Slide 12 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun hasItem(list: List, predicate: (item: Int) -> Boolean): Boolean { for (i in list) { if (predicate(i)) return true } return false } 関数リテラル

Slide 13

Slide 13 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun hasItem(list: List, predicate: (item: Int) -> Boolean): Boolean { for (i in list) { if (predicate(i)) return true } return false }

Slide 14

Slide 14 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun hasItem(list: List, predicate: (item: Int) -> Boolean): Boolean { for (i in list) { if (predicate(i)) return true } return false }

Slide 15

Slide 15 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun hasItem(list: List, predicate: (item: Int) -> Boolean): Boolean { for (i in list) { if (predicate(i)) return true } return false }

Slide 16

Slide 16 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun hasItem(list: List, predicate: (item: Int) -> Boolean): Boolean { for (i in list) { if (predicate(i)) return true } return false }

Slide 17

Slide 17 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val isEven: (item: Int) -> Boolean = { it % 2 == 0 } hasItem(listOf(1, 2, 3), isEven)

Slide 18

Slide 18 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val isEven: (item: Int) -> Boolean = { it % 2 == 0 } hasItem(listOf(1, 2, 3), isEven)

Slide 19

Slide 19 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val isEven: (item: Int) -> Boolean = { it % 2 == 0 } hasItem(listOf(1, 2, 3), isEven)

Slide 20

Slide 20 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val isEven: (item: Int) -> Boolean = { it % 2 == 0 } hasItem(listOf(1, 2, 3), isEven)

Slide 21

Slide 21 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. hasItem(listOf(1, 2, 3), { it % 2 == 0 })

Slide 22

Slide 22 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. hasItem(listOf(1, 2, 3)) { it % 2 == 0 }

Slide 23

Slide 23 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun sum(nums: List): Int { tailrec fun go(nums: List, acc: Int): Int = if (nums.isEmpty()) acc else go(nums.drop(1), acc + nums.first()) return go(nums, 0) } ⾼階関数

Slide 24

Slide 24 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun sum(nums: List): Int { tailrec fun go(nums: List, acc: Int): Int = if (nums.isEmpty()) acc else go(nums.drop(1), acc + nums.first()) return go(nums, 0) }

Slide 25

Slide 25 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun sum(nums: List): Int { tailrec fun go(nums: List, acc: Int): Int = if (nums.isEmpty()) acc else go(nums.drop(1), acc + nums.first()) return go(nums, 0) } ☞ 末尾再帰最適化

Slide 26

Slide 26 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. fun sum(nums: List): Int { tailrec fun go(nums: List, acc: Int): Int = if (nums.isEmpty()) acc else go(nums.drop(1), acc + nums.first()) return go(nums, 0) }

Slide 27

Slide 27 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Null安全 val nullable: String? = "foo" val str = nullable?.let { it.toUpperCase() } ?: "bar"

Slide 28

Slide 28 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val nullable: String? = "foo" val str = nullable?.let { it.toUpperCase() } ?: "bar"

Slide 29

Slide 29 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val nullable: String? = "foo" val str = nullable?.let { it.toUpperCase() } ?: "bar"

Slide 30

Slide 30 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val nullable: String? = "foo" val str = nullable?.let { it.toUpperCase() } ?: "bar"

Slide 31

Slide 31 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val nullable: String? = "foo" val str = nullable?.let { it.toUpperCase() } ?: "bar"

Slide 32

Slide 32 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. val nullable: String? = "foo" val str = nullable?.let { it.toUpperCase() } ?: "bar"

Slide 33

Slide 33 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. object Singleton { @JvmStatic fun staticFunc() { } } // from Java Singleton.staticFunc(); Java相互運⽤

Slide 34

Slide 34 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task @JvmOverloads constructor(val id: Long, val content: String, val done: Boolean = false) // from Java new Task(1, "foo"); new Task(2, "bar", true);

Slide 35

Slide 35 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task @JvmOverloads constructor(val id: Long, val content: String, val done: Boolean = false) // from Java new Task(1, "foo"); new Task(2, "bar", true);

Slide 36

Slide 36 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task @JvmOverloads constructor(val id: Long, val content: String, val done: Boolean = false) // from Java new Task(1, "foo"); new Task(2, "bar", true);

Slide 37

Slide 37 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. data class Task @JvmOverloads constructor(val id: Long, val content: String, val done: Boolean = false) // from Java new Task(1, "foo"); new Task(2, "bar", true);

Slide 38

Slide 38 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Spring with Kotlin

Slide 39

Slide 39 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Spring Initializr https://start.spring.io/

Slide 40

Slide 40 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. interface Greeter { fun hello(name: String): String }

Slide 41

Slide 41 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. @Component class JapaneseGreeter : Greeter { override fun hello(name: String): String = "こんにちは、$name!" }

Slide 42

Slide 42 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. @RestController class HelloController(val greeter: Greeter) { @GetMapping("hello") fun hello(@RequestParam("name") name: String): String = greeter.hello(name) }

Slide 43

Slide 43 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Docker化する

Slide 44

Slide 44 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Docker化するメリット • 簡単に捨てられる開発環境 • ステートレスなアーキテクチャの強制 • 本番運⽤を⾒据えられる

Slide 45

Slide 45 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. FROM amazoncorretto:8 LABEL maintainer="Fumihiko Shiroyama " RUN mkdir /app WORKDIR /app COPY ./build/libs/*.jar /app/app.jar ENTRYPOINT [ "sh", "-c", "java -jar /app/app.jar"] Dockerfile docker build -t spring-demo . docker container run --rm --name spring-test --net=web --env-file=default.env -d -p 8080:8080 spring-demo:latest

Slide 46

Slide 46 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. DBもDocker化しよう

Slide 47

Slide 47 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. XCTestのはじめ⽅ % docker container run --rm --name mysql-test --net=web -e MYSQL_ROOT_PASSWORD=testtest \ -d -p 3306:3306 mysql:latest \ --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci # prepare setup.sql % docker exec mysql-test mysql \ -u root --password='testtest' -e"$(cat setup.sql)"

Slide 48

Slide 48 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. application.yml 環境変数

Slide 49

Slide 49 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. interface SampleRepository : JpaRepository @Controller @RequestMapping("tasks") class TaskController(private val repository: SampleRepository) { @GetMapping("") fun index(model: Model): String { val tasks = repository.findAll() model.addAttribute("tasks", tasks) return "tasks/index" } } ORMはJPAを利⽤

Slide 50

Slide 50 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. DBに接続完了!

Slide 51

Slide 51 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. AWSにデプロイする

Slide 52

Slide 52 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. 今回利⽤するコンポーネント • Amazon Aurora • Amazon Elastic Container Service • CodeStar

Slide 53

Slide 53 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon Aurora

Slide 54

Slide 54 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon Aurora • エディションはMySQL互換 • 1つのライターと複数のリーダ • 書き込みエンドポイントと読み込みエンドポイントをメモ ☞基本的なアクセス⽅法はこれまでと変わらない

Slide 55

Slide 55 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon Elastic Container Service

Slide 56

Slide 56 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECS • Amazon ECRにイメージの登録 • タスクの作成 • クラスタの作成 • サービスの作成

Slide 57

Slide 57 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECR

Slide 58

Slide 58 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECR $(aws ecr get-login --no-include-email --region ap- northeast-1) docker build -t spring-demo . docker tag spring-demo:latest xxxxxx.dkr.ecr.ap- northeast-1.amazonaws.com/spring-demo:latest docker push xxxxxx.dkr.ecr.ap-northeast- 1.amazonaws.com/spring-demo:latest ☝解説に従うだけ!

Slide 59

Slide 59 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECSの概念 • Dockerコンテナを簡単にデプロイ・管理するためのマ ネージド・サービス • コントロールプレーンにはECS/EKSが選べる • データプレーンにはEC2/Fargateが選べる • Fargateを使うとリソースについて意識する必要がない

Slide 60

Slide 60 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECSの登場⼈物 • タスク • Dockerコンテナと考えればよい。タスク定義から作る • サービス • 複数のタスクからなる。「APIサーバ」「HTTPサーバ」など の役割が1単位となる。 • クラスタ • 複数のサービスを束ねたもの

Slide 61

Slide 61 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECS – クラスター

Slide 62

Slide 62 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECS – タスク

Slide 63

Slide 63 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECS – タスク

Slide 64

Slide 64 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECS – タスク ☝環境変数にDB接続情報を格納

Slide 65

Slide 65 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Amazon ECS – サービス

Slide 66

Slide 66 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved.

Slide 67

Slide 67 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. まとめ • ローカルから段階的にDocker化することで簡単にECS化できた • Fargateは下回りを意識しなくてもコンテナが扱えて便利 • サービスをALBに接続することでロードバランシングなども可能 • CodeStar等のCI/CDツールと連携すると、コードチェックインを契 機にビルド、ECRの作成、ECSへのデプロイなども⾃動化できる

Slide 68

Slide 68 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. ご清聴ありがとございました(

Slide 69

Slide 69 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. 質疑応答

Slide 70

Slide 70 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. Appendix

Slide 71

Slide 71 text

© 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved. 参考⽂献 • ⻑澤太郎(2017)『Kotlin Web アプリケーション – 新しいサーバ サイドプログラミング』リックテレコム.