ikeike443のブログ

ソフトウェアビジネスに関心がある系のブログ

Kong Plugin 開発の始め方

Kongは軽量なAPIゲートウェイとして広く世界中で使われています。クラシカルなAPIマネジメントの文脈ではもちろんのこと、KubernetesネイティブなAPIゲートウェイとしても人気があります(CNCF Hubでも見つけられます)。さらに最近CP/DPセパレーションも実現して*1、ますます使いやすくなっています。

Kongの魅力は圧倒的なスループットもさることながら、プラグイン開発をすることでゲートウェイにいろんな処理を挟み込めることじゃないでしょうか。プラグインはすでに公式のものだけでも結構な数があり、特にOpenID Connectはかなりの人気がありますが、更にプラグインを自作することができます。

今回はKong Plugin開発の始め方についてご紹介します。なお、Kong OSSでもKong Enterprise Editionでも、Plugin開発のやり方は基本的に同じです。

ドキュメントなど

まず公式のガイドは以下の2つになります。それぞれOSS版、EE版のドキュメントですが、内容は同じです。

Plugin Development - Introduction - v2.0.x | Kong - Open-Source API Management and Microservice Management

Plugin Development - Introduction - v1.3-x | Kong - Open-Source API Management and Microservice Management

基本的にはこのガイドに従ってファイルを作っていき、APIドキュメントを見ながら開発していけば動くはずなのですが、開発にはKongの環境が必要だったり、NginxやLua/OpenRestyの知識が必要だったりと、なかなかハードルが高いです。*2

Kong社では、このあたりのハードルを下げるための開発・テストフレームワークを用意しています。

Kong-pongoというフレームワークと、 github.com

Kong-pluginというテンプレートの2つです。 github.com

この2つを使って、ヘッダの追加、書き換えを行うプラグインを書いてみたいと思います。

Kong-Pluginリポジトリのフォーク

ますはじめに、GitHub上でkong-pluginリポジトリをフォークしてください。このリポジトリはKong社が用意しているプラグイン開発のテンプレートです。開発を始めるのに必要な設定ファイルやマニフェストプラグインディレクトリ構造、テストファイルなどを用意してあり、すぐに実行できる状態になっています。

フォークしたら、リポジトリの設定画面で、"Template repository"にチェックを入れてこのリポジトリをテンプレートとして使えるようにしましょう。

f:id:ikeike443:20200315111242p:plain
リポジトリの設定画面

この設定を保存したら、GitHub上で新規リポジトリ作成をします。

リポジトリ作成時に、先程設定したテンプレートを選択してください。

f:id:ikeike443:20200315111444p:plain
テンプレートを選択

こうして作ったリポジトリ上で開発を行います。ローカルPCにクローンしておいてください。

ファイルの説明を簡単に。Pluginの構成は以下のようになっています。

$ cd my-first-plugin
$ tree .
.
├── LICENSE
├── README.md
├── kong
│   └── plugins
│       └── myplugin
│           ├── handler.lua
│           └── schema.lua
├── kong-plugin-myplugin-0.1.0-1.rockspec
└── spec
    └── myplugin
        ├── 01-schema_spec.lua
        └── 02-access_spec.lua

まず kong-plugin-myplugin-0.1.0-1.rockspec というのがマニフェストファイルです。rocspecというのはLuaのパッケージマネージャであるLuaRocksの仕様です。詳しく知りたい方はこちらをどうぞ。今回の開発では一旦このまま放置しておいても問題ないです。

kong/plugins/myplugin フォルダ以下に配置されているのがプラグインのソースファイルです。なお、mypluginというフォルダ名はrockspecで定義したプラグイン名から来ています。

  • handler.lua: リクエスト・レスポンスのハンドラです。Kongが定義したイベントハンドラにここからアクセスして、処理を組み込めます。NginxやOpenRestyに詳しいなら理解は簡単なはずです

  • schema.lua: プラグインのコンフィグを入れておくスキーマ定義です。ここで定義したフィールドを使ってユーザーは設定値をカスタマイズできます

spec/myplugin/ フォルダ以下にあるのがSpecファイルです。Bustedという、Lua製のBDDフレームワークを使っています。Rspecになれた人なら簡単だと思います。

Kong-pongoのインストール

