285

Running kubectl logs shows me the stderr/stdout of one Kubernetes container.

How can I get the aggregated stderr/stdout of a set of pods, preferably those created by a certain replication controller?

Rob Kielty
  • 7,958
  • 8
  • 39
  • 51
Torsten Bronger
  • 9,899
  • 7
  • 34
  • 41
  • have in mind that not setting the tail argument when using a selector will default every pod log to 10 lines length – chachan Jan 29 '20 at 16:26

20 Answers20

406

You can use labels

kubectl logs -l app=elasticsearch

And you'd probably want to specify --all-containers --ignore-errors in order to:

  • Include logs from pods with multiple containers
  • Continue to next pod on fatal error (e.g. logs could not be retrieved)
Noam Manos
  • 15,216
  • 3
  • 86
  • 85
Adrian Ng
  • 4,204
  • 1
  • 11
  • 3
  • 26
    Good solution and most likely enough to answer the original question but it won't tail: "error: only one of follow (-f) or selector (-l) is allowed". – Nestor Urquiza Oct 16 '17 at 05:27
  • 4
    Also, no `--all-namespaces`. – Eric Walker Dec 27 '17 at 18:23
  • What will be the order of those logs? I mean if there are multiple pods and each pod will have their own logs. So if logs from all are displayed, then in what order will they be displayed and how do I identify a source pod of a particular log line? – Shubham May 20 '19 at 11:59
  • 21
    It seems like this works with `-f` now (as of Kubernetes 1.12+ / `kubectl` 1.12+). Also @Shubham - it displays the messages in the order received, there are no tags or anything on the log lines. This is just for quick debugging. If you need more log detail, you'll need to ship your logs to a central logging system like EFK, SumoLogic, Datadog, etc. – geerlingguy Jun 18 '19 at 22:10
  • 1
    Is there anyway to do the same using kubernetes dashboard. – mchawre Jul 29 '19 at 11:03
  • 1
    You may also need `--all-containers` if there are multi-container pods. And `--max-log-requests=42` if there are many pods. – prokher Oct 11 '19 at 11:27
  • is there any way to do the same using the k8s client? – Jibin Mathews Nov 13 '19 at 04:53
  • 4
    might want to use `-n --tail=` – evgnomon Apr 11 '20 at 14:20
  • How do I get the label from `kubectl`? – Jeff Tian Dec 17 '20 at 09:12
  • Probably also want to pass `--prefix` to differentiate where the lines are from. – Andrew Marshall Jun 18 '21 at 16:34
  • sometimes the number of containers under a pod can exceed maximum concurrent streams number. can further append `--max-log-requests {number of stream}` to combine all containers' logs in one stream – Yu Tian Toby Jun 21 '22 at 02:17
  • issue: stacktrace from multiple pods mixed together. how to fix this? thanks – eastwater Jun 06 '23 at 22:05
98

I've created a small bash script called kubetail that makes this possible. For example to tail all logs for pods named "app1" you can do:

kubetail app1

You can find the script here.

Johan
  • 37,479
  • 32
  • 149
  • 237
  • Installed it with: `brew tap johanhaleby/kubetail && brew install kubetail --with-short-names` detailed documentation: `kt -h` Awesome! – Khalil Gharbaoui Apr 08 '19 at 13:00
  • Awesome. I have a couple of questions. ``` 1. Can we tail logs of multiple pods belonging to different deployments? Something like "kt -l app=service1,app=service2" 2. How do I write em all to a file? Doing this "kt -l app=service1` >> filename.log" writes only pod names to it. 3. Does it also tail in case of autoscaling deployments? ``` – Vasudev Jun 03 '19 at 11:00
51

You can get the logs from multiple containers using labels as Adrian Ng suggested:

kubectl logs --selector app=yourappname

BUT in case you have a pod with multiple containers, the above command is going to fail and you'll need to specify the container name:

kubectl logs --selector app=yourappname --container yourcontainername

Note: If you want to see which labels are available to you, the following command will list them all:

kubectl get pod <one of your pods> -o template --template='{{.metadata.labels}}'

...where the output will look something like

map[app:yourappname controller-revision-hash:598302898 pod-template-generation:1]

Note that some of the labels may not be shared by other pods - picking "app" seems like the easiest one

Jean Spector
  • 916
  • 9
  • 9
37

To build on the previous answer if you add -f you can tail the logs.

kubectl logs -f deployment/app
Ruben
  • 503
  • 4
  • 4
  • 26
    Be careful! This command chooses only one pod to stream the logs. It doesn't stream the logs from all pods in the replica set/deployment. – Teodoro Dec 27 '21 at 01:14
  • 2
    best answer: kubectl logs -f --all-containers deployment/app – johntellsall Feb 13 '22 at 19:58
  • 4
    But it will still not log from all *pods* that run this deployment, only all *containers* within these pods (and usually you only have one container per pod, but multiple pods per deployment) – Daniel Albuschat Feb 18 '22 at 07:38
30

Previously provided solutions are not that optimal. The kubernetes team itself has provided a solution a while ago, called stern.

stern app1

