はじめに
この記事では、Kubernetes の概要とともに、サンプルアプリケーションを開発してデプロイする方法を学びます。くどい説明や他の資料との重複を避けるため、理論のトピックを最初に取り上げるのではなく、Kubernetes クラスタに最初のアプリケーションをデプロイする上でどのような作業が必要なのかを重点的に説明します。ただし、理論のトピックを避けるわけではなく、必要に応じてその場で学んでいきます。こうしたアプローチにより、抽象的で無意味なものになりがちな、早すぎる段階での議論や説明が避けられます。
この記事を読み終えると、Kubernetes クラスタを(DigitalOcean上に)構築する方法を習得して、クラスタでアプリケーションを実行できるようになります。このトピックに魅力を感じた場合は、ぜひお読みください。
“この記事では、Kubernetesの基本的な概念を学ぶと同時に、Kubernetesクラスタにサンプルアプリケーションをデプロイする方法を理解できます。おすすめです。”
これをツイートする
Kubernetes の概要
Kubernetes とは、コンテナ化したアプリケーションのデプロイ、スケーリング、管理を自動化するためのオープンソースシステムです。このプラットフォームでは、アプリケーションをマイクロサービスと呼ばれる小規模のシステムに分解して開発を進め、それらのシステムを取りまとめて(つまり、オーケストレーションして)、デプロイできます。これから学ぶとおり、Kubernetes には、アプリケーションのマイクロサービスを管理の容易な論理ユニットへと整理しやすくなるよう、様々なオブジェクトが用意されています。
上記の説明は的確なものですが、Kubernetes やマイクロサービスになじみがない場合、あいまいで抽象的すぎるかもしれません。今回の記事の目標はそのような概論を避けることですので、さっそく実践に入りましょう。
Kubernetes クラスタを構築する方法
現時点で、各国のサービスから多種多様な Kubernetes 実装が提供されています。その中でも利用率がきわめて高い実装は、以下のとおりです。
- Minikube:ローカルマシンにインストールすると、Kubernetes をローカルで使用できるようになるオープンソースツールです。VirtualBoxをはじめとする仮想化ソリューションを利用して、ローカルの Kubernetes クラスタをセットアップします。
- Google Kubernetes Engine(GKE):本番運用可能な Kubernetes クラスタを管理するための Google 社のソリューションです。
- Amazon Elastic Kubernetes Service(EKS):本番運用可能な Kubernetes クラスタを管理するための Amazon 社のソリューションです。
- Azure Kubernetes Service(AKS):本番運用可能なマネージド型の Kubernetes クラスタを提供する Azure ソリューションです。
- OpenShift Kubernetes:Kubernetes クラスタを制御するための Red Hat 社のソリューションです。
注:Minikube は、無期限で無償となっている唯一のソリューションです(ただし、ローカルでしか実行できないことから、有用性もさほど高くありません)。無料枠が設定され、初期費用なしで利用を開始できるソリューションは他にもいくつかありますが、クラスタを実行し続けると、最終的には料金の請求が発生します。
DigitalOcean を選ぶ理由
今回の記事では DigitalOcean を使用すると述べたにもかかわらず、前述のリストに DigitalOcean が含まれていないことにお気づきかもしれません。その理由は、DigitalOcean がManaged Kubernetes Serviceを投入した直後であり、同サービスが今なお限定提供モードであるためです。
つまり、DigitalOcean Kubernetes については、すべての機能が実装され、十分なサポートが提供されているものの、本番運用可能とは言えない部分(エラーが発生するおそれ)があります。ただし、この記事の目的を果たす上では、現行のサービスは十分に安定しています。また、この記事内の紹介リンクから、60 日間有効な 100 米ドル分の DigitalOcean クレジットが利用できるので、無償でクラスタを構築できます。
Kube Control(kubectl)をインストールする
Kubernetes クラスタを構築する前に、
kubectl
と呼ばれるツールが必要になります。一般に「Kube Control」として知られるこのツールは、Kubernetes クラスタをターミナルから簡単に管理できるコマンドラインインターフェイスです。kubectl
を使いこなすまでに、さほど時間はかかりません。kubectl
をインストールするには、この資料にアクセスし、記載されているリストを参照して、使用している OS 向けの手順に従ってください。当該のリストには、以下の OS での手順が記述されています。- Linux(およびUbuntuなどの派生バージョン)
- macOS(HomebrewまたはMacPortsを使用することで導入可能)
- Windows(PowerShellとChocolateyについて手順の記載あり)
それぞれの手順に従って
kubectl
をマシンにインストールした後、以下のコマンドを実行すると、ツールが使用可能になったかどうかを確認できます。kubectl version
上のコマンドの出力には、クライアントのバージョン(
kubectl
のリリース)と「connection to the server localhost:8080 was refused」というメッセージが表示されています。このメッセージは、kubectl
のインストールは問題なく完了したものの、(存在しているはずの)クラスタが使用可能でないことを意味します。以下のセクションで、Kubernetes クラスタを構築する方法を学んでいきます。DigitalOcean 上で Kubernetes クラスタを作成する方法
使用する Kubernetes クラスタがすでに存在している場合は、このセクションの作業を省略できます。存在していない場合は、このセクションの手順に従って、DigitalOcean 上に Kubernetes クラスタを作成します。初めて作成する場合は、前述したこちらの紹介リンクを利用してください。紹介リンクを利用しない場合は、最初からクラスタの料金が発生します。
このリンクから DigitalOcean 上にアカウントを作成すると、確認の電子メールが送信されます。電子メール内のリンクを使用して、電子メールアドレスを確認してください。アドレスを確認すると、DigitalOcean からクレジットカード情報の入力を求められます。入力しても問題はありません。使用量が 100 米ドル分を超えない限り、請求は発生しません。
有効なクレジットカード情報を入力した後、その次の画面では、プロジェクトを作成できます。こちらのリンクを利用して、特に必要のないこのステップを省略し、Kubernetes ダッシュボードに進んでもかまいません。
Kubernetes ダッシュボードで、「Create a Kubernetes cluster」ボタンを押します(必要に応じて、最初に「Enable Limited Access」をクリックしてください)。新しいページが表示され、フォームで以下の情報を入力できるようになります。
- 「Select a Kubernetes version」:この記事の手順は、
バージョンでテストされています。他のバージョンをテストしたい場合は、任意のバージョンを使用してかまいません。結果をぜひお知らせください。1.13.5-do.1
- 「Choose a datacenter region」:任意の地域を選択できます。
- 「Add node pool(s)」:ノードプールが 1 つだけであり、「
」オプションが選択されていて、少なくとも 3 つのノードがあることを確認してください。$10/Month per node
- 「Add Tags」:タグ付けに関しては、注意事項は特にありません。
- 「Choose a name」:クラスタには任意の名前を設定できます(たとえば、「kubernetes-tutorial」)。ただし、DigitalOcean で使用できる名前であることを確認してください(名前に空白文字が含まれていないなど)。
このフォームに情報を入力すると、「Create Cluster」ボタンをクリックできるようになります。クラスタの作成は数分(約 4 分)で完了します。一方、クラスタの構成ファイルはもうダウンロードできます。
このファイルには、クラスタの管理者としての作業に必要な資格情報が収められています。この情報はクラスタのダッシュボードに表示されます。「Create Cluster」ボタンをクリックすると、クラスタのダッシュボードにリダイレクトされます。ダッシュボードで画面の下端までスクロールすると、「Download Config File」ボタンがあります。このボタンをクリックして、構成ファイルをダウンロードします。
このファイルのダウンロードが完了したら、ターミナルを開いて、ホームディレクトリの
.kube
ディレクトリにファイルを移動します(必要に応じてディレクトリを作成します)。# make sure .kube exists mkdir ~/.kube # move the config file to it mv ~/Downloads/kubernetes-tutorial-kubeconfig.yaml ~/.kube
必要な場合、最後のコマンドの記述を調整して、ダウンロード済みファイルの適切なパスを指定してください。
Kubernetes の資格情報の格納場所は、
~/.kube
ディレクトリにすることをおすすめします。kubectl
のデフォルトでは、config
という名前のファイルがクラスタとの情報のやり取りに使用されます(.kube
ディレクトリにファイルがある場合)。別のファイルを使用するには、以下の 3 つの方法があります。- 1 番目の方法は、
コマンドでkubectl
フラグを使用して別のファイルを指定することですが、とても非能率的です。--kubeconfig
- 2 番目の方法は、
環境変数を定義することです。KUBECONFIG
を毎回入力する必要がなくなります。--kubeconfig
- 3 番目の方法は、コンテキストを同一の
ファイルにマージした後、コンテキストを切り替えることです。config
2 番目の方法(
KUBECONFIG
環境変数の設定)が最も簡単ですが、お好みに応じて、別のアプローチを任意に選択してかまいません。この環境を設定するには、以下のコマンドを実行します。export KUBECONFIG=~/.kube/kubernetes-tutorial-kubeconfig.yaml
注:ファイルパスは環境によって異なる場合があります。上のコマンドに適切なパスを指定したことを確認してください。
このコマンドでは、このターミナルのセッションに対してのみ、この環境が設定されます。新しいターミナルを開く場合は、このコマンドをもう一度実行する必要があります。
Kubernetes クラスタのノードを確認する方法
Kubernetes クラスタを準備し、
kubectl
で使用する資格情報を定義したので、クラスタとの情報のやり取りを開始できます。初めて導入する場合は、クラスタを構成するノードに問題がないことを以下のコマンドで確認できます。kubectl get nodes
このコマンドを実行すると、(クラスタの作成時に選択したノードの数に応じて)3 つ以上のノードが含まれたリストが出力されます。Kubernetes のノードとは仮想または物理のワーカーマシンで、アプリケーション(ユーザーアプリケーションまたは Kubernetes の運用に必要なアプリケーション)を実行するために Kubernetes が使用します。
クラスタに含まれているノードの数にかかわらず、上のコマンドで出力されるリストには、ノードの名前、ステータス(正常であれば「ready」)、役割、存続時間、バージョンが記述されています。この情報については、現時点で特に留意する必要はありません。Kubernetes クラスタのノードの詳細については、後ほど詳しく学んでいきます。
ノードのリストを参照して、どのノードのステータスも「ready」であれば、準備は完了です。
最初の Kubernetes アプリケーションをデプロイする方法
これまでのセットアップをすべて完了したら、最初の Kubernetes アプリケーションをデプロイしましょう。デプロイを進めていくとわかるとおり、難しくはないものの、数多くの手順が必要です。したがって、プロセスを迅速化するため、(Kubernetes 上で実行するには何らかの準備が必要な)手持ちのアプリケーションをデプロイしたり、デプロイ用にアプリケーションを新しく作成したりするのではなく、既存のサンプルアプリケーションをデプロイします。具体的には、ユーザー同士で意見を出し合えるアプリケーションをデプロイします。Twitter での人々のやり取りに似ていますが、認証が不要で、はるかにシンプルです。
Kubernetes デプロイメントを作成する方法
ターミナルに戻って最初の作業は、一連のYAML ファイルの保存先となるディレクトリを作成することです(このディレクトリには、
kubernetes-tutorial
など任意の名前を設定できます)。Kubernetes を利用する際、クラスタ内でオーケストレーションするリソースの記述には、多くの場合、この"マークアップ言語"を使用します。ディレクトリを作成した後、そのディレクトリに
deployment.yaml
という名前のファイルを作成し、以下のコードを記述します。apiVersion: apps/v1 kind: Deployment metadata: name: kubernetes-tutorial-deployment spec: replicas: 2 selector: matchLabels: app: kubernetes-tutorial-deployment template: metadata: labels: app: kubernetes-tutorial-deployment spec: containers: - name: kubernetes-tutorial-application image: auth0blog/kubernetes-tutorial ports: - containerPort: 3000
この構成ファイルは、特に理解しにくいものではありません。基本的には、このファイルは
kubernetes-tutorial-application
という名前のコンテナを作成するためのデプロイメントオブジェクト(kind: Deployment
)を定義するものです。このコンテナは、auth0blog/kubernetes-tutorial
というイメージを使用してサンプルアプリケーションを実行します。Kubernetes では、何を実行するかをクラスタに指示するには、レジストリにあるイメージを利用することが一般的です。デフォルトでは、Kubernetes は公開のDocker Hubレジストリにあるイメージを取得しようとします。イメージを非公開のままにしておきたい場合は、非公開レジストリを使用することもできます。
このファイルのその他のプロパティについては、現時点で特に留意する必要はありません。適宜、これから学んでいきます。ただし、最後の段落にある文で、2 つの新しい概念が登場していることに注目してください。
- デプロイメント:Kubernetes のデプロイメントとは、基本的に、目的となるシステムステートを記述したものです。デプロイメントを通じて、特定のアプリケーションのポッドをいくつ実行するかを Kubernetes クラスタに指示します。ここでは、ポッドが 2 つであることを指定しています(
)。replicas: 2
- コンテナ:コンテナは、実行中のアプリケーション、およびそのライブラリと依存関係を保持する最も低レベルのマイクロサービスです。コンテナは外部 IP アドレスを通じて世界に公開することが可能で、通常はポッドの構成要素です。
もう 1 つ学ぶべき重要な事項は、ポッドとは何かです。ポッドとは、公式ドキュメントで定義されているとおり、Kubernetes で作成し管理してデプロイできる最小のコンピューティングユニットです。さしあたり、関連性がきわめて強く個別にデプロイできないマイクロサービス(コンテナ)をグループにまとめたものと考えてください。今回の場合は、ポッドには単一のコンテナであるサンプルアプリケーションが保持されています。
注:昨今、ポッドとレプリケーションのオーケストレーションには、デプロイメントを使用する手法が好ましいとされています。ただし、最近まで Kubernetes エキスパートが一般に使用していたのは、レプリケーションコントローラとレプリケーションセットでした。このチュートリアルに沿って作業を進めていく上で、こうした他のオブジェクトについて学ぶことは必須ではありませんが、関心がある場合は、これらのオブジェクトの相違点をこちらのわかりやすい資料で確認できます。
次に、このデプロイメントを Kubernetes クラスタで実行するために、以下のコマンドを実行する必要があります。
# make sure you are inside the kubernetes-tutorial directory kubectl apply -f deployment.yaml
このコマンドを実行すると、クラスタは実行を開始し、目的のステートに到達しているかどうかを確認します。つまり、クラスタは両方のポッド(
replicas: 2
)をクラスタのノード上で実行しようとします。その後、「サンプルアプリケーションをクラスタにデプロイしたから、これでアプリケーションをブラウザから使えるようになる」とお考えかもしれません。ですが、そこまでシンプルではありません。ポッドが、絶えず生成されては消える信頼できない処理ユニットであることが問題です。したがって、その一過性の性質上、ポッド自体に外部からアクセスすることはできません。
前掲のコマンドでは、クラスタに対して、同じアプリケーションの実行インスタンス(ポッド)が 2 つであることを通知しました。クラスタ内でこれらのポッドはそれぞれ別の IP アドレスを持ち、いずれか一方が動作を停止した場合は、その原因にかかわらず、Kubernetes はさらに別の IP アドレスを持つポッドを新しく起動します。したがって、こうした IP アドレスを手動で追跡することは困難です。この問題を解決するには、Kubernetes のサービスを使用します。
注:もう 1 つ、Kubernetes でデプロイメント用に新しいポッドが起動される可能性がある状況は、(たとえば、ユーザーの増加に対応できるように)クラスタにアプリケーションのスケーリングを要求した場合です。
サービスについて学ぶ前に、ポッドが実際に稼働していることを以下のコマンドで確認しましょう。
kubectl get pods
このコマンドを実行すると、Kubernetes クラスタ内の使用可能なポッドのリストが出力されます。そのリストを参照すると、2 つのポッド(2 つの行)があり、それぞれのポッドにコンテナが 1 つ含まれていることがわかります(「READY」列の「
1/1
」)。また、ポッドのステータス、再起動回数(問題がなければ「0」)、存続時間も確認できます。サービスとイングレスを使用してデプロイメントを公開する
ポッド、デプロイメント、コンテナについて学んだ今、新しいデプロイメントを利用してみたくなったのではないでしょうか。利用するには、デプロイメントを外部に公開するためのイングレスルールを作成する必要があります。Kubernetes のイングレスとは、「通常は HTTP を通じて、クラスタ内のサービスに対する外部からのアクセスを管理するオブジェクト」です。イングレスを利用すると、クラスタ内部からの負荷分散、TLS 終端処理、名前ベースの仮想ホスティングをサポートできます。
Kubernetes クラスタにイングレスルールを構成するには、まず、イングレスコントローラが必要です。こちらでわかるとおり、多種多様なイングレスコントローラが利用できます。このチュートリアルでは、多くの人が利用している高性能で使いやすいNGINX イングレスコントローラを利用します。
このコントローラをクラスタにインストールする手順は、きわめてシンプルです。最初に必要な作業は、以下のコマンドを実行して、いくつかの必須リソースをインストールすることです。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
次に、このコマンドを実行して、コントローラに必要な別の一連のリソースをインストールします。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml
注:DigitalOcean 以外のサービス上で Kubernetes クラスタを実行している場合は、必要に応じて、これらと異なる一連のコマンドを実行します。相違点の詳細については、こちらの資料を確認してください。
上のコマンドが正常に機能したことを確認するには、以下のコマンドを実行します。
kubectl get pods -n ingress-nginx
このコマンドを実行すると、
nginx-ingress-controller-...
という名前のポッドが表示され、ステータスが「running」となっているはずです。このコマンドに渡す-n ingress-nginx
フラグは、ingress-nginx
名前空間にあるポッドのリストを出力することを指定しています。名前空間は、Kubernetes クラスタ内のリソースを整理するための優れた手段です。Kubernetes のこの機能については、別の機会に詳しく取り上げる予定です。クラスタ内にイングレスコントローラを構成した後、次の作業はサービスを作成することです。ここで、なぜサービスなのでしょうか。イングレスでないのは、なぜでしょうか。
その理由は、ポッドが一過性のものであることから(何らかの理由で削除されたり、レプリケーションルールに基づいて新しいものが作成される可能性があります)、すべての関連ポッドを単一の要素として表現する(つまり、ここでは、それらのポッドに関係しているデプロイメントを表現する)静的なリソースが必要であることです。ポッドに対してサービスを定義すると、当該のサービスをポイントするイングレスルールを作成できるようになります。
ここで必要になるのが、デプロイメント用のポートを開く ClusterIP サービスです。作成するには、
service.yaml
という名前のファイルを作成して、以下のコードを追加します。apiVersion: v1 kind: Service metadata: name: kubernetes-tutorial-cluster-ip spec: ports: - port: 80 protocol: TCP targetPort: 3000 selector: app: kubernetes-tutorial-deployment type: ClusterIP
注:Kubernetes では、多種多様なサービスを利用できます。ここで利用する ClusterIP は、デプロイメントをクラスタ内部でのみ公開する場合に役立ちます。つまり、この種のサービスは、デプロイメントを外部に公開するものではありません。外部への公開用に他のタイプのサービスも存在していますが(詳細はこちらの資料で確認できます)、今回のシリーズでは使用しません。
次に、以下のコマンドを実行して、このサービスをクラスタ内に作成します。
kubectl apply -f service.yaml
このコマンドを実行すると、クラスタ内でのデプロイメントを表現するサービスが作成されます。このサービスが当該のデプロイメントの(つまり、実際にはポッドの)ブローカとして機能しているかどうかを把握するため、
kubernetes-tutorial-deployment
をポイントするselector.app
プロパティをサービスの記述(service.yaml
)に追加しました。deployment.yaml
ファイルをもう一度参照すると、同じ値(kubernetes-tutorial-deployment
)を持つlabels.app
というプロパティがあることがわかります。Kubernetes は、これらのプロパティを使用して、このサービスをデプロイメントのポッドと紐付けます。作成しているサービスに関して、もう 1 つ注目すべき重要事項があります。定義しようとしているのは、このサービスが
port: 80
をリッスンすること、ポッド上ではtargetPort: 3000
をリッスンすることです。デプロイメントのファイルを確認すると、コンテナでこのポート(containerPort: 3000
)が使用されるように定義したことがわかります。したがって、リクエストがポッドへとリダイレクトされるとき、サービスで適切なポートが宛先となっていることを確認する必要があります。注:ここで
を実行した場合、2 つのサービスが表示されます。最初のサービスkubectl get svc
は、Kubernetes 自体で使用されるメインのサービスです。もう一方は、作成したサービスkubernetes
です。出力からわかるとおり、どちらも内部 IP アドレス(kubernetes-tutorial-cluster-ip
)を持っています。ただし、これらのアドレスを把握する必要はありません。今後わかりますが、イングレスではサービスをもっと効率的な方法で参照できます。CLUSTER-IP
サービスを作成した後は、いよいよイングレス(およびいくつかのルール)を定義して、このサービス(およびサービスが表現しているデプロイメント)を外部に公開できます。公開するには、
ingress.yaml
という名前のファイルを作成し、以下のコードを記述します。apiVersion: extensions/v1beta1 kind: Ingress metadata: name: kubernetes-tutorial-ingress spec: rules: - http: paths: - path: / backend: serviceName: kubernetes-tutorial-cluster-ip servicePort: 80
このファイルでは、イングレスのリソースを単一のルール(
spec.rules
)で定義します。このルールは、Kubernetes に対して、ルートパス(path: /
)をポイントしているリクエストをポート80
(servicePort: 80
)上のkubernetes-tutorial-cluster-ip
サービス(以前に作成したサービスの名前)へとリダイレクトするよう指示するものです。新しいイングレスをクラスタにデプロイするには、以下のコマンドを実行します。
kubectl apply -f ingress.yaml
次に、全体が適切に機能していることを確認するため、Kubernetes クラスタのパブリック IP アドレスを把握する必要があります。このためには、以下のコマンドを実行します。
kubectl get svc \ -n ingress-nginx ingress-nginx \ -o=jsonpath='{.status.loadBalancer.ingress[0].ip}'
注:上のコマンドでは、Kubernetes のJSONPathと呼ばれる機能を利用して、必要なプロパティそのもの(この場合はパブリック IP アドレス)を
サービスから抽出しています。JSONPath 機能の詳細については、こちらを参照してください。ingress-nginx
このコマンドでは、ブラウザでアプリケーションの参照に使用できる IP アドレス(たとえば、
104.248.109.181
)が出力されます。したがって、ブラウザを開いて当該の IP アドレスにアクセスすると、デプロイしたアプリケーションが表示されます。注:このアプリケーションは、ユーザー同士が意見を出し合えるきわめて単純な Twitter アプリケーションをエミュレートしているに過ぎず、有用性はさほど高くなく、アイデンティティ管理(ユーザー認証)の仕組みすら備えていません。
作業はこれで終了です。ローカルマシンの構成を完了して Kubernetes の運用を開始し、最初のアプリケーションを Kubernetes にデプロイしました。魅力の一端を感じられたのではないでしょうか。
注:DigitalOcean から提供されるクレジットを使い切ることがないよう、今回のクラスタはすぐに削除するとよいでしょう。削除するには、DigitalOcean ダッシュボードの Kubernetes のセクションにアクセスして、画面右側の「More」ボタンをクリックし、「Destroy」をクリックします。プロセスを実行するかどうかの確認画面が表示されます。
“Kubernetesアプリケーションを初めてデプロイしてみましたがとても簡単でした。”
これをツイートする
終わりに
この記事では、DigitalOcean 上に Kubernetes クラスタを作成した後、そのクラスタを利用してサンプルアプリケーションを起動しました。このアプリケーションのデプロイで、デプロイメント、ポッド、コンテナ、サービス、イングレスといった Kubernetes の基本的な概念を学びました。この知識を活かして、Kubernetes でマイクロサービスアプリケーションをオーケストレーションできるよう、より高度な概念の学習へと踏み出す準備が整いました。この記事がお役に立った場合、また、このトピックについてコンテンツの拡充をご希望の場合は、下にあるディスカッションのセクションでぜひお知らせください。
Auth0 について
Auth0 は、アプリケーションビルダーのためにつくられた最初のアイデンティティ管理プラットフォームであり、カスタムビルドアプリケーションに必要とされる唯一のアイデンティティソリューションです。世界中のアイデンティティを守り、イノベーターがイノベーションを起こせるようにするというミッションのもと、Auth0 はシンプルで、拡張性のある、スケーラブルなプラットフォームを提供し、あらゆるオーディエンスのために、あらゆるアプリケーションのアイデンティティを守ります。Auth0 は毎日 1 億回以上のログインを保護し、法人企業が信頼されるエレガントなデジタルエクスペリエンスを世界中の顧客に提供できるようにします。
より詳しい情報に関して、https://auth0.com/jp/もしくは@auth0_jp on Twitterをご覧ください。
About the author
Bruno Krebs
R&D Content Architect