mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
CRI: Add devices implementation and moves GPU to devices
This commit is contained in:
parent
c53fee7725
commit
e0f89a322b
@ -162,13 +162,23 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
|
||||
CPUShares: rOpts.GetCpuShares(),
|
||||
CPUQuota: rOpts.GetCpuQuota(),
|
||||
CPUPeriod: rOpts.GetCpuPeriod(),
|
||||
// TODO: Need to set devices.
|
||||
}
|
||||
hc.OomScoreAdj = int(rOpts.GetOomScoreAdj())
|
||||
}
|
||||
// Note: ShmSize is handled in kube_docker_client.go
|
||||
}
|
||||
|
||||
// Set devices for container.
|
||||
devices := make([]dockercontainer.DeviceMapping, len(config.Devices))
|
||||
for i, device := range config.Devices {
|
||||
devices[i] = dockercontainer.DeviceMapping{
|
||||
PathOnHost: device.GetHostPath(),
|
||||
PathInContainer: device.GetContainerPath(),
|
||||
CgroupPermissions: device.GetPermissions(),
|
||||
}
|
||||
}
|
||||
hc.Resources.Devices = devices
|
||||
|
||||
var err error
|
||||
hc.SecurityOpt, err = getContainerSecurityOpts(config.Metadata.GetName(), sandboxConfig, ds.seccompProfileRoot)
|
||||
if err != nil {
|
||||
|
@ -619,7 +619,6 @@ func (dm *DockerManager) runContainer(
|
||||
memoryLimit := container.Resources.Limits.Memory().Value()
|
||||
cpuRequest := container.Resources.Requests.Cpu()
|
||||
cpuLimit := container.Resources.Limits.Cpu()
|
||||
nvidiaGPULimit := container.Resources.Limits.NvidiaGPU()
|
||||
var cpuShares int64
|
||||
// If request is not specified, but limit is, we want request to default to limit.
|
||||
// API server does this for new containers, but we repeat this logic in Kubelet
|
||||
@ -631,17 +630,18 @@ func (dm *DockerManager) runContainer(
|
||||
// of CPU shares.
|
||||
cpuShares = milliCPUToShares(cpuRequest.MilliValue())
|
||||
}
|
||||
var devices []dockercontainer.DeviceMapping
|
||||
if nvidiaGPULimit.Value() != 0 {
|
||||
// Experimental. For now, we hardcode /dev/nvidia0 no matter what the user asks for
|
||||
// (we only support one device per node).
|
||||
devices = []dockercontainer.DeviceMapping{
|
||||
{PathOnHost: "/dev/nvidia0", PathInContainer: "/dev/nvidia0", CgroupPermissions: "mrw"},
|
||||
{PathOnHost: "/dev/nvidiactl", PathInContainer: "/dev/nvidiactl", CgroupPermissions: "mrw"},
|
||||
{PathOnHost: "/dev/nvidia-uvm", PathInContainer: "/dev/nvidia-uvm", CgroupPermissions: "mrw"},
|
||||
|
||||
// Set devices for container.
|
||||
devices := make([]dockercontainer.DeviceMapping, len(opts.Devices))
|
||||
for i, device := range opts.Devices {
|
||||
devices[i] = dockercontainer.DeviceMapping{
|
||||
PathOnHost: device.PathOnHost,
|
||||
PathInContainer: device.PathInContainer,
|
||||
CgroupPermissions: device.Permissions,
|
||||
}
|
||||
}
|
||||
binds := makeMountBindings(opts.Mounts)
|
||||
|
||||
// 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.
|
||||
|
@ -74,6 +74,23 @@ func (kl *Kubelet) getActivePods() []*api.Pod {
|
||||
return activePods
|
||||
}
|
||||
|
||||
// makeDevices determines the devices for the given container.
|
||||
// Experimental. For now, we hardcode /dev/nvidia0 no matter what the user asks for
|
||||
// (we only support one device per node).
|
||||
// TODO: add support for more than 1 GPU after #28216.
|
||||
func makeDevices(container *api.Container) []kubecontainer.DeviceInfo {
|
||||
nvidiaGPULimit := container.Resources.Limits.NvidiaGPU()
|
||||
if nvidiaGPULimit.Value() != 0 {
|
||||
return []kubecontainer.DeviceInfo{
|
||||
{PathOnHost: "/dev/nvidia0", PathInContainer: "/dev/nvidia0", Permissions: "mrw"},
|
||||
{PathOnHost: "/dev/nvidiactl", PathInContainer: "/dev/nvidiactl", Permissions: "mrw"},
|
||||
{PathOnHost: "/dev/nvidia-uvm", PathInContainer: "/dev/nvidia-uvm", Permissions: "mrw"},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeMounts determines the mount points for the given container.
|
||||
func makeMounts(pod *api.Pod, podDir string, container *api.Container, hostName, hostDomain, podIP string, podVolumes kubecontainer.VolumeMap) ([]kubecontainer.Mount, error) {
|
||||
// Kubernetes only mounts on /etc/hosts if :
|
||||
@ -252,6 +269,7 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *api.Pod, container *api.Cont
|
||||
volumes := kl.volumeManager.GetMountedVolumesForPod(podName)
|
||||
|
||||
opts.PortMappings = makePortMappings(container)
|
||||
opts.Devices = makeDevices(container)
|
||||
|
||||
opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes)
|
||||
if err != nil {
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||
@ -1262,3 +1263,36 @@ func TestGetHostPortConflicts(t *testing.T) {
|
||||
pods = append(pods, expected)
|
||||
assert.True(t, hasHostPortConflicts(pods), "Should have port conflicts")
|
||||
}
|
||||
|
||||
func TestMakeDevices(t *testing.T) {
|
||||
testCases := []struct {
|
||||
container *api.Container
|
||||
devices []kubecontainer.DeviceInfo
|
||||
test string
|
||||
}{
|
||||
{
|
||||
test: "no device",
|
||||
container: &api.Container{},
|
||||
devices: nil,
|
||||
},
|
||||
{
|
||||
test: "gpu",
|
||||
container: &api.Container{
|
||||
Resources: api.ResourceRequirements{
|
||||
Limits: map[api.ResourceName]resource.Quantity{
|
||||
api.ResourceNvidiaGPU: resource.MustParse("1000"),
|
||||
},
|
||||
},
|
||||
},
|
||||
devices: []kubecontainer.DeviceInfo{
|
||||
{PathOnHost: "/dev/nvidia0", PathInContainer: "/dev/nvidia0", Permissions: "mrw"},
|
||||
{PathOnHost: "/dev/nvidiactl", PathInContainer: "/dev/nvidiactl", Permissions: "mrw"},
|
||||
{PathOnHost: "/dev/nvidia-uvm", PathInContainer: "/dev/nvidia-uvm", Permissions: "mrw"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
assert.Equal(t, test.devices, makeDevices(test.container), "[test %q]", test.test)
|
||||
}
|
||||
}
|
||||
|
@ -151,6 +151,7 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *api.Conta
|
||||
Labels: newContainerLabels(container, pod),
|
||||
Annotations: newContainerAnnotations(container, pod, restartCount),
|
||||
Mounts: m.makeMounts(opts, container, podHasSELinuxLabel),
|
||||
Devices: makeDevices(opts),
|
||||
LogPath: &containerLogsPath,
|
||||
Stdin: &container.Stdin,
|
||||
StdinOnce: &container.StdinOnce,
|
||||
@ -251,6 +252,22 @@ func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *api.
|
||||
return linuxConfig
|
||||
}
|
||||
|
||||
// makeDevices generates container devices for kubelet runtime api.
|
||||
func makeDevices(opts *kubecontainer.RunContainerOptions) []*runtimeApi.Device {
|
||||
devices := make([]*runtimeApi.Device, len(opts.Devices))
|
||||
|
||||
for idx := range opts.Devices {
|
||||
device := opts.Devices[idx]
|
||||
devices[idx] = &runtimeApi.Device{
|
||||
HostPath: &device.PathOnHost,
|
||||
ContainerPath: &device.PathInContainer,
|
||||
Permissions: &device.Permissions,
|
||||
}
|
||||
}
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
// makeMounts generates container volume mounts for kubelet runtime api.
|
||||
func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerOptions, container *api.Container, podHasSELinuxLabel bool) []*runtimeApi.Mount {
|
||||
volumeMounts := []*runtimeApi.Mount{}
|
||||
|
Loading…
Reference in New Issue
Block a user