Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Commit 9f55ee0

Browse files
committed
Add sandbox /dev/shm.
Signed-off-by: Lantao Liu <[email protected]>
1 parent 5a17f6f commit 9f55ee0

File tree

5 files changed

+157
-31
lines changed

5 files changed

+157
-31
lines changed

pkg/server/container_start.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,16 @@ func (c *criContainerdService) generateContainerMounts(sandboxRootDir string, co
309309
HostPath: getSandboxHosts(sandboxRootDir),
310310
Readonly: securityContext.ReadonlyRootfs,
311311
})
312+
sandboxDevShm := getSandboxDevShm(sandboxRootDir)
313+
if securityContext.GetNamespaceOptions().GetHostIpc() {
314+
sandboxDevShm = devShm
315+
}
316+
mounts = append(mounts, &runtime.Mount{
317+
ContainerPath: devShm,
318+
HostPath: sandboxDevShm,
319+
Readonly: false,
320+
})
312321
// TODO(random-liu): [P0] Mount sandbox resolv.config.
313-
// TODO(random-liu): [P0] Mount sandbox /dev/shm.
314322
return mounts
315323
}
316324

@@ -349,6 +357,8 @@ func addImageEnvs(g *generate.Generator, imageEnvs []string) error {
349357
}
350358

351359
// addOCIBindMounts adds bind mounts.
360+
// TODO(random-liu): Figure out whether we need to change all CRI mounts to readonly when
361+
// rootfs is readonly. (https://github.com/moby/moby/blob/master/daemon/oci_linux.go)
352362
func addOCIBindMounts(g *generate.Generator, mounts []*runtime.Mount) {
353363
for _, mount := range mounts {
354364
dst := mount.GetContainerPath()

pkg/server/container_start_test.go

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -313,19 +313,50 @@ func TestGenerateContainerMounts(t *testing.T) {
313313
securityContext: &runtime.LinuxContainerSecurityContext{
314314
ReadonlyRootfs: true,
315315
},
316-
expectedMounts: []*runtime.Mount{{
317-
ContainerPath: "/etc/hosts",
318-
HostPath: testSandboxRootDir + "/hosts",
319-
Readonly: true,
320-
}},
316+
expectedMounts: []*runtime.Mount{
317+
{
318+
ContainerPath: "/etc/hosts",
319+
HostPath: testSandboxRootDir + "/hosts",
320+
Readonly: true,
321+
},
322+
{
323+
ContainerPath: "/dev/shm",
324+
HostPath: testSandboxRootDir + "/shm",
325+
Readonly: false,
326+
},
327+
},
321328
},
322329
"should setup rw /etc/hosts mount when rootfs is read-write": {
323330
securityContext: &runtime.LinuxContainerSecurityContext{},
324-
expectedMounts: []*runtime.Mount{{
325-
ContainerPath: "/etc/hosts",
326-
HostPath: testSandboxRootDir + "/hosts",
327-
Readonly: false,
328-
}},
331+
expectedMounts: []*runtime.Mount{
332+
{
333+
ContainerPath: "/etc/hosts",
334+
HostPath: testSandboxRootDir + "/hosts",
335+
Readonly: false,
336+
},
337+
{
338+
ContainerPath: "/dev/shm",
339+
HostPath: testSandboxRootDir + "/shm",
340+
Readonly: false,
341+
},
342+
},
343+
},
344+
"should use host /dev/shm when host ipc is set": {
345+
securityContext: &runtime.LinuxContainerSecurityContext{
346+
NamespaceOptions: &runtime.NamespaceOption{HostIpc: true},
347+
},
348+
expectedMounts: []*runtime.Mount{
349+
{
350+
ContainerPath: "/etc/hosts",
351+
HostPath: testSandboxRootDir + "/hosts",
352+
Readonly: false,
353+
},
354+
{
355+
ContainerPath: "/dev/shm",
356+
HostPath: "/dev/shm",
357+
Readonly: false,
358+
},
359+
},
329360
},
330361
} {
331362
config := &runtime.ContainerConfig{

pkg/server/helpers.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ const (
5858
// defaultSandboxImage is the image used by sandbox container.
5959
// TODO(random-liu): [P1] Build schema 2 pause image and use it here.
6060
defaultSandboxImage = "gcr.io/google.com/noogler-kubernetes/pause-amd64:3.0"
61+
// defaultShmSize is the default size of the sandbox shm.
62+
defaultShmSize = int64(1024 * 1024 * 64)
6163
// relativeRootfsPath is the rootfs path relative to bundle path.
6264
relativeRootfsPath = "rootfs"
6365
// defaultRuntime is the runtime to use in containerd. We may support
@@ -85,6 +87,8 @@ const (
8587
utsNSFormat = "/proc/%v/ns/uts"
8688
// pidNSFormat is the format of pid namespace of a process.
8789
pidNSFormat = "/proc/%v/ns/pid"
90+
// devShm is the default path of /dev/shm.
91+
devShm = "/dev/shm"
8892
// etcHosts is the default path of /etc/hosts file.
8993
etcHosts = "/etc/hosts"
9094
)
@@ -149,6 +153,11 @@ func getSandboxHosts(sandboxRootDir string) string {
149153
return filepath.Join(sandboxRootDir, "hosts")
150154
}
151155

156+
// getSandboxDevShm returns the shm file path inside the sandbox root directory.
157+
func getSandboxDevShm(sandboxRootDir string) string {
158+
return filepath.Join(sandboxRootDir, "shm")
159+
}
160+
152161
// prepareStreamingPipes prepares stream named pipe for container. returns nil
153162
// streaming handler if corresponding stream path is empty.
154163
func (c *criContainerdService) prepareStreamingPipes(ctx context.Context, stdin, stdout, stderr string) (

pkg/server/sandbox_run.go

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package server
1919
import (
2020
"encoding/json"
2121
"fmt"
22+
"os"
2223
"time"
2324

2425
"github.com/containerd/containerd/api/services/execution"
@@ -30,6 +31,7 @@ import (
3031
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
3132
"github.com/opencontainers/runtime-tools/generate"
3233
"golang.org/x/net/context"
34+
"golang.org/x/sys/unix"
3335
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
3436

3537
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
@@ -133,11 +135,14 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
133135
}
134136

135137
// Setup sandbox /dev/shm, /etc/hosts and /etc/resolv.conf.
136-
if err = c.setupSandboxFiles(sandboxRootDir, config); err != nil {
138+
if err = c.setupSandboxFiles(sandboxRootDir, config.GetLinux().GetSecurityContext()); err != nil {
137139
return nil, fmt.Errorf("failed to setup sandbox files: %v", err)
138140
}
139-
// No need to cleanup on error, because the whole sandbox root directory will be removed
140-
// on error.
141+
defer func() {
142+
if retErr != nil {
143+
c.cleanupSandboxFiles(sandboxRootDir, config.GetLinux().GetSecurityContext())
144+
}
145+
}()
141146

142147
// Start sandbox container.
143148
spec, err := c.generateSandboxContainerSpec(id, config, imageMeta.Config)
@@ -297,14 +302,38 @@ func (c *criContainerdService) generateSandboxContainerSpec(id string, config *r
297302

298303
// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts
299304
// and /etc/resolv.conf.
300-
func (c *criContainerdService) setupSandboxFiles(rootDir string, config *runtime.PodSandboxConfig) error {
305+
func (c *criContainerdService) setupSandboxFiles(rootDir string, sc *runtime.LinuxSandboxSecurityContext) error {
301306
// TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet.
302307
sandboxEtcHosts := getSandboxHosts(rootDir)
303308
if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0666); err != nil {
304309
return fmt.Errorf("failed to generate sandbox hosts file %q: %v", sandboxEtcHosts, err)
305310
}
311+
// Setup sandbox /dev/shm.
312+
if sc.GetNamespaceOptions().GetHostIpc() {
313+
if _, err := c.os.Stat(devShm); err != nil {
314+
return fmt.Errorf("host %q is not available for host ipc: %v", devShm, err)
315+
}
316+
} else {
317+
sandboxDevShm := getSandboxDevShm(rootDir)
318+
if err := c.os.MkdirAll(sandboxDevShm, 0700); err != nil {
319+
return fmt.Errorf("failed to create sandbox shm: %v", err)
320+
}
321+
shmproperty := fmt.Sprintf("mode=1777,size=%d", defaultShmSize)
322+
if err := c.os.Mount("shm", sandboxDevShm, "tmpfs", uintptr(unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV), shmproperty); err != nil {
323+
return fmt.Errorf("failed to mount sandbox shm: %v", err)
324+
}
325+
}
326+
306327
// TODO(random-liu): [P0] Set DNS options. Maintain a resolv.conf for the sandbox.
307-
// TODO(random-liu): [P0] Deal with /dev/shm. Use host for HostIpc, and create and mount for
308-
// non-HostIpc. What about mqueue?
309328
return nil
310329
}
330+
331+
// cleanupSandboxFiles only unmount files, we rely on the removal of sandbox root directory to remove files.
332+
// Each cleanup task should log error instead of returning, so as to keep on cleanup on error.
333+
func (c *criContainerdService) cleanupSandboxFiles(rootDir string, sc *runtime.LinuxSandboxSecurityContext) {
334+
if !sc.GetNamespaceOptions().GetHostIpc() {
335+
if err := c.os.Unmount(getSandboxDevShm(rootDir), unix.MNT_DETACH); err != nil && os.IsNotExist(err) {
336+
glog.Errorf("failed to unmount sandbox shm: %v", err)
337+
}
338+
}
339+
}

pkg/server/sandbox_run_test.go

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,65 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
159159

160160
func TestSetupSandboxFiles(t *testing.T) {
161161
testRootDir := "test-sandbox-root"
162-
expectedCopys := [][]interface{}{
163-
{"/etc/hosts", testRootDir + "/hosts", os.FileMode(0666)},
164-
}
165-
c := newTestCRIContainerdService()
166-
var copys [][]interface{}
167-
c.os.(*ostesting.FakeOS).CopyFileFn = func(src string, dest string, perm os.FileMode) error {
168-
copys = append(copys, []interface{}{src, dest, perm})
169-
return nil
162+
for desc, test := range map[string]struct {
163+
hostIpc bool
164+
expectedCalls []ostesting.CalledDetail
165+
}{
166+
"should check host /dev/shm existence when hostIpc is true": {
167+
hostIpc: true,
168+
expectedCalls: []ostesting.CalledDetail{
169+
{
170+
Name: "CopyFile",
171+
Arguments: []interface{}{
172+
"/etc/hosts", testRootDir + "/hosts", os.FileMode(0666),
173+
},
174+
},
175+
{
176+
Name: "Stat",
177+
Arguments: []interface{}{"/dev/shm"},
178+
},
179+
},
180+
},
181+
"should create sandbox shm when hostIpc is false": {
182+
hostIpc: false,
183+
expectedCalls: []ostesting.CalledDetail{
184+
{
185+
Name: "CopyFile",
186+
Arguments: []interface{}{
187+
"/etc/hosts", testRootDir + "/hosts", os.FileMode(0666),
188+
},
189+
},
190+
{
191+
Name: "MkdirAll",
192+
Arguments: []interface{}{
193+
testRootDir + "/shm", os.FileMode(0700),
194+
},
195+
},
196+
{
197+
Name: "Mount",
198+
// Ignore arguments which are too complex to check.
199+
},
200+
},
201+
},
202+
} {
203+
t.Logf("TestCase %q", desc)
204+
c := newTestCRIContainerdService()
205+
cfg := &runtime.LinuxSandboxSecurityContext{
206+
NamespaceOptions: &runtime.NamespaceOption{
207+
HostIpc: test.hostIpc,
208+
},
209+
}
210+
c.setupSandboxFiles(testRootDir, cfg)
211+
calls := c.os.(*ostesting.FakeOS).GetCalls()
212+
assert.Len(t, calls, len(test.expectedCalls))
213+
for i, expected := range test.expectedCalls {
214+
if expected.Arguments == nil {
215+
// Ignore arguments.
216+
expected.Arguments = calls[i].Arguments
217+
}
218+
assert.Equal(t, expected, calls[i])
219+
}
170220
}
171-
c.setupSandboxFiles(testRootDir, nil)
172-
assert.Equal(t, expectedCopys, copys, "should copy /etc/hosts for sandbox")
173221
}
174222

175223
func TestRunPodSandbox(t *testing.T) {
@@ -183,7 +231,6 @@ func TestRunPodSandbox(t *testing.T) {
183231
var pipes []string
184232
fakeOS.MkdirAllFn = func(path string, perm os.FileMode) error {
185233
dirs = append(dirs, path)
186-
assert.Equal(t, os.FileMode(0755), perm)
187234
return nil
188235
}
189236
fakeOS.OpenFifoFn = func(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
@@ -210,11 +257,11 @@ func TestRunPodSandbox(t *testing.T) {
210257
require.NotNil(t, res)
211258
id := res.GetPodSandboxId()
212259

213-
assert.Len(t, dirs, 1)
214-
assert.Equal(t, getSandboxRootDir(c.rootDir, id), dirs[0], "sandbox root directory should be created")
260+
sandboxRootDir := getSandboxRootDir(c.rootDir, id)
261+
assert.Contains(t, dirs[0], sandboxRootDir, "sandbox root directory should be created")
215262

216263
assert.Len(t, pipes, 2)
217-
_, stdout, stderr := getStreamingPipes(getSandboxRootDir(c.rootDir, id))
264+
_, stdout, stderr := getStreamingPipes(sandboxRootDir)
218265
assert.Contains(t, pipes, stdout, "sandbox stdout pipe should be created")
219266
assert.Contains(t, pipes, stderr, "sandbox stderr pipe should be created")
220267

0 commit comments

Comments
 (0)