Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

FRESH LIVEにおけるServer Side Kotlinと Microservices...

soushi
October 05, 2018

FRESH LIVEにおけるServer Side Kotlinと Microservicesの今 / Logmi Tech Live #1

soushi

October 05, 2018
Tweet

More Decks by soushi

Other Decks in Technology

Transcript

  1. ϚΠΫϩαʔϏεͷར఺ w ୯Ұো֐఺Ͱཹ·Γશମ͸౗Εͳ͍ w ϚΠΫϩαʔϏε͸ೝূɺϩά ɺ՝ۚͳͲͷ୯ҐͰಈ͍͍ͯΔ w ՝͕ۚͰ͖ͳͯ͘΋ࢹௌ͸Ͱ͖Δ w εέʔϧઓཱུ͕ͯ΍͍͢

    w αʔϏεઓུͱڞʹεέʔϧͤ͞ΔϚΠΫϩαʔϏε͕໌֬ʹͳΔ w ٕज़తνϟϯϨϯδͷෑډΛԼ͛Δ w ʮνϟϯϨϯδ͍ͨ͠ݴޠͰϚΠΫϩαʔϏεΛ࡞ͬͯΈΑ͏!ʯ w ʮখ͍͞αʔϏε͔ͩΒޙͰ࡞Γ௚ͦ͏ʯʢΤϯδχΞͷϞνϕʔγϣϯ⬆
  2. ,PUMJOͷ޷͖ͳͱ͜Ζ w /VMMTBGFUZ w ߴ֊ؔ਺ w ֦ுؔ਺ w %BUBDMBTT w

    είʔϓؔ਺ 3FJpFEUZQFQBSBNFUFST ʜFUD w "OESPJEΤϯδχΞͱ஥ྑ͘ͳΕΔ w ,PUMJOΛѪͰͨ͘ͳΔͱ͜Ζ͕͍ͬͺ͍
  3. *EJPNBUJD,PUMJO$PEF 1 val context = GenericApplicationContext().apply { 2 registerBean<Foo>() 3

    registerBean { Bar(it.getBean<Foo>()) } 4 } w είʔϓؔ਺΍֦ுؔ਺Λ࢖ͬͯ,PUMJOΒ͍͠ίʔυΛॻ͘ w SFHJTUFS#FBO HFU#FBO͸֦ுؔ਺ 1 GenericApplicationContext context=new GenericApplicationContext(); 2 context.registerBean(Foo.class); 3 context.registerBean(Bar.class,()->new 4 Bar(context.getBean(Foo.class)) 5 ); w +BWB w ,PUMJO
  4. ,PUMJOTVQQPSU w 4QSJOH'SBNFXPSLͷ,PUMJOαϙʔτ w 3FJpFEUZQFQBSBNFUFSͰίʔυதͷܕʹΞΫηεͰ͖Δ 1 inline fun <reified T

    : Any> BeanFactory.getBean(): T = 2 getBean(T::class.java) 3 4 inline fun <reified T : Any> GenericApplicationContext.registerBean( 5 vararg customizers: BeanDefinitionCustomizer) { 6 registerBean(T::class.java, *customizers) 7 } 8 9 inline fun <reified T : Any> GenericApplicationContext.registerBean( 10 vararg customizers: BeanDefinitionCustomizer, 11 crossinline function: (ApplicationContext) -> T) { 12 registerBean(T::class.java, 13 Supplier { function.invoke(this) }, *customizers) 14 }
  5. 3PVUFS'VODUJPO%4- 1 @Configuration 2 class TaskRoutes(private val taskHandler: TaskHandler, 3

    private val authFilter: AuthFilter) { 4 5 @Bean 6 fun taskRouter() = router { 7 "/api".nest { 8 accept(APPLICATION_JSON).nest { 9 POST("/task", taskHandler::create) 10 GET("/task/{id}", taskHandler::fetchByTaskId) 11 } 12 } 13 }.filter(authFilter) 14 } w 4QSJOH'SBNFXPSL͔Βͷ৽ػೳͰ"1*ϧʔςΟϯάͷ%4-
  6. 3PVUFS'VODUJPO%4- w 5BTL"1*ͷ5BTL)BOEMFSΫϥε w SFR4FSWFS3FRVFTU ΛҾ਺ʹ.POP4FSWFS3FTQPOTFΛฦؔ͢਺͕ฒͿ 1 @Component 2 class

    TaskHandler(private val taskRepository: TaskRepository) { 3 4 fun fetchByTaskId(req: ServerRequest): Mono<ServerResponse> = 5 (req.pathVariable("id").toLongOrNull() 6 ?: throw WebAppException.BadRequestException("required id")).let { 7 ServerResponse.ok().json().body(Mono.just(taskRepository.getTaskById(it))) 8 } 9 10 fun create(req: ServerRequest): Mono<ServerResponse> = 11 Validator.validBody<RequestCreateTask>(req).let { 12 taskRepository.createTask(it.title, it.description).let { 13 ServerResponse.ok().json().body(Mono.just(it)) 14 } 15 } 16 }
  7. 4QSJOH8FC'MVY 1 @Configuration 2 class TaskRoutes(private val taskHandler: TaskHandler, 3

    private val authFilter: AuthFilter) { 4 @Bean 5 fun taskRouter() = router { 6 "/api".nest { 7 accept(TEXT_EVENT_STREAM).nest { 8 GET("/task/count", taskHandler::fetchTaskCount) 9 } 10 } 11 }.filter(authFilter) 12 } 13 14 @Component 15 class TaskHandler(private val taskService: TaskService) { 16 fun fetchTaskCount(req: ServerRequest): Mono<ServerResponse> { 17 return ok().json().bodyToServerSentEvents( 18 taskService.subscribeTaskCount().map { TaskCount(it) } 19 ) 20 } 21 } w 4USFBNͳ"1*Λ࣮૷Ͱ͖Δ؆ศͳ࢓૊Έ͕͋Δ
  8. ؀ڥม਺Λίϯςφʹ%* 1 // src/main/resources/application.properties 2 3 auth.env=${AUTH_ENV:local} 1 // src/main/kotlin/app/config/AppProperties.kt

    2 3 @ConfigurationProperties("auth") 4 class AppProperties { 5 var env: String = “local" // local͸σϑΥϧτม਺ 6 } w %#ઃఆͳͲҟͳΔ஋͸ίϯςφͷ؀ڥม਺ʹηοτ w 4QSJOHͷ$POpHVSBUJPO1SPQFSUJFTͰBQQMJDBUJPOQSPQFSUJFTΛϚοϐϯά w ֤؀ڥͷ؀ڥม਺͸ू໿ͨ͠ϨϙδτϦͰ؅ཧ w 4QSJOHʹ͸ίϯςφͱ਌࿨ੑΛ࣋ͭ࢓૊Έ͕͋Δ"
  9. LTͷ4FDSFUϦιʔε 1 apiVersion: v1 2 kind: Secret 3 metadata: 4

    name: mysecret 5 type: Opaque 6 data: 7 username: YWRtaW4= 8 password: MWYyZDFlMmU2N2Rm w ؀ڥຖʹҟͳΔ஋ɺओʹػີ৘ใΛѻ͏Ϧιʔε w /BNFTQBDFຖʹϦιʔεԽ
  10. 4FDSFUΛ؀ڥม਺Ͱ͔ͭ͏ 1 apiVersion: v1 2 kind: Pod 3 metadata: 4

    name: secret-env-pod 5 spec: 6 containers: 7 - name: mycontainer 8 image: redis 9 env: 10 - name: SECRET_USERNAME 11 valueFrom: 12 secretKeyRef: 13 name: mysecret 14 key: username 15 - name: SECRET_PASSWORD 16 valueFrom: 17 secretKeyRef: 18 name: mysecret 19 key: password 20 restartPolicy: Never w ίϯςφͷ؀ڥม਺ʹηοτ w ϚΠΫϩαʔϏεͰԣஅతʹڞ௨ͷϦιʔεΛࢀরͰ͖Δ
  11. H31$ w (PPHMF͕։ൃͨ͠31$ϑϨʔϜϫʔΫ w )551ͱͷޮ཰తͳ઀ଓ w ૒ํ޲ετϦʔϛϯάͷ௨৴ํࣜ w 1SPUPCVGʹΑΓσʔλγϦΞϥΠζ w

    ๛෋ͳݴޠαϙʔτ w $ɺ+BWBɺ(Pɺ/PEFKTɺ1ZUIPOɺ1)1ɺ3VCZ w ϚΠΫϩαʔϏε։ൃͱ߹கͨ͠઀ଓ΍σʔλసૹ
  12. ετϦʔϛϯά w ༷ʑͳ௨৴ํࣜ w 6OBSZ31$ʗ୯Ұ௨৴ w 4FSWFSTUSFBNJOH31$ʗ4FSWFS1VTIܕ w $MJFOUTUSFBNJOH31$ʗ$MJFOU1VTIܕ w

    #JEJSFDUJPOBMTUSFBNJOHʗ૒ํ޲௨৴ w ࢹௌ਺ɺίϝϯτ਺ɺ഑৴ঢ়گͳͲͷϦιʔ εΛετϦʔϛϯάͰྲྀ͢ 4FWFSTUSFBNJOH31$
  13. H31$4FWFS3VOOFS 1 @Configuration 2 class GrpcGlobalServerRunner(private val appProperties: AppProperties, private

    val authInterceptor: AuthInterceptor, 3 private val balanceServer: BalanceServer) : CommandLineRunner, DisposableBean { 4 5 lateinit var server: Server 6 7 override fun run(args: Array<String>) { 8 NettyServerBuilder.forPort(appProperties.grpc.global.port) 9 .addService(ProtoReflectionService.newInstance()) 10 .apply { 11 balanceServer.let { 12 ServerInterceptors.intercept(it, authInterceptor) 13 addService(it) 14 } 15 } 16 .build().start() 17 .also { server = it } 18 } 19 20 override fun destroy() { 21 Optional.ofNullable(server).ifPresent { 22 it.shutdown() 23 } 24 } 25 }
  14. ·ͱΊ w ϚΠΫϩαʔϏε։ൃͰकΓ΋߈Ί΋Ռ׶ʹ w αʔόαΠυ,PUMJO։ൃʹ͸4QSJOH#PPUYΛΦεεϝ" w ,PUMJOαϙʔτ ॆ࣮ͨ͠4QSJOH'SBNFXPSLͷίϯϙʔωϯτ w ίϯςφͱͷ਌࿨ੑ

    w LTͷಋೖʹΑΓίϯςφ഑ஔઓུʹมԽ w ϦΞϧλΠϜͳίϯςϯπఏڙʹ࠷దͳ௨৴ํࣜͷબ୒ w 44& )551 w 4QSJOH8FC'MVY H31$