mirror of https://github.com/k3s-io/k3s
270 lines
12 KiB
Markdown
270 lines
12 KiB
Markdown
![]() |
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
|||
|
|
|||
|
<!-- BEGIN STRIP_FOR_RELEASE -->
|
|||
|
|
|||
|
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
|||
|
width="25" height="25">
|
|||
|
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
|||
|
width="25" height="25">
|
|||
|
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
|||
|
width="25" height="25">
|
|||
|
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
|||
|
width="25" height="25">
|
|||
|
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
|||
|
width="25" height="25">
|
|||
|
|
|||
|
<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>
|
|||
|
|
|||
|
If you are using a released version of Kubernetes, you should
|
|||
|
refer to the docs that go with that version.
|
|||
|
|
|||
|
Documentation for other releases can be found at
|
|||
|
[releases.k8s.io](http://releases.k8s.io).
|
|||
|
</strong>
|
|||
|
--
|
|||
|
|
|||
|
<!-- END STRIP_FOR_RELEASE -->
|
|||
|
|
|||
|
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
|||
|
|
|||
|
# CRI: Log management for container stdout/stderr streams
|
|||
|
|
|||
|
|
|||
|
## Goals and non-goals
|
|||
|
|
|||
|
Container Runtime Interface (CRI) is an ongoing project to allow container
|
|||
|
runtimes to integrate with kubernetes via a newly-defined API. The goal of this
|
|||
|
proposal is to define how container's *stdout/stderr* log streams should be
|
|||
|
handled in CRI.
|
|||
|
|
|||
|
The explicit non-goal is to define how (non-stdout/stderr) application logs
|
|||
|
should be handled. Collecting and managing arbitrary application logs is a
|
|||
|
long-standing issue [1] in kubernetes and is worth a proposal of its own. Even
|
|||
|
though this proposal does not touch upon these logs, the direction of
|
|||
|
this proposal is aligned with one of the most-discussed solutions, logging
|
|||
|
volumes [1], for general logging management.
|
|||
|
|
|||
|
*In this proposal, “logs” refer to the stdout/stderr streams of the
|
|||
|
containers, unless specified otherwise.*
|
|||
|
|
|||
|
Previous CRI logging issues:
|
|||
|
- Tracking issue: https://github.com/kubernetes/kubernetes/issues/30709
|
|||
|
- Proposal (by @tmrtfs): https://github.com/kubernetes/kubernetes/pull/33111
|
|||
|
|
|||
|
The scope of this proposal is narrower than the #33111 proposal, and hopefully
|
|||
|
this will encourage a more focused discussion.
|
|||
|
|
|||
|
|
|||
|
## Background
|
|||
|
|
|||
|
Below is a brief overview of logging in kubernetes with docker, which is the
|
|||
|
only container runtime with fully functional integration today.
|
|||
|
|
|||
|
**Log lifecycle and management**
|
|||
|
|
|||
|
Docker supports various logging drivers (e.g., syslog, journal, and json-file),
|
|||
|
and allows users to configure the driver by passing flags to the docker daemon
|
|||
|
at startup. Kubernetes defaults to the "json-file" logging driver, in which
|
|||
|
docker writes the stdout/stderr streams to a file in the json format as shown
|
|||
|
below.
|
|||
|
|
|||
|
```
|
|||
|
{“log”: “The actual log line”, “stream”: “stderr”, “time”: “2016-10-05T00:00:30.082640485Z”}
|
|||
|
```
|
|||
|
|
|||
|
Docker deletes the log files when the container is removed, and a cron-job (or
|
|||
|
systemd timer-based job) on the node is responsible to rotate the logs (using
|
|||
|
`logrotate`). To preserve the logs for introspection and debuggability, kubelet
|
|||
|
keeps the terminated container until the pod object has been deleted from the
|
|||
|
apiserver.
|
|||
|
|
|||
|
**Container log retrieval**
|
|||
|
|
|||
|
The kubernetes CLI tool, kubectl, allows users to access the container logs
|
|||
|
using [`kubectl logs`]
|
|||
|
(http://kubernetes.io/docs/user-guide/kubectl/kubectl_logs/) command.
|
|||
|
`kubectl logs` supports flags such as `--since` that requires understanding of
|
|||
|
the format and the metadata (i.e., timestamps) of the logs. In the current
|
|||
|
implementation, kubelet calls `docker logs` with parameters to return the log
|
|||
|
content. As of now, docker only supports `log` operations for the “journal” and
|
|||
|
“json-file” drivers [2]. In other words, *the support of `kubectl logs` is not
|
|||
|
universal in all kuernetes deployments*.
|
|||
|
|
|||
|
**Cluster logging support**
|
|||
|
|
|||
|
In a production cluster, logs are usually collected, aggregated, and shipped to
|
|||
|
a remote store where advanced analysis/search/archiving functions are
|
|||
|
supported. In kubernetes, the default cluster-addons includes a per-node log
|
|||
|
collection daemon, `fluentd`. To facilitate the log collection, kubelet creates
|
|||
|
symbolic links to all the docker containers logs under `/var/log/containers`
|
|||
|
with pod and container metadata embedded in the filename.
|
|||
|
|
|||
|
```
|
|||
|
/var/log/containers/<pod_name>_<pod_namespace>_<container_name>-<container_id>.log`
|
|||
|
```
|
|||
|
|
|||
|
The fluentd daemon watches the `/var/log/containers/` directory and extract the
|
|||
|
metadata associated with the log from the path. Note that this integration
|
|||
|
requires kubelet to know where the container runtime stores the logs, and will
|
|||
|
not be directly applicable to CRI.
|
|||
|
|
|||
|
|
|||
|
## Requirements
|
|||
|
|
|||
|
1. **Provide ways for CRI-compliant runtimes to support all existing logging
|
|||
|
features, i.e., `kubectl logs`.**
|
|||
|
|
|||
|
2. **Allow kubelet to manage the lifecycle of the logs to pave the way for
|
|||
|
better disk management in the future.** This implies that the lifecycle
|
|||
|
of containers and their logs need to be decoupled.
|
|||
|
|
|||
|
3. **Allow log collectors to easily integrate with Kubernetes across
|
|||
|
different container runtimes while preserving efficient storage and
|
|||
|
retrieval.**
|
|||
|
|
|||
|
Requirement (1) provides opportunities for runtimes to continue support
|
|||
|
`kubectl logs --since` and related features. Note that even though such
|
|||
|
features are only supported today for a limited set of log drivers, this is an
|
|||
|
important usability tool for a fresh, basic kubernetes cluster, and should not
|
|||
|
be overlooked. Requirement (2) stems from the fact that disk is managed by
|
|||
|
kubelet as a node-level resource (not per-pod) today, hence it is difficult to
|
|||
|
delegate to the runtime by enforcing per-pod disk quota policy. In addition,
|
|||
|
container disk quota is not well supported yet, and such limitation may not
|
|||
|
even be well-perceived by users. Requirement (1) is crucial to the kubernetes'
|
|||
|
extensibility and usability across all deployments.
|
|||
|
|
|||
|
## Proposed solution
|
|||
|
|
|||
|
This proposal intends to satisfy the requirements by
|
|||
|
|
|||
|
1. Enforce where the container logs should be stored on the host
|
|||
|
filesystem. Both kubelet and the log collector can interact with
|
|||
|
the log files directly.
|
|||
|
|
|||
|
2. Ask the runtime to decorate the logs in a format that kubelet understands.
|
|||
|
|
|||
|
**Log directories and structures**
|
|||
|
|
|||
|
Kubelet will be configured with a root directory (e.g., `/var/log/pods` or
|
|||
|
`/var/lib/kubelet/logs/) to store all container logs. Below is an example of a
|
|||
|
path to the log of a container in a pod.
|
|||
|
|
|||
|
```
|
|||
|
/var/log/pods/<podUID>/<containerName>_<instance#>.log
|
|||
|
```
|
|||
|
|
|||
|
In CRI, this is implemented by setting the pod-level log directory when
|
|||
|
creating the pod sandbox, and passing the relative container log path
|
|||
|
when creating a container.
|
|||
|
|
|||
|
```
|
|||
|
PodSandboxConfig.LogDirectory: /var/log/pods/<podUID>/
|
|||
|
ContainerConfig.LogPath: <containerName>_<instance#>.log
|
|||
|
```
|
|||
|
|
|||
|
Because kubelet determines where the logs are stores and can access them
|
|||
|
directly, this meets requirement (1). As for requirement (2), the log collector
|
|||
|
can easily extract basic pod metadata (e.g., pod UID, container name) from
|
|||
|
the paths, and watch the directly for any changes. In the future, we can
|
|||
|
extend this by maintaining a metada file in the pod directory.
|
|||
|
|
|||
|
**Log format**
|
|||
|
|
|||
|
The runtime should decorate each log entry with a RFC 3339Nano timestamp
|
|||
|
prefix, the stream type (i.e., "stdout" or "stderr"), and ends with a newline.
|
|||
|
|
|||
|
```
|
|||
|
2016-10-06T00:17:09.669794202Z stdout The content of the log entry 1
|
|||
|
2016-10-06T00:17:10.113242941Z stderr The content of the log entry 2
|
|||
|
```
|
|||
|
|
|||
|
With the knowledge, kubelet can parses the logs and serve them for `kubectl
|
|||
|
logs` requests. This meets requirement (3). Note that the format is defined
|
|||
|
deliberately simple to provide only information necessary to serve the requests.
|
|||
|
We do not intend for kubelet to host various logging plugins. It is also worth
|
|||
|
mentioning again that the scope of this proposal is restricted to stdout/stderr
|
|||
|
streams of the container, and we impose no restriction to the logging format of
|
|||
|
arbitrary container logs.
|
|||
|
|
|||
|
**Who should rotate the logs?**
|
|||
|
|
|||
|
We assume that a separate task (e.g., cron job) will be configured on the node
|
|||
|
to rotate the logs periodically, similar to today’s implementation.
|
|||
|
|
|||
|
We do not rule out the possibility of letting kubelet or a per-node daemon
|
|||
|
(`DaemonSet`) to take up the responsibility, or even declare rotation policy
|
|||
|
in the kubernetes API as part of the `PodSpec`, but it is beyond the scope of
|
|||
|
the this proposal.
|
|||
|
|
|||
|
**What about non-supported log formats?**
|
|||
|
|
|||
|
If a runtime chooses to store logs in non-supported formats, it essentially
|
|||
|
opts out of `kubectl logs` features, which is backed by kubelet today. It is
|
|||
|
assumed that the user can rely on the advanced, cluster logging infrastructure
|
|||
|
to examine the logs.
|
|||
|
|
|||
|
It is also possible that in the future, `kubectl logs` can contact the cluster
|
|||
|
logging infrastructure directly to serve logs [1a]. Note that this does not
|
|||
|
eliminate the need to store the logs on the node locally for reliability.
|
|||
|
|
|||
|
|
|||
|
**How can existing runtimes (docker/rkt) comply to the logging requirements?**
|
|||
|
|
|||
|
In the short term, the ongoing docker-CRI integration [3] will support the
|
|||
|
proposed solution only partially by (1) creating symbolic links for kubelet
|
|||
|
to access, but not manage the logs, and (2) add support for json format in
|
|||
|
kubelet. A more sophisticated solution that either involves using a custom
|
|||
|
plugin or launching a separate process to copy and decorate the log will be
|
|||
|
considered as a mid-term solution.
|
|||
|
|
|||
|
For rkt, implementation will rely on providing external file-descriptors for
|
|||
|
stdout/stderr to applications via systemd [4]. Those streams are currently
|
|||
|
managed by a journald sidecar, which collects stream outputs and store them
|
|||
|
in the journal file of the pod. This will replaced by a custom sidecar which
|
|||
|
can produce logs in the format expected by this specification and can handle
|
|||
|
clients attaching as well.
|
|||
|
|
|||
|
## Alternatives
|
|||
|
|
|||
|
There are ad-hoc solutions/discussions that addresses one or two of the
|
|||
|
requirements, but no comprehensive solution for CRI specifically has been
|
|||
|
proposed so far (with the excpetion of @tmrtfs's proposal
|
|||
|
[#33111](https://github.com/kubernetes/kubernetes/pull/33111), which has a much
|
|||
|
wider scope). It has come up in discussions that kubelet can delegate all the
|
|||
|
logging management to the runtime to allow maximum flexibility. However, it is
|
|||
|
difficult for this approach to meet either requirement (1) or (2), without
|
|||
|
defining complex logging API.
|
|||
|
|
|||
|
There are also possibilities to implement the current proposal by imposing the
|
|||
|
log file paths, while leveraging the runtime to access and/or manage logs. This
|
|||
|
requires the runtime to expose knobs in CRI to retrieve, remove, and examine
|
|||
|
the disk usage of logs. The upside of this approach is that kubelet needs not
|
|||
|
mandate the logging format, assuming runtime already includes plugins for
|
|||
|
various logging formats. Unfortunately, this is not true for existing runtimes
|
|||
|
such as docker, which supports log retrieval only for a very limited number of
|
|||
|
log drivers [2]. On the other hand, the downside is that we would be enforcing
|
|||
|
more requirements on the runtime through log storage location on the host, and
|
|||
|
a potentially premature logging API that may change as the disk management
|
|||
|
evolves.
|
|||
|
|
|||
|
## References
|
|||
|
|
|||
|
[1] Log management issues:
|
|||
|
- a. https://github.com/kubernetes/kubernetes/issues/17183
|
|||
|
- b. https://github.com/kubernetes/kubernetes/issues/24677
|
|||
|
- c. https://github.com/kubernetes/kubernetes/pull/13010
|
|||
|
|
|||
|
[2] Docker logging drivers:
|
|||
|
- https://docs.docker.com/engine/admin/logging/overview/
|
|||
|
|
|||
|
[3] Docker CRI integration:
|
|||
|
- https://github.com/kubernetes/kubernetes/issues/31459
|
|||
|
|
|||
|
[4] rkt support: https://github.com/systemd/systemd/pull/4179
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
|||
|
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/proposals/kubelet-cri-logging.md?pixel)]()
|
|||
|
<!-- END MUNGE: GENERATED_ANALYTICS -->
|