Upgrade to Pro — share decks privately, control downloads, hide ads and more …

調べながらGCPやってみた話/gcpug-osaka-3

 調べながらGCPやってみた話/gcpug-osaka-3

GCPUG In Osaka #3 で発表した資料。
色々サービス使ってみました。
https://gcpug-osaka.connpass.com/event/61297/

kadota kyohei

July 20, 2017
Tweet

More Decks by kadota kyohei

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ • ໳ଟګฏ • Favorites • OS: Plan 9 •

    Editor: acme • Shell: rc • ϑΣϯϦϧͰಇ͍͍ͯ·͢
  2. ৘ใऩू • Google Cloud Platform Japan ެࣜϒϩά • Publickey •

    Google Cloud Platform Advent Calendar • ໘നͦ͏ͳαʔϏε͸υΩϡϝϯτಡΉ
  3. ༻ҙ͢Δ΋ͷ • GAE/Go SDK • Go (͋Δͱศར) $ nix-env -i

    go-1.8.3 $ nix-env -i google-app-engine-go-sdk
  4. 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
  5. Ϣʔβೝূ(1) • Users API (google.golang.org/appengine/user) • ͱͯ΋؆୯ʹ࢖͑Δ • Current(); CurrentOAuth();

    LoginURL() • GoogleΞΧ΢ϯτ͔͠ରԠ͍ͯ͠ͳ͍ • GitHubΞΧ΢ϯτͰ΋ϩάΠϯ͍ͨ͠... • ࣗલ࣮૷ • ໘౗͍͘͞
  6. 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
  7. 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
  8. 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 }
  9. 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 ͱͳΔ
  10. 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() }
  11. 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 }
  12. 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) }
  13. 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) } ࣦഊͷ৔߹͸ϦτϥΠ͞ΕΔͷͰɺ ࠷৽ͷ஋ΛಡΈ௚͔ͯ͠Βߋ৽
  14. Task Queue • Push QueueͱPull Queueͷ2छྨ͋Δ • GAE/Go SE͸Push Queue

    • ಛఆͷΤϯυϙΠϯτʹϦΫΤετ͞ΕΔ • GAE͔ΒͷΈ࣮ߦ͍ͤͨ͞
  15. 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 ؅ཧऀͷΈΞΫηεՄೳ
  16. 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 } ... }
  17. 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() }
  18. Χʔιϧͷ࢖͍ํ 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 } ಉ౳ͳΫΤϦͰऔಘͨ͠Χʔιϧ
  19. • ΠϯσοΫεʹɺෳ਺ͷυΩϡϝϯτΛొ࿥ 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 } υΩϡϝϯτΛఆٛ ΠϯσοΫε΁௥Ճ
  20. • ΠϯσοΫε͔ΒΩʔϫʔυݕࡧ...ͷ͸͕ͣ... 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) } }