Upload
takuya-ueda
View
510
Download
1
Embed Size (px)
Citation preview
Namespace APIを用いたマルチテナント型Webアプリの実践
2017/03/02(木)@やっぱり App Engine ja Night #1
The Go gopher was designed by Renee French.The gopher stickers was made by Takuya Ueda.Licensed under the Creative Commons 3.0 Attributions license.
自己紹介
メルカリ/ソウゾウ
上田拓也twitter: @tenntenn■ コミュニティ活動
Google Cloud Platform User Group (GCPUG) TokyoGoビギナーズgolang.tokyoGo Conference
■ 業務GAE/Goでメルカリアッテを作ってます
GoやGCPコミュニティを盛り上げる仕事
Gopherを描く仕事(LINEスタンプ)
2
アッテ開発の技術 : Golang と Google App Engine
アジェンダ
■ 複数アプリにバナーを配信するツールの開発
● バナー配信ツールと必要とされた背景● 柔軟さと運用のしやすさの実現● 複数アプリから利用する● デモ
■ Namespace APIとマルチテナント型アプリ
● Namespace APIとは● マルチテナント型とは● マルチテナント型アプリの実現
■ まとめ
4
複数のアプリにバナーを配信するツールを作る
5
バナー配信ツール
■ 何をするツールか?
● モバイルアプリにバナーを配信する
● バナーの管理や配信条件を設定する
6
バナー配信ツールの要件
■ 複数のアプリから利用する
● メルカリアッテとメルカリから利用
● サービス間で干渉させたくない● サービスごとの特有の処理は入れない
■ わかりやすいUI● 非エンジニアが使う
● サービスごとに別な人が入力する
■ デバッグがしやすい
● 個人環境や開発環境が作りやすい
7
柔軟性と運用のしやすさの実現
■ コア部分は柔軟に
● 配信条件は式で表現
● 関数や変数も使えるようにする
■ UIはわかりやすく
● JSON Editorを用いて自動生成
● 複雑な式は入力させず組み合わせる
8
String(os) == "ios"
この話は別の機会に!
複数のアプリから利用する
■ Namespace APIを使う
● Namespaceを分けることで干渉させない
● サービスごとの設定はデータとして保存○ ソースコードの中には一切書かない
● 管理コンソールのエンドポイントも分ける
9
デモ
10
Namespace APIとマルチテナント型のWebアプリ
11
Namespace APIとは?12
■ Namespace API● Namespaceを分けることのできるAPI● 利用可能なAPI
○ Datastore, Memcache, Task Queue, Search
■ Namespaceを分ける理由
● Namespace間でデータの干渉を防ぐ
● マルチテナント型のWebアプリを作れる
マルチテナント型のWebアプリとは?
■ マルチテナント型
● 1つのシステムを複数のユーザ(企業など)に提供する
■ GAEでの実現方法
13
ApplicationDatastore
NS1 NS2 NS3
Memcache
NS1 NS2 NS3
Namespaceを設定する
■ Contextに埋め込む
■ Datastoreにアクセスする
14
newCtx, err := appengine.Namespace(ctx, ns)
...err = datastore.Get(newCtx, key, &val)
Contextを差し替えるだけ!
Namespaceを取得する
■ 取得する関数はないのでラップする
15
type keyType stringconst key keyType = "namespace"
func WithContext(ctx context.Context, ns string)(context.Context, error) {c, err := appengine.Namespace(ctx, ns)if err != nil {...}return context.WithValue(c, key, ns), nil
}
func FromContext(ctx context.Context) string {ns, _ := ctx.Value(key).(string)return ns
}
ホスト名でNamespaceを切り替える
■ Context付きのハンドラを作る
16
type AEHandler interface {ServeHTTP(c context.Context,
w http.ResponseWriter, r *http.Request) error
}type AEHandlerFunc func(...) errorfunc (f AEHandlerFunc) ServeHTTP(...) error {
return f(c, w, r)}
省略
ホスト名でNamespaceを切り替える
■ ミドルウェアでNamespaceを切り替える
17
func WithNS(h AEHandler) AEHandler {return AEHandlerFunc(func(...){
ns, err := FindNS(c, r.Host)if err != nil {...}c, err = WithNamespace(c, ns)if err != nil {...}
})}
ホスト名で探す
DatastoreにNamespaceを保存
URLとルーティングルール
■ GAEのURLは以下のようにアクセスできる
● Inst: インスタンス(数値)● Ver: バージョン● Serv: サービス● AppID: アプリケーションID
■ ゆるいルーティング
● インスタンス、バージョン、サービスが存在しないとデフォルトのものにルーティングされる
● インスタンスorバージョンの代わりにNamespaceを書く
18
<Inst>-dot-<Ver>-dot-<Serv>-dot-<AppID>.appspot.com
<NS>-dot-<Ver>-dot-<Serv>-dot-<AppID>.appspot.com
管理用APIの分離
■ Namespaceを保存するNamespaceは?
● 管理用のNamespaceは統一しておく● アプリ全体の共通設定などに使う
○ Namespaceの管理など
■ 管理用のAPIは管理者権限を要求する
● Namespaceの保存などは管理者だけ● app.yamlで設定しておく
19
- url: /admin/api/ns/.* script: _go_app login: admin secure: always
Cloud Console上での扱い
■ Cloud Datastore
■ Memcahe
20
マルチテナント型にした利点
■ 他のサービス(アプリ)に影響与えない
● 見かけ上別のものになってる● データが競合しない
■ 開発環境をすぐ作れる
● Namespaceを登録すれば作れる● 同じサービス(アプリ)内でも別の用途に環境
を提供できる○ バナーだけじゃなく、他のコンテンツも
21
マルチテナント型にしときの課題
■ Namespace間の設定の移行● 開発環境を用意する際にほしい
● 移行するAPIを用意する必要がある
■ バグが出ると全滅する
● すべて同じソースコードを使ってる
● バージョンをうまく使って移行する
■ ローカルでのデバッグが面倒
● ローカルのコンソールのNamespaceの対応が貧弱
● MemcacheはNamespaceを指定できない
22
まとめ
■ 柔軟さと運用のしやすさのバランスは大事● 柔軟でも使いづらかったら意味がない● 工夫次第で両立することは可能
■ GAEでマルチテナント型のアプリは簡単● Namespace APIが使える
● バージョン/サービスとうまく組み合わせる
■ GAEで社内ツールを作ると便利● アクセス制御も簡単
● G Suite のアカウントも使える
23
golang.tokyo ☓ GCPUG
24
4月開催予定@メルカリ発表者募集中!
Thank you!
twitter: @tenntenn Qiita: tenntennconnpass: tenntenn
25