Skip to content

Commit f4e48e3

Browse files
committed
image: Switch to NIH cloud-init
This drops cloud-init and switches to a minimal golang implementation that is just enough to read what lima outputs. This lets us drop all of python in the image. We also switch to systemd-networkd instead of NetworkManager because it is slightly easier to configure in this scenario. Signed-off-by: Mark Yen <mark.yen@suse.com>
1 parent d4c5a26 commit f4e48e3

12 files changed

Lines changed: 561 additions & 6 deletions

File tree

Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/g
1212
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg/mod \
1313
go build -ldflags '-s -w' -o /go/bin/rancher-desktop-guest-agent ./src/go/guestagent
1414

15+
COPY src /rd
16+
WORKDIR /rd/rd-init
17+
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg/mod \
18+
go build -ldflags '-s -w' -o /go/bin/rd-init .
19+
1520
FROM registry.opensuse.org/opensuse/bci/kiwi:10 AS builder
1621
ARG type=qcow2
1722
ARG NERDCTL_VERSION

config.kiwi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@
9292
<package name="systemd &gt;= 255.7" />
9393
</packages>
9494
<packages type="image" profiles="lima">
95-
<package name="cloud-init" />
9695
<package name="cni-plugin-flannel" />
9796
<package name="dracut" />
9897
<package name="grub2" />
9998
<package name="kernel-default-base" />
100-
<package name="NetworkManager" />
99+
<package name="systemd-networkd" />
100+
<package name="systemd-resolved" />
101101
<package name="grub2-x86_64-efi" arch="x86_64" />
102102
</packages>
103103
<users>

config.sh

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ done
7575
# tini-static has a different name
7676
ln /usr/sbin/tini-static /usr/sbin/tini
7777

