SmartNews に新たに登場した「タイムセール」のバックエンドシステムの開発の裏側をお話しました。
SmartNews ʹ͓͚Δcontainer friendly ͳSpring Boot ΞϓϦέʔγϣϯ։ൃJSUG ษڧձ 2019 ͦͷ5 / 2019-05-31KOMIYA Atsushi
View Slide
@komiya_atsushi
SmartNews ʹ͓͚Δcontainer friendly ͳSpring Boot ΞϓϦέʔγϣϯ։ൃ
SmartNews ʹ͓͚Δcontainer friendly ͳSpring Boot ΞϓϦέʔγϣϯ։ൃ(container friendly ݴ͏΄Ͳͷൃද༰͡Όͳ͍ͳ )(Spring Boot ͕ओͱ͍͏ײ͡Ͱͳ͍ͳ… )
Spring Boot DockerΈ͍ͨͳΛظ͞Εͯͨํ͢Έ·ͤΜ
Docker Λ·͋·͋׆༻ͨ͠Spring Boot ΞϓϦέʔγϣϯ։ൃͷࣄྫΛ͓͠·͢
http://about.smartnews.com/ja/2019/05/21/20190521/
SmartNews ͷඪ४తͳٕज़ελοΫ
http://bit.ly/smartnews-tech-stack-2019
ૡ͍ఠΜͰΛ͢Δͱ…• AWS + AmazonLinux• ALB/CLB + ASG + EC2• nginx + Spring Boot w/ embedded Tomcat• Java 8 (Java, Scala, Kotlin)• Terraform, CircleCI, CodeDeploy, Nexus, Datadog
λΠϜηʔϧ։ൃͷཪ
։ൃॳͷঢ়گ• 2019 Q1 தʹ։࢝ͯ͠ Q1 தʹϦϦʔε༧ఆ• ࣮ࡍʹϦϦʔεͰ͖ͨͷ Q2 ಄• ϦϦʔε·Ͱͷ࣌ؒత༛༧͕গͳ͍• ׳Ε͠Έɺ։ൃޮΑ͍ϑϨʔϜϫʔΫ / ݴޠΛબ• Spring Boot + Kotlin
։ൃॳͷঢ়گ• 2019 Q1 ࣌ͷࣾ֎ͷঢ়گ• Java 11 ͕ϦϦʔε͞Εͯ 1Q Ҏ্ܦա• ࣾతʹ·ͩ Java 8 ͕ݱͷγεςϜ͕େΛΊ͍ͯͨ• ৽ن։ൃ͢ΔαʔϏεͳͷͰɺ͍·͞Β Java 8 બͨ͘͠ͳ͍
։ൃॳͷঢ়گ• ࣾͷඪ४తͳٕज़ελοΫ Java 8 લఏ• طଘγεςϜͷ Java 11 ҠߦΛݕ౼• ඪ४తͳٕज़ελοΫͷԸܙڗड͍ͨ͠• Spring Boot ΞϓϦέʔγϣϯ & JDK Λ ߹ΘͤͯίϯςφԽͤ͞Δ͜ͱʹͨ͠
͜ͷޙͷ͓• ։ൃ• Ϗϧυ• σϓϩΠɾࢹ
։ൃ
API※࣮ࡍͷߏΛҰ෦؆ུԽ͍ͯ͠·͢όοΫΤϯυγεςϜͷ֓ཁ
։ൃڥͷඋ• ։ൃڥͷݸਓࠩΛ࠷খԽ͍ͨ͠• MySQL αʔόΛखݩͷڥʹ༻ҙ͢Δ• ଞαʔϏεͰ MySQL Λར༻͍ͯ͠Δ͕ɺ όʔδϣϯ͕ҟͳΓಘΔͨΊڞ༻͍͠• Datadog agent (ͷ DogStatsD) ͕ඞཁʹͳΔ• ϝτϦΫεͷࢹʹ Datadog Λར༻͍ͯ͠Δ
։ൃڥͷඋ• Vagrant / VirtualBox Λ༻͍Δखஈ͋Γ͏Δ• ϓϩϏδϣχϯάνϣοτδΧϯΧΧϧ• ࠷ۙ৽نʹ։ൃڥΛߏங͢Δͱ͖ʹ όʔδϣϯབྷΈͷτϥϒϧʹר͖ࠐ·Ε ͕ͪͳͷͰܟԕ͍ͨ͠
# docker-compose.ymlversion: '3.1'services:db:image: mysql:5.7.25environment:MYSQL_ROOT_PASSWORD: passwordMYSQL_DATABASE: main_dbvolumes:- ./tmp/mysql:/var/lib/mysqlports:- "13307:3306"dogstatsd:image: datadog/docker-dd-agent:12.7.5321-dogstatsdenvironment:API_KEY: ${DATADOG_API_KEY}ports:- “8125:8125/udp"
$ docker stack deploy \-c docker-compose.yml \stack-name$ docker stack rm stack-name
# application.ymlspring:profiles: local-devdatasource:url: jdbc:mysql://127.0.0.1:3306/main_dbusername: rootpassword: passwordmanagement.metrics.export.statsd.host: 127.0.0.1---spring:profiles: docker-devdatasource:url: jdbc:mysql://host.docker.internal:3306/main_dbusername: rootpassword: passwordmanagement.metrics.export.statsd.host: host.docker.internal
Ϗϧυ
Spring Boot ΞϓϦέʔγϣϯΛDocker Πϝʔδͱͯ͠Ϗϧυ͢Δ
Ұൠతͳ Spring Boot app ͷϏϧυ• Spring Boot Gradle plugin Λಋೖ͢Δ• ./gradlew build ͢Δ• fat jar ͕࡞ΒΕΔ
# DockerfileFROM adoptopenjdk/openjdk11:jdk-11.0.3_7COPY build/libs/spring-boot-app.jar /app/CMD ["java", "-jar", “/app/spring-boot-app.jar”]
Docker Πϝʔδͱͯ͠Ϗϧυ͢Δ• Docker Gradle plugin (Palantir) Λಋೖ͢Δ• ./gradlew build docker Ͱ Docker ΠϝʔδΛϏϧυ͢Δ• ./gradlew dockerPush Ͱ Docker ΠϝʔδΛϨδετϦʹ push ͢Δ
# build.gradleplugins {id 'org.springframework.boot'id 'com.palantir.docker'id 'net.researchgate.release'}// ...docker {name “$dockerNamespace/spring-boot-app:$version”copySpec.from(“build/libs/spring-boot-app—${version}.jar”).into('build/libs').rename { “spring-boot-app.jar” }}docker.dependsOn(build)// ...afterReleaseBuild.dependsOn(dockerPush)
Docker ϕʔεΠϝʔδΛબͿ
ϕʔεΠϝʔδɺԿΛબͿʁ• ༷ʑͳ৫͕͍ΖΜͳΠϝʔδΛఏڙ͍ͯͯ͠ɺͱͯ ΧΦε ଟ༷ੑʹΜͰ͍Δ • OS: Debian, Ubuntu, Alpine Linux, Oracle Linux,Amazon Linux, …• ৫: Docker official, Oracle, AdoptOpenJDK,Azul systems, …• ͦͷଞ: LTS ͷ༗ແ, JRE/JDK, …
ϕʔεΠϝʔδɺԿΛબͿʁ• AdoptOpenJDK ΛબΜͩ• “LTS ͕͋ͬͯ JDK ͷΠϝʔδͰ͋ΕԿͰΑ͔ͬͨɻࠓʹͯ͠ΈΕ Amazon Corretto ΛબΜͰΑ͔͔ͬͨ͠Εͳ͍ͱল͍ͯ͠Δ”• OS (Alpine Ͱͳ͘) Ubuntu Λબ, slim બͣ• slim Πϝʔδͩͱ jstack ͳͲ͕ೖ͍ͬͯͳ͍
λΠϜηʔϧͷϏϧυύΠϓϥΠϯ
Docker imageCodeDeploy artifactJargit push
ΑΓΑ͍ Docker ΠϝʔδΛ࡞Δ
ྑ࣭ͳใ͕ͪ͜Βʹ…• https://spring.io/guides/topicals/spring-boot-docker/• https://spring.io/guides/gs/spring-boot-docker/
ϨΠϠΛ͚͋͑ͯΔFROM adoptopenjdk/openjdk11:jdk-11.0.3_7ARG DEPENDENCY=build/dependencyCOPY ${DEPENDENCY}/BOOT-INF/lib /app/libCOPY ${DEPENDENCY}/META-INF /app/META-INFCOPY ${DEPENDENCY}/BOOT-INF/classes /appCMD ["java", "-cp", "app:app/lib/*", "foo.bar.EntryPoint"]
ϨΠϠΛ͚͋͑ͯΔ$ ./gradlew build$ mkdir build/dependency$ (cd build/dependency; jar -xf ../libs/spring-boot-app.jar)$ ./gradlew docker
ϨΠϠΛ͚͋͑ͯΔ• ґଘϥΠϒϥϦʹมߋ͕ੜ͡ͳ͍ݶΓɺ ΠϝʔδͷϏϧυߴԽ͕ظͰ͖Δ• JarLauncher Λܦ༝ͤͣ main Ϋϥε͔Β ࣮ߦ͢ΔͷͰɺىಈͷߴԽظͰ͖Δ
σϓϩΠɾࢹ
Docker imagestart.shCodeDeploy artifactcreate-deploymentdocker run
Spring Boot app ͷίϯςφΛಈ͔͢$ docker run -d —name spring-boot-app \-p 8080:8080 \-e SPRING_PROFILES_ACTIVE=production \-v /path/to/host/log:/path/to/container/log \spring-boot-app:X.Y.Z
# application.ymlspring.profiles: productionspring:profiles:include: common, aws, prd-db---spring.profiles: stagingspring:profiles:include: common, aws, stg-db---spring.profiles: localspring:profiles:include: common, local-db
ϗετͷϑΝΠϧγεςϜʹϩάग़ྗ͢Δ$ docker run -d —name spring-boot-app \-p 8080:8080 \-e SPRING_PROFILES_ACTIVE=production \-v /path/to/host/log:/path/to/container/log \spring-boot-app:X.Y.Z
Datadog ʹΑΔϝτϦΫεࢹDatadogagentVEQ
# build.gradledependencies {// ...implementation ‘org.springframework.boot:spring-boot-starter-actuator’implementation ‘io.micrometer:micrometer-registry-statsd’}# application.ymlmanagement:metrics:export:statsd:flavor: datadoghost: host.docker.internal# 18.03 ΑΓલͷ docker Λ͏߹ --network=host ͷΦϓγϣϯ͚ͯ# docker run ͱ͢Δɻ·ͨ host ͷࢦఆҎԼͷΑ͏ʹ 127.0.0.1 ͱ͢Δhost: 127.0.0.1
jstack ͨ͘͠ͳͬͨͱ͖ʁ$ docker exec spring-boot-app jstack 1
·ͱΊ
·ͱΊ• Java 11 + Spring Boot + Kotlin ͱ͍͏ߏͷ ৽نαʔϏεͷ։ൃͰ Docker Λ׆༻ͨ͠• ։ൃڥͷඋ• Docker Πϝʔδͷߏஙํ๏• σϓϩΠɾΞϓϦέʔγϣϯ࣮ߦํ๏