Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
調べながらGCPやってみた話/gcpug-osaka-3
Search
kadota kyohei
July 20, 2017
Programming
550
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
調べながらGCPやってみた話/gcpug-osaka-3
GCPUG In Osaka #3 で発表した資料。
色々サービス使ってみました。
https://gcpug-osaka.connpass.com/event/61297/
kadota kyohei
July 20, 2017
More Decks by kadota kyohei
See All by kadota kyohei
govulncheckの紹介/govulncheck-intro
lufia
1
84
パッケージ設計の黒魔術/Kyoto.go#63
lufia
3
590
最近変わった開発時のあれこれ/features-of-recent-go
lufia
0
970
GCPとGoの話/gcpug-osaka-6
lufia
0
530
REST is not only (web) API interface
lufia
1
1.1k
Go駆動開発で超速Pushエンジンを作った話
lufia
19
7.5k
Other Decks in Programming
See All in Programming
型解析で実現する Go の言語内 DSL / Conference に Go! タイムテーブルの歩き方 for Gophers
mazrean
0
140
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
1.7k
Laravelのアプリケーションをどこにデプロイするか #ツナギメオフライン.9
akase244
0
120
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
110
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
130
ハーネス設計入門 〜プロンプト、コンテキストの次〜
kinopeee
55
37k
App Intentsのビルドプロセスを支える技術
kntkymt
0
190
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
120
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
280
自分的「カンファレンスの楽しみ方」
syumai
0
200
Building an Out-of-Order CPU
latte72
1
750
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
230
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
330
41k
HDC tutorial
michielstock
2
860
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
820
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
440
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
My Coaching Mixtape
mlcsv
0
310
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Deep Space Network (abreviated)
tonyrice
0
300
Transcript
ௐͳ͕ΒGCPͬͯ Έͨ GCPUG In Osaka #3 @plan9user (2017-07-19)
ࣗݾհ • ଟګฏ • Favorites • OS: Plan 9 •
Editor: acme • Shell: rc • ϑΣϯϦϧͰಇ͍͍ͯ·͢
None
Ϟνϕʔγϣϯ • GoΛॻ͍͍ͯͨͷͰڵຯͣͬͱ͋ͬͨ • ࣮Compute EngineͰPlan 9͕ಈ͘ • ಈ͚ͩ͘͡Όͳͯ͘ίϯιʔϧ͕͑Δ •
Plan 9ͷཧʹίϯιʔϧඞਢ
ใऩू • Google Cloud Platform Japan ެࣜϒϩά • Publickey •
Google Cloud Platform Advent Calendar • ໘നͦ͏ͳαʔϏευΩϡϝϯτಡΉ
Կ͔͠·ͤΜ͔?
• ཉ͔ͬͨ͠αʔϏεΛ(్த·Ͱ)࡞ͬͨ • ॳΊͯͷਓ • Ͳ͏͍͏αʔϏε͕͋Δͷ͔ • ͍ͬͯΔਓ • ڭ͍͑ͯͩ͘͞
ࠓ͢͜ͱ
͜Μͳ͜ͱ͋Γ·ͤΜ͔? • ಡΜͩ͜ͱ͋Δ͚ͲݕࡧͰ͖ͳ͍ • ϒοΫϚʔΫ͢ΔͷΛΕ͍ͯͨ • هࣄͦͷͷ͕ͳ͘ͳͬͯ͠·ͬͨ ޙഐʮͳΜͰ͜Ε೩͑ͯΔΜͰ͔͢ʯʮͦΕ͔֬ݩهࣄ͕...ʯ
ಡΜͩهࣄશ෦͍ͨ͠
࡞ΔαʔϏεͷ༷ • Ϣʔβຖʹ͚ͯཧ͢Δ • APIͱ࣮ͯ͢͠Δ • ಡΜͩهࣄΛऔࣺબͤͣશ෦อଘ͢Δ • ࣌ܥྻʹಡΜͩϦετΛऔಘ͢Δ •
อଘͨ͠هࣄ͔Βશจݕࡧ͢Δ
༻ҙ͢Δͷ • GAE/Go SDK • Go (͋Δͱศར) $ nix-env -i
go-1.8.3 $ nix-env -i google-app-engine-go-sdk
ڥΛબͿ
Computing Option • App Engine Standard Environment (GAE SE) •
App Engine Flexible Environment (GAE FE) • Container Engine (GKE) • Compute Engine (GCE) GCP ͷίϯϐϡʔτ Φϓγϣϯ ΨΠυΛެ։ https://cloudplatform-jp.googleblog.com/2016/06/gcp_17.html
GAE/Go SEΛ͏ • ғ͍ࠐΈͷϦεΫ͋Δ͚Ͳ... • ӡ༻ʹखؒΛ͔͚ͨ͘ͳ͔ͬͨ • ແྉ͕͋Δͷخ͍͠ • RDB͑ͳͯ͘ࠔΒͳ͍
࡞ΔαʔϏεͷ༷ • Ϣʔβຖʹ͚ͯཧ͢Δ • APIͱ࣮ͯ͢͠Δ • ಡΜͩهࣄΛऔࣺબͤͣશ෦อଘ͢Δ • ࣌ܥྻʹಡΜͩϦετΛऔಘ͢Δ •
อଘͨ͠هࣄ͔Βશจݕࡧ͢Δ
Ϣʔβೝূ(1) • Users API (google.golang.org/appengine/user) • ͱͯ؆୯ʹ͑Δ • Current(); CurrentOAuth();
LoginURL() • GoogleΞΧϯτ͔͠ରԠ͍ͯ͠ͳ͍ • GitHubΞΧϯτͰϩάΠϯ͍ͨ͠... • ࣗલ࣮ • ໘͍͘͞
Ϣʔβೝূ(2) • Cloud Identity-Aware Proxy (IAP) • Cloud Endpoints
Cloud Identity-Aware Proxy • ೝূ͞ΕͨϢʔβʹΞϓϦΛެ։͢Δ • GoogleΞΧϯτલఏͷΑ͏ͳͷͰະ༻
Cloud Endpoints • REST APIΛ࡞ΔͨΊͷαʔϏε • ϩΪϯάɺϞχλϦϯάɺอޢͳͲߦ͏ • GAE SE:
Cloud Endpoints Framework • ͦΕҎ֎: Extensible Service Proxy Extensible Service Proxy ͱ Endpoints Frameworks ͷൺֱ https://cloud.google.com/endpoints/docs/frameworks-extensible-service-proxy?hl=ja
Cloud Endpoints • Cloud Endpoints Framework github.com/GoogleCloudPlatform/go-endpoints/endpoints • ඪ४ͰIssuer =
accounts.google.com • AuthenticatorΛ࣮͢Ε৭ʑΕͦ͏
࡞ΔαʔϏεͷ༷ • Ϣʔβຖʹ͚ͯཧ͢Δ • APIͱ࣮ͯ͢͠Δ • ಡΜͩهࣄΛऔࣺબͤͣશ෦อଘ͢Δ • ࣌ܥྻʹಡΜͩϦετΛऔಘ͢Δ •
อଘͨ͠هࣄ͔Βશจݕࡧ͢Δ
go-endpointsΛ͏ • app.yamlʹhandlerΛՃ application: [app-name] version: 1 runtime: go api_version:
go1 handlers: - url: /_ah/spi/.* script: _go_app
Go 1.8Λ͏ • api_versionΛมߋ͢Δ(1.9.55Ҏ্) application: [app-name] version: 1 runtime: go
api_version: go1.8 handlers: - url: /_ah/spi/.* script: _go_app Google App Engine for Go͕Go1.8ʹରԠͨ͠ͷͰࢼͯ͠Έͨ http://qiita.com/tenntenn/items/0b92fc089f8826fabaf1
go-endpointsͰAPI࣮ • APIͱͯ͠ѻ͏ϝιουಛఆͷϧʔϧΛຬͨ͢ • JSONͷมউखʹͬͯ͘ΕΔ type Service struct{} type ListOptions
struct { Limit int `json:"limit" endpoints:"d=10"` } type ArticleList struct { Items []*Article `json:"items"` } type Article struct { URL string `json:"url"` } func (s *Service) ArticleList(c context.Context, r *ListOptions) (*ArticleList, error) { return &ArticleList{ Items: []*Article{ &Article{URL: "http://example.com/"}, }, }, nil }
go-endpointsͷURL Router • ࡞ͬͨAPIΛURLʹϚοϓ͢Δ func init() { srv := new(Service)
api, err := endpoints.RegisterService(srv, "logs", "v1", "Reading Log API", true) if err != nil { log.Fatal(err) } m := api.MethodByName("ArticleList") if m == nil { log.Fatal("Missing ArticleList method") } info := m.Info() info.Name = "article.list" info.Path = "articles" info.HTTPMethod = "GET" info.Desc = "List most recent reading articles." endpoints.HandleHTTP() } APIαʔϏεొ URLͷઃఆ ͜ͷྫ https://[app-name].appspot.com/_ah/api/logs/v1/articles ͱͳΔ
࡞ΔαʔϏεͷ༷ • Ϣʔβຖʹ͚ͯཧ͢Δ • APIͱ࣮ͯ͢͠Δ • ಡΜͩهࣄΛऔࣺબͤͣશ෦อଘ͢Δ • ࣌ܥྻʹಡΜͩϦετΛऔಘ͢Δ •
อଘͨ͠هࣄ͔Βશจݕࡧ͢Δ
go-endpointsͰೝূ • infoʹɺೝূ͢ΔͨΊʹඞཁͳΛઃఆ͢Δ • API Manager / ೝূใ / ΫϥΠΞϯτIDͷ࡞
ͰWeb Application Λબ • ੜ͞ΕͨΫϥΠΞϯτIDͱγʔΫϨοτΛอଘ const ClientID = "xxxx" func init() { info := m.Info() info.Name = "article.list" info.Path = "articles" info.HTTPMethod = "GET" info.Desc = "List most recent reading articles." info.Scopes = []string{endpoints.EmailScope} info.Audiences = []string{"[app-name].appspot.com"} info.ClientIds = []string{ClientID, endpoints.APIExplorerClientID} endpoints.HandleHTTP() }
go-endpointsͰೝূ • infoͱಉ͡ΛͬͯCurrentUser()Λݺͼग़͢ func (s *Service) ArticleList(c context.Context, r *ListOptions)
(*ArticleList, error) { scopes := []string{endpoints.EmailScope} audiences := []string{"[app-name].appspot.com"} clientIDs := []string{ClientID, endpoints.APIExplorerClientID} user, err := endpoints.CurrentUser(c, scopes, audiences, clientIDs) if err != nil { return nil, err } return &ArticleList{ Items: []*Article{ &Article{URL: "http://example.com/"}, }, }, nil }
API ExplorerͰςετ • https://[app-name].appspot.com/_ah/api/explorer • ೝূ͕ඞཁͱѻΘΕΔΑ͏ʹͳ͍ͬͯΔ
࡞ΔαʔϏεͷ༷ • Ϣʔβຖʹ͚ͯཧ͢Δ • APIͱ࣮ͯ͢͠Δ • ಡΜͩهࣄΛऔࣺબͤͣશ෦อଘ͢Δ • ࣌ܥྻʹಡΜͩϦετΛऔಘ͢Δ •
อଘͨ͠هࣄ͔Βશจݕࡧ͢Δ
DatastoreΛ͏ • NoSQLܕσʔλϕʔε • Keyͷઃܭ͕͍͠ • Cloud StorageSQLܕDB͋Δ͚Ͳ...
Datastoreอଘ • ϢʔβIDͱهࣄͷURLͰ֊ʹ͍ͯ͠Δ type Page struct { URL string LastMod
time.Time } func AddEntry(c context.Context, u *User, url string) error { p := datastore.NewKey(c, "User", u.ID, 0, nil) key := datastore.NewKey(c, "Page", url, 0, p) return datastore.RunInTransaction(c, func(c context.Context) error { var page Page err := datastore.Get(c, key, &page) if err != nil && err != datastore.ErrNoSuchEntity { return err } page.URL = url page.LastMod = time.Now() _, err = datastore.Put(c, key, &page) return err }, nil) }
Datastoreอଘ • datastore.RunInTransaction()Ͱߋ৽͢Δ type Page struct { URL string LastMod
time.Time } func AddEntry(c context.Context, u *User, url string) error { p := datastore.NewKey(c, "User", u.ID, 0, nil) key := datastore.NewKey(c, "Page", url, 0, p) return datastore.RunInTransaction(c, func(c context.Context) error { var page Page err := datastore.Get(c, key, &page) if err != nil && err != datastore.ErrNoSuchEntity { return err } page.URL = url page.LastMod = time.Now() _, err = datastore.Put(c, key, &page) return err }, nil) } ࣦഊͷ߹ϦτϥΠ͞ΕΔͷͰɺ ࠷৽ͷΛಡΈ͔ͯ͠Βߋ৽
هࣄ༰ͷऔಘ • Goඪ४ͷhttp.Get()੍ݶ͞Ε͍ͯΔ • ΘΓʹurlfetch.ClientΛ͏ • API࣮ߦͷཪͰऔಘΛ͍ͨ͠ • GAE/Go SEͷϦΫΤετ60ඵͰλΠϜΞτ
• Task QueueΛ͏ • Cloud Pub/SubSubscribe͢Δଆ͕ෳͷ߹ʹศརͦ͏
Task Queue • Push QueueͱPull Queueͷ2छྨ͋Δ • GAE/Go SEPush Queue
• ಛఆͷΤϯυϙΠϯτʹϦΫΤετ͞ΕΔ • GAE͔ΒͷΈ࣮ߦ͍ͤͨ͞
Task Queue༻URLՃ • Task Queue͕ϦΫΤετ͢ΔURLΛՃ application: [app-name] version: 1 runtime:
go api_version: go1.8 handlers: - url: /_ah/spi/.* script: _go_app - url: /_ah/queue/.* script: _go_app login: admin ཧऀͷΈΞΫηεՄೳ
Ωϡʔͷઃఆ • queue.yamlΛ࡞ͯ͠ΩϡʔΛઃఆ • ৭ʑͰ͖ΔͷͰެࣜυΩϡϝϯτΛಡ͏ queue: - name: snap rate:
1/s bucket_size: 5
Task Queue࣮ • ΩϡʔʹೖΕ࣮ͯߦɺΤϥʔͳΒϦτϥΠ func AddTask(c context.Context, url string) error
{ v := url.Values{} v.Set("url", url) t := taskqueue.NewPOSTTask("/_ah/queue/snap", v) _, err := taskqueue.Add(c, t, "snap") return err } func SnapQueueHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) url := r.FormValue("url") cli := urlfetch.Client(c) resp, err := cli.Get(uri) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } ... }
Task QueueϋϯυϥՃ • go-endpoints͕endpoints.HandleHTTP()͍ͯ͠Δ͕ɺ ී௨ʹͦͷ··Goඪ४net/httpͰՃ͢Ε͍͍ const ClientID = "xxxx" func
init() { info := m.Info() info.Name = "article.list" info.Path = "articles" info.HTTPMethod = "GET" info.Desc = "List most recent reading articles." info.Scopes = []string{endpoints.EmailScope} info.Audiences = []string{"[app-name].appspot.com"} info.ClientIds = []string{ClientID, endpoints.APIExplorerClientID} http.HandleFunc("/_ah/queue/snap", SnapQueueHandler) endpoints.HandleHTTP() }
࡞ΔαʔϏεͷ༷ • Ϣʔβຖʹ͚ͯཧ͢Δ • APIͱ࣮ͯ͢͠Δ • ಡΜͩهࣄΛऔࣺબͤͣશ෦อଘ͢Δ • ࣌ܥྻʹಡΜͩϦετΛऔಘ͢Δ •
อଘͨ͠هࣄ͔Βશจݕࡧ͢Δ
Χʔιϧͷར༻ • DatastoreҙͷϖʔδʹҠಈ͢Δͷ͔ͳ͍ ༷͔Β֎ͨ͠΄͏͕͍͍ • Query.Offset()ಡΈඈ͕͢ಡΈࠐΈ͍ͯ͠Δ ಡΈࠐΈճͰ՝ۚ͞ΕΔ... • ΧʔιϧΛͬͯલޙͷΛऔಘ͢Δͱ͍͍ •
ͨͩ͠Χʔιϧ͕࡞ΒΕͨΫΤϦͱಉ͕݅͡ඞཁ
Χʔιϧͷ͍ํ func FetchEntries(c context.Context, u *User, cursor string) ([]*Page, string,
error) { key := datastore.NewKey(c, "User", u.ID, 0, nil) q := datastore.NewQuery("Page").Ancestor(key).Limit(20) if cursor != "" { p, err := datastore.DecodeCursor(cursor) if err != nil { return nil, "", err } q = q.Start(p) } var a []*Page t := q.Run(c) for { var page Page _, err := t.Next(&page) ... লུ ... } p, err := t.Cursor() if err != nil { return nil, "", err } return a, p.String(), nil } ಉͳΫΤϦͰऔಘͨ͠Χʔιϧ
࡞ΔαʔϏεͷ༷ • Ϣʔβຖʹ͚ͯཧ͢Δ • APIͱ࣮ͯ͢͠Δ • ಡΜͩهࣄΛऔࣺબͤͣશ෦อଘ͢Δ • ࣌ܥྻʹಡΜͩϦετΛऔಘ͢Δ •
อଘͨ͠هࣄ͔Βશจݕࡧ͢Δ
Search API • DatastoreΩʔϫʔυݕࡧ͕ۤख • Search APIͰ༻͢Δ • ͨͩ͠DatastoreͱผͷཧʹͳΔ
• ΠϯσοΫεʹɺෳͷυΩϡϝϯτΛొ Search APIͷ͍ํ import "google.golang.org/appengine/search" type Document struct {
Content search.HTML LastMod time.Time } func AddContent(c context.Context, uid string, body []byte) error { doc := Document{ Content: search.HTML(body), LastMod: time.Now(), } x, err := search.Open("article_" + uid) if err != nil { return err } if _, err := x.Put(c, uri, &doc); err != nil { return err } return nil } υΩϡϝϯτΛఆٛ ΠϯσοΫεՃ
ݕࡧͯ͠ΈΔ Query String https://cloud.google.com/appengine/docs/standard/go/search/query_strings
• ΠϯσοΫε͔ΒΩʔϫʔυݕࡧ...ͷ͕ͣ... Search APIͷ͍ํ func Query(c context.Context, uid, expr string,
cursor Cursor) ([]*Document, string, error) { x, err := search.Open("article_" + uid) if err != nil { return nil, "", err } var a []*Document if cursor != "" { options.Cursor = search.Cursor(cursor) } t := x.Search(c, expr, nil) for { var doc Document _, err := t.Next(&doc) if err == search.Done { return a, string(t.Cursor()), nil } if err != nil { return nil, "", err } a = append(a, &doc) } }
·ͱΊ • ϚωʔδυαʔϏε͓खܰ • झຯͰॻ͘ίʔυͳΒ໎Θͣ͏ • ϕϯμʔϩοΫΠϯؾΛ͚ͭͯ...
͋Γ͕ͱ͏͍͟͝·ͨ͠