1
0
forked from wrenn/wrenn

Replace one-shot clock_settime with chrony for continuous guest time sync

Switch from the envd /init endpoint pushing host time via syscall to
chronyd reading the KVM PTP hardware clock (/dev/ptp0) continuously.
This fixes clock drift between init calls and handles snapshot resume
gracefully.

Changes:
- Add clocksource=kvm-clock kernel boot arg
- Start chronyd in wrenn-init.sh before tini (PHC /dev/ptp0, makestep 1.0 -1)
- Remove clock_settime logic from envd SetData and shouldSetSystemTime
- Remove client.Init() clock sync calls from sandbox manager (3 sites)
- Remove Init() method from envdclient (no longer needed)
- Simplify rootfs scripts: socat/chrony now come from apt in the container
  image, only envd/wrenn-init/tini are injected by build scripts
This commit is contained in:
2026-03-26 04:47:44 +06:00
parent 12d1e356fa
commit 6898528096
8 changed files with 37 additions and 234 deletions

View File

@ -3,14 +3,12 @@ package envdclient
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"mime/multipart"
"net/http"
"net/url"
"time"
"connectrpc.com/connect"
@ -49,35 +47,6 @@ func (c *Client) BaseURL() string {
return c.base
}
// Init calls POST /init on envd to sync the guest clock with the host.
// This is important after snapshot resume where the guest clock is frozen.
func (c *Client) Init(ctx context.Context) error {
now := time.Now().UTC()
body, err := json.Marshal(map[string]any{"timestamp": now})
if err != nil {
return fmt.Errorf("marshal init body: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.base+"/init", bytes.NewReader(body))
if err != nil {
return fmt.Errorf("create init request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("init request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusNoContent {
respBody, _ := io.ReadAll(resp.Body)
return fmt.Errorf("init: status %d: %s", resp.StatusCode, string(respBody))
}
return nil
}
// ExecResult holds the output of a command execution.
type ExecResult struct {
Stdout []byte

View File

@ -203,16 +203,6 @@ func (m *Manager) Create(ctx context.Context, sandboxID, template string, vcpus,
return nil, fmt.Errorf("wait for envd: %w", err)
}
// Sync guest clock in background. Non-fatal — sandbox is usable before this completes.
// Run in a goroutine so Init latency doesn't block the RPC response back to the control plane.
go func() {
initCtx, initCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer initCancel()
if err := client.Init(initCtx); err != nil {
slog.Warn("envd init (clock sync) failed", "sandbox", sandboxID, "error", err)
}
}()
now := time.Now()
sb := &sandboxState{
Sandbox: models.Sandbox{
@ -636,16 +626,6 @@ func (m *Manager) Resume(ctx context.Context, sandboxID string, timeoutSec int)
return nil, fmt.Errorf("wait for envd: %w", err)
}
// Sync guest clock in background. Non-fatal — sandbox is usable before this completes.
// Run in a goroutine so Init latency doesn't block the RPC response back to the control plane.
go func() {
initCtx, initCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer initCancel()
if err := client.Init(initCtx); err != nil {
slog.Warn("envd init (clock sync) failed", "sandbox", sandboxID, "error", err)
}
}()
now := time.Now()
sb := &sandboxState{
Sandbox: models.Sandbox{
@ -957,16 +937,6 @@ func (m *Manager) createFromSnapshot(ctx context.Context, sandboxID, snapshotNam
return nil, fmt.Errorf("wait for envd: %w", err)
}
// Sync guest clock in background. Non-fatal — sandbox is usable before this completes.
// Run in a goroutine so Init latency doesn't block the RPC response back to the control plane.
go func() {
initCtx, initCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer initCancel()
if err := client.Init(initCtx); err != nil {
slog.Warn("envd init (clock sync) failed", "sandbox", sandboxID, "error", err)
}
}()
now := time.Now()
sb := &sandboxState{
Sandbox: models.Sandbox{

View File

@ -91,7 +91,7 @@ func (c *VMConfig) kernelArgs() string {
)
return fmt.Sprintf(
"console=ttyS0 reboot=k panic=1 pci=off quiet loglevel=1 init=%s %s",
"console=ttyS0 reboot=k panic=1 pci=off quiet loglevel=1 clocksource=kvm-clock init=%s %s",
c.InitPath, ipArg,
)
}