mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
dockershim: set security option separators based on the docker version
Also add a version cache to avoid hitting the docker daemon frequently.
This commit is contained in:
parent
9dec47dc28
commit
d8e29e782f
@ -43,14 +43,15 @@ go_library(
|
|||||||
"//pkg/kubelet/qos:go_default_library",
|
"//pkg/kubelet/qos:go_default_library",
|
||||||
"//pkg/kubelet/server/streaming:go_default_library",
|
"//pkg/kubelet/server/streaming:go_default_library",
|
||||||
"//pkg/kubelet/types:go_default_library",
|
"//pkg/kubelet/types:go_default_library",
|
||||||
|
"//pkg/kubelet/util/cache:go_default_library",
|
||||||
"//pkg/kubelet/util/ioutils:go_default_library",
|
"//pkg/kubelet/util/ioutils:go_default_library",
|
||||||
"//pkg/util/hash:go_default_library",
|
"//pkg/util/hash:go_default_library",
|
||||||
"//pkg/util/term:go_default_library",
|
"//pkg/util/term:go_default_library",
|
||||||
|
"//vendor:github.com/blang/semver",
|
||||||
"//vendor:github.com/docker/engine-api/types",
|
"//vendor:github.com/docker/engine-api/types",
|
||||||
"//vendor:github.com/docker/engine-api/types/container",
|
"//vendor:github.com/docker/engine-api/types/container",
|
||||||
"//vendor:github.com/docker/engine-api/types/filters",
|
"//vendor:github.com/docker/engine-api/types/filters",
|
||||||
"//vendor:github.com/docker/engine-api/types/strslice",
|
"//vendor:github.com/docker/engine-api/types/strslice",
|
||||||
"//vendor:github.com/docker/engine-api/types/versions",
|
|
||||||
"//vendor:github.com/docker/go-connections/nat",
|
"//vendor:github.com/docker/go-connections/nat",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||||
@ -87,7 +88,9 @@ go_test(
|
|||||||
"//pkg/kubelet/network:go_default_library",
|
"//pkg/kubelet/network:go_default_library",
|
||||||
"//pkg/kubelet/network/mock_network:go_default_library",
|
"//pkg/kubelet/network/mock_network:go_default_library",
|
||||||
"//pkg/kubelet/types:go_default_library",
|
"//pkg/kubelet/types:go_default_library",
|
||||||
|
"//pkg/kubelet/util/cache:go_default_library",
|
||||||
"//pkg/security/apparmor:go_default_library",
|
"//pkg/security/apparmor:go_default_library",
|
||||||
|
"//vendor:github.com/blang/semver",
|
||||||
"//vendor:github.com/docker/engine-api/types",
|
"//vendor:github.com/docker/engine-api/types",
|
||||||
"//vendor:github.com/docker/engine-api/types/container",
|
"//vendor:github.com/docker/engine-api/types/container",
|
||||||
"//vendor:github.com/golang/mock/gomock",
|
"//vendor:github.com/golang/mock/gomock",
|
||||||
|
@ -107,6 +107,12 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeapi
|
|||||||
// Write the sandbox ID in the labels.
|
// Write the sandbox ID in the labels.
|
||||||
labels[sandboxIDLabelKey] = podSandboxID
|
labels[sandboxIDLabelKey] = podSandboxID
|
||||||
|
|
||||||
|
apiVersion, err := ds.getDockerAPIVersion()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to get the docker API version: %v", err)
|
||||||
|
}
|
||||||
|
securityOptSep := getSecurityOptSeparator(apiVersion)
|
||||||
|
|
||||||
image := ""
|
image := ""
|
||||||
if iSpec := config.GetImage(); iSpec != nil {
|
if iSpec := config.GetImage(); iSpec != nil {
|
||||||
image = iSpec.Image
|
image = iSpec.Image
|
||||||
@ -152,7 +158,7 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeapi
|
|||||||
// Note: ShmSize is handled in kube_docker_client.go
|
// Note: ShmSize is handled in kube_docker_client.go
|
||||||
|
|
||||||
// Apply security context.
|
// Apply security context.
|
||||||
applyContainerSecurityContext(lc, podSandboxID, createConfig.Config, hc)
|
applyContainerSecurityContext(lc, podSandboxID, createConfig.Config, hc, securityOptSep)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply cgroupsParent derived from the sandbox config.
|
// Apply cgroupsParent derived from the sandbox config.
|
||||||
@ -177,7 +183,7 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeapi
|
|||||||
hc.Resources.Devices = devices
|
hc.Resources.Devices = devices
|
||||||
|
|
||||||
// Apply appArmor and seccomp options.
|
// Apply appArmor and seccomp options.
|
||||||
securityOpts, err := getContainerSecurityOpts(config.Metadata.Name, sandboxConfig, ds.seccompProfileRoot)
|
securityOpts, err := getContainerSecurityOpts(config.Metadata.Name, sandboxConfig, ds.seccompProfileRoot, securityOptSep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to generate container security options for container %q: %v", config.Metadata.Name, err)
|
return "", fmt.Errorf("failed to generate container security options for container %q: %v", config.Metadata.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -378,7 +378,7 @@ func (ds *dockerService) ListPodSandbox(filter *runtimeapi.PodSandboxFilter) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// applySandboxLinuxOptions applies LinuxPodSandboxConfig to dockercontainer.HostConfig and dockercontainer.ContainerCreateConfig.
|
// applySandboxLinuxOptions applies LinuxPodSandboxConfig to dockercontainer.HostConfig and dockercontainer.ContainerCreateConfig.
|
||||||
func (ds *dockerService) applySandboxLinuxOptions(hc *dockercontainer.HostConfig, lc *runtimeapi.LinuxPodSandboxConfig, createConfig *dockertypes.ContainerCreateConfig, image string) error {
|
func (ds *dockerService) applySandboxLinuxOptions(hc *dockercontainer.HostConfig, lc *runtimeapi.LinuxPodSandboxConfig, createConfig *dockertypes.ContainerCreateConfig, image string, separator rune) error {
|
||||||
// Apply Cgroup options.
|
// Apply Cgroup options.
|
||||||
cgroupParent, err := ds.GenerateExpectedCgroupParent(lc.CgroupParent)
|
cgroupParent, err := ds.GenerateExpectedCgroupParent(lc.CgroupParent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -386,7 +386,7 @@ func (ds *dockerService) applySandboxLinuxOptions(hc *dockercontainer.HostConfig
|
|||||||
}
|
}
|
||||||
hc.CgroupParent = cgroupParent
|
hc.CgroupParent = cgroupParent
|
||||||
// Apply security context.
|
// Apply security context.
|
||||||
applySandboxSecurityContext(lc, createConfig.Config, hc, ds.networkPlugin)
|
applySandboxSecurityContext(lc, createConfig.Config, hc, ds.networkPlugin, separator)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -401,6 +401,12 @@ func (ds *dockerService) makeSandboxDockerConfig(c *runtimeapi.PodSandboxConfig,
|
|||||||
// TODO(random-liu): Deprecate this label once container metrics is directly got from CRI.
|
// TODO(random-liu): Deprecate this label once container metrics is directly got from CRI.
|
||||||
labels[types.KubernetesContainerNameLabel] = sandboxContainerName
|
labels[types.KubernetesContainerNameLabel] = sandboxContainerName
|
||||||
|
|
||||||
|
apiVersion, err := ds.getDockerAPIVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to get the docker API version: %v", err)
|
||||||
|
}
|
||||||
|
securityOptSep := getSecurityOptSeparator(apiVersion)
|
||||||
|
|
||||||
hc := &dockercontainer.HostConfig{}
|
hc := &dockercontainer.HostConfig{}
|
||||||
createConfig := &dockertypes.ContainerCreateConfig{
|
createConfig := &dockertypes.ContainerCreateConfig{
|
||||||
Name: makeSandboxName(c),
|
Name: makeSandboxName(c),
|
||||||
@ -422,7 +428,7 @@ func (ds *dockerService) makeSandboxDockerConfig(c *runtimeapi.PodSandboxConfig,
|
|||||||
|
|
||||||
// Apply linux-specific options.
|
// Apply linux-specific options.
|
||||||
if lc := c.GetLinux(); lc != nil {
|
if lc := c.GetLinux(); lc != nil {
|
||||||
if err := ds.applySandboxLinuxOptions(hc, lc, createConfig, image); err != nil {
|
if err := ds.applySandboxLinuxOptions(hc, lc, createConfig, image, securityOptSep); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,7 +449,7 @@ func (ds *dockerService) makeSandboxDockerConfig(c *runtimeapi.PodSandboxConfig,
|
|||||||
setSandboxResources(hc)
|
setSandboxResources(hc)
|
||||||
|
|
||||||
// Set security options.
|
// Set security options.
|
||||||
securityOpts, err := getSandboxSecurityOpts(c, ds.seccompProfileRoot)
|
securityOpts, err := getSandboxSecurityOpts(c, ds.seccompProfileRoot, securityOptSep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate sandbox security options for sandbox %q: %v", c.Metadata.Name, err)
|
return nil, fmt.Errorf("failed to generate sandbox security options for sandbox %q: %v", c.Metadata.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,10 @@ package dockershim
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/blang/semver"
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||||
@ -33,6 +36,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubelet/network/cni"
|
"k8s.io/kubernetes/pkg/kubelet/network/cni"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network/kubenet"
|
"k8s.io/kubernetes/pkg/kubelet/network/kubenet"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/util/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -61,6 +65,9 @@ const (
|
|||||||
containerLogPathLabelKey = "io.kubernetes.container.logpath"
|
containerLogPathLabelKey = "io.kubernetes.container.logpath"
|
||||||
sandboxIDLabelKey = "io.kubernetes.sandbox.id"
|
sandboxIDLabelKey = "io.kubernetes.sandbox.id"
|
||||||
|
|
||||||
|
// The expiration time of version cache.
|
||||||
|
versionCacheTTL = 60 * time.Second
|
||||||
|
|
||||||
// TODO: https://github.com/kubernetes/kubernetes/pull/31169 provides experimental
|
// TODO: https://github.com/kubernetes/kubernetes/pull/31169 provides experimental
|
||||||
// defaulting of host user namespace that may be enabled when the docker daemon
|
// defaulting of host user namespace that may be enabled when the docker daemon
|
||||||
// is using remapped UIDs.
|
// is using remapped UIDs.
|
||||||
@ -153,6 +160,12 @@ func NewDockerService(client dockertools.DockerInterface, seccompProfileRoot str
|
|||||||
glog.Infof("Setting cgroupDriver to %s", cgroupDriver)
|
glog.Infof("Setting cgroupDriver to %s", cgroupDriver)
|
||||||
}
|
}
|
||||||
ds.cgroupDriver = cgroupDriver
|
ds.cgroupDriver = cgroupDriver
|
||||||
|
ds.versionCache = cache.NewObjectCache(
|
||||||
|
func() (interface{}, error) {
|
||||||
|
return ds.getDockerVersion()
|
||||||
|
},
|
||||||
|
versionCacheTTL,
|
||||||
|
)
|
||||||
return ds, nil
|
return ds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,25 +193,37 @@ type dockerService struct {
|
|||||||
checkpointHandler CheckpointHandler
|
checkpointHandler CheckpointHandler
|
||||||
// legacyCleanup indicates whether legacy cleanup has finished or not.
|
// legacyCleanup indicates whether legacy cleanup has finished or not.
|
||||||
legacyCleanup legacyCleanupFlag
|
legacyCleanup legacyCleanupFlag
|
||||||
|
// caches the version of the runtime.
|
||||||
|
// To be compatible with multiple docker versions, we need to perform
|
||||||
|
// version checking for some operations. Use this cache to avoid querying
|
||||||
|
// the docker daemon every time we need to do such checks.
|
||||||
|
versionCache *cache.ObjectCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns the runtime name, runtime version and runtime API version
|
// Version returns the runtime name, runtime version and runtime API version
|
||||||
func (ds *dockerService) Version(_ string) (*runtimeapi.VersionResponse, error) {
|
func (ds *dockerService) Version(_ string) (*runtimeapi.VersionResponse, error) {
|
||||||
|
v, err := ds.getDockerVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &runtimeapi.VersionResponse{
|
||||||
|
Version: kubeAPIVersion,
|
||||||
|
RuntimeName: dockerRuntimeName,
|
||||||
|
RuntimeVersion: v.Version,
|
||||||
|
RuntimeApiVersion: v.APIVersion,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dockerVersion gets the version information from docker.
|
||||||
|
func (ds *dockerService) getDockerVersion() (*dockertypes.Version, error) {
|
||||||
v, err := ds.client.Version()
|
v, err := ds.client.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("docker: failed to get docker version: %v", err)
|
return nil, fmt.Errorf("failed to get docker version: %v", err)
|
||||||
}
|
}
|
||||||
runtimeAPIVersion := kubeAPIVersion
|
|
||||||
name := dockerRuntimeName
|
|
||||||
// Docker API version (e.g., 1.23) is not semver compatible. Add a ".0"
|
// Docker API version (e.g., 1.23) is not semver compatible. Add a ".0"
|
||||||
// suffix to remedy this.
|
// suffix to remedy this.
|
||||||
apiVersion := fmt.Sprintf("%s.0", v.APIVersion)
|
v.APIVersion = fmt.Sprintf("%s.0", v.APIVersion)
|
||||||
return &runtimeapi.VersionResponse{
|
return v, nil
|
||||||
Version: runtimeAPIVersion,
|
|
||||||
RuntimeName: name,
|
|
||||||
RuntimeVersion: v.Version,
|
|
||||||
RuntimeApiVersion: apiVersion,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRuntimeConfig updates the runtime config. Currently only handles podCIDR updates.
|
// UpdateRuntimeConfig updates the runtime config. Currently only handles podCIDR updates.
|
||||||
@ -298,3 +323,31 @@ func (ds *dockerService) GenerateExpectedCgroupParent(cgroupParent string) (stri
|
|||||||
glog.V(3).Infof("Setting cgroup parent to: %q", cgroupParent)
|
glog.V(3).Infof("Setting cgroup parent to: %q", cgroupParent)
|
||||||
return cgroupParent, nil
|
return cgroupParent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getDockerAPIVersion gets the semver-compatible docker api version.
|
||||||
|
func (ds *dockerService) getDockerAPIVersion() (*semver.Version, error) {
|
||||||
|
var dv *dockertypes.Version
|
||||||
|
var err error
|
||||||
|
if ds.versionCache != nil {
|
||||||
|
dv, err = ds.getDockerVersionFromCache()
|
||||||
|
} else {
|
||||||
|
dv, err = ds.getDockerVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
apiVersion, err := semver.Parse(dv.APIVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &apiVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *dockerService) getDockerVersionFromCache() (*dockertypes.Version, error) {
|
||||||
|
// We only store on key in the cache.
|
||||||
|
const dummyKey = "version"
|
||||||
|
value, err := ds.versionCache.Get(dummyKey)
|
||||||
|
dv := value.(*dockertypes.Version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dv, nil
|
||||||
|
}
|
||||||
|
@ -21,8 +21,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/blang/semver"
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"k8s.io/client-go/util/clock"
|
"k8s.io/client-go/util/clock"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
@ -30,6 +33,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network/mock_network"
|
"k8s.io/kubernetes/pkg/kubelet/network/mock_network"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/util/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newTestNetworkPlugin returns a mock plugin that implements network.NetworkPlugin
|
// newTestNetworkPlugin returns a mock plugin that implements network.NetworkPlugin
|
||||||
@ -40,11 +44,22 @@ func newTestNetworkPlugin(t *testing.T) *mock_network.MockNetworkPlugin {
|
|||||||
|
|
||||||
func newTestDockerService() (*dockerService, *dockertools.FakeDockerClient, *clock.FakeClock) {
|
func newTestDockerService() (*dockerService, *dockertools.FakeDockerClient, *clock.FakeClock) {
|
||||||
fakeClock := clock.NewFakeClock(time.Time{})
|
fakeClock := clock.NewFakeClock(time.Time{})
|
||||||
c := dockertools.NewFakeDockerClient().WithClock(fakeClock)
|
c := dockertools.NewFakeDockerClient().WithClock(fakeClock).WithVersion("1.11.2", "1.23")
|
||||||
return &dockerService{client: c, os: &containertest.FakeOS{}, networkPlugin: &network.NoopNetworkPlugin{},
|
return &dockerService{client: c, os: &containertest.FakeOS{}, networkPlugin: &network.NoopNetworkPlugin{},
|
||||||
legacyCleanup: legacyCleanupFlag{done: 1}, checkpointHandler: NewTestPersistentCheckpointHandler()}, c, fakeClock
|
legacyCleanup: legacyCleanupFlag{done: 1}, checkpointHandler: NewTestPersistentCheckpointHandler()}, c, fakeClock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newTestDockerServiceWithVersionCache() (*dockerService, *dockertools.FakeDockerClient, *clock.FakeClock) {
|
||||||
|
ds, c, fakeClock := newTestDockerService()
|
||||||
|
ds.versionCache = cache.NewObjectCache(
|
||||||
|
func() (interface{}, error) {
|
||||||
|
return ds.getDockerVersion()
|
||||||
|
},
|
||||||
|
time.Hour*10,
|
||||||
|
)
|
||||||
|
return ds, c, fakeClock
|
||||||
|
}
|
||||||
|
|
||||||
// TestStatus tests the runtime status logic.
|
// TestStatus tests the runtime status logic.
|
||||||
func TestStatus(t *testing.T) {
|
func TestStatus(t *testing.T) {
|
||||||
ds, fDocker, _ := newTestDockerService()
|
ds, fDocker, _ := newTestDockerService()
|
||||||
@ -90,3 +105,26 @@ func TestStatus(t *testing.T) {
|
|||||||
runtimeapi.NetworkReady: false,
|
runtimeapi.NetworkReady: false,
|
||||||
}, status)
|
}, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVersion(t *testing.T) {
|
||||||
|
ds, _, _ := newTestDockerService()
|
||||||
|
|
||||||
|
expectedVersion := &dockertypes.Version{Version: "1.11.2", APIVersion: "1.23.0"}
|
||||||
|
v, err := ds.getDockerVersion()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, expectedVersion, v)
|
||||||
|
|
||||||
|
expectedAPIVersion := &semver.Version{Major: 1, Minor: 23, Patch: 0}
|
||||||
|
apiVersion, err := ds.getDockerAPIVersion()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, expectedAPIVersion, apiVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIVersionWithCache(t *testing.T) {
|
||||||
|
ds, _, _ := newTestDockerServiceWithVersionCache()
|
||||||
|
|
||||||
|
expected := &semver.Version{Major: 1, Minor: 23, Patch: 0}
|
||||||
|
version, err := ds.getDockerAPIVersion()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, version)
|
||||||
|
}
|
||||||
|
@ -22,9 +22,9 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/blang/semver"
|
||||||
dockertypes "github.com/docker/engine-api/types"
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
dockerfilters "github.com/docker/engine-api/types/filters"
|
dockerfilters "github.com/docker/engine-api/types/filters"
|
||||||
dockerapiversion "github.com/docker/engine-api/types/versions"
|
|
||||||
dockernat "github.com/docker/go-connections/nat"
|
dockernat "github.com/docker/go-connections/nat"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
@ -40,26 +40,12 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
conflictRE = regexp.MustCompile(`Conflict. (?:.)+ is already in use by container ([0-9a-z]+)`)
|
conflictRE = regexp.MustCompile(`Conflict. (?:.)+ is already in use by container ([0-9a-z]+)`)
|
||||||
|
|
||||||
|
// Docker changes the security option separator from ':' to '=' in the 1.23
|
||||||
|
// API version.
|
||||||
|
optsSeparatorChangeVersion = semver.MustParse(dockertools.SecurityOptSeparatorChangeVersion)
|
||||||
)
|
)
|
||||||
|
|
||||||
// apiVersion implements kubecontainer.Version interface by implementing
|
|
||||||
// Compare() and String(). It uses the compare function of engine-api to
|
|
||||||
// compare docker apiversions.
|
|
||||||
type apiVersion string
|
|
||||||
|
|
||||||
func (v apiVersion) String() string {
|
|
||||||
return string(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v apiVersion) Compare(other string) (int, error) {
|
|
||||||
if dockerapiversion.LessThan(string(v), other) {
|
|
||||||
return -1, nil
|
|
||||||
} else if dockerapiversion.GreaterThan(string(v), other) {
|
|
||||||
return 1, nil
|
|
||||||
}
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateEnvList converts KeyValue list to a list of strings, in the form of
|
// generateEnvList converts KeyValue list to a list of strings, in the form of
|
||||||
// '<key>=<value>', which can be understood by docker.
|
// '<key>=<value>', which can be understood by docker.
|
||||||
func generateEnvList(envs []*runtimeapi.KeyValue) (result []string) {
|
func generateEnvList(envs []*runtimeapi.KeyValue) (result []string) {
|
||||||
@ -198,7 +184,7 @@ func makePortsAndBindings(pm []*runtimeapi.PortMapping) (map[dockernat.Port]stru
|
|||||||
// getContainerSecurityOpt gets container security options from container and sandbox config, currently from sandbox
|
// getContainerSecurityOpt gets container security options from container and sandbox config, currently from sandbox
|
||||||
// annotations.
|
// annotations.
|
||||||
// It is an experimental feature and may be promoted to official runtime api in the future.
|
// It is an experimental feature and may be promoted to official runtime api in the future.
|
||||||
func getContainerSecurityOpts(containerName string, sandboxConfig *runtimeapi.PodSandboxConfig, seccompProfileRoot string) ([]string, error) {
|
func getContainerSecurityOpts(containerName string, sandboxConfig *runtimeapi.PodSandboxConfig, seccompProfileRoot string, separator rune) ([]string, error) {
|
||||||
appArmorOpts, err := dockertools.GetAppArmorOpts(sandboxConfig.GetAnnotations(), containerName)
|
appArmorOpts, err := dockertools.GetAppArmorOpts(sandboxConfig.GetAnnotations(), containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -208,17 +194,13 @@ func getContainerSecurityOpts(containerName string, sandboxConfig *runtimeapi.Po
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
securityOpts := append(appArmorOpts, seccompOpts...)
|
securityOpts := append(appArmorOpts, seccompOpts...)
|
||||||
var opts []string
|
fmtOpts := dockertools.FmtDockerOpts(securityOpts, separator)
|
||||||
for _, securityOpt := range securityOpts {
|
return fmtOpts, nil
|
||||||
k, v := securityOpt.GetKV()
|
|
||||||
opts = append(opts, fmt.Sprintf("%s=%s", k, v))
|
|
||||||
}
|
|
||||||
return opts, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSandboxSecurityOpts(sandboxConfig *runtimeapi.PodSandboxConfig, seccompProfileRoot string) ([]string, error) {
|
func getSandboxSecurityOpts(sandboxConfig *runtimeapi.PodSandboxConfig, seccompProfileRoot string, separator rune) ([]string, error) {
|
||||||
// sandboxContainerName doesn't exist in the pod, so pod security options will be returned by default.
|
// sandboxContainerName doesn't exist in the pod, so pod security options will be returned by default.
|
||||||
return getContainerSecurityOpts(sandboxContainerName, sandboxConfig, seccompProfileRoot)
|
return getContainerSecurityOpts(sandboxContainerName, sandboxConfig, seccompProfileRoot, separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNetworkNamespace(c *dockertypes.ContainerJSON) string {
|
func getNetworkNamespace(c *dockertypes.ContainerJSON) string {
|
||||||
@ -323,3 +305,18 @@ func recoverFromCreationConflictIfNeeded(client dockertools.DockerInterface, cre
|
|||||||
glog.V(2).Infof("Create the container with randomized name %s", createConfig.Name)
|
glog.V(2).Infof("Create the container with randomized name %s", createConfig.Name)
|
||||||
return client.CreateContainer(createConfig)
|
return client.CreateContainer(createConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getSecurityOptSeparator returns the security option separator based on the
|
||||||
|
// docker API version.
|
||||||
|
// TODO: Remove this function along with the relevant code when we no longer
|
||||||
|
// need to support docker 1.10.
|
||||||
|
func getSecurityOptSeparator(v *semver.Version) rune {
|
||||||
|
switch v.Compare(optsSeparatorChangeVersion) {
|
||||||
|
case -1:
|
||||||
|
// Current version is less than the API change version; use the old
|
||||||
|
// separator.
|
||||||
|
return dockertools.SecurityOptSeparatorOld
|
||||||
|
default:
|
||||||
|
return dockertools.SecurityOptSeparatorNew
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ package dockershim
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/blang/semver"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ func TestGetContainerSecurityOpts(t *testing.T) {
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
opts, err := getContainerSecurityOpts(containerName, test.config, "test/seccomp/profile/root")
|
opts, err := getContainerSecurityOpts(containerName, test.config, "test/seccomp/profile/root", '=')
|
||||||
assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
|
assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
|
||||||
assert.Len(t, opts, len(test.expectedOpts), "TestCase[%d]: %s", i, test.msg)
|
assert.Len(t, opts, len(test.expectedOpts), "TestCase[%d]: %s", i, test.msg)
|
||||||
for _, opt := range test.expectedOpts {
|
for _, opt := range test.expectedOpts {
|
||||||
@ -140,7 +141,7 @@ func TestGetSandboxSecurityOpts(t *testing.T) {
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
opts, err := getSandboxSecurityOpts(test.config, "test/seccomp/profile/root")
|
opts, err := getSandboxSecurityOpts(test.config, "test/seccomp/profile/root", '=')
|
||||||
assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
|
assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
|
||||||
assert.Len(t, opts, len(test.expectedOpts), "TestCase[%d]: %s", i, test.msg)
|
assert.Len(t, opts, len(test.expectedOpts), "TestCase[%d]: %s", i, test.msg)
|
||||||
for _, opt := range test.expectedOpts {
|
for _, opt := range test.expectedOpts {
|
||||||
@ -236,3 +237,27 @@ func TestParsingCreationConflictError(t *testing.T) {
|
|||||||
require.Len(t, matches, 2)
|
require.Len(t, matches, 2)
|
||||||
require.Equal(t, matches[1], "24666ab8c814d16f986449e504ea0159468ddf8da01897144a770f66dce0e14e")
|
require.Equal(t, matches[1], "24666ab8c814d16f986449e504ea0159468ddf8da01897144a770f66dce0e14e")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetSecurityOptSeparator(t *testing.T) {
|
||||||
|
for c, test := range map[string]struct {
|
||||||
|
desc string
|
||||||
|
version *semver.Version
|
||||||
|
expected rune
|
||||||
|
}{
|
||||||
|
"older docker version": {
|
||||||
|
version: &semver.Version{Major: 1, Minor: 22, Patch: 0},
|
||||||
|
expected: ':',
|
||||||
|
},
|
||||||
|
"changed docker version": {
|
||||||
|
version: &semver.Version{Major: 1, Minor: 23, Patch: 0},
|
||||||
|
expected: '=',
|
||||||
|
},
|
||||||
|
"newer docker version": {
|
||||||
|
version: &semver.Version{Major: 1, Minor: 24, Patch: 0},
|
||||||
|
expected: '=',
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
actual := getSecurityOptSeparator(test.version)
|
||||||
|
assert.Equal(t, test.expected, actual, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,13 +24,12 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools/securitycontext"
|
"k8s.io/kubernetes/pkg/kubelet/dockertools/securitycontext"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
// applySandboxSecurityContext updates docker sandbox options according to security context.
|
// applySandboxSecurityContext updates docker sandbox options according to security context.
|
||||||
func applySandboxSecurityContext(lc *runtimeapi.LinuxPodSandboxConfig, config *dockercontainer.Config, hc *dockercontainer.HostConfig, networkPlugin network.NetworkPlugin) {
|
func applySandboxSecurityContext(lc *runtimeapi.LinuxPodSandboxConfig, config *dockercontainer.Config, hc *dockercontainer.HostConfig, networkPlugin network.NetworkPlugin, separator rune) {
|
||||||
if lc == nil {
|
if lc == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -47,19 +46,19 @@ func applySandboxSecurityContext(lc *runtimeapi.LinuxPodSandboxConfig, config *d
|
|||||||
}
|
}
|
||||||
|
|
||||||
modifyContainerConfig(sc, config)
|
modifyContainerConfig(sc, config)
|
||||||
modifyHostConfig(sc, hc)
|
modifyHostConfig(sc, hc, separator)
|
||||||
modifySandboxNamespaceOptions(sc.GetNamespaceOptions(), hc, networkPlugin)
|
modifySandboxNamespaceOptions(sc.GetNamespaceOptions(), hc, networkPlugin)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyContainerSecurityContext updates docker container options according to security context.
|
// applyContainerSecurityContext updates docker container options according to security context.
|
||||||
func applyContainerSecurityContext(lc *runtimeapi.LinuxContainerConfig, sandboxID string, config *dockercontainer.Config, hc *dockercontainer.HostConfig) {
|
func applyContainerSecurityContext(lc *runtimeapi.LinuxContainerConfig, sandboxID string, config *dockercontainer.Config, hc *dockercontainer.HostConfig, separator rune) {
|
||||||
if lc == nil {
|
if lc == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
modifyContainerConfig(lc.SecurityContext, config)
|
modifyContainerConfig(lc.SecurityContext, config)
|
||||||
modifyHostConfig(lc.SecurityContext, hc)
|
modifyHostConfig(lc.SecurityContext, hc, separator)
|
||||||
modifyContainerNamespaceOptions(lc.SecurityContext.GetNamespaceOptions(), sandboxID, hc)
|
modifyContainerNamespaceOptions(lc.SecurityContext.GetNamespaceOptions(), sandboxID, hc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -78,7 +77,7 @@ func modifyContainerConfig(sc *runtimeapi.LinuxContainerSecurityContext, config
|
|||||||
}
|
}
|
||||||
|
|
||||||
// modifyHostConfig applies security context config to dockercontainer.HostConfig.
|
// modifyHostConfig applies security context config to dockercontainer.HostConfig.
|
||||||
func modifyHostConfig(sc *runtimeapi.LinuxContainerSecurityContext, hostConfig *dockercontainer.HostConfig) {
|
func modifyHostConfig(sc *runtimeapi.LinuxContainerSecurityContext, hostConfig *dockercontainer.HostConfig, separator rune) {
|
||||||
if sc == nil {
|
if sc == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -104,7 +103,7 @@ func modifyHostConfig(sc *runtimeapi.LinuxContainerSecurityContext, hostConfig *
|
|||||||
Type: sc.SelinuxOptions.Type,
|
Type: sc.SelinuxOptions.Type,
|
||||||
Level: sc.SelinuxOptions.Level,
|
Level: sc.SelinuxOptions.Level,
|
||||||
},
|
},
|
||||||
dockertools.SecurityOptSeparatorNew,
|
separator,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ func TestModifyHostConfig(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
dockerCfg := &dockercontainer.HostConfig{}
|
dockerCfg := &dockercontainer.HostConfig{}
|
||||||
modifyHostConfig(tc.sc, dockerCfg)
|
modifyHostConfig(tc.sc, dockerCfg, '=')
|
||||||
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
|
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +157,7 @@ func TestModifyHostConfigWithGroups(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
dockerCfg := &dockercontainer.HostConfig{}
|
dockerCfg := &dockercontainer.HostConfig{}
|
||||||
modifyHostConfig(tc.securityContext, dockerCfg)
|
modifyHostConfig(tc.securityContext, dockerCfg, '=')
|
||||||
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
|
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ func TestModifyHostConfigAndNamespaceOptionsForContainer(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
dockerCfg := &dockercontainer.HostConfig{}
|
dockerCfg := &dockercontainer.HostConfig{}
|
||||||
modifyHostConfig(tc.sc, dockerCfg)
|
modifyHostConfig(tc.sc, dockerCfg, '=')
|
||||||
modifyContainerNamespaceOptions(tc.sc.GetNamespaceOptions(), sandboxID, dockerCfg)
|
modifyContainerNamespaceOptions(tc.sc.GetNamespaceOptions(), sandboxID, dockerCfg)
|
||||||
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
|
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ const (
|
|||||||
versionCacheTTL = 60 * time.Second
|
versionCacheTTL = 60 * time.Second
|
||||||
|
|
||||||
// Docker changed the API for specifying options in v1.11
|
// Docker changed the API for specifying options in v1.11
|
||||||
SecurityOptSeparatorChangeVersion = "1.23" // Corresponds to docker 1.11.x
|
SecurityOptSeparatorChangeVersion = "1.23.0" // Corresponds to docker 1.11.x
|
||||||
SecurityOptSeparatorOld = ':'
|
SecurityOptSeparatorOld = ':'
|
||||||
SecurityOptSeparatorNew = '='
|
SecurityOptSeparatorNew = '='
|
||||||
)
|
)
|
||||||
|
@ -569,7 +569,8 @@ func (f *FakeDockerClient) PullImage(image string, auth dockertypes.AuthConfig,
|
|||||||
func (f *FakeDockerClient) Version() (*dockertypes.Version, error) {
|
func (f *FakeDockerClient) Version() (*dockertypes.Version, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
return &f.VersionInfo, f.popError("version")
|
v := f.VersionInfo
|
||||||
|
return &v, f.popError("version")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeDockerClient) Info() (*dockertypes.Info, error) {
|
func (f *FakeDockerClient) Info() (*dockertypes.Info, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user