次に、kong-pongoをクローンして、ローカルにインストールを行います。Pongoは、プラグイン開発に必要なKong環境を用意してくれるフレームワークです。Kong起動に必要なPostgress/CassandraのDockerコンテナを用意してくれたり、該当バージョンのKong Dockerイメージをビルドして起動してくれたりします。OpenRestyやBustedといった依存モジュールも全部用意されます。開発環境構築の面倒を見てくれる便利フレームワークです。

基本的にはREADMEに書いてあるとおりに行えば大丈夫なはずですが、pongoはDockerがインストールされていることを前提していているのでDockerがない場合にはまずそれを入れてください。

あとは下記に書いてあるとおりで大丈夫です。MacOSの人はCoreutilsが必要になるのでそれも入れてください。 f:id:ikeike443:20200315112033p:plain

その他に前提条件としてLICENCEが必要とかBintrayが必要とか書いてありますが、これはKong EEに対して開発する場合の話なので、OSS版に対しての開発の場合は必要ありません。EEで開発したい場合には私に問い合わせてくれればトライアルライセンスをお渡しできます。

Pongoで開発を始める

Pongoがインストールできたら、開発対象のリポジトリ(先程テンプレから作成してクローンしておいたもの)に移動します。

$ cd ../First-Kong-Plugin  # 自分でつけた名前のディレクトリに移動。Kong-pongoじゃないことに注意

プラグインディレクトリに移動したらまずは動作確認も兼ねて、pongo run します。このコマンド一発で、依存するPostgress/CassandraのDockerコンテナを起動した上で、配下にあるSpecファイルを探し出して実行して単体テストをしてくれます。

$ pongo run
Notice: auto-starting the test environment, use the 'down' action to stop it
Creating network "kong-pongo_test-network" with the default driver
Creating kong-pongo_postgres_1 ... done        # Postgresイメージ作成
Creating kong-pongo_cassandra_1 ... done      # Cassandraイメージ作成
Waiting for postgres
Waiting for cassandra
Notice: image 'kong-pongo-test:2.0.1' not found, auto-building it   # PongoイメージがなければBuild

...中略: dockerイメージのPull, Build...

Successfully tagged kong-pongo-test:2.0.1

Stopping after installing dependencies for kong-plugin-myplugin 0.1.0-1

# Pongo run (./spec) の実行開始
Kong version: 2.0.1
[==========] Running tests from scanned files.
[----------] Global test environment setup.
[----------] Running tests from /kong-plugin/spec/myplugin/01-schema_spec.lua
[ RUN      ] /kong-plugin/spec/myplugin/01-schema_spec.lua @ 18: myplugin: (schema) accepts distinct request_header and response_header
[       OK ] /kong-plugin/spec/myplugin/01-schema_spec.lua @ 18: myplugin: (schema) accepts distinct request_header and response_header (1.20 ms)
[ RUN      ] /kong-plugin/spec/myplugin/01-schema_spec.lua @ 28: myplugin: (schema) does not accept identical request_header and response_header
[       OK ] /kong-plugin/spec/myplugin/01-schema_spec.lua @ 28: myplugin: (schema) does not accept identical request_header and response_header (2.01 ms)
[----------] 2 tests from /kong-plugin/spec/myplugin/01-schema_spec.lua (289.37 ms total)