78+
# This file name is invalid on Windows, so we have to rename it as part of the
79+
# build process to prevent issues checking the repository out.
80+
mv /usr/local/lib/systemd/system/mnt-lima{-,\\x2d}cidata.mount
81+
7882
#======================================
7983
# Fix permissions
8084
#--------------------------------------
@@ -99,11 +103,12 @@ if [[ ${kiwi_profiles:-} =~ lima ]]; then
99103
# Enable services
100104
systemctl enable buildkitd
101105
systemctl enable containerd
102-
systemctl enable cloud-config
103-
systemctl enable cloud-final
104-
systemctl enable cloud-init
105106
systemctl enable docker
106-
systemctl enable NetworkManager # Needed for cloud-init to work correctly
107+
systemctl enable systemd-networkd
108+
systemctl enable systemd-resolved
109+
110+
systemctl enable lima-init.service
111+
systemctl enable rd-init.service
107112
# Disable network namespace related functionality (WSL only)
108113
rm -f /usr/local/lib/systemd/system/*/network-namespace.conf
109114
# Remove the docker config that is only used on Windows
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[Unit]
2+
Description=Minimal cloud-init for Rancher Desktop
3+
ConditionVirtualization=vm
4+
Wants=rd-init.service ssh-keygen.service sshd.service
5+
After=rd-init.service systemd-networkd-wait-online.service
6+
After=network.service NetworkManager.service NetworkManager-wait-online.service
7+
RequiresMountsFor=/mnt/lima-cidata
8+
Before=network-online.target sshd-keygen.service sshd.service shutdown.target
9+
Conflicts=shutdown.target
10+
11+
[Service]
12+
Type=exec
13+
Environment=LIMA_CIDATA_MNT=/mnt/lima-cidata
14+
EnvironmentFile=/mnt/lima-cidata/lima.env
15+
ExecStart=/mnt/lima-cidata/boot.sh
16+
RemainAfterExit=yes
17+
TimeoutSec=0
18+
StandardOutput=journal+console
19+
20+
[Install]
21+
WantedBy=multi-user.target
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[Unit]
2+
Description=/mnt/lima-cidata Mount Point
3+
ConditionVirtualization=vm
4+
5+
[Mount]
6+
Where=/mnt/lima-cidata
7+
What=/dev/disk/by-label/cidata
8+
Options=ro,mode=0700,dmode=0700,overriderockperm,exec,uid=0
9+
DirectoryMode=0700
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[Unit]
2+
Description=Minimal cloud-init for Rancher Desktop (pre-networking)
3+
ConditionVirtualization=vm
4+
Wants=network-pre.target
5+
After=systemd-remount-fs.service
6+
Requires=systemd-udevd.service
7+
After=systemd-udevd.service
8+
Before=network-pre.target
9+
Before=shutdown.target
10+
RequiresMountsFor=/mnt/lima-cidata
11+
12+
[Service]
13+
Type=notify
14+
EnvironmentFile=/mnt/lima-cidata/lima.env
15+
ExecStart=/usr/local/bin/rd-init
16+
RemainAfterExit=yes
17+
TimeoutSec=0
18+
StandardOutput=journal+console
19+
20+
[Install]
21+
WantedBy=multi-user.target

src/rd-init/go.mod

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module github.com/rancher-sandbox/rancher-desktop-opensuse/src/rd-init
2+
3+
go 1.24.2
4+
5+
require (
6+
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
7+
github.com/coreos/go-systemd/v22 v22.5.0
8+
github.com/goccy/go-yaml v1.17.1
9+
golang.org/x/sys v0.33.0
10+
)
11+
12+
require github.com/godbus/dbus/v5 v5.0.4 // indirect

src/rd-init/go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
2+
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
3+
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
4+
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
5+
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
6+
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
7+
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
8+
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
9+
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
10+
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=

src/rd-init/main.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Command rd-init is a minimal implementation of cloud-init to start lima.
2+
// Note that this only implements `cloud-init-local`.
3+
package main
4+
5+
import (
6+
"context"
7+
"fmt"
8+
"log/slog"
9+
"os"
10+
"os/exec"
11+
12+
"github.com/coreos/go-systemd/daemon"
13+
"github.com/coreos/go-systemd/v22/dbus"
14+
)
15+
16+
func runCommand(ctx context.Context, name string, arg... string) error {
17+
slog.DebugContext(ctx, "Running command", "name", name, "arg", arg)
18+
cmd := exec.CommandContext(ctx, name, arg...)
19+
cmd.Stdout = os.Stdout
20+
cmd.Stderr = os.Stderr
21+
return cmd.Run()
22+
}
23+
24+
func run(ctx context.Context) error {
25+
var units []string
26+
fns := []func(context.Context)([]string, error) {
27+
LoadMetadata,
28+
LoadUserData,
29+
LoadNetworkConfig,
30+
}
31+
for _, fn := range fns {
32+
if newUnits, err := fn(ctx); err != nil {
33+
return err
34+
} else {
35+
units = append(units, newUnits...)
36+
}
37+
}
38+
39+
slog.InfoContext(ctx, "reloading systemd", "units", units)
40+
41+
conn, err := dbus.NewSystemConnectionContext(ctx)
42+
if err != nil {
43+
return fmt.Errorf("failed to connect to systemd: %w", err)
44+
}
45+
defer conn.Close()
46+
47+
if err := conn.ReloadContext(ctx); err != nil {
48+
return fmt.Errorf("failed to reload systemd: %w", err)
49+
}
50+
51+
// Trigger udevadm to cause the network interface to change name.
52+
slog.InfoContext(ctx, "triggering udevadm to rename interfaces")
53+
if err := runCommand(ctx, "/usr/bin/udevadm", "control", "--reload"); err != nil {
54+
return fmt.Errorf("failed to reload udev: %w", err)
55+
}
56+
err = runCommand(ctx, "/usr/bin/udevadm", "trigger", "--type=devices", "--subsystem-match=net")
57+
if err != nil {
58+
return fmt.Errorf("failed to rename network devices: %w", err)
59+
}
60+
61+
// Notify ready before we reload the other units; otherwise we end up
62+
// blocking startup due to a loop with systemd-networkd.
63+
if _, err := daemon.SdNotify(true, daemon.SdNotifyReady); err != nil {
64+
return err
65+
}
66+
67+
seenUnits := make(map[string]bool)
68+
for _, unit := range units {
69+
if seenUnits[unit] {
70+
continue
71+
}
72+
seenUnits[unit] = true
73+
ch := make(chan string)
74+
_, err = conn.RestartUnitContext(ctx, unit, "replace", ch)
75+
if err != nil {
76+
return fmt.Errorf("failed to start unit %s: %w", unit, err)
77+
}
78+
slog.InfoContext(ctx, "restarted systemd unit", "unit", unit, "result", <-ch)
79+
}
80+
81+
return nil
82+
}
83+
84+
func main () {
85+
ctx := context.Background()
86+
if err := run(ctx); err != nil {
87+
slog.ErrorContext(ctx, "rd-init failed", "error", err)
88+
os.Exit(1)
89+
}
90+
}

src/rd-init/metadata.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log/slog"
7+
"os"
8+
9+
"github.com/goccy/go-yaml"
10+
"golang.org/x/sys/unix"
11+
)
12+
13+
// Load /mnt/lima-cidata/meta-data
14+
func LoadMetadata(ctx context.Context) ([]string, error) {
15+
var metaData struct {
16+
LocalHostName string `yaml:"local-hostname"`
17+
}
18+
19+
file, err := os.Open("/mnt/lima-cidata/meta-data")
20+
if err != nil {
21+
return nil, fmt.Errorf("failed to load meta-data file: %w", err)
22+
}
23+
defer file.Close()
24+
if err := yaml.NewDecoder(file).DecodeContext(ctx, &metaData); err != nil {
25+
return nil, fmt.Errorf("failed to unmarshal meta-data file: %w", err)
26+
}
27+
slog.InfoContext(ctx, "setting host name", "hostname", metaData.LocalHostName)
28+
if err := unix.Sethostname([]byte(metaData.LocalHostName)); err != nil {
29+
return nil, fmt.Errorf("failed to set hostname: %w", err)
30+
}
31+
return nil, nil
32+
}

0 commit comments

Comments
 (0)