Skip to content

Commit 2a27e00

Browse files
committed
WIP
1 parent f2f3eaa commit 2a27e00

22 files changed

+644
-225
lines changed

Makefile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ all: out_dir docs
1313

1414
.PHONY: proxy
1515
proxy: out_dir
16-
go build -o $(output_dir)/$(binary_proxy) ./proxy
16+
go build -o ${output_dir}/$(binary_proxy) ./proxy
1717

1818
out_dir:
1919
mkdir -p $(output_dir)
@@ -28,10 +28,9 @@ integration_tests:
2828
e2e_test: all
2929
ginkgo -tags $(build_tags) ./test/...
3030

31-
image:
31+
image: proxy
3232
podman build -t $(vm_image) --device /dev/kvm \
33-
-f containerfiles/vm/Containerfile \
34-
containerfiles/vm
33+
-f containerfiles/vm/Containerfile .
3534

3635
.PHONY: docs
3736
docs:

cmd/install.go

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,20 @@ import (
99
"github.com/containers/podman-bootc/pkg/podman"
1010
"github.com/containers/podman-bootc/pkg/vm"
1111
"github.com/containers/podman-bootc/pkg/vm/domain"
12-
proxy "github.com/containers/podman-bootc/pkg/vsock"
1312
"github.com/containers/podman/v5/pkg/bindings"
1413
"github.com/spf13/cobra"
15-
)
16-
17-
const (
18-
// TODO: change the image tag with a proper version
19-
defaultImage = "quay.io/containers/bootc-vm:latest"
20-
diskName = "disk.img"
21-
podmanSocket = "/run/user/1000/podman/podman.sock"
14+
log "github.com/sirupsen/logrus"
2215
)
2316

