はじめに #
kubernetesに展開しているAPPのlog収集をElasticSearchのkubernetes Integrationを使って実施します。
今回は以下の様なAPIサーバー一式を用意して、これらのlog収集を実施します。
$ kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
api-75969fcbb4-9nzm2 1/1 Running 0 23d
mysql-cluster-0 2/2 Running 0 24d
mysql-cluster-1 2/2 Running 0 24d
mysql-cluster-2 2/2 Running 0 24d
mysql-cluster-router-57c657f6cf-np6jw 1/1 Running 0 24d
redis-master-0 1/1 Running 0 24d
redis-replicas-0 1/1 Running 0 24d
worker-6cfbd5dcd5-5ws4k 1/1 Running 0 23d
$ kubectl logs api-75969fcbb4-9nzm2 -n dev | jq
{
"level": "info",
"timestamp": "2024-07-22 23:11:59",
"caller": "logging/access_logger.go:82",
"msg": "handled request",
"requestId": "01J3DCHV6FPB1QPJERFZVAFSP9",
"remote": "192.168.1.215",
"host": "192.168.1.215:30000",
"uri": "/oauth2/token",
"method": "POST",
"status": 200,
"userAgent": "Go-http-client/1.1",
"responseTimeMs": 213
}
1. kubernetes integrationの追加 #
1. 検証環境の用意
vSphere Integrationを使うには事前にfleet-serverを構築している必要があります。構築方法は第1回を参照ください。
2. kubernetes integrationの追加
Kibanaでkuberenetesと検索すると出てくるので追加します。
3. 収集するlog,metricsを選ぶ
かなり多くの項目があるのですが、今回はCollect Kubernetes container logs
だけ収集することにします。
これで全てのpodのlogが収集できます。もちろん特定namespace、podだけに絞り込むことができますが後に解説します。
4. 新規Agentのdeploy用manifestの用意
Elastic Agent自体をkuberetesにpodとしてdeployしたいので、New hostsを選びSave and continue
で保存します。
するとdeploy用のmanifestが生成されるので、これを使ってdeployします。
4-1. deploy前準備1 -elasticsearchとfleetの名前解決-
manifestには以下の様に、docker-nw内部でのみ名前解決ができるhostnameが割り当てられています。このままではk8sからhttp://fleet-server:8220
には名前解決できません。
- name: FLEET_URL
value: "http://fleet-server:8220"
- name: KIBANA_HOST
value: "http://kibana:5601"
従ってnameserverや、k8sのnodeの/etc/hosts
を変更する等でfleet-server
とkibana
が名前解決ができるようします。
私は検証環境である + dnsmasqで独自のDNS-serverを構築しているので、以下の様に無理やり名前解決ができる様にしています。。。
# cat /etc/hosts
192.168.1.203 fleet-server elasticsearch
4-2 deploy前準備2 -HTTPSでFleetと接続するか-
Elastic AgentとFleetの接続がHTTPSでできない場合は、manifest内部のFLEET_INSECURE
をtrueにしておきましょう。
# Set to true to communicate with Fleet with either insecure HTTP or unverified HTTPS
- name: FLEET_INSECURE
value: "false" # ここをtrueにする
5. k8sにAgentをdeploy
前準備が終わったらmanifestを使ってagentをdeployします。defaultだとnamespace: kube-system
にdeployされます。
$ kubectl apply -f elastic-agent-managed-kubernetes.yml
$ kubectl get pods -n kube-system | grep elastic
elastic-agent-b4nhz 1/1 Running
elastic-agent-bjv6k 1/1 Running
elastic-agent-m6vkk 1/1 Running
deployが成功すると、fleet画面にagentが表示されます。
6. logの確認
fleetからData streams名を確認します。今回はlogs-kubernetes.container_logs-default
でした。
これでDiscoverからcheckすると、kube-system
を含めた全てのpodのログが取得できていることがわかります。
2. log取得の調整 #
logの取得はこれでできましたが、不要な情報もあったりとカスタマイズしたい点がいくつかあると思います。このカスタマイズはkubernetes integrationの画面から実施できます。
取得するlogの絞り込み #
Condition
セクションでは、収集するlogの絞り込みができます。
defaultだと全てのpodsのlogを取得し数が膨大になるので、必要に応じて任意のpod,namespaceだけなど絞り込みをしましょう。
# 特定podのみ
${kubernetes.container.name} == "api"
# 特定namespaceのみ
${kubernetes.namespace} == "dev"
基本的にkubernetes integrationで取得できるfield名でgrepをかけることができます。ドキュメントとして確認したい場合は以下です。
jsonをparseする #
Additional parsers configuration
セクションでは、logのparse処理ができます。
例えばコメントアウトされているndjson
を使うと、jsonのmessageをparseすることができます。
# - ndjson:
# target: json
# ignore_decoding_error: true
これによってjsonの文字列が丸ごと入ってしまっている状態から、
ndjson
を有効にすることで、jsonがparseされてfield毎に保存されます。
ndjson
には他にもoptionがあるので、ドキュメントを確認しておきましょう
不要なfieldを削除する #
Processor
セクションを使うと、logに様々な処理を追加でかけることができます。
例えばdrop_fields
を使うことで、任意のfieldを削除しlogの容量を削減することができます。
- drop_fields:
fields: [
"/kubernetes.labels*/"
]
ignore_missing: true
3. トラブルシューティング #
名前解決ができない #
fleet-serverとAgentが疎通できないと、ステータスがhealth
にならないので注意しましょう。
elasticsearchへAgentが接続できない #
まずはElastic Agentのlogを見て状態をcheckしましょう。
kubectl -n kube-system logs <pod名> | jq -r -R 'fromjson?'
その上で401 Unauthorized
が出ている場合は、tokenがreset等で変わったのにAgentには反映されないAgentのbugの可能性があります。
"log.level": "error",
"@timestamp": "2024-08-15T10:07:30.230Z",
"message": "Failed to connect to backoff(elasticsearch(http://elasticsearch:9200)): 401 Unauthorized: {\"error\":{\"root_cause\":[{\"type\":\"security_exception\",\"reason\":\"unable to authenticate with provided credentials and anonymous access is not allowed for this request\",\"additional_unsuccessful_credentials\":\"API key: unable to find apikey with id FYsk05ABBKobXbf_vkfx\",\"header\":{\"WWW-Authenticate\":[\"Basic realm=\\\"security\\\" charset=\\\"UTF-8\\\"\",\"ApiKey\"]}}],\"type\":\"security_exception\",\"reason\":\"unable to authenticate with provided credentials and anonymous access is not allowed for this request\",\"additional_unsuccessful_credentials\":\"API key: unable to find apikey with id FYsk05ABBKobXbf_vkfx\",\"header\":{\"WWW-Authenticate\":[\"Basic realm=\\\"security\\\" charset=\\\"UTF-8\\\"\",\"ApiKey\"]}},\"status\":401}",
Agentのtoken等の状態がhostpath
でnodeに保存されて使いまわされることが原因なので、rm -r /var/lib/elastic-agent-managed/kube-system/state
等で削除すると新しいtokenが反映されます。
# Mount /var/lib/elastic-agent-managed/kube-system/state to store elastic-agent state
# Update 'kube-system' with the namespace of your agent installation
- name: elastic-agent-state
hostPath:
path: /var/lib/elastic-agent-managed/kube-system/state
type: DirectoryOrCreate
おわりに #
kubernetes intgrationを使うことで、k8s上のAPPのログ収集をかなり簡単に実施することができました。Elastic Agentもk8s上にdeployされたので冗長化ができ運用も楽そうです。
次回はElasticSearch自体をk8sで稼働させる、Elastic Cloud on Kubernetes (ECK)を紹介したいと思います。