Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions internal/guest/runtime/hcsv2/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
package hcsv2

import (
"context"
"fmt"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/opencontainers/runc/libcontainer/devices"
"path/filepath"
"strconv"
"strings"
Expand Down Expand Up @@ -42,6 +45,18 @@ func isInMounts(target string, mounts []oci.Mount) bool {
return false
}

// removeMount removes mount from the array if `target` matches `Destination`
func removeMount(target string, mounts []oci.Mount) []oci.Mount {
var result []oci.Mount
for _, m := range mounts {
if m.Destination == target {
continue
}
result = append(result, m)
}
return result
}

func setProcess(spec *oci.Spec) {
if spec.Process == nil {
spec.Process = &oci.Process{}
Expand Down Expand Up @@ -152,3 +167,69 @@ func getGroup(spec *oci.Spec, filter func(user.Group) bool) (user.Group, error)
}
return groups[0], nil
}

// applyAnnotationsToSpec modifies the spec based on additional information from annotations
func applyAnnotationsToSpec(ctx context.Context, spec *oci.Spec) error {
// Check if we need to override container's /dev/shm
if val, ok := spec.Annotations["io.microsoft.container.storage.shm.size-kb"]; ok {
sz, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return errors.Wrap(err, "/dev/shm size must be a valid integer")
}
if sz <= 0 {
return errors.Errorf("/dev/shm size must be a positive integer, got: %d", sz)
}

// Use the same options as in upstream https://github.com/containerd/containerd/blob/0def98e462706286e6eaeff4a90be22fda75e761/oci/mounts.go#L49
size := fmt.Sprintf("size=%dk", sz)
mt := oci.Mount{
Destination: "/dev/shm",
Type: "tmpfs",
Source: "shm",
Options: []string{"nosuid", "noexec", "nodev", "mode=1777", size},
Comment thread
anmaxvl marked this conversation as resolved.
}
spec.Mounts = removeMount("/dev/shm", spec.Mounts)
spec.Mounts = append(spec.Mounts, mt)
log.G(ctx).WithField("size", size).Debug("set custom /dev/shm size")
}

// Check if we need to do any capability/device mappings
if spec.Annotations["io.microsoft.virtualmachine.lcow.privileged"] == "true" {
log.G(ctx).Debug("'io.microsoft.virtualmachine.lcow.privileged' set for privileged container")

// Add all host devices
hostDevices, err := devices.HostDevices()
if err != nil {
return err
}
for _, hostDevice := range hostDevices {
addLinuxDeviceToSpec(ctx, hostDevice, spec, false)
Comment thread
katiewasnothere marked this conversation as resolved.
}

// Set the cgroup access
spec.Linux.Resources.Devices = []oci.LinuxDeviceCgroup{
{
Allow: true,
Access: "rwm",
},
}
} else {
tempLinuxDevices := spec.Linux.Devices
spec.Linux.Devices = []oci.LinuxDevice{}
for _, ld := range tempLinuxDevices {
hostDevice, err := devices.DeviceFromPath(ld.Path, "rwm")
if err != nil {
return err
}
addLinuxDeviceToSpec(ctx, hostDevice, spec, true)
}
}

// Check if we need to set non-default user
if userstr, ok := spec.Annotations["io.microsoft.lcow.userstr"]; ok {
if err := setUserStr(spec, userstr); err != nil {
return err
}
}
return nil
}
39 changes: 2 additions & 37 deletions internal/guest/runtime/hcsv2/workload_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/devices"
oci "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"go.opencensus.io/trace"
Expand Down Expand Up @@ -119,42 +118,8 @@ func setupWorkloadContainerSpec(ctx context.Context, sbid, id string, spec *oci.
// also has a concept of a sandbox/shm file when the IPC NamespaceMode !=
// NODE.

// Check if we need to do any capability/device mappings
if spec.Annotations["io.microsoft.virtualmachine.lcow.privileged"] == "true" {
log.G(ctx).Debug("'io.microsoft.virtualmachine.lcow.privileged' set for privileged container")

// Add all host devices
hostDevices, err := devices.HostDevices()
if err != nil {
return err
}
for _, hostDevice := range hostDevices {
addLinuxDeviceToSpec(ctx, hostDevice, spec, false)
}

// Set the cgroup access
spec.Linux.Resources.Devices = []oci.LinuxDeviceCgroup{
{
Allow: true,
Access: "rwm",
},
}
} else {
tempLinuxDevices := spec.Linux.Devices
spec.Linux.Devices = []oci.LinuxDevice{}
for _, ld := range tempLinuxDevices {
hostDevice, err := devices.DeviceFromPath(ld.Path, "rwm")
if err != nil {
return err
}
addLinuxDeviceToSpec(ctx, hostDevice, spec, true)
}
}

if userstr, ok := spec.Annotations["io.microsoft.lcow.userstr"]; ok {
if err := setUserStr(spec, userstr); err != nil {
return err
}
if err := applyAnnotationsToSpec(ctx, spec); err != nil {
return err
}

// Force the parent cgroup into our /containers root
Expand Down
51 changes: 51 additions & 0 deletions test/cri-containerd/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -775,3 +775,54 @@ func Test_RunContainer_ShareScratch_CheckSize_LCOW(t *testing.T) {
t.Fatalf("expected available rootfs size to be the same, got: %s and %s", availableSizeContainerOne, availableSizeContainerTwo)
}
}

func Test_CreateContainer_DevShmSize(t *testing.T) {
requireFeatures(t, featureLCOW)

pullRequiredLcowImages(t, []string{imageLcowK8sPause, imageLcowAlpine})

client := newTestRuntimeClient(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

podReq := getRunPodSandboxRequest(t, lcowRuntimeHandler, nil)
podID := runPodSandbox(t, client, ctx, podReq)
defer removePodSandbox(t, client, ctx, podID)

cmd := []string{"ash", "-c", "while true; do sleep 1; done"}
contReq1 := getCreateContainerRequest(podID, "test-container-devshm-256", imageLcowAlpine, cmd, podReq.Config)
// the /dev/shm size is expected to be in KB, set it to 256 MB
size := 256 * 1024
contReq1.Config.Annotations = map[string]string{
"io.microsoft.container.storage.shm.size-kb": strconv.Itoa(size),
}
containerID1 := createContainer(t, client, ctx, contReq1)
defer removeContainer(t, client, ctx, containerID1)

startContainer(t, client, ctx, containerID1)
defer stopContainer(t, client, ctx, containerID1)

contReq2 := getCreateContainerRequest(podID, "test-container-devshm-default", imageLcowAlpine, cmd, podReq.Config)
containerID2 := createContainer(t, client, ctx, contReq2)
defer removeContainer(t, client, ctx, containerID2)
startContainer(t, client, ctx, containerID2)
defer stopContainer(t, client, ctx, containerID2)

// check /dev/shm size on container 1, should be set to 256 MB
execResponse1 := execSync(t, client, ctx, &runtime.ExecSyncRequest{
ContainerId: containerID1,
Cmd: []string{"df", "-h", "/dev/shm"},
})
if !strings.Contains(string(execResponse1.Stdout), "256.0M") {
t.Fatalf("expected the size of /dev/shm to be 256MB. Got output instead: %s", string(execResponse1.Stdout))
}

// check /dev/shm size on container 2, should be set to default 64 MB
execResponse2 := execSync(t, client, ctx, &runtime.ExecSyncRequest{
ContainerId: containerID2,
Cmd: []string{"df", "-h", "/dev/shm"},
})
if !strings.Contains(string(execResponse2.Stdout), "64.0M") {
t.Fatalf("expected the size of /dev/shm to be 64MB. Got output instead: %s", string(execResponse1.Stdout))
}
}