2417
type installCmd struct {
2518
image string
26-
vmImage string
2719
bootcCmdLine []string
2820
artifactsDir string
2921
diskPath string
3022
ctx context.Context
3123
socket string
24+
podmanSocketDir string
25+
libvirtDir string
3226
outputImage string
3327
containerStorage string
3428
configPath string
@@ -64,7 +58,6 @@ func NewInstallCommand() *cobra.Command {
6458
cacheDir = ""
6559
}
6660
cacheDir = filepath.Join(cacheDir, "bootc")
67-
cmd.PersistentFlags().StringVar(&c.vmImage, "bootc-vm", defaultImage, "bootc-vm container image containing the VM disk image")
6861
cmd.PersistentFlags().StringVar(&c.image, "bootc-image", "", "bootc-vm container image")
6962
cmd.PersistentFlags().StringVar(&c.artifactsDir, "dir", cacheDir, "directory where the artifacts are extracted")
7063
cmd.PersistentFlags().StringVar(&c.outputPath, "output-dir", "", "directory to store the output results")
@@ -75,7 +68,6 @@ func NewInstallCommand() *cobra.Command {
7568
if args, err := filterCmdlineArgs(os.Args); err == nil {
7669
c.bootcCmdLine = args
7770
}
78-
c.diskPath = filepath.Join(c.artifactsDir, diskName)
7971

8072
return cmd
8173
}
@@ -94,11 +86,6 @@ func (c *installCmd) validateArgs() error {
9486
if c.outputImage == "" {
9587
return fmt.Errorf("the output-image needs to be set")
9688
}
97-
absPath, err := filepath.Abs(c.outputImage)
98-
if err != nil {
99-
return fmt.Errorf("failed to get absolute path for the output image: %v", err)
100-
}
101-
c.outputImage = absPath
10289
if c.outputPath == "" {
10390
return fmt.Errorf("the output-path needs to be set")
10491
}
@@ -114,6 +101,7 @@ func (c *installCmd) validateArgs() error {
114101
if len(c.bootcCmdLine) == 0 {
115102
return fmt.Errorf("the bootc commandline needs to be specified after the '--'")
116103
}
104+
var err error
117105
c.ctx, err = bindings.NewConnection(context.Background(), "unix://"+c.socket)
118106
if err != nil {
119107
return fmt.Errorf("failed to connect to podman at %s: %v", c.socket, err)
@@ -122,25 +110,18 @@ func (c *installCmd) validateArgs() error {
122110
return nil
123111
}
124112

125-
func (c *installCmd) installBuildVM() error {
126-
inputPath := filepath.Join(c.artifactsDir, "disk.img")
127-
inputImageFormat, err := domain.GetDiskInfo(inputPath)
128-
if err != nil {
129-
return err
130-
}
131-
outputImageFormat, err := domain.GetDiskInfo(c.outputImage)
113+
func (c *installCmd) installBuildVM(kernel, initrd string) error {
114+
image := filepath.Join(c.outputPath, c.outputImage)
115+
outputImageFormat, err := domain.GetDiskInfo(image)
132116
if err != nil {
133117
return err
134118
}
135-
c.installVM = vm.NewInstallVM(vm.InstallOptions{
136-
DiskImage: inputPath,
137-
OutputImage: c.outputImage,
138-
InputFormat: inputImageFormat,
139-
OutputFormat: outputImageFormat,
140-
ContainerStoragePath: c.containerStorage,
141-
ConfigPath: c.configPath,
142-
OutputPath: c.outputPath,
143-
Root: false,
119+
c.installVM = vm.NewInstallVM(filepath.Join(c.libvirtDir, "virtqemud-sock"), vm.InstallOptions{
120+
OutputFormat: outputImageFormat,
121+
OutputImage: filepath.Join(vm.OutputDir, c.outputImage), // Path relative to the container filesystem
122+
Root: false,
123+
Kernel: kernel,
124+
Initrd: initrd,
144125
})
145126
if err := c.installVM.Run(); err != nil {
146127
return err
@@ -153,22 +134,43 @@ func (c *installCmd) doInstall(_ *cobra.Command, _ []string) error {
153134
if err := c.validateArgs(); err != nil {
154135
return err
155136
}
156-
157-
if err := podman.ExtractDiskImage(c.socket, c.artifactsDir, c.vmImage); err != nil {
137+
c.libvirtDir = filepath.Join(c.artifactsDir, "libvirt")
138+
if _, err := os.Stat(c.libvirtDir); os.IsNotExist(err) {
139+
if err := os.Mkdir(c.libvirtDir, 0755); err != nil {
140+
return err
141+
}
142+
}
143+
c.podmanSocketDir = filepath.Join(c.artifactsDir, "podman")
144+
if _, err := os.Stat(c.podmanSocketDir); os.IsNotExist(err) {
145+
if err := os.Mkdir(c.podmanSocketDir, 0755); err != nil {
146+
return err
147+
}
148+
}
149+
remoteSocket := filepath.Join(c.podmanSocketDir, "podman-vm.sock")
150+
vmCont := podman.NewVMContainer(c.image, c.socket, &podman.RunVMContainerOptions{
151+
ContainerStoragePath: c.containerStorage,
152+
ConfigDir: c.configPath,
153+
OutputDir: c.outputPath,
154+
SocketDir: c.podmanSocketDir,
155+
LibvirtSocketDir: c.libvirtDir,
156+
})
157+
if err := vmCont.Run(); err != nil {
158158
return err
159159
}
160-
if err := c.installBuildVM(); err != nil {
160+
defer vmCont.Stop()
161+
162+
kernel, initrd, err := vmCont.GetBootArtifacts()
163+
if err != nil {
161164
return err
162165
}
163-
defer c.installVM.Stop()
166+
log.Debugf("Boot artifacts kernel: %s and initrd: %s", kernel, initrd)
164167

165-
p := proxy.NewProxy(vm.CIDInstallVM, vm.VSOCKPort, filepath.Join(c.artifactsDir, "bootcvm.sock"))
166-
if err := p.Start(); err != nil {
168+
if err := c.installBuildVM(kernel, initrd); err != nil {
167169
return err
168170
}
169-
defer p.Stop()
171+
defer c.installVM.Stop()
170172

171-
if err := podman.RunPodmanCmd(p.GetSocket(), c.image, c.bootcCmdLine); err != nil {
173+
if err := podman.RunPodmanCmd(remoteSocket, c.image, c.bootcCmdLine); err != nil {
172174
return err
173175
}
174176

containerfiles/vm/Containerfile

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,28 @@
1-
FROM quay.io/fedora/fedora:42 as builder
1+
FROM quay.io/fedora/fedora:42
22

3-
ENV URL https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images
4-
ENV IMAGE Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2
5-
ENV CHECKSUM Fedora-Cloud-42-1.1-x86_64-CHECKSUM
6-
ENV LIBGUESTFS_BACKEND direct
3+
RUN dnf install -y \
4+
libvirt-client \
5+
libvirt-daemon \
6+
libvirt-daemon-driver-qemu \
7+
libvirt-daemon-driver-storage-core \
8+
qemu-kvm \
9+
socat \
10+
virt-install \
11+
virtiofsd \
12+
&& dnf clean all
713

8-
RUN dnf install -y curl libguestfs guestfs-tools curl
14+
RUN mkdir -p /home/qemu && chown -R qemu:qemu /home/qemu
15+
RUN mkdir -p /etc/libvirt /vm_files
916

10-
RUN curl -L -O $URL/$IMAGE \
11-
&& curl -L -O $URL/$CHECKSUM \
12-
&& curl -O https://fedoraproject.org/fedora.gpg \
13-
&& gpgv --keyring ./fedora.gpg $CHECKSUM \
14-
&& sha256sum --ignore-missing -c $CHECKSUM \
15-
&& mv $IMAGE /disk.img
17+
COPY containerfiles/vm/entrypoint.sh /entrypoint.sh
18+
COPY ./bin/vsock-proxy /usr/local/bin/vsock-proxy
19+
COPY containerfiles/vm/files /vm_files
20+
COPY containerfiles/vm/qemu.conf /etc/libvirt/qemu.conf
21+
COPY containerfiles/vm/virtqemud.conf /etc/libvirt/virtqemud.conf
22+
COPY containerfiles/vm/virtiofsd-wrapper /usr/local/bin/virtiofsd-wrapper
1623

17-
RUN mkdir -p /systemd-services
18-
COPY ./podman-vsock-proxy.service /systemd-services/podman-vsock-proxy.service
19-
RUN virt-copy-in -a /disk.img /systemd-services/* /etc/systemd/system
24+
EXPOSE 5959
2025

21-
# Configuration of the guest image
22-
RUN virt-customize -a /disk.img --install socat,podman \
23-
--root-password password:bootc \
24-
--run-command "sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config" \
25-
--run-command "mkdir -p /usr/lib/bootc/config" \
26-
--run-command "echo \"config /usr/lib/bootc/config virtiofs rw,relatime,nofail 0 0\" >> /etc/fstab" \
27-
--run-command "mkdir -p /usr/lib/bootc/storage" \
28-
--run-command "echo \"storage /usr/lib/bootc/storage virtiofs rw,relatime,nofail 0 0\" >> /etc/fstab" \
29-
--run-command "mkdir -p /usr/lib/bootc/output" \
30-
--run-command "echo \"output /var/lib/bootc/output virtiofs rw,relatime,nofail 0 0\" >> /etc/fstab" \
31-
--run-command "systemctl enable podman.socket" \
32-
--run-command "systemctl enable podman-vsock-proxy" \
33-
--run-command "sed -i '/^additionalimagestores = \[/a\ \"/usr/lib/bootc/storage\",' /usr/share/containers/storage.conf" \
34-
--run-command "dnf clean all -y" \
35-
&& virt-sparsify --in-place /disk.img
26+
RUN dnf install -y socat
3627

37-
FROM scratch
38-
COPY --from=builder /disk.img /disk.img
28+
ENTRYPOINT ["/entrypoint.sh"]

containerfiles/vm/entrypoint.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/bash
2+
3+
set -xe
4+
5+
BOOTC_ROOT=/bootc-data
6+
7+
# Inject the binaries, systemd and configuration files in the bootc image
8+
mkdir -p ${BOOTC_ROOT}/etc/sysusers.d
9+
mkdir -p ${BOOTC_ROOT}/usr/lib/containers/storage
10+
cp /vm_files/bootc.conf ${BOOTC_ROOT}/etc/sysusers.d/bootc.conf
11+
cp /vm_files/podman-vsock-proxy.service ${BOOTC_ROOT}/etc/systemd/system/podman-vsock-proxy.service
12+
cp /vm_files/mount-vfsd-targets.service ${BOOTC_ROOT}/etc/systemd/system/mount-vfsd-targets.service
13+
cp /vm_files/mount-vfsd-targets.sh ${BOOTC_ROOT}/usr/local/bin/mount-vfsd-targets.sh
14+
cp /vm_files/container-storage.conf ${BOOTC_ROOT}/etc/containers/storage.conf
15+
cp /vm_files/selinux-config ${BOOTC_ROOT}/etc/selinux/config
16+
cp /vm_files/sudoers-bootc ${BOOTC_ROOT}/etc/sudoers.d/bootc
17+
cp /usr/local/bin/vsock-proxy ${BOOTC_ROOT}/usr/local/bin/vsock-proxy
18+
19+
# Enable systemd services
20+
chroot ${BOOTC_ROOT} systemctl enable mount-vfsd-targets
21+
chroot ${BOOTC_ROOT} systemctl enable podman.socket
22+
chroot ${BOOTC_ROOT} systemctl enable podman-vsock-proxy.service
23+
# Create an empty password for the bootc user
24+
entry='bootc::20266::::::'
25+
echo $entry >> ${BOOTC_ROOT}/etc/shadow
26+
27+
# Start proxy the VM port 1234 to unix socket
28+
vsock-proxy --log-level debug -s /run/podman/podman-vm.sock -p 1234 --cid 3 \
29+
--listen-mode unixToVsock &> /var/log/vsock-proxy.log &
30+
31+
# Finally, start libvirt
32+
/usr/sbin/virtlogd &
33+
/usr/bin/virtstoraged &
34+
/usr/sbin/virtqemud -v -t 0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[Service]
2+
ExecStart=
3+
ExecStart=-/usr/sbin/agetty --autologin bootc --noclear %I $TERM

containerfiles/vm/files/bootc.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
u bootc - "Bootc User" /home/bootc /bin/bash
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[storage]
2+
3+
driver = "overlay"
4+
runroot = "/run/containers/storage"
5+
graphroot = "/var/lib/containers/storage"
6+
7+
[storage.options]
8+
additionalimagestores = [
9+
"/usr/lib/containers/storage",
10+
"/usr/lib/bootc/container_storage",
11+
]
12+
pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""}
13+
[storage.options.overlay]
14+
mountopt = "nodev,metacopy=on"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Unit]
2+
Description=Mount all virtiofs targets
3+
After=local-fs.target
4+
ConditionPathExists=/sys/fs/virtiofs
5+
6+
[Service]
7+
Type=oneshot
8+
ExecStart=/usr/local/bin/mount-vfsd-targets.sh
9+
RemainAfterExit=true
10+
11+
[Install]
12+
WantedBy=multi-user.target
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
3+
set -xe
4+
mkdir -p /usr/lib/bootc/config
5+
mkdir -p /usr/lib/bootc/container_storage
6+
mkdir -p /usr/lib/bootc/output
7+
mount -t virtiofs config /usr/lib/bootc/config
8+
mount -t virtiofs storage /usr/lib/bootc/container_storage
9+
mount -t virtiofs output /usr/lib/bootc/output

containerfiles/vm/podman-vsock-proxy.service renamed to containerfiles/vm/files/podman-vsock-proxy.service

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ Requires=network.target
55

66
[Service]
77
Type=simple
8-
ExecStart=/usr/bin/socat VSOCK-LISTEN:1234,reuseaddr,fork UNIX-CONNECT:/var/run/podman/podman.sock
8+
ExecStart=/usr/local/bin/vsock-proxy --log-level debug --cid 3 --port 1234 \
9+
--socket /var/run/podman/podman.sock --listen-mode vsockToUnix
910
Restart=always
1011
RestartSec=3
1112

0 commit comments

Comments
 (0)