Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions cmd/ephemerd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,18 @@ func serveCmd() *cli.Command {
Name: "dind",
Usage: "mount a fake Docker socket into each container (passed to WSL worker)",
},
&cli.BoolFlag{
Name: "dind-allow-privileged",
Usage: "allow privileged sibling containers (overrides config). Set on the in-VM ephemerd from the host's dind.allow_privileged.",
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return serve(ctx, cmd.String("config"), cmd.String("images-dir"), uint32(cmd.Uint("containerd-tcp-port")), cmd.String("containerd-tcp-addr"), cmd.Bool("containerd-only"), cmd.Bool("dind"))
return serve(ctx, cmd.String("config"), cmd.String("images-dir"), uint32(cmd.Uint("containerd-tcp-port")), cmd.String("containerd-tcp-addr"), cmd.Bool("containerd-only"), cmd.Bool("dind"), cmd.Bool("dind-allow-privileged"))
},
}
}

func serve(ctx context.Context, configFile, imagesDirFlag string, containerdTCPPort uint32, containerdTCPAddr string, containerdOnly bool, dindFlag bool) error {
func serve(ctx context.Context, configFile, imagesDirFlag string, containerdTCPPort uint32, containerdTCPAddr string, containerdOnly bool, dindFlag, dindAllowPrivilegedFlag bool) error {
// Check if another instance is already running.
if cc, err := dialControl(ctx); err == nil {
if resp, err := cc.Status(ctx, &apiv1.StatusRequest{}); err == nil {
Expand Down Expand Up @@ -165,6 +169,14 @@ func serve(ctx context.Context, configFile, imagesDirFlag string, containerdTCPP
if dindFlag {
cfg.Dind.Enabled = true
}
// CLI --dind-allow-privileged flag overrides config file. Used by the
// in-VM ephemerd: the host plumbs its own dind.allow_privileged across
// the VM boundary via this flag because the in-VM daemon has its own
// (defaulted) config file.
if dindAllowPrivilegedFlag {
t := true
cfg.Dind.AllowPrivileged = &t
}

// When running as a Windows Service, route log output to the Event Log.
if w := getServiceLogWriter(); w != nil {
Expand Down Expand Up @@ -197,7 +209,7 @@ func serve(ctx context.Context, configFile, imagesDirFlag string, containerdTCPP
// Start container runtime.
// On Linux/Windows: embedded containerd runs in-process.
// On macOS: boot a Linux VM via Virtualization.framework, containerd runs inside it.
ctrdClient, waitDispatch, cleanup, err := startContainerRuntime(configDir, log, cfg.VM.Linux.Enabled, containerdTCPPort, containerdTCPAddr, cfg.Dind.Enabled, cfg.VM.Linux.CPUs, cfg.VM.Linux.MemoryMB, cfg.VM.Linux.DiskSizeGB)
ctrdClient, waitDispatch, cleanup, err := startContainerRuntime(configDir, log, cfg.VM.Linux.Enabled, containerdTCPPort, containerdTCPAddr, cfg.Dind.Enabled, cfg.Dind.ResolvedAllowPrivileged(), cfg.VM.Linux.CPUs, cfg.VM.Linux.MemoryMB, cfg.VM.Linux.DiskSizeGB)
if err != nil {
return fmt.Errorf("starting container runtime: %w", err)
}
Expand Down
13 changes: 7 additions & 6 deletions cmd/ephemerd/runtime_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ import (
// a dispatch client to ephemerd-linux running inside the VM. Linux jobs run as
// containers inside the VM, dispatched through the gRPC dispatch server so
// they get full CNI networking (the raw containerd API skips CRI/CNI).
func startContainerRuntime(dataDir string, log *slog.Logger, _ bool, _ uint32, _ string, _ bool, linuxVMCPUs uint, linuxVMMemoryMB uint64, linuxVMDiskSizeGB uint64) (*client.Client, func() (*scheduler.DispatchClient, *client.Client), func(), error) {
func startContainerRuntime(dataDir string, log *slog.Logger, _ bool, _ uint32, _ string, _, dindAllowPrivileged bool, linuxVMCPUs uint, linuxVMMemoryMB uint64, linuxVMDiskSizeGB uint64) (*client.Client, func() (*scheduler.DispatchClient, *client.Client), func(), error) {
log.Info("macOS detected — booting Linux VM for container runtime")

linuxVM, err := vm.StartLinuxVM(vm.LinuxVMConfig{
DataDir: dataDir,
CPUs: linuxVMCPUs,
MemoryMB: linuxVMMemoryMB,
DiskSizeGB: linuxVMDiskSizeGB,
Log: log,
DataDir: dataDir,
CPUs: linuxVMCPUs,
MemoryMB: linuxVMMemoryMB,
DiskSizeGB: linuxVMDiskSizeGB,
DindAllowPrivileged: dindAllowPrivileged,
Log: log,
})
if err != nil {
return nil, nil, nil, err
Expand Down
2 changes: 1 addition & 1 deletion cmd/ephemerd/runtime_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

// startContainerRuntime starts an in-process containerd server on Linux.
func startContainerRuntime(dataDir string, log *slog.Logger, _ bool, tcpPort uint32, tcpAddr string, _ bool, _ uint, _ uint64, _ uint64) (*client.Client, func() (*scheduler.DispatchClient, *client.Client), func(), error) {
func startContainerRuntime(dataDir string, log *slog.Logger, _ bool, tcpPort uint32, tcpAddr string, _, _ bool, _ uint, _ uint64, _ uint64) (*client.Client, func() (*scheduler.DispatchClient, *client.Client), func(), error) {
ctrd, err := containerd.New(containerd.Config{
DataDir: dataDir,
TCPPort: tcpPort,
Expand Down
15 changes: 8 additions & 7 deletions cmd/ephemerd/runtime_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
// Returns the native containerd client for Windows jobs and a function that
// blocks until the Linux dispatch client is ready (nil if Linux VM is disabled
// or failed to start).
func startContainerRuntime(dataDir string, log *slog.Logger, linuxVMEnabled bool, _ uint32, _ string, dindEnabled bool, linuxVMCPUs uint, linuxVMMemoryMB uint64, linuxVMDiskSizeGB uint64) (*client.Client, func() (*scheduler.DispatchClient, *client.Client), func(), error) {
func startContainerRuntime(dataDir string, log *slog.Logger, linuxVMEnabled bool, _ uint32, _ string, dindEnabled, dindAllowPrivileged bool, linuxVMCPUs uint, linuxVMMemoryMB uint64, linuxVMDiskSizeGB uint64) (*client.Client, func() (*scheduler.DispatchClient, *client.Client), func(), error) {
// Start native containerd for Windows container jobs
ctrd, err := containerd.New(containerd.Config{
DataDir: dataDir,
Expand All @@ -45,12 +45,13 @@ func startContainerRuntime(dataDir string, log *slog.Logger, linuxVMEnabled bool
log.Info("starting Linux VM in background (Hyper-V)")

lvm, err := vm.StartLinuxVM(vm.LinuxVMConfig{
DataDir: dataDir,
CPUs: linuxVMCPUs,
MemoryMB: linuxVMMemoryMB,
DiskSizeGB: linuxVMDiskSizeGB,
DindEnabled: dindEnabled,
Log: log,
DataDir: dataDir,
CPUs: linuxVMCPUs,
MemoryMB: linuxVMMemoryMB,
DiskSizeGB: linuxVMDiskSizeGB,
DindEnabled: dindEnabled,
DindAllowPrivileged: dindAllowPrivileged,
Log: log,
})
if err != nil {
log.Warn("Linux VM not started — Linux jobs will not be available on this host", "error", err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/ephemerd/svc_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (s *ephemerdService) Execute(_ []string, r <-chan svc.ChangeRequest, status

errCh := make(chan error, 1)
go func() {
errCh <- serve(ctx, s.configFile, "", s.ctrdTCPPort, s.ctrdTCPAddr, s.containerdOnly, s.dind)
errCh <- serve(ctx, s.configFile, "", s.ctrdTCPPort, s.ctrdTCPAddr, s.containerdOnly, s.dind, false)
}()

status <- svc.Status{State: svc.Running, Accepts: accepted}
Expand Down
24 changes: 17 additions & 7 deletions mage/download/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,13 +696,18 @@ func extractVmlinuxFromBzImage(bzImagePath, dest string) error {
// exec's ephemerd-linux as PID 1.
func Initrdx86() error {
dest := filepath.Join(vmEmbedDir, "initrd")
// Initrd embeds the rootfs tarball and kernel modules from linux-virt.
// ephemerd-linux is appended to the boot initrd at runtime by
// pkg/vm.buildBootInitrd, so changes to Linux code do not require an
// initrd rebuild — only changes to busybox, the rootfs, or kernel
// modules invalidate this output.
// Initrd embeds the rootfs tarball, kernel modules from linux-virt, and
// the init script which is templated in-line below from this very file.
// ephemerd-linux itself is appended to the boot initrd at runtime by
// pkg/vm.buildBootInitrd, so changes to *Linux ephemerd source* do not
// require an initrd rebuild — but changes to busybox, the rootfs,
// kernel modules, OR the init script (i.e. download.go itself)
// invalidate this output. The download.go input is what catches edits
// to the init script body; without it `mage build:windows` happily
// embeds a stale init script and the kernel boots with old behavior.
inputs := []string{
filepath.Join(vmEmbedDir, "ephemerd-rootfs-"+AlpineVersion+"-x86_64.tar.gz"),
filepath.Join("mage", "download", "download.go"),
}
if !outOfDate(dest, inputs...) {
fmt.Printf(" %s already up to date, skipping\n", dest)
Expand Down Expand Up @@ -1416,14 +1421,16 @@ sleep 1
CONTAINERD_PORT="10000"
ROOT_DISK=""
DIND="0"
DIND_ALLOW_PRIV="0"
for param in $(cat /proc/cmdline); do
case "$param" in
ephemerd.containerd_port=*) CONTAINERD_PORT="${param#*=}" ;;
ephemerd.root_disk=*) ROOT_DISK="${param#*=}" ;;
ephemerd.dind=1) DIND="1" ;;
ephemerd.dind_allow_privileged=1) DIND_ALLOW_PRIV="1" ;;
esac
done
echo "ephemerd-init: containerd_port=$CONTAINERD_PORT root_disk=$ROOT_DISK"
echo "ephemerd-init: containerd_port=$CONTAINERD_PORT root_disk=$ROOT_DISK dind=$DIND dind_allow_privileged=$DIND_ALLOW_PRIV"

# Network: eth0 via hv_netvsc (built-in), DHCP from Default Switch
NET_IF=""
Expand Down Expand Up @@ -1607,8 +1614,11 @@ export HOME=/root
DIND_FLAG=""
if [ "$DIND" = "1" ]; then
DIND_FLAG="--dind"
if [ "$DIND_ALLOW_PRIV" = "1" ]; then
DIND_FLAG="$DIND_FLAG --dind-allow-privileged"
fi
fi
echo "ephemerd-init: launching ephemerd-linux (dind=$DIND)"
echo "ephemerd-init: launching ephemerd-linux (dind=$DIND allow_privileged=$DIND_ALLOW_PRIV)"
exec switch_root /newroot /usr/local/bin/ephemerd-linux serve \
--data-dir /var/lib/ephemerd \
--containerd-tcp-port "$CONTAINERD_PORT" \
Expand Down
3 changes: 3 additions & 0 deletions pkg/vm/linuxvm_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,9 @@ func (l *hypervLinuxVM) createAndBootVM() error {
dindFlag := ""
if l.cfg.DindEnabled {
dindFlag = " ephemerd.dind=1"
if l.cfg.DindAllowPrivileged {
dindFlag += " ephemerd.dind_allow_privileged=1"
}
}
cmdline := fmt.Sprintf(
"rdinit=/init ephemerd.containerd_port=%d ephemerd.root_disk=/dev/sda%s "+
Expand Down
7 changes: 7 additions & 0 deletions pkg/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ type LinuxVMConfig struct {
// Docker socket into each container.
DindEnabled bool

// DindAllowPrivileged forwards the host's dind.allow_privileged setting
// to the in-VM ephemerd via the kernel cmdline. Without this, the in-VM
// daemon reads its own (minimal) config and Linux defaults to false,
// rejecting `docker run --privileged` siblings even when the host
// operator explicitly opted in.
DindAllowPrivileged bool

Log *slog.Logger
}

Expand Down
Loading