1. 概述

日志是监控和定位问题的关键,在Kubernetes中它提供了对Pod中容器生成的日志的实时访问。

在这篇文章中,我们将学习如何使用kubectl logs命令从Kubernetes pods获取连续的日志流

2. 示例

为了方便演示,下面我们运行一个 ubuntu 容器,每分钟打印一条消息。ubuntu-pod.yaml 如下:

$ cat ubuntu-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-pod
spec:
  containers:
  - name: ubuntu-container
    image: ubuntu
    command: ["bash", "-c", "while true; do echo 'running ...' && sleep 60 done"]

command 指定了一个无限 while 循环。因此,pod 会一直保持运行状态,同时每分钟输出一条消息

使用 kubectl apply 命令创建 ubuntu-pod

$ kubectl apply -f ubuntu-pod.yaml
pod/ubuntu-pod created

检查 Pod 是否正常运行:

$ kubectl get pods --field-selector metadata.name=ubuntu-pod
NAME         READY   STATUS    RESTARTS   AGE
ubuntu-pod   1/1     Running   0          3m7s

使用 kubectl logs 查看 ubuntu-pod 日志输出:

$ kubectl logs ubuntu-pod
running ...
running ...
running ...
running ...
running ...
$ 

日志是有了,但只打印截止当前时间的日志后就结束了。

3. 使用 –follow 跟踪输出

使用 -follow 会一直循环跟踪日志流的输出,而不会结束:

$ kubectl logs --follow ubuntu-pod
running ...
running ...
running ...
running ...
running ...
running ...
running ...

可以看到,等待一分钟后又有新的日志打印。

4. 丰富日志流

4.1. 添加时间戳

使用 –timestamps 参数,可在每行消息开头追加时间戳:

$ kubectl logs --follow --timestamps ubuntu-pod
2023-07-30T03:09:49.368021900Z running ...
2023-07-30T03:10:49.368683774Z running ...
2023-07-30T03:11:49.370931509Z running ...

其时间戳格式为RFC3339

4.2. 添加来源

除了时间戳外,另一个比较重要的是如何确定日志来源,来自那个pod和容器?

使用 –prefix 可实现这一点,显示日志消息的来源

$ kubectl logs --follow --prefix ubuntu-pod
[pod/ubuntu-pod/ubuntu-container] running ...
[pod/ubuntu-pod/ubuntu-container] running ...

可以看到现在每条日志显示了pod名称(ubuntu-pod)和容器名称(ubuntu-container)。有了这些信息,我们可以追溯每条日志行到其正确的来源。

5. 限制日志长度

在我们的场景中,我们添加了一个非常简单的日志消息,并在任何两个日志消息之间留足够的延迟。然而,对于解决实际业务需求的应用程序,应用程序可能会以显著更高的频率记录更长的消息。因此,让我们学习如何根据日志的大小来限制流式日志。

5.1. 使用 –tail 参数

类似与 Linux 中的 tail 命令,添加 -tail 参数可以只输出最后的几行日志。

$ date
Sun Jul 30 03:19:14 AM UTC 2023
$ kubectl logs --follow --timestamps --tail 2 ubuntu-pod
2023-07-30T03:17:49.383687361Z running ...
2023-07-30T03:18:49.386528064Z running ...

上面我们使用 --follow--tail 实现只展示末尾两行日志,并实时监听新的输出。

5.2. –limit-bytes 限制日志大小

另一种,我们可以利用 –limit-bytes 通过字节大小,限制日志输出长度:

$ kubectl logs --follow --limit-bytes 1 ubuntu-pod
r
$

我们可以看到,因为我们设置的字节数为1,所以只打印了一个字符 “r”。

改为 500 试试:

$ kubectl logs --follow --limit-bytes 500 ubuntu-pod
running ...
running ...
running ...
running ...
running ...
running ...
running ...
running ...
running ...
running ...
running ...
running ...
running ...
running ...

6. 根据时间过滤日志

本节我们将使用 –since–since-time 选项,通过时间过滤日志。

6.1. 使用 –since

返回相对时间内的日志。例如设置 '300s',返回过去 300秒的日志:

$ date
Sun Jul 30 03:28:51 AM UTC 2023
$ kubectl logs --follow --timestamps --since 300s ubuntu-pod
2023-07-30T03:24:49.398533266Z running ...
2023-07-30T03:25:49.401017157Z running ...
2023-07-30T03:26:49.402346354Z running ...
2023-07-30T03:27:49.404715543Z running ...
2023-07-30T03:28:49.407544746Z running ...

上面只显示了五条日志行。这是因为我们的应用程序每分钟记录一次,这计算为300秒中的5次。

也可以分钟为单位,例如2m(2分钟)内:

$ date
Sun Jul 30 03:29:53 AM UTC 2023
$ kubectl logs --follow --timestamps --since 2m ubuntu-pod
2023-07-30T03:28:49.407544746Z running ...
2023-07-30T03:29:49.409491441Z running ...

0.05h 小时(3分钟):

$ date
Sun Jul 30 03:31:43 AM UTC 2023
$ kubectl logs --follow --timestamps --since 0.05h ubuntu-pod
2023-07-30T03:28:49.407544746Z running ...
2023-07-30T03:29:49.409491441Z running ...
2023-07-30T03:30:49.411283477Z running ...

