この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
「ま、丸見えやないか!!」
以前から興味があったAWS X-Ray。ごっつ便利そうながら、導入の敷居が高そうで触るのを躊躇してました。
そんな悶々とした日々を送っていた矢先、いつもお世話になっているEKS Workshopにおいて、X-Rayをサンプルアプリケーションと共に簡単に試すことができるチュートリアルがあったので、渡りに船とばかり触ってみました。
インフラ側を設定しサンプルアプリケーションを展開することで、各マイクロサービス間のリクエスト内容とリクエストタイム、その分布が丸裸になるという、なんとも興奮する結果が得られました。
実際のアプリケーションに導入するにはひと手間かかりますが、まずはEKSにおいてAWS X-Rayがどのような役割をはたすのかその感触を掴むには最適なので、マイクロサービスな分散トレーシングに興味がある方は、一度触ってみることをオススメいたします。
(祭) ∧ ∧ Y ( ゚Д゚) Φ[_ソ__y_l〉 X-Rayマツリダワッショイ |_|_| し'´J
AWS X-Rayによる分散トレーシングとは
いわゆるAPM(Application Performance Management)に属するサービスです。
近年の分散システムの進化により、そのシステムの監視やデバッグは困難となっています。Kubernetesのようなコンテナオーケストレーションプラットフォームはそれらの多くの問題を解決しますが、サービス間の相互作用やそれぞれの待機時間を把握するのは依然として難しい問題です。
AWS X-Rayは、X-RayエージェントをDaemonSetとして各Workerノードに展開し、アプリケーション内にX-Ray SDKを導入することで、分散トレーシングを可能とします。
今回は、Amazon EKS Workshop内のTracing with X-Rayを利用して、サンプリアプリケーションを利用しながら、AWS X-Rayの挙動を確認してみます。
ほな、いってみよ。
EKS環境の確認
既にEKSのクラスターが用意されている前提で進めていきます。この記事では、EKSクラスターのバージョンは1.12.6です。
$ kubectl version --short
Client Version: v1.10.3
Server Version: v1.12.6-eks-d69f1b
AWS X-Rayのセットアップ
アプリケーションへのAWS X-Ray SDKの組み込み
今回はサンプルアプリケーションを利用するのでこの手順は不要です。
自分のアプリケーション内にX-Ray SDKを組み込む場合は、下記公式ドキュメントを参考に、各言語で必要なSDKの組み込みを実施しておきます。
What Is AWS X-Ray? - AWS X-Ray
WorkerノードへのIAMポリシー付与
最初にWorkerノードがX-Rayに対してトレーシング結果を送信できるように、WorkerノードのIAMロールにarn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess
ポリシーが必要です。
WorkerノードのEC2インスタンスに付与されているIAMロール名を確認し、以下のコマンドでポリシーを付与します。
$ aws iam attach-role-policy --role-name $ROLE_NAME \
--policy-arn arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess
X-RayエージェントをDaemonSetとして展開
各WorkerノードにX-Rayエージェントを展開するため、エージェントをDaemonSetとして展開します。
eksworkshopで用意されている、マニフェストファイルをダウンロードします。
$ curl -O https://eksworkshop.com/x-ray/daemonset.files/xray-k8s-daemonset.yaml
マニフェストファイルの内容です。ここでは、DeamonSetのポートに2000を利用しています。
xray-k8s-daemonset.yaml
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# A copy of the License is located at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: xray-daemon
name: xray-daemon
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: xray-daemon
labels:
app: xray-daemon
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: xray-daemon
namespace: default
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: xray-daemon
spec:
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: xray-daemon
spec:
volumes:
- name: config-volume
configMap:
name: xray-config
hostNetwork: true
containers:
- name: xray-daemon
image: rnzdocker1/eks-workshop-x-ray-daemon:dbada4c77e6ae10ecf5a7b1c5864aa6522d9fb02
imagePullPolicy: Always
command: [ "/usr/bin/xray", "-c", "/aws/xray/config.yaml" ]
resources:
limits:
memory: 24Mi
ports:
- name: xray-ingest
containerPort: 2000
hostPort: 2000
protocol: UDP
volumeMounts:
- name: config-volume
mountPath: /aws/xray
readOnly: true
---
# Configuration for AWS X-Ray daemon
apiVersion: v1
kind: ConfigMap
metadata:
name: xray-config
data:
config.yaml: |-
# Maximum buffer size in MB (minimum 3). Choose 0 to use 1% of host memory.
TotalBufferSizeMB: 0
# Maximum number of concurrent calls to AWS X-Ray to upload segment documents.
Concurrency: 8
# Send segments to AWS X-Ray service in a specific region
Region: ""
# Change the X-Ray service endpoint to which the daemon sends segment documents.
Endpoint: ""
Socket:
# Change the address and port on which the daemon listens for UDP packets containing segment documents.
# Make sure we listen on all IP's by default for the k8s setup
UDPAddress: 0.0.0.0:2000
Logging:
LogRotation: true
# Change the log level, from most verbose to least: dev, debug, info, warn, error, prod (default).
LogLevel: prod
# Output logs to the specified file path.
LogPath: ""
# Turn on local mode to skip EC2 instance metadata check.
LocalMode: false
# Amazon Resource Name (ARN) of the AWS resource running the daemon.
ResourceARN: ""
# Assume an IAM role to upload segments to a different account.
RoleARN: ""
# Disable TLS certificate verification.
NoVerifySSL: false
# Upload segments to AWS X-Ray through a proxy.
ProxyAddress: ""
# Daemon configuration file format version.
Version: 1
---
# k8s service definition for AWS X-Ray daemon headless service
apiVersion: v1
kind: Service
metadata:
name: xray-service
spec:
selector:
app: xray-daemon
clusterIP: None
ports:
- name: incoming
port: 2000
protocol: UDP
このマニフェストファイルをクラスタに適用します。
$ kubectl create -f xray-k8s-daemonset.yaml
serviceaccount "xray-daemon" created
clusterrolebinding.rbac.authorization.k8s.io "xray-daemon" created
daemonset.extensions "xray-daemon" created
configmap "xray-config" created
service "xray-service" created
デーモンセットとして正常に展開されているか確認します。Pods Status
が3 Running
になっていれば、きちんとPodとして展開されています。
$ kubectl describe daemonset xray-daemon
Name: xray-daemon
Selector: app=xray-daemon
Node-Selector: <none>
Labels: app=xray-daemon
Annotations: <none>
Desired Number of Nodes Scheduled: 3
Current Number of Nodes Scheduled: 3
Number of Nodes Scheduled with Up-to-date Pods: 3
Number of Nodes Scheduled with Available Pods: 3
Number of Nodes Misscheduled: 0
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=xray-daemon
Containers:
xray-daemon:
Image: rnzdocker1/eks-workshop-x-ray-daemon:dbada4c77e6ae10ecf5a7b1c5864aa6522d9fb02
Port: 2000/UDP
Host Port: 2000/UDP
Command:
/usr/bin/xray
-c
/aws/xray/config.yaml
Limits:
memory: 24Mi
Environment: <none>
Mounts:
/aws/xray from config-volume (ro)
Volumes:
config-volume:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: xray-config
Optional: false
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 1m daemonset-controller Created pod: xray-daemon-kzzzr
Normal SuccessfulCreate 1m daemonset-controller Created pod: xray-daemon-bgmzs
Normal SuccessfulCreate 1m daemonset-controller Created pod: xray-daemon-lvlxd
Podの展開も確認。
$ kubectl get pod --selector app=xray-daemon
NAME READY STATUS RESTARTS AGE
xray-daemon-bgmzs 1/1 Running 0 2m
xray-daemon-kzzzr 1/1 Running 0 2m
xray-daemon-lvlxd 1/1 Running 0 2m
こんな感じでログが出力されていればOKです。
$ kubectl logs -l app=xray-daemon
2019-06-01T06:24:37Z [Info] Initializing AWS X-Ray daemon 3.0.0
2019-06-01T06:24:37Z [Info] Using buffer memory limit of 38 MB
2019-06-01T06:24:37Z [Info] 608 segment buffers allocated
2019-06-01T06:24:37Z [Info] Using region: ap-northeast-1
2019-06-01T06:24:37Z [Info] Starting proxy http server on 127.0.0.1:2000
2019-06-01T06:24:34Z [Info] Initializing AWS X-Ray daemon 3.0.0
2019-06-01T06:24:34Z [Info] Using buffer memory limit of 38 MB
2019-06-01T06:24:34Z [Info] 608 segment buffers allocated
2019-06-01T06:24:34Z [Info] Using region: ap-northeast-1
2019-06-01T06:24:34Z [Info] Starting proxy http server on 127.0.0.1:2000
2019-06-01T06:24:34Z [Info] Initializing AWS X-Ray daemon 3.0.0
2019-06-01T06:24:34Z [Info] Using buffer memory limit of 38 MB
2019-06-01T06:24:34Z [Info] 608 segment buffers allocated
2019-06-01T06:24:34Z [Info] Using region: ap-northeast-1
2019-06-01T06:24:34Z [Info] Starting proxy http server on 127.0.0.1:2000
サンプルアプリケーションのデプロイ
eksworkshopには、AWS X-RayのSDKを事前に組み込んだサンプルアプリケーションが用意されているので、それらをデプロイします。
$ kubectl apply -f https://eksworkshop.com/x-ray/sample-front.files/x-ray-sample-front-k8s.yml
$ kubectl apply -f https://eksworkshop.com/x-ray/sample-back.files/x-ray-sample-back-k8s.yml
しばらくまったら、デプロイメントを確認し、正常に展開されているか確認します。
$ kubectl describe deployments x-ray-sample-front-k8s x-ray-sample-back-k8s
サービスステータスを確認します。
$ kubectl describe services x-ray-sample-front-k8s x-ray-sample-back-k8s
フロントエンドサービスが正常にデプロイされていることを確認したら、CLBでフロントエンドサービスを公開します。
$ kubectl get service x-ray-sample-front-k8s -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
x-ray-sample-front-k8s LoadBalancer 10.100.X.YYY abcdefg0123456789.ap-northeast-1.elb.amazonaws.com 80:31229/TCP 4m app=x-ray-sample-front-k8s,tier=frontend
ロードバランサーがデプロイされた後、実行結果に表示されているEXTERNAL-IPにブラウザでアクセスし、サンプルアプリケーションのフロント画面が表示されたOKです。
むっちゃ怪しい感じスネ… 分散トレーシングのサンプルとするため、フロントから1秒ごとに自動的にサーバーにリクエストが飛んでいます。
AWS X-Rayコンソールを確認する
ここまでで事前準備はOK。いよいよAWS X-Rayコンソールで、分散トレーシングの内容を確認していきます。
Service Map
無事、X-Rayにデータが転送されていれば、こんな感じでService Mapが表示されています。ここでは、各Pod間のリクエストの依存関係とPod名を確認できます。
各リソースは、同じコンテキスト空間でX-Rayにデータ転送され、グラフとして表示されます。このサンプルサプリケーションでは、x-ray-sample-fornt-k8s
サービスが、1分間あたり43回のりクエストをなげていて、平均レイテンシーが0.6msとなります。x-ray-sample-back-k8s
は、平均トランザクションが0.08msになっていることがわかります。
各サービスをクリックすると、計測範囲時間におけるレスポンスの分布を確認できます。
Traces
左側メニューのTraces
をクリックすると、各リクエストにおけるセグメント単位のリクエストの実行結果をトレースできます。初期表示では、URLをELBのエンドポイントでグループ化したトレース結果が表示されています。
リストのトレースリストをクリックすると、各リクエスト内全ての実行時間を確認できます。
Rawデータも確認ができます。
このGolangのサンプルでは、the main segmentにおいて、xray.Handler helper
を初期化しており、全てのhttpリクエスト内の全ての必要な情報を構造化して送信しています。
アナリティクス
左側メニューのアナリティクスをクリックすると、トレースデータの理解に役立つ、サービス性能の全体的な分析結果を確認できます。最近でた機能らしいですが、なんかすげぇな…
応答時間の分布状況を確認できたり
応答時間でフィルタしたなかでの、HTTPステータスコードの分布、リクエストURI、ユーザーエージェント、HTTPメソッドの分布、レスポンスタイム、そして、そこに含まれる詳細トレースを確認することができます。
サンプルアプリケーションなので、全レスポンスが200だったりあまり意味のあるグラフには見えないのですが、実アプリケーションであれば、応答時間が非常にかかっている部分のリクエストに絞って、そのエラー率や実際のトレース内容を把握するのに威力を発揮しそうです。
AWS X-Rayの料金
無料利用枠が用意されています。とりあえず試してみるにはありがたい。
- 期限なしの無料利用枠
- 毎月、トレースの記録は 10 万回まで無料です。
- 毎月、トレースの取得とスキャンは合わせて 100 万回まで無料です。
- 追加料金
- トレースの記録の無料利用枠を超えた分の料金は、トレースの記録 100 万件あたり 5 USD (トレース 1 件あたり 0.000005 USD) です。
- トレースの取得とスキャンの無料利用枠を超えた分の料金は、トレースの取得とスキャンを合わせて 100 万件あたり 0.50 USD (トレース 1 件あたり 0.0000005 USD) です。
サンプルアプリケーションの後片付け
サンプルアプリケーションは、このままだと延々ログを吐き出してしまうので、検証が終わったらさくっと片付けてしまいましょう。
サンプルアプリケーションの削除はこちら。
$ kubectl delete deployments x-ray-sample-front-k8s x-ray-sample-back-k8s
$ kubectl delete services x-ray-sample-front-k8s x-ray-sample-back-k8s
X-Rayデーモンセットの削除はこちら。
$ kubectl delete -f https://eksworkshop.com/x-ray/daemonset.files/xray-k8s-daemonset.yaml
アプリケーションへのSDK組み込みは必須だが、分散トレーシングとして非常にパワフル
サンプルアプリケーションがあるおかげで、Pod間のリクエストのビジュアライズから、各リクエストのトレースと分析結果を垣間見ることができました。むっちゃ面白かったです。
アプリケーションへのX-Ray SDKの組み込みと設定が必須になっている部分は最初の導入で敷居が高いですが、マイクロサービスにおける各サービス間のトレーシングや分析には非常に役立つ機能かと思います。
実際に活きたアプリケーションに導入しないとその威力がわかりにくいと思いますが、サンプルアプリケーションの導入と展開自体はこの記事で書いたように非常に簡単なので、まずはどのようなデータがでるか感触を掴んでいただき、「これ、ごっつええやん(^q^)」と興奮した人であれば、皆さんの運用アプリケーションに組み込んでみてはいかがでしょうか。
それでは、今日はこのへんで。濱田(@hamako9999)でした。