feature: support image pull progress timeout
Kubelet sends the PullImage request without timeout, because the image size is unknown and timeout is hard to defined. The pulling request might run into 0B/s speed, if containerd can't receive any packet in that connection. For this case, the containerd should cancel the PullImage request. Although containerd provides ingester manager to track the progress of pulling request, for example `ctr image pull` shows the console progress bar, it needs more CPU resources to open/read the ingested files to get status. In order to support progress timeout feature with lower overhead, this patch uses http.RoundTripper wrapper to track active progress. That wrapper will increase active-request number and return the countingReadCloser wrapper for http.Response.Body. Each bytes-read can be count and the active-request number will be descreased when the countingReadCloser wrapper has been closed. For the progress tracker, it can check the active-request number and bytes-read at intervals. If there is no any progress, the progress tracker should cancel the request. NOTE: For each blob data, the containerd will make sure that the content writer is opened before sending http request to the registry. Therefore, the progress reporter can rely on the active-request number. fixed: #4984 Signed-off-by: Wei Fu <fuweid89@gmail.com>
This commit is contained in:
@@ -309,6 +309,14 @@ type PluginConfig struct {
|
||||
EnableCDI bool `toml:"enable_cdi" json:"enableCDI"`
|
||||
// CDISpecDirs is the list of directories to scan for Container Device Interface Specifications
|
||||
CDISpecDirs []string `toml:"cdi_spec_dirs" json:"cdiSpecDirs"`
|
||||
// ImagePullProgressTimeout is the maximum duration that there is no
|
||||
// image data read from image registry in the open connection. It will
|
||||
// be reset whatever a new byte has been read. If timeout, the image
|
||||
// pulling will be cancelled. A zero value means there is no timeout.
|
||||
//
|
||||
// The string is in the golang duration format, see:
|
||||
// https://golang.org/pkg/time/#ParseDuration
|
||||
ImagePullProgressTimeout string `toml:"image_pull_progress_timeout" json:"imagePullProgressTimeout"`
|
||||
}
|
||||
|
||||
// X509KeyPairStreaming contains the x509 configuration for streaming
|
||||
@@ -452,5 +460,12 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error {
|
||||
return fmt.Errorf("invalid stream idle timeout: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Validation for image_pull_progress_timeout
|
||||
if c.ImagePullProgressTimeout != "" {
|
||||
if _, err := time.ParseDuration(c.ImagePullProgressTimeout); err != nil {
|
||||
return fmt.Errorf("invalid image pull progress timeout: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/pkg/cri/streaming"
|
||||
"github.com/pelletier/go-toml"
|
||||
@@ -104,7 +106,8 @@ func DefaultConfig() PluginConfig {
|
||||
ImageDecryption: ImageDecryption{
|
||||
KeyModel: KeyModelNode,
|
||||
},
|
||||
EnableCDI: false,
|
||||
CDISpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
||||
EnableCDI: false,
|
||||
CDISpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
||||
ImagePullProgressTimeout: time.Minute.String(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package config
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/pkg/cri/streaming"
|
||||
@@ -62,5 +63,6 @@ func DefaultConfig() PluginConfig {
|
||||
ImageDecryption: ImageDecryption{
|
||||
KeyModel: KeyModelNode,
|
||||
},
|
||||
ImagePullProgressTimeout: time.Minute.String(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user