adds volatile state directory to the fs plan for cntrs/pods/fifo
Signed-off-by: Mike Brown <brownwm@us.ibm.com>
This commit is contained in:
parent
7f64f9b85c
commit
94df315de8
6
cri.go
6
cri.go
@ -63,13 +63,11 @@ func initCRIService(ic *plugin.InitContext) (interface{}, error) {
|
|||||||
ctx := ic.Context
|
ctx := ic.Context
|
||||||
pluginConfig := ic.Config.(*criconfig.PluginConfig)
|
pluginConfig := ic.Config.(*criconfig.PluginConfig)
|
||||||
c := criconfig.Config{
|
c := criconfig.Config{
|
||||||
PluginConfig: *pluginConfig,
|
PluginConfig: *pluginConfig,
|
||||||
// This is a hack. We assume that containerd root directory
|
|
||||||
// is one level above plugin directory.
|
|
||||||
// TODO(random-liu): Expose containerd config to plugin.
|
|
||||||
ContainerdRootDir: filepath.Dir(ic.Root),
|
ContainerdRootDir: filepath.Dir(ic.Root),
|
||||||
ContainerdEndpoint: ic.Address,
|
ContainerdEndpoint: ic.Address,
|
||||||
RootDir: ic.Root,
|
RootDir: ic.Root,
|
||||||
|
StateDir: ic.State,
|
||||||
}
|
}
|
||||||
log.G(ctx).Infof("Start cri plugin with config %+v", c)
|
log.G(ctx).Infof("Start cri plugin with config %+v", c)
|
||||||
|
|
||||||
|
@ -67,4 +67,4 @@ The explanation and default value of each configuration item are as follows:
|
|||||||
[plugins.cri.registry.mirrors]
|
[plugins.cri.registry.mirrors]
|
||||||
[plugins.cri.registry.mirrors."docker.io"]
|
[plugins.cri.registry.mirrors."docker.io"]
|
||||||
endpoint = ["https://registry-1.docker.io", ]
|
endpoint = ["https://registry-1.docker.io", ]
|
||||||
```
|
```
|
||||||
|
@ -189,7 +189,8 @@ $ crictl info
|
|||||||
"statsCollectPeriod": 10,
|
"statsCollectPeriod": 10,
|
||||||
"containerdRootDir": "/var/lib/containerd",
|
"containerdRootDir": "/var/lib/containerd",
|
||||||
"containerdEndpoint": "/run/containerd/containerd.sock",
|
"containerdEndpoint": "/run/containerd/containerd.sock",
|
||||||
"rootDir": "/var/lib/containerd/io.containerd.grpc.v1.cri"
|
"rootDir": "/var/lib/containerd/io.containerd.grpc.v1.cri",
|
||||||
|
"stateDir": "/run/containerd/io.containerd.grpc.v1.cri",
|
||||||
},
|
},
|
||||||
"golang": "go1.10"
|
"golang": "go1.10"
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,8 @@ type Config struct {
|
|||||||
// RootDir is the root directory path for managing cri plugin files
|
// RootDir is the root directory path for managing cri plugin files
|
||||||
// (metadata checkpoint etc.)
|
// (metadata checkpoint etc.)
|
||||||
RootDir string `json:"rootDir"`
|
RootDir string `json:"rootDir"`
|
||||||
|
// StateDir is the root directory path for managing volatile pod/container data
|
||||||
|
StateDir string `json:"stateDir"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig returns default configurations of cri plugin.
|
// DefaultConfig returns default configurations of cri plugin.
|
||||||
|
@ -134,7 +134,7 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
|
|||||||
logrus.Debugf("Use OCI %+v for container %q", ociRuntime, id)
|
logrus.Debugf("Use OCI %+v for container %q", ociRuntime, id)
|
||||||
|
|
||||||
// Create container root directory.
|
// Create container root directory.
|
||||||
containerRootDir := getContainerRootDir(c.config.RootDir, id)
|
containerRootDir := c.getContainerRootDir(id)
|
||||||
if err = c.os.MkdirAll(containerRootDir, 0755); err != nil {
|
if err = c.os.MkdirAll(containerRootDir, 0755); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to create container root directory %q",
|
return nil, errors.Wrapf(err, "failed to create container root directory %q",
|
||||||
containerRootDir)
|
containerRootDir)
|
||||||
@ -148,12 +148,26 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
volatileContainerRootDir := c.getVolatileContainerRootDir(id)
|
||||||
|
if err = c.os.MkdirAll(volatileContainerRootDir, 0755); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to create volatile container root directory %q",
|
||||||
|
volatileContainerRootDir)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
// Cleanup the volatile container root directory.
|
||||||
|
if err = c.os.RemoveAll(volatileContainerRootDir); err != nil {
|
||||||
|
logrus.WithError(err).Errorf("Failed to remove volatile container root directory %q",
|
||||||
|
volatileContainerRootDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Create container volumes mounts.
|
// Create container volumes mounts.
|
||||||
volumeMounts := c.generateVolumeMounts(containerRootDir, config.GetMounts(), &image.ImageSpec.Config)
|
volumeMounts := c.generateVolumeMounts(containerRootDir, config.GetMounts(), &image.ImageSpec.Config)
|
||||||
|
|
||||||
// Generate container runtime spec.
|
// Generate container runtime spec.
|
||||||
mounts := c.generateContainerMounts(getSandboxRootDir(c.config.RootDir, sandboxID), config)
|
mounts := c.generateContainerMounts(sandboxID, config)
|
||||||
|
|
||||||
spec, err := c.generateContainerSpec(id, sandboxID, sandboxPid, config, sandboxConfig, &image.ImageSpec.Config, append(mounts, volumeMounts...))
|
spec, err := c.generateContainerSpec(id, sandboxID, sandboxPid, config, sandboxConfig, &image.ImageSpec.Config, append(mounts, volumeMounts...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -188,7 +202,7 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
|
|||||||
}
|
}
|
||||||
|
|
||||||
containerIO, err := cio.NewContainerIO(id,
|
containerIO, err := cio.NewContainerIO(id,
|
||||||
cio.WithNewFIFOs(containerRootDir, config.GetTty(), config.GetStdin()))
|
cio.WithNewFIFOs(volatileContainerRootDir, config.GetTty(), config.GetStdin()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to create container io")
|
return nil, errors.Wrap(err, "failed to create container io")
|
||||||
}
|
}
|
||||||
@ -416,13 +430,13 @@ func (c *criService) generateVolumeMounts(containerRootDir string, criMounts []*
|
|||||||
|
|
||||||
// generateContainerMounts sets up necessary container mounts including /dev/shm, /etc/hosts
|
// generateContainerMounts sets up necessary container mounts including /dev/shm, /etc/hosts
|
||||||
// and /etc/resolv.conf.
|
// and /etc/resolv.conf.
|
||||||
func (c *criService) generateContainerMounts(sandboxRootDir string, config *runtime.ContainerConfig) []*runtime.Mount {
|
func (c *criService) generateContainerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount {
|
||||||
var mounts []*runtime.Mount
|
var mounts []*runtime.Mount
|
||||||
securityContext := config.GetLinux().GetSecurityContext()
|
securityContext := config.GetLinux().GetSecurityContext()
|
||||||
if !isInCRIMounts(etcHosts, config.GetMounts()) {
|
if !isInCRIMounts(etcHosts, config.GetMounts()) {
|
||||||
mounts = append(mounts, &runtime.Mount{
|
mounts = append(mounts, &runtime.Mount{
|
||||||
ContainerPath: etcHosts,
|
ContainerPath: etcHosts,
|
||||||
HostPath: getSandboxHosts(sandboxRootDir),
|
HostPath: c.getSandboxHosts(sandboxID),
|
||||||
Readonly: securityContext.GetReadonlyRootfs(),
|
Readonly: securityContext.GetReadonlyRootfs(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -432,13 +446,13 @@ func (c *criService) generateContainerMounts(sandboxRootDir string, config *runt
|
|||||||
if !isInCRIMounts(resolvConfPath, config.GetMounts()) {
|
if !isInCRIMounts(resolvConfPath, config.GetMounts()) {
|
||||||
mounts = append(mounts, &runtime.Mount{
|
mounts = append(mounts, &runtime.Mount{
|
||||||
ContainerPath: resolvConfPath,
|
ContainerPath: resolvConfPath,
|
||||||
HostPath: getResolvPath(sandboxRootDir),
|
HostPath: c.getResolvPath(sandboxID),
|
||||||
Readonly: securityContext.GetReadonlyRootfs(),
|
Readonly: securityContext.GetReadonlyRootfs(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isInCRIMounts(devShm, config.GetMounts()) {
|
if !isInCRIMounts(devShm, config.GetMounts()) {
|
||||||
sandboxDevShm := getSandboxDevShm(sandboxRootDir)
|
sandboxDevShm := c.getSandboxDevShm(sandboxID)
|
||||||
if securityContext.GetNamespaceOptions().GetIpc() == runtime.NamespaceMode_NODE {
|
if securityContext.GetNamespaceOptions().GetIpc() == runtime.NamespaceMode_NODE {
|
||||||
sandboxDevShm = devShm
|
sandboxDevShm = devShm
|
||||||
}
|
}
|
||||||
|
@ -497,7 +497,7 @@ func TestGenerateVolumeMounts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateContainerMounts(t *testing.T) {
|
func TestGenerateContainerMounts(t *testing.T) {
|
||||||
testSandboxRootDir := "test-sandbox-root"
|
const testSandboxID = "test-id"
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
criMounts []*runtime.Mount
|
criMounts []*runtime.Mount
|
||||||
securityContext *runtime.LinuxContainerSecurityContext
|
securityContext *runtime.LinuxContainerSecurityContext
|
||||||
@ -510,17 +510,17 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
expectedMounts: []*runtime.Mount{
|
expectedMounts: []*runtime.Mount{
|
||||||
{
|
{
|
||||||
ContainerPath: "/etc/hosts",
|
ContainerPath: "/etc/hosts",
|
||||||
HostPath: testSandboxRootDir + "/hosts",
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
||||||
Readonly: true,
|
Readonly: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: resolvConfPath,
|
ContainerPath: resolvConfPath,
|
||||||
HostPath: testSandboxRootDir + "/resolv.conf",
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "resolv.conf"),
|
||||||
Readonly: true,
|
Readonly: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: "/dev/shm",
|
ContainerPath: "/dev/shm",
|
||||||
HostPath: testSandboxRootDir + "/shm",
|
HostPath: filepath.Join(testStateDir, sandboxesDir, testSandboxID, "shm"),
|
||||||
Readonly: false,
|
Readonly: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -530,17 +530,17 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
expectedMounts: []*runtime.Mount{
|
expectedMounts: []*runtime.Mount{
|
||||||
{
|
{
|
||||||
ContainerPath: "/etc/hosts",
|
ContainerPath: "/etc/hosts",
|
||||||
HostPath: testSandboxRootDir + "/hosts",
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
||||||
Readonly: false,
|
Readonly: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: resolvConfPath,
|
ContainerPath: resolvConfPath,
|
||||||
HostPath: testSandboxRootDir + "/resolv.conf",
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "resolv.conf"),
|
||||||
Readonly: false,
|
Readonly: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: "/dev/shm",
|
ContainerPath: "/dev/shm",
|
||||||
HostPath: testSandboxRootDir + "/shm",
|
HostPath: filepath.Join(testStateDir, sandboxesDir, testSandboxID, "shm"),
|
||||||
Readonly: false,
|
Readonly: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -552,12 +552,12 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
expectedMounts: []*runtime.Mount{
|
expectedMounts: []*runtime.Mount{
|
||||||
{
|
{
|
||||||
ContainerPath: "/etc/hosts",
|
ContainerPath: "/etc/hosts",
|
||||||
HostPath: testSandboxRootDir + "/hosts",
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"),
|
||||||
Readonly: false,
|
Readonly: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ContainerPath: resolvConfPath,
|
ContainerPath: resolvConfPath,
|
||||||
HostPath: testSandboxRootDir + "/resolv.conf",
|
HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "resolv.conf"),
|
||||||
Readonly: false,
|
Readonly: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -597,7 +597,7 @@ func TestGenerateContainerMounts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
c := newTestCRIService()
|
c := newTestCRIService()
|
||||||
mounts := c.generateContainerMounts(testSandboxRootDir, config)
|
mounts := c.generateContainerMounts(testSandboxID, config)
|
||||||
assert.Equal(t, test.expectedMounts, mounts, desc)
|
assert.Equal(t, test.expectedMounts, mounts, desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,12 +116,12 @@ func (c *criService) execInContainer(ctx context.Context, id string, opts execOp
|
|||||||
}
|
}
|
||||||
execID := util.GenerateID()
|
execID := util.GenerateID()
|
||||||
logrus.Debugf("Generated exec id %q for container %q", execID, id)
|
logrus.Debugf("Generated exec id %q for container %q", execID, id)
|
||||||
rootDir := getContainerRootDir(c.config.RootDir, id)
|
volatileRootDir := c.getVolatileContainerRootDir(id)
|
||||||
var execIO *cio.ExecIO
|
var execIO *cio.ExecIO
|
||||||
process, err := task.Exec(ctx, execID, pspec,
|
process, err := task.Exec(ctx, execID, pspec,
|
||||||
func(id string) (containerdio.IO, error) {
|
func(id string) (containerdio.IO, error) {
|
||||||
var err error
|
var err error
|
||||||
execIO, err = cio.NewExecIO(id, rootDir, opts.tty, opts.stdin != nil)
|
execIO, err = cio.NewExecIO(id, volatileRootDir, opts.tty, opts.stdin != nil)
|
||||||
return execIO, err
|
return execIO, err
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -76,11 +76,16 @@ func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveConta
|
|||||||
return nil, errors.Wrapf(err, "failed to delete container checkpoint for %q", id)
|
return nil, errors.Wrapf(err, "failed to delete container checkpoint for %q", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
containerRootDir := getContainerRootDir(c.config.RootDir, id)
|
containerRootDir := c.getContainerRootDir(id)
|
||||||
if err := system.EnsureRemoveAll(containerRootDir); err != nil {
|
if err := system.EnsureRemoveAll(containerRootDir); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to remove container root directory %q",
|
return nil, errors.Wrapf(err, "failed to remove container root directory %q",
|
||||||
containerRootDir)
|
containerRootDir)
|
||||||
}
|
}
|
||||||
|
volatileContainerRootDir := c.getVolatileContainerRootDir(id)
|
||||||
|
if err := system.EnsureRemoveAll(volatileContainerRootDir); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to remove volatile container root directory %q",
|
||||||
|
volatileContainerRootDir)
|
||||||
|
}
|
||||||
|
|
||||||
c.containerStore.Delete(id)
|
c.containerStore.Delete(id)
|
||||||
|
|
||||||
|
@ -156,29 +156,42 @@ func getCgroupsPath(cgroupsParent, id string, systemdCgroup bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getSandboxRootDir returns the root directory for managing sandbox files,
|
// getSandboxRootDir returns the root directory for managing sandbox files,
|
||||||
// e.g. named pipes.
|
// e.g. hosts files.
|
||||||
func getSandboxRootDir(rootDir, id string) string {
|
func (c *criService) getSandboxRootDir(id string) string {
|
||||||
return filepath.Join(rootDir, sandboxesDir, id)
|
return filepath.Join(c.config.RootDir, sandboxesDir, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getContainerRootDir returns the root directory for managing container files.
|
// getVolatileSandboxRootDir returns the root directory for managing volatile sandbox files,
|
||||||
func getContainerRootDir(rootDir, id string) string {
|
// e.g. named pipes.
|
||||||
return filepath.Join(rootDir, containersDir, id)
|
func (c *criService) getVolatileSandboxRootDir(id string) string {
|
||||||
|
return filepath.Join(c.config.StateDir, sandboxesDir, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getContainerRootDir returns the root directory for managing container files,
|
||||||
|
// e.g. state checkpoint.
|
||||||
|
func (c *criService) getContainerRootDir(id string) string {
|
||||||
|
return filepath.Join(c.config.RootDir, containersDir, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getVolatileContainerRootDir returns the root directory for managing volatile container files,
|
||||||
|
// e.g. named pipes.
|
||||||
|
func (c *criService) getVolatileContainerRootDir(id string) string {
|
||||||
|
return filepath.Join(c.config.StateDir, containersDir, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSandboxHosts returns the hosts file path inside the sandbox root directory.
|
// getSandboxHosts returns the hosts file path inside the sandbox root directory.
|
||||||
func getSandboxHosts(sandboxRootDir string) string {
|
func (c *criService) getSandboxHosts(id string) string {
|
||||||
return filepath.Join(sandboxRootDir, "hosts")
|
return filepath.Join(c.getSandboxRootDir(id), "hosts")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getResolvPath returns resolv.conf filepath for specified sandbox.
|
// getResolvPath returns resolv.conf filepath for specified sandbox.
|
||||||
func getResolvPath(sandboxRoot string) string {
|
func (c *criService) getResolvPath(id string) string {
|
||||||
return filepath.Join(sandboxRoot, "resolv.conf")
|
return filepath.Join(c.getSandboxRootDir(id), "resolv.conf")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSandboxDevShm returns the shm file path inside the sandbox root directory.
|
// getSandboxDevShm returns the shm file path inside the sandbox root directory.
|
||||||
func getSandboxDevShm(sandboxRootDir string) string {
|
func (c *criService) getSandboxDevShm(id string) string {
|
||||||
return filepath.Join(sandboxRootDir, "shm")
|
return filepath.Join(c.getVolatileSandboxRootDir(id), "shm")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getNetworkNamespace returns the network namespace of a process.
|
// getNetworkNamespace returns the network namespace of a process.
|
||||||
|
@ -78,8 +78,9 @@ func (c *criService) recover(ctx context.Context) error {
|
|||||||
return errors.Wrap(err, "failed to list containers")
|
return errors.Wrap(err, "failed to list containers")
|
||||||
}
|
}
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
containerDir := getContainerRootDir(c.config.RootDir, container.ID())
|
containerDir := c.getContainerRootDir(container.ID())
|
||||||
cntr, err := loadContainer(ctx, container, containerDir)
|
volatileContainerDir := c.getVolatileContainerRootDir(container.ID())
|
||||||
|
cntr, err := loadContainer(ctx, container, containerDir, volatileContainerDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Errorf("Failed to load container %q", container.ID())
|
logrus.WithError(err).Errorf("Failed to load container %q", container.ID())
|
||||||
continue
|
continue
|
||||||
@ -113,21 +114,42 @@ func (c *criService) recover(ctx context.Context) error {
|
|||||||
// we can't even get metadata, we should cleanup orphaned sandbox/container directories
|
// we can't even get metadata, we should cleanup orphaned sandbox/container directories
|
||||||
// with best effort.
|
// with best effort.
|
||||||
|
|
||||||
// Cleanup orphaned sandbox directories without corresponding containerd container.
|
// Cleanup orphaned sandbox and container directories without corresponding containerd container.
|
||||||
if err := cleanupOrphanedSandboxDirs(sandboxes, filepath.Join(c.config.RootDir, "sandboxes")); err != nil {
|
for _, cleanup := range []struct {
|
||||||
return errors.Wrap(err, "failed to cleanup orphaned sandbox directories")
|
cntrs []containerd.Container
|
||||||
|
base string
|
||||||
|
errMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
cntrs: sandboxes,
|
||||||
|
base: filepath.Join(c.config.RootDir, sandboxesDir),
|
||||||
|
errMsg: "failed to cleanup orphaned sandbox directories",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cntrs: sandboxes,
|
||||||
|
base: filepath.Join(c.config.StateDir, sandboxesDir),
|
||||||
|
errMsg: "failed to cleanup orphaned volatile sandbox directories",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cntrs: containers,
|
||||||
|
base: filepath.Join(c.config.RootDir, containersDir),
|
||||||
|
errMsg: "failed to cleanup orphaned container directories",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cntrs: containers,
|
||||||
|
base: filepath.Join(c.config.StateDir, containersDir),
|
||||||
|
errMsg: "failed to cleanup orphaned volatile container directories",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if err := cleanupOrphanedIDDirs(cleanup.cntrs, cleanup.base); err != nil {
|
||||||
|
return errors.Wrap(err, cleanup.errMsg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup orphaned container directories without corresponding containerd container.
|
|
||||||
if err := cleanupOrphanedContainerDirs(containers, filepath.Join(c.config.RootDir, "containers")); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to cleanup orphaned container directories")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadContainer loads container from containerd and status checkpoint.
|
// loadContainer loads container from containerd and status checkpoint.
|
||||||
func loadContainer(ctx context.Context, cntr containerd.Container, containerDir string) (containerstore.Container, error) {
|
func loadContainer(ctx context.Context, cntr containerd.Container, containerDir, volatileContainerDir string) (containerstore.Container, error) {
|
||||||
id := cntr.ID()
|
id := cntr.ID()
|
||||||
var container containerstore.Container
|
var container containerstore.Container
|
||||||
// Load container metadata.
|
// Load container metadata.
|
||||||
@ -197,7 +219,7 @@ func loadContainer(ctx context.Context, cntr containerd.Container, containerDir
|
|||||||
// containerd got restarted during that. In that case, we still
|
// containerd got restarted during that. In that case, we still
|
||||||
// treat the container as `CREATED`.
|
// treat the container as `CREATED`.
|
||||||
containerIO, err = cio.NewContainerIO(id,
|
containerIO, err = cio.NewContainerIO(id,
|
||||||
cio.WithNewFIFOs(containerDir, meta.Config.GetTty(), meta.Config.GetStdin()),
|
cio.WithNewFIFOs(volatileContainerDir, meta.Config.GetTty(), meta.Config.GetStdin()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return container, errors.Wrap(err, "failed to create container io")
|
return container, errors.Wrap(err, "failed to create container io")
|
||||||
@ -448,59 +470,30 @@ func loadImages(ctx context.Context, cImages []containerd.Image,
|
|||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupOrphanedSandboxDirs(cntrs []containerd.Container, sandboxesRoot string) error {
|
func cleanupOrphanedIDDirs(cntrs []containerd.Container, base string) error {
|
||||||
// Cleanup orphaned sandbox directories.
|
// Cleanup orphaned id directories.
|
||||||
dirs, err := ioutil.ReadDir(sandboxesRoot)
|
dirs, err := ioutil.ReadDir(base)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return errors.Wrapf(err, "failed to read pod sandboxes directory %q", sandboxesRoot)
|
return errors.Wrap(err, "failed to read base directory")
|
||||||
}
|
}
|
||||||
cntrsMap := make(map[string]containerd.Container)
|
idsMap := make(map[string]containerd.Container)
|
||||||
for _, cntr := range cntrs {
|
for _, cntr := range cntrs {
|
||||||
cntrsMap[cntr.ID()] = cntr
|
idsMap[cntr.ID()] = cntr
|
||||||
}
|
}
|
||||||
for _, d := range dirs {
|
for _, d := range dirs {
|
||||||
if !d.IsDir() {
|
if !d.IsDir() {
|
||||||
logrus.Warnf("Invalid file %q found in pod sandboxes directory", d.Name())
|
logrus.Warnf("Invalid file %q found in base directory %q", d.Name(), base)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := cntrsMap[d.Name()]; ok {
|
if _, ok := idsMap[d.Name()]; ok {
|
||||||
// Do not remove sandbox directory if corresponding container is found.
|
// Do not remove id directory if corresponding container is found.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sandboxDir := filepath.Join(sandboxesRoot, d.Name())
|
dir := filepath.Join(base, d.Name())
|
||||||
if err := system.EnsureRemoveAll(sandboxDir); err != nil {
|
if err := system.EnsureRemoveAll(dir); err != nil {
|
||||||
logrus.WithError(err).Warnf("Failed to remove pod sandbox directory %q", sandboxDir)
|
logrus.WithError(err).Warnf("Failed to remove id directory %q", dir)
|
||||||
} else {
|
} else {
|
||||||
logrus.Debugf("Cleanup orphaned pod sandbox directory %q", sandboxDir)
|
logrus.Debugf("Cleanup orphaned id directory %q", dir)
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanupOrphanedContainerDirs(cntrs []containerd.Container, containersRoot string) error {
|
|
||||||
// Cleanup orphaned container directories.
|
|
||||||
dirs, err := ioutil.ReadDir(containersRoot)
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
return errors.Wrapf(err, "failed to read containers directory %q", containersRoot)
|
|
||||||
}
|
|
||||||
cntrsMap := make(map[string]containerd.Container)
|
|
||||||
for _, cntr := range cntrs {
|
|
||||||
cntrsMap[cntr.ID()] = cntr
|
|
||||||
}
|
|
||||||
for _, d := range dirs {
|
|
||||||
if !d.IsDir() {
|
|
||||||
logrus.Warnf("Invalid file %q found in containers directory", d.Name())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, ok := cntrsMap[d.Name()]; ok {
|
|
||||||
// Do not remove container directory if corresponding container is found.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
containerDir := filepath.Join(containersRoot, d.Name())
|
|
||||||
if err := system.EnsureRemoveAll(containerDir); err != nil {
|
|
||||||
logrus.WithError(err).Warnf("Failed to remove container directory %q", containerDir)
|
|
||||||
} else {
|
|
||||||
logrus.Debugf("Cleanup orphaned container directory %q", containerDir)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -72,12 +72,17 @@ func (c *criService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup the sandbox root directory.
|
// Cleanup the sandbox root directories.
|
||||||
sandboxRootDir := getSandboxRootDir(c.config.RootDir, id)
|
sandboxRootDir := c.getSandboxRootDir(id)
|
||||||
if err := system.EnsureRemoveAll(sandboxRootDir); err != nil {
|
if err := system.EnsureRemoveAll(sandboxRootDir); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to remove sandbox root directory %q",
|
return nil, errors.Wrapf(err, "failed to remove sandbox root directory %q",
|
||||||
sandboxRootDir)
|
sandboxRootDir)
|
||||||
}
|
}
|
||||||
|
volatileSandboxRootDir := c.getVolatileSandboxRootDir(id)
|
||||||
|
if err := system.EnsureRemoveAll(volatileSandboxRootDir); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to remove volatile sandbox root directory %q",
|
||||||
|
volatileSandboxRootDir)
|
||||||
|
}
|
||||||
|
|
||||||
// Delete sandbox container.
|
// Delete sandbox container.
|
||||||
if err := sandbox.Container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {
|
if err := sandbox.Container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {
|
||||||
|
@ -189,8 +189,8 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create sandbox container root directory.
|
// Create sandbox container root directories.
|
||||||
sandboxRootDir := getSandboxRootDir(c.config.RootDir, id)
|
sandboxRootDir := c.getSandboxRootDir(id)
|
||||||
if err := c.os.MkdirAll(sandboxRootDir, 0755); err != nil {
|
if err := c.os.MkdirAll(sandboxRootDir, 0755); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to create sandbox root directory %q",
|
return nil, errors.Wrapf(err, "failed to create sandbox root directory %q",
|
||||||
sandboxRootDir)
|
sandboxRootDir)
|
||||||
@ -204,14 +204,28 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
volatileSandboxRootDir := c.getVolatileSandboxRootDir(id)
|
||||||
|
if err := c.os.MkdirAll(volatileSandboxRootDir, 0755); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to create volatile sandbox root directory %q",
|
||||||
|
volatileSandboxRootDir)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
// Cleanup the volatile sandbox root directory.
|
||||||
|
if err := c.os.RemoveAll(volatileSandboxRootDir); err != nil {
|
||||||
|
logrus.WithError(err).Errorf("Failed to remove volatile sandbox root directory %q",
|
||||||
|
volatileSandboxRootDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Setup sandbox /dev/shm, /etc/hosts and /etc/resolv.conf.
|
// Setup sandbox /dev/shm, /etc/hosts and /etc/resolv.conf.
|
||||||
if err = c.setupSandboxFiles(sandboxRootDir, config); err != nil {
|
if err = c.setupSandboxFiles(id, config); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to setup sandbox files")
|
return nil, errors.Wrapf(err, "failed to setup sandbox files")
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil {
|
if retErr != nil {
|
||||||
if err = c.unmountSandboxFiles(sandboxRootDir, config); err != nil {
|
if err = c.unmountSandboxFiles(id, config); err != nil {
|
||||||
logrus.WithError(err).Errorf("Failed to unmount sandbox files in %q",
|
logrus.WithError(err).Errorf("Failed to unmount sandbox files in %q",
|
||||||
sandboxRootDir)
|
sandboxRootDir)
|
||||||
}
|
}
|
||||||
@ -398,9 +412,9 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
|
|||||||
|
|
||||||
// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts
|
// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts
|
||||||
// and /etc/resolv.conf.
|
// and /etc/resolv.conf.
|
||||||
func (c *criService) setupSandboxFiles(rootDir string, config *runtime.PodSandboxConfig) error {
|
func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error {
|
||||||
// TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet.
|
// TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet.
|
||||||
sandboxEtcHosts := getSandboxHosts(rootDir)
|
sandboxEtcHosts := c.getSandboxHosts(id)
|
||||||
if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0644); err != nil {
|
if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0644); err != nil {
|
||||||
return errors.Wrapf(err, "failed to generate sandbox hosts file %q", sandboxEtcHosts)
|
return errors.Wrapf(err, "failed to generate sandbox hosts file %q", sandboxEtcHosts)
|
||||||
}
|
}
|
||||||
@ -414,7 +428,7 @@ func (c *criService) setupSandboxFiles(rootDir string, config *runtime.PodSandbo
|
|||||||
return errors.Wrapf(err, "failed to parse sandbox DNSConfig %+v", dnsConfig)
|
return errors.Wrapf(err, "failed to parse sandbox DNSConfig %+v", dnsConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolvPath := getResolvPath(rootDir)
|
resolvPath := c.getResolvPath(id)
|
||||||
if resolvContent == "" {
|
if resolvContent == "" {
|
||||||
// copy host's resolv.conf to resolvPath
|
// copy host's resolv.conf to resolvPath
|
||||||
err = c.os.CopyFile(resolvConfPath, resolvPath, 0644)
|
err = c.os.CopyFile(resolvConfPath, resolvPath, 0644)
|
||||||
@ -434,7 +448,7 @@ func (c *criService) setupSandboxFiles(rootDir string, config *runtime.PodSandbo
|
|||||||
return errors.Wrapf(err, "host %q is not available for host ipc", devShm)
|
return errors.Wrapf(err, "host %q is not available for host ipc", devShm)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sandboxDevShm := getSandboxDevShm(rootDir)
|
sandboxDevShm := c.getSandboxDevShm(id)
|
||||||
if err := c.os.MkdirAll(sandboxDevShm, 0700); err != nil {
|
if err := c.os.MkdirAll(sandboxDevShm, 0700); err != nil {
|
||||||
return errors.Wrap(err, "failed to create sandbox shm")
|
return errors.Wrap(err, "failed to create sandbox shm")
|
||||||
}
|
}
|
||||||
@ -475,9 +489,9 @@ func parseDNSOptions(servers, searches, options []string) (string, error) {
|
|||||||
// remove these files. Unmount should *NOT* return error when:
|
// remove these files. Unmount should *NOT* return error when:
|
||||||
// 1) The mount point is already unmounted.
|
// 1) The mount point is already unmounted.
|
||||||
// 2) The mount point doesn't exist.
|
// 2) The mount point doesn't exist.
|
||||||
func (c *criService) unmountSandboxFiles(rootDir string, config *runtime.PodSandboxConfig) error {
|
func (c *criService) unmountSandboxFiles(id string, config *runtime.PodSandboxConfig) error {
|
||||||
if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() != runtime.NamespaceMode_NODE {
|
if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() != runtime.NamespaceMode_NODE {
|
||||||
if err := c.os.Unmount(getSandboxDevShm(rootDir), unix.MNT_DETACH); err != nil && !os.IsNotExist(err) {
|
if err := c.os.Unmount(c.getSandboxDevShm(id), unix.MNT_DETACH); err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
cni "github.com/containerd/go-cni"
|
cni "github.com/containerd/go-cni"
|
||||||
@ -177,7 +178,7 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSetupSandboxFiles(t *testing.T) {
|
func TestSetupSandboxFiles(t *testing.T) {
|
||||||
testRootDir := "test-sandbox-root"
|
const testID = "test-id"
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
dnsConfig *runtime.DNSConfig
|
dnsConfig *runtime.DNSConfig
|
||||||
ipcMode runtime.NamespaceMode
|
ipcMode runtime.NamespaceMode
|
||||||
@ -189,13 +190,17 @@ func TestSetupSandboxFiles(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
"/etc/hosts", testRootDir + "/hosts", os.FileMode(0644),
|
"/etc/hosts",
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hosts"),
|
||||||
|
os.FileMode(0644),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
"/etc/resolv.conf", testRootDir + "/resolv.conf", os.FileMode(0644),
|
"/etc/resolv.conf",
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"),
|
||||||
|
os.FileMode(0644),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -215,13 +220,16 @@ func TestSetupSandboxFiles(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
"/etc/hosts", testRootDir + "/hosts", os.FileMode(0644),
|
"/etc/hosts",
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hosts"),
|
||||||
|
os.FileMode(0644),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "WriteFile",
|
Name: "WriteFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
testRootDir + "/resolv.conf", []byte(`search 114.114.114.114
|
filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"),
|
||||||
|
[]byte(`search 114.114.114.114
|
||||||
nameserver 8.8.8.8
|
nameserver 8.8.8.8
|
||||||
options timeout:1
|
options timeout:1
|
||||||
`), os.FileMode(0644),
|
`), os.FileMode(0644),
|
||||||
@ -239,19 +247,24 @@ options timeout:1
|
|||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
"/etc/hosts", testRootDir + "/hosts", os.FileMode(0644),
|
"/etc/hosts",
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "hosts"),
|
||||||
|
os.FileMode(0644),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "CopyFile",
|
Name: "CopyFile",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
"/etc/resolv.conf", testRootDir + "/resolv.conf", os.FileMode(0644),
|
"/etc/resolv.conf",
|
||||||
|
filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"),
|
||||||
|
os.FileMode(0644),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "MkdirAll",
|
Name: "MkdirAll",
|
||||||
Arguments: []interface{}{
|
Arguments: []interface{}{
|
||||||
testRootDir + "/shm", os.FileMode(0700),
|
filepath.Join(testStateDir, sandboxesDir, testID, "shm"),
|
||||||
|
os.FileMode(0700),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -273,7 +286,7 @@ options timeout:1
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c.setupSandboxFiles(testRootDir, cfg)
|
c.setupSandboxFiles(testID, cfg)
|
||||||
calls := c.os.(*ostesting.FakeOS).GetCalls()
|
calls := c.os.(*ostesting.FakeOS).GetCalls()
|
||||||
assert.Len(t, calls, len(test.expectedCalls))
|
assert.Len(t, calls, len(test.expectedCalls))
|
||||||
for i, expected := range test.expectedCalls {
|
for i, expected := range test.expectedCalls {
|
||||||
|
@ -81,9 +81,8 @@ func (c *criService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandb
|
|||||||
|
|
||||||
logrus.Infof("TearDown network for sandbox %q successfully", id)
|
logrus.Infof("TearDown network for sandbox %q successfully", id)
|
||||||
|
|
||||||
sandboxRoot := getSandboxRootDir(c.config.RootDir, id)
|
if err := c.unmountSandboxFiles(id, sandbox.Config); err != nil {
|
||||||
if err := c.unmountSandboxFiles(sandboxRoot, sandbox.Config); err != nil {
|
return nil, errors.Wrap(err, "failed to unmount sandbox files")
|
||||||
return nil, errors.Wrapf(err, "failed to unmount sandbox files in %q", sandboxRoot)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only stop sandbox container when it's running.
|
// Only stop sandbox container when it's running.
|
||||||
|
@ -28,7 +28,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
testRootDir = "/test/rootfs"
|
testRootDir = "/test/root"
|
||||||
|
testStateDir = "/test/state"
|
||||||
// Use an image id as test sandbox image to avoid image name resolve.
|
// Use an image id as test sandbox image to avoid image name resolve.
|
||||||
// TODO(random-liu): Change this to image name after we have complete image
|
// TODO(random-liu): Change this to image name after we have complete image
|
||||||
// management unit test framework.
|
// management unit test framework.
|
||||||
@ -40,7 +41,8 @@ const (
|
|||||||
func newTestCRIService() *criService {
|
func newTestCRIService() *criService {
|
||||||
return &criService{
|
return &criService{
|
||||||
config: criconfig.Config{
|
config: criconfig.Config{
|
||||||
RootDir: testRootDir,
|
RootDir: testRootDir,
|
||||||
|
StateDir: testStateDir,
|
||||||
PluginConfig: criconfig.PluginConfig{
|
PluginConfig: criconfig.PluginConfig{
|
||||||
SandboxImage: testSandboxImage,
|
SandboxImage: testSandboxImage,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user