It is also matching regular expressions and does tail and -f (follow) by default. A nice benefit is, that it shows you the pod which generated the log as well.

app1-12381266dad-3233c foobar log
app1-99348234asd-959cc foobar log2

Grab the go-binary for linux or install via brew for OSX.

https://kubernetes.io/blog/2016/10/tail-kubernetes-with-stern/

https://github.com/stern/stern

Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78
vienna
  • 401
  • 4
  • 3
  • I took a binary from https://github.com/wercker/stern/releases and it worked perfectly out of the box. Thanks! – wim Oct 13 '20 at 20:26
  • Now use the "friendly fork": https://github.com/stern/stern I got a not found for https://github.com/wercker/stern – Enrique S. Filiage Feb 01 '23 at 21:08
20

In this example, you can replace the <namespace> and <app-name> to get the logs when there are multiple Containers defined in a Pod.

kubectl -n <namespace> logs -f deployment/<app-name> \
    --all-containers=true --since=10m
Michael Lihs
  • 7,460
  • 17
  • 52
  • 85
  • 2
    this would be fantastic if it dumped days worth of logs, i wonder what the limits are? – Randy L Feb 02 '21 at 22:40
  • 3
    for some reason, this command extracts logs for a random pod but not for all of them. I've switch to using labels instead – aderesh Apr 16 '22 at 00:15
13

I use this simple script to get a log from the pods of a deployment:

#!/usr/bin/env bash

DEPLOYMENT=$1

for p in $(kubectl get pods | grep ^${DEPLOYMENT}- | cut -f 1 -d ' '); do 
    echo --------------------------- 
    echo $p 
    echo --------------------------- 
    kubectl logs $p
done

Gist of the script

Usage: log_deployment.sh "deployment-name".

Script will then show log of all pods that start with that "deployment-name".

Martlark
  • 14,208
  • 13
  • 83
  • 99
12

You can get help from kubectl logs -h and according the info,

kubectl logs -f deployment/myapp -c myapp --tail 100

-c is the container name and --tail will show the latest num lines,but this will choose one pod of the deployment, not all pods. This is something you have to bear in mind.

kubectl logs -l app=myapp -c myapp --tail 100

If you want to show logs of all pods, you can use -l and specify a lable, but at the same time -f won't be used.

zimmer
  • 1,159
  • 3
  • 13
  • 23
  • 2
    "but this will choose one pod of the deployment, not all pods" -> true and I've spent a lot of time debugging my app before realizing that not all logs were being displayed. This should be more explicit both in the other answers and the official docs. – Teodoro Dec 27 '21 at 01:13
11

This answer attempts to provide a concise example along with an explanation. In order to get all the outputs of all the containers in a set of pods, you have to use labels (selectors) unless you plan on doing some additional scripting.

kubectl logs \
--namespace my-namespace \
-l app=my-app-label \
--tail=-1 \
--timestamps=true \
--prefix=true \
--all-containers=true

This example returns complete snapshot logs from all containers in pods defined by label app=my-app-label.

Optional Options

It may be helpful to add the --timestamps=true and --prefix=true flags so that the timestamp and log source are visible in the output, but they are not required.

Logs by Resource

If a resource such as a deployment is specified and that deployment has multiple pods such as a ReplicaSet, then only one of the pods logs will be returned. This is why a selector is used to identify the pods.

Despite specifying --all-containers, targeting a resource such as a service or a deployment does not successfully return the logs of all containers in all pods using kubectl v1.22.5 when this response was written. This is why selectors must be used.

Container Names

Per the output of kubectl logs --help

Print the logs for a container in a pod or specified resource. If the pod has only one container, the container name is optional.

What this means is that if there is more than one container, you have to do one of the following:

  • Let the command pick a container for you
  • Use the --all-containers=true option

Following and Tailing

If you specify a label as the example above does, then tail will get set to 10, returning only the last 10 logs for each container. To get all logs, set tail to -1.

Add -f or --follow to the example to follow the logs. If you don't need all of the logs, change the value of the --tail option. When tailing the logs, you may want to ensure that the default option --max-log-requests=5 is sufficient. If there are 20 containers upping --max-log-requests=20 is required.

eltee
  • 196
  • 1
  • 6
  • 1
    This is an excellent answer, thank you for providing it. Using Helm's tags I was able to retreive the logs of all the APPNAME pods in my deployment using `kubectl logs -l app.kubernetes.io/name=APPNAME --all-containers=true --timestamps=true --prefix=true --tail=-1 --follow`. Thank you! – Gifford N. Nov 03 '22 at 04:49
6

One option is to set up cluster logging via Fluentd/ElasticSearch as described at https://kubernetes.io/docs/user-guide/logging/elasticsearch/. Once logs are in ES, it's easy to apply filters in Kibana to view logs from certain containers.

Anirudh Ramanathan
  • 46,179
  • 22
  • 132
  • 191
6

You can do either of the following options based on your requirements:

  1. kubectl -n my_namespace logs deployment/my_deployment --all-containers=true --since 10m
  2. for i in $(kubectl get pods -n "my_namespace" | sed 1d | cut -d" " -f1); do kubectl logs $i -n "my_namespace" "app_name" | grep -i "filter_string you want to" ; done
