Windows: Fixes termination-file mounting for containerd

If Containerd is used on Windows, then we can also mount individual
files into containers (e.g.: termination-log files), which was not
possible with Docker.

Checks if the container runtime is containerd, and if it is, then also
mount the termination-log file.
This commit is contained in:
Claudiu Belu 2019-09-04 09:16:21 -07:00
parent 3a50184421
commit d4d7f58362
7 changed files with 40 additions and 5 deletions

View File

@ -63,6 +63,9 @@ type Runtime interface {
// Type returns the type of the container runtime.
Type() string
//SupportsSingleFileMapping returns whether the container runtime supports single file mappings or not.
SupportsSingleFileMapping() bool
// Version returns the version information of the container runtime.
Version() (Version, error)

View File

@ -177,6 +177,10 @@ func (f *FakeRuntime) Type() string {
return f.RuntimeType
}
func (f *FakeRuntime) SupportsSingleFileMapping() bool {
return true
}
func (f *FakeRuntime) Version() (kubecontainer.Version, error) {
f.Lock()
defer f.Unlock()

View File

@ -47,6 +47,11 @@ func (r *Mock) Type() string {
return args.Get(0).(string)
}
func (r *Mock) SupportsSingleFileMapping() bool {
args := r.Called()
return args.Get(0).(bool)
}
func (r *Mock) Version() (kubecontainer.Version, error) {
args := r.Called()
return args.Get(0).(kubecontainer.Version), args.Error(1)

View File

@ -471,9 +471,10 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Contai
}
opts.Mounts = append(opts.Mounts, mounts...)
// Disabling adding TerminationMessagePath on Windows as these files would be mounted as docker volume and
// Docker for Windows has a bug where only directories can be mounted
if len(container.TerminationMessagePath) != 0 && runtime.GOOS != "windows" {
// adding TerminationMessagePath on Windows is only allowed if ContainerD is used. Individual files cannot
// be mounted as volumes using Docker for Windows.
supportsSingleFileMapping := kl.containerRuntime.SupportsSingleFileMapping()
if len(container.TerminationMessagePath) != 0 && supportsSingleFileMapping {
p := kl.getPodContainerDir(pod.UID, container.Name)
if err := os.MkdirAll(p, 0750); err != nil {
klog.Errorf("Error on creating %q: %v", p, err)

View File

@ -53,6 +53,7 @@ go_library(
"//pkg/util/parsers:go_default_library",
"//pkg/util/selinux:go_default_library",
"//pkg/util/tail:go_default_library",
"//pkg/volume/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",

View File

@ -25,6 +25,7 @@ import (
"net/url"
"os"
"path/filepath"
goruntime "runtime"
"sort"
"strings"
"sync"
@ -47,6 +48,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/util/format"
"k8s.io/kubernetes/pkg/util/selinux"
"k8s.io/kubernetes/pkg/util/tail"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
)
var (
@ -292,7 +294,9 @@ func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerO
// The reason we create and mount the log file in here (not in kubelet) is because
// the file's location depends on the ID of the container, and we need to create and
// mount the file before actually starting the container.
if opts.PodContainerDir != "" && len(container.TerminationMessagePath) != 0 {
// we can only mount individual files (e.g.: /etc/hosts, termination-log files) on Windows only if we're using Containerd.
supportsSingleFileMapping := m.SupportsSingleFileMapping()
if opts.PodContainerDir != "" && len(container.TerminationMessagePath) != 0 && supportsSingleFileMapping {
// Because the PodContainerDir contains pod uid and container name which is unique enough,
// here we just add a random id to make the path unique for different instances
// of the same container.
@ -312,10 +316,13 @@ func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerO
utilruntime.HandleError(fmt.Errorf("unable to set termination-log file permissions %q: %v", containerLogPath, err))
}
// Volume Mounts fail on Windows if it is not of the form C:/
containerLogPath = volumeutil.MakeAbsolutePath(goruntime.GOOS, containerLogPath)
terminationMessagePath := volumeutil.MakeAbsolutePath(goruntime.GOOS, container.TerminationMessagePath)
selinuxRelabel := selinux.SELinuxEnabled()
volumeMounts = append(volumeMounts, &runtimeapi.Mount{
HostPath: containerLogPath,
ContainerPath: container.TerminationMessagePath,
ContainerPath: terminationMessagePath,
SelinuxRelabel: selinuxRelabel,
})
}
@ -355,6 +362,8 @@ func getTerminationMessage(status *runtimeapi.ContainerStatus, terminationMessag
if len(terminationMessagePath) == 0 {
return "", fallbackToLogs
}
// Volume Mounts fail on Windows if it is not of the form C:/
terminationMessagePath = volumeutil.MakeAbsolutePath(goruntime.GOOS, terminationMessagePath)
for _, mount := range status.Mounts {
if mount.ContainerPath != terminationMessagePath {
continue

View File

@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"os"
goruntime "runtime"
"time"
cadvisorapi "github.com/google/cadvisor/info/v1"
@ -243,6 +244,17 @@ func (m *kubeGenericRuntimeManager) Type() string {
return m.runtimeName
}
// SupportsSingleFileMapping returns whether the container runtime supports single file mappings or not.
// It is supported on Windows only if the container runtime is containerd.
func (m *kubeGenericRuntimeManager) SupportsSingleFileMapping() bool {
switch goruntime.GOOS {
case "windows":
return m.Type() != types.DockerContainerRuntime
default:
return true
}
}
func newRuntimeVersion(version string) (*utilversion.Version, error) {
if ver, err := utilversion.ParseSemantic(version); err == nil {
return ver, err