Change:
What would you like to be : Periodically remove cleanupInfos for old containers from dockershim's map. One way of doing that would be to just forget about s older than say an hour, as they should always be short-lived. Why is this needed: introduced a new in-memory map for the dockershim, that could potentially (in pathological cases) cause memory leaks - for containers that use GMSA cred specs, get created successfully, but then never get started nor removed. This might be okay for the alpha release of the GMSA feature, but should be addressed in the beta. See
/assign wk8
/sig windows
/milestone v1.15
got moved out. let's move this issue with it as well /milestone v1.16
Hello! I'm bug triage lead for the 1.16 release cycle and considering this issue is tagged for 1.16, but not updated for a long time, I'd like to check its status. The code freeze is starting on August 29th (about 1.5 weeks from now), which means that there should be a PR ready (and merged) until then. Do we still target this issue to be fixed for 1.16?
: yup we'd love to have this in 1.16, still waiting for kind reviewers on :) ...

Discussion:
if cleanupInfo != nil { // we don't perform the clean up just yet at that could destroy information // needed for the container to start (e.g. Windows credentials stored in <del> // registry keys); instead, we'll clean up after the container successfully // starts or gets removed </del> <ins> // registry keys); instead, we'll clean up when the container gets removed </ins> ds.containerCleanupInfos[containerID] = cleanupInfo } return &runtimeapi.CreateContainerResponse{ContainerId: containerID}, nil } <del> // the creation failed, let's clean up right away </del> <ins> // the creation failed, let's clean up right away - we ignore any errors though, // this is best effort </ins> ds.performPlatformSpecificContainerCleanupAndLogErrors(containerName, cleanupInfo) return nil, createErr

return nil, fmt.Errorf("failed to start container %q: %v", r.ContainerId, err) } <del> ds.performPlatformSpecificContainerForContainer(r.ContainerId) </del> return &runtimeapi.StartContainerResponse{}, nil }

// RemoveContainer removes the container. func (ds *dockerService) RemoveContainer(_ context.Context, r *runtimeapi.RemoveContainerRequest) (*runtimeapi.RemoveContainerResponse, error) { <del> ds.performPlatformSpecificContainerForContainer(r.ContainerId) </del> // Ideally, log lifecycle should be independent of container lifecycle. // However, docker will remove container log after container is removed, // we can't prevent that now, so we also clean up the symlink here.

if err != nil { return nil, err } <ins> errors := ds.performPlatformSpecificContainerForContainer(r.ContainerId) if len(errors) != 0 { return nil, fmt.Errorf("failed to run platform-specific clean ups for container %q: %v", r.ContainerId, errors) } </ins> err = ds.client.RemoveContainer(r.ContainerId, dockertypes.ContainerRemoveOptions{RemoveVolumes: true, Force: true}) if err != nil { return nil, fmt.Errorf("failed to remove container %q: %v", r.ContainerId, err) } return &runtimeapi.RemoveContainerResponse{}, nil }

return &runtimeapi.UpdateContainerResourcesResponse{}, nil } <del> func (ds *dockerService) performPlatformSpecificContainerForContainer(containerID string) { </del> <ins> func (ds *dockerService) performPlatformSpecificContainerForContainer(containerID string) (errors []error) { </ins> if cleanupInfo, present := ds.containerCleanupInfos[containerID]; present { <del> ds.performPlatformSpecificContainerCleanupAndLogErrors(containerID, cleanupInfo) delete(ds.containerCleanupInfos, containerID) </del> <ins> errors = ds.performPlatformSpecificContainerCleanupAndLogErrors(containerID, cleanupInfo) if len(errors) == 0 { delete(ds.containerCleanupInfos, containerID) } </ins> } <ins> return </ins> } <del> func (ds *dockerService) performPlatformSpecificContainerCleanupAndLogErrors(containerNameOrID string, cleanupInfo *containerCleanupInfo) { </del> <ins> func (ds *dockerService) performPlatformSpecificContainerCleanupAndLogErrors(containerNameOrID string, cleanupInfo *containerCleanupInfo) []error { </ins> if cleanupInfo == nil { <del> return </del> <ins> return nil </ins> } <del> for _, err := range ds.performPlatformSpecificContainerCleanup(cleanupInfo) { </del> <ins> errors := ds.performPlatformSpecificContainerCleanup(cleanupInfo) for _, err := range errors { </ins> klog.Warningf("error when cleaning up after container %q: %v", containerNameOrID, err) } <ins> return errors </ins> }

// applyPlatformSpecificDockerConfig applies platform-specific configurations to a dockertypes.ContainerCreateConfig struct. // The containerCleanupInfo struct it returns will be passed as is to performPlatformSpecificContainerCleanup <del> // after either: //   * the container creation has failed //   * the container has been successfully started //   * the container has been removed // whichever happens first. </del> <ins> // after either the container creation has failed or the container has been removed. </ins> func (ds *dockerService) applyPlatformSpecificDockerConfig(*runtimeapi.CreateContainerRequest, *dockertypes.ContainerCreateConfig) (*containerCleanupInfo, error) { return nil, nil } // performPlatformSpecificContainerCleanup is responsible for doing any platform-specific cleanup <del> // after either: //   * the container creation has failed //   * the container has been successfully started //   * the container has been removed // whichever happens first. // Any errors it returns are simply logged, but do not prevent the container from being started or // removed. </del> <ins> // after either the container creation has failed or the container has been removed. </ins> func (ds *dockerService) performPlatformSpecificContainerCleanup(cleanupInfo *containerCleanupInfo) (errors []error) { return }

// applyPlatformSpecificDockerConfig applies platform-specific configurations to a dockertypes.ContainerCreateConfig struct. // The containerCleanupInfo struct it returns will be passed as is to performPlatformSpecificContainerCleanup <del> // after either: //   * the container creation has failed //   * the container has been successfully started //   * the container has been removed // whichever happens first. </del> <ins> // after either the container creation has failed or the container has been removed. </ins> func (ds *dockerService) applyPlatformSpecificDockerConfig(request *runtimeapi.CreateContainerRequest, createConfig *dockertypes.ContainerCreateConfig) (*containerCleanupInfo, error) { cleanupInfo := &containerCleanupInfo{}

} // performPlatformSpecificContainerCleanup is responsible for doing any platform-specific cleanup <del> // after either: //   * the container creation has failed //   * the container has been successfully started //   * the container has been removed // whichever happens first. // Any errors it returns are simply logged, but do not prevent the container from being started or // removed. </del> <ins> // after either the container creation has failed or the container has been removed. </ins> func (ds *dockerService) performPlatformSpecificContainerCleanup(cleanupInfo *containerCleanupInfo) (errors []error) { if err := removeGMSARegistryValue(cleanupInfo); err != nil { errors = append(errors, err)

startLocalStreamingServer bool // containerCleanupInfos maps container IDs to the `containerCleanupInfo` structs <del> // needed to clean up after containers have been started or removed. </del> <ins> // needed to clean up after containers have been removed. </ins> // (see `applyPlatformSpecificDockerConfig` and `performPlatformSpecificContainerCleanup` // methods for more info). containerCleanupInfos map[string]*containerCleanupInfo