hp_elite
  • 158
  • 1
  • 6
3

If the pods are named meaningfully one could use simple Plain Old Bash:

keyword=nodejs
command="cat <("
for line in $(kubectl get pods | \
  grep $keyword | grep Running | awk '{print $1}'); do 
    command="$command (kubectl logs --tail=2 -f $line &) && "
  done
command="$command echo)"
eval $command

Explanation: Loop through running pods with name containing "nodejs". Tail the log for each of them in parallel (single ampersand runs in background) ensuring that if any of the pods fail the whole command exits (double ampersand). Cat the streams from each of the tail commands into a unique stream. Eval is needed to run this dynamically built command.

Nestor Urquiza
  • 2,821
  • 28
  • 21
3

You can also do this by service name.

First, try to find the service name of the respective pod which corresponds to multiple pods of the same service. kubectl get svc.

Next, run the following command to display logs from each container.

kubectl logs -f service/<service-name>
Harshit
  • 617
  • 1
  • 6
  • 15
  • 5
    【Found 12 pods, using pod/xxx-app-234234-fdsfsd】, This is my output when using this command, it seems it didn't follow all 12 pods. – Zen Sep 10 '20 at 02:25
3

@johan's answer gave me an idea of a one liner:

for i in $(kubectl get pods -n default |cut -d" " -f1); do kubectl logs $i -n default; done
Ferris
  • 51
  • 2
1

Worked for me:

kubectl logs -n namespace -l app=label -c container

Rostislav V
  • 1,706
  • 1
  • 19
  • 31
0

Another solution that I would consider is using K9S which is a great kube administration tool.

After installation, the usage is very straightforward:

 k9s -n my-namespace --context the_context_name_in_kubeconfig

(If kubeconfig is not in the default location add KUBECONFIG=path/to/kubeconfig prefix).

The default view will list all pods as a list:

enter image description here

We can change the view to other Kube controllers like replica set (question asked for replication controllers so notice they are deprecated), deployments, cron jobs, etc' by entering a colon : and start typing the desired controller - as we can see K9S provides autocompletion for us:

enter image description here

And we can see all replica sets in the current namespace:

enter image description here

We can just choose the desired replica set by clicking enter and then we'll see the list of all pods which are related to this replica set - we can then press on 'l' to view logs of each pod.

So, unlike in the case of stern, we still need to go on each pod and view its logs but I think it is very convenient with K9S - we first view all pods of a related controller and then investigate logs of each pod by simply navigating with enter, l and escape.

Rot-man
  • 18,045
  • 12
  • 118
  • 124
0

We've just launched a Kubernetes native logging tool that can collect logs from all the pods (that you specify) and send the logs to a centralised location.

I hope it helps anyone landing on this page: https://github.com/parseablehq/collector

Nitish T
  • 132
  • 1
  • 1
  • 8
0

Pods are usually associated with "parent" resources like Services, Deployments and ReplicaSets, via some selector in those resources. In order to get the logs of all pods associated with a certain resource, you need to transform their selector into a valid --selector expression for kubectl logs.

For example, the following will generate a --selector expression for a Service:

kubectl --context "${CONTEXT}" --namespace "${NAMESPACE}" \
    get "service/${SERVICE}" --output=jsonpath='{.spec.selector}' \
| jq 'to_entries | map("\(.key)=\(.value)") | join(",")' -r

Thus, the following command would follow the logs of all Pods associated with the ${SERVICE}:

kubectl --context "${CONTEXT}" --namespace "${NAMESPACE}" \
    logs --follow --all-containers --prefix --timestamps --selector "$(
        kubectl --context "${CONTEXT}" --namespace "${NAMESPACE}" \
            get "service/${SERVICE}" --output=jsonpath='{.spec.selector}' \
        | jq 'to_entries | map("\(.key)=\(.value)") | join(",")' -r
    )"

A similar thing can be expressed with xargs, if you don't like nesting:

kubectl --context "${CONTEXT}" --namespace "${NAMESPACE}" \
    get "service/${SERVICE}" --output=jsonpath='{.spec.selector}' \
| jq 'to_entries | map("\(.key)=\(.value)") | join(",")' -r \
| xargs -rn1 kubectl --context "${CONTEXT}" --namespace "${NAMESPACE}" \
    logs --follow --all-containers --prefix --timestamps --selector
Robin479
  • 1,606
  • 15
  • 16
-3

I use this command.

kubectl -n <namespace> logs -f deployment/<app-name> --all-containers=true --since=10m
  • 1
    Hello! While that command may solve the question, [including an explanation](https://meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Brian61354270 Apr 24 '20 at 13:35
  • How is this answer different from @Gokul Gunasekaran's answer? – ssasi Nov 05 '20 at 13:17
-9

Not sure if this is a new thing, but with deployments it is possible to do it like this:

kubectl logs deployment/app1
Tiago Martins Peres
  • 14,289
  • 18
  • 86
  • 145