Share
mixi tech note #07
#技術書典12 に出典されたミクシィグループエンジニア有志による技術書です。
<< 目次 >>
1章:Elm + Haskell で作る Web アプリ with Bazel
2章:ガチャシステムで見る、マイクロサービスと整合性の話
3章:Cloud Build を使い倒そう!
4章:TIPSTAR の開発で学んだ Cloud Spanner Tips
5章:エンジニアリングマネジャー半年くらいやってみた
6章:Unleash を使った feature toggle 管理
<< TECH NOTE 一覧 >>
mixi tech note #01
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-01
mixi tech note #02
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-02
mixi tech note #03
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-03
mixi tech note #04
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-04
mixi tech note #05
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-05
mixi tech note #06
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-06
mixi tech note #07
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-07
MIXI TECH NOTE #08
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-08
XFLAG Tech Note Vol.01
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-01
XFLAG Tech Note vol.02
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-02
MIXI ENGINEERS PRO
Transcript
103 slides
-
·͕͖͑ ຊॻʮmixi tech note #07ʯɺϛΫγΟάϧʔϓʹॴଐ͢Δ༗ࢤୡʹΑͬͯࣥචɾ੍࡞͞Εͨ ٕज़ॻͰ͢ɻ࣮ࡍͷϓϩμΫτ։ൃͷݱͰ༻͞Εٕͨज़ͷɺʑͷۀͷΒɺݸਓతʹௐ ͨ͜ͱͳͲɺࢥ͍ࢥ͍ʹࣥච͍ͯ͠·͢ɻͦͷͨΊɺ֤ষͦΕͧΕͰ͍݁ͯ͠Δ༰ʹͳ͍ͬͯ ·͢ͷͰɺ͖ͳষ͔Β͖ͳॱ൪Ͱָ͓͠Έ͍ͩ͘͞ɻ ·ͨɺຊॻɺϛΫγΟάϧʔϓʹ͋Δٕज़తݟΞΠσΞΛੵۃతʹڞ༗ɾެ։͍ͯ͘͜͠ͱ ͰɺੈͷதʹΑΓྑ͍αʔϏε͕ҲΕग़͢͜ͱΛئͬͯץߦ͞Ε͍ͯ·͢ɻܝࡌ͞Ε͍ͯΔใɺ
ࣥචऀࣗͷڥͰݕূࣥ͠ච͞ΕͨͷͰ͢ͷͰɺ͝ࢀߟʹ͞ΕΔࡍɺࣗ͝ͷஅͱʹ͓ ͍ͯ͝׆༻͍ͩ͘͞ɻͳ͓ɺจষදݱʹ͖ͭ·ͯ͠ɺࣥචऀࣗͷݴ༿Ͱ͑ͨ͘ɺϑϥϯΫͳද ݱͱͳ͓ͬͯΓ·͢͜ͱ͝ཧղ͍͚ͨͩΕͱࢥ͍·͢ɻ גࣜձࣾϛΫγΟ CTO ࣨ DevRel άϧʔϓҰಉ ˗ຊॻʹؔ͢Δ͓͍߹Θͤઌ ɹ https://twitter.com/mixi_engineers ˗ϛΫγΟάϧʔϓʹ͍ͭͯ ɹ https://mixi.co.jp/ ˞ʠϛΫγΟʡ ɺ ʠmixiʡ ɺ ʠmixi ϩΰʡ ɺגࣜձࣾϛΫγΟͷඪ·ͨొඪͰ͢ɻ·ͨɺ֤ ࣾͷձ໊ࣾɺαʔϏεٴͼͷ໊শɺͦΕͧΕͷॴ༗͢Δඪ·ͨొඪͰ͢ɻ iii -
࣍ ·͕͖͑ iii ୈ 1 ষ Elm + Haskell Ͱ࡞Δ
Web ΞϓϦ with Bazel 1 1.1 ࡐɿऩೖάϥϑ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 ओཁٕज़ͷհ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Elm + Haskell + Bazel Ͱ࡞Δ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.4 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 17 2.1 ઃఆڥͱΨνϟϑϩʔͷఆٛ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.2 γʔέϯεਤͰߟ͑ͯΈΔ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.3 3 ͭͷ߹Խઓུ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.4 ϚΠΫϩαʔϏεͱ߹ੑͷ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.5 ͓ΘΓ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 29 3.1 ͡Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.2 Cloud Build Deep Dive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.3 Cloud Build Λͬͱศརʹ͏ํ๏ . . . . . . . . . . . . . . . . . . . . . . . . . 39 3.4 Cloud Build ͷίετΛઅ͢Δํ๏ . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.5 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 65 4.1 TIPSTAR ͷ։ൃͱ Google Cloud Spanner . . . . . . . . . . . . . . . . . . . . . 65 4.2 Cloud Spanner ώϯτू . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 4.4 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ͬͯΈͨ 77 5.1 ͡Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 5.2 ϛΫγΟʹ͓͚ΔϚωδϟʔɾEM . . . . . . . . . . . . . . . . . . . . . . . . . . 77 v -
࣍ 5.3 γεςϜ 2G ͱ . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 5.4 EM ͱͯ͠औΓΜͩ͜ͱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 5.5 ͜Ε͔ΒΓ͍ͨ͜ͱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 5.6 ·ͱΊ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 85 6.1 τϥϯΫϕʔε։ൃ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 6.2 Unleash ͱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 6.3 Unleash ͷಋೖ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 6.4 ܕ҆શʹ feature toggle Λཧ͢Δ . . . . . . . . . . . . . . . . . . . . . . . . . . 89 6.5 ϩʔΧϧͷΈͰҰ࣌తʹ feature toggle ΛΓସ͑Δ . . . . . . . . . . . . . . . . 91 6.6 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 ஶऀհ 93 vi -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel දͷ௨ΓɺElm ͱ Haskell Ͱ Web ΞϓϦέʔγϣϯ࡞͠·͢ɻաڈʹʮmixi tech note #02*1ʯʮElm + Haskell Ͱ࡞Δ Web ΞϓϦ (2019 ฤ)ʯͱ͍͏ͷΛدߘ͠·ͨ͠ɻաڈͷ ͷͱͷҧ͍ҎԼͷ௨ΓͰɺ༰ͱͯ͠΄΅ผͰ͢ɻ • Ϗϧυπʔϧͱͯ͠ Bazel Λಋೖ͠যΛͯ·͢ • GHC ͷόʔδϣϯΛݱࡏ࠷৽ͷ 9.2.1 ʹ͠·͢ʢաڈͷ 8.6.5ʣ • Elm ʹΑΔΞϓϦέʔγϣϯ։ൃʹ͍ͭͯେ෯ʹׂѪ͠·͢ 1.1 ࡐɿऩೖάϥϑ ࣗͷऩೖΛ࣍ͷΑ͏ʹάϥϑԽͯ͠දࣔͰ͖ΔΑ͏ͳ؆қతͳ Web ΞϓϦΛࡐͱ͠·͢*2ɻ *1 https://techbookfest.org/product/5256674994552832 *2 ྫͱͯ͠ࡌͤͨάϥϑͷऩೖචऀͷͷͰͳ͘దʹͰ্ͬͪ͛ͨσʔλͰ͢ɻ 1 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.2 ओཁٕज़ͷհ σʔλ JSON ͰϩʔΧϧʹอଘͯ͋͠Δͱ͠·͢ɻElm Ͱॻ͍ͨ Web ϑϩϯτϖʔδɺ όο ΫΤϯυ͔Β API Λհͯ͠σʔλΛड͚औΓάϥϑඳࣸ͠·͢ɻϑϩϯτଆ͔ΒೖྗΛड͚ͳ͍ ʢPOST ͢ΔΑ͏ͳ API ଘࡏ͠ͳ͍ʣͨΊɺWeb ΞϓϦͱ͓ͯ͠͠ΖΈʹ͚ܽ·͕͢ɺࠓճͷ ओϏϧυπʔϧͷ Bazel ͳͷͰ͝༰͍ࣻͩ͘͞ɻιʔείʔυ matsubara0507/salary-graph ͱ͍͏ϦϙδτϦ໊Ͱ GitHub ʹެ։͓͖ͯ͠·ͨ͠*3ɻ 1.2 ओཁٕज़ͷհ ຊߘͷओཁٕज़ͱͯ͠ɺόοΫΤϯυΛهड़͢ΔϓϩάϥϛϯάݴޠʮHaskellʯͱϑϩϯτΤϯ υΛهड़͢ΔϓϩάϥϛϯάݴޠʮElmʯ ɺͦͯ͜͠ΕΒΛϏϧυ͢ΔͨΊͷϏϧυπʔϧʮBazelʯ ͕͋Γ·͢ɻ͜ΕΒΛ؆୯ʹͰ͕͢հ͠·͢ɻ Haskell Haskell ࣍ͷΑ͏ͳಛΛ࣋ͭϓϩάϥϛϯάݴޠͰ͢ɻ • ڧྗͳ੩తܕ͚ʢܕϨϕϧϓϩάϥϛϯάͳͲՄೳʣ • ڧྗͳϝλϓϩάϥϛϯάʢTemplate Haskell ͳͲʣ • ԆධՁʢࣜར༻͢ΔλΠϛϯά·ͰධՁ͞Εͳ͍ʣ • ڧྗͳฒߦॲཧʢܰྔεϨουιϑτΣΞτϥϯβΫγϣϯϝϞϦͳͲʣ ·ͨɺͦͷσϑΝΫτελϯμʔυͳॲཧܥͱͯ͠ GHCʢGlasgow Haskell Compilerʣͱ͍͏ͷ Λ͍·͢ɻࠓճར༻͢Δ GHC 9.2.1 Ͱ࣍ͷΑ͏ͳػೳ͕Ճ͞Ε·ͨ͠*4ɻ • ϨίʔυܕͷϑΟʔϧυΞΫηεʹ . ه๏͕͑ΔΑ͏ʹͳͬͨ • ແͰރΕͨ GHC ֦ுΛ·ͱΊͨ GHC2021 ͱ͍͏ݴޠ֦ு͕Ճ͞Εͨ • ܕϨϕϧจࣈܕϨϕϧൺֱԋࢉࢠͷՃ • ͳͲͳͲ ಛʹɺ 1 ͭͷػೳ Haskeller ʹͱͬͯͪʹͬͨͱ͍͏Α͏ͳػೳͰ͢ɻHaskeller ͱϨίʔ υܕͷྺ࢙ʹ͍ͭͯ ʮHaskell Day 2021ʯ ͷ ʮHaskell ผݴޠʹͳΓ·ͨ͠ʕʕRecordDotSyntax ͱ NoFieldSelectorsʯͱ͍͏ൃද͕࠷ৄ͍͠ͷͰɺڵຯ͕͋ΔํൃදಈըΛࢼௌͯ͠Έͯͩ͘͞ ͍*5ɻ *3 https://github.com/matsubara0507/salary-graph *4 GHC9.2.1 ʹ͍ͭͯɺͩΊΆࢯͷʮGHC 9.2 ͷ৽ػೳͱɺGHC ͷಈ 2021ʯ͕ͱͯࢀߟʹͳΓ·͢ɻhttps: //zenn.dev/mod_poppo/articles/ghc-9-2-and-future *5 https://haskell.jp/haskell-day-2021/#timetable-fumieval 2 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ Elm Elm JavaScript τϥϯεύΠϧ͞ΕΔϓϩάϥϛϯάݴޠͰɺ࣍ͷΑ͏ͳಛΛ࣋ͪ·͢*6ɻ • The Elm Architecture ͱ͍͏ಠࣗͷύλʔϯΛ࣮͢ΔͨΊͷݴޠ • ΠϯλϑΣʔεܕΫϥεͷΑ͏ͳΞυϗοΫଟ૬ͷͨΊͷػೳͳ͍ • ύϥϝτϦοΫଟ૬ʢ͍ΘΏΔδΣωϦΫεʣ͋Δ • Haskell Ͱ࣮͞Ε͍ͯΔ Haskell ʹΠϯεύΠΞ͞Ε͔ͯɺͱ͍ͯۙߏจΛ࣋ͪ·͕͢ɺHaskell ͷΑ͏ͳଟछଟ༷ͳݴ ޠػೳ͋Γ·ͤΜɻThe Elm Architecture ͱ͍͏ύλʔϯͰ Single Page Application Λ࡞Δͨ Ί͚ͩʹಛԽͨ͠ϓϩάϥϛϯάݴޠͰ͢ɻ༨ஊͰ͕͢ɺHaskell ๊͕͍͑ͯͨʮϨίʔυܕʯ ͳ͍Α͏ʹσβΠϯ͞Ε͍ͯ·͢ɻ Bazel Bazel ࣍ͷΑ͏ͳಛΛ࣋ͭϏϧυπʔϧͰ͢*7ɻ • ϏϧυΛಠࣗͷαϯυϘοΫεڥͷதͰߦ͏ • ґଘؔΛ໌ه͢ΔͨΊΩϟογϡޮ͕ྑ͍ • Starlark ͱ͍͏ Python αϒηοτͳݴޠͰ֦ுՄೳ ·ͨɺ͍ΘΏΔϥΠϒϥϦͷΑ͏ͳͷΛ͏͜ͱͰɺ؆୯ʹ͞·͟·ͳϓϩάϥϜͷϏϧυς ετͷ࣮ߦΛಉ͡ΠϯλϑΣʔεͰߦ͏͜ͱ͕Ͱ͖·͢ɻϥΠϒϥϦʹɺͨͱ͑࣍ͷΑ͏ͳͷ ͕͋Γ·͢ɻ • bazelbuild/rules_docker : Docker ΠϝʔδͷϏϧυϓογϡͳͲ*8 • tweag/rules_haskell : Haskell ϓϩάϥϜͷϏϧυςετͳͲ*9 • matsubara0507/rules_elm : Elm ϓϩάϥϜͷϏϧυςετͳͲʢࣗ࡞ʣ *10 αʔυύʔςΟؚΊͯ͞·͟·ͳϥΠϒϥϦʢϧʔϧʣ͕͋Γ·͢ɻ 1.3 Elm + Haskell + Bazel Ͱ࡞Δ ͍Α͍ΑຊͰ͢ɻ·ͣɺΞϓϦέʔγϣϯΛ Bazel ͰϏϧυ͢ΔͨΊͷ४උΛ͠·͢ɻ *6 https://elm-lang.org/ *7 https://bazel.build/ *8 https://github.com/bazelbuild/rules_docker *9 https://github.com/tweag/rules_haskell *10 https://github.com/matsubara0507/rules_elm 3 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ Bazel ͷ४උ Bazel Ͱओʹ WORKSPACE ϑΝΠϧͱ BUILD ϑΝΠϧͱ͍͏ 2 छྨͷϑΝΠϧΛར༻͠ ·͢ɻWORKSPACE ϑΝΠϧɺϓϩδΣΫτຖʹҰͭ༻ҙ͢ΔϑΝΠϧͰϓϩδΣΫτͷϧʔ τʹஔ͖·͢ɻWORKSPACE ϑΝΠϧʹɺBazel ͷґଘϥΠϒϥϦʢϧʔϧʣΛهड़ͨ͠Γɺ Bazel Ͱར༻͢ΔπʔϧʢGHC ͳͲʣͷઃఆΛهड़ͨ͠Γ͠·͢ɻ·ͣɺHaskell ΛϏϧυ͢ ΔͨΊʹ rules_haskell Λར༻͢ΔͷͰɺWORKSPACE ϑΝΠϧʹͦͷ͜ͱΛهड़͠·͢ɻ workspace(name = "salary-graph") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "rules_haskell", strip_prefix = "rules_haskell-0.14", url = "https://github.com/tweag/rules_haskell/archive/refs/tags/v0.14.tar.gz", sha256 = "851e16edc7c33b977649d66f2f587071dde178a6e5bcfeca5fe9ebbe81924334", ) load("@rules_haskell//haskell:repositories.bzl", "rules_haskell_dependencies") rules_haskell_dependencies() load("@rules_haskell//haskell:toolchain.bzl", "rules_haskell_toolchains") rules_haskell_toolchains(version = "9.2.1") GHC 9.2.1 Λ͏ʹɺrules_haskell ͷ v0.14 Ҏ߱Λ͏ඞཁ͕͋Δʹҙ͍ͯͩ͘͠͞ɻ BUILD ϑΝΠϧϧʔϧʹΑΓ·͕͢ɺಠཱͨ͠σΟϨΫτϦຖʹஔ͖·͢ɻࠓճͷ߹ɺϓϩ δΣΫτϧʔτʹҰͭ͋ΕेͰ͢ɻ Haskell Λ Bazel ͰϏϧυ લड़ͨ͠௨Γɺ Haskell ϓϩάϥϜΛ Bazel ͰϏϧυ͢Δʹ tweag/rules_haskell Λ͏ͱྑ͍Ͱ ͠ΐ͏ɻrules_haskell Ͱɺ Haskell ϓϩδΣΫτ͕ґଘ͢Δ Haskell ύοέʔδΛ WORKSPACE ʹྻڍ͢Δඞཁ͕͋Γ·͢ɻΑΓݫີʹɺґଘύοέʔδ͕ґଘ͢Δύοέʔδ·Ͱ haskell_ca bal_library Λར༻ͯ͠ྻڍ͢Δඞཁ͕͋Γ·͕͢ɺ͜ΕΒΛେ෯ʹ؆ུԽ͢ΔͨΊͷϧʔϧͱ͠ ͯ stack_snapshot ͱ͍͏ͷ͕͋ΔͷͰɺࠓճ͜ΕΛ͍·͢ɻ load("@rules_haskell//haskell:cabal.bzl", "stack_snapshot") 4 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ stack_snapshot( name = "stackage", packages = [ "aeson", "base", "bytestring", ... ], snapshot = "lts-18.21", ) stack ͱ͍͏ͷ Haskell ͷϏϧυπʔϧ stack ͷ͜ͱΛࢦ͍ͯ͠·͢*11ɻstack ʹʮඞͣϏ ϧυͰ͖ΔύοέʔδͷόʔδϣϯͷΈ߹Θͤηοτʢsnapshotʣ ʯ͕ Stackage ͱ͍͏αΠτ Ͱཧ͞Ε͓ͯΓ*12ɺ͜ΕΛར༻͍ͯ͠ΔͷͰ͢ɻ͜͜Ͱ͕Ұͭ͋Γ·͢ɻlts-18.21 ͱ͍͏ snapshot GHC 8.10.7 ༻ͷͷͷͨΊɺࠓճ͍͍ͨ GHC 9.2.1 Ͱಈ࡞͠·ͤΜɻ೦ͳ͕ Βɺຊߘࣥච࣌ʹ GHC 9.2.1 ༻ͷ snapshot ·ͩͳ͍ͨΊɺࣗ࡞͢Δඞཁ͕͋Γ·͢ɻͦΕΛ stack-snapshot.yaml ͱ͍͏ϑΝΠϧ໊Ͱอଘ͠ɺstack_snapshot Λ࣍ͷΑ͏ʹॻ͖͑·͢ɻ stack_snapshot( name = "stackage", packages = [ ... ], local_snapshot = "//:stack-snapshot.yaml", ) ༨ஊͰ͕͢ɺStackage ʹ͋Δ snapshot ʹͳ͍ύοέʔδΛར༻͍ͨ͠߹ɺಉ༷ͷํ๏Λͱ Δඞཁ͕͋Γ·͢ɻͰ࣍ʹɺBUILD ϑΝΠϧଆΛهड़͠·͢ɻࠓճ࣍ͷΑ͏ͳσΟϨΫτϦߏ Λ࣋ͭϓϩδΣΫτΛఆ͍ͯ͠·͢ɻ / |- app | |- server | |- Main.hs : Haskell Ͱͷ Main ίʔυ |- src | |- ͦͷ΄͔ Haskell ιʔείʔυ |- BUILD.bazel |- stack-snapshot.yaml |- WORKSPACE *11 https://docs.haskellstack.org/ *12 https://www.stackage.org/ 5 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ rules_haskell ͰɺMain ίʔυΛϏϧυͯ͠όΠφϦΛੜ͢ΔͨΊͷ haskell_binary ϧʔ ϧͱʮͦͷ΄͔ Haskell ιʔείʔυʯΛύοέʔδͱͯ͠Ϗϧυ͢ΔͨΊͷ haskell_library ϧʔϧ͕͋Γ·͢ɻ load("@rules_haskell//haskell:defs.bzl", "haskell_library", "haskell_binary") haskell_library( name = "salary-graph-library", src_strip_prefix = "src", srcs = glob(["src/**/*.hs"]), deps = [ "@stackage//:aeson", "@stackage//:base", "@stackage//:bytestring", ... ], ) haskell_binary( name = "salary-graph", srcs = glob(["app/server/**/*.hs"]), deps = [ ":salary-graph-library", "@stackage//:base", "@stackage//:servant-server", "@stackage//:warp", ], ) ͜ΕͰɺbazel build //:salary-graph Ͱ Haskell ϓϩάϥϜͷϏϧυ͕Ͱ͖ΔΑ͏ʹͳΓ· ͨ͠ɻ ίϯύΠϧϑϥά Haskell ϓϩάϥϜΛϏϧυ͢Δͱ͖ʹίϯύΠϧϑϥάΛ͢͜ͱ͕ଟ͍Ͱ͢ɻrules_haskell ͷ߹ compiler_flags ҾͰࢦఆ͠·͢ɻ·ͨɺຖճྻڍ͢Δͷ͍ͨΜͰ͢ͷͰɺมʹ ͓ͯ͘͠ͱศརͰ͢ɻ GHC_FLAGS = [ "-Wall", "-Wcompat", "-optP-Wno-nonportable-include-path", "-DBAZEL_BUILD=1", "-XGHC2021", "-XDataKinds", "-XNoFieldSelectors", 6 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ "-XOverloadedRecordDot", "-XOverloadedStrings", ] haskell_library( name = "salary-graph-library", src_strip_prefix = "src", srcs = glob(["src/**/*.hs"]), deps = [ ... ], compiler_flags = GHC_FLAGS, ) haskell_binary( name = "salary-graph", srcs = glob(["app/server/**/*.hs"]), deps = [ ... ], compiler_flags = GHC_FLAGS, ) ύοέʔδόʔδϣϯΛ͢ CLI πʔϧΛ࡞Δࡍʹɺ--version ΦϓγϣϯͰόʔδϣϯΛද͍ࣔͨ͠߹͕͋Γ·͢ΑͶɻ Haskell ͷ΄͔ͷϏϧυπʔϧͷ߹ɺPaths Ϟδϡʔϧͱ͍͏ͷ͕࡞ΒΕͯɺઃఆϑΝΠϧʹ͋ ΔόʔδϣϯΛࢀরͰ͖·͢ɻ {-# LANGUAGE DuplicateRecordFields, MultiWayIf #-} module Main where import Paths_salary_graph (version) import Data.Version qualified as Version import System.Console.GetOpt import System.Environment (getArgs) main :: IO () main = do opts <- compilerOpts usage =<< getArgs if | opts.help -> putStrLn usage | opts.version -> putStrLn $ Version.showVersion version | otherwise -> runServer opts where usage = usageInfo "Usage: salary-graph [OPTION...]" options 7 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ runServer :: Options -> IO () runServer opts = ... -- ׂѪ data Options = Options { help :: Bool , version :: Bool } -- GetOpt ϞδϡʔϧʹΑΔίϚϯυϥΠϯҾͷύʔεׂѪ Paths_salary_graph ͱ͍͏ͷ͕ Paths ϞδϡʔϧͰ͢ɻ͔͠͠ɺ rules_haskell ͷ߹ Paths Ϟδϡʔϧ͕ੜ͞Ε·ͤΜɻͰ͢ͷͰɺStarlark Λॻ͍ͯಠࣗϧʔϧΛهड़ͪ͠Ό͍·͢ɻ͘ ͳΔͷͰಠࣗϧʔϧࣗମׂѪ͠·͢ʢϦϙδτϦͷ build/rules/haskell Լʹ͋ΔͷͰڵຯ ͷ͋Δਓࢀরͯ͠Έ͍ͯͩ͘͞ʣ ɻఆٛͨ͠ಠࣗϧʔϧ paths_module Λͬͯ Main ίʔυʹ Paths ϞδϡʔϧΛͯ͠Έ·͢ɻ load("//build/rules/haskell:def.bzl", "paths_module") paths_module( name = "paths_module", package = "salary-graph", version = "1.0.0", ) haskell_binary( name = "salary-graph", srcs = glob(["app/server/**/*.hs"]), deps = [ ":salary-graph-library", ":paths_module", # Ճ "@stackage//:base", "@stackage//:servant-server", "@stackage//:warp", ], compiler_flags = GHC_FLAGS, ) ϑΝΠϧͷຒΊࠐΈ ৄࡉׂѪ͠·͕͢ɺࠓճ Servant ͱ͍͏ύοέʔδΛར༻ͯ͠ Web όοΫΤϯυΛهड़ͯ͠ ͍·͢*13ɻServant API ఆٛΛܕͱͯ͠هड़Ͱ͖ΔಛΛ͍࣋ͬͯ·͢ɻ *13 https://docs.servant.dev/ 8 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ type API = Get ’[HTML] ByteString :<|> "api" :> SalaryAPI type SalaryAPI = "salaries" :> Capture "year" Year :> Get ’[JSON] [Salary] :<|> "appointments" :> Capture "year" Year :> Get ’[JSON] [Salary.Appointment] Get ’[HTML] ByteString ͷ෦ϧʔτͰ index.html ʹ૬͢ΔͷΛฦ͢ͱ͍͏ͷදݱ͠ ͍ͯΔܕͰ͢ɻࠓճɺ͜ͷ index.html ΛίϯύΠϧ࣌ʹຒΊࠐΜͰΈ·͢ɻϑΝΠϧΛίϯύΠ ϧ࣌ʹຒΊࠐΉʹ file-embed ύοέʔδ*14ͱ Template Haskell Λར༻͠·͢ɻ {-# LANGUAGE TemplateHaskell #-} import Data.FileEmbed (embedFile) indexHtml :: ByteString indexHtml = $(embedFile "static/index.html") લड़ͨ͠௨ΓɺBazel ґଘ͢ΔͷΛࡉ͔͘ྻڍ͢Δඞཁ͕͋Γ·͢ɻຒΊࠐΜͰ͍Δ static/index.html ྫ֎Ͱ͋Γ·ͤΜɻͰ͢ͷͰɺ࣍ͷΑ͏ʹ BUILD ϑΝΠϧΛॻ͖͑ Δඞཁ͕͋Γ·͢ɻ haskell_library( name = "salary-graph-library", src_strip_prefix = "src", srcs = glob(["src/**/*.hs"]), deps = [ ... ], extra_srcs = ["static/index.html"], # Ճ compiler_flags = GHC_FLAGS, ) Haskell ͔Β Elm ίʔυΛੜ ͓·͚Ͱ͕͢ɺ Haskell ͔Β Elm ͷίʔυΛੜ͢Δ͜ͱͰ࣮ͷҰ෦Λڞ༗͠·͢ɻHaskell ܕఆ͔ٛΒԿ͔Λࣗಈੜ͢Δͷ͕ಘҙͰ͢ɻͭ·ΓɺHaskell ͷܕఆ͔ٛΒ Elm ͷܕఆٛΛੜ *14 https://hackage.haskell.org/package/file-embed-0.0.15.0 9 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ ͨ͠ΓɺServant ʹΑΔ API ఆ͔ٛΒ API ϦΫΤετ͢Δ Elm ίʔυΛੜͨ͠ΓͰ͖·͢ɻ લऀΛ͢Δͷʹ elm-bridge ύοέʔδ*15ΛɺޙऀΛ͢Δͷʹ servant-elm ύοέʔδ*16Λར༻͠ ·͢ɻ Elm ͷܕఆٛΛੜ͢Δʹɺੜ͍ͨ͠ܕͰ elm-bridge ύοέʔδʹ͋ΔܕΫϥεͷΠϯελ ϯεΛఆٛ͢Δඞཁ͕͋Γ·͢ɻ͜Ε Template Haskell Λར༻͢Δ͜ͱͰɺ؆୯ʹΠϯελϯε ఆ͕ٛͰ͖·͢ɻ {-# LANGUAGE DerivingStrategies, DuplicateRecordFields, TemplateHaskell #-} module SalaryGraph.Salary where import Data.Aeson (FromJSON, ToJSON, ToJSONKey) import Elm.Derive import Web.HttpApiData (FromHttpApiData) newtype Year = Year Int deriving newtype (Show, Eq, Ord, FromJSON, ToJSON, ToJSONKey, FromHttpApiData) deriveElmDef defaultOptions ’’Year newtype Month = Month Int deriving newtype (Show, Eq, FromJSON, ToJSON) deriveElmDef defaultOptions ’’Month data Salary = Salary { year :: Year , month :: Month , gross :: Int , net :: Int } deriving (Show, Eq) deriveBoth defaultOptions ’’Salary data Appointment = Appointment { year :: Year , month :: Month , before :: Int , after :: Int } deriving (Show, Eq) deriveBoth defaultOptions ’’Appointment deriveElmDef ͱ deriveBoth ͷ෦͕ Template Haskell Λ׆༻ͨ͠ΠϯελϯεఆٛʹͳΓ ·͢ɻ༨ஊͰ͕࣮͢ɺ͜ͷίʔυ࠷ۙͷ GHC ػೳ͕ͦΕͳΓʹ͍ࠞͬͯ͟·͢ɻ *15 https://hackage.haskell.org/package/elm-bridge-0.8.0 *16 https://hackage.haskell.org/package/servant-elm-0.7.2 10 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ ಉҰ໊ͷϑΟʔϧυ ·ͣɺSalary ܕͱ Appointment ܕͷ྆ํʹಉҰ໊ͷϑΟʔϧυ͕͋Γ·͢ɻ͜ΕΒΛՄೳʹ͠ ͍ͯΔͷ͕ GHC 8.0 Ͱೖͬͨ DuplicateRecordFields ֦ுͱ GHC 9.2 Ͱೖͬͨ NoFieldSele ctors ֦ுͰ͢ɻৄࡉׂѪ͠·͕͢ɺ͜Εͱ GHC 9.2 ͔Βͷυοτه๏֦ுΛར༻͢Δ͜ͱͰɺ ΄͔ͷϨίʔυܕͷϑΟʔϧ໊໊ؔʹؾ݉Ͷͳࣗ͘વͳϑΟʔϧυ໊Λ͚Δ͜ͱ͕Ͱ͖·͢ɻ newtype ܕએݴ ·ͨɺderiving newtype ͱ͍͏ͷ GHC 8.2 Ͱೖͬͨ DerivingStrategies ֦ுͷػೳͰ ͢*17ɻHaskell ͷ newtype ܕએݴʮܕݕࠪ࣌ผͷܕͱͯ͠ѻ͍ɺ࣮ߦ࣌θϩίετͰಉҰͷ ܕͱͯ͠ػೳͯ͠΄͍͠ܕʯΛදݱͰ͖·͢ɻHaskell type ܕએݴΛ͏͜ͱͰܕʹผ໊Λ༩͑ Δ͜ͱ͕Ͱ͖·͕͢ɺ͜ͷ߹ܕݕࠪ࣌ʹ۠ผ͞ΕͣܕΫϥεͷΠϯελϯεڞ༗ͯ͠͠·͍· ͢ɻͭ·ΓɺԾʹ Year ܕͱ Month ܕʹ type ܕએݴΛར༻͢Δͱ deriveElmDef ͕Ͱ͖ͳ͍ͷͰ ͢ɻٯʹ newtype ܕએݴΛ͏ͱɺڞ༗ͯ͠΄͍͠ Int ܕͷܕΫϥεΠϯελϯεΛࣗͰఆٛ͠ ͢ඞཁ͕͋Γ·ͨ͠ɻͦ͜Ͱ DerivingStrategies Λ͏͜ͱͰɺ໌ࣔͨ͠ܕΫϥεͷΠϯελ ϯε͚ͩΛڞ༗Ͱ͖ΔͷͰ͢ɻ ؓٳ Elm ͷܕఆٛΛੜ͢ΔͨΊͷ४උ͕Ͱ͖ͨͷͰɺ࣮ࡍʹੜ͢ΔίʔυΛඳ͖·͢ɻ {-# LANGUAGE TypeApplications, TypeOperators #-} module Main where import Data.Maybe (fromMaybe, listToMaybe) import SalaryGraph.API (SalaryAPI) import SalaryGraph.Salary as Salary import Servant ((:>)) import Servant.Elm import System.Environment (getArgs) main :: IO () main = do dirPath <- fromMaybe "elm-src" . listToMaybe <$> getArgs generateElmModuleWith defElmOptions ["Generated", "SalaryAPI"] defElmImports dirPath [ DefineElm (Proxy @Salary), DefineElm (Proxy @Salary.Appointment) , DefineElm (Proxy @Salary.Year), DefineElm (Proxy @Salary.Month) ] (Proxy @("api" :> SalaryAPI)) *17 newtype ܕએݴͷΑΓৄ͍͠ղઆʹ͍ͭͯ Hiromi Ishii ࢯͷʮຊ͍͢͝ newtypeʯͱ͍͏εϥΠυ͕Θ͔Γ ͍͢Ͱ͢ɻhttps://speakerdeck.com/konn/ben-dang-hasugoi-newtype 11 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ ͜ΕΛ app/generate/Main.hs ͱ͠·͢ɻ͋ͱɺBUILD ϑΝΠϧʹϧʔϧΛهड़͠·͢ɻ haskell_binary( name = "generateElm", srcs = glob(["app/generate/**/*.hs"]), deps = [ ":salary-graph-library", "@stackage//:base", "@stackage//:elm-bridge", "@stackage//:servant-elm", "@stackage//:servant-server", ], compiler_flags = GHC_FLAGS, ) ͜ΕͰɺbazel run //:generateElm -- $(pwd)/elm-src Ͱ Haskell ίʔυ͔Β Elm ίʔυ Λ elm-src Լʹੜ͞Ε·͢ɻ Elm Λ Bazel ͰϏϧυ ࠷ޙʹɺElm Λ Bazel ͰϏϧυͯ͠Έ·͢ɻBazel Ͱ Elm ίʔυΛϏϧυ͢Δʹɺචऀ͕ࣗ࡞ ͍ͯ͠Δ matsubara0507/rules_elm Λ͏ͱྑ͍Ͱ͢ɻ·ͣɺWORKSPACE ϑΝΠϧʹར༻ ͢Δ Bazel ϥΠϒϥϦͷఆٛΛهड़͠·͢ɻ http_archive( name = "rules_elm", sha256 = "a9db7f55e3693ab94a60cbf602221095514aec6541253b21cc89f0ba1365d87c", url = "https://github.com/matsubara0507/rules_elm/releases/download/v1.0.0/rules_elm-v1.0.0.zip", ) load("@rules_elm//elm:repositories.bzl", rules_elm_repositories = "repositories") rules_elm_repositories() load("@rules_elm//elm:toolchain.bzl", rules_elm_toolchains = "toolchains") rules_elm_toolchains(version = "0.19.1") Elm ϓϩδΣΫτ elm.json ϑΝΠϧʹɺιʔείʔυ elm-src σΟϨΫτϦԼʹ͋Δͱ͠ ·͢ɻBUILD ϑΝΠϧʹ࣍ͷΑ͏ʹه͠·͢ɻ 12 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ load("@rules_elm//elm:def.bzl", "elm_dependencies", "elm_make") elm_dependencies( name = "deps", elm_json = "elm.json", ) elm_make( name = "mainjs", srcs = glob(["elm-src/**"]), elm_home = ":deps", elm_json = "elm.json", main = "elm-src/Main.elm", output = "static/javascript/main.js", ) ͜ͷఆ͕ٛ elm make elm-src/Main.elm --output=static/javascript/main.js ͱՁʹ ͳΓ·͢ɻੜͨ͠ main.js ɺindex.html ಉ༷ʹ Haskell ίʔυίϯύΠϧ࣌ʹຒΊࠐΈ͍ͨ Ͱ͢ΑͶɻͦ͜Ͱ͕Ұͭ͋Γ·͢ɻBazel Ͱੜͨ͠ main.js ͷύε͕Θ͔Βͳ͍Ͱ͢ɻͦ ͷΛղܾ͢ΔͨΊʹɺCPP ݴޠ֦ுʹΑΔίϯύΠϧ࣌มΛར༻͠·͢ɻ {-# LANGUAGE CPP, TemplateHaskell #-} import Data.FileEmbed (embedDir) import System.FilePath (takeDirectory) type API = Get ’[HTML] ByteString :<|> "static" :> Raw :<|> "api" :> SalaryAPI server :: Server API server = pure indexHtml :<|> serveDirectoryEmbedded $(embedDir (takeDirectory MAINJS_FILE)) :<|> getSalaries :<|> getAppointments MAINJS_FILE ͕ίϯύΠϧ࣌ʹஔ͖ΘΔมͰ͢ɻࠓճɺϑΝΠϧ୯ମͰͳ͘σΟϨΫτ ϦΛؙͬͱຒΊࠐΈ͍ͨͷͰ embedDir takeDirectory Λར༻͍ͯ͠·͢ɻMAINJS_FILE ͱஔ ͖͑ΔʢύεʣΛ͢ʹίϯύΠϧϑϥάΛར༻͠·͢ɻ haskell_library( name = "salary-graph-library", 13 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ src_strip_prefix = "src", srcs = glob(["src/**/*.hs"]), deps = [ ... ], extra_srcs = [ "static/index.html", ":mainjs", ], compiler_flags = ["-DMAINJS_FILE=\"$(execpath :mainjs)\""] + GHC_FLAGS, ) Bazel ͷཪٕʢʁʣͱͯ͠ɺ$(execpath :mainjs) ͱ͢Δ͜ͱͰ Bazel ʹΑͬͯੜͨ͠ϑΝΠ ϧͷύεΛϏϧυ࣌ʹग़͢͜ͱ͕Ͱ͖·͢ɻ·ͨɺ͜ΕͰ Haskell ͷϏϧυ͕ Elm ͷϏϧυʹґଘ ͢ΔΑ͏ʹͳͬͨͨΊɺbazel build //:salary-graph ͱ͢Δ͚ͩͰ྆ํͷϏϧυ͕࣮ߦ͞ΕΔ Α͏ʹͳΓ·ͨ͠*18ɻ ͓·͚ɿDocker ΠϝʔδͷϏϧυ ͓·͚ͱͯ͠ɺElm ͱ Haskell ͷϏϧυͷ΄͔ʹ Docker ΠϝʔδΛ࡞Δ෦ Bazel Ͱߦ͏͜ ͱͰɺ1 ίϚϯυͰ Docker Πϝʔδͷϓογϡ·ͰΛߦ͑ΔΑ͏ʹͯ͠Έ·͢ɻDocker Πϝʔδ ͷૢ࡞Λ Bazel Ͱߦ͏ʹ rules_docker Λ͏ͷͰɺWORKSPACE ϑΝΠϧʹͦͷ͜ͱΛه ͠·͢ɻ http_archive( name = "io_bazel_rules_docker", sha256 = "59536e6ae64359b716ba9c46c39183403b01eabfbd57578e84398b4829ca499a", strip_prefix = "rules_docker-0.22.0", url = "https://github.com/bazelbuild/rules_docker/releases/download/v0.22.0/rules_docker-v0.22.0.tar.gz", ) load("@io_bazel_rules_docker//repositories:repositories.bzl", container_repositories = "repositories") container_repositories() load("@io_bazel_rules_docker//repositories:deps.bzl", container_deps = "deps") container_deps() ࠓճϕʔεΠϝʔδͱͯ͠ɺචऀ͕ࣗ࡞ͯ͠ GitHub Container Registory ʹ͍͋͛ͯΔͷΛ ར༻͠·͢ɻϕʔεΠϝʔδͳͲɺBazel Ͱར༻͢Δ֎෦ͷ Docker Πϝʔδ container_pul *18 ͨͩ͠ɺHaskell ίʔυ͔Β Elm ίʔυΛੜ͢Δ෦ɺbazel run Ͱߦ͏ඞཁ͕͋ΔͨΊผͰ࣮ߦ͢Δඞཁ͕͋ Γ·͢ɻ 14 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.3 Elm + Haskell + Bazel Ͱ࡞Δ l ϧʔϧΛར༻ͯ͠ WORKSPACE ϑΝΠϧʹهड़͢Δඞཁ͕͋Γ·͢ɻ load("@io_bazel_rules_docker//container:container.bzl", "container_pull") container_pull( name = "ubuntu_for_haskell", tag = "18.04", registry = "ghcr.io", repository = "matsubara0507/ubuntu-for-haskell", ) ͋ͱ BUILD ϑΝΠϧʹΠϝʔδͷϏϧυͷઃఆͱϓογϡͷઃఆΛهड़͢Δ͚ͩͰ͢ɻϓο γϡઌචऀͷ GitHub Container Registory ʹͯ͋͠Γ·͢ɻ load("@rules_pkg//:pkg.bzl", "pkg_tar") load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") pkg_tar( name = "bin", srcs = [":salary-graph"], mode = "0755", package_dir = "/usr/local/bin", ) container_image( name = "image", base = "@ubuntu_for_haskell//image", tars = [":bin"], entrypoint = ["/usr/local/bin/salary-graph"], ) container_push( name = "push", format = "Docker", image = ":image", registry = "ghcr.io", repository = "matsubara0507/salary-graph", ) ͜ΕͰɺbazel run //:push ͱ͢Δ͚ͩͰ Elm ͱ Haskell ͷϏϧυ͔ΒΠϝʔδͷ࡞ɺϓο γϡ·ͰΛͬͯ͘Ε·͢*19ɻ *19 ͨͩ͠ɺ͜ͷίϚϯυΛ macOS Windows Ͱ࣮ߦ͢ΔͱɺLinux ͷΠϝʔδʹ macOS Windows ͷ࣮ߦϑΝ Πϧؚ͕·Εͯ͠·͍·͢ɻ͜ΕΛղܾ͢ΔʹΫϩείϯύΠϧ͕Ͱ͖Δඞཁ͕͋Γɺrules_haskell Ͱ·ͩ͏· ͘Ͱ͖·ͤΜɻ 15 -
ୈ 1 ষ Elm + Haskell Ͱ࡞Δ Web ΞϓϦ with
Bazel 1.4 ऴΘΓʹ 1.4 ऴΘΓʹ Bazel ෳͷϓϩάϥϛϯάݴޠͳͲ͕ࠞͬͯ͘͟ΔͱޮՌ͕ग़ͯ͘ΔϏϧυπʔϧͰ͢ɻैདྷ Ͱ͋ΕɺͦΕͧΕͷϓϩάϥϛϯάݴޠͷϏϧυπʔϧΛར༻͠ɺMakefile ͰΑ͠ͳʹͭͳ͗߹Θ ͤΔͷ͕ओྲྀͩͱࢥ͍·͢ɻMakefile ʹ͍ͭͯචऀ͋·ΓΒͳ͍ͷͰൺֱͰ͖·ͤΜɻ͔͠ ͠ Bazel Ͱ͋Εɺ ʢ໊ͷߴ͍ʣ֤ϓϩάϥϛϯάݴޠͷઃఆ͕ϥΠϒϥϦͱͯ͠ఏڙ͞Εͯͨ ΓɺPython ϥΠΫͳϓϩάϥϛϯάݴޠͰϓϩάϥϛϯάͷΑ͏ʹ֦ுͰ͖ͨΓͳͲͷར͕͋Γ ·͢ɻͪΖΜɺಠࣗͷαϯυϘοΫεڥʹΑΔϏϧυґଘؔΛ໌ࣔతʹཧ͢Δ͜ͱʹΑΔ ࠶ݱੑͷߴ͞େ͖ͳརͰ͢ɻͨͩܽ͠ͱͯ͠ɺBazel ͷใ·ͩগͳ͍ʢಛʹຊޠͰʣ ͨΊɺࣗͰΰϦΰϦͱ͍͡ΕΔਓ͕ඞཁ͔͠Ε·ͤΜɻ 16 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏ εͱ߹ੑͷ օ͞ΜΨνϟճ͍ͯ͠·͔͢ʁ ࢲຊݪߘࣥච࣌Ͱ͋Δ 2021 12
݄ 31 22 ࣌ 35 ɺ ࢝ΨνϟͰരࢮ͍ͯ͠·͢ɻ ΑΖ͓͘͠ئ͍͠·͢ɻ Ϣʔβʔͷઢ͔Βͷલ࠲͓͖ͯ͞ɺࠓճͷɺιʔγϟϧήʔϜͳͲͷΨνϟʹ͍ͭͯɺ ઃܭͱ࣮ʹ·ͭΘΔ߹ੑͷ͓Ͱ͢ɻ 2.1 ઃఆڥͱΨνϟϑϩʔͷఆٛ ઃܭͱ࣮ʹ·ͭΘΔ߹ੑͷ͓ΛਐΊ͍ͯ͘ʹ͋ͨΓɺ·ͣࠓճઃఆͨ͠ɺΨνϟγεςϜ͕ ͔͍ͬͬͯΔϓϩμΫτʹ͍ͭͯհ͠·͢ɻ ؆୯ͳߏਤΛ ਤ 2.1 ʹࣔ͠·͢ɻͳ͓ɺෛՙࢄԽɺ ϩάͷӬଓԽͷ෦దؚٓ·Ε ͍ͯΔͷͱ͠·͢ɻ 17 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.1 ઃఆڥͱΨνϟϑϩʔͷఆٛ ਤ 2.1: ઃఆڥͷΞʔΩςΫνϟਤ ͨΒόοΫΤϯυͷొਓ͕ଟ͘ͳ͍ʁ
ͱ͍͏ͷ͕ݟͨͷୈҰҹͰ͋Δͱࢥ͍·͢ɻ҆ ৺͍ͯͩ͘͠͞ɻ͜͜ͰऔΓѻ͏ͷɺιʔγϟϧήʔϜαʔϏεͱࢿܾۚࡁαʔϏεͷ͚̎ͭͩ Ͱ͢ɻ 18 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.2 γʔέϯεਤͰߟ͑ͯΈΔ ߏਤΛհͨ͠ͱ͜ΖͰɺ࣍ʹࠓճऔΓѻ͏Ψνϟͷ۩ମతͳྲྀΕΛઃఆ͠·͢ɻ 1. ΨνϟͰେരࢮͨ͠ E
͞Μɺ·ͣ՝ۚॲཧΛߦ͍ɺΨνϟͷͨΊͷήʔϜࢿ࢈Λ֫ ಘ͠·͢ 2. ήʔϜࢿ࢈Λ֫ಘͨ͠ E ͞Μɺ10 ࿈ΨνϟΛҾ͖ɺ͓ͯͷظؒݶఆΩϟϥΫλΛ֫ ಘ͠·͢ɻ 3. ظؒݶఆΩϟϥΫλΛ֫ಘ͠ӻʹೖͬͨ E ͞Μ͕ϗʔϜը໘ʹΔͱɺ ʮಛఆ݅ͷΩϟϥΫ λͷऔಘ͕نఆΛ͑ͨͷͰϛογϣϯୡϘʔφεΛड͚औΔ͜ͱ͕Ͱ͖Δʯͱ͍͏ϔο μ௨Λड͚औΓ·͢ɻ ͜ͷ͋ͱ E ͞ΜΩΩͰϛογϣϯใुड͚औΓը໘͍͖·ͨ͠ɻԿͳΒ͏ 30 ࿈͘Β ͍ΨνϟΛճ͠·͢ɻճ͢ͷͰɺͥͻҾ͔͍͖͍ͤͯͨͩͨͰ͢ɻ 2.2 γʔέϯεਤͰߟ͑ͯΈΔ લઅͰΨνϟϑϩʔΛఆٛͰ͖ͨͱ͜ΖͰɺ࣍ʹ͜ͷΨνϟͷྲྀΕΛγʔέϯεਤͰղऍͯ͠Έ ·͢ɻ 19 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.2 γʔέϯεਤͰߟ͑ͯΈΔ ՝ۚϑϩʔ ·ͣ՝ۚϑϩʔ Λ ਤ
2.2 Ͱࣔ͠·͢ɻήʔϜͷΫϥΠΞϯτը໘͔ΒɺࢿܾۚࡁαʔϏεͷܾ ࡁը໘ભҠɺܾࡁͰ͖ΕήʔϜࢿ࢈͕ߋ৽͞ΕΫϥΠΞϯτը໘ʹө͞ΕΔɺͱ͍͏ྲྀΕ͕ ֬ೝͰ͖Δͱࢥ͍·͢ɻ ਤ 2.2: ՝ۚϑϩʔ: γʔέϯεਤ 20 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.2 γʔέϯεਤͰߟ͑ͯΈΔ Ψνϟϑϩʔ ࣍ʹΨνϟϑϩʔͪ͜Β ਤ 2.3ɻ՝ۚͷγʔέϯεਤʹൺΔͱɺ͔ͳΓఔ͕গͳ͘ײ͡Δͷ
Ͱͳ͍Ͱ͠ΐ͏͔ʁ ҙͯ͠΄͍͠ͷ͕ɺ PublishPlayGachaEvent ͱ͍͏෦Ͱ͢ɻ͜ͷ෦Ͱ Google Cloud Pub/Sub *1 ͷΑ͏ͳϝοηʔδϯάαʔϏεΛ༻͍ͯɺΨνϟΛҾ͍ͨ͜ͱͱͦͷ݁ՌΛϛογϣ ϯॲཧϫʔΧʹ͚͍͛ͭͯ·͢ɻͭ·Γɺ ϛογϣϯॲཧͷ݁Ռʹ͍ͭͯɺΨνϟϑϩʔͰऔ ΓѻΘͳ͍ɺͱ͍͏͜ͱΛҙຯ͍ͯ͠·͢ ɻ ਤ 2.3: Ψνϟϑϩʔ: γʔέϯεਤ *1 https://cloud.google.com/pubsub 21 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.2 γʔέϯεਤͰߟ͑ͯΈΔ ϛογϣϯॲཧϑϩʔ ࠷ޙʹϛογϣϯॲཧϑϩʔʹ͍ͭͯ ਤ 2.4
Ͱࣔ͠·͢ɻϛογϣϯॲཧϑϩʔ͜Ε·Ͱͷϑ ϩʔͱҟͳΓɺΫϥΠΞϯτ͔ΒͷϦΫΤετىҼͰಈ͘Θ͚Ͱͳ͘ɺΞϓϦαʔό͔Βͷϝο ηʔδϯάͰಈ͕ͪ͘ΐͬͱҧ͍·͢ɻ ਤ 2.4: ϛογϣϯॲཧϑϩʔ: γʔέϯεਤ 22 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.3 3 ͭͷ߹Խઓུ 2.3 3 ͭͷ߹Խઓུ
લষ·ͰΨνϟϑϩʔͷॲཧͷྲྀΕΛ 1. ՝ۚॲཧ 2. ΨνϟΛҾ͘ॲཧ 3. ϛογϣϯͷॲཧ ͷ 3 ͭʹׂͯ͠հ͖ͯ͠·ͨ͠ɻ ͜ͷ 3 ͭͦΕͧΕɺ (Ϣʔβʔઢతʹ / αʔϏεతʹ) ݪࢠతͳ୯Ґͱͯ͠ѻΘΕ͍ͯ·͢ *2ɻ͓ͦͯ͠͠Ζ͍͜ͱʹɺͦΕͧΕͰߦ͍ͬͯΔ୯ҐͷҰ؏ੑΛอͭͨΊͷ߹Խઓུ͕ҟͳΓ ·͢ɻ *3 ࣄલʹͦΕΒʹͦΕͬΆ͍ݴ༿ͰλΠτϧΛ͚ͭΔͱ͢Εɺ࣍ͷΑ͏ͳܗʹͳΓ·͢ɻ • TCC ͳ ࢄτϥϯβΫγϣϯ (՝ۚॲཧ) • DB ͱ ACID τϥϯβΫγϣϯ (Ψνϟॲཧ) • ݁Ռ߹ͳσʔλߋ৽ͷಛघύλʔϯ (ϛογϣϯॲཧ) ͔͜͜Βɺ͜ΕΒͷ 3 ͭͷ߹Խઓུʹ͍ͭͯհ͍͖ͯ͠·͢ɻ *2 ϢʔβʔαʔϏεͷશମ૾͔ΒӅณ͞Ε͍ͯΔ෦ΛؚΜͩɺݫີͳݪࢠ୯ҐͰͳ͍Ͱ͢ɻ *3 ͜ͷઓུ͕ͦΕͧΕҟͳΔͷɺͦ͏͍͏հΛ͢ΔͨΊͰɺඞͣΨνϟϑϩʔΛ࣮͢Δͱ͖ʹ͜ͷܗࣜʹै͑ɺ ͱ͍͏ͷͰͳ͍Ͱ͢ͷͰ͔͋͠Βͣɻ 23 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.3 3 ͭͷ߹Խઓུ TCC ͳࢄτϥϯβΫγϣϯ ·ͣ
՝ۚॲཧͰ͋Δɺ TCC (Try Confirm Cancel pattern) ͳࢄτϥϯβΫγϣϯʹ͍ͭͯ հ͍͖ͯ͠·͢ɻࢄτϥϯβΫγϣϯͱɺಛʹϚΠΫϩαʔϏεͷจ຺Ͱग़ͯ͘Δɺෳͷ αʔϏεͰσʔλͷ߹ੑΛอͭͨΊͷઓུΛࢦ͍ͯ͠·͢ɻTCC ͦͷதͷҰͭͰɺ֤αʔϏε Ͱσʔλͷߋ৽ॲཧΛɺ Try Phase ͱ Confirm / Cancel Phase ͱ͍͏ɺ2 ஈ֊ͷॲཧʹ͚ͯߦ ͏ύλʔϯʹͳΓ·͢ɻ Try Phase σʔλߋ৽Ͱ͋Δ͜ͱΛอূ͢ΔϑΣʔζɻ ܾࡁॲཧͰ͋Εɺݱࡏͷߴ͔ΒܾࡁֹΛࠩ͠Ҿ͘͜ͱ͕Ͱ͖Δ͜ͱΛ֬ೝ͠ɺͦͷঢ়ଶΛ ֬อ͢Δ ஈ֊Ͱ͢ɻ ҙ͢Δͱͯ͠ɺTry Phase Confirm / Cancel Phase ͕ݺͼग़͞ΕΔ·Ͱ֬อͨ͠ όοϑΝΛख์͞ͳ͍͜ͱΛอূ͠ͳ͚ΕͳΒͳ͍ɺͱ͍͏Ͱ͢ɻͭ·Γ Try Phase Ͱ 10 ສԁͷߴ͔Β 9 ສ ֬อͨ͠߹ɺͦͷޱ࠲͔Β͞Βʹ 2 ສԁҾ͖ग़ͤͳ͍Α͏ʹ͠ͳ ͚Ε͍͚·ͤΜɻ Confirm / Cancel Phase Try Phase Ͱ֬อͨ͠όοϑΝΛ։์͢ΔϑΣʔζɻ ܾࡁॲཧͰ͋ΕɺCancel ͷͱ͖֬อֹ͍ͯͨۚ͠Λ࠶ͼҾ͖ग़͠Մೳʹ͠ɺ Confirm ͷ ߹Ͱ͋Εɺݱࡏͷߴ͔Β֬อֹ͍ͯͨۚ͠Λࠩ͠Ҿ͖·͢ɻ ҙ͢Δͱͯ͠ɺCancel / Confirm Phase ࣗମʹΤϥʔى͜Γ͏Δɺͱ͍͏ళͰ͢ɻ ͭ·Γ Try Phase Ͱ Cancel / Confirm Phase ͕ ࣮ߦͰ͖Δ ͜ͱΛอূ͓ͯ͠Γɺޭ͢ Δ ͜ͱΛอূ͍ͯ͠ΔΘ͚Ͱͳ͍ɺͱ͍͏͜ͱͰ͢ɻͰ͢ͷͰɺ Cancel / Confirm Phase ͕ࣦഊͨ͠ͱ͖ʹɺԿΒ͔ͷํ๏ͰϦτϥΠ͢ΔػߏΛ༻ҙ͢Δඞཁ͕͋Γ·͢ɻ ՝ۚॲཧͰɺιʔγϟϧήʔϜαʔϏε͚ͩͰͳ͘ɺࢿܾۚࡁαʔϏεΛ·͍ͨͩॲཧʹͳͬ ͍ͯ·͢ (ʮ2.1 ઃఆڥͱΨνϟϑϩʔͷఆٛʯ > ʮ՝ۚϑϩʔʯ) ɻΑͬͯɺݱ͚ۚͩҾ͖ԼΖ ͞ΕͯɺήʔϜࢿ࢈͕૿͑ͳ͍ɺͱ͍͏Α͏ͳࣗମ͕ى͜͞ͳ͍ͨΊʹࢄτϥϯβΫγϣϯͷ TCC ༗ޮͳखஈͱݴ͑·͢ɻ ͨͩ͠ TCC Λ࣮͢ΔʹɺجຊతʹͦΕͧΕͷαʔϏεͰ TCC ύλʔϯΛ࣮Ͱ͖͍ͯΔ͜ ͱ͕ඞཁͰ͋Γɺͦ͏Ͱͳ͍߹ʹ TCC ύλʔϯΛԠ༻ͨ͠ผͷॲཧ͕ඞཁʹͳΓ·͢ *4ɻ *4 ͨͩ͠ࠓճͷύλʔϯͰɺࢿܾۚࡁαʔϏε͕ TCC Λ࣮ͯ͠ͳ͘ͱɺΞϓϦαʔό͚ͩ TCC ͕࣮Ͱ͖͍ͯ ΕɺࢿܾۚࡁαʔϏεͷ Succeed / Failed ͰΞϓϦαʔϏεͷ Confirm / Cancel Λ͢Εྑ͍ͷͰͳ͍Ͱ ͢ɻ 24 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.3 3 ͭͷ߹Խઓུ DB ͱ ACID
τϥϯβΫγϣϯ ଓ͍ͯɺΨνϟΛҾ͘ॲཧͰ͋Δɺ DB ͱ ACID τϥϯβΫγϣϯʹ͍ͭͯհ͍͖ͯ͠·͢ɻ ACID ͱɺAtomicityɺConsistencyɺIsolationɺDurability ͷ಄จࣈΛฒུͨޠʹͳΓ·͢ɻͭ ·Γ ACID τϥϯβΫγϣϯͱɺ ACID ͳੑ࣭Λຬͨ͢τϥϯβΫγϣϯͰ͢ɻ Atomicity (ݪࢠੑ) τϥϯβΫγϣϯͰͬͨ͘͘୯Ґͷ࣮ߦ͕ɺ࣮ߦ͞ΕΔ / ͞Εͳ͍ͷ 2 ΛऔΔ͜ͱɻ·ͨ ͦͷ్தܦաΛ֎෦͔ΒࢀরͰ͖ͳ͍͞·Λࣔ͠·͢ɻ Consistency (Ұ؏ੑ) τϥϯβΫγϣϯͷલதޙͰυϝΠϯͷෆม݅Λຬͨ͢͜ͱɻ Isolation (ಠཱੑ) τϥϯβΫγϣϯॲཧͷग़དྷࣄɺ΄͔ͷಡΈࠐΈɺॻ͖ࠐΈʹରͯ͠ӨڹΛٴ͞ͳ͍͜ ͱɻݴ͍͑Εɺ్தܦաΛ֎෦͔Βࢀর͞Εͳ͍͜ͱΛࣔ͠·͢ɻ Durability (Ӭଓੑ) τϥϯβΫγϣϯͷޙͷ݁Ռ͕อ࣋͞ΕΔ͜ͱɻ ͜͜ͰɺࢄτϥϯαΫγϣϯ ACID Ͱͳ͍ͷʁɺͱ͍͏͕ٙग़ͯ͘Δͱࢥ͍·͢ɻ݁ ͔Βߦͬͯ͠·͏ͱɺ೦ͳ͕ΒɺࢄτϥϯβΫγϣϯ ACID Ͱ͋Γ·ͤΜ *5 ɻ ͨͱ͑Ұͭલͷ՝ۚॲཧͰɺܾࡁ DB ͷ Confirm ॲཧͱΞϓϦέʔγϣϯ DB ͷ Confirm ॲཧ͍͘Β͔ͷλΠϜϥά͕ੜ͡·͢ɻͦͷͨΊɺ͜ͷॠؒʹࢿܾۚࡁαʔϏεͷߴͱιʔγϟ ϧήʔϜαʔϏεͷήʔϜࢿ࢈௰᧒͕߹Θͳ͍ঢ়ଶʹͳ͍ͬͯ·͢ɻ(TCC ɺ͜ͷঢ়ଶͰࢿۚ ܾࡁαʔϏε͔ΒࢿۚΛԼΖͤͳ͘͢ΔηʔϑςΟωοτΛு͍ͬͯ·͢ɻ) ՝ۚॲཧͷ͓͖ͯ͞ΨνϟͷτϥϯβΫγϣϯʹΔͱɺPostgreSQL *6 Google Cloud Spanner *7 ͰɺಉҰ DB ͷ ACID ͳτϥϯβΫγϣϯΛαϙʔτ͍ͯ͠·͢ɻΨνϟΛҾ͘ ॲཧͰɺσʔλͷૢ࡞ιʔγϟϧήʔϜαʔϏεʹด͓ͯ͡ΓɺDB ͱͯ͠ΞϓϦέʔγϣϯ DB ͷΈΛ͍ͬͯΔͨΊɺACID ͳτϥϯβΫγϣϯΛద༻Ͱ͖·͢ɻ ·ͨଟ͘ͷ DB Ͱ τϥϯβΫγϣϯॲཧ͕ࣦഊͨ͠ͱ͖ͷ (ςʔϒϧͷσʔλʹ͍ͭͯͷ) ϩʔϧόοΫ͕࣮͞Ε͓ͯΓ *8 ɺॲཧࣦഊͷͱ͖ͷॲཧΛ؆୯ʹ࣮Ͱ͖·͢ɻۙͷ DB ͔ ͍͜͠Ͱ͢Ͷɻ *5 ࢄτϥϯβΫγϣϯ͕ৗʹ ACID τϥϯβΫγϣϯͰͳ͍ূ໌ʹ͍ͭͯɺCAP ఆཧΛࢀর͍ͯͩ͘͠͞ *6 https://www.postgresql.org *7 https://cloud.google.com/spanner *8 https://cloud.google.com/spanner/docs/transactions 25 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.3 3 ͭͷ߹Խઓུ ݁Ռ߹ͳσʔλߋ৽ͷಛघύλʔϯ ࠷ޙʹϛογϣϯͷॲཧͰ͋Δɺ݁Ռ߹ͳσʔλߋ৽ͷಛघύλʔϯΛհ͠·͢ɻ݁Ռ߹ɺ ͱ
“࠷ऴతʹσʔλҰ؏ੑΛ࣋ͬͯߋ৽͞ΕΔ” ͱ͍͏ಛੑΛࢦ͠·͢ɻ ࠓճͷϛογϣϯॲཧɺతʹݴͬͯ͠·͑ɺΨνϟͷ݁Ռ͕ग़͔ͯΒ ͠Βͯ͘͠ ϛο γϣϯσʔλͷߋ৽͕ߦΘΕ·͢ɻ͞Βʹ͓͠Ζ͍͜ͱʹɺԾʹϛογϣϯॲཧ͕ࣦഊͨ͠ͱͯ͠ Ψνϟ݁ՌΛϩʔϧόοΫ͢Δػߏ͕༻ҙ͞Ε͍ͯ·ͤΜɻ গͳ͘ͱҟৗܥΛߟ͑ΕɺϛογϣϯσʔλͱΨνϟσʔλ݁Ռ߹Ͱͳ͍ͷͰʁɺͱ ࢥ͏͔͠Ε·ͤΜɻ͔͠͠ཧ͢ΔͱɺυϝΠϯͷࣄલ/ࣄޙ/ෆม͕݅ཧతʹਖ਼͘͠ཏੑ ͕͋Δ߹ʹɺ͜ͷॲཧ݁Ռ߹Λอͭ͜ͱ͕Ͱ͖͍ͯ·͢ɻಛघͳΛڍ͛Δͱ͢Εɺϛο γϣϯॲཧͷޭ / ࣦഊʹ͔͔ΘΒͣɺઌʹΨνϟॲཧΛ֬ఆ͍ͤͯͯ͞ɺϛογϣϯॲཧ͕ࣦഊ͠ ͯΨνϟσʔλΛϩʔϧόοΫ͠ͳ͍ɺͱ͍͏Ͱ͢ɻ ද 2.1: ϛογϣϯσʔλͱΨνϟσʔλͷ߹ԽରԠ Ψνϟ\ϛογϣϯ ޭ ࣦഊ ޭ ਖ਼ৗܥ ϛογϣϯॲཧϫʔΧࣦഊ࣌ʹϦτϥΠ͢Δ ࣦഊ ϛογϣϯॲཧϫʔΧݺͼग़͞Εͳ͍ ϛογϣϯॲཧϫʔΧݺͼग़͞Εͳ͍ ͜͜Ͱαʔό࣮͔ΒΕͯɺαʔϏεશମͷࢹΛ͛·͢ɻ ԾʹݱۚࢉͰ 1000 ສԁ / 1 ࣌ؒചΓ্͛ΔΠϕϯτΨνϟظؒதʹɺϛογϣϯॲཧͷ࣮͕ Կ͔͠Βࣦഊ͢ΔΠϯγσϯτ͕ൃੜͨ࣌͠ɺҰॹʹΨνϟҾ͚ͳ͘ͳΔ࣮ͩͬͨͱ͠·͢ɻ͜ ͷΠϯγσϯτରԠʹ 2 ͔͔࣌ؒͬͨͱ͢Δͱɺ୯७ܭࢉͰ 2000 ສଛࣦΛੜΉΘ͚Ͱ͢ *9ɻٯʹ ϛογϣϯॲཧ͕Ψνϟॲཧʹରͯ͠͞Ε͍ͯΕɺোൣғΛϛογϣϯʹऩΊΔ͜ͱ͕Ͱ ͖·͢ɻ࣮ͦͯ֘͠Λमਖ਼͠ϛογϣϯॲཧΛϦτϥΠ͢Ε ݁Ռతʹ Ϣʔβʔਖ਼͍͠σʔ λөΛߦ͏͜ͱ͕Ͱ͖·͢ *10ɻ ݴ͍͑ΕɺΨνϟͱϛογϣϯͷΑ͏ͳυϝΠϯʹ͞Εͨσʔλͷ߹ԽରԠΛ͢Δͱ ͖ɺͪ͜Βͷύλʔϯͷ࣮Λߦ͏͜ͱͰো࣌ͷӨڹൣғΛ͑Δ͜ͱ͕ݟࠐΊ·͢ɻ *9 ͍ͣΕʹͤΑൃੜ͢Δɺϛογϣϯॲཧ࣮ࣦഊʹ·ͭΘΔӡӦͷෆ৴ײ͔Βൃੜ͢Δଛࣦআ͖·͢ *10 ͨͩ͠ɺͷϛογϣϯॲཧʹႈੑ͕ͳ͔ͬͨΓشൃੑσʔλʹґଘ͍ͯͨ͠Γ͢Δ߹ʜ 26 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.3 3 ͭͷ߹Խઓུ ˙ίϥϜ: αʔϏεͷ༷ఆٛͱ݁Ռ߹ͷ (
͜͜·Ͱॻ͍͓͍ͯͯඇৗʹਃ͠༁ͳ͍ͱ͜ΖͰ͕͢ ) ͜ΕαʔϏεͱը໘ઃܭʹΑͬͯ ઃܭ͕ڐ͞Εͳ͍ύλʔϯ ʹͳΓ·͢ɻ ͨͱ͑࣍ͷΑ͏ͳը໘ઃܭɺΫϥΠΞϯτઃܭΛ͍ͯ͠Δ߹ɺ݁Ռ߹ͳσʔλߋ৽ෆ ͖Ͱ͢ɻ • Ψνϟը໘ͷԣʹϛογϣϯୡ֬ೝը໘͕͋Δ • ϗʔϜը໘ϛογϣϯୡը໘ͷσʔλΛ࠶औಘ͢ΔํࣜʹɺPush ܕͷΞϓϩʔν (e.g. Web socket or ΠϕϯτϦεφ) ͔ɺϙʔϦϯάͳΞϓϩʔνΛऔ͍ͬͯͳ͍ ͨͩ͠ڧҾͳಀ͛ಓͱͯ͠ɺϛογϣϯॲཧͷਖ਼ৗܥॲཧ͚ͩΨνϟॲཧʹؚΊΔ͜ͱͰɺ্ ͷཁ݅Ͱ࣮Ͱ͖ΔՄೳੑ͋Γ·͢ɻ ਤ 2.5: Ψνϟϑϩʔ with ϛογϣϯॲཧ (ਖ਼ৗܥ): γʔέϯεਤ 27 -
ୈ 2 ষ ΨνϟγεςϜͰݟΔɺϚΠΫϩαʔϏεͱ߹ੑͷ 2.4 ϚΠΫϩαʔϏεͱ߹ੑͷ 2.4 ϚΠΫϩαʔϏεͱ߹ੑͷ ͜͜·ͰϚΠΫϩαʔϏεͱ͍͏୯ޠ͕Ұͭग़͖͍ͯͯͳ͍ͷͰɺ͜ͷࢠͷΛ͠·͢ɻϚΠ ΫϩαʔϏεͱɺϏδωεཁ݅ʹ͚ͯখ͞ͳαʔϏεΛ࡞Γɺͦͷू߹ͱͯ͠ҰͭͷΞϓϦ
έʔγϣϯ (e.g. ιʔγϟϧήʔϜ) Λߏங͢Δઃܭख๏Ͱ͢ɻରԠ͢Δ༻ޠͱͯ͠ ϞϊϦγοΫ (monolithic) ͱ͍͏ͷ͕͋Γɺ͜ΕΞϓϦέʔγϣϯશମΛҰͭͷαʔϏεͰදݱ͢Δɺͱ͍͏ ઃܭख๏Ͱ͢ɻ ࠓճͷઃఆڥɺࢿܾۚࡁαʔϏεɺ ιʔγϟϧήʔϜͷϝΠϯॲཧαʔϏεɺ ιʔγϟϧ ήʔϜͷϛογϣϯॲཧαʔϏεɺ ΞΧϯτͷೝূ/ೝՄαʔϏε ʹ͔Ε͍ͯΔͱ͍͏ͰϚΠ ΫϩαʔϏεدΓͷ࣮Λ͍ͯ͠·͢ɻ͜Ε͕ϞϊϦγοΫͰ͋Εશ෦ͻͬ͘ΔΊͯɺ͑ʔ͍ɺͱ ҰͭͷαʔόΞϓϦέʔγϣϯʹ͔ͬΔײ͡ʹͳΓ·͢ɻ ࠓ·Ͱ্͖͛ͯͨ 3 ͭͷ߹ੑͷͰɺҰͭͷαʔϏεͰ݁͢Δͷ (Ψνϟॲཧ) ͱɺෳ ͷαʔϏεΛ·͕ͨΔͷ (՝ۚॲཧɺϛογϣϯॲཧ) ʹ͚Δ͜ͱ͕Ͱ͖·͢ɻ͜͜Ͱ͍ͨ͠ ͷෳͷαʔϏεʹ·͕ͨΔํͰɺϚΠΫϩαʔϏεͰසग़͢Δ߹ੑͷॲཧύλʔϯʹͳΓ ·͢ɻ ҰൠʹϚΠΫϩαʔϏεͷ߹ੑपΓͷॲཧϞϊϦεαʔϏεͷ߹ॲཧपΓʹൺͯෳࡶʹͳ Δ͜ͱ͕ΒΕ͓ͯΓɺγʔέϯεਤհ༰ΛಡΉͱɺҰͭͷαʔϏεͰ݁͢Δͷʹൺͯ ෳࡶͰ͋Δ͜ͱ͕͝ཧղ͍͚ͨͩΔͱࢥ͍·͢ɻ ͭ·ΓԿ͕ݴ͍͍͔ͨͱ͍͏ͱɺϚΠΫϩαʔϏεϞϊϦεαʔϏεʹରͯ͠߹ੑઓུͱ͍͏ Ͱઃܭɾ࣮ίετΛଟ͘ࢧ͏ඞཁ͕͋Δɺͱ͍͏͜ͱͰ͢ɻ͜ͷͨΊɺεέʔϦϯά୯Ұ োͷݮগͳͲͷએࠂ͔Β҆қʹϚΠΫϩαʔϏεʹඈͼͭ͘ͷͰͳ͘ɺ͍ͬͨΜαʔϏ εͱͦͷ༷Λཧͯ͠ϚΠΫϩԽͷํΛܾΊ͍ͯ͘ඞཁ͕͋Δͱ͍͏͜ͱͰ͢ɻͦ͏Ͱͳ͍ͱ Ԇʑʹ߹ੑʹ͍ͭͯͷઃܭɾ࣮ʹίετΛऔΒΕɺ݁Ռͱͯ͠αʔϏεͷ࣭ɺఏڙ͕Ϟϊ ϦγοΫΑΓྼͬͯ͠·͏ࣗମΛҾ͖ى͔͜͠Ͷ·ͤΜɻ 2.5 ͓ΘΓ ࠓճΨνϟΛࡐʹͯ͠߹ੑʹ·ͭΘΔΛΨνϟΨνϟͱհ͖ͯ͠·ͨ͠ɻ͓ͦΒ͘ຊষ ΛݟΔਓɺαʔϏεͷ༷ʹै࣮ͬͯํΛܾΊΔํͳͷ͔ͳͱࢥ͍·͕͢ɺͦΜͳํͷࢀߟ ʹͳΕ͍Ͱ͢ɻ ͱ͜ΖͰࢲΨνϟΛఱҪ *11 ͠·ͨ͠ɻޙչ͍ͯ͠·ͤΜɻ *11 Ұ෦ͷιʔγϟϧήʔϜͳͲͰ͋ΔҰఆ (e.g. 9 ສԁ) ͷΨνϟΛҾ͘ͱɺͦͷΨνϟͷۄͱͳΔΩϟϥΫλΛ ަͰ͖ΔγεςϜ͕ଘࡏ͍ͯ͠·͢ɻͦͷจ຺Ͱ "ͨ͘͞ΜҾ͍͓͚ͨͰ͓ͯͷΩϟϥΫλΛ֫ಘ͢Δ" ͜ͱ ΛɺఱҪ͢Δɺͱදݱ͠·͢ɻ 28 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ ୈ 3 ষ Cloud
Build Λ͍ͦ͏ʂ 30 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.1 ͡Ίʹ 3.1 ͡Ίʹ
ຊॻͰ Google Cloud Ͱఏڙ͞Ε͍ͯΔ Cloud Build Λ͍ͨ͢Ίͷ͞·͟·ͳใΛհ ͠·͢ɻ ରಡऀ • CI/CD ͕Կ͔Λ͓ͬͯΓɺར༻͓Αͼߏஙͷܦݧ͕͋Δ • Cloud Build ͷجຊతͳಈ࡞ɾ͍ํΛཧղ͍ͯ͠Δ ҙ ຊষʹ Cloud Build ͷެࣜυΩϡϝϯτʹهࡌͷͳ͍༰Λଟհ͍ͯ͠·͢ɻͦΕΒࣥ ච࣌ (2021 12 ݄ 21 ) ʹ චऀ (riddle) ͕࣮ػͰ֬ೝͨ͠ͷͷͨΊɺαʔϏεͷঢ়گΞο ϓσʔτʹΑͬͯࠓޙมߋʹͳΔՄೳੑ͕͋Δʹ͝ҙ͍ͩ͘͞ɻ ·ͨ Cloud Build ʹϓϥΠϕʔτϓʔϧ*1ϋΠϒϦοτϓʔϧ*2ͱ͍͏ػೳ͕ଘࡏ͠·͕͢ɺ ຊষͰ͜ΕΒΛѻ͍ͬͯͳ͍ʹ͝ҙ͍ͩ͘͞ɻ߲ͨͩ͠ʹΑͬͯൺֱͷͨΊใΛܝࡌ͠ ͍ͯΔՕॴ͋Γ·͢ɻ Cloud Build ͱ Google Cloud Ͱఏڙ͞Ε͍ͯΔϑϧϚωʔδυͳϏϧυڥͰ͢ɻΠϯελϯεͷཧɺ໘ ͳઃఆͳ͠ʹ CI/CD ͕࣮ߦͰ͖·͢ɻ(ಉछͷαʔϏεʹ CircleCI GitHub Actionsɺ AWS ͷ CodeBuild ͳͲ͕ଘࡏ͠·͢) ಛͱͯ͠ Google Cloud ͷઃఆΛαʔϏεΞΧϯτܦ༝ͰηΩϡΞʹߦ͑Δ͕͋͛ΒΕɺ Google Kubernetes Engine Cloud Run ͷγʔϜϨεͳσϓϩΠ͕ηΩϡΞʹߦ͑Δͷັྗ ͷ 1 ͭͰ͠ΐ͏ɻ·ͨϏϧυδϣϒͷ࡞ʹඞཁͳઃఆ؆୯ͰϦετ 3.1 ʹॻ͍ͨ༰͚ͩͰ࠷ *1 https://cloud.google.com/build/docs/private-pools/private-pools-overview *2 https://cloud.google.com/build/docs/hybrid/overview 31 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.2 Cloud Build Deep
Dive ݶͷδϣϒΛ࣮ߦͰ͖·͢ɻ Ϧετ 3.1: cloudbuild.yaml steps: - name: "bash" args: - -c - echo - "hello" 3.2 Cloud Build Deep Dive ຊষͰ Cloud Build ͷػೳཪଆͷ͘͠Έʹ͍ͭͯհ͠·͢ɻ ΫΠοΫελʔτϏϧυ ΫΠοΫελʔτϏϧυ*3ͱ͋Β͔͡Ίىಈ͍ͯ͠Δ Google Compute Engine (Ҏ߱ GCE ͱུ͠·͢) ্Ͱ͙͢ʹϏϧυδϣϒΛ։࢝Ͱ͖Δ Cloud Build ͷػೳͰ͢ɻ(ϓϩϏδϣχϯάͷ Ԇͱ GCE ͕ىಈ͢Δ·Ͱͷͪ࣌ؒͷ͜ͱͰ͢) ࣥච࣌ͰϚγϯλΠϓ͕ e2-medium ͷ GCE ͷΈ͕ରͰɺ΄͔ͷϚγϯλΠϓ*4ΑΓߴ ʹϏϧυΛ։࢝Ͱ͖·͢ɻ(͋͘·Ͱىಈ͕ૣ͍͚ͩͳͷͰ CPU ϝϞϦ͕ඞཁͳ߹దͳ ϚγϯλΠϓΛ͏ඞཁ͕͋Γ·͢) *3 https://cloud.google.com/build/pricing *4 https://cloud.google.com/build/docs/api/reference/rest/v1/projects.builds#machinetype 32 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.2 Cloud Build Deep
Dive Ͳͷ͙Β͍ىಈ͕͍ͷ͔ʁ "hello" Λग़ྗ͢Δ͚ͩͷδϣϒΛ֤ͬͯϚγϯλΠϓ (Cloud Build Ͱ༻Մೳͳͷ) ͰͲͷ ఔɺىಈʹ͕͔͔͍࣌ؒͬͯΔͷ͔Λௐࠪ͠·ͨ͠ɻ(ϓϥΠϕʔτϓʔϧϋΠϒϦοτϓʔϧ Ͱ༻ՄೳͳϚγϯλΠϓܭଌ͍ͯ͠·ͤΜ) Ϧετ 3.2: cloudbuild.yaml steps: - name: "bash" args: - -c - echo - "hello" ਤ 3.1: ϚγϯλΠϓ͝ͱͷ࣮ߦ࣌ؒ • ίϚϯυ࣮ߦ࣌ؒ : time gcloud builds submit --machine-type=MACHINE_TYPE Λ࣮ ߦ͔ͯ͠Β݁Ռ͕ؼͬͯ͘Δ·Ͱͷ࣌ؒ 33 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.2 Cloud Build Deep
Dive • δϣϒ࣮ߦ࣌ؒ : Cloud Build δϣϒͷॲཧʹ͔͔ͬͨ࣌ؒ • GCE ͷϓϩϏδϣχϯά࣌ؒ : ίϚϯυ࣮ߦ͔࣌ؒΒδϣϒ࣮ߦ࣌ؒΛҾ͍ͨ࣌ؒ – ݫີʹϑΝΠϧΛ Google Cloud Storage (Ҏ߱ GCS ͱུ͠·͢) ʹΞοϓϩʔυ͢ Δؚ͕࣌ؒ·ΕΔͨΊϓϩϏδϣχϯά࣌ؒ͏গ͘͠ͳΓ·͢ • هࡌ͍ͯ͠Δ࣌ؒͯ͢ෳճ࣮ߦ্ͨ͠ͰͷதԝͰ͢ ͜ͷ݁Ռ͔ΒϚγϯλΠϓ͕ e2-medium ͷ߹ GCE ͷϓϩϏδϣχϯά͕࣌ؒѹతʹ ͍͜ͱ͕Θ͔Γ·͢ɻͦͷͨΊδϣϒ͕ܰྔͰϚγϯϦιʔεΛඞཁͱ͠ͳ͍߹ɺՄೳͳݶΓ - -machine-type ΛΘͣʹ࣮ߦ͖͢Ͱ͠ΐ͏ɻ *5(ఆٛϑΝΠϧΛར༻͢Δ߹ options.mach ineType Λ༻͠ͳ͍) Cloud Build ͷཪଆͷ͘͠Έ Cloud Build ͕ͲͷΑ͏ʹಈ͍͍ͯΔͷ͔ΛΔͨΊʹɺϦετ 3.3 ΛͬͯδϣϒΛىಈͯ͠Έ ·͢ɻ͜ͷఆٛϑΝΠϧҎԼͷ 2 ͭͷεςοϓͰΓཱ͍ͬͯ·͢ɻ 1. docker-compose.yaml ʹఆٛ͞Εͨ Apache Λىಈ͢Δ 2. Hello ͱදࣔ͢Δ Ϧετ 3.3: cloudbuild.yaml steps: - id: Setup Middlewares name: "docker/compose" args: - -f - docker-compose.yaml - up - --build - -d - id: test step name: "gcr.io/google.com/cloudsdktool/cloud-sdk:cloudbuild_cache" entrypoint: bash args: - -c - | echo "hello test" waitFor: ["-"] *5 e2-medium Λ໌ࣔతʹ͏ઃఆͳ͍ͷͰɺ͍͍ͨͱ͖ machine-type Λઃఆ͠ͳ͍Α͏ʹ͠·͠ΐ͏ 34 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.2 Cloud Build Deep
Dive Ϧετ 3.4: docker-compose.yaml version: "3.8" services: http1: container_name: http1 image: httpd networks: default: external: name: cloudbuild ਤ 3.2 Ϧετ 3.3 Ͱ࣮ߦ͞Ε֤ͨϏϧυεςοϓ͕ Cloud Build ͰͲͷΑ͏ʹಈ࡞͍ͯ͠Δ͔ Λਤࣔͨ͠ΠϥετͰ͢ɻ ਤ 3.2: Cloud Build ͕Քಇ͢Δ GCE ͷ෦ߏ Cloud Build Google ʹཧ͞Εͨ GCE Ͱಈ͍͍ͯ·͢ɻ֤Ϗϧυεςοϓ͝ͱʹίϯςφ ͕ step_ࣈ ͱ͍͏໊લͰىಈ͠ɺ͜ͷίϯςφͷதͰ Ϧετ 3.3 Ͱఆٛ͞ΕͨίϚϯυ͕࣮ߦ ͞Ε·͢ɻͦͯ͠ Ϧετ 3.4 Ͱఆٛ͞Εͨ Apache ίϯςφ http1 ͱ͍͏໊લͰىಈ͠ɺϏϧυ εςοϓͷίϯςφͱಉ༷ʹ cloudbuild ʹॴଐ͢ΔωοτϫʔΫΠϯλʔϑΣʔε (NIC) Λ࣋ͪ ·͢ɻ 35 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.2 Cloud Build Deep
Dive ˙ϝϞ: cloudbuild network ʹ͍ͭͯ ωοτϫʔΫ໊ ͷ cloudbuilda Google Cloud ʹΑͬͯ༧͞Ε͍ͯ·͢ɻ ·ͨɺcloudbuild ωοτϫʔΫʹॴଐ͢ΔίϯςφΞϓϦέʔγϣϯͷσϑΥϧτೝূใ (ADCb) ͕༻Ͱ͖ΔͨΊɺCloud Build Λ࣮ߦ͍ͯ͠ΔαʔϏεΞΧϯτͷݖݶ͕༻Ͱ͖ ·͢ɻ a https://cloud.google.com/build/docs/build-config?hl=ja#network b https://cloud.google.com/docs/authentication/production ͯ͢ͷίϯςφ͕ಉҰͷωοτϫʔΫ (cloudbuild) ʹଘࡏ͢ΔͨΊɺϦετ 3.5 ͷΑ͏ʹϏϧ υεςοϓͷίϯςφ͔Β http1 ίϯςφͷ௨৴ՄೳͰ͢ɻ Ϧετ 3.5: step_0 ίϯςφ͔Β http1 ίϯςφʹ͚ͯ curl Λ࣮ߦͨ݁͠Ռ $ curl http1 <html><body><h1>It works!</h1></body></html> ͦͷͨΊෳͷίϯςφΛಉ࣌ʹىಈ͢Δํ๏Λ༻͍Δ͜ͱͰ Cloud Build ্ʹσʔλϕʔε key-value ετΞͳͲͷϛυϧΣΞΛಈ࡞ͤͨ͞ΓɺϚΠΫϩαʔϏεΛىಈͯ͠ͷςετ͕Մೳ ʹͳΓ·͢ɻ metadata ίϯςφ Cloud Build ্ͰϢʔβʔ͕ఆٛ͠ͳͯ͘ metadata ίϯςφ͕ىಈ͍ͯ͠·͢ɻ͜Ε GCE ͷ VM ϝλσʔλ*6Λฦ٫͢ΔΞϓϦέʔγϣϯͰ͢ɻ ௨ৗϝλσʔλαʔόͱΑΕΔ http://metadata.google.internal (·ͨ 169.254.169.254) Ͱ Listen ͢ΔαʔόʹΞΫηε͠ GCE ࣗͷใΛऔಘ͢ΔͷͰ͕͢ɺCloud Build ্ͷ֤ίϯ ςφͷ߹ಉ༷ͷ URL Λୟ͍ͯϦΫΤετ metadata ίϯςφʹసૹ͞Ε·͢ɻ ࣮ࡍʹίϚϯυΛୟ͍ͯΈΔͱɺҟͳͬͨѼઌʹ௨৴͕͍͍ͯΔࣄ͕Θ͔Γ·͢ɻ Ϧετ 3.13: ίϯςφͰϝλσʔλͷ໊લղܾΛͨ͠߹ $ nslookup metadata.google.internal Server: 127.0.0.11 *6 https://cloud.google.com/compute/docs/metadata/overview 36 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.2 Cloud Build Deep
Dive Address: 127.0.0.11#53 Non-authoritative answer: Name: metadata.google.internal Address: 192.168.10.5 $ docker inspect metadata -f "{{json .NetworkSettings.Networks.cloudbuild.IPAddress}}" "192.168.10.5" Ϧετ 3.13: GCE Ͱϝλσʔλͷ໊લղܾΛͨ͠߹ $ nslookup metadata.google.internal Server: 169.254.169.254 Address: 169.254.169.254#53 Non-authoritative answer: Name: metadata.google.internal Address: 169.254.169.254 Docker outside of Docker ֤Ϗϧυεςοϓ্ͷίϯςφͰ (Docker ίϚϯυ͕Πϯετʔϧ͞Ε͍ͯΕ) Docker ίϚ ϯυͷ࣮ߦ͕ՄೳͰ͢ɻ Ϧετ 3.13: ίϯςφͰͷ docker ps ͷ݁Ռ $ docker ps --format="table {{.Names}}\t{{.Image}}\t{{.Command}}" NAMES IMAGE COMMAND http1 httpd "httpd-foreground" step_0 docker/compose "sh /usr/local/bin/dʜ" step_1 gcr.io/google.com/cloudsdktool/cloud-sdk "bash -c ’echo hellʜ" metadata gcr.io/cloud-builders/metadata "/metadata" ͔͠͠ίϯςφʹ Docker σʔϞϯ͕ଘࡏͤͣɺϦϞʔτͷ Docker σʔϞϯΛ͏ͨΊͷઃ ఆೖ͍ͬͯ·ͤΜɻͰ͍͍ͬͨͲ͏ͬͯϏϧυεςοϓ্ͷίϯςφ Docker σʔϞϯʹ ଓ͍ͯ͠ΔͷͰ͠ΐ͏͔ʁ Cloud Build Ͱ Docker outside of Docker (Ҏ߱ DooD ͱུ͠·͢) ͱ͍͏ํ๏Λͬͯ ͜ΕΛ࣮ݱ͍ͯ͠·͢ɻDooD ίϯςφ͔Βϗετͷ docker.sock (/var/run/docker.sock*7) Λ *7 https://docs.docker.jp/engine/userguide/basics.html#docker-unix 37 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.2 Cloud Build Deep
Dive ϘϦϡʔϜϚϯτ͠ɺίϯςφڥͷ docker ίϚϯυͷ࣮ߦΛϗετଆͰ࣮ݱ͢ΔํࣜͰ͢ɻ ͜ΕʹΑΓ CI ڥࣗମ͕ίϯςφԽͨ͠ͱͯ͠ɺDocker ϓϩηεΛίϯςφͰ্ཱͪ͛Δ ඞཁͳ͘ɺϗετͷ Docker σʔϞϯʹ໋ྩΛ͛Δ͜ͱͰ৽ͨͳίϯςφ (δϣϒͳͲ) Λ CI ίϯ ςφ͔Β࡞Ͱ͖·͢ɻ ˙ϝϞ: Docker in Docker (DinD) DooD ͷ΄͔ʹ Docker in Docker (DinD) a ͱݺΕΔίϯςφͰ Docker σʔϞϯΛىಈ ͠ɺίϯςφͷதͰ͞ΒʹίϯςφΛىಈ͢Δํ๏͋Γ·͢ɻ(Cloud Build Ͱ͜ͷํࣜ ΘΕ͍ͯ·ͤΜ) ਤ 3.3: Docker in Docker ͷߏਤ a http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/ લ߲ͷʮCloud Build ͷཪଆͷ͘͠Έʯ Ͱࣔͨ͠ͱ͓ΓɺϏϧυεςοϓͰىಈ֤ͨ͠ίϯςφ docker.sock (/var/run/docker.sock) ΛϚϯτ͍ͯ͠ΔͨΊɺίϯςφʹ docker ίϚϯυ͞ 38 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
͑ଘࡏ͍ͯ͠Εϗετଆͷ Docker Λ௨ͯ͡ίϯςφͷૢ࡞͕ՄೳͰ͢ɻ Ϧετ 3.13: Ϗϧυεςοϓ 1 ͷδϣϒ͕ /var/run/docker.sock ΛϚϯτ͍ͯ͠Δ༷ࢠ $ docker inspect step_1 \ | jq -r ’.[]|.Mounts|.[]|select(.Source == "/var/run/docker.sock")’ { "Type": "bind", "Source": "/var/run/docker.sock", "Destination": "/var/run/docker.sock", "Mode": "", "RW": false, "Propagation": "rprivate" } 3.3 Cloud Build Λͬͱศརʹ͏ํ๏ 1. Ϗϧυ݁ՌΛ௨͢Δ Cloud Build ͰςετϏϧυΛࣗಈԽͰ͖ͨΒ࣍Ϗϧυ݁Ռͷ௨Λߦ͍͍ͨͰ͢Ͷɻ Google Cloud Ͱ Cloud Build Notifiers*8 ͱ͍͏ Cloud Run ্Ͱಈ࡞͢Δ௨πʔϧ͕ఏ ڙ͞Ε͍ͯ·͢ɻ͜ͷπʔϧҎԼͷ௨ઌʹରԠ͍ͯ͠ΔͷͰɺ΄ͱΜͲͷϢʔεέʔεͰ͜Ε Λ͑ྑ͍Ͱ͠ΐ͏ɻ • BigQuery • HTTP • Slack • SMTP *8 https://github.com/GoogleCloudPlatform/cloud-build-notifiers 39 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
·ͨ͜ͷπʔϧ Go Ͱॻ͔Ε͓ͯΓ༰γϯϓϧͳͨΊɺϝοηʔδΛΧελϚΠζ͍ͨ͠ ߹ Git Clone ͯ͠खΛೖΕΔͱྑ͍Ͱ͠ΐ͏ɻ ࢀߟ·ͰʹզʑͷڥͰҎԼͷΑ͏ͳ௨Λߦ͍ͬͯ·͢ɻίʔυͷཧʹ GitHub Λͬͯ ͍ΔͨΊɺͲͷ Pull Request Ͱ୭͕࣮ߦͨ͠ͷ͔͕Θ͔Δͱࣦഊ࣌ʹݪҼ͕͍͘͢ॏๅ͍ͯ͠ ·͢ɻ ਤ 3.4: ݱͰͷ Slack ௨ 2. Τϥʔऴྃ࣌ʹཧ༝Λ௨͢Δ ଓ͍ͯ௨ͷதͰಛʹδϣϒ͕ࣦഊͨ͠ࡍͷͰ͢ɻδϣϒ͕ࣦഊͨ͠ࡍδϣϒ͕ࣦഊͨ͠ ཧ༝ΛΓ͍ͨͰ͢ΑͶɻ Cloud Build ͷ REST Ϧιʔεͷ projects.builds ʹ FailureInfo*9 ͱ͍͏ϑΟʔϧυʹ ࣦഊཧ༝ؚ͕·Ε͍ͯ·͢ɻͨͩ͠ FailureInfo ʮͲͷϏϧυεςοϓͰࣦഊͨ͠ͷ͔ʁʯͱ ʮऴྃίʔυʯ͔͠σʔλΛ֨ೲ͍ͯ͠ͳ͍ͨΊɺ۩ମతʹʮͳͥδϣϒ͕ࣦഊͨ͠ͷ͔ʁʯ ʹ͍ͭ ͯϏϧυϩάΛ֬ೝ͠ͳ͍ͱݪҼΛѲͰ͖·ͤΜɻ *9 https://cloud.google.com/build/docs/api/reference/rest/v1/projects.builds#Build.FailureInfo 40 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
Ϧετ 3.13: failureInfo Ͱग़ྗ͞ΕͨΤϥʔཧ༝ failureInfo: detail: ’Build step failure: build step 1 "gcr.io/xxx/xxx:xxx" failed: step exited with non-zero status: 1’ δϣϒࣦഊ࣌ʹʮεςοϓͷͲͷίϚϯυ࣮ߦͰࣦഊͨ͠ͷ͔ʁʯʮίϚϯυ݁Ռͷग़ྗʯ ΛΔͨΊʹগʑτϦοΩʔͳํ๏Λߦ͏ඞཁ͕͋Γ·͢ɻͦ͜ͰຊষͰ GitHub ͷ Pull Request ΛτϦΨͱͨ͠ϏϧυͰൃੜͨ͠ΤϥʔΛίϝϯτͱͯ͠ߘ͢Δํ๏Λհ͠·͢ɻ ˙ϝϞ: Pull Request τϦΨҎ֎Ͱ͑Δͷ͔ʁ ͜Ε͔Βհ͢Δํ๏΄͔ͷτϦΨͷ߹Ͱར༻ՄೳͰ͢ɻͨͩ͠ίϝϯτߘ෦ΛҰ ෦มߋ͢Δඞཁ͕͋Γ·͢ɻ͜͜ͰτϦΨΛݶఆ͍ͯ͠Δͷ Pull Request ͷ URL Λऔಘ͢ Δͷʹ Cloud Build ͷ _PR_NUMBER มaΛ༻Ͱ͖Δͷ͕߹͕ྑ͍͚ͩͰɺͦΕҎ֎ ʹཧ༝͋Γ·ͤΜɻ a https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values ۩ମతͳ௨ͷϑϩʔ ਤ 3.5: Τϥʔऴྃ࣌ͷ௨ϑϩʔ ۩ମతͳྲྀΕҎԼͷͱ͓ΓͰ͢ɻ 41 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
1. GitHub ͷ Pull Request ʹมߋΛ Push 2. Cloud Build Ͱςετͷ࣮ࢪ 3. Cloud Build ͕ࣦഊͨ͠߹ GitHub ʹίϝϯτΛߘ 4. GitHub ͷίϝϯτΛ Slack ʹ௨ ˞ 4 ͷ Slack ͱ GitHub ͷ࿈ܞʹ͍ͭͯຊॻͰѻ͍·ͤΜɻSlack ެࣜαΠτͷʮGitHub ͱ Slack Λ࿈ܞͤ͞Δʯ *10Λࢀߟʹ͍ͯͩ͘͠͞ɻ ϏϧυεςοϓͰΤϥʔऴྃΛϋϯυϦϯά͢Δ Ͱͬͦ͘͞ϏϧυεςοϓͷΤϥʔΛ GitHub ʹߘ͢Δํ๏Λݟ͍͖ͯ·͠ΐ͏ɻ Ϧετ 3.7: cloudbuild.yaml availableSecrets: # ࣄલʹ Secret Manager ʹ GitHub ͷϓϥΠϕʔτΞΫηετʔΫϯΛ֨ೲ͓ͯ͘͠ # ΞΫηετʔΫϯʹ Pull Request ͷίϝϯτ͕ՄೳͳݖݶΛ༩͠·͢ secretManager: - versionName: projects/${PROJECT_ID}/secrets/github-access-token/versions/latest env: "GITHUB_TOKEN" substitutions: _COMMIT_URL: "$(commit.html_url)" steps: - id: failure step name: gcr.io/cloud-builders/curl secretEnv: ["GITHUB_TOKEN"] entrypoint: "bash" args: - -c - | set -o pipefail # pipe ॲཧͰࣦഊͨ͠Βऴྃ͢Δ set -o nounset # ม͕ະఆٛͷ߹ऴྃ͢Δ set -o errexit # ίϚϯυͷ࣮ߦʹࣦഊͨ͠Βऴྃ͢Δ # ऴྃίʔυΛνΣοΫ͠ɺਖ਼ৗऴྃ(0)Ҏ֎ GitHub ʹίϝϯτΛߘ͢Δ function catch () { # ؔΛݺͼग़͢લͷऴྃίʔυΛอଘ͓ͯ͘͠ original_exit=$? if [ "$original_exit" -eq 0 ]; then # ਖ਼ৗऴྃ(0)ͷ߹Կ͠ͳ͍ true else # ҟৗऴྃͷ߹GitHubʹߘ͢Δ(github-commenterͳͲΛ͏ͷྑ͍) *10 https://slack.com/intl/ja-jp/help/articles/232289568-GitHub-%E3%81%A8-Slack- %E3%82%92%E9%80%A3%E6%90%BA%E3%81%95%E3%81%9B%E3%82%8B 42 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
# url ͔Β Φʔφʔ ͱ ϦϙδτϦ໊ Λऔಘ͢Δ # ˞ιʔεϦϙδτϦ͕ GitHub Ͱ͋ΔલఏͰ͢ read owner repo <<< $(echo "$_COMMIT_URL" \ | sed -re "s@.*github\.com/([^/]*)/([^/]*)/commit.*@\1 \2@g") pr=$_PR_NUMBER curl_opts=( -s -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $$GITHUB_TOKEN" -d @- "https://api.github.com/repos/${owner}/${repo}/issues/${pr}/comments" ) # GitHub ʹίϝϯτΛߘ curl "${curl_opts[@]}" << CURL_BODY { # վߦΛߦ͏ͨΊ֤ߦͷඌʹ \n Λ༩͢Δ "body": "$(cat $result_file | sed -e ’s/$/\\n/g’)" } CURL_BODY fi # ݩʑͷऴྃίʔυͰδϣϒΛऴྃ͢Δ exit "$original_exit" } # γΣϧͷऴྃΛΩϟον͠ɺऴྃલʹ _catch ؔΛݺͼग़͢ trap catch EXIT # Ҏ߱͜ͷϏϧυεςοϓͰ࣮ࡍʹ࣮ߦ͍ͨ͠ॲཧΛॻ͘ # ؔʹ͍ͯ͠ΔͷΤϥʔग़ྗΛͻͱ·ͱΊʹ͍ͨ͢͠Ί function main() { echo "test step 1 - success" echo "test step 2 - success" # ͜͜Ͱࣦഊͤ͞Δ echo "test step 3 - fail" >&2 echo "this step is failed" >&2 echo "reason is ’hoge hoge hoge’" >&2 exit 1 } # ίϚϯυͷΤϥʔ݁ՌΛ֨ೲ͢ΔϑΝΠϧ result_file="/tmp/result" # main ؔΛݺͼग़ඪͯ͠ඪ४ΤϥʔΛϑΝΠϧʹग़ྗ͠·͢ main 2> "$result_file" ্هͷఆٛϑΝΠϧΛ࣮ߦ͢Δͱδϣϒ͕ࣦഊͯ͠ҎԼͷίϝϯτ͕ Pull Request ʹߘ͞Ε ·͢ɻ 43 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
ਤ 3.6: GitHub ʹΤϥʔΛߘͨ͠ਤ ࢲͷνʔϜͰ GitHub Markdown ͰଟগϨΠΞτΛมߋͯ͜͠ͷΑ͏ͳίϝϯτΛߘͯ͠ ͍·͢ɻ ਤ 3.7: GitHub ʹΤϥʔΛߘͨ͠ਤ_ݱ ˙ϝϞ: Τϥʔ௨ʹ Cloud Build Notifiers ΛΘͳ͍ཧ༝ Cloud Build Notifiers Cloud Build ͷ݁ՌΛ Cloud Pub/Sub ͔Βड͚औΓɺͦΕΛ Cloud Run Ͱղऍͯ͠௨Λߦ͏ͷͰ͕͢ɺCloud Run Ͱड͚औͬͨஈ֊ͰৄࡉͳΤϥʔ݁Ռؚ͕· Ε͍ͯͳ͍ͨΊɺϋϯυϦϯά͠Α͏ʹͦͦσʔλ͕ଘࡏ͠ͳ͍ͨΊར༻Ͱ͖·ͤΜɻ 44 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
3. ϏϧυͷϑϩʔΛਤղԽ͢Δ ෳࡶͳϏϧυΛ࣮ߦ͍ͨ͠߹ waitFor ΛͬͯεςοϓؒͷґଘؔΛنఆͰ͖·͢ɻ͜Ε ʹΑΓδϣϒͷฒྻ࣮ߦ͕ՄೳͰ͢ɻ ෳࡶͳॲཧΛ Cloud Build Ͱ࣮ݱ͢Δͷͱָ͍ͯ͠ͷͰ͕͢ɺνʔϜͰ։ൃΛߦ͏߹࣌ ͕ؒܦͬͯ༰Λݟฦͨ͠ࡍͳͲʹɺશମ૾ͷѲʹ͕͔͔࣌ؒΓ·͢ɻͦΜͳͱ͖ʹʹཱͭͷ͕ ͜Ε͔Βհ͢ΔϏϧυεςοϓΛਤղԽ͢ΔπʔϧͰ͢ɻ ·ͣෳࡶͳؔ࿈ੑΛͬͨఆٛϑΝΠϧ (Ϧετ 3.8) Λ༻ҙ͠·͢ɻ(؆ུԽͷͨΊ֤Ϗϧυε ςοϓͷ࣮ߦίϚϯυΛলུ͍ͯ͠·͢) Ϧετ 3.8: cloudbuild.yaml steps: - id: test1 name: bash - id: test2 name: bash waitFor: ["-"] - id: test3 name: bash waitFor: [ "test2" ] - id: test4 name: bash waitFor: [ "test1", "test3" ] - id: test5 name: bash waitFor: [ "test1" ] 45 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
- id: test6 name: bash waitFor: [ "test5", "test3" ] - id: test7 name: bash waitFor: [ "test1", "test2", "test6" ] - id: test8 name: bash waitFor: [ "test2" ] - id: test9 name: bash waitFor: [ "test2", "test7", "test8" ] - id: test10 name: bash waitFor: [ "test1", "test9" ] ͜ΕΛπʔϧΛͬͯΘ͔Γͯ͘͢͠Έ·͠ΐ͏ʂ cloudbuildgraph ·ͣ patrickhoefler ࢯʹΑͬͯ࡞ΒΕͨ cloudbuildgraph*11 Ͱ͢ɻ͜ͷπʔϧఆٛϑΝΠϧ ΛಡΈࠐΜͰԣ͖ʹґଘؔΛਤࣔͯ͘͠Ε·͢ɻ Ϧετ 3.13: cloudbuildgraph ͷ࣮ߦ $ cloudbuildgraph cloudbuild.yaml *11 https://github.com/patrickhoefler/cloudbuildgraph 46 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
ਤ 3.8: cloudbuildgraph Ͱग़ྗͨ͠ਤ cloudbuildgraph ΧϨϯτσΟϨΫτϦʹଘࡏ͢Δ cloudbuild.yaml/cloudbuild.yml/cloudbuild.json ͷ͍ͣΕ͔ͷϑΝΠϧ͔͠ಡΈऔΔ͜ͱ͕Ͱ͖·ͤΜɻͦͷͨΊϑΝΠϧ໊Λࣗ༝ʹมߋ͍ͨ͠߹ ɺϑΥʔΫ͞Εͨ cloudbuildgraph*12Λ༻͢Δͱࣗ༝ͳϑΝΠϧ໊ͰਤղԽͰ͖·͢ɻ gcb-visualizer ଓ͍ͯ RyanSiu1995 ࢯʹΑͬͯ࡞ΒΕͨ gcb-visualizer*13 Ͱ͢ɻ͜ͷπʔϧ cloudbuild- graph ͱҟͳΓॎʹґଘ͕ؔਤղԽ͞Ε·͢ɻ Ϧετ 3.13: gcb-visualizer ͷ࣮ߦ $ gcb-visualizer visualize cloudbuild.yaml *12 https://github.com/lirlia/cloudbuildgraph *13 https://github.com/RyanSiu1995/gcb-visualizer 47 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
ਤ 3.9: gcb-visualizer Ͱग़ྗͨ͠ਤ ͲͪΒखܰʹ͑ΔπʔϧͳͷͰݟ͍͢ํΛબΜͰͬͯΈ͍ͯͩ͘͞ɻ ·ͱΊ ෳࡶͳϏϧυεςοϓΛ࣋ͭδϣϒͰਤղԽ͢Δ͜ͱͰɺҰؾʹશମ૾͕͖ͬΓͯ͠ཧղ͠ ͘͢ͳΓ·͢ɻͲͪΒͷίϚϯυ؆୯ʹΠϯετʔϧͰ͖·͢ͷͰɺ·ͣࠓ͍ͬͯΔ Cloud Build ͷఆٛϑΝΠϧͷը૾Λ࡞͢Δͱ͜Ζ͔Β࢝ΊͯΈ·͠ΐ͏ɻ ׳Ε͖ͯͨΒఆٛϑΝΠϧͷमਖ਼ΛτϦΨʹͯ͠ਤղԽͷ CI ΛΒͤͯɺϨϏϡʔͷࡍʹ৽ɾچ ͷఆٛϑΝΠϧͷਤΛදࣔ͢ΔͷศརͰ͠ΐ͏ɻ 48 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
4. δϣϒΛػ͠ଓ͚Δ Cloud Build ୯ମͰಉ͡τϦΨͷδϣϒΛγϦΞϧʹ࣮ߦ͢Δ͜ͱͰ͖·ͤΜɻ(ಉ࣌ʹ 2 ճ ࣮ߦ͢Εฒྻʹδϣϒ͕࣮ߦ͠·͢) ͦͷͨΊ֎෦ϦιʔεΛδϣϒ͕ϩοΫͨ͠Γઐ༗͍ͯ͠Δ߹ɺԿΒ͔ͷखஈΛ༻͍ͯδϣϒ ΛΩϡʔʹஷΊΔΑ͏ͳ͘͠Έ͕ඞཁʹͳΓ·͢ɻ(ઌߦ͍ͯ͠ΔδϣϒΛΩϟϯηϧ͢Δ͚ͩͰࣄ ΓΔ߹ ʮCancelotʯ Λࢀর͍ͯͩ͘͠͞) ΩϡʔʹஷΊΔ͘͠ΈΛ Google Cloud Ͱ࡞Δ߹ʹ Cloud Pub/Sub Cloud Tasks ͳͲ͕ ڍ͛ΒΕ·͕͢ɺδϣϒͷछྨ͕૿͑ͨΓखܰʹ࣮ݱ͠Α͏ͱࢥ͏ͱগ͕͔͔͠Γ·͢ɻͦ͜Ͱ ࠓճࢦఆͷδϣϒͷྃΛͪଓ͚Δํ๏Λհ͠·͢ɻ δϣϒͷྃΛػ͢ΔεΫϦϓτ Ϧετ 3.9 δϣϒ͔Βݺͼग़͢εΫϦϓτͰɺࢦఆͷ݅Λຬͨ͢ϏϧυδϣϒͷҰཡΛग़ྗ͠ ·͢ɻ Ϧετ 3.9: get-filtered-cloudbuild-job-list.sh #!/bin/bash # ࢦఆͷϏϧυIDΑΓલʹ࣮ߦ͞Εͨɺ֤छ݅ʹώοτ͢Δ Cloud Build δϣϒͷϏϧυIDΛऔಘ͠·͢ set -o pipefail set -o nounset set -o errexit CMDNAME=${0##*/} function prefail() { echo "$@" 1>&2; usage; exit 1; } function usage() { cat <<USAGE >&2 Usage: $CMDNAME [OPTIONS] Options 49 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
--build_id [BUILD_ID] ݕࡧରʹ͏δϣϒ --check_trigger_name_regex [NAME_REGEX] ϏϧυτϦΨ໊ͷݕࡧ࣌ʹ༻͢Δਖ਼نදݱͰ͢ --limit num ݕࡧͷ্ݶͰ͢ --disable_on_going ௨ৗ࣮ߦதͷδϣϒͷΈΛରʹ͠·͕͢ɺ ͜ͷϑϥάͷར༻࣌ͯ͢ͷδϣϒΛରʹ͠·͢ --region [REGION_NAME] Private Pool ར༻࣌ϦʔδϣϯΛࢦఆ͍ͯͩ͘͠͞ --help / -h USAGE } LIMIT=10 # Cloud Build ͷδϣϒΛݕࡧ͢ΔͰ͢ BUILD_ID=dummy # ݕࡧͷىͱͳΔδϣϒIDͰ͢ TRIGGER_NAME_REGEX=dummy # ݕࡧରͱ͢ΔδϣϒΛ࣮ߦͨ͠τϦΨ໊Ͱ͢ ONGOING_FLAG=true # ݱࡏ࣮ߦதͷδϣϒͷΈΛରʹ͢Δ߹ true REGION="" # Private Pool Ͱར༻͢Δ߹ඞཁͰ͢ # Process arguments while [[ $# -gt 0 ]]; do case "$1" in --build_id) BUILD_ID="$2" shift 2 ;; --check_trigger_name_regex) TRIGGER_NAME_REGEX="$2" shift 2 ;; --limit) LIMIT="$2" shift 2 ;; --disable_on_going) ONGOING_FLAG="false" shift 1 ;; --region) REGION="--region $2" shift 2 ;; --help|-h) usage exit 0 ;; *) prefail "Unknown argument: $1" ;; esac done # ݅ʹϚονͨ͠δϣϒͷҰཡΛฦ٫͠·͢ function getOngoingJobListBeforeSpecificJob() { local build_start_time=$(\ gcloud builds describe $BUILD_ID --format=’value(startTime)’ $REGION) 50 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.3 Cloud Build Λͬͱศརʹ͏ํ๏
local args=( # δϣϒ࡞ॱʹιʔτ --sort-by=create_time # ݕࡧ --limit "${LIMIT}" # ϏϧυIDΛऔಘ --format="value(ID)" # ݕࡧͷϑΟϧλʔͰ͢ --filter="id!=$BUILD_ID \ AND startTime<=$build_start_time \ AND substitutions.TRIGGER_NAME~$TRIGGER_NAME_REGEX" # Private Pool Ͱ͏ϦʔδϣϯͰ͢ $REGION ) [ $ONGOING_FLAG = true ] && args+=(--ongoing) # ࣮ߦதͷδϣϒͷϏϧυIDҰཡΛऔಘ gcloud builds list "${args[@]}" } getOngoingJobListBeforeSpecificJob ͜ͷγΣϧΛϦετ 3.10 ͷΑ͏ʹϏϧυεςοϓʹΈࠐΉ͜ͱͰ݅Λຬͨ͢Ϗϧυδϣϒ͕ ྃ͢Δ·Ͱϧʔϓ͠ଓ͚ΔϏϧυεςοϓΛ࣮ݱͰ͖ɺಉ༷ͷδϣϒͷγϦΞϧ࣮ߦ͕ՄೳʹͳΓ ·͢ɻ(ͨͩ͠δϣϒ͕Քಇ͠ଓ͚ΔͨΊɺػதϏϧυδϣϒͷҡ࣋ʹඅ༻͕ൃੜ͢Δʹҙ ͍ͯͩ͘͠͞) Ϧετ 3.10: cloudbuild.yaml - id: check another jobs name: gcr.io/google.com/cloudsdktool/cloud-sdk:slim_cloudbuild_cache entrypoint: bash args: - -c - | set -o pipefail set -o nounset set -o errexit while true do # ${PROJECT_ID}-hogehoge-job ͷ͕ 0 ͳΒਖ਼ৗऴྃ͠ɺ # ͦΕҎ֎ͷ߹ɺδϣϒͷऴྃΛͪ·͢ # ࣮ߦ͢Δ Git ϦϙδτϦͷϧʔτԼʹ get-filtered-cloudbuild-job-list.sh ͕ # ࣮ߦݖݶ͖Ͱอଘ͞Ε͍ͯΔඞཁ͕͋Γ·͢ job_num=$(./get-filtered-cloudbuild-job-list.sh \ --build_id ${BUILD_ID} \ 51 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
--check_trigger_name_regex "${PROJECT_ID}-hogehoge-job" \ --limit 500 | wc -l) [ $job_num -eq 0 ] && break sleep 30 # sec done 3.4 Cloud Build ͷίετΛઅ͢Δํ๏ CI ඇৗʹศརͳ໘ɺ։ൃਓ͕ଟ͘ͳͬͨΓɺδϣϒ͕૿͑ͯ͘ΔͱߴίετʹͳΓ͕ͪ Ͱ͢ɻϚωʔδυͳπʔϧཧ͕ෆཁͳखܰͰྑ͍Ͱ͕͢ɺར༻ճ͕૿͑Δͱར༻ίετ͕૿ ͑Δͷ͕ؾʹͳΓ·͢ɻ ͦ͜ͰຊষͰ Cloud Build ͷίετΛ͑ΔίπΛ͍͔ͭ͘հ͠·͢ɻ Cloud Build ͷίετߏΛΔ ίπΛΔલʹ·ͣ Cloud Build ίετߏΛ͑·͠ΐ͏ɻ ਤ 3.10: cloudbuild pricing 52 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
*14 ˙ϝϞ: ͦͷ΄͔ͷίετ Cloud Build ͰωοτϫʔΫసૹྉ͕Ϗϧυྉۚʹ͋Β͔͡ΊΈࠐ·Ε͍ͯΔͨΊɺGCE ͱҟͳΓΠϯλʔωοτͷϑΝΠϧͷΞοϓϩʔυ͕δϣϒͰߦΘΕͯՃͷඅ༻ ൃੜ͠·ͤΜɻͨͩ͠ GCS Cloud Logging ʹର͢ΔϩάΞοϓϩʔυσʔλͷอଘʹͭ ͍ͯɺผ్ετϨʔδଆͷωοτϫʔΫసૹྉετϨʔδ༻ྉ͕ൃੜ͢Δʹҙͯ͘͠ ͍ͩ͞ɻ ίετઅํ๏ͷछྨ Cloud Build ͰϏϧυ࣮ߦ࣌ؒʹରͯ͠՝ۚ͞ΕΔͨΊɺίετͷઅํ๏ͱͯ͠େ͖͚ͯ͘ 2 ͭͷํ๏͕ଘࡏ͠·͢ɻ 1. Ϗϧυ࣌ؒΛॖ͢Δ 2. Ϗϧυʹඞཁͳ CPU / ϝϞϦαΠζΛখ͘͢͞Δ ࠓճϏϧυ࣌ؒΛॖ͢Δํ๏ʹ͍͍͔ͭͯͭ͘ͷίπΛհ͠·͢ɻ ͳ͓ίϯςφΠϝʔδͷϏϧυʹొ͢Δ͞·͟·ͳπʔϧɺܰྔͳΠϝʔδΛͬͨίϯςφ ΠϝʔδαΠζͷॖখํ๏ʹ͍ͭͯ Cloud Build ͱ͕ؔͳ͍ͨΊ͜͜Ͱհ͠·ͤΜ 1. ϏϧυΩϟογϡΛ͏ *14 https://cloud.google.com/build/pricing ΑΓҾ༻ 53 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
·ͣఆ൪Ͱ͕͢ɺϏϧυΩϟογϡΛ͏·͍͘·͠ΐ͏ɻ ެࣜαΠτ*15Ͱհ͞Ε͍ͯΔ௨ΓɺҎԼͷํ๏ͰΩϟογϡΛ͍ճ͢͜ͱ͕Ͱ͖·͢ɻ • Kaniko Ωϟογϡ ·ͨ ΩϟογϡࡁΈͷ Docker Πϝʔδͷར༻ • GCS Docker Build Λ͢Δࡍɺࣄલʹऔಘͨ͠ Kaniko ΩϟογϡΩϟογϡࡁΈͷ Docker Π ϝʔδΛ༻͢Δ͜ͱͰϏϧυΛεΩοϓͰ͖ΔΑ͏ʹͳΔͨΊϏϧυ࣌ؒΛݮͰ͖·͢ɻ·ͨɺ ίϯςφҎ֎ͷ߹Ͱ͋ΕதؒՌΛ GCS ʹอଘ͓ͯ͘͜͠ͱͰɺಉ༷ʹϏϧυ࣌ؒΛݮͰ ͖·͢ɻ 2. ϩέʔγϣϯʹҙ͠Α͏ ϓϥΠϕʔτϓʔϧ ϋΠϒϦουϓʔϧ ͱ͍ͬͨಛผͳ Cloud Build ڥΛ͍ͬͯΔ߹ Λআ͍ͯɺ௨ৗ global Ͱδϣϒ͕࣮ߦ͞Ε͍ͯ·͢ɻͰ global ͱ Google Cloud ͷͲ͜ͷ ϦʔδϣϯͳͷͰ͠ΐ͏͔ʁ global ͬͯͲ͜ͷ͜ͱʁ Ϗϧυδϣϒͷ VM ϝλσʔλʹΞΫηεͯ͠ɺδϣϒίϯςφͷϩέʔγϣϯΛνΣοΫͯ͠ Έ·͠ΐ͏ɻ Ϧετ 3.11: cloudbuild.yaml steps: - name: gcr.io/cloud-builders/curl args: [ "-sS", "-H", "Metadata-Flavor: Google", "http://metadata.google.internal/computeMetadata/v1/instance/zone", ] *15 https://cloud.google.com/build/docs/speeding-up-builds 54 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
Ϧετ 3.13: δϣϒͷϩέʔγϣϯΛௐࠪ $ gcloud builds submit 2>&1 | grep zones projects/xxxxxxxxxxxxx/zones/us-central1-f ݁Ռʮzones/us-central1-fʯͱදࣔ͞Ε·ͨ͠ɻ͔͠͠ຊʹͦΕͰྑ͔ͬͨͷͰ͠ΐ͏͔ʁ લষͷ ʮCloud Build ͷཪଆͷ͘͠Έʯ Ͱ Cloud Build ʹΑͬͯىಈ͞Εͨίϯςφ͕ɺGCE ্Ͱಈ͍͍ͯΔ͜ͱΛઆ໌͠·ͨ͠ɻ·ͨࠓճ curl Λ࣮ߦͨ͠δϣϒͷଓઌಉ͡ GCE ্ʹଘ ࡏ͢Δ metadata ίϯςφͰ͋Δ͜ͱઆ໌͠·ͨ͠ɻ ࣮ strings ίϚϯυͰ metadata ίϯςφͷΞϓϦέʔγϣϯΛݕࡧ͢Δͱ us-central1-f ͱ ͍͏จݴ͕ຒΊࠐ·Ε͍ͯ·͢ɻ Ϧετ 3.13: metadata ʹຒΊࠐ·ΕͨϦʔδϣϯ $ docker run -it --entrypoint strings gcr.io/cloud-builders/metadata:latest /metadata \ | grep us-central1-f ʙʙলུʙʙ trace StackTab trailing data trigger Ratio=unknown time run supported: us-central1-f user canceled value method xadd64 failed xchg64 failed ʙʙলུʙʙ ͔ͨ͠͠ΒϏϧυδϣϒ͕Ͳ͜Ͱಈ࡞͍ͯ͠Δͷ͔ʹݶΒͣ Ϧετ 3.11 Λ࣮ߦͨ͠ࡍʹຒΊ ࠐ·Εͨ us-central1-f ͕ৗʹදࣔ͞ΕΔͷͰͳ͍Ͱ͠ΐ͏͔ʁ ͜ΕΛ֬ೝ͢ΔͨΊʹ౦ژ (asia-northeast1) ʹཱͯͨϓϥΠϕʔτϓʔϧͰϦετ 3.12 Λ࣮ߦ ͯ͠ɺίϯςφ͔ΒΈͨ VM ϝλσʔλͱίϯςφ͕ଘࡏ͢Δ GCE ͔ΒΈͨ VM ϝλσʔλΛ νΣοΫͯ͠Έ·͢ɻ Ϧετ 3.12: cloudbuild.yaml options: pool: name: ’projects/${PROJECT_ID}/locations/asia-northeast1/workerPools/POOL_NAME’ steps: 55 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
- id: container zone name: gcr.io/cloud-builders/curl args: [ "-sS", "-H", "Metadata-Flavor: Google", "http://metadata.google.internal/computeMetadata/v1/instance/zone", ] - id: virtual machine zone name: "gcr.io/google.com/cloudsdktool/cloud-sdk:cloudbuild_cache" entrypoint: bash args: - -c - | docker_opts=( # ಛݖݖݶΛ༩͢Δ --privileged --ipc=host --net=host --pid=host --rm # chroot ༻ʹϚϯτ͢Δ -v /:/mnt --entrypoint sh # ༻͢ΔΠϝʔδ busybox # args -c "chroot /mnt curl \ -s ’http://metadata.google.internal/computeMetadata/v1/instance/zone’ \ -H ’Metadata-Flavor: Google’ \ " ) docker run "${docker_opts[@]}" waitFor: [’-’] Ϧετ 3.13: ϓϥΠϕʔτϓʔϧ (౦ژ) Ͱͷϩέʔγϣϯͷ֬ೝ $ gcloud builds submit --region asia-northeast1 2>&1 | grep zones Step #0 - "container zone": projects/MY_PROJECT_ID/zones/us-central1-f Step #1 - "virtual machine zone": projects/xxxxxxxxxxxxx/zones/asia-northeast1-c ݁ՌɺGCE ͔ΒΞΫηε͢Δͱ asia-northeast1 ͱදࣔ͞Ε͍ͯ·͕͢ɺίϯςφͰͷ௨৴ us-central1-f ͱදࣔ͞Εͯ͠·͍ͬͯ·͢ɻ͜ͷ݁Ռ͔Β metadata ίϯςφ͕ΞϓϦʹຒΊࠐ· 56 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
Εͨ us-central1-f Λͦͷ··ฦ͍ͯ͠Δઆ͕ೱްʹͳ͖ͬͯ·ͨ͠ɻ ຊͷ global Ͳ͜ʁ Ͱ͍͍ͬͨ Cloud Build ͷ global Λࢦఆ͞ΕͨδϣϒͲ͜Ͱಈ࡞͍ͯ͠ΔͷͰ͠ΐ͏͔ʁ ͦΕΛ͔֬ΊΔͨΊʹ Cloud Build Ͱ༻͢Δ GCE ͕Ͳ͜ͷϦʔδϣϯͰಈ࡞͍ͯ͠Δͷ ͔ʁ ΛϚγϯλΠϓ͝ͱʹ֤ 100 ճͣͭௐࠪͯ͠Έ·ͨ͠ɻ Ϧετ 3.13: cloudbuild.yaml steps: - id: get zone name: "gcr.io/google.com/cloudsdktool/cloud-sdk:cloudbuild_cache" entrypoint: bash args: - -c - | docker_opts=( # ಛݖݖݶΛ༩͢Δ --privileged --ipc=host --net=host --pid=host --rm # chroot ༻ʹϚϯτ͢Δ -v /:/mnt --entrypoint sh # ༻͢ΔΠϝʔδ busybox # shell args -c "chroot /mnt curl \ -H ’Metadata-Flavor: Google’ \ -s ’http://metadata.google.internal/computeMetadata/v1/instance/zone’ \ " 57 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
) docker run "${docker_opts[@]}" ݁ՌΛ·ͱΊͨͷ͕ͪ͜ΒͰ͢ɻ ਤ 3.11: ϚγϯλΠϓผͷ࣮ߦ࣌ؒ δϣϒ࣮ߦճ͕Ұ൪ଟ͍ͷ us-east4 (όʔδχΞभ) Ͱɺ͍ͭͰ us-central1(ΞΠΦϫभ) ͱ ͳ͍ͬͯ·͢ɻ͜ͷ͜ͱ͔Βগͳ͘ͱ Cloud Build ʹ͓͚Δ global ΞϝϦΧͷ͍ͣΕ͔ͷϦʔ δϣϯΛ͍ࣔͯ͠Δͱߟ͑ͯྑ͍Ͱ͠ΐ͏ɻ ·ͱΊΔͱ Cloud Build ͕ global ͷ߹ΞϝϦΧͷϦʔδϣϯͰಈ࡞͍ͯ͠Δ͕ɺδϣϒࣗ ͕ࣗ us-central1-f ʹ͍Δͱࡨ͍֮ͯ͠Δ (metadata ίϯςφ͕ৗʹ us-central1-f Λฦ͢) ͱ ͍͏͜ͱʹͳΓ·͢ɻ GCS ͷྉۚΛ͑Δ Cloud Build ʹ͓͍ͯ Container Registry (Ҏ߱ GCR ͱུ͠·͢) GCS ͔ΒࢿࡐΛμϯ ϩʔυͨ͠ΓɺϏϧυͷՌΛΞοϓϩʔυ͢Δͱ GCS ͷωοτϫʔΫసૹྉ͕ൃੜ͠·͢ɻ (GCS ͷσʔλอྉΦϖϨʔγϣϯྉࠓճߟྀʹೖΕ·ͤΜ) 58 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
ਤ 3.12: GCS ͷωοτϫʔΫసૹྉ *16 ͜ͷ࣌ʮಉ͡ϩέʔγϣϯͷσʔλͷҠಈʯʮϚϧνϦʔδϣϯʹ͋Δ GCS όέοτ͔Β͋ Δ 1 ͭͷϦʔδϣϯʹ͋Δผͷ Google Cloud αʔϏεͷσʔλͷҠಈͰɺ྆ํͷϩέʔγϣϯ ͕ಉ͡େʹ͋Δʯແྉͱॻ͔Ε͍ͯΔͨΊɺGCS ͱ Cloud Build Λಉ͡ϩέʔγϣϯͰಈ ͔͢͜ͱͰωοτϫʔΫసૹྉΛ 0 ԁʹͰ͖·͢ɻ ઌఔͷݕূʹΑͬͯɺglobal ར༻࣌ΞϝϦΧͷϦʔδϣϯͰಈ࡞͍ͯ͠Δ͜ͱ͕Θ͔Γ·ͨ͠ͷ *16 https://cloud.google.com/storage/pricing ΑΓҾ༻ 59 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
Ͱ GCS ΞϝϦΧΛར༻͠·͠ΐ͏ɻ ˙ϝϞ: εςʔδϯάྖҬ (Ұ࣌σʔλ֨ೲྖҬ) Cloud Build ͰҰ࣌తͳσʔλ֨ೲྖҬ (εςʔδϯάྖҬ) ͱͯ͠ GCS Λ༻͠·͢ɻσ ϑΥϧτͰ gs://[PROJECT_ID]_cloudbuild/source ͱ͍͏໊લͰ࡞͞ΕɺΞϝϦΧͷ ϚϧνϦʔδϣϯͰಈ࡞͠·͢ɻ ͦͷͨΊɺCloud Build ͷ global ઃఆΛ͏߹సૹྉ͕ۚൃੜ͠·ͤΜ͕ɺϓϥΠϕʔτ ϓʔϧϋΠϒϦουϓʔϧΛ͏߹ --gcs-source-staging-dir=GCS_SOURCE_STAGI NG_DIR ͷύϥϝʔλΛͬͯɺҙͷϩέʔγϣϯʹσʔλ֨ೲྖҬΛมߋ͢Δඞཁ͕͋Γ ·͢ɻ GCR ͷྉۚΛ͑Δ GCR ͷཪଆ GCS ͷͨΊɺಉ༷ʹ GCS ͷ௨৴ྉͷΈߟྀ͢Ε͋Γ·ͤΜɻ(GCS ͷ σʔλอྉΦϖϨʔγϣϯྉࠓճߟྀʹೖΕ·ͤΜ) ͨͩ͠ GCR ʹΑͬͯϗετ͞ΕΔϩέʔγϣϯ͕มΘΔͷͰ Cloud Build Ͱ docker pull / push ͢ΔΠϝʔδͷ֨ೲॴͳΔ͘ us.gcr.io Λ͏ͱྑ͍Ͱ͠ΐ͏ɻ 60 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
ਤ 3.13: GCR ͷϩέʔγϣϯ *17 ͨͩ͠ɺ֨ೲͨ͠ίϯςφΠϝʔδΛ౦ژେࡕͷϦʔδϣϯͰ༻͢Δ߹ɺίϯςφىಈ࣌ ʹΞϝϦΧ͔Β pull ͢Δ͜ͱʹͳΔͨΊɺͦ͜ͰωοτϫʔΫసૹྉ͕ൃੜͨ͠Γɺμϯϩʔυ ʹ͕͔͔࣌ؒΔΑ͏ʹͳΔͨΊҙ͠·͠ΐ͏ɻϏϧυʹ͏πʔϧΩϟογϡͷஔ͖ΛΞϝϦ Χʹ͢Δ͙Β͍͕ͪΐ͏ͲΑ͍Ԙകͩͱࢥ͍·͢ɻ ·ͱΊ ௨৴ྉۚͷΛ·ͱΊΔͱ͜ͷΑ͏ʹͳΓ·͢ɻ ਤ 3.14: Cloud Build ͱ GCS / GCR ͷ௨৴ྉ *17 https://cloud.google.com/container-registry/docs/overview#registries ΑΓҾ༻ 61 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
͋͘·Ͱඅ༻ͱ͍͏؍ͷΈʹண͍ͯ͠ΔͨΊɺ࣮ࡍʹར༻͢Δࡍ࠷ऴతʹੜͨ͠σʔλ͕ ͲͷΑ͏ʹΘΕΔͷ͔ʁ Λߟྀͯ͠શମతͳઃܭΛߦ͏ඞཁ͕͋Δʹҙ͍ͯͩ͘͠͞ɻ 3. δϣϒΛΩϟϯηϧ͢Δ GitHub ͷ Pull Request ΛτϦΨʹͯ͠ Cloud Build Λಈ͔͍ͯ͠ΔͱɺGit Push ͞Εͨ͢ ͯͷίϛοτʹରͯ͠δϣϒ͕ಈ͍͍ͯΔ͜ͱ͋͘͠Γ·ͤΜɻ ͔ͨ͠ʹෳͷδϣϒ͕ىಈ͢Δͷ͕ਖ਼͍͠ͷͰ͕͢ɺຊʹඞཁͳͷҰ൪࠷ޙʹ Git Push ͞Εͨͱ͖ͷίϛοτʹର͢ΔδϣϒͰ͢ɻ(Ұ൪࠷ޙʹੵ·Εͨίϛοτ͕Ұ൪ਖ਼͍͠ͱ͍͏લఏ Ͱ͢) Cloud Build δϣϒ͕ಈ͍ͨඵʹରͯ͠՝͕ۚߦΘΕΔͨΊɺෆཁͳδϣϒΛ͍ͪૣ͘ Ωϟϯηϧ͢Δ͜ͱͰແବͳඅ༻Λ͑Δ͜ͱ͕Ͱ͖·͢ɻ ·ͨδϣϒʹΑͬͯϦιʔε (σʔλϕʔεςετڥ) ͷઐ༗͕ඞཁͰɺδϣϒͷฒྻ࣮ߦ͕ ڐ༰Ͱ͖ͳ͍δϣϒ͋ΔͰ͠ΐ͏ɻͦΜͳͱ͖ʹɺෆཁͳδϣϒΛΩϟϯηϧ͢Δ͜ͱ CI/CD ͷߴԽʹߩݙ͠·͢ɻ Ͱͬͦ͘͞ Cloud Build ͰδϣϒͷΩϟϯηϧΛ࣮ݱ͢Δํ๏Λݟ͍͖ͯ·͠ΐ͏ɻ Cancelot Cancelot*18 cloud-builders-community Ͱެ։͞Ε͍ͯΔπʔϧͰɺࢦఆͨ݅͠Λຬͨ͢ δϣϒΛΩϟϯηϧͰ͖·͢ɻ ͍ํඇৗʹ୯७ͰΩϟϯηϧΛ࣮ߦ͍ͨ͠δϣϒఆٛͷதʹઃఆΛՃ͢Δ͚ͩͰ͢ɻ ˞ίϯςφΠϝʔδࣗͰ༻ҙ͢Δඞཁ͕͋Γ·͢ Ϧετ 3.14: cloudbuild.yaml steps: - name: "gcr.io/$PROJECT_ID/cancelot" args: [ "--current_build_id", "$BUILD_ID", *18 https://github.com/GoogleCloudPlatform/cloud-builders-community/blob/master/cancelot/README.md 62 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.4 Cloud Build ͷίετΛઅ͢Δํ๏
"--branch_name", "$BRANCH_NAME", "--same_trigger_only", ] ͜ͷఆٛʮࣗͱಉ͡τϦΨ ID ͱ Git ϒϥϯν໊Λ࣋ͭδϣϒΛΩϟϯηϧ͢ΔʯΛҙຯ͠ ͓ͯΓɺݴ͍͑Δͱʮ͋Δ Pull Request ʹෳճ Git Push Λͯ͠ੜ͞ΕͨɺݱࡏՔಇத ͰࣗΑΓલʹ࣮ߦ͞Εͨ Cloud Build δϣϒΛΩϟϯηϧ͢Δʯͱಉ͡ҙຯʹͳΓ·͢ɻ ͨͩ͠೦ͳ͕Βࣥච࣌Ͱ Cancelot ਖ਼͘͠ಈ࡞͠·ͤΜɻҎલಈ࡞͍ͯͨ͠ͷͰ͕͢ Cloud SDK ͷΞοϓσʔτʹ͍ಈ࡞͠ͳ͘ͳͬͨΑ͏Ͱ͢ɻ(ৄࡉ Issue*19 Λ͝ཡ͍ͩ͘͞) ͦͷͨΊ Cancelot Ͱͳ͘ siberex ࢯ͕ެ։͍ͯ͠Δ cancelot.sh*20 ΛͬͯδϣϒͷΩϟϯη ϧΛ࣮ݱͯ͠Έ·͠ΐ͏ɻ͜ͷγΣϧ Cancelot ͱಉ͡ػೳͱΠϯλʔϑΣʔεΛ͍࣋ͬͯ·͢ͷ Ͱɺ΄΅ಉ͡༻ํ๏Ͱར༻͢Δ͜ͱ͕Ͱ͖·͢ɻ Ϧετ 3.15: cloudbuild.yaml steps: - name: "gcr.io/google.com/cloudsdktool/cloud-sdk:slim_cloudbuild_cache" entrypoint: "bash" args: - -c - | # ࣮ߦ͢Δ Git ϦϙδτϦͷϧʔτԼʹ cancelot.sh ͕ # ࣮ߦݖݶ͖Ͱอଘ͞Ε͍ͯΔඞཁ͕͋Γ·͢ ./cancelot.sh \ --current_build_id "$BUILD_ID" \ --branch_name "$BRANCH_NAME" \ --same_trigger_only *19 https://github.com/GoogleCloudPlatform/cloud-builders-community/issues/386 *20 https://gist.github.com/siberex/bb0540b208019382d08732cc6dd59007 63 -
ୈ 3 ষ Cloud Build Λ͍ͦ͏ʂ 3.5 ऴΘΓʹ
˙ϝϞ: cancelot.sh ͷϓϥΠϕʔτϓʔϧͷରԠ cancelot.sh ϓϥΠϕʔτϓʔϧͷδϣϒΩϟϯηϧʹରԠ͍ͯ͠·ͤΜɻ ͱ͍͏ͷϓϥΠϕʔτϓʔϧͰδϣϒΛಈ͔ͨ͢Ίʹ --region ΦϓγϣϯΛ gcloud ί Ϛϯυʹ༩͢Δඞཁ͕͋ΔͷͰ͕͢ɺcancelot.sh ͰͦͷରԠ͕͞Ε͍ͯͳ͍ͨΊͰ͢ɻͦ ͷͨΊϓϥΠϕʔτϓʔϧͰར༻͢Δ߹ cancelot.sh ʹखΛՃ͑ͯ --region Λ֤ gcloud ίϚϯυʹ͚ͭΔΑ͏ʹ͠·͠ΐ͏ɻ 4. ·ͱΊ Cloud Build ͷՁ֨ߏ͔ΒՔಇ͢ΔϦʔδϣϯɺͦͯ͠δϣϒͷΩϟϯηϧΛݟ͖ͯ·ͨ͠ɻCI ͷίετ͍͖ͳΓߴ͘ͳΔͷͰͳ͘ɺঃʑʹ૿Ճͯ͘͠ΔͨΊಋೖ࣌ʹ͋Δఔ CI ͷશମߏ ΛѲͨ͠͏͑Ͱઃܭ͢Δ͜ͱΛ͓קΊ͠·͢ɻ 3.5 ऴΘΓʹ ͜͜·Ͱ͓͖߹͍Λ͍͖ͨͩ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻCloud Build Λͬͱศརʹ͏ํ๏Λ ͍Ζ͍Ζͱհ͍͖ͤͯͨͩ͞·ͨ͠ɻ1 ͭͰࢀߟʹͳΕ͍Ͱ͢ɻ ͠΄͔ͷςΫχοΫπʔϧΛ͝ଘ͡ͷํɺͥͻڭ͍͚͑ͯͨͩ·͢ͱ͍Ͱ͢ʂ 64 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.1 TIPSTAR
ͷ։ൃͱ Google Cloud Spanner TIPSTAR*1ͱචऀ͕։ൃʹܞΘ͍ͬͯΔϛΫγΟࣾͷαʔϏεͰ͢ɻެӦڝٕͷථΛѻͬͯ ͍ΔαʔϏεͰɺं݊ͷߪೖͪΖΜͷ͜ͱɺϨʔεө૾৴ͷ΄͔ɺιʔγϟϧήʔϜͷΑ͏ͳ ϛογϣϯɺϚϧνϓϨΠɺΨνϟߪೖͨ͠ं݊Λࣗͷ༧ͱͯ͠ڞ༗͢ΔͳͲଟ͘ͷػೳΛఏ ڙ͍ͯ͠·͢ɻϝΠϯͷόοΫΤϯυʹ Google Cloud Λ࠾༻͓ͯ͠ΓɺGoogle Cloud Spanner ʢҎԼ: Cloud Spannerʣ Google Kubernetes Engine Λ࢝Ίɺ͞·͟·ͳϓϩμΫτΛ࠾༻͍ͯ͠ ·͢ɻͦͷதͰࠓճ Cloud Spanner ʹ͍ͭͯհ͍ͨ͠ͱࢥ͍·͢ɻ΄͔ʹհ͍ͨ͠ Google Cloud ͷ׆༻ࣄྫ͕͋ΔͷͰ͕͢ɺࠓճׂѪ͠ผͷػձʹհͰ͖Εͱࢥ͍·͢ɻTIPSTAR ͷ ։ൃͰֶΜͩ Cloud Spanner ͷώϯτɺۀͰ Cloud Spanner Λ͏্Ͱҙ͓͖͍ࣝͯͨ͠ϙΠ ϯτͳͲɺҰൠతͳσʔλϕʔεͷཹҙͱަ͑ͳ͕Βհ͠·͢ɻ Google Cloud Spanner ͱ Google Cloud Spanner ਫฏεέʔϦϯά͕ՄೳͰ͋Γɺڧ߹ੑՄ༻ੑΛඋ͍͑ͯΔϑϧϚ ωʔδυͷϦϨʔγϣφϧσʔλϕʔεͰ͢ɻଏʹݴ͏ NewSQL ͱΑΕΔσʔλϕʔεͷҰछͱ ͳΓ·͢ɻྑ͍͜ͱͮ͘͠ͳσʔλϕʔεͳͷͰ͕͢ɺςʔϒϧઃܭΫΤϦઃܭʹෆඋ͕͋Δͱɺ ϗοτεϙοτ͕ൃੜ͠ CPU ͷෛՙ্͕͛ͯ͠·ͬͨΓɺఆ֎ͷͱ͜ΖͰΤϥʔ͕ଟ͘ͳΔՄೳ ੑ͕͋ΔͨΊɺCloud Spanner ͷಛΛཧղ͠ઃܭ͢Δඞཁ͕͋Γ·͢ɻmixi tech note #04*2Ͱ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ͖߹͍ํͱ͍͏ςʔϚͷهࣄ͕͋ΔͷͰɺڵ ຯ͕͋Δํͪ͜Β͝ཡ͍͚ͨͩΕͱࢥ͍·͢ɻ *1 TIPSTAR ɺڝྠɾ৽ KEIRIN PIST6ɾΦʔτϨʔεͷωοτථΛɺ༑ୡͱָ͠Ή͜ͱ͕Ͱ͖ΔαʔϏεͰ͢ɻ https://tipstar.com *2 mixi tech note #04 https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-04 65 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.2 Cloud
Spanner ώϯτू ଟػೳͳ TIPSTAR Λࢧ͑Δ Cloud Spanner TIPSTAR 2020 6 ݄ 30 ͷϩʔϯνҎ߱ɺଟ͘ͷػೳΛϦϦʔε͖ͯ͠·ͨ͠ɻػೳΛ ։ൃ্͍ͯ͘͠ͰͬͯΓͤͳ͍ͷ͕ओཁσʔλϕʔεͰ͋Δ Cloud Spanner ͷଘࡏͰ͢ɻ TIPSTAR ͷػೳ։ൃɺاը৬ͷํ͔ΒΩοΫΦϑϛʔςΟϯάͰػೳཁ͕݅ల։͞Εͨ͋ͱɺ֤ νʔϜ͕࣋ͪؼΓݒ೦Λચ͍ग़͠ɺ։ൃظؒػೳ༰Λ֬ఆ͢Δϑϩʔͱͳ͍ͬͯ·͢ɻΩο ΫΦϑͰ༷ॻ͕ల։͞ΕͨλΠϛϯά͔Βɺ͘ͱαʔόαΠυνʔϜͰٞ͢Δલʹ Cloud Spanner ͷݒ೦Λҙࣝ͢Δ͜ͱΛ৺͕͚͍ͯ·͢ɻݒ೦Λҙࣝ͢Δ͜ͱͰϦϦʔεલͰઃܭ ϛε͕ൃ֮͠खΓ͕ى͖ͨΓɺϦϦʔεޙʹఆ֎ͷෛՙΤϥʔ͕ຄൃ͢Δͱ͍ͬͨՄೳੑΛܰ ݮͰ͖·͢ɻ 4.2 Cloud Spanner ώϯτू ຊઅͰ TIPSTAR ͷ։ൃΛ͢Δ্Ͱීஈ͔Βҙ͍ࣝͯ͠Δ Cloud Spanner ͷཹҙΛհ ͠·͢ɻࠓճσʔλϕʔεʹ͍߹ΘͤΛߦ͏ API Λ։ൃ͢Δ্ͰͷཹҙͱͳΔͷͰ Cloud Spanner ʹݶͬͨ͠Ͱͳ͘ɺRDB NoSQL ͱ͍ͬͨ΄͔ͷσʔλϕʔεʹڞ௨͢Δݟ ؚ·Ε·͢ɻ͜Ε͔Β Cloud Spanner Λ༻͢Δ༧ఆͷํͪΖΜͷ͜ͱɺσʔλϕʔεઃܭͷ ܦݧ͕ઙ͘͜Ε͔ΒֶΜͰ͍͖͍ͨͱࢥ͍ͬͯΔํͷࢀߟʹͳΕ͍Ͱ͢ɻ ΠϯλʔϦʔϒ Cloud Spanner ʹΠϯλʔϦʔϒͱݺΕΔςʔϒϧͷࢠؔΛఆٛ͢Δએݴ͕͋Γ·͢ɻ ΠϯλʔϦʔϒ͞ΕͨࢠςʔϒϧͷϨίʔυͱςʔϒϧͷϨίʔυɺಉ͡εϓϦοτ*3ʹอଘ͞ ΕΔͨΊɺσΟεΫΞΫηεͱωοτϫʔΫτϥϑΟοΫΛ࠷খݶʹ͑Δ͜ͱ͕Ͱ͖·͢ɻ ͨͱ͑ҎԼͷΑ͏ͳ User ςʔϒϧͱ User ͷཤྺςʔϒϧͷಋೖΛݕ౼ͨ͠ͱ͖ɺUser ཤྺ ඞͣ User ͕ଘࡏ͍ͯ͠Δ͜ͱ͕݅Ͱ͋ΓɺUser ͕ࣗࣗͷཤྺΛಡΈࠐΉͱ͍ͬͨཁ͕݅͋Δ ͱ͠·͢ɻ͜ͷ߹ڞ௨͍ͯ࣋ͬͯ͠Δ user_id Λ༻͍ͯݕࡧ͢ΔఆͰ͢ɻ͜ͷ߹ΠϯλϦʔ ϒͰࢠؔΛ࡞Γɺusers ςʔϒϧʹ͋ΔϢʔβʔ A ͞Μͷใͱ user_histories ςʔϒϧʹ͋ ΔϢʔβʔ A ͞Μͷཤྺใཧతʹಉ͡ετϨʔδʹσʔλ͕อଘ͞ΕΔͨΊɺಡΈࠐΈͷύ ϑΥʔϚϯε্͕ظͰ͖·͢ɻ CREATE TABLE users ( user_id STRING(36) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, ) PRIMARY KEY (user_id) *3 Cloud Spanner ओΩʔͷൣғʹΑͬͯςʔϒϧΛׂ͓ͯ͠Γɺͦͷׂ͞Εͨ୯ҐΛεϓϦοτͱݺͿ 66 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.2 Cloud
Spanner ώϯτू CREATE TABLE user_histories ( user_history_id STRING(36) NOT NULL, user_id STRING(36) NOT NULL, history_id STRING(MAX) NOT NULL, state STRING(MAX) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, ) PRIMARY KEY (user_history_id) INTERLEAVE Λ͍ users ͱ user_histories Λࢠؔʹ͢Δɻ CREATE TABLE users ( user_id STRING(36) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, ) PRIMARY KEY (user_id); CREATE TABLE user_histories ( user_history_id STRING(36) NOT NULL, user_id STRING(36) NOT NULL, history_id STRING(MAX) NOT NULL, state STRING(MAX) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, ) PRIMARY KEY (user_id, user_history_id), INTERLEAVE IN PARENT users ON DELETE NO ACTION; ҙ͍ࣝͨ͠ϙΠϯτ: ΠϯλϦʔϒͰ͖ͳ͍͔ߟ͑Δ users user_histories ͷΑ͏ͳΠϯλϦʔϒͰࢠؔͱͳΔςʔϒϧΛ࡞Εͳ͍͔ߟ͑ΔͱΑ ͦ͞͏Ͱ͢ɻϢʔβʔάϧʔϓͱ͍ͬͨ͋Δଐੑ͕ͭσʔλΛཧ͢Δςʔϒϧͷ߹ɺ͜ͷ ΠϯλϦʔϒΛ͑Δέʔε͕ଟ͍ҹͰ͢ɻ ϗοτεϙοτ͕ൃੜ͠ͳ͍͔ Cloud Spanner ओΩʔͷࣙॻॱʹϨίʔυ͕ฒΜͰ͓ΓʢσϑΥϧτঢॱʣ ɺΩʔͷൣғʹԠ ͯ͡ςʔϒϧΛׂ͠ɺεϓϦοτͱ͍͏୯Ґʹ͚ Spanner ϊʔυσʔλΛׂΓͯ·͢ɻͦ ͷߏͨΊओΩʔ͕୯ௐ૿Ճ͢ΔΑ͏ͳΛ༻͢Δͱ৽͍͠Ϩίʔυ࠷ޙͷεϓϦοτʹՃ͞ Ε·͢ɻ ಉҰͷεϓϦοτʹ͕อଘ͞Εͯ͠·͏ͱɺͦ͜ʹϦΫΤετ͕ूத͠ϗοτεϙοτ͕ൃੜ ͢ΔՄೳੑ͕͋Γ·͢ɻͦͷͨΊओΩʔʹγʔέϯγϟϧͳΛೖΕΔͷඇਪͱͳ͓ͬͯΓɺ UUID v4 Λ͏͜ͱ͕ਪ͞Ε͍ͯ·͢ɻ͜ͷݱΠϯσοΫεͰಉ͕͡ൃੜ͠·͢ɻ 67 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.2 Cloud
Spanner ώϯτू ΠϯσοΫε෦ͰςʔϒϧͷΑ͏ͳߏͰ࣮͞Ε͍ͯΔͨΊɺΠϯσοΫεͰ୯ௐ૿Ճ· ͨݮগ͢ΔΛΘͳ͍͜ͱ͕ਪ͞Ε͍ͯ·͢ɻͨͩ͠ΠϯλϦʔϒ͞ΕͨΠϯσοΫεͰ͋Ε εϓϦοτׂ͞Ε͍ͯΔͨΊ͋Γ·ͤΜɻ ҙ͍ࣝͨ͠ϙΠϯτ: ओΩʔʹγʔέϯγϟϧͳΛΘͳ͍ ओΩʔʹ UUID v4 Λ͏ɻͱʹ͔͘ओΩʔʹ୯ௐ૿Ճ·ͨݮগ͢ΔγʔέϯγϟϧͳΛ ༻͠ͳ͍ɻCloud Spanner Λ͏্Ͱ࠷ॳͷํʹհ͞ΕΔݒ೦ͷͨΊɺ͋ΒͨΊͯ܁Γฦ͢ ༰Ͱͳ͍ͱࢥ͍·͕͢ɺCloud Spanner Λ͏্ͰॏཁͳϙΠϯτͱͳΔͷͰհ͠·ͨ͠ɻ ಡΈࠐΈ ಡΈࠐΈϑϧεΩϟϯ͕Βͳ͍͔ͳͲجຊతͳҙΛ࢝ΊɺରϨίʔυ͕ಉҰͷεϓϦοτ Ͱݕࡧͳͷ͔ Spanner શϊʔυΛލ͙ݕࡧͱͳΔ͔Λҙࣝͯ͠ઃܭ͢Δඞཁ͕͋Γ·͢ɻΞϓϦ έʔγϣϯͷ༷ཁ݅ʹΑͬͯશϊʔυݕࡧฒͼସ͕͑ඞਢͱͳΔέʔεଟʑ͋Δͱࢥ͏ͷͰ ղܾͷώϯτΛհ͠·͢ɻ ݕࡧର͕நతͰϊʔυΛ͑ͨݕࡧ͍ͨ͠ͱ͖ લड़ͷ User ཤྺςʔϒϧͷ߹ɺuser_id Λࢦఆࣗ͠ͷཤྺͷΈΛݕࡧ͢Δͷ͕Ұ൪ޮͷྑ ͍ΫΤϦͱͳΔͷͰ͕͢ɺόονॲཧͳͲͰશϢʔβʔͷத͔Βಛఆͷ history_id ͱ state Λࢦఆ ͠ରϨίʔυΛநग़͍ͨ͜͠ͱ͋Δͱࢥ͍·͢ɻͦΜͳͱ͖ shard_key ΛՃ͠ઐ༻ͷΠϯ σοΫεΛ࡞Δ͜ͱͰϑϧεΩϟϯΛճආͰ͖·͢ɻ CREATE TABLE user_histories ( user_history_id STRING(36) NOT NULL, user_id STRING(36) NOT NULL, shard_key INT64 NOT NULL, history_id STRING(MAX) NOT NULL, state STRING(MAX) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, ) PRIMARY KEY (user_id, user_history_id), INTERLEAVE IN PARENT users ON DELETE NO ACTION; CREATE INDEX idx_user_histories_shard_key_history_id_state ON user_histories(shard_key, history_id, state); ΞϓϦέʔγϣϯଆ͔Βݺͼग़͢ͱ͖ҎԼͷΑ͏ͳΫΤϦͰݕࡧ͠·͢ɻཁ݅ʹΑΔͱࢥ͍· ͕͢ɺͪ͜ΒͷΫΤϦશϊʔυΛލ͙ݕࡧͱͳΔͷͰɺΞϓϦέʔγϣϯଆͰ༻͍ͨ͠ΧϥϜΛ ߜΓɺ͞Βʹ WHERE ۟Λ͍ state Ҏ߱ʹରϨίʔυΛߜΔͱΞϓϦέʔγϣϯαʔόͷϝ ϞϦͷ༻ྔΛ͑ΒΕ·͢ɻ 68 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.2 Cloud
Spanner ώϯτू SELECT user_id, history_id FROM user_histories WHERE shard_key BETWEEN 0 AND 99 AND state = "finish"; ҙ͍ࣝͨ͠ϙΠϯτ: ݕࡧൣғ͕͍ͱ͖ shard_key ͷՃΛݕ౼͢Δ shard_key ͷൣғʹ͍ͭͯޙड़Ͱ৮Ε·͕͢ɺ0-99 ͳͲൣғΛܾΊΞϓϦέʔγϣϯଆͰ ϥϯμϜͰઃఆ͢Δͱྑ͍Ͱ͠ΐ͏ɻ ฒͼସ͕͑ඞཁͳςʔϒϧ͔ ཤྺͷΑ͏ͳςʔϒϧͷ߹৽͍͠ॱʹݕࡧ͍ͨ͠ͱ͍ͬͨཁ͕݅Ͱͯ͘Δ͜ͱ͋Δͱࢥ͍· ͢ɻCloud Spanner ͰओΩʔͷࣙॻॱʢσϑΥϧτঢॱʣʹϨίʔυ͕ฒΜͰ͍ΔͨΊɺͦͷ· ·ιʔτ͕ඞཁͳݕࡧʹཱͯΔ͜ͱ͕Ͱ͖·͢ɻํ๏ user_history_id ΛλΠϜελϯϓؚ͕ ·ΕΔ ID Λಋೖ͠ɺDESC Λࢦఆ͢Δ͜ͱͰ߱ॱͰϨίʔυ͕อଘ͞Ε·͢ɻςʔϒϧ࡞࣌ʹܾ Ί͓ͯ͘ඞཁ͕͋ΔͷͰɺΞϓϦέʔγϣϯͷ༷ཁ݅ͱͯ߱͠ॱͰऔΓ͍͔ͨͳͲઌʹԡ͓͑ͯ͞ ͖͍ͨϙΠϯτͰ͢ɻଞͷฒସ͕͑ඞཁʹͳͬͨ߹ΠϯσοΫεͷՃͰରԠͰ͖·͢ɻ CREATE TABLE user_histories ( user_history_id STRING(36) NOT NULL, user_id STRING(36) NOT NULL, shard_key INT64 NOT NULL, history_id STRING(MAX) NOT NULL, state STRING(MAX) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, ) PRIMARY KEY (user_id, user_history_id DESC), INTERLEAVE IN PARENT users ON DELETE NO ACTION; ҙ͍ࣝͨ͠ϙΠϯτ: ฒͼସ͑ʹओΩʔͷಛੑΛར༻Ͱ͖ͳ͍͔ݕ౼͢Δ DESC ࢦఆ͞Εͨ ID ࣌ܥྻʹฒΔඞཁ͕͋ΔͷͰɺULID*4ͳͲΛ͏ͱྑ͍Ͱ͠ΐ͏ɻ ॻ͖ࠐΈ σʔλϕʔεͷॻ͖ࠐΈɺظతʹ୯ҰϨίʔυͷॻ͖ࠐΈ͕ूத͠ϩοΫͪΛൃੜͤ͞ ͨΓɺෛՙΛ͋͛ͯ͠·Θͳ͍͔ͳͲҙ͕ඞཁͰ͢ɻ·ͨ Cloud Spanner mutations ͱݺΕ Δ୯Ґ͕͋ΓɺҰʹॲཧͰ͖Δྔͷ੍ݶ͋ΔͷͰͦͪΒհ͠·͢ɻ *4 Universally Unique Lexicographically Sortable Identifier ͷུͰɺཚͱλΠϜελϯϓΛؚΜͰ͓Γɺ ॏෳ͠ͳ͍Ұҙͳ ID ͔ͭɺϛϦඵ୯ҐͰ࣌ܥྻͳιʔτ͕Մೳͳ ID 69 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ
ϦΞϧλΠϜө͕ඞਢͰͳ͍έʔε ΞϓϦέʔγϣϯͷ༷ཁ݅ʹΑͬͯɺ୯ҰϨίʔυߋ৽͕ଟ͘ͳΔ͜ͱ͋Δͱࢥ͍·͢ɻ ͦΜͳͱ͖ߋ৽සΛԼ͛ΒΕͳ͍͔ݕ౼͢ΔͱΑͦ͞͏Ͱ͢ɻ ྫ͑ SNS ͷʮ͍͍ͶʯߘͷӾཡͳͲɺඞͣ͠ϦΞϧλΠϜͷՃࢉ͕ඞཁͰͳ͍έʔ ε͕ଟ͍Ͱ͢ɻ ඇಉظͷߋ৽Ͱ͕ͳ͍߹ɺҰ࣌αʔόͷϝϞϦͳͲʹΛՃࢉ͓͖ͯ͠ɺҰఆ͕࣌ؒܦա ͨ͠Βσʔλϕʔεө͢Δͱ͍ͬͨ͜ͱΛݕ౼͢Δͱྑͦ͞͏Ͱ͢ɻ·ͨσʔλͷܽଛ͕ڐ༰ Ͱ͖ͳ͍߹ɺ͋ΔΧϥϜͷΛݟͯߋ৽༰Λมߋ͍ͨ͠߹ Cloud Pub/Sub ͷΑ͏ͳϝο ηʔδΩϡʔΠϯάͷಋೖ͕͓קΊͰ͢ɻ τϥϯβΫγϣϯ Cloud Spanner 1 ճͷτϥϯβΫγϣϯʹ͖ͭ 20,000 mutations ҎԼʹ͢Δͱ੍͍ͬͨݶ͕ ͋Γ·͢ɻmutations ͱ INSERTɺUPDATEɺDELETE ͳͲΛૢ࡞͢Δ࣌ͷ୯ҐͰ͋ΓมߋΛ Ճ͑ΔߦɺྻɺΠϯσοΫεͳͲͰ͕ܾ·Γ·͢ɻ20,000 mutations Λ͑ͦ͏ʹͳͬͨ ߹τϥϯβΫγϣϯΛ͚ɺඇಉظૠೖ͢ΔΑ͏ͳσʔϞϯϫʔΧΛ࡞͢Δඞཁ͕͋Γ·͢ɻ mutations ͷܭࢉ Commit statistics*5 spanner-cli*6ͷ -v ΦϓγϣϯͰ֬ೝՄೳͰ͢ɻτϥϯ βΫγϣϯΛ͚Δ߹ෆ߹͕ൃੜ͢ΔϦεΫ͕͋ΔͷͰɺCloud Pub/Sub ͳͲͷϝοηʔδ ΩϡʔΠϯάαʔϏεΛ׆༻͠ɺΤϥʔ͕͋ͬͨͱͯ͠τϥϯβΫγϣϯ͕ޭ͢Δ·Ͱ࠶࣮ߦ͞ ΕΔ͘͠Έʹ͢Δͷ͕·͍͠Ͱ͢ɻ 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ ͜͜·Ͱ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner ͷώϯτΛհ͠·ͨ͠ɻຊઅͰ࣮ࡍʹ TIPSTAR ͷ։ൃͰ͋ͬͨέʔεΛࢀߟʹɺ࠷ऴతʹͱͬͨߦಈͳͲΛհ͠·͢ɻ ෆಛఆଟͷϢʔβʔ͕ಡΈॻ͖͢ΔςʔϒϧΛ࡞Γ͍ͨ ෆಛఆଟͷϢʔβʔʹΑΔಡΈॻ͖Λఆ͠ɺ͞Βʹ a_countɺb_countɺc_count ͱ͍͏Χϥ ϜΛ༻ҙ͠ɺͦΕͧΕιʔτΓ͍ͨͱ͍ͬͨཁ͕݅͋Γ·ͨ͠ɻॻ͖ࠐΈΑΓಡΈࠐΈස͕ ѹతʹଟ͍ςʔϒϧͷͨΊಡΈࠐΈͷύϑΥʔϚϯεΛ࠷༏ઌͱ͍ͯ͠·͢ɻ ఆ͍ͯ͠Δςʔϒϧ ҎԼͷΑ͏ͳςʔϒϧͰ͋Γɺtype_id Λࢦఆ͠ରϨίʔυΛநग़͢ΔఆͰ͢ɻ *5 Commit statistics https://cloud.google.com/spanner/docs/commit-statistics *6 spanner-cli https://github.com/cloudspannerecosystem/spanner-cli 70 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ
CREATE TABLE user_posts ( user_post_id STRING(36) NOT NULL, user_id STRING(36) NOT NULL, type_id STRING(36) NOT NULL, a_count INT64 NOT NULL, b_count INT64 NOT NULL, c_count INT64 NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, ) PRIMARY KEY (user_id, user_post_id), INTERLEAVE IN PARENT users ON DELETE NO ACTION; ιʔτʹ༏ઌॱҐ͕͋ΓɺಡΈࠐΈͷΫΤϦཁ݅ύλʔϯଘࡏ͠·͢ɻ 1. a_count 2. b_count 3. c_count SELECT * FROM user_posts where type_id = "xxx" ORDER BY a_count DESC, b_count DESC, c_count DESC; SELECT * FROM user_posts where type_id = "xxx" ORDER BY b_count DESC, a_count DESC, c_count DESC; SELECT * FROM user_posts where type_id = "xxx" ORDER BY c_count DESC, a_count DESC, b_count DESC; ͜ͷΑ͏ͳཁ͕݅͋ͬͨͱ͖ʹɺҙ͍ࣝͨ͠ϙΠϯτ̏ͭ͋Γ·ͨ͠ɻ • ಡΈࠐΈͷίετ • ॻ͖ࠐΈͷίετ • ॻ͖ࠐΈ࣌ͷϗοτεϙοτͷݒ೦ ಡΈࠐΈͷίετ ಡΈࠐΈͷίετΛԼ͍͛ͨ߹ɺҰൠతʹಡΈࠐΈͷ༷ཁ݅ʹԠͯ͡ΠϯσοΫεΛՃ͢ ΔͱύϑΥʔϚϯε্͕ظͰ͖·͢ɻॻ͖ࠐΈͷίετΛҙࣝͯ͠ΠϯσοΫεΛՃ͠ͳ͍ͱ ͍͏Ҋ͋Γ·͕͢ɺ SELECT * FROM user_posts where type_id = "xxx" 71 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ
ORDER BY a_count DESC, b_count DESC, c_count DESC; ্هͷΑ͏ͳΫΤϦΛൃߦͨ͠ͱ͖ʹ where type_id = "xxx"Ͱສɾेສͱ͍ͬͨϨίʔ υͩͬͨ߹ɺͦΕΛͯ͢ιʔτ͢ΔͱͳΔͱ CPU ࣌ؒΛඵͬͯ͠·͏Մೳੑ͕͋Δͨ ΊɺಡΈࠐΈίετΛԼ͍͛ͨ߹ૉʹɺa_countɺb_countɺc_count ΧϥϜΛΠϯσοΫε ʹؚΊͨ΄͏Αͦ͞͏Ͱ͢ɻ CREATE INDEX idx_user_posts ON user_posts(type_id, a_count DESC, b_count DESC, c_count DESC); ॻ͖ࠐΈͷίετ ࣍ʹಡΈࠐΈͷίετΛԼ͛ΔͨΊʹɺa_count, b_count, c_count ΧϥϜΛΠϯσοΫεʹؚ Ίͨ߹ͷॻ͖ࠐΈͷίετΛߟ͑ͯΈ·͢ɻҰൠతʹΠϯσοΫεΛ࡞͢ΔͱɺͦͷΠϯσοΫ εʹؚΊͨΧϥϜͷߋ৽ϕʔεςʔϒϧͱͷ 2-Phase Commit ʹͳΔͨΊ (ΠϯλϦʔϒΠϯσο ΫεͰͳ͍߹)ɺॻ͖ࠐΈͷϨΠςϯγ͕एׯѱԽ͢Δ͜ͱʹͳΓ·͢ɻ·ͨ a_count, b_count, c_count ΧϥϜ͕සൟʹߋ৽͞ΕΔͷͳΒɺͦΕͧΕͷߋ৽ͷʹΠϯσοΫεߋ৽͕ΔͷͰͦ Είετ͕͕͋ΔཁҼͱͳΔՄೳੑ͕͋Γ·͢ɻ͜ΕΒͷ՝Λղফ͢ΔͨΊʹɺલઅͰհͨ͠ ඇಉظʹߋ৽͢Δ͘͠ΈΛಋೖΛ͢Δͱྑͦ͞͏Ͱ͢ɻ·ͨ Cloud Spanner ͷ Node ΛՃ͠ॻ͖ ࠐΈΛࢄ͢Δ͜ͱͰॻ͖ࠐΈͷίετΛԼ͛Δ͜ͱͰ͖·͢ɻ ॻ͖ࠐΈ࣌ͷϗοτεϙοτͷՄೳੑ a_count, b_count, c_count ΧϥϜΛΠϯσοΫεʹؚΊͨ߹ʹɺॻ͖ࠐΈ࣌ʹϗοτεϙο τ͕Ͱ͖ΔՄೳੑ͕͋Γ·͢ɻCloud Spanner ͰΠϯσοΫεςʔϒϧͱಉͷߏΛ͍ͯ͠ Δͱ͞Ε͍ͯ·͢ɻࠓճͷ user_posts ςʔϒϧͷεΩʔϚͰ͢ͱɺσʔλԼهͷΑ͏ʹอଘ͞Ε ͍ͯ·͢ɻ ද 4.1: user_posts ςʔϒϧͷσʔλΠϝʔδ user_id user_post_id type_id a_count b_count c_count user_id_1 user_post_id_1 type_id_1 8 3 10 user_id_2 user_post_id_2 type_id_1 9 8 3 user_id_3 user_post_id_3 type_id_1 9 7 3 user_id_4 user_post_id_4 type_id_1 10 9 7 ͪ͜Βͷςʔϒϧʹର͠ɺ 72 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ
CREATE INDEX idx_user_posts ON user_posts(type_id, a_count DESC, b_count DESC, c_count DESC); ্هͷΑ͏ͳΠϯσοΫεΛ࡞͢ΔͱҎԼͷΑ͏ͳΠϯσοΫεςʔϒϧ͕࡞͞Ε·͢ɻ ද 4.2: ΠϯσοΫεςʔϒϧͷσʔλΠϝʔδ type_id a_count b_count c_count user_id user_post_id type_id_1 10 9 7 user_id_4 user_post_id_4 type_id_1 9 8 3 user_id_2 user_post_id_2 type_id_1 9 7 3 user_id_3 user_post_id_3 type_id_1 8 3 10 user_id_1 user_post_id_1 ͭ·Γ͜ͷΠϯσοΫε type_id ͷঢॱ ˠ a_count ͷ߱ॱ ˠ b_count ͷ߱ॱ ˠ c_count ͷ ߱ॱ ˠ user_id ͷঢॱ ˠ user_post_id ͷঢॱͰϨίʔυ͕ฒͿఆͱͳΓ·͢ɻa_count ͕Ұ ൪༏ઌॱҐ͕ߴ͍ͨΊ a_count ͷ͕Ұ൪େ͖͍ user_id_4 ͷϨίʔυ͕Ұ൪্ʹ͖·͢ɻ ϗοτεϙοτ͕ൃੜ͢Δͷɺ͜ͷΠϯσοΫεʹରͯ͠ɺ • ৗʹઌ಄ʹϨίʔυ͕ૠೖ͞ΕΔ • ৗʹ࠷ޙʹϨίʔυ͕ૠೖ͞ΕΔ • ৗʹ్தͷͲ͔͜ͷϨίʔυҎ߱ʹૠೖ͞ΕΔ ͷ͍ͣΕ͔ͷύλʔϯ͕ى͖ɺ͔ͭͦͷ QPS ͕ߴ͍߹ʢྫ: ୯Ұͷ Spanner ϊʔυͷ࠷େॻ͖ ࠐΈ 2,000QPS) ͱͳΓ·͢ɻTIPSTAR ͰࠓճͷΑ͏ͳέʔεͷςʔϒϧΛઃܭͨ͠ࡍେ͖ ͳ͓͖ͳ͍ͱஅ͠ɺ࣮ࡍʹॻ͖ࠐ·ΕΔΛͨ͠ϕϯνʔϚʔΫΛ࣮ࢪ͠ͳ͍͜ͱΛ ֬ೝ͍ͯ͠·͢ɻ·ͨϗοτεϙοτͷ*7load-based splitting Ͱղফ͞ΕΔͱਪଌ͍ͯͨ͠ ͨΊɺҰ࣌తʹϨΠςϯγ͕ѱԽ͙ͯ͢͠ʹղফ͞ΕΔఆͰ͍·ͨ͠ɻ ࠷ऴతʹͱͬͨߦಈ ಡΈࠐΈͷύϑΥʔϚϯεΛ࠷༏ઌ͓ͯ͠ΓɺࣄલͷෛՙςετͰେ͖ͳݒ೦͕ͳ͔ͬͨͨ ΊɺಡΈࠐΈཁ݅ʹԠͨ͡ιʔτΞϊςʔγϣϯΛ͖ͷઐ༻ͷΠϯσοΫεΛ࡞͢Δ͜ͱͰରԠ ͠·ͨ͠ɻ *7 load-based splitting ɹෛՙ্ঢʹΑͬͯςʔϒϧ͕εϓϦοτׂ͞ΕΔ͘͠Έɻσʔλྔ૿ՃʹΑͬͯεϓϦοτ ׂ͞ΕΔɺsize-based spliting ͱ͍͏ͷ͋Δɻ 73 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ
shard_key ͷௐ લઅͰ shard_key Λ͍ͪͨΠϯσοΫεͷհΛ͠·͕ͨ͠ɺ͜ͷ shard_key ൣғ࣌ͱ߹ ʹΑͬͯௐͨ͠΄͏͕·͍͠έʔε͕͋Γ·͢ɻ͋Δςʔϒϧʹରͯ͜͠ͷΑ͏ͳΠϯσοΫε ͷՃΛߦ͓͏ͱ͠·ͨ͠ɻ CREATE INDEX idx_user_posts_shard_key_code_id ON user_posts(shard_key, code, id); ͜ͷςʔϒϧʹରͯ͠ಡΈࠐΈͷෛՙࢼݧΛ࣮ࢪͨ͠ͱ͜ΖɺύϑΥʔϚϯε͕ѱ͔ͬͨͨΊɺ shard_key ൣғΛ 0-99 ͔Β 0-1 ͷൣғมߋͯ͠Έ·ͨ͠ɻ͢Δͱ݁ՌతʹಡΈࠐΈͷύϑΥʔϚ ϯε্͕͠·ͨ͠ɻ͜Ε 0-1 ͷൣғʹมߋ͢Δ͜ͱͰεϓϦοτͷࢄ͕ݮΔͨΊॻ͖ࠐΈϨ Πςϯγ͕͋Γ·͕͢ɺ݁ՌతʹಡΈࠐΈͷύϑΥʔϚϯε্͕͕Γ·ͨ͠ɻൣғ͕ 0ʙ1 ͚ͩͰ ͋ͬͨͱͯ͠ɺগͳ͘ͱ 2 ͭͷαʔόʹॻ͖ࠐΈΛࢄ͞ΕΔ͜ͱ͕ظͰ͖ΔͷͰɺಡΈࠐ ΈͷύϑΥʔϚϯεΛ༏ઌ͠ shard_key Λ 0ʙ1 ʹ͠·ͨ͠ɻͪ͜ΒͷέʔεͰظతʹେྔͷ ॻ͖ࠐΈ͕ൃੜ͢ΔςʔϒϧͰͳ͔ͬͨͷͰ 0ʙ1 ͷ shard_key ൣғͰͳ͘ಈ࡞ͯ͠·͢ɻ Optimizer ͷௐ GROUP BY Λ͢ΔΫΤϦͰΦϓγϣϯͷઃఆΛ͢Δ͜ͱͰύϑΥʔϚϯε্͕ͨ͠έʔε͕ ͋ͬͨͷͰհ͠·͢ɻ CREATE INDEX idx_user_posts_shard_key_code_id ON user_posts(shard_key, code, id); ͷΠϯσοΫεΛ༻͍ͨΫΤϦͰ id Λऔಘ͍ͨ͠έʔε͕͋Γ·ͨ͠ɻid ͷ༷ UUID ͷΑ͏ ͳҰҙͳ ID Ͱͳ͘ɺ͋ΔಛఆͷࣄฑΛࣔ͢ڞ௨Ͱ͑Δ ID Ͱ͢ɻ SELECT id FROM user_posts WHERE shard_key BETWEEN @shared_key_min AND @shared_key_max AND code IN UNNEST(@codes) AND id IN UNNEST(@ids) GROUP BY id ্هͷΑ͏ʹ GROUP BY ࢦఆͰಛఆͷ ID Λݕࡧ͢Δ߹ɺ GROUPBY_SCAN_OPTIMIZATION Λࢦఆ͢ΔͱύϑΥʔϚϯε্͕Ί·͢ɻ 74 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.3 ࣮ࡍͷέʔεʹج͍ͮͨղܾྫ
SELECT id FROM user_posts@{GROUPBY_SCAN_OPTIMIZATION=TRUE} WHERE shard_key BETWEEN @shared_key_min AND @shared_key_max AND code IN UNNEST(@codes) AND id IN UNNEST(@ids) GROUP BY id ͜ͷΦϓγϣϯΛࢦఆ͢Δͱɺ͢Ͱʹಉ͡ id ͕εΩϟϯࡁͷ߹ͦ͜ͰεΩϟϯ͕தࢭ͞Ε࣍ͷ id ͷεΩϟϯʹҠΔڍಈΛߦͬͯ͘Ε·͢ɻΑͬͯಉҰͷ id ͕ଟ͚Εଟ͍΄Ͳ͜ͷޮՌ͕ߴ͘ͳ Δ͜ͱ͕ΊΔͷͰɺͥͻ׆༻͍ͨ͠ΦϓγϣϯͰ͢ɻ΄͔ͷ SQL ߏจʹ͍ͭͯͬͱΓ͍ͨͱ ͍͏ํɺQuery syntax in Google Standard SQL*8 Λ͝ࢀর͍͚ͨͩΕͱࢥ͍·͢ɻ ຊ൪ͷσʔλΛ҆શʹमਖ਼͢Δ ΞϓϦέʔγϣϯͷෆ۩߹ʹΑΓɺҰ෦ͷσʔλ͕ҙਤ͠ͳ͍Ͱอଘ͞ΕಛఆͷΧϥϜͷΛम ਖ਼͍ͨ͠έʔεʹ͍ͭͯߟ͑ͯΈ·͢ɻͪ͜ΒέʔεҰൠϢʔβʔʹӨڹ͠ͳ͍ܰඍͳमਖ਼Λఆ ͓ͯ͠Γɺमਖ਼༰ͱରϨίʔυͷநग़͕Ͱ͖Δલఏͱ͠·͢ɻ ରϨίʔυͷநग़ ͜ͷΑ͏ͳέʔεͷ߹ఆͨ͠நग़Ͱͳ͍ͨΊɺΠϯσοΫε࡞͓ͯ͠Βͣநग़͕ࠔ ͳ߹͕͋Γ·͢ɻͦͷͨΊࣄલʹ BigQuery ͳͲʹόοΫΞοϓͨ͠σʔλ͔ΒରϨίʔυΛࢉ ग़͓ͯ͘͠ඞཁ͕͋Γ·͢ɻΞϓϦέʔγϣϯͷෆ۩߹ʹΑΔͷͰ͋ͬͨ߹ɺෆ۩߹ൃੜ࣌ ͔Βमਖ਼͕ө͞Εͨ࣌ͷൣғͰରϨίʔυΛ୳͢ͱྑͦ͞͏Ͱ͢ɻࠓճΧϥϜͷमਖ਼ͱͳΔ ͨΊɺରϨίʔυͷओΩʔΛࣄલʹऔಘ͓͖ͯ͠·͢ɻ ରΧϥϜΛ҆શʹߋ৽͢Δ ରϨίʔυͷओΩʔΛநग़ͨ͋͠ͱɺ͍Α͍Αमਖ਼࡞ۀͱͳΓ·͕͢ɺ͜͜Ͱ͍͔ͭ͘ϙΠ ϯτ͕͋Γ·͢ɻ • ్தτϥϯβΫγϣϯΤϥʔͳͲͰεΫϦϓτ͕ࣦഊͨ͠ͱͯ͠࠶ࢼߦͰ͖ΔΑ͏ʹႈੑ Λ୲อͨ͠࡞Γʹ͓ͯ͘͠ • ରϨίʔυ͕ଟ͍߹τϥϯβΫγϣϯͷ mutatios Τϥʔ͕ൃੜ͠ͳ͍Α͏ߟྀ͢Δ • ຊ൪ͷσʔλϕʔεʹӨڹ͕Ͱͳ͍Α͏ɺΫΤϦͷ*9Priority Λ Low ࢦఆ͠༏ઌͰ࣮ߦ ͢Δ *8 Query syntax in Google Standard SQL https://cloud.google.com/spanner/docs/reference/ standard-sql/query-syntax#sql_syntax *9 Priority ʹ LowɺMediumɺHigh ͕͋Γɺঢ়گʹԠͯ͡ CPU ༻͕ௐ͞Ε·͢ɻͨͱ͑ High ͷ ॲཧ͕ଟ͍ͱ͖ Low ͷ CPU ༻࠷େ 60% ʹͳΓ·͢ɻ https://cloud.google.com/blog/topics/ developers-practitioners/introducing-request-priorities-cloud-spanner-apis 75 -
ୈ 4 ষ TIPSTAR ͷ։ൃͰֶΜͩ Cloud Spanner Tips 4.4 ऴΘΓʹ
Ҏ্ͷϙΠϯτΛ͑ͨमਖ਼εΫϦϓτΛ༻ҙ͠ରԠ͢ΔͱΑͦ͞͏Ͱ͢ɻ 4.4 ऴΘΓʹ ຊষͰ TIPSTAR ͷ։ൃΛ௨ͯ͡ಘͨ Cloud Spanner ͷ Tips Λհ͠·ͨ͠ɻσʔλϕʔ εʹ Cloud Spanner Λ࠾༻͍ͯ͠ΔҎ্ɺͦͷಛΛ༷͑ͭͭཁ݅Λཧ͢Δஈ֊Ͱݒ೦ Λચ͍ग़͓ͯ͘͜͠ͱ͕·͍͠ͱײ͍ͯ͡·͢ɻCloud Spanner ͷجຊతͳ֓೦ͪΖΜͰ ͕͢ɺҎલݒ೦ͩͬͨՕॴ͕ΞοϓσʔτʹΑΓࠓղফ͞Ε͍ͯΔͱ͍ͬͨ͜ͱ͋ΔͷͰɺ QueryOptimizer ΫϥΠΞϯτϥΠϒϥϦΛ࢝Ί Cloud Spanner ͷ੍ݶ؇ͳͲͷΞοϓσʔτ ʹΛ͚͓ͯ͘ͱྑͦ͞͏Ͱ͢ɻචऀ͕ܦݧͨ͠ҰྫΛ͋͛ΔͱɺҎલΠϯλϦʔϒͰ͖Δα Πζʹ্ݶ͕͋Γ·͕ͨ͠ɺݱࡏ͜ͷ੍ݶ͕ͳ͘ͳ͍ͬͯ·͢ɻ͜Ε͔Β Cloud Spanner ͷಈ Λ͍ͳ͕ΒɺTIPSTAR ͷ։ൃʹߩݙͰ͖ΔΑ͏νʔϜҰಉਫ਼ਐ͍ͨ͠ͱߟ͍͑ͯ·͢ɻಉ͡Α ͏ʹ Cloud Spanner Λ༻͍ͯ͠Δํɺ͋Δ͍͜Ε͔Β Cloud Spanner ͷಋೖΛݕ౼͍ͯ͠Δํ ʹຊষ͕গ͠ͰࢀߟʹͳΕ͍Ͱ͢ɻ 76 -
ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ ͬͯΈͨ 5.1 ͡Ίʹ 2021 4
݄ɺචऀ TIPSTAR*1 ͱ͍͏αʔϏεͷ։ൃΛ͍ͯ͠ΔʮTIPSTAR ։ൃ෦ γες Ϝ 2 άϧʔϓʢγεςϜ 2Gʣ ʯͷϚωδϟʔʹब͖ɺΕͯʮΤϯδχΞϦϯάϚωδϟʔ (EM)ʯ ͱͯ͠ͷΩϟϦΞΛาΈ࢝Ί·ͨ͠ɻ ຊষͰɺචऀ͕ EM ͱͯ͠ͲͷΑ͏ͳߦಈΛऔΓɺͲͷΑ͏ͳ͜ͱΛߟ͑ͨͷ͔Λड़·͢ɻ ରಡऀ EM ʹब͍͔ͨΓͷಉࢤͷํɺ͢Ͱʹ EM ͱͯ͠͝׆༂͞Ε͍ͯΔํɻͦͯ͠ɺEM Λࢤͯ͠ ͍Δํɻ 5.2 ϛΫγΟʹ͓͚ΔϚωδϟʔɾEM υϥοΧʔʮϚωδϝϯτʲΤοηϯγϟϧ൛ʳ ʯ *2ͷதͰɺϚωδϟʔΛʮ৫ͷՌʹΛ ࣋ͭऀʯͱఆ͍ٛͯ͠·͢ɻ ϛΫγΟάϧʔϓʹ͓͍ͯɺϚωδϝϯτʹٻΊΒΕΔׂͱͯ͠ʮ৫Ռͷ࠷େԽʯΛܝ ͍͛ͯ·͢ɻͦͷׂΛՌͨͨ͢Ίʮ৫ͷΰʔϧΛఆΊΔʯ ʮ৫ͷϑΥʔϝʔγϣϯΛΉʯ ʮ ৫͕ΰʔϧ͔͑ΔΑ͏ʹࢦش͢Δʯ ʮ৫ͷϝϯόʔΛҭ͢Δʯͱ͍͏ 4 ͭͷ۩ମతߦಈΛఆ Ί͍ͯ·͢ɻ EM ͱͯ͠ͷϙδγϣϯ͕໌֬ʹଘࡏ͍ͯ͠ΔΘ͚Ͱͳ͘ɺචऀͷϙδγϣϯʮΤϯδχΞ ৫ͷϚωδϟʔʯͰ͋Δͱݴ͑·͢ɻͦͷͨΊɺଟ༷ͳಇ͖ํɾׂΛ࣋ͬͨ EM ͕ଘࡏ͍ͯ͠ ·͢ɻ *1 TIPSTAR ɺڝྠɾ৽ KEIRIN PIST6ɾΦʔτϨʔεͷωοτථΛɺ༑ୡͱָ͠Ή͜ͱ͕Ͱ͖ΔαʔϏεͰ͢ɻ https://tipstar.com/ *2 https://www.diamond.co.jp/book/9784478410233.html 77 -
ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ͬͯΈͨ 5.3 γεςϜ 2G ͱ 5.3 γεςϜ
2G ͱ ͯ͞ɺචऀ͕Ϛωδϝϯτ͍ͯ͠ΔʮγεςϜ 2Gʯ *3ʹ͍ͭͯ؆୯ʹઆ໌͠·͢ɻ γεςϜ 2G ɺϝϯόʔ͕ 5 ໊ఔͰɺશһ͕αʔόαΠυΞϓϦέʔγϣϯΠϯϑϥͷε ϖγϟϦςΟΛ͍࣋ͬͯ·͢ɻචऀɺٕज़ʹඇৗʹਂ͍Θ͚Ͱͳ͍ͷͰɺϝϯόʔʹ͍Ζ͍Ζڭ ΘͬͨΓ࣭ͨ͠Γ͠ͳ͕ΒमߦΛ͍ͯ͠Δͱ͜ΖͰ͢ɻ ͜ͷ৫ͷͻͱ·ͣͷϛογϣϯʮϢʔβʔͷՁఏڙͷ࠷େԽʯͰ͢*4ɻTIPSTAR 2020 6 ݄ͷϩʔϯνҎདྷɺʑଟ͘ͷࢪࡦͷ։ൃ͕ਐΈɺʑͷ৽ػೳΛϢʔβʔʹఏڙ͍ͯ͠ ·͢ɻ͜Ε·ͰશΤϯδχΞϝϯόʔ͕৽ػೳ։ൃʹྗ͍ͯ͠·͕ͨ͠ɺ2021 4 ݄ʹγες Ϝ 2G Λ৫͠ɺ༷ࡦఆɾ։ൃɾϦϦʔεɾϢʔβʔ͔ΒͷϑΟʔυόοΫΛड͚ΔαΠΫϧΛΑ Γૣ͘ճͨ͢Ίͷ͘͠Έͮ͘ΓΛ͢Δ͜ͱʹ͠·ͨ͠ɻಛʹɺϦʔυλΠϜΛ͘͢ΔͨΊʹඞཁͳ ͞·͟·ͳࢪࡦʹऔΓΈ·͢ɻ ·ͨɺ10 ݄ʹϩʔϯν͞Εͨ PIST6*5 ͷϓϥοτϑΥʔϜγεςϜͱ TIPSTAR ͱΛଓ͢Δ ͨΊͷϚΠΫϩαʔϏεͷ։ൃߦ͍ͬͯ·ͨ͠ɻTIPSTAR ʹ͓͚Δ PIST6 ͷ༷ݕ౼ΑΓ ઌʹϓϥοτϑΥʔϜγεςϜͱͷ࿈ܞ෦ΛઌΜ࣮ͯ͢͡Δ͜ͱͰɺϝΠϯετϦʔϜͷ։ൃϦ ιʔεΛ TIPSTAR ͷػೳ։ൃͷΈʹྗͤ͞Δ͜ͱ͕తͰ͢ɻ 5.4 EM ͱͯ͠औΓΜͩ͜ͱ γεςϜ 2G ߹ͷΑ͍͜ͱʹɺචऀ͕ EM ʹब͘λΠϛϯάͰ৽ઃ͞ΕͨάϧʔϓͰ͢ɻά ϧʔϓͱͯ͠ͷΰʔϧɾϛογϣϯνʔϜ࡞Γ͔ΒؔΘΔ͜ͱ͕Ͱ͖·͢ɻ EM ʹब͘ʹ͋ͨͬͯҎԼΛࣗͷׂͩͱఆٛ͠·ͨ͠ɻ • ৫ͷՌΛ࠷େԽ͢ΔͨΊɺ ʮՌʯͷఆٛΛ໌֬ʹߦ͍ɺ ʮ࠷େԽʯ͢ΔͨΊͷαϙʔτΛ ͢Δ͜ͱ • ֎ͷνʔϜͱͷϋϒʹͳΔ͜ͱ • ϝϯόʔͷҭϞνϕʔςΟϯάΛؚΊͨϐʔϓϧϚωδϝϯτϦιʔείϯτϩʔϧΛ ͢Δ͜ͱʹΑΓ҆ఆͨ͠ՌΛ͋͛ΒΕΔΑ͏ʹ͢Δ͜ͱ චऀ͚ࣗͬͯ͠ΤϯδχΞϦϯάೳྗ͕ߴ͍ͱ͍͏Θ͚Ͱͳ͘ɺר͖ࠐΈೳྗ՝ղܾ ͷ࢟ͳͲΛධՁͯ͠Β͍Ϛωδϟʔʹब͔ͤͯΒͬͨͱࢥ͍ͬͯ·͢ɻϝϯόʔͷ΄͏͕ٕज़ తεΩϧѹతʹ্Ͱ͢ͷͰɺ൴ΒͷਐΉ͖ಓΛ໌Β͔ʹ͠ɺ҆৺ͯ͠ಥ͖ਐΜͰΒ͑Δڥ Λ࡞Δ͜ͱʹઐ೦͢Δͷ͕ࣄͰ͋Δͱཧղ͍ͯ͠·͢ɻ ͦͷׂΛ͔ͬ͠Γ͠ͱ͛ΔͨΊɺ ʮ৫ͷΰʔϧΛఆΊΔʯ ʮ৫ͷϑΥʔϝʔγϣϯΛΉʯ *3 ຊͬͱεϚʔτͳ໊લʹ͍͚ͨ͠ΕͲɺϐϯͱ͘Δ໊લ͕·ͩࢥ͍ු͔ͣʜɻ *4 ݱঢ়ͷγεςϜ 2G ͕Ռͨͦ͏ͱ͍ͯ͠Δׂɺࠓޙ։ൃνʔϜ͕ओମతʹߦ͏͜ͱ͕·͍͠ͱߟ͍͑ͯΔͨΊɺ γεςϜ 2G ͕ࠓޙͲͷΑ͏ͳ׆ಈΛ͍͔ͯ͘͠Λݱࡏઈࢍݕ౼தɻ *5 ʮPIST6ʯɺ6 ਓͷબख͕ͨͪ 1 प 250 ̼ͷόϯΫΛ 6 प͠ɺ࠷͘ΰʔϧͨ͠ऀ͕উར͢ΔࣗసंڝٕͰ͢ɻઍ ༿ެԂʹ͋Δ TIPSTAR DOME CHIBA Ͱ΄΅ຖिܹಆ͕܁Γ͛ΒΕ͍ͯ·͢ɻ https://pist6.com/ 78 -
ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ͬͯΈͨ 5.4 EM ͱͯ͠औΓΜͩ͜ͱ ʮ৫͕ΰʔϧ͔͑ΔΑ͏ʹࢦش͢Δʯ ʮ৫ͷϝϯόʔΛҭ͢Δʯͱ͍͏ 4
ͭͷ؍Ͱ৫ͮ ͘ΓʹऔΓΈ·ͨ͠ɻ ৫ͷΰʔϧΛఆΊΔ Ϛωδϟʔʹब͍͔ͯΒͷؒɺ ʮPIST6 ͱͷଓ͢ΔͨΊͷϚΠΫϩαʔϏεΛ࡞Δʯͷ ͕άϧʔϓͷେ͖ͳϛογϣϯͰͨ͠ɻͦͷͨΊɺͦͷظؒ TIPSTAR ͷ։ൃঢ়گͦͷ՝Λ ͔ͬ͠Γ؍͠ɺߟ͢Δظؒͱͯ͠ඇৗʹ༗ҙٛͰͨ͠ɻ ·্ͣ࢘΄͔ͷϚωδϟʔͱձ͠·ͨ͠ɻཁ͢ΔͱɺϢʔβʔͷػೳఏڙͷΛ্ ͍ͤͨ͞ʢ։ൃΛ্͍ͨ͠ʣͱ͍͏ཁ͕ڧ͍Α͏Ͱͨ͠ɻ ϝϯόʔͱͨ͘͞ΜٞΛ͠·ͨ͠ɻͦͷதͰग़͖ͯͨٞɺClean Architecture ͷΑ͏ͳ ϨΠϠʔυΞʔΩςΫνϟͷΑ͏ʹͳ͍ͬͯΔͷͷ UseCase ͕ް͘ͳΓ͍͗ͯ͢Δ*6ͱ͔ɺͦΕ ʹΑͬͯςετίʔυͰέʔεΛेʹཏͰ͖͍ͯͳ͍ͱ͔ɺΞϓϦέʔγϣϯͷϏϧυͱσϓϩ ΠΛ͍ͨ͠ͱ͔ɻ ϝϯόʔͱͷձͰ্͕͍ͬͨٞͣΕ՝ͦͷͷͷΈͳΒͣɺԿ͔͠Βͷ՝ʹରॲ͢ ΔͨΊͷखஈଟ͍Α͏ʹײ͡ΒΕ·ͨ͠ɻͦ͜Ͱɺ ʮͳΜͰͦͷٞΛʰ՝ʱͱͱΒ͑ͨͷͩΖ ͏ʁʯͱ͍͏͍͔͚Λͯ͠Έ·ͨ͠ɻͦͷ݁Ռݟ͖͑ͯͨͷɺকདྷతʹࢦ͍͖͍ͯͨ࢟͠ͱݱ ঢ়ͱͷဃɺͦͯ͠ͳͥͦͷ࢟Λࢦ͍ͨ͠ͷ͔ͱ͍͏ϝϯόʔͷҙࢥͰͨ͠ɻ ্ҐϨΠϠϝϯόʔϨΠϠɺ͍ͣΕʮόάͷগͳ͍ΞϓϦέʔγϣϯΛΑΓૣ͘Ϣʔβʔʹ ಧ͚͍ͨʯͱ͍͏ࢥ͍͕͋Γɺͦ͜Λΰʔϧɾϛογϣϯͱ͢Δͷ͕దͩΖ͏ͱߟ͑·ͨ͠ɻͦ͜ ͰγεςϜ 2G ͷϛογϣϯʮϢʔβʔͷՁఏڙΛ্࣭ͤ͞Λຏ͖ଓ͚Δʯͱ͠·͠ ͨɻՁఏڙɾԾઆݕূʹऔΓֻ͔Δ·ͰͷεϐʔυΛ্ͤ͞Δ͜ͱͰɺαʔϏεվળͷεϐʔυ Λຏ্͖͛ΔͨΊͷࢪࡦΛଧͭάϧʔϓͰ͋Δͱ໌֬ʹఆٛ͢Δ͜ͱͰɺ֤ϝϯόʔͷऔΓΉۀ ʹର͢Δ՝Λ໌֬ʹͰ͖ΔΑ͏ʹͳͬͨͷͰͳ͍͔ͱࢥ͍·͢ɻ ҰํͰɺ·ͩظઢͰγεςϜ 2G ͕ͲͷΑ͏ʹ׆༂͍͔ͯ͘͠ݕ౼தͰ͢ɻ͜͜ʹ͍ͭͯ Ҿ͖ଓ͖ϝϯόʔ্ͱٞΛਂΊ͍͖ͯ·͢ɻ ্هͰهࡌͨ͠ϛογϣϯΛ͛͠ΔͨΊɺFY2022 ԼظҎԼͷ՝ʹऔΓΉ͜ͱʹ͠· ͨ͠ɻ ։ൃνʔϜͷύϑΥʔϚϯεࢦඪΛΥον͢Δ Google ͷ DevOps Research and Assesment νʔϜཱ͕֬ͨ͠ Four Keys*7 ͱ͍͏ 4 ͭͷࢦඪ Λ༻͍ͯɺݱঢ়ͷ TIPSTAR αʔόαΠυΞϓϦέʔγϣϯ։ൃνʔϜͷύϑΥʔϚϯεΛΥο νͰ͖ΔΑ͏ʹ͠·͢ɻऔΓΉ͖՝Λ໌֬Խ͠ɺͦΕͧΕͷࢪࡦͷޮՌΛܭଌ͢Δࢦඪͱͯ͠ ༻͍·͢ɻ *6 ϏδωεϩδοΫ Domain ʹɺUseCase ॲཧͷϑϩʔͱӬଓԽͷॲཧΛஔ͘Α͏ʹ͍ͨ͠ͱ͍͏ࢥ͕ͩͬͨɺ UseCase ʹϏδωεϩδοΫ͕ʹ͡Έग़ͯ͠·͍ͬͯΔঢ়ଶɻ *7 https://cloud.google.com/blog/ja/products/gcp/using-the-four-keys-to-measure-your-devops-performance 79 -
ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ͬͯΈͨ 5.4 EM ͱͯ͠औΓΜͩ͜ͱ αʔόαΠυΞϓϦέʔγϣϯͷσϓϩΠϑϩʔͷ؆ܿԽ ݱঢ়ɺCircleCI ্ͰΞϓϦέʔγϣϯͷϏϧυͱσϓϩΠΛߦ͓ͬͯΓɺαʔόαΠυΞϓϦ
έʔγϣϯͷ Git ϦϙδτϦ্ʹσϓϩΠʹؔ͢Δϑϩʔ͕هࡌ͞Ε͍ͯ·͢ɻҰํͰɺTerraform Kubernetes ͷ Manifest ͳͲΛཧ͢Δ ops ϦϙδτϦଘࡏ͓ͯ͠ΓɺͦͪΒʹΞϓϦέʔ γϣϯͷσϓϩΠϑϩʔ͕هࡌ͞Ε͍ͯΔঢ়ଶͰ͢ɻͦͷͨΊɺσϓϩΠʹؔ͢ΔઃఆΛมߋ͍ͨ͠ ߹ʹɺͦΕͧΕͷϦϙδτϦʹมߋΛՃ͑Δඞཁ͕͋Γɺඇৗʹࡶʹͳͬͯ͠·͍ͬͯ·͢ɻ৽ ؔ͘͠ΘΔϝϯόʔཧղͮ͠Β͍ঢ়گͱͳΓɺى͜Γ͍ͨ͢Ίɺ͜ΕΛվળ͠·͢ɻ ۩ମతʹɺΞϓϦέʔγϣϯͷϦϙδτϦϏϧυ͕ɾops ͷϦϙδτϦσϓϩΠ͕ɺ ͱ໌֬ʹΛ͢Δ͜ͱͱ͠·͢ɻ͢ͳΘͪɺCIOps ͔Β GitOps ʹมߋ͍ͯ͘͠ͱ͍͏͜ͱ ʹͳΓ·͢ɻ ࠓظɺϏϧυͱσϓϩΠΛ͢Δ͜ͱͱɺGitOps ʹ͢ΔͨΊͷϚΠϧετʔϯͷ໌֬ԽΛਐ Ί·͢ɻ αʔόαΠυΞϓϦέʔγϣϯΞʔΩςΫνϟͷվળܒ׆ಈ ઌʹड़ͨͱ͓ΓɺαʔόαΠυΞϓϦέʔγϣϯͷ UseCase ͕ް͘ͳΓ͍͗ͯ͢Δͱ͍͏՝ ʹऔΓΈ·͢ɻ͜ΕʹΑΓɺదͳςετ͕ߦΘΕ͍ͯͳ͍ʢదͳςετέʔεΛཏͰ͖ͯ ͍ͳ͍ʣͱ͍͏͕ੜ͍ͯ͡·͢ɻ ͦ͜ͰɺҎԼͷ 2 ͭͷΞϓϩʔνʹऔΓΈ·͢ɻ • ͜͏͍͏࣮Α͍ͶʗΑ͘ͳ͍Ͷ Λ໌֬ʹ͠ɺυΩϡϝϯτԽ • طଘͷ UseCase ࣮ςετͷվળΛߦ͍ɺ։ൃϝϯόʔʹϨϏϡʔͯ͠Β͏ ଞʹɺUseCase ͷೝతෳࡶςετΧόϨοδͷܭଌͱ͍͏Ҋ͋ΔͷͰɺͦΕΒͷखஈ ݕ౼͠·͢ɻ ৫ͷϑΥʔϝʔγϣϯΛΉ ৫ͷΰʔϧظͷϛογϣϯ͕໌֬ʹͳͬͨͱ͜ΖͰɺݱঢ়ͷϝϯόʔͷεϖγϟϦςΟຊਓ ͷر͢ΔΩϟϦΞύεɾʹ͚ͭͯ΄͍͠εΩϧͳͲΛՃຯ͠ɺ৫ͷϑΥʔϝʔγϣϯΛݕ౼͠ ·͢ɻ ֤ϝϯόʔͷՁ؍ڧΈ/ऑΈΛ 1on1 ͳͲͰ֬ೝͨ͠͏͑ͰɺϝϯόʔͷׂΛఆٛ͠·ͨ͠ɻ ςοΫϦʔυͷΑ͏ͳׂΛ͓ئ͍͢ΔϝϯόʔɺϦʔμʔͱͯ͠ͷ׆༂Λظ͢Δϝϯόʔɺ΄ ͔ͷνʔϜͱίϛϡχέʔγϣϯΛऔΓͳ͕ΒࣄΛਪਐ͢ΔྗΛ͚ͭͯΒ͍͍ͨϝϯόʔͳͲ ͳͲɻ ݱࡏγεςϜ 2G ͷԼʹϝϯόʔΛஔ͍ͯ͠Δঢ়گͰ͕͢ɺαʔϏεʹର͢Δׂ͝ͱ ʹνʔϜΛ࡞Δ͜ͱݕ౼͍ͯ͠·͢ɻظతͳ৫ͷϛογϣϯΛݕ౼ͨ͠͏͑Ͱɺࠓޙͷମ੍Λ ݕ౼͢Δ༧ఆͰ͢ɻ 80 -
ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ͬͯΈͨ 5.5 ͜Ε͔ΒΓ͍ͨ͜ͱ ৫͕ΰʔϧ͔͑ΔΑ͏ʹࢦش͢Δ ղܾ͍ͨ͠՝ͱͦͷͨΊͷํੑ͋ΔఔઌͰ໌֬ʹͳ͍ͬͯΔͨΊɺͦΕͧΕͷ՝ʹϝϯ όʔ͕͔ͬ͠ΓͱऔΓΊΔΑ͏ɺҎԼͷΑ͏ͳऔΓΈΛ͍ͯ͠·͢ɻ •
֤՝ʹϝϯόʔΛΞαΠϯ͠ɺ۩ମతͳखஈͦͷϝϯόʔͷࡋྔͰܾఆ͢ΔʢΦʔφʔ γοϓΛൃشͯ͠Β͍ɺϦʔυͯ͠Β͏ʣ • ि࣍ͷఆྫͰਐΜͰ͍Δ͜ͱΛνʔϜͰڞ༗͢Δ – ํੑͷೝࣝ߹Θͤͱɺݟڞ༗͕త – ϙδςΟϒͳՌʹؔͯ͠ΈΜͳͰশ͑߹͏ චऀࣗݸผͷ՝Λ࣋ͨͣɺͦΕͧΕͷ՝ղܾͷαϙʔτΛߦ͍·͢ɻఆྫͰͦΕͧΕͷࢪ ࡦͷํੑεέδϡʔϧײͷೝࣝ߹ΘͤΛ͢Δ͜ͱͰɺඞཁͳஅΛߦͬͨΓɺಈػ͚ͮɾํੑ ͷೝࣝ߹ΘͤͳͲΛߦ͍·͢ɻ ৫ͷϝϯόʔΛҭ͢Δ લड़ͷʮ֤՝ʹϝϯόʔΛΞαΠϯ͠ɺ۩ମతͳखஈͦͷϝϯόʔͷࡋྔͰܾఆ͢Δʯͱ͍͏ Γํҭͷଆ໘ඇৗʹڧ͍Ͱ͢ɻγεςϜ 2G ͕औΓΉ՝ɺγεςϜ 2G ͷΈͳΒͣ΄ ͔ͷνʔϜͷϝϯόʔͷר͖ࠐΈΛඞཁͱ͢Δͷ͕ଟ͋͘Γ·͢ɻ͕ͨͬͯ͠ɺ֤ϝϯόʔʹϦʔ μʔγοϓεέδϡʔϦϯάͷೳྗ͕ߴ͘ٻΊΒΕɺલ͖ʹࣄΛߦ͢Δೳྗ͕ٻΊΒΕ· ͢ɻϦʔμʔγοϓͷൃشͷ͠ํΛ֤ϝϯόʔ͕࣮ફ͠ɺ͢ͰʹϦʔμʔγοϓͷೳྗ͕ߴ͍ϝϯ όʔ͕ΑΓΑ͍ਐΊํΛΞυόΠε͢Δ͜ͱͰɺࠓޙͷ৫ͱͯ͠ͷڧ͞ɺ֤ϝϯόʔͷՁΛߴ ΊΔ͜ͱΛҙ͍ࣝͯ͠·͢*8ɻ ·ͨɺΞαΠϯ͢Δ՝ϝϯόʔͱ૬ஊ͠ͳ͕Βܾఆ͠·͢ɻܾͯ͠ৄ͘͠ͳ͍ྖҬͰ͋ͬͯ ɺຊਓ͕৳͍ͨ͠ྖҬͰ͋Ε҆৺ͯͤ͠Δ͜ͱ͕Ͱ͖ΔΑ͏͓ޓ͍͕αϙʔτͰ͖Εͱ ࢥ͍ͬͯ·͢ɻ 1on1 ִिͰߦ͍ͬͯ·͢ɻςʔϚ͔ͬ͠ΓͱܾΊ͓ͯΒͣɺ֤ϝϯόʔ͔ΒఏҊͯ͠Β ͏Α͏ʹ͍ͯ͠·͢ɻ͕ͳ͍ͱ͖ʹɺࡶஊͰऴΘΔ͜ͱ͋ΕɺΩϟϦΞʹ͍ͭͯͷΛ͠ ͨΓɺ࠷ۙͷߦಈʹؔ͢ΔϑΟʔυόοΫΛͨ͠Γ͍ͯ͠·͢ɻ·ͩ·ͩ 1on1 ͷεΩϧߴΊΒΕ Δͱײ͡ΔͷͰɺճΛॏͶͳ͕ΒɺϞνϕʔςΟϯάίʔνϯάͳͲͷख๏Λʹண͚͍͚ͯΕ ͱࢥ͍·͢ɻ 5.5 ͜Ε͔ΒΓ͍ͨ͜ͱ γεςϜ 2G ͜Ε·Ͱड़ͨΑ͏ʹɺ৽͘͠࡞ͬͨ৫Ͱ͋ΓɺͲͷΑ͏ʹࣄۀՌʹߩݙͯ͠ ͍͔͘Λࡧ͍ͯ͠Δஈ֊Ͱ͢ɻ͔͠͠ͳ͕Βɺ͢Ͱʹଟ͘ͷՌΛ͢͜ͱ͕Ͱ͖͍ͯ·͢ɻ *8 ͪΖΜɺखΛಈ͔͢͜ͱ͕࠷ॏཁͳͷͰϝϯόʔʹԠͯ͡ෛՙ͕େ͖͘ͳΓ͗͢ͳ͍Α͏චऀ͕αϙʔτ͠·͢ɻ 81 -
ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ͬͯΈͨ 5.5 ͜Ε͔ΒΓ͍ͨ͜ͱ • ৫։ൃΛ၆ᛌ͠ɺվળΛ࣮ࢪ – ൃੜͨ͠Πϯγσϯτʹର͢ΔޮՌతͳ࠶ൃࢭࡦͷ࣮ࢪ
∗ Τϥʔ͕దʹ Trace ͞Ε͍ͯͳ͔ͬͨ ˰ దʹ Trace ͞Εͳ͍Α͏ͳΤϥʔΛ PR ্Ͱܯࠂ͢Δ Linter ͷՃ ∗ Ξοϓσʔτ͞Εͨ͘ͳ͍σʔλ͕ߋ৽͞Ε͍ͯͨ ˰ Go ͷ struct tag Λ༻͍ͯߋ ৽Λ͙Α͏ͳ͘͠Έͮ͘Γ ∗ اը୲ऀͷϚελσʔλೖߘϛε͕ଟ͔ͬͨ ˰ PR ্ͰϨϏϡʔΛ͘͢͢͠Δ ͘͠Έͮ͘Γ – ։ൃͷɾ࣭ͷ্ ∗ CircleCI ͷ config ϑΝΠϧ͕େ͔ͭॏෳͨ͠ॲཧ͕ଟ͔ͬͨͨΊ matrix job ʹ ΑͬͯεϦϜԽ ∗ Table Driven Test ͷڭ ∗ TIPSTAR ͷ֤ΫϥΠΞϯτͱڞ༗͍ͯ͠Δ IDL Λཧ͢ΔϦϙδτϦΛαʔόα ΠυΞϓϦέʔγϣϯͷϦϙδτϦ͔Β ∗ ٸᬎඞཁͱͳΔγεςϜͷΠϯϑϥߏஙͱϊϋͷੵ • PIST6 ͷαʔϏε։ൃͱӡ༻ – ϝΠϯετϦʔϜͷ։ൃΑΓઌߦͯ͠ணख͢Δ͜ͱͰɺϓϩμΫτ։ൃͷΛอͬͨ· ·ϦϦʔε – ӡ༻Λݟਾ͑ͨཧը໘ͷ࣮ – TIPSTAR ىҼͰͷ PIST6 োΛىͣ͜͞ӡ༻ ϝΠϯͷ։ൃνʔϜ͔ΒҰาҾཱ͍ͨͪҐஔͰ՝Λݟ͚ͭɺղܾࡦΛଧ͍ͬͯ͘ͱ͍͏ϙδ γϣϯ͔ͩΒͦ͜औΓΊͨ՝ଟ͋͘Γ·͢ɻ·ͨɺͦΕΒΛ࣋ͬͯଟ͘ͷϊϋΛάϧʔ ϓʹཷΊࠐΉ͜ͱ͕Ͱ͖·ͨ͠ɻ ࠓޙͷେ͖ͳςʔϚҎԼͷ 2 ͭʹͳΔ͔ͱࢥ͍·͢ɻ ։ൃ৫αʔϏεͷঢ়گͷϞχλϦϯά TIPSTAR Ͱʑଟ͘ͷࢪࡦΛ։ൃ͍ͯ͠·͕͢ɺͦΕΒͷύϑΥʔϚϯε։ൃ৫ͷঢ়ଶΛ ͔ͬ͠ΓͱϞχλϦϯά͍ͨ͠ͱࢥ͍ͬͯ·͢ɻզʑͷϛογϣϯʮϢʔβʔͷՁఏڙͷ ࠷େԽʯͰ͢ɻͨͱ͑ো͕ൃੜͨ͠Βɺͦͯͦ͠ͷো͕Ҿ͘ͱવ։ൃͷखΛΊͯௐࠪɾ ϢʔβʔରԠΛߦ͏ඞཁ͕ग़͖ͯ·͢ɻোΛى͜͞ͳ͍γεςϜͮ͘ΓɺͦΕΛͰ͖Δ৫ͮ͘ ΓΛ͍ͯ͘͠ඞཁ͕͋Γ·͢ɻ ͍͍ͬͨԿ͕ݪҼͰো͕ى͜Δͷ͔Λ͔ͬ͠Γߟ͠ɺվળ͍ͯͨ͘͠ΊʹϞχλϦϯάඇ ৗʹॏཁͩͱߟ͍͑ͯ·͢ɻͦͷͨΊͷج൫ͮ͘ΓʹऔΓΜͰ͍͖·͢ɻ 82 -
ୈ 5 ষ ΤϯδχΞϦϯάϚωδϟʔ͘Β͍ͬͯΈͨ 5.6 ·ͱΊ ։ൃͷվળΛϝΠϯετϦʔϜͷ։ൃ৫͕औΓΉαϙʔτ γεςϜ 2G ։ൃͷվળʹશྗͰऔΓΜͰ͍·͢ɻཧͱ͢Δͱ͜Ζɺ͜ΕΒͷվળΛγε
ςϜ 2G ͚͕ͩߦ͏ͷͰͳ͘ɺ։ൃͷϝΠϯετϦʔϜ͕ओମతʹվળʹऔΓΊΔঢ়ଶʹ͢Δ͜ ͱͰ͢ɻͦ͏͍ͬͨจԽ͘͠ΈΛ࡞͍ͬͯ͘͜ͱ͕զʑͷ࠷ऴతͳඪͰ͋ΓɺͦΕΛ͛ͨ͠ ͱ͖ʹϛογϣϯΛୡͨ͠ͱݴ͑Δͱࢥ͍ͬͯ·͢ɻ ͦͷͨΊʹɺυΩϡϝϯτͰ͋ͬͨΓɺطଘͷΞϓϦέʔγϣϯ։ൃελΠϧɾϫʔΫϑϩʔ ͷվળͳͲ͕ඇৗʹॏཁͰ͢ɻγεςϜ 2G ͕ࣗϦʔμʔγοϓΛ࣋ͬͯͦ͏͍ͬͨΛ࡞ͬͯ ͍͘͜ͱɺͦͯͦ͠ͷϊϋΛେऺԽ͍͖ͯ͠·͢ɻ 5.6 ·ͱΊ EM ͕Ռׂ͖ͨ͢ͱʮϝϯόʔͷεϖγϟϦςΟΛ׆͔͠ɾ৳͠ͳ͕Β৫Ռʹߩݙ͠ ͍ͯ͘͜ͱʯͰ͋Δͱɺ͜ͷͪΐͬͱͰؾ͘͜ͱ͕Ͱ͖·ͨ͠ɻͦͷͨΊʹ EM ɺ֤ϝϯ όʔͷεϖγϟϦςΟΛѲ͢Δඞཁ͕͋Δ͠ɺͦΕΒʹֶ͍ͭͯͿඞཁ͕͋Γ·͢ɻͦͯ͠·ͨ αʔϏεʹؔΘΔ৫શମͷঢ়گώτɾϞϊɾΧωͷಈ͖Λཧղͨ͠͏͑Ͱɺࣗͨͪͷ৫͕Ͳ ͜Λࢦ͢ͷ͔໌֬ʹࣔ͢͜ͱ͕ॏཁͰ͢ɻ ͱ͍͏͍ظؒͰ͋Γ·͕͢ɺͨ͘͞ΜΈɺ౻͠ɺવࣦഊͨ͘͞Μ͖ͯ͠·͕ͨ͠ɺ ͦΕʹ͍͖ͭͯͯ͘Εͯͨ͘͞ΜͷՌΛ্͛ͯ͘Ε͍ͯΔϝϯόʔʹײँ͔͋͠Γ·ͤΜɻҾ͖ଓ ͖൴Β͕࠷େݶ׆༂Ͱ͖Δڥͮ͘Γʹᬏਐͭͭ͠ɺචऀࣗΤϯδχΞͱͯ͠ɺϚωδϟʔͱ͠ ͯɺ͍͚ͯ͠Εͱࢥ͍ͬͯ·͢ɻ 83 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ feature toggle
ʢผ໊ feature flagʣͱ ։ൃ͢Δػೳͷಈ࡞Λ༗ޮԽ͢Δ͔ແޮԽ͢Δ͔Λ੍ޚ ͢ΔͨΊͷख๏Ͱ͢ɻ Ϧετ 6.1: featureToggleExample.ts 1: function someFunction () { 2: if (featureToggle) { 3: newFunc(); // feature toggle ͕༗ޮԽ͞Ε͍ͯΔͱ͖ͷΈ࣮ߦ 4: return; 5: } 6: 7: oldFunc(); 8: } ্هͷίʔυྫͷΑ͏ʹ boolean ͳͲͷΛ࣋ͬͨ feature toggle Λ༻͍ͯॲཧΛذ͢Δ͜ͱ Ͱ࣮ݱ͠·͢ɻ͜ΕɺτϥϯΫϕʔε։ൃͱ͍͏։ൃख๏Λ࣮ફ͢ΔͨΊͷख๏ͰɺػೳϦϦʔ ελΠϛϯάͱ main ϒϥϯνͷػೳࠩͷϚʔδͷλΠϛϯάΛ͢Δ͜ͱͰɺখ͞ͳࠩ Ͱͷ Pull Request ɺϦϦʔεසͷ૿ՃΛ࣮ݱ͘͢͠ͳΓ·͢ɻ·ͨɺػೳϦϦʔελΠϛϯ άΛ੍ޚ͢Δ͜ͱͰҰ෦ϢʔβʔʹػೳΛ։์ͯ͠ AB ςετ͢Δ͜ͱՄೳʹͳΓ·͢ɻGoogle Analytics ͳͲͷੳπʔϧΛҰॹʹࠐΉ͜ͱͰશϢʔβʔʹϦϦʔε͢Δલʹ৽͍͠ػೳͷޮՌ ଌఆ͕Ͱ͖·͢ɻҙͱͯ͠ɺfeature flag Ͱಈ࡞Λ੍ޚ͍ͯͯ͠৽ػೳͷιʔείʔυࣗମ όϯυϧ͞ΕΔͷͰɺWeb ΫϥΠΞϯτͳͲϢʔβʔ͔Βιʔείʔυ͕ݟ͑Δڥͷ߹ɺϩʔ ΧϧͰॲཧΛॻ͖͑Δ͜ͱͰ༗ޮԽ͞ΕΔՄೳੑ͕͋Δ͜ͱΛཹҙ͢Δඞཁ͕͋Γ·͢ɻ 85 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 6.1 τϥϯΫϕʔε։ൃ
6.1 τϥϯΫϕʔε։ൃ τϥϯΫϕʔε։ൃͱ main ϒϥϯνʢτϥϯΫʣʹ feature ϒϥϯνͳͲͷࠩΛϚʔ δ͠ͳ͕Βɺmain ϒϥϯνΛৗʹσϓϩΠՄೳͳঢ়ଶΛ࡞ΔͨΊͷϒϥϯνઓུͰ͢ɻGitflow ͳ ͲͷΑ͏ʹ develop ϒϥϯν࣋ͨͣɺ CI ͷࣗಈςετʹΑͬͯίʔυͷ࣭Λอূ͠·͢ɻϦ Ϧʔεલͷࠩ main ϒϥϯνʹϚʔδͯ͠ɺfeature toggle ΛιʔείʔυʹࠐΉ͜ͱͰಈ࡞ Λ੍ޚ͠·͢ɻҰͭ͋ͨΓͷ Pull Request ͷࠩΛͰ͖Δ͚ͩখ͘͢͞Δ͜ͱΛҙࣝ͢Δ͜ͱͰϨ ϏϡʔΛݮΒ͠ɺϚʔδ·ͰͷظؒΛͯ͘͠ɺϦϦʔεසɾ։ൃͷ্Λࢦ͠·͢ɻ feature toggle ͷཧํ๏ʹɺࣗલͰཧج൫Λ༻ҙ͢Δํ๏ɺOSS SaaS Λར༻͢Δํ๏͕ ͋Γ·͢ɻࠓճ OSS Ͱ͋Δ Unleash ͱ͍͏ feature toggle ཧαʔϏεʹ͍ͭͯհ͠·͢ɻ 6.2 Unleash ͱ Unleash ͱɺfeature toggle Λཧ͢ΔͨΊͷ OSS Ͱ͢ɻηϧϑϗεςΟϯάͷ΄͔ɺ͢Ͱʹ Unleash ଆͰϗεςΟϯά͞Ε͍ͯΔͷΛར༻͢Δ͜ͱͰ͖ɺӡ༻ํ๏ͷࣗ༝͕ߴ͍αʔϏ εͰ͢ɻGUI ͷཧը໘͕༻ҙ͞Ε͍ͯͯඇΤϯδχΞͰ feature toggle ͷ༗ޮɾແޮͷ੍ޚͰ ͖ΔͷͰɺػೳͷϦϦʔεΛΤϯδχΞҎ֎ͷਓ͕ߦ͏͜ͱ͕ՄೳʹͳΓ·͢ɻ·ͨɺUnleash ͷ ΞΧϯτ͝ͱʹݖݶΛཧ͢Δ͜ͱͰ͖Ұ෦ͷΞΧϯτʹ͚ͩॻ͖ࠐΈݖݶΛ༩͑ΔͳͲ͠ ͯɺ feature toggle ͷૢ࡞Λ҆શʹߦ͏͜ͱ͕Ͱ͖·͢ɻWeb hook slack ௨ʹରԠ͍ͯͯ͠ feature toggle ͷมߋΛ͙͢ʹνʔϜʹ͑Δ͜ͱ͕Ͱ͖ͨΓ๛ͳػೳΛඋ͍͑ͯ·͢ɻUnleash ͷγεςϜ͍͔ͭ͘ͷαʔϏεΛΈ߹ΘͤΔ͜ͱͰ࣮ݱ͍ͯ͠·͢ɻ ਤ 6.1: Unleash ͷγεςϜߏਤ Unleash Admin UI Unleash ཧը໘Λఏڙ͢ΔϑϩϯτΤϯυ Unleash API Unleash Admin UI Unleash ϓϩΩγ ͳͲͱΓͱΓͯ͠σʔλϕʔε্ͷ feature 86 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 6.3 Unleash
ͷಋೖ toggle Λཧ͢Δ API Unleash ϓϩΩγ ΫϥΠΞϯτͷ Unleash SDK ͱ Unleash API ͷؒʹଘࡏ͢ΔϓϩΩγɻΫϥΠΞϯτͷ Ϣʔβʔ͝ͱʹެ։͢Δ feature toggle Λ੍ݶͨ͠Γɺ API ϦΫΤετΛΩϟογϡ͢Δ͜ ͱͰύϑΥʔϚϯεΛ্ͤ͞ΔׂͳͲΛ୲͍ͬͯ·͢ɻ Unleash SDK Unleash API ͱ௨৴ͯ͠ feature toggle ͕༗ޮ͔ແޮ͔Λ֬ೝ͢ΔػೳΛఏڙ͍ͯ͠· ͢ɻαʔόαΠυͰͷΞϓϦέʔγϣϯͰ༻͢Δ SDK Ͱ͢ɻ Unleash ϓϩΩγ SDK ΫϥΠΞϯτͷΞϓϦέʔγϣϯͱ Unleash ϓϩΩγ ͷΓͱΓɺ feature toggle ͕༗ޮ ͔ແޮ͔Λ֬ೝ͢ΔػೳΛఏڙ͍ͯ͠·͢ɻ feature toggle ͷछྨ Unleash Ͱ༻్ʹ߹Θͤͯ͞·͟·ͳछྨͷ feature toggle ͕༻ҙ͞Ε͍ͯ·͢ɻfeature toggle ͷछྨʹΑͬͯϥΠϑλΠϜͱ͍͏ Deprecated ʹͳΔ·ͰͷϦϛοτ͕ઃఆ͞Ε͍ͯ· ͢ɻ͜ͷϥΠϑλΠϜ͕ઃఆ͞Ε͍ͯΔ͜ͱʹΑͬͯ͢Ͱʹ Deprecated ʹͳͬͨ feature toggle Λ slack Ͱ௨͢ΔͳͲɺ͍ͭ·ͰϓϩδΣΫτίʔυʹΓଓ͚Δ͜ͱΛ͙͜ͱ͕Ͱ͖·͢ɻ Release ༧ఆ͞ΕͨϦϦʔε·ͰػೳΛແޮԽ͢ΔͨΊͷϑϥάɻϥΠϑλΠϜ 40 ɻ Experiment AB ςετʹ༻͢ΔػೳΛΓସ͑ΔͨΊͷϑϥάɻϥΠϑλΠϜ 40 ɻ Permission ಛఆͷϢʔβʔͷΈػೳΛΓସ͑ΔͨΊͷϑϥάɻϥΠϑλΠϜಛʹͳ͘ɺ Deprecated ʹͳΔ͜ͱͳ͍ɻ Operational γεςϜͷӡ༻ͷͨΊʹ͘͝ظ͚ؒͩѻ͏ϑϥάɻϥΠϑλΠϜ 7 ɻ Kill switch ͢ͰʹϦϦʔε͞Ε͍ͯΔ͕ܧଓͯ͠ػೳͷແޮԽɾ༗ޮԽΛ੍ޚ͍ͨ͠έʔεͷͨΊͷϑ ϥάɻϥΠϑλΠϜಛʹͳ͘ɺ Deprecated ʹͳΔ͜ͱͳ͍ɻ 6.3 Unleash ͷಋೖ Unleash ΛϓϩδΣΫτʹಋೖ͍ͯͨ͘͠ΊͷαϯϓϧΛ Web ΫϥΠΞϯτͷ࣮Λத৺ʹհ ͠·͢ɻαʔόଆ΄΅ύοέʔδΛϗεςΟϯά͢ΔͷΈͰ͢ͷͰɺಛผίʔυΛॻ͍ͨΓͤͣʹ ࡁΈ·͢ɻ 87 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 6.3 Unleash
ͷಋೖ αʔόͷ༻ҙ Unleash Ͱ Admin UI ͱ Unleash API ΛηϧϑϗεςΟϯάͰ͖·͢ɻެࣜͷ Docker Πϝʔ δ Helm νϟʔτ͕༻ҙ͞Ε͍ͯΔͷͰ͜ΕΛར༻ͯ͠ Unleash API ͱ Admin UI Λ༻ҙͰ͖ ·͢ɻ Unleash ϓϩΩγ ͷ༻ҙ લड़ͷ௨ΓΫϥΠΞϯτͱ Unleash API ͱͷ௨৴ʹ Unleash ϓϩΩγ ΛڬΉඞཁ͕͋Γ· ͢ɻUnleash ϓϩΩγ Node.js ͔ Docker Ͱಈ͔͢͜ͱ͕Ͱ͖·͢ɻجຊతʹڥมͱͯ͠ Unleash API ͷΤϯυϙΠϯτ API τʔΫϯΛ͚ͩ͢ͰࡁΈ·͢ɻAPI τʔΫϯ Admin UI ͔ΒൃߦͰ͖·͢ɻ ΫϥΠΞϯτʹ Unleash SDK Λಋೖ αϯϓϧίʔυͱͯ͠ Vanilla JS *1 ͷྫΛհ͠·͢ɻJavaScript ༻ͷ Unleash SDK Λϓϩ δΣΫτʹΠϯετʔϧͯ͠ɺॳظԽॲཧΛॻ͖·͢ɻ Ϧετ 6.2: shell 1: npm install unleash-proxy-client ॳظԽͷࡍʹͦΕͧΕڥมΛ͠·͢ɻ Ϧετ 6.3: featureToggle.ts 1: import { UnleashClient } from "unleash-proxy-client"; 2: 3: const unleash = new UnleashClient({ 4: url: UNLEASH_PROXY_URL, // Unleash Proxy ΤϯυϙΠϯτ 5: clientKey: UNLEASH_CLEANT_KEY, // Unleash API Ωʔ 6: appName: UNLEASH_APP_NAME, // ҙͷ໊લ 7: }); 8: 9: unleash.updateContext({ userId: UNLEASH_USER_ID }); 10: 11: unleash.start(); ॳظԽ͕ྃͨ͠Β isEnabled ϝιουʹΑͬͯҙͷ feature toggle ͷΛݕূͰ͖·͢ɻ *1 ϥΠϒϥϦϑϨʔϜϫʔΫΛ͍ͬͯͳ͍ૉͷ JS ͷ͜ͱ 88 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 6.4 ܕ҆શʹ
feature toggle Λཧ͢Δ Ϧετ 6.4: featureToggleExample.ts 1: function someFunction () { 2: if (unleash.isEnabled("someFeatureToggle")) { 3: newFunc(); // feature toggle ͕༗ޮԽ͞Ε͍ͯΔͱ͖ͷΈ࣮ߦ 4: return; 5: } 6: 7: oldFunc(); 8: } جຊతʹ্هͷखॱͰ Unleash ΛΫϥΠΞϯτͰར༻Ͱ͖ΔͷͰ͕͢ɺҎԼͷΑ͏ͳ͕ ߟ͑ΒΕ·͢ɻ • ݕূ͠Α͏ͱ͍ͯ͠Δ feature toggle ͕ଘࡏ͢Δ͔Ͳ͏͔Λ੩తʹݕͰ͖ͳ͍ɻ • σόοάͳͲݕূ࣌ʹ feature toggle ΛҰ࣌తʹΓସ͍ͨ࣌ʹಉ͡ڥͷΫϥΠΞϯτ͢ ͯʹӨڹͯ͠͠·͏ɻ ࠓճ͜ΕΒͷʹ͍ͭͯɺϩʔΧϧͰ feature toggle ͷΛอ࣋͢ΔͳͲͯ͠ղܾΛࢼΈͯ Έ·͢ɻ 6.4 ܕ҆શʹ feature toggle Λཧ͢Δ ܕ҆શʹ feature toggle Λཧ͢Δ͜ͱʹΑͬͯɺଘࡏ͠ͳ͍ feature toggle Λ CI ͳͲͰͷܕ νΣοΫͰݕͯ͠όάͷࠞࡏΛ͙͜ͱ͕Ͱ͖·͢ɻfeature toggle ͕ଘࡏ͢Δ͔Ͳ͏͔੩తʹݕ ͢ΔͨΊʹɺίʔυϕʔεͰඞཁͳ feature toggle Λอ࣋ͯ͠ TypeScript ͕ܕͱͯ͠ feature toggle ΛਪͰ͖Δඞཁ͕͋Γ·͢ɻͦͷͨΊʹࣄલʹଘࡏ͢Δ feature toggle ͯ͢Λऔಘͯ͠ ܕਪՄೳͳܗͷϑΥʔϚοτͰอଘͯ͠Έ·͢ɻࠓճ Node.js Ͱଘࡏ͢Δ feature toggle Ұཡ ͷྻͷ TypeScript ϑΝΠϧΛు͖ग़͢εΫϦϓτΛΜͰΈ·ͨ͠ɻ Node.js ༻ͷ SDK ΛΠϯετʔϧ͠·͢ɻ Ϧετ 6.5: shell 1: npm install -D unleash-client ҙͷσΟϨΫτϦʹҎԼͷΑ͏ͳ feature toggle Ұཡͷྻͷ TypeScript ϑΝΠϧΛు͖ग़͢ εΫϦϓτϑΝΠϧΛ࡞͠·͢ɻదٓ Unleash ͷ ڥมΛ͍ͯͩ͘͠͞ɻ 89 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 6.4 ܕ҆શʹ
feature toggle Λཧ͢Δ Ϧετ 6.6: generateFeatureToggles.js 1: const fs = require("fs"); 2: const path = require("path"); 3: const unleash = require("unleash-client"); 4: 5: const OUTPUT_FILE = path.resolve("featureToggleNames.ts"); 6: const MODULE_NAME = "featureToggles"; 7: 8: const main = async () => { 9: await unleash.startUnleash({ 10: url: UNLEASH_API_URL, 11: appName: UNLEASH_APP_NAME, 12: customHeaders: { 13: Authorization: UNLEASH_CLEANT_KEY, 14: }, 15: }); 16: 17: const toggles = unleash.getFeatureToggleDefinitions(); 18: 19: const toggleNames = toggles.map((toggle) => toggle.name); 20: 21: const fileContent = ‘export const ${MODULE_NAME} = ${JSON.stringify( 22: toggleNames 23: )} as const;‘; 24: 25: await fs.promises.writeFile(OUTPUT_FILE, fileContent); 26: }; 27: 28: main().catch((error) => { 29: console.error(error); 30: process.exit(1); 31: }); node ίϚϯυ͔Β࡞ͨ͠εΫϦϓτΛ࣮ߦ͢Δ͜ͱͰ TypeScript ϑΝΠϧ͕ు͖ग़͞ΕΔͱ ࢥ͍·͢ɻ path/to ʹ͋ͨΔͱ͜Ζదٓॻ͖͍͑ͯͩ͘͞ɻ Ϧετ 6.7: shell 1: node path/to/generateFeatureToggles.js ࠓճ࡞ͨ͠εΫϦϓτͰ featureToggles Ϟδϡʔϧ ͱͯ͠ feature toggle ҰཡΛྻͷఆ ͱͯ͠ export ͨ͠ͷΛੜ͢ΔΑ͏ʹ͍ͯ͠·͢ɻ 90 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 6.5 ϩʔΧϧͷΈͰҰ࣌తʹ
feature toggle ΛΓସ͑Δ Ϧετ 6.8: featureToggleNames.ts 1: export const featureToggles = [...] as const; ੜͨ͠ feature toggle Ұཡͷྻ͔ΒϩʔΧϧͰͷ feature toggle ͷ map Λੜͨ͠Γɺ feature toggle ͷΛऔಘ͢Δࡍʹ feature toggle Ұཡͷྻʹؚ·ΕΔͷΈ͕ࢦఆ͞ΕΔΑ͏ʹ ܕΛઃఆ͠·͢ɻ Ϧετ 6.9: featureToggle.ts 1: import { UnleashClient } from "unleash-proxy-client"; 2: import { featureToggles } from "path/to/featureToggleNames"; 3: 4: const toggles = Object.fromEntries(featureToggles.map((key) => [key, false])); 5: 6: export const startUnleash = async () => { 7: const updateToggles = () => { 8: const featureToggles = unleash.getAllToggles(); 9: 10: featureToggles.forEach((toggle) => { 11: if (toggle.name in toggles) { 12: toggles[toggle.name] = toggle.enabled; 13: } 14: }); 15: }; 16: 17: unleash.on("ready", updateToggles); 18: 19: await unleash.start(); 20: }; 21: 22: export const getFeatureToggleEnabled = (name: typeof featureToggles[number]) => { 23: return toggles[name]; 24: }; 6.5 ϩʔΧϧͷΈͰҰ࣌తʹ feature toggle ΛΓସ͑Δ ϩʔΧϧͰ feature toggle ͷΛอ࣋͢Δ͜ͱͰҰ࣌తʹϩʔΧϧڥͷΈͰ feature toggle ͷ Γସ͑ΛͰ͖ΔΑ͏ʹͯ͠Έ·͢ɻܕ҆શʹ feature toggle Λཧ͢Δ ͷ߲ͰɺεΫϦϓτͰੜ ͨ͠ྻΛͱʹϩʔΧϧͰ feature toggle ͷΛ࣋ͭΑ͏ʹͨ͠ͷͰɺ͜ͷΛߋ৽͢ΔؔΛ ༻ҙ͠·͢ɻ 91 -
ୈ 6 ষ Unleash Λͬͨ feature toggle ཧ 6.6 ऴΘΓʹ
Ϧετ 6.10: featureToggle.ts 1: const toggles = Object.fromEntries(featureToggles.map((key) => [key, false])); 2: 3: export const updateFeatureToggles = (featureToggles: typeof toggles) => { 4: Object.keys(toggles).forEach((toggle) => { 5: if (toggle in featureToggles) { 6: toggles[toggle] = featureToggles[toggle]; 7: } 8: }); 9: }; ·ͨɺࠓճϝϞϦ্Ͱͷ feature toggle ͷͷཧํ๏Λհ͠·͕ͨ͠ɺlocal storage session storage ͳͲΛ׆༻͢Δ͜ͱͰϖʔδϦϩʔυͯ͠ϩʔΧϧͰͷ feature toggle ͷΛӬ ଓԽ͢Δ͜ͱͰ͖·͢ɻ 6.6 ऴΘΓʹ feature toggle ͷཧํ๏ͻͱͭͱͬͯɺͱͯͨ͘͞Μͷํ๏͕͋Γ·ͩ·ͩվળ͍͚ͯ͠Δ ͜ͱଟ͍ͱࢥ͏ͷͰΑΓྑ͍։ൃମݧͷ࣮ݱͷͨΊʹͬͱݚڀ͍͖͍ͯͨ͠ͳͱࢥ͍ͬͯ·͢ɻ Ͳ͔͜ͷϓϩδΣΫτͰ͜ͷݟ͕গ͠Ͱཱͭͱ͏Ε͍͠Ͱ͢ɻ 92 -
ஶऀհ দݪ ৴ (ୈ 1 ষ୲) ॴଐϞϯεταʔόνʔϜͰ Ruby Go
Λॻ͍ͯΔɻϓϩάϥϛϯά͕͖Ͱɺීஈਪ ͠ݴޠͷ Haskell Ͱ༡ΜͩΓɺ৽͍͠ϓϩάϥϛϯάݴޠΛษڧͨ͠Γ͍ͯ͠ΔɻHaskell-jp Elm-jp Ͱͪΐͪ͜ΐ͜׆ಈ͍ͯ͠Δɻ ɹ ߐാ ࠸ (ୈ 2 ষ୲, Github: MokkeMeguru, Twitter: @MeguruMokke) ੜ·Ε͔ͯΒ Lisp ͔͠ॻ͍ͨ͜ͱ͕ͳ͍ਓͰ͢ɻઌιγϟήͷ͓Έ͘͡ͰେڟΛҾ͖· ͨ͠ɻ ɹ riddle (ୈ 3 ষ୲, Medium: @riddle) ։ൃຊ෦ CTO ࣨ SRE άϧʔϓ ॴଐɻपΓͷਓ͕͢͜͠ͰศརʹͳΔΑ͏ͳ Developer Experience(։ൃମݧ) ͷ্ɺޙͰ͍·Θ͠Λ͍͢͠ίʔυίϝϯτΛॻ͘ͷʹ࠷ ۙϋϚ͍ͬͯ·͢ʂʂ ɹ ా ګฏ (ୈ 4 ষ୲, GitHub,Medium,Qiita: flatfisher, Twitter: @canoefishing) ࣍ੈΤϯλʔςΠϯϝϯτࣄۀຊ෦ TIPSTAR ։ൃ෦ γεςϜ 1 άϧʔϓ Ϛωʔδϟʔɻ TIPSTAR ͷαʔόʔαΠυνʔϜͰ։ൃɾӡ༻ϓϩδΣΫτϦʔυΛ͍ͯ͠·͢ɻΓ͕ झຯͳͷͰʮΓʷςΫϊϩδʔʯͱ͍ͬͨςʔϚʹऔΓΉͷ͕͖Ͱ͢ɻ ɹ ഡݪ ྋհ a.k.a. ΒΓΐ͢ (ୈ 5 ষ୲, Twitter: @raryosu) 2018 ৽ଔɻ՝ղܾ͞Μͱͯ͠ TIPSTAR ͷαʔϏεӡӦɾ։ൃʹؔ͢Δ՝ղܾʹऔ ΓΉɻ2021 4 ݄͔ΒɺTIPSTAR ͰΤϯδχΞϦϯάϚωʔδϟʔʹब͘ɻ࠷ۙδϜʹ ௨͍ͩͯ͠ےτϨͨ͠ΓମΛಈ͔͢ͷ͕͖ɻ૫݈ͤͯ߁ମʹͳΓ͍ͨɻ ɹ ɹ 93 -
ஶऀհ ٢ ༐ଠ (ୈ 6 ষ୲, GitHub: yutaroyoshikawa) 2021
৽ଔೖࣾɻ࣍ੈΤϯλʔςΠϯϝϯτࣄۀຊ෦ TIPSTAR ։ൃ෦ ΫϥΠΞϯτά ϧʔϓ Web ։ൃνʔϜॴଐɻWebGL ৮ΔͷͱΠϯυΧϨʔ͕͖Ͱ͢ɻ ɹ ౢࣇ ະདྷ (Graphic designer / Art director) σβΠϯຊ෦ ΫϦΤΠςΟϒࣨɻΞΠίϯΠϥετɾදࢴσβΠϯΛ୲ɻҾ͖ଓ͖୲ ͍͖ͤͯͨͩ͞·ͨ͠ɻײँʂ ɹ تଟ ޭ࣍ (੍࡞ਐߦ, Twitter: @kojikita) CTO ࣨ DevRel άϧʔϓͰษڧձΠϕϯτͷӡӦΛ͍ͯ͠·͢ɻ࠷ۙͷྗࣄۀࢠҭͯ Ͱ͢ɻ ɹ ӹࢁ ઍय़ (੍࡞ਐߦ, Twitter: @charlielog_ggg) IT اۀͰͷҰਓ࠾༻ใΛܦͯɺ2021 11 ݄ʹϛΫγΟͷ CTO ࣨ DevRel άϧʔϓʹδϣ Πϯ͠·ͨ͠ɻ࠷ۙΤάΊͷϛεςϦখઆͱ͔Θ͍͍ύϑΣ͕͖Ͱ͢ɻ ɹ 94 -
mixi tech note #07 2022 1 ݄ 22 ɹॳ൛ୈ
1 ɹൃߦ ஶɹऀ גࣜձࣾϛΫγΟ ༗ࢤ ൃߦॴ גࣜձࣾϛΫγΟ ҹॴ ޫاը ɹ mixi, Inc.