From 314fb8f08ec9e046603c814a0a19ff03ab140ee0 Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Fri, 12 Sep 2025 18:55:06 +0800 Subject: [PATCH] feat(host): hide host files mounted to container (#23293) --- .../snapshot_service/snapshot_service.go | 4 +- .../container/volume_mount/interface.go | 1 + pkg/hostman/container/volume_mount/text.go | 7 +- pkg/hostman/guestman/pod.go | 87 +++++++++++++++++-- 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/pkg/hostman/container/snapshot_service/snapshot_service.go b/pkg/hostman/container/snapshot_service/snapshot_service.go index 7101c235a6..6c9064ee3d 100644 --- a/pkg/hostman/container/snapshot_service/snapshot_service.go +++ b/pkg/hostman/container/snapshot_service/snapshot_service.go @@ -43,7 +43,7 @@ type IGuestManager interface { } type ISnapshotContainerManager interface { - GetRootFsMountPath(ctx context.Context, containerId string) (string, error) + GetRootFsMountPath(containerId string) (string, error) } func NewSnapshotter(guestMan IGuestManager, root string, opts ...overlay.Opt) (snapshots.Snapshotter, error) { @@ -129,7 +129,7 @@ func (s *overlayRootFsUpperSnapshotter) changeUpper(ctx context.Context, key str if err != nil { return mounts, errors.Wrapf(err, "GetContainerManager with %s", serverId) } - rootFsPath, err := ctrMan.GetRootFsMountPath(ctx, containerId) + rootFsPath, err := ctrMan.GetRootFsMountPath(containerId) if err != nil { return mounts, errors.Wrapf(err, "GetRootFsMountPath with %s, %s", serverId, containerId) } diff --git a/pkg/hostman/container/volume_mount/interface.go b/pkg/hostman/container/volume_mount/interface.go index ec0ec8d066..76e95fcbcc 100644 --- a/pkg/hostman/container/volume_mount/interface.go +++ b/pkg/hostman/container/volume_mount/interface.go @@ -48,6 +48,7 @@ type IPodInfo interface { GetVolumesOverlayDir() string GetDisks() []*desc.SGuestDisk GetDiskMountPoint(disk storageman.IDisk) string + GetRootFsMountPath(ctrId string) (string, error) } type IVolumeMount interface { diff --git a/pkg/hostman/container/volume_mount/text.go b/pkg/hostman/container/volume_mount/text.go index f6935f520e..4004537aab 100644 --- a/pkg/hostman/container/volume_mount/text.go +++ b/pkg/hostman/container/volume_mount/text.go @@ -51,7 +51,12 @@ func (t text) GetRuntimeMountHostPath(pod IPodInfo, ctrId string, vm *hostapi.Co if err := EnsureDir(pod.GetVolumesDir()); err != nil { return "", errors.Wrapf(err, "mkdir %s", pod.GetVolumesDir()) } - mntPath := filepath.Join(pod.GetVolumesDir(), fmt.Sprintf("%s-%s", ctrId, strings.ReplaceAll(vm.MountPath, "/", "_"))) + dirPath := pod.GetVolumesDir() + rootFsPath, _ := pod.GetRootFsMountPath(ctrId) + if rootFsPath != "" { + dirPath = rootFsPath + } + mntPath := filepath.Join(dirPath, fmt.Sprintf("%s-%s", ctrId, strings.ReplaceAll(vm.MountPath, "/", "_"))) if err := t.writeContent(ti, mntPath); err != nil { return "", errors.Wrapf(err, "write content %s to %s", ti, mntPath) } diff --git a/pkg/hostman/guestman/pod.go b/pkg/hostman/guestman/pod.go index 30e318bda1..31e356475d 100644 --- a/pkg/hostman/guestman/pod.go +++ b/pkg/hostman/guestman/pod.go @@ -676,7 +676,7 @@ func (s *sPodGuestInstance) umountRootFs(ctrId string, rootFs *hostapi.Container return nil } -func (s *sPodGuestInstance) getRootFsMountPath(ctrId string) (string, error) { +func (s *sPodGuestInstance) GetRootFsMountPath(ctrId string) (string, error) { ctr := s.GetContainerById(ctrId) if ctr == nil { return "", errors.Wrapf(httperrors.ErrNotFound, "not found container %s", ctrId) @@ -694,10 +694,6 @@ func (s *sPodGuestInstance) getRootFsMountPath(ctrId string) (string, error) { return hostPath, nil } -func (s *sPodGuestInstance) GetRootFsMountPath(ctx context.Context, ctrId string) (string, error) { - return s.getRootFsMountPath(ctrId) -} - func (s *sPodGuestInstance) mountPodVolumes() error { for _, ctr := range s.GetDesc().Containers { if ctr.Spec.Rootfs == nil { @@ -1778,6 +1774,14 @@ func (s *sPodGuestInstance) createContainer(ctx context.Context, userCred mcclie HostPath: shmPath, }) } + // inject /etc/hosts to hide host storage + if spec.Rootfs != nil { + if etcFilesMount, err := s.getEtcFilesMount(ctrId); err != nil { + return "", errors.Wrapf(err, "get etc hosts mount") + } else { + mounts = append(mounts, etcFilesMount...) + } + } var cpuSetCpus string var cpuSetMems string @@ -1999,6 +2003,75 @@ func (s *sPodGuestInstance) createContainer(ctx context.Context, userCred mcclie return criId, nil } +// copyEtcFile 复制主机上的 etc 文件到容器根文件系统 +func (s *sPodGuestInstance) copyEtcFile(hostPath, etcFilePath string) (*runtimeapi.Mount, error) { + hostEtcFilePath := filepath.Join(hostPath, etcFilePath) + + // 确保目录存在 + if err := volume_mount.EnsureDir(filepath.Dir(hostEtcFilePath)); err != nil { + return nil, errors.Wrapf(err, "ensure dir %s", filepath.Dir(hostEtcFilePath)) + } + + // 复制文件 + if err := volume_mount.CopyFile(etcFilePath, hostEtcFilePath); err != nil { + return nil, errors.Wrapf(err, "copy file %s to %s", etcFilePath, hostEtcFilePath) + } + + // 创建挂载点 + return &runtimeapi.Mount{ + ContainerPath: etcFilePath, + HostPath: hostEtcFilePath, + }, nil +} + +// generateEtcFile 生成 etc 文件内容到容器根文件系统 +func (s *sPodGuestInstance) generateEtcFile(hostPath, etcFilePath, content string) (*runtimeapi.Mount, error) { + hostEtcFilePath := filepath.Join(hostPath, etcFilePath) + + // 确保目录存在 + if err := volume_mount.EnsureDir(filepath.Dir(hostEtcFilePath)); err != nil { + return nil, errors.Wrapf(err, "ensure dir %s", filepath.Dir(hostEtcFilePath)) + } + + // 生成文件内容 + if err := fileutils2.FilePutContents(hostEtcFilePath, content, false); err != nil { + return nil, errors.Wrapf(err, "put file %s to %s", etcFilePath, hostEtcFilePath) + } + + // 创建挂载点 + return &runtimeapi.Mount{ + ContainerPath: etcFilePath, + HostPath: hostEtcFilePath, + }, nil +} + +func (s *sPodGuestInstance) getEtcFilesMount(ctrId string) ([]*runtimeapi.Mount, error) { + hostPath, err := s.GetRootFsMountPath(ctrId) + if err != nil { + return nil, errors.Wrapf(err, "get container root fs path of %s", ctrId) + } + + // 复制 /etc/hosts 文件 + etcHostsMount, err := s.copyEtcFile(hostPath, "/etc/hosts") + if err != nil { + return nil, errors.Wrap(err, "copy /etc/hosts") + } + + // 生成 /etc/hostname 文件 + etcHostnameMount, err := s.generateEtcFile(hostPath, "/etc/hostname", s.GetDesc().Hostname) + if err != nil { + return nil, errors.Wrap(err, "generate /etc/hostname") + } + + // 复制 /etc/resolv.conf 文件 + etcResolvConfMount, err := s.copyEtcFile(hostPath, "/etc/resolv.conf") + if err != nil { + return nil, errors.Wrap(err, "copy /etc/resolv.conf") + } + + return []*runtimeapi.Mount{etcHostsMount, etcHostnameMount, etcResolvConfMount}, nil +} + func filterContainerDevices(devs []*hostapi.ContainerDevice) ([]*hostapi.ContainerDevice, []*hostapi.ContainerDevice) { envDevs := []*hostapi.ContainerDevice{} restDevs := []*hostapi.ContainerDevice{} @@ -2075,6 +2148,10 @@ func (s *sPodGuestInstance) getIsolatedDeviceExtraConfig(spec *hostapi.Container } func (s *sPodGuestInstance) getContainerSystemCpusDir(ctrId string) string { + rootFsPath, _ := s.GetRootFsMountPath(ctrId) + if rootFsPath != "" { + return filepath.Join(rootFsPath, "cpus", ctrId) + } return filepath.Join(s.HomeDir(), "cpus", ctrId) }