2m120s (2分120秒):

$ date
Sun Jul 30 03:30:36 AM UTC 2023
$ kubectl logs --follow --timestamps --since 2m120s ubuntu-pod
2023-07-30T03:26:49.402346354Z running ...
2023-07-30T03:27:49.404715543Z running ...
2023-07-30T03:28:49.407544746Z running ...
2023-07-30T03:29:49.409491441Z running ...

6.2. 使用 –since-time

使用 –since-time 指定绝对时间:

$ date
Sun Jul 30 03:35:47 AM UTC 2023
$ kubectl logs --follow --timestamps --since-time 2023-07-30T03:30:00.000000000Z ubuntu-pod
2023-07-30T03:30:49.411283477Z running ...
2023-07-30T03:31:49.414355691Z running ...
2023-07-30T03:32:49.416516375Z running ...
2023-07-30T03:33:49.418557475Z running ...
2023-07-30T03:34:49.420578582Z running ...

7. 多个容器日志

在本节中,我们将学习如何从一个包含多个容器的 pod 中读取日志。

7.1. 多容器Pod示例

首先,编写一个示例 pod 配置,定义多个容器: ubuntu-container-1ubuntu-container-2

$ cat ubuntu-multi-containers.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-pod-multi-containers
spec:
  containers:
  - name: ubuntu-container-1
    image: ubuntu
    command: ["bash", "-c", "while true; do echo 'running container-1...' && sleep 60; done"]
  - name: ubuntu-container-2
    image: ubuntu
    command: ["bash", "-c", "while true; do echo 'running container-2...' && sleep 60; done"]

执行apply:

$ kubectl apply -f ubuntu-multi-containers.yaml 
pod/ubuntu-pod-multi-containers created

检查是否正常启动:

$ kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
ubuntu-pod-multi-containers   2/2     Running   0          58s

最后,让我们看看是否可以使用现有的方法来查看pod的日志:

$ kubectl logs --follow ubuntu-pod-multi-containers
Defaulted container "ubuntu-container-1" out of: ubuntu-container-1, ubuntu-container-2
running container-1...
running container-1...

虽然有日志输出,但它来自单个容器。

7.2. 指定容器日志

使用 -–container 指定我们要查看的容器名称, 这里为 ubuntu-container-2:

$ kubectl logs --follow ubuntu-pod-multi-containers --container ubuntu-container-2
running container-2...
running container-2...

7.3. 全部容器

如果我们通过多次传递 –container 选项来指定多个容器名称,只会最后一个生效:

$ kubectl logs -f ubuntu-pod-multi-containers --container ubuntu-container-1 --container ubuntu-container-2
running container-2...
running container-2...

正确的做法是通过 –all-containers 参数获取该Pod下所有容器的日志:

$ kubectl logs -f ubuntu-pod-multi-containers --all-containers
running container-2...
running container-2...
running container-1...
running container-1...

8. Deployment Pods 日志

在本节中,我们将学习如何从Kubernetes Deployment 创建的Pods中获取日志。

8.1. Setup

编写Deployment示例,ubuntu-deployment.yaml

$ cat ubuntu-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ubuntu-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ubuntu-app
  template:
    metadata:
      labels:
        app: ubuntu-app
    spec:
      containers:
      - name: ubuntu-container
        image: ubuntu
        command: ["bash", "-c", "while true; do echo $(hostname)' is running ...' && sleep 60; done"]

执行apply,创建ubuntu-deployment deployment:

$ kubectl apply -f ubuntu-deployment.yaml
deployment.apps/ubuntu-deployment created

验证是否正常工作:

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
ubuntu-deployment-7ffd5967d-m2h59   1/1     Running   0          25s
ubuntu-deployment-7ffd5967d-trdv6   1/1     Running   0          25s
ubuntu-deployment-7ffd5967d-zpvxg   1/1     Running   0          25s

因为每个 Pod 后面都有一个动态的后缀,虽然,我们还是可以通过指定名称获取单个Pod日志,但不太方便。

8.2. 根据Label查询日志

在我们的Deployment配置中,我们已经定义了app标签,并将其值设置为ubuntu-app。因此,所有由ubuntu-deployment管理的Pod都具有这个标签。

我们可以通过 -l 选项,传递标签查询**:

$ kubectl logs -f -l app=ubuntu-app
ubuntu-deployment-7ffd5967d-m2h59 is running ...
ubuntu-deployment-7ffd5967d-trdv6 is running ...
ubuntu-deployment-7ffd5967d-zpvxg is running ...
ubuntu-deployment-7ffd5967d-zpvxg is running ...
ubuntu-deployment-7ffd5967d-trdv6 is running ...
ubuntu-deployment-7ffd5967d-m2h59 is running ...

太好了!我们可以看到日志流包含了所有三个Pod的日志。

9. 总结

在本文中,我们学习了如何使用kubectl logs命令的–follow选项来获取Kubernetes集群中运行的Pod的连续日志流。此外,我们还探索了多个其他选项,如timestampsprefixsincesince-timelimit-bytes等,以细化日志。

最后,我们学习了如何为特定容器、Pod中的所有容器或由Deployment管理的所有Pod流日志。