diff --git a/pkg/kubelet/dockershim/BUILD b/pkg/kubelet/dockershim/BUILD index 35e24b9a6db..8412e41480f 100644 --- a/pkg/kubelet/dockershim/BUILD +++ b/pkg/kubelet/dockershim/BUILD @@ -14,6 +14,7 @@ go_library( "docker_checkpoint.go", "docker_container.go", "docker_image.go", + "docker_legacy_service.go", "docker_sandbox.go", "docker_service.go", "docker_streaming.go", @@ -90,6 +91,7 @@ go_library( "//pkg/kubelet/dockershim/cm:go_default_library", "//pkg/kubelet/dockershim/libdocker:go_default_library", "//pkg/kubelet/dockershim/metrics:go_default_library", + "//pkg/kubelet/kuberuntime:go_default_library", "//pkg/kubelet/leaky:go_default_library", "//pkg/kubelet/network:go_default_library", "//pkg/kubelet/network/cni:go_default_library", diff --git a/pkg/kubelet/dockershim/docker_legacy_service.go b/pkg/kubelet/dockershim/docker_legacy_service.go new file mode 100644 index 00000000000..357e673622f --- /dev/null +++ b/pkg/kubelet/dockershim/docker_legacy_service.go @@ -0,0 +1,123 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License 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. +*/ + +package dockershim + +import ( + "fmt" + "io" + "strconv" + "time" + + "github.com/armon/circbuf" + dockertypes "github.com/docker/docker/api/types" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kubetypes "k8s.io/apimachinery/pkg/types" + kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" + "k8s.io/kubernetes/pkg/kubelet/kuberuntime" + + "k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker" +) + +// DockerLegacyService interface embeds some legacy methods for backward compatibility. +// This file/interface will be removed in the near future. Do not modify or add +// more functions. +type DockerLegacyService interface { + // GetContainerLogs gets logs for a specific container. + GetContainerLogs(*v1.Pod, kubecontainer.ContainerID, *v1.PodLogOptions, io.Writer, io.Writer) error + + // IsCRISupportedLogDriver checks whether the logging driver used by docker is + // suppoted by native CRI integration. + // TODO(resouer): remove this when deprecating unsupported log driver + IsCRISupportedLogDriver() (bool, error) + + kuberuntime.LegacyLogProvider +} + +// GetContainerLogs get container logs directly from docker daemon. +func (d *dockerService) GetContainerLogs(pod *v1.Pod, containerID kubecontainer.ContainerID, logOptions *v1.PodLogOptions, stdout, stderr io.Writer) error { + container, err := d.client.InspectContainer(containerID.ID) + if err != nil { + return err + } + + var since int64 + if logOptions.SinceSeconds != nil { + t := metav1.Now().Add(-time.Duration(*logOptions.SinceSeconds) * time.Second) + since = t.Unix() + } + if logOptions.SinceTime != nil { + since = logOptions.SinceTime.Unix() + } + opts := dockertypes.ContainerLogsOptions{ + ShowStdout: true, + ShowStderr: true, + Since: strconv.FormatInt(since, 10), + Timestamps: logOptions.Timestamps, + Follow: logOptions.Follow, + } + if logOptions.TailLines != nil { + opts.Tail = strconv.FormatInt(*logOptions.TailLines, 10) + } + + sopts := libdocker.StreamOptions{ + OutputStream: stdout, + ErrorStream: stderr, + RawTerminal: container.Config.Tty, + } + return d.client.Logs(containerID.ID, opts, sopts) +} + +// GetContainerLogTail attempts to read up to MaxContainerTerminationMessageLogLength +// from the end of the log when docker is configured with a log driver other than json-log. +// It reads up to MaxContainerTerminationMessageLogLines lines. +func (d *dockerService) GetContainerLogTail(uid kubetypes.UID, name, namespace string, containerId kubecontainer.ContainerID) (string, error) { + value := int64(kubecontainer.MaxContainerTerminationMessageLogLines) + buf, _ := circbuf.NewBuffer(kubecontainer.MaxContainerTerminationMessageLogLength) + // Although this is not a full spec pod, dockerLegacyService.GetContainerLogs() currently completely ignores its pod param + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + UID: uid, + Name: name, + Namespace: namespace, + }, + } + err := d.GetContainerLogs(pod, containerId, &v1.PodLogOptions{TailLines: &value}, buf, buf) + if err != nil { + return "", err + } + return buf.String(), nil +} + +// criSupportedLogDrivers are log drivers supported by native CRI integration. +var criSupportedLogDrivers = []string{"json-file"} + +// IsCRISupportedLogDriver checks whether the logging driver used by docker is +// suppoted by native CRI integration. +func (d *dockerService) IsCRISupportedLogDriver() (bool, error) { + info, err := d.client.Info() + if err != nil { + return false, fmt.Errorf("failed to get docker info: %v", err) + } + for _, driver := range criSupportedLogDrivers { + if info.LoggingDriver == driver { + return true, nil + } + } + return false, nil +} diff --git a/pkg/kubelet/dockershim/docker_service.go b/pkg/kubelet/dockershim/docker_service.go index 290a1d199ef..2256ade8a3f 100644 --- a/pkg/kubelet/dockershim/docker_service.go +++ b/pkg/kubelet/dockershim/docker_service.go @@ -18,21 +18,16 @@ package dockershim import ( "fmt" - "io" "net/http" - "strconv" "sync" "time" - "github.com/armon/circbuf" "github.com/blang/semver" dockertypes "github.com/docker/docker/api/types" "github.com/golang/glog" "golang.org/x/net/context" "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kubetypes "k8s.io/apimachinery/pkg/types" runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig" kubecm "k8s.io/kubernetes/pkg/kubelet/cm" @@ -86,6 +81,25 @@ const ( // to kubelet behavior and system settings in addition to any API flags that may be introduced. ) +// CRIService includes all methods necessary for a CRI server. +type CRIService interface { + runtimeapi.RuntimeServiceServer + runtimeapi.ImageServiceServer + Start() error +} + +// DockerService is an interface that embeds the new RuntimeService and +// ImageService interfaces. +type DockerService interface { + CRIService + + // For serving streaming calls. + http.Handler + + // For supporting legacy features. + DockerLegacyService +} + // NetworkPluginSettings is the subset of kubelet runtime args we pass // to the container runtime shim so it can probe for network plugins. // In the future we will feed these directly to a standalone container @@ -262,32 +276,6 @@ func NewDockerService(config *ClientConfig, podSandboxImage string, streamingCon return ds, nil } -// CRIService is the interface implement CRI remote service server. -type CRIService interface { - runtimeapi.RuntimeServiceServer - runtimeapi.ImageServiceServer - - Start() error -} - -// DockerService is an interface that embeds the new RuntimeService and -// ImageService interfaces. -type DockerService interface { - CRIService - - // For serving streaming calls. - http.Handler - - // IsCRISupportedLogDriver checks whether the logging driver used by docker is - // suppoted by native CRI integration. - // TODO(resouer): remove this when deprecating unsupported log driver - IsCRISupportedLogDriver() (bool, error) - - // NewDockerLegacyService created docker legacy service when log driver is not supported. - // TODO(resouer): remove this when deprecating unsupported log driver - NewDockerLegacyService() DockerLegacyService -} - type dockerService struct { client libdocker.Interface os kubecontainer.OSInterface @@ -520,103 +508,3 @@ func toAPIProtocol(protocol Protocol) v1.Protocol { glog.Warningf("Unknown protocol %q: defaulting to TCP", protocol) return v1.ProtocolTCP } - -// DockerLegacyService interface embeds some legacy methods for backward compatibility. -type DockerLegacyService interface { - // GetContainerLogs gets logs for a specific container. - GetContainerLogs(*v1.Pod, kubecontainer.ContainerID, *v1.PodLogOptions, io.Writer, io.Writer) error -} - -// dockerLegacyService implements the DockerLegacyService. We add this for non json-log driver -// support. (See #41996) -type dockerLegacyService struct { - client libdocker.Interface -} - -// NewDockerLegacyService created docker legacy service when log driver is not supported. -// TODO(resouer): remove this when deprecating unsupported log driver -func (d *dockerService) NewDockerLegacyService() DockerLegacyService { - return &dockerLegacyService{client: d.client} -} - -// GetContainerLogs get container logs directly from docker daemon. -func (d *dockerLegacyService) GetContainerLogs(pod *v1.Pod, containerID kubecontainer.ContainerID, logOptions *v1.PodLogOptions, stdout, stderr io.Writer) error { - container, err := d.client.InspectContainer(containerID.ID) - if err != nil { - return err - } - - var since int64 - if logOptions.SinceSeconds != nil { - t := metav1.Now().Add(-time.Duration(*logOptions.SinceSeconds) * time.Second) - since = t.Unix() - } - if logOptions.SinceTime != nil { - since = logOptions.SinceTime.Unix() - } - opts := dockertypes.ContainerLogsOptions{ - ShowStdout: true, - ShowStderr: true, - Since: strconv.FormatInt(since, 10), - Timestamps: logOptions.Timestamps, - Follow: logOptions.Follow, - } - if logOptions.TailLines != nil { - opts.Tail = strconv.FormatInt(*logOptions.TailLines, 10) - } - - sopts := libdocker.StreamOptions{ - OutputStream: stdout, - ErrorStream: stderr, - RawTerminal: container.Config.Tty, - } - return d.client.Logs(containerID.ID, opts, sopts) -} - -// LegacyLogProvider implements the kuberuntime.LegacyLogProvider interface -type LegacyLogProvider struct { - dls DockerLegacyService -} - -func NewLegacyLogProvider(dls DockerLegacyService) LegacyLogProvider { - return LegacyLogProvider{dls: dls} -} - -// GetContainerLogTail attempts to read up to MaxContainerTerminationMessageLogLength -// from the end of the log when docker is configured with a log driver other than json-log. -// It reads up to MaxContainerTerminationMessageLogLines lines. -func (l LegacyLogProvider) GetContainerLogTail(uid kubetypes.UID, name, namespace string, containerId kubecontainer.ContainerID) (string, error) { - value := int64(kubecontainer.MaxContainerTerminationMessageLogLines) - buf, _ := circbuf.NewBuffer(kubecontainer.MaxContainerTerminationMessageLogLength) - // Although this is not a full spec pod, dockerLegacyService.GetContainerLogs() currently completely ignores its pod param - pod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - UID: uid, - Name: name, - Namespace: namespace, - }, - } - err := l.dls.GetContainerLogs(pod, containerId, &v1.PodLogOptions{TailLines: &value}, buf, buf) - if err != nil { - return "", err - } - return buf.String(), nil -} - -// criSupportedLogDrivers are log drivers supported by native CRI integration. -var criSupportedLogDrivers = []string{"json-file"} - -// IsCRISupportedLogDriver checks whether the logging driver used by docker is -// suppoted by native CRI integration. -func (d *dockerService) IsCRISupportedLogDriver() (bool, error) { - info, err := d.client.Info() - if err != nil { - return false, fmt.Errorf("failed to get docker info: %v", err) - } - for _, driver := range criSupportedLogDrivers { - if info.LoggingDriver == driver { - return true, nil - } - } - return false, nil -} diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 27a4e2d5ba0..e71ae01e744 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -630,8 +630,8 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, return nil, err } if !supported { - klet.dockerLegacyService = ds.NewDockerLegacyService() - legacyLogProvider = dockershim.NewLegacyLogProvider(klet.dockerLegacyService) + klet.dockerLegacyService = ds + legacyLogProvider = ds } case kubetypes.RemoteContainerRuntime: // No-op.