diff --git a/pkg/apis/container.go b/pkg/apis/container.go index 520a236c5d..b0e929a0d0 100644 --- a/pkg/apis/container.go +++ b/pkg/apis/container.go @@ -63,6 +63,7 @@ type ContainerSpec struct { Lifecyle *ContainerLifecyle `json:"lifecyle"` CgroupDevicesAllow []string `json:"cgroup_devices_allow"` SimulateCpu bool `json:"simulate_cpu"` + ShmSizeMB int `json:"shm_size_mb"` } type ContainerCapability struct { diff --git a/pkg/compute/guestdrivers/pod.go b/pkg/compute/guestdrivers/pod.go index af548c4e2a..889925f1f8 100644 --- a/pkg/compute/guestdrivers/pod.go +++ b/pkg/compute/guestdrivers/pod.go @@ -443,6 +443,10 @@ func (p *SPodDriver) RequestStartContainer(ctx context.Context, userCred mcclien } func (p *SPodDriver) RequestStopContainer(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error { + ctr := task.GetContainer() + params := task.GetParams() + params.Add(jsonutils.NewString(ctr.GetName()), "container_name") + params.Add(jsonutils.NewInt(int64(ctr.Spec.ShmSizeMB)), "shm_size_mb") return p.performContainerAction(ctx, userCred, task, "stop", task.GetParams()) } diff --git a/pkg/compute/models/containers.go b/pkg/compute/models/containers.go index b85884f11f..fd064a6075 100644 --- a/pkg/compute/models/containers.go +++ b/pkg/compute/models/containers.go @@ -160,6 +160,10 @@ func (m *SContainerManager) ValidateSpec(ctx context.Context, userCred mcclient. return errors.Wrap(err, "validate lifecycle") } + if spec.ShmSizeMB < 64 { + return httperrors.NewInputParameterError("/dev/shm size is small than 64MB") + } + return nil } diff --git a/pkg/hostman/guestman/pod.go b/pkg/hostman/guestman/pod.go index cab72cdc2b..c2cb76a9ba 100644 --- a/pkg/hostman/guestman/pod.go +++ b/pkg/hostman/guestman/pod.go @@ -267,6 +267,14 @@ func (s *sPodGuestInstance) getPodLogDir() string { return filepath.Join(s.HomeDir(), "logs") } +func (s *sPodGuestInstance) getShmDir() string { + return filepath.Join(s.HomeDir(), "shm") +} + +func (s *sPodGuestInstance) getContainerShmDir(containerName string) string { + return filepath.Join(s.getShmDir(), fmt.Sprintf("%s-shm", containerName)) +} + func (s *sPodGuestInstance) GetDisks() []*desc.SGuestDisk { return s.GetDesc().Disks } @@ -701,6 +709,18 @@ func (s *sPodGuestInstance) StopContainer(ctx context.Context, userCred mcclient if body.Contains("timeout") { timeout, _ = body.Int("timeout") } + if body.Contains("shm_size_mb") { + shmSizeMB, _ := body.Int("shm_size_mb") + if shmSizeMB > 64 { + name, err := body.GetString("container_name") + if err != nil { + return nil, errors.Wrapf(err, "not found name from body: %s", body) + } + if err := s.unmountDevShm(name); err != nil { + return nil, errors.Wrapf(err, "unmount shm %s", name) + } + } + } if err := s.getCRI().StopContainer(ctx, criId, timeout); err != nil { return nil, errors.Wrap(err, "CRI.StopContainer") } @@ -923,6 +943,19 @@ func (s *sPodGuestInstance) createContainer(ctx context.Context, userCred mcclie mounts = newMounts } + // process shm size + if spec.ShmSizeMB > 64 { + // mount empty dir + shmPath, err := s.mountDevShm(input, spec.ShmSizeMB) + if err != nil { + return "", errors.Wrapf(err, "mount dev shm") + } + mounts = append(mounts, &runtimeapi.Mount{ + ContainerPath: "/dev/shm", + HostPath: shmPath, + }) + } + ctrCfg := &runtimeapi.ContainerConfig{ Metadata: &runtimeapi.ContainerMetadata{ Name: input.Name, @@ -1301,3 +1334,34 @@ func (s *sPodGuestInstance) ExecContainer(ctx context.Context, userCred mcclient } return url.Parse(resp.Url) } + +func (s *sPodGuestInstance) mountDevShm(input *hostapi.ContainerCreateInput, mb int) (string, error) { + shmPath := s.getContainerShmDir(input.Name) + if !fileutils2.Exists(shmPath) { + out, err := procutils.NewRemoteCommandAsFarAsPossible("mkdir", "-p", shmPath).Output() + if err != nil { + return "", errors.Wrapf(err, "mkdir -p %s: %s", shmPath, out) + } + } + if err := procutils.NewRemoteCommandAsFarAsPossible("mountpoint", shmPath).Run(); err == nil { + log.Warningf("mountpoint %s is already mounted", shmPath) + return "", nil + } + out, err := procutils.NewRemoteCommandAsFarAsPossible("mount", "-t", "tmpfs", "-o", fmt.Sprintf("size=%dM", mb), "tmpfs", shmPath).Output() + if err != nil { + return "", errors.Wrapf(err, "mount tmpfs %s: %s", shmPath, out) + } + return shmPath, nil +} + +func (s *sPodGuestInstance) unmountDevShm(containerName string) error { + shmPath := s.getContainerShmDir(containerName) + if err := procutils.NewRemoteCommandAsFarAsPossible("mountpoint", shmPath).Run(); err != nil { + return nil + } + out, err := procutils.NewRemoteCommandAsFarAsPossible("umount", shmPath).Output() + if err != nil { + return errors.Wrapf(err, "mount tmpfs %s: %s", shmPath, out) + } + return nil +} diff --git a/pkg/mcclient/options/compute/containers.go b/pkg/mcclient/options/compute/containers.go index 1e0c03e6df..0a859f9e17 100644 --- a/pkg/mcclient/options/compute/containers.go +++ b/pkg/mcclient/options/compute/containers.go @@ -58,6 +58,7 @@ type ContainerCreateCommonOptions struct { PostStartExec string `help:"Post started execution command"` CgroupDeviceAllow []string `help:"Cgroup devices.allow, e.g.: 'c 13:* rwm'"` SimulateCpu bool `help:"Simulating /sys/devices/system/cpu files"` + ShmSizeMb int `help:"Shm size MB"` } func (o ContainerCreateCommonOptions) getCreateSpec() (*computeapi.ContainerSpec, error) { @@ -74,6 +75,9 @@ func (o ContainerCreateCommonOptions) getCreateSpec() (*computeapi.ContainerSpec SimulateCpu: o.SimulateCpu, }, } + if o.ShmSizeMb > 0 { + req.ContainerSpec.ShmSizeMB = o.ShmSizeMb + } if len(o.PostStartExec) != 0 { req.Lifecyle = &apis.ContainerLifecyle{ PostStart: &apis.ContainerLifecyleHandler{