Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
FRESH LIVEにおけるServer Side Kotlinと Microservices...
Search
soushi
October 05, 2018
Technology
1.4k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
FRESH LIVEにおけるServer Side Kotlinと Microservicesの今 / Logmi Tech Live #1
ログミーTech Live #1
https://logmitechlive.connpass.com/event/100619/
soushi
October 05, 2018
More Decks by soushi
See All by soushi
FRESH!プロジェクト/Server Side Kotlin 活用事例 / CA.kt #3
soushi
3
2.1k
Other Decks in Technology
See All in Technology
SIer20年! 培ったスキルがスタートアップで輝く時
shucho0103
0
830
タクシーアプリ『GO』の実践的データ活用
mot_techtalk
3
190
AIっぽい文章を採点して人間らしく直すアプリを作ってみた
yama3133
2
120
2026TECHFRESH畢業分享會 - Lightning Talk - 資料也要 CI/CD? 用 Airbyte 自動化資料同步
line_developers_tw
PRO
0
730
2026TECHFRESH畢業分享會 - 葬送的通靈師:化系統與用戶雜訊成行動訊號
line_developers_tw
PRO
0
740
2026.06.13_AI時代に事業会社が「SIer出身エンジニア」を求める理由 / Why Businesses Seek Engineers with a System Integrator Background in the AI Era
jumtech
0
1k
LLMにもCAP定理があるという話
harukasakihara
0
290
チームで進めるAI駆動アジャイル×ウォーターフォール
kumaiu
0
150
AI駆動開発が変える、大規模開発の前提 ーHuman in the Loop から Human on the Loop へ / AIE2026
visional_engineering_and_design
30
24k
なぜ Platform Engineering の土台に Kubernetes を選ぶのか
r4ynode
1
570
AmazonRoute 53ではじめてのドメイン取得!HTTPS化までの道のりを整理してみた
usanchuu
3
130
ルールやカスタム機能、どう活かす?ハンズオンで体感するIBM Bobの出力コントロール
muehara
1
130
Featured
See All Featured
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Google's AI Overviews - The New Search
badams
0
1k
WCS-LA-2024
lcolladotor
0
620
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
170
Evolving SEO for Evolving Search Engines
ryanjones
0
210
Designing for Performance
lara
611
70k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
The browser strikes back
jonoalderson
0
1.2k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
What does AI have to do with Human Rights?
axbom
PRO
1
2.2k
Transcript
'3&4)-*7&ʹ͓͚Δ 4FSWFS4JEF,PUMJOͱ.JDSPTFSWJDFTͷࠓ ϩάϛʔ5FDI-JWF ᖒ૱࢙!TPVTIJ@OP[BXB
BCPVUNF w αʔόαΠυΤϯδχΞ w ͍·"OESPJEΤϯδχΞͬͯ·͢! w ʙ'3&4)-*7&ॴଐLUྺ @soushi_nozawa @soushin blog.soushi.me
ੜ์ૹಈըϓϥοτϑΥʔϜ .JDSPTFSWJDFT"SDIJUFDUVSF'VMM%PDLFSOJ[FE"NB[PO8FC4FSWJDFT,VCFSOFUFT
ʮͣΌͪΌΜͶΔ'3&4)ʯ ήʔϜঁࢠͣΤͱ࣮گ͕͑ΔΌʹ͑ʹΑΔ࣮ گϢχοτ IUUQTGSFTIMJWFUWNID IUUQTUXJUUFSDPNZPVTFJ@IBZBOJF ࢲͷਪ͠νϟϯωϧͰ͢"
"HFOEB '3&4)-*7&ͱαʔόαΠυͱ,PUMJO '3&4)-*7&ͷϚΠΫϩαʔϏεࣄྫ 4QSJOH#PPUͱ,PUMJO ίϯςφͱϚΠΫϩαʔϏε
H31$ͱϚΠΫϩαʔϏε ·ͱΊ
ʮ'3&4)-*7&ʹ͓͚ΔαʔόαΠυ,PUMJO Λத৺ͱͨ͠पลٕज़ͷίϯςφͱH31$ ʹ৮ΕϚΠΫϩαʔϏε։ൃͷݟΛڞ༗ʯ
'3&4)-*7&ͱαʔόαΠυͱ,PUMJO w ༷ʑͳϚΠΫϩαʔϏεʹ,PUMJOΛಋೖ w ܾࡁूܭɺΞφϦςΟΫεɺϓογϡ௨ɺϩάऩूɺ"1* ήʔτΣΠͳͲ w ࠷৽՝ۚج൫ͷϚΠΫϩαʔϏε w ༷ʑͳγεςϜཁ݅ʹॊೈʹରԠͰ͖͍ͯΔ
ϚΠΫϩαʔϏεͷར w ୯ҰোͰཹ·ΓશମΕͳ͍ w ϚΠΫϩαʔϏεೝূɺϩά ɺ՝ۚͳͲͷ୯ҐͰಈ͍͍ͯΔ w ՝͕ۚͰ͖ͳͯ͘ࢹௌͰ͖Δ w εέʔϧઓཱུ͕͍ͯ͢
w αʔϏεઓུͱڞʹεέʔϧͤ͞ΔϚΠΫϩαʔϏε͕໌֬ʹͳΔ w ٕज़తνϟϯϨϯδͷෑډΛԼ͛Δ w ʮνϟϯϨϯδ͍ͨ͠ݴޠͰϚΠΫϩαʔϏεΛ࡞ͬͯΈΑ͏!ʯ w ʮখ͍͞αʔϏε͔ͩΒޙͰ࡞Γͦ͏ʯʢΤϯδχΞͷϞνϕʔγϣϯ⬆
ΞʔΩςΫνϟ w ̍ͭͷϚΠΫϩαʔϏεʹ̍ͭͷϨϙδτϦɺ̍ͭͷϦιʔεʢ%#ʣ͕ίϯηϓτ w ̍ͭͷϚΠΫϩαʔϏε%PDLFSpMFΛͪίϯςφԽ͢Δ w %PDLFSOJ[FE͞ΕͨϚΠΫϩαʔϏε,VCFSOFUFTͰΦʔέετϨʔγϣϯ
ݱࡏͷ'3&4)-*7& w (PMBOHͱ,PUMJOͷϋΠϒϦουߏ w ৴γεςϜɺϨΠϠʔܥ(PMBOH w ৽نͷ"1*جຊ,PUMJOͰ w "1*Λ(PMBOHͰ͍ͬͺ͍ॻ͘ͷπϥΠʢ(Pے௧ʣ w
+BWBࢿ࢈Λ׆༻͢Εૣ͘࡞ΕΔͱ͜Ζ͋Δ w ϚΠΫϩαʔϏε։ൃͷརΛ׆͔ͯ͠ݴޠʹറΒΕͣϑϥοτʹ
,PUMJOͷ͖ͳͱ͜Ζ w /VMMTBGFUZ w ߴ֊ؔ w ֦ுؔ w %BUBDMBTT w
είʔϓؔ 3FJpFEUZQFQBSBNFUFST ʜFUD w "OESPJEΤϯδχΞͱྑ͘ͳΕΔ w ,PUMJOΛѪͰͨ͘ͳΔͱ͜Ζ͕͍ͬͺ͍
4QSJOH#PPU w ओʹ࠾༻͍ͯ͠ΔϑϨʔϜϫʔΫ w WY3&-&"4&Λಋೖ w ,PUMJOTVQQPSU w ίʔυΛγϯϓϧʹݟ௨͠Α͘*EJPNBUJD ,PUMJO$PEFΛॻ͘͜ͱΛ৺͕͚Δ
IUUQTEPDTTQSJOHJPTQSJOHEPDTDVSSFOUTQSJOH GSBNFXPSLSFGFSFODFLPUMJOIUNM
*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
,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 }
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-
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 }
4QSJOH8FC'MVY w͔ΒՃ͞Εͨίϯϙʔωϯτ w3FBDUJWF1SPHSBNNJOHΛαϙʔτ wαʔό1VTIܕͷ"1*͕ͭ͘ΕΔ w4FSWFS4FOU&WFOUTͰఏڙ w4QSJOHXFCqVYͱXFCNWDڞଘՄ ೳ
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*Λ࣮Ͱ͖Δ؆ศͳΈ͕͋Δ
IUUQTTQFBLFSEFDLDPNTPVTIJDBEPULUOVNCFS w ,PUMJOݴޠͷ׆༻ࣄྫΛத৺ʹͨ͠εϥΠυ
·ͱΊ4QSJOH#PPUͱ,PUMJO w ,PUMJOαϙʔτͰ,PUMJOΒ͍͠ίʔυΛॻ͘ w 3PVUFS'VODUJPO%4- w "1*։ൃʹมԽ w 4QSJOH8FC'MVY w
ϦΞϧλΠϜͳίϯςϯπఏڙ͕Մೳʹ
ίϯςφͱϚΠΫϩαʔϏε w ϚΠΫϩαʔϏεͷϧʔϧ w %PDLFSpMFΛ࣋ͪίϯςφԽ͢Δ͜ͱ w ڥมΛίϯςφʹ%* w LTͷ4FDSFUϦιʔεΛ׆༻ w
LTͷ%BNFO4FUʹΑΔαʔϏεϩάऩूͷมԽ
ڥมΛίϯςφʹ%* 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ʹίϯςφͱੑΛ࣋ͭΈ͕͋Δ"
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ຖʹϦιʔεԽ
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 ϚΠΫϩαʔϏεͰԣஅతʹڞ௨ͷϦιʔεΛࢀরͰ͖Δ
αʔϏεϩάऩूͷมԽ w ͜Ε·ͰͷFDTͰϚΠΫϩαʔϏε୯ҐͰΫϥελΛΜͰ͍ͨ w ϚΠΫϩαʔϏεͱηοτͰαΠυΧʔίϯςφΛஔʢqVFOUʣ w LTͷ%BFNPO4FUͰqVFOUEΛ/PEFʹஔʢ/PEFQPEͷू߹ମʣ w /PEFͷίϯςφͷϩάΛऩू w
αΠυΧʔίϯςφͷఫഇ( w ΞϓϦͷϩάग़ྗઌΛඪ४ग़ྗͷΈͱ͢Δ w MPHCBDLͷઃఆ͕؆ૉʹ(
TUFSO wQPEͷϩάΛUBJMͯ͘͠ΕΔ wDMVTUFS OBNFTQBDF DPOUBJOFS TFMFDUPSFUDͰϑΟϧλϦϯά wKRͱ߹Θͤͯϩά֬ೝ wೝূ͕௨ΕϩʔΧϧ͔Βར༻Մೳ w։ൃͷ͓ڙʹ"
IUUQTHJUIVCDPNXFSDLFSTUFSO
ίϯςφͱϚΠΫϩαʔϏεਤղ wίϯςφͷڥใڥมͰ %* wڞ௨Խ͍ͨ͠มLTͷ4FDSFU ϦιʔεΛར༻ wίϯςφͷϩάLTͷ %BFNPO4FUΛ/PEFʹஔͯ͠ qVFUEͰऩू
%PDLFS,VCFSOFUFT࣮ફ։ൃೖ w '3&4)-*7&5FDI-FBEͷࢁా໌ݑʢஶʣ w ग़൛ɿٕज़ධࣾ ଓ͖ςΩετͰ"
·ͱΊίϯςφͱϚΠΫϩαʔϏε w ίϯςφͱͷੑ͕େࣄ w ڥมͷϚοϐϯά w LTϦιʔεʹΑΓίϯςφߏʹมԽ w 4FDSFU %BFNPO4FU
w TUFSOศར(
H31$ w (PPHMF͕։ൃͨ͠31$ϑϨʔϜϫʔΫ w )551ͱͷޮతͳଓ w ํετϦʔϛϯάͷ௨৴ํࣜ w 1SPUPCVGʹΑΓσʔλγϦΞϥΠζ w
๛ͳݴޠαϙʔτ w $ɺ+BWBɺ(Pɺ/PEFKTɺ1ZUIPOɺ1)1ɺ3VCZ w ϚΠΫϩαʔϏε։ൃͱ߹கͨ͠ଓσʔλసૹ
ετϦʔϛϯά w ༷ʑͳ௨৴ํࣜ w 6OBSZ31$ʗ୯Ұ௨৴ w 4FSWFSTUSFBNJOH31$ʗ4FSWFS1VTIܕ w $MJFOUTUSFBNJOH31$ʗ$MJFOU1VTIܕ w
#JEJSFDUJPOBMTUSFBNJOHʗํ௨৴ w ࢹௌɺίϝϯτɺ৴ঢ়گͳͲͷϦιʔ εΛετϦʔϛϯάͰྲྀ͢ 4FWFSTUSFBNJOH31$
ϚΠΫϩαʔϏεͱH31$ w 1VCMJDͱ*OUFSOBM͚ͷH31$4FSWFSͷఏڙ w 1PSUΛ͚ͯ̎ͭͷ4FSWFSΛىಈ w 4QSJOHGSBNFXPSL w $PNNBOE-JOF3VOOFS w
%JTQPTBCMF#FBO
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 }
4QSJOH'SBNFXPSLͱH31$ w 4QSJOHGSBNFXPSLͷFDPTZTUFNͱHSQDKBWBͷڞଘ( w 4FSWFSىಈɺ*OUFSDFQUPSͳͲͳ͘ߏஙՄೳ w ೖ೦ͳΫϥΠΞϯτૄ௨֬ೝʢಛʹ"OESPJEʣ w ఆظతͳपลϥΠϒϥϦͷΞοϓσʔτ
·ͱΊH31$ͱϚΠΫϩαʔϏε w ޮతͳ௨৴ w ϚΠΫϩαʔϏεʹ߹கͨ͠։ൃ w 4QSJOH'SBNFXPSLͰH31$4FWFSͷߏங w 1PSUͷ׆༻ w
̍ͭͷKBSʹ1VCMJD *OUFSOBMͷ4FSWFSΛىಈ
·ͱΊ w ϚΠΫϩαʔϏε։ൃͰकΓ߈ΊՌʹ w αʔόαΠυ,PUMJO։ൃʹ4QSJOH#PPUYΛΦεεϝ" w ,PUMJOαϙʔτ ॆ࣮ͨ͠4QSJOH'SBNFXPSLͷίϯϙʔωϯτ w ίϯςφͱͷੑ
w LTͷಋೖʹΑΓίϯςφஔઓུʹมԽ w ϦΞϧλΠϜͳίϯςϯπఏڙʹ࠷దͳ௨৴ํࣜͷબ w 44& )551 w 4QSJOH8FC'MVY H31$
খ͞ͳϚΠΫϩαʔϏε͔Β ,PUMJOͰ4FSWFS4JEF։ൃΛ"
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