[----------] Running tests from /kong-plugin/spec/myplugin/02-access_spec.lua
[ RUN      ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 53: myplugin: (access) [#postgres] request gets a 'hello-world' header
[       OK ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 53: myplugin: (access) [#postgres] request gets a 'hello-world' header (48.05 ms)
[ RUN      ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 71: myplugin: (access) [#postgres] response gets a 'bye-world' header
[       OK ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 71: myplugin: (access) [#postgres] response gets a 'bye-world' header (7.35 ms)
[ RUN      ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 53: myplugin: (access) [#cassandra] request gets a 'hello-world' header
[       OK ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 53: myplugin: (access) [#cassandra] request gets a 'hello-world' header (78.16 ms)
[ RUN      ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 71: myplugin: (access) [#cassandra] response gets a 'bye-world' header
[       OK ] /kong-plugin/spec/myplugin/02-access_spec.lua @ 71: myplugin: (access) [#cassandra] response gets a 'bye-world' header (6.05 ms)
[----------] 4 tests from /kong-plugin/spec/myplugin/02-access_spec.lua (16132.22 ms total)

[----------] Global test environment teardown.
[==========] 6 tests from 2 test files ran. (16422.94 ms total)
[  PASSED  ] 6 tests.

こんなイメージです。ログを見て分かる通り、依存しているPostgress/CassandraをそれぞれDocker pullしてBuildの上起動してくれ、その後kong-pongo-testという全部入りのKongイメージのビルドを始めます。

それが終わった後、kong-pongo-testコンテナを起動して、その上でspecフォルダ以下のテストを実行して、結果を教えてくれる、というそういう流れになっています。

あとはファイルをいじりながらテストを繰り返していけば開発ができます。

なお、pongo runはテスト終了後にkong-pongo-testコンテナについては自動で終了してくれますが、Postgress/Cassandraコンテナについては自動では終了しません。こちらを終了したい場合には、明示的に手でpongo downする必要があります。なお、逆に明示的にPostgress/Cassandraなど依存コンテナだけ起動したい場合にはpongo upでできます。pongo runは起動時に依存コンテナがupしてなければ自動でやってくれますが、終了時にdownはしてくれないということです。

Pongoを使ってマニュアルでKongをテストする

Specを通してではなくて実際にKongを起動してマニュアルテストをしたい場合には、下記コマンドを実行すると、pongoが立ち上げたKongコンテナにsshログインできます。

$ pongo up
$ pongo shell

Stopping after installing dependencies for kong-plugin-myplugin 0.1.0-1

Kong version: 2.0.1
/kong #

次にこのShell上でKongのDBマイグレーションを走らせます。ちなみに初回のみです。次回以降pongo shellした際はこの手順は必要ありません。

/kong # kong migrations bootstrap
Bootstrapping database...
migrating core on database 'kong_tests'...
core migrated up to: 000_base (executed)
core migrated up to: 003_100_to_110 (executed)
core migrated up to: 004_110_to_120 (executed)
core migrated up to: 005_120_to_130 (executed)
core migrated up to: 006_130_to_140 (executed)
core migrated up to: 007_140_to_150 (executed)
core migrated up to: 008_150_to_200 (executed)
migrating hmac-auth on database 'kong_tests'...
hmac-auth migrated up to: 000_base_hmac_auth (executed)
hmac-auth migrated up to: 002_130_to_140 (executed)
migrating oauth2 on database 'kong_tests'...
oauth2 migrated up to: 000_base_oauth2 (executed)
oauth2 migrated up to: 003_130_to_140 (executed)
migrating jwt on database 'kong_tests'...
jwt migrated up to: 000_base_jwt (executed)
jwt migrated up to: 002_130_to_140 (executed)
migrating basic-auth on database 'kong_tests'...
basic-auth migrated up to: 000_base_basic_auth (executed)
basic-auth migrated up to: 002_130_to_140 (executed)
migrating key-auth on database 'kong_tests'...
key-auth migrated up to: 000_base_key_auth (executed)
key-auth migrated up to: 002_130_to_140 (executed)
migrating acl on database 'kong_tests'...
acl migrated up to: 000_base_acl (executed)
acl migrated up to: 002_130_to_140 (executed)
migrating session on database 'kong_tests'...
session migrated up to: 000_base_session (executed)
migrating response-ratelimiting on database 'kong_tests'...
response-ratelimiting migrated up to: 000_base_response_rate_limiting (executed)
migrating rate-limiting on database 'kong_tests'...
rate-limiting migrated up to: 000_base_rate_limiting (executed)
rate-limiting migrated up to: 003_10_to_112 (executed)
23 migrations processed
23 executed
Database is up-to-date

Database is up-to-dateとなればOKです。ここでPostgresまたはCassandraのエラーが出る場合、DBコンテナが立ち上がっていませんので、いちどShellからExitし、改めてpongo upして起動してみてください。

OKなら、Kongを起動します。

/kong # kong start
Kong started

起動できたら動作確認します。Pongoコンテナには予めHTTPieが入っていますので、それを使って動作確認します。HTTPieに慣れない人はcurlを使っても同じことです。

localhostの8001番ポートにリクエストを発行して、動作確認ついでにAdmin APIの設定状況を確認します。

/kong # http localhost:8001
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 8973
Content-Type: application/json; charset=utf-8
Date: Mon, 16 Mar 2020 06:09:27 GMT
Server: kong/2.0.1
X-Kong-Admin-Latency: 186

{
    "configuration": {
        "admin_acc_logs": "/kong-plugin/servroot/logs/admin_access.log",
        "admin_access_log": "logs/admin_access.log",
        "admin_error_log": "logs/error.log",
        "admin_listen": [
            "127.0.0.1:8001 reuseport backlog=16384",
            "127.0.0.1:8444 http2 ssl reuseport backlog=16384"
        ],
...中略...
    "plugins": {
        "available_on_server": {
            "acl": true,
            "aws-lambda": true,
            "azure-functions": true,
            "basic-auth": true,
            "bot-detection": true,
            "correlation-id": true,
            "cors": true,
            "datadog": true,
            "file-log": true,
            "hmac-auth": true,
            "http-log": true,
            "ip-restriction": true,
            "jwt": true,
            "key-auth": true,
            "ldap-auth": true,
            "loggly": true,
            "myplugin": true,  # 注目:今回開発しているプラグインがロードされています

...後略...

上記のようにレスポンスが返ってくれば正しく動作しています。開発中のプラグインがロードされていることも確認できます。

動作が確認できればあとは普通のKongです。ServiceやRouteを登録して、そこにPluginを紐付ければ手動テスト可能です。

と言いつつこれを読んでる人はKongがどういうものかしらない人も多いと思うので、ServiceとRouteをAdmin APIで登録し、そこに開発中のPluginを紐付けて、手動でテストできるところまでお見せします。

Serviceの登録

引き続きpongo shellの中で下記を実行します。Serviceオブジェクトとは、Kongがプロキシする対象のアップストリームサービスを指すものです。

http POST :8001/services/ name=mock-service url=http://mockbin.org
HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 293
Content-Type: application/json; charset=utf-8
Date: Mon, 16 Mar 2020 06:37:50 GMT
Server: kong/2.0.1
X-Kong-Admin-Latency: 178

{
    "client_certificate": null,
    "connect_timeout": 60000,
    "created_at": 1584340670,
    "host": "mockbin.org",
    "id": "129b9b78-c493-42c6-b834-e754798ba462",
    "name": "mock-service",
    "path": null,
    "port": 80,
    "protocol": "http",
    "read_timeout": 60000,
    "retries": 5,
    "tags": null,
    "updated_at": 1584340670,
    "write_timeout": 60000
}

mock-serviceという名前で、http://mockbin.orgを指すサービスを作りました。 MockbinはKongが提供するモックサービスです。デフォルトではhttp://mockbin.org/mock/requestで常にリクエストを受け取って返事をしてくれます。

Routeの登録

次にRouteオブジェクトを作ります。Kongがサービスにリクエストをルーティングする際に参照するものです。

ここでは下記のようにして、ヘッダーに"Host: mockbin.org"がありかつリクエストパスが/mockだったときに先程のmock-serviceオブジェクトにルーティングするように設定します。

/kong # http POST :8001/services/mock-service/routes hosts:='["mockbin.org"]' paths:='["/mock"]'
HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 435
Content-Type: application/json; charset=utf-8
Date: Mon, 16 Mar 2020 06:38:04 GMT
Server: kong/2.0.1
X-Kong-Admin-Latency: 12

{
    "created_at": 1584340684,
    "destinations": null,
    "headers": null,
    "hosts": [
        "mockbin.org"
    ],
    "https_redirect_status_code": 426,
    "id": "cd661405-a1a8-4465-a347-daf5ce32e030",
    "methods": null,
    "name": null,
    "path_handling": "v0",
    "paths": [
        "/mock"
    ],
    "preserve_host": false,
    "protocols": [
        "http",
        "https"
    ],
    "regex_priority": 0,
    "service": {
        "id": "129b9b78-c493-42c6-b834-e754798ba462"
    },
    "snis": null,
    "sources": null,
    "strip_path": true,
    "tags": null,
    "updated_at": 1584340684
}

Pluginの紐付け

最後に、mock-serviceサービスに開発中のプラグインを紐付けます。

/kong # http POST :8001/services/mock-service/plugins name=myplugin
HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 325
Content-Type: application/json; charset=utf-8
Date: Mon, 16 Mar 2020 06:41:35 GMT
Server: kong/2.0.1
X-Kong-Admin-Latency: 12

{
    "config": {
        "request_header": "Hello-World",
        "response_header": "Bye-World",
        "ttl": 600
    },
    "consumer": null,
    "created_at": 1584340895,
    "enabled": true,
    "id": "68caa29c-8985-4f75-87d7-c25bb89efd35",
    "name": "myplugin",
    "protocols": [
        "grpc",
        "grpcs",
        "http",
        "https"
    ],
    "route": null,
    "service": {
        "id": "129b9b78-c493-42c6-b834-e754798ba462"
    },
    "tags": null
}

これで、mock-serviceにリクエストを送ると常にmypluginが動作するようになりました。

プラグインの手動テスト

下記のようにリクエストを発行してテストしてみましょう。

/kong # http :8000/mock/request Host:mockbin.org
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: host,connection,x-forwarded-for,x-forwarded-proto,x-forwarded-host,x-forwarded-port,x-real-ip,accept-encoding,accept,user-agent,hello-world,x-request-id,via,connect-time,x-request-start,total-route-time
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: *
Bye-World: this is on the response # 今回のプラグインが差し込んでいるヘッダ
...後略...

上記のように、Bye-Worldというヘッダが差し込まれているのが確認できます。これが今回のプラグインが動作している証拠です。ちなみに参考までにこれを行っている該当コードは下記です。

まずschema.luaで下記のようにヘッダ名を定義しています。

          { response_header = typedefs.header_name {
              required = true,
              default = "Bye-World" } },

次にhandler.luaで設定したヘッダを読み込み、そこに値をセットしています。

---[[ runs in the 'header_filter_by_lua_block'
function plugin:header_filter(plugin_conf)

  -- your custom code here, for example;
  ngx.header[plugin_conf.response_header] = "this is on the response"

end --]]

こんなふうにして、手動で動作確認、テストすることも可能です。

まとめ

いかがだったでしょうか。

Pongoを使えば、面倒な環境構築も素早く簡単に済ませてプラグイン開発に専念できることがわかったかと思います。BDDも手軽にできますし、CIのセットアップも簡単です。

特定バージョンのKongを指定することもできますし、Kong EEを指定することも可能です。他にも様々な機能が用意されています。そのあたりはぜひPongoのREADMEを読んで、試して見ください。

出来上がったプラグインをパッケージにしてインストール・配布する場合には基本的にはLuarocksを使って行うことになります。こちらのドキュメントを参考にしてください

ぜひ、面白いプラグインを作ってみてください!

*1:いまはOSSのみですが、もうすぐEEに搭載されます

*2:なお、最近Go言語によるプラグイン開発も可能になりましたが、今回の説明では割愛します

Sansan Innovation Project 2020 に登壇します

GitHub時代に大変お世話になった及川卓也さんのお誘いで、Sansan Innovation Project 2020 に登壇させていただくことになりました。及川卓也さん、メルカリの名村卓さんと「社内ハッカーのすすめ」というお題でパネルディスカッションさせていただきます。1日目の3月12日です。

自分は日本はじめ世界各国にInnersourceの実態を見聞きしてきた立場として、海外及び日本の状況や、Innersourceをするのに何が重要なのか、といったあたりを話しできればと思います。

イベントサイトはこちらです。 jp.sansan.com

当該セッションは下記から探せます。まだ若干席があるらしいので、よろしくどうぞー! https://sip2020.smktg.jp/public/application/add/64?fsi=BdJRzHPB&ebx=egmk14626w.1578041565.79gaja9

ちなみに全然関係ない話ですけど、このイベントサイトもシャノンさんのプラットフォームですね。シャノンに在籍した身として感慨深いです。ほんとにシャノンさんは国内でシェアとってますね。

2月17日にパートナーさんとミートアップします

今回は日本のパートナーであるエクセルソフトさんの協力の下、エクセルソフトさんのミートアップに私と、SEのトップのFelderi Santiagoの2人でお邪魔して、Kong for KubernetesやUniversal Service MeshのKumaについて、お話をします!

ご興味のある方はぜひ、エクセルソフトさんの下記のページからお申し込みをお願いします! 軽食もでるとのことです。 www.xlsoft.com

内容的には下記の感じです。

18:30 開場

19:00 - 19:05 開催のご挨拶/会場の説明 : エクセルソフト 田淵 義人

19:05 - 19:25 Kong の概要 : エクセルソフト 田淵 義人

19:25 - 19:35 休憩

19:35 - 19:40 Kong の日本展開について : Kong Solutions Engineer 池田尚史 氏

19:40 - 20:20 Kong の未来:Kong for Kubernetes と Kuma (Universal Service Mesh) : Kong Global Director Felderi Santiago 氏

20:20 - 21:30 懇親会

21:30 - 22:00 撤収

Kongにジョインしました

ジョインしました、というのはかなり正確な表現です。Kongはまだ日本法人がないため、契約上は業務委託となっているので、入社というのはちょっと違うからです。

法人もなければまだオフィスもないので、今のところ私の自宅がKong Japanです。 f:id:ikeike443:20200103172748p:plain

Kongはサンフランシスコに拠点を置く会社で、APIゲートウェイKubernetesIngress controllerおよびService meshの領域で複数のOSSとそのエンタープライズ・ソリューションを提供している会社です。競合はApigeeやMulesoftと言われることもありますが、むしろLinkerdや最近Service meshみが著しいConsulあたりになっていくかもしれない雰囲気を出し始めていて、なかなか面白いことになりそうだと感じています。(Istioも競合になり得るかもしれないけど、今はむしろ協調して使ってもらうイメージを考えてるっぽい)

github.com

github.com

kuma.io

まだ自分もジョインしたばかりで勉強中なのでアレですが、マイクロサービスを推進していく際に最初に導入すべきものとして認知されていってきてるのが強みかなと思います。様々ソリューションを出していて、それをエンタープライズ・ソリューションを使って統合すると、アプリ種別でいうと伝統的なモノリスアプリから、k8s、各種サーバレスアプリ、プロトコルでいうとREST, GraphQL, gRPC, etc... をもろもろ合わせて透過的に扱えるようになるはずです。

特に個人的には最近出したKumaに注目しています。CTOの下記メッセージがとても刺さったのがジョインのきっかけでもあります。

Before Kuma, service mesh was considered to be the last step of architecture modernization after transitioning to containers and perhaps to Kubernetes. We believe this philosophy is backwards. Service mesh should be available before implementing other massive transformations so that developers can keep the network both secure and observable in the process.

訳: Kuma以前だと、サービスメッシュというのはアーキテクチャのモダン化プロセスの中でのコンテナ化とかKubernetesへの移行を終えた後の最後のステップと捉えられがちでした。我々はこの考え方はまるっきり逆だと考えています。サービスメッシュは大きなアーキテクチャの移行を実施し始める前に導入すべきです。それによってネットワークをセキュアでモニタリング可能な状態に保ちながら、アーキテクチャの移行プロセスを進めることができるからです。

jaxenter.com

当分は自宅とサンフランシスコで研修を受けたあと、既存のパートナー様やお客様先などを訪問する予定です。(日本にはすでに複数お客様がいらっしゃいます)

さて、とりあえずしばらく日本でたった一人なので、よかったらランチとか、Co-workとか、誘ってくださいまし。

出張時に役立つTips

ソリューションズエンジニアとして働くようになって、ここ数年は仕事で出張することが非常に多くなりました。国内出張は月に2,3回、海外出張は4半期に1,2回の頻度ですから、荷物をいかに素早く用意できるかが結構重要です。この頻度ですと、毎回出張の都度何が必要か考えて用意しているとしんどいので、予めいろいろなものを用意しておくようになります。

今回は僕がこの4年でやるようになったTips的なことを共有します。参考になれば幸いですし、もしもっといい方法を知ってる人がいれば、教えてほしいです。情報交換していきましょう。主に海外出張時のTipsが主ですが、そのまま国内出張にも使っています。

バックパック

仕事で2泊やせいぜい3泊程度の海外出張を上記したような頻度ですることが多いのですが、この頻度だと飛行機に乗り込む都度いちいち荷物として預けて到着時に毎回Luggage claimで待たされるのが面倒になります。飛行機はLuggage lostも割とありますし、できれば荷物をそのまま機内に持ち込みたいですが、機内持ち込み可のサイズだとそこまで荷物が入らなかったりします。

そこで僕が使ってるのがオスプレイのこのバックパックです。

40リットルの容量が入って、国内線、国際線、両方とも機内持ち込み可能です。詰め込むともう少し入ります。 スーツケースのように180度フラットに全開する構造になっていて、荷物の積み込みが非常にしやすいです。冬であれば2泊から頑張って3泊分の着替えや日用品が入ります。夏であれば詰め込めば4泊も不可能ではないです。

マックブックやiPadなんかも安全にしまえるように専門のポケットがありますし、何かと便利です。

洗面用品

歯ブラシやひげ剃り、クリームやその手のものってなんていうんですかね。洗面用品であってます? グルーミング用品かな? 化粧品というと少し違和感がある。

ともあれ、この手のものは日常でも使っているものをそのまま出張にも持っていくという人が普通だと思います。そうすると問題になるのが、この手の品物って、当日の朝まで使っていることが多いのでそのまま当日積み込み忘れたりとか、逆に前日に積み込んでしまって朝慌てて出し直すとか(そしてそのまま忘れる)、だと思います。

僕は同じくオスプレイのこれを使っています。

これは洗面用品を入れて丸めて収納するバッグです。広げるとフックが付いていて、ホテルや家の壁に引っ掛けてそのまま使えます。

この写真みたいな感じですね。これは非常に便利です。僕は写真のように、日常的に使っているデオドラントやひげ剃り、また旅行用の歯ブラシや歯磨き粉などを常にこのバッグに入れた状態にして家の洗面所の壁にぶら下げています。

出張の日の朝までこの状態で使って、使い終わったらこのまま壁から外して丸めてかばんに突っ込みます。必要なものがすべてここに入っているので絶対に忘れないという寸法です。

なお、こんなふうに簡易的な鏡もついているので、安めのホテルで鏡がないというときにも便利です。

SIM

海外出張するとインタネット接続をどうしようかという悩みが出てくるかと思います。短期の出張であれば、キャリアが提供しているローミングでもいいと思いますが、結構高いですよね。それなりの頻度で海外出張している人なら、もっと安い手段を選んだほうがいいと思います。

最近だとGoogle FIがいいのかもしれませんが、たしかまだ日本からは使えないので試してません。使ってる人は使い心地を教えて下さい。

僕が使っているのはこのKeepgoというグローバルデータSIMサービスです。 www.keepgo.com

年間1GBで$49です。1GBという容量はたしかに少ないですが、年間契約というところがポイントです。ほとんどのデータSIMサービスが月間契約で月$20~30取るところを、年間で$49ですむというのがお得だと思います。僕のように「年間に4,5回出張するが1回の出張あたり滞在は数日で大抵の場合Wifiに接続しているので衛星回線につなぐ頻度はそこまで高くない、でも例えばカンファレンス終了後にホテルに戻るとか、ディナー後にレストランの外からUberを呼ぶとか、必要なケースがある。でも毎月維持費を払うほどじゃない」という人間は意外と多いと思います。

そんなときに年間契約のSIMは非常に使い勝手がいいです。大抵の場合オフィスやカンファレンスセンターのWifiで足りるので、年間1GBで意外と足りますし、足りなくなってもチャージも簡単でやすいです。

カバーしている国も120カ国と非常に広く、主要な国はすべて網羅しています。実は日本もカバーしてます。

興味がある人には下記に10%オフのクーポンがあるので使ってください。 go.referralcandy.com

電話番号

あまり必要ないかもしれませんが、データSIMを用意すると次にあるといいのは海外での電話番号です。特にUberを使うときにはドライバーとやり取りするときに電話番号が必要ですので、用意しておく必要があります。

最近はデュアルSIMに対応した端末が増えたので、日本の音声通話可能なSIMを挿したままグローバルSIMを挿しておけばいいだけかもしれませんが、僕のようにデュアル端末を持っていない場合にはデータSIMを挿してしまうと電話を受けられなくなります。

僕はUberのためにSkypeで電話番号をとってます。別にここはGoogle Voiceでも他のサービスでもいい気がします。

電源変換アダプター

国によって電源プラグの形が違いますので、これも用意しておく必要があります。僕は実はこれを複数持っています。。洗面用品と違って、こっちはしょっちゅう旅行時に持って行き忘れるからです。。 アメリカは日本と同じ形状なのでいいのですが、オーストラリア、韓国、シンガポール、インド、みんな違います。僕は忘れるたびに現地で買い直しているので、たくさん持っています。。ホテルが貸してくれることも多いので、それで済ますこともあります。

マックブックを使っている人であれば、下記を買ってしまうのも手だと思います。

Appleワールドトラベルアダプタキット

Appleワールドトラベルアダプタキット

  • 発売日: 2015/02/17
  • メディア: Personal Computers

シャワー

最後ですが、飛行機に乗る前にシャワーを浴びるといいです。よく寝られます。また、現地到着時の体のベタつきとか臭いとか、不快度が劇的に下がるので、現地についてからの行動がスムーズで早くなります。 ラウンジアクセスがない人も、実は各空港で有料のシャワーサービスがあったりするので、探して使うといいです。

マイクロソフトを退職します

もとい、4年7ヶ月ソリューションズエンジニア(=セールスエンジニア)として勤めたGitHubを退職します。月曜が最終出社で、年末をもって退職です。

f:id:ikeike443:20190610223940j:plainf:id:ikeike443:20190610223954j:plainf:id:ikeike443:20190529140039j:plainf:id:ikeike443:20150903222741j:plainf:id:ikeike443:20151214214354j:plainf:id:ikeike443:20191205215414j:plainf:id:ikeike443:20180802190726j:plainf:id:ikeike443:20160916193639j:plainf:id:ikeike443:20150617180348j:plainf:id:ikeike443:20150624203835j:plainf:id:ikeike443:20150619202555j:plainf:id:ikeike443:20151013001628g:plain
GitHubでの思い出たち

思い返せば2014年、GitHubに応募したときにはまだGitHubにはグローバルでも120人ほどしか社員がいなかったのですが、半年後、2015年に入社したときには300人、その翌年には600人を超える規模に急激に成長しました。。 2019年も終わりの現在、1400人近くいます。来年にはさらに倍近く増えるはず。随分大きな企業になったものだ。。この4年半でシリーズBで2.5億ドル調達、その3年後にはマイクロソフトに75億ドルで買収されたわけです。いやはや。。

日本法人も私が入社したときはDiceと僕の2人しかおらず、アメリカからセールスがもう1人の3人体制でしたが、今は16人ほどに増えています。いやー大きくなった。 自分はずっとJapanチームとAPACチーム両方に所属していたのですが、APACのセールスは2015年当初は僕と今のVP of APACの2人しかいなかったけど、これも数十人規模になりました。

シリコンバレーユニコーン企業に4年半勤めたというのはかなり得難い経験だったな、と思います。。HBOのドラマに『シリコンバレー』という人気シリーズがあるのですが、観たことありますか? 観たことない人はぜひ観てほしいのですが、あのドラマを地で行くような4年半でした。マジで。。波乱しかなかった。。

マイクロソフトに買収され、財務的にも強固になりました。ファウンダーはじめ初期の社員はもうほとんど残ってないけど、マイクロソフトの助けを借りてより一層、デベロッパーのプラットフォームとして輝いていくことでしょう。

さて、僕はというと、そろそろ次のフェーズを考えたいな、というのが正直なところで、この1年間、いろんな可能性を探っていましたが、来年1月より、別のサンフランシスコベースのスタートアップに(日本から)参加することにしました。この会社も成功するといいなと思ってます。

この会社はまだ日本法人もない会社なので、年明けてしばらくは業務委託という形を取ることになりそうです。期せずして独立ですね。。業務委託の受け皿として元々持っていた個人事務所を使う感じになるので、せっかくなのでその他の事業もゆるーくやれたらなと思ってます。

というわけで12月は暇なので、是非ランチや飲みに誘ってください!

お約束のほしいものリストを置いておきます。 :-)

Paint GitHub がいい

同僚の Muan がいい感じに GitHub 上でお絵かきができる Extension を書いて公開してました。

github.com

ChromeFirefoxのExtension として提供されています。 chrome.google.com

これを使うと例えば、下記のような感じで、GitHub上でキャプチャの上に線や矢印引いて要望をビジュアルに伝えたり、とかもできます。いろんな可能性が広がりそうですね。


draw

本体に組み込んでもいいんじゃないのという気もするくらい、気に入りました。