mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add checkpoint restore metrics.
- SandboxCheckpointedMetric and SandboxRestoredMetric are added for sandbox metadata metric which indicate whether sandbox is checkpointed or restored. - NumCheckpointedSandboxesMetric and NumRestoredSandboxesMetric are added at the process level which will get the count of number of sandboxes being checkpointed and restored. PiperOrigin-RevId: 726797010
This commit is contained in:
committed by
gVisor bot
parent
d1fe5aeae0
commit
d05a277ca3
@@ -1106,6 +1106,14 @@ func testCheckpointRestore(t *testing.T, conf *config.Config, compression statef
|
||||
t.Fatalf("error restoring container: %v", err)
|
||||
}
|
||||
|
||||
if !cont2.Sandbox.Restored {
|
||||
t.Fatalf("sandbox returned wrong value for Sandbox.Restored, got: false, want: true")
|
||||
}
|
||||
|
||||
if cont2.Sandbox.Checkpointed {
|
||||
t.Fatalf("sandbox returned wrong value for Sandbox.Checkpointed, got: true, want: false")
|
||||
}
|
||||
|
||||
// Wait until application has ran.
|
||||
if err := waitForFileNotEmpty(outputFile2); err != nil {
|
||||
t.Fatalf("Failed to wait for output file: %v", err)
|
||||
@@ -3968,3 +3976,69 @@ func TestSpecValidationIgnore(t *testing.T) {
|
||||
t.Fatalf("spec validation was not ignored, got: %v, want: nil", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckpointResume(t *testing.T) {
|
||||
for name, conf := range configs(t, true /* noOverlay */) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
dir, err := os.MkdirTemp(testutil.TmpDir(), "checkpoint-test")
|
||||
if err != nil {
|
||||
t.Fatalf("os.MkdirTemp failed: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
if err := os.Chmod(dir, 0777); err != nil {
|
||||
t.Fatalf("error chmoding file: %q, %v", dir, err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(dir, "output")
|
||||
outputFile, err := createWriteableOutputFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating output file: %v", err)
|
||||
}
|
||||
defer outputFile.Close()
|
||||
|
||||
script := fmt.Sprintf("i=0; while true; do echo $i >> %q; sleep 1; i=$((i+1)); done", outputPath)
|
||||
spec := testutil.NewSpecWithArgs("bash", "-c", script)
|
||||
_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
|
||||
if err != nil {
|
||||
t.Fatalf("error setting up container: %v", err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
// Create and start the container.
|
||||
args := Args{
|
||||
ID: testutil.RandomContainerID(),
|
||||
Spec: spec,
|
||||
BundleDir: bundleDir,
|
||||
}
|
||||
cont, err := New(conf, args)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating container: %v", err)
|
||||
}
|
||||
if err := cont.Start(conf); err != nil {
|
||||
t.Fatalf("error starting container: %v", err)
|
||||
}
|
||||
|
||||
// Wait until application has ran.
|
||||
if err := waitForFileNotEmpty(outputFile); err != nil {
|
||||
t.Fatalf("Failed to wait for output file: %v", err)
|
||||
}
|
||||
|
||||
sfOpts := statefile.Options{
|
||||
Resume: true,
|
||||
}
|
||||
// Checkpoint running container; save state into new file.
|
||||
if err := cont.Checkpoint(dir, false /* direct */, sfOpts, pgalloc.SaveOpts{}); err != nil {
|
||||
t.Fatalf("error checkpointing container to empty file: %v", err)
|
||||
}
|
||||
|
||||
if !cont.Sandbox.Checkpointed {
|
||||
t.Fatalf("sandbox returned wrong value for Sandbox.Checkpointed, got: false, want: true")
|
||||
}
|
||||
|
||||
if cont.Sandbox.Restored {
|
||||
t.Fatalf("sandbox returned wrong value for Sandbox.Restored, got: true, want: false")
|
||||
}
|
||||
cont.Destroy()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,9 +531,11 @@ func (m *metricServer) loadSandboxesLocked(ctx context.Context) []sandboxLoadRes
|
||||
// metric data (if querying metrics from the sandbox process succeeded).
|
||||
type sandboxMetricsResult struct {
|
||||
sandboxLoadResult
|
||||
isRunning bool
|
||||
snapshot *prometheus.Snapshot
|
||||
err error
|
||||
isRunning bool
|
||||
isCheckpointed bool
|
||||
isRestored bool
|
||||
snapshot *prometheus.Snapshot
|
||||
err error
|
||||
}
|
||||
|
||||
// queryMultiSandboxMetrics queries metric data from multiple loaded sandboxes.
|
||||
@@ -570,6 +572,8 @@ func queryMultiSandboxMetrics(ctx context.Context, loadedSandboxes []sandboxLoad
|
||||
defer wg.Done()
|
||||
for s := range loadedSandboxCh {
|
||||
isRunning := false
|
||||
isCheckpointed := false
|
||||
isRestored := false
|
||||
var snapshot *prometheus.Snapshot
|
||||
err := s.err
|
||||
if err == nil {
|
||||
@@ -577,10 +581,14 @@ func queryMultiSandboxMetrics(ctx context.Context, loadedSandboxes []sandboxLoad
|
||||
snapshot, err = querySandboxMetrics(queryCtx, s.sandbox, s.verifier, metricsFilter)
|
||||
queryCtxCancel()
|
||||
isRunning = s.sandbox.IsRunning()
|
||||
isCheckpointed = s.sandbox.Checkpointed
|
||||
isRestored = s.sandbox.Restored
|
||||
}
|
||||
processSandbox(sandboxMetricsResult{
|
||||
sandboxLoadResult: s,
|
||||
isRunning: isRunning,
|
||||
isCheckpointed: isCheckpointed,
|
||||
isRestored: isRestored,
|
||||
snapshot: snapshot,
|
||||
err: err,
|
||||
})
|
||||
@@ -660,6 +668,8 @@ func (m *metricServer) serveMetrics(w *httpResponseWriter, req *http.Request) ht
|
||||
type metaMetrics struct {
|
||||
numRunningSandboxes int64
|
||||
numCannotExportSandboxes int64
|
||||
numCheckpointedSandboxes int64
|
||||
numRestoredSandboxes int64
|
||||
}
|
||||
meta := metaMetrics{} // Protected by metricsMu.
|
||||
selfMetrics := prometheus.NewSnapshot() // Protected by metricsMu.
|
||||
@@ -675,11 +685,23 @@ func (m *metricServer) serveMetrics(w *httpResponseWriter, req *http.Request) ht
|
||||
defer metricsMu.Unlock()
|
||||
selfMetrics.Add(prometheus.LabeledIntData(&SandboxPresenceMetric, nil, 1).SetExternalLabels(r.served.extraLabels))
|
||||
sandboxRunning := int64(0)
|
||||
sandboxCheckpointed := int64(0)
|
||||
sandboxRestored := int64(0)
|
||||
if r.isRunning {
|
||||
sandboxRunning = 1
|
||||
meta.numRunningSandboxes++
|
||||
}
|
||||
if r.isCheckpointed {
|
||||
sandboxCheckpointed = 1
|
||||
meta.numCheckpointedSandboxes++
|
||||
}
|
||||
if r.isRestored {
|
||||
sandboxRestored = 1
|
||||
meta.numRestoredSandboxes++
|
||||
}
|
||||
selfMetrics.Add(prometheus.LabeledIntData(&SandboxRunningMetric, nil, sandboxRunning).SetExternalLabels(r.served.extraLabels))
|
||||
selfMetrics.Add(prometheus.LabeledIntData(&SandboxCheckpointedMetric, nil, sandboxCheckpointed).SetExternalLabels(r.served.extraLabels))
|
||||
selfMetrics.Add(prometheus.LabeledIntData(&SandboxRestoredMetric, nil, sandboxRestored).SetExternalLabels(r.served.extraLabels))
|
||||
if r.err == nil {
|
||||
selfMetrics.Add(prometheus.LabeledIntData(&SandboxMetadataMetric, r.sandbox.MetricMetadata, 1).SetExternalLabels(r.served.extraLabels))
|
||||
for _, cap := range r.served.capabilities {
|
||||
@@ -732,6 +754,8 @@ func (m *metricServer) serveMetrics(w *httpResponseWriter, req *http.Request) ht
|
||||
selfMetrics.Add(prometheus.NewIntData(&NumRunningSandboxesMetric, meta.numRunningSandboxes))
|
||||
selfMetrics.Add(prometheus.NewIntData(&NumCannotExportSandboxesMetric, meta.numCannotExportSandboxes))
|
||||
selfMetrics.Add(prometheus.NewIntData(&NumTotalSandboxesMetric, numSandboxesTotal))
|
||||
selfMetrics.Add(prometheus.NewIntData(&NumCheckpointedSandboxesMetric, meta.numCheckpointedSandboxes))
|
||||
selfMetrics.Add(prometheus.NewIntData(&NumRestoredSandboxesMetric, meta.numRestoredSandboxes))
|
||||
|
||||
// Write out all data.
|
||||
lastMetricsWrittenSize := int(m.lastMetricsWrittenSize.Load())
|
||||
|
||||
@@ -30,6 +30,16 @@ var (
|
||||
Type: prometheus.TypeGauge,
|
||||
Help: "Boolean metric set to 1 for each running sandbox.",
|
||||
}
|
||||
SandboxCheckpointedMetric = prometheus.Metric{
|
||||
Name: "sandbox_checkpointed",
|
||||
Type: prometheus.TypeGauge,
|
||||
Help: "Boolean metric set to 1 for each checkpointed sandbox.",
|
||||
}
|
||||
SandboxRestoredMetric = prometheus.Metric{
|
||||
Name: "sandbox_restored",
|
||||
Type: prometheus.TypeGauge,
|
||||
Help: "Boolean metric set to 1 for each restored sandbox.",
|
||||
}
|
||||
SandboxMetadataMetric = prometheus.Metric{
|
||||
Name: "sandbox_metadata",
|
||||
Type: prometheus.TypeGauge,
|
||||
@@ -66,6 +76,16 @@ var (
|
||||
Type: prometheus.TypeCounter,
|
||||
Help: "Counter of sandboxes that have ever been started.",
|
||||
}
|
||||
NumCheckpointedSandboxesMetric = prometheus.Metric{
|
||||
Name: "num_sandboxes_checkpointed",
|
||||
Type: prometheus.TypeCounter,
|
||||
Help: "Counter of sandboxes that have been checkpointed.",
|
||||
}
|
||||
NumRestoredSandboxesMetric = prometheus.Metric{
|
||||
Name: "num_sandboxes_restored",
|
||||
Type: prometheus.TypeCounter,
|
||||
Help: "Counter of sandboxes that have been restored.",
|
||||
}
|
||||
)
|
||||
|
||||
// Metrics is a list of metrics that the metric server generates.
|
||||
@@ -73,11 +93,15 @@ var Metrics = []*prometheus.Metric{
|
||||
&SandboxPresenceMetric,
|
||||
&SandboxRunningMetric,
|
||||
&SandboxMetadataMetric,
|
||||
&SandboxCheckpointedMetric,
|
||||
&SandboxRestoredMetric,
|
||||
&SandboxCapabilitiesMetric,
|
||||
&SpecMetadataMetric,
|
||||
&SandboxCreationMetric,
|
||||
&NumRunningSandboxesMetric,
|
||||
&NumCannotExportSandboxesMetric,
|
||||
&NumTotalSandboxesMetric,
|
||||
&NumCheckpointedSandboxesMetric,
|
||||
&NumRestoredSandboxesMetric,
|
||||
&prometheus.ProcessStartTimeSeconds,
|
||||
}
|
||||
|
||||
@@ -219,6 +219,12 @@ type Sandbox struct {
|
||||
// threads to wait on sandbox and get the exit code, since Linux will return
|
||||
// WaitStatus to one of the waiters only.
|
||||
status unix.WaitStatus `nojson:"true"`
|
||||
|
||||
// Checkpointed will be true when the sandbox has been checkpointed.
|
||||
Checkpointed bool `json:"checkpointed"`
|
||||
|
||||
// Restored will be true when the sandbox has been restored.
|
||||
Restored bool `json:"restored"`
|
||||
}
|
||||
|
||||
// Getpid returns the process ID of the sandbox process.
|
||||
@@ -537,7 +543,7 @@ func (s *Sandbox) Restore(conf *config.Config, cid string, imagePath string, dir
|
||||
if err := conn.Call(boot.ContMgrRestore, &opt, nil); err != nil {
|
||||
return fmt.Errorf("restoring container %q: %v", cid, err)
|
||||
}
|
||||
|
||||
s.Restored = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1439,6 +1445,7 @@ func (s *Sandbox) Checkpoint(cid string, imagePath string, direct bool, sfOpts s
|
||||
if err := s.call(boot.ContMgrCheckpoint, &opt, nil); err != nil {
|
||||
return fmt.Errorf("checkpointing container %q: %w", cid, err)
|
||||
}
|
||||
s.Checkpointed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user