Skip to content

Commit

Permalink
Misc container usage improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
cgwalters committed Nov 12, 2023
1 parent 60de250 commit a158106
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 64 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name: Build containers

on:
push:
branches: [main]
pull_request:
branches: [main]
paths-ignore:
Expand Down
1 change: 1 addition & 0 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ RUN cd /src && make && make install DESTDIR=/instroot
FROM quay.io/fedora/fedora:39
COPY --from=builder /instroot /
RUN /usr/lib/osbuildbootc/installdeps.sh
ENTRYPOINT ["osbuildbootc"]
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

## Usage

This tool can be invoked as a pre-built container image, and it can also be installed
as a standalone tool inside another environment. The implementation uses qemu+KVM.

Example invocation for the container image:

```bash
podman run --rm -ti --security-opt label=disable --device /dev/kvm -v $(pwd):/srv -w /srv ghcr.io/cgwalters/osbuildbootc:latest build-qcow2 -I quay.io/cgwalters/ostest example.qcow2
```

Explanation of podman arguments:

- `--security-opt label=disable`: This is necessary to bind mount in host paths at all
- `--device /dev/kvm`: Pass the KVM device into the container image
- `-v $(pwd):/srv -w /srv`: Pass the current directory as `/srv` into the container

Note that by default KVM is required. You can set the `OSBUILD_NO_KVM` environment variable
to use full qemu emulation if necessary.

### Take a container image from remote registry, output a qcow2

```bash
Expand Down
16 changes: 14 additions & 2 deletions cmd/osbuildbootc.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ var (
source := args[0]
dest := args[1]

if err := KVMPreflightCheck(); err != nil {
return err
}

if err := os.MkdirAll("tmp", 0755); err != nil {
return err
}
Expand Down Expand Up @@ -78,7 +82,7 @@ var (
},
}

cmdVMSHell = &cobra.Command{
cmdVMShell = &cobra.Command{
Use: "vmshell",
Short: "Run a shell in the build VM",
Args: cobra.MatchAll(cobra.ExactArgs(0), cobra.OnlyValidArgs),
Expand All @@ -95,14 +99,22 @@ var (
}
)

func KVMPreflightCheck() error {
_, err := os.Stat("/dev/kvm")
if err != nil {
return fmt.Errorf("failed to access /dev/kvm; you can set OSBUILD_NO_KVM to bypass this at the cost of performance: %w", err)
}
return nil
}

func init() {
rootCmd.AddCommand(cmdBuildQcow2)
cmdBuildQcow2.Flags().StringVar(&sourceTransport, "transport", "docker://", "Source image stransport")
cmdBuildQcow2.Flags().Uint64VarP(&sizeMiB, "size", "", 10*1024, "Disk size in MiB")
cmdBuildQcow2.Flags().StringVarP(&targetImage, "target", "t", "", "Target image (e.g. quay.io/exampleuser/someimg:latest)")
cmdBuildQcow2.Flags().BoolVarP(&targetInsecure, "target-no-signature-verification", "I", false, "Disable signature verification for target")
cmdBuildQcow2.Flags().BoolVarP(&skipFetchCheck, "skip-fetch-check", "S", false, "Skip verification of target image")
rootCmd.AddCommand(cmdVMSHell)
rootCmd.AddCommand(cmdVMShell)
rootCmd.AddCommand(qemuexec.CmdQemuExec)
rootCmd.AddCommand(builddiskimpl.CmdBuildDiskImpl)
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/qemuexec/qemuexec.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var (
usernet bool
cpuCountHost bool
nvme bool
disableKVM bool

architecture string

Expand Down Expand Up @@ -47,6 +48,7 @@ func init() {
CmdQemuExec.Flags().StringVar(&firmware, "firmware", "", "Boot firmware: bios,uefi,uefi-secure (default bios)")
CmdQemuExec.Flags().StringVar(&diskimage, "image", "", "path to primary disk image")
CmdQemuExec.Flags().BoolVarP(&usernet, "usernet", "U", false, "Enable usermode networking")
CmdQemuExec.Flags().BoolVar(&disableKVM, "disable-kvm", false, "Do not use KVM hardware acceleration")
CmdQemuExec.Flags().StringVarP(&hostname, "hostname", "", "", "Set hostname via DHCP")
CmdQemuExec.Flags().IntVarP(&memory, "memory", "m", 0, "Memory in MB")
CmdQemuExec.Flags().StringVar(&architecture, "arch", "", "Use full emulation for target architecture (e.g. aarch64, x86_64, s390x, ppc64le)")
Expand Down
6 changes: 4 additions & 2 deletions internal/pkg/qemu/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ type QemuBuilder struct {
Swtpm bool
Pdeathsig bool
Argv []string
// Whether or not KVM is enabled
KVM bool

// AppendKernelArgs are appended to the bootloader config
AppendKernelArgs string
Expand Down Expand Up @@ -407,6 +409,7 @@ func NewQemuBuilder() *QemuBuilder {
Firmware: defaultFirmware,
Swtpm: true,
Pdeathsig: true,
KVM: true,
Argv: []string{},
architecture: coreosarch.CurrentRpmArch(),
}
Expand Down Expand Up @@ -860,7 +863,7 @@ func baseQemuArgs(arch string, memoryMiB int) ([]string, error) {
// The machine argument needs to reference our memory device; see below
machineArg := "memory-backend=" + memoryDevice
accel := "accel=kvm"
if _, ok := os.LookupEnv("COSA_NO_KVM"); ok || hostArch != arch {
if _, ok := os.LookupEnv("OSBUILD_NO_KVM"); ok || hostArch != arch {
accel = "accel=tcg"
kvm = false
}
Expand Down Expand Up @@ -965,7 +968,6 @@ func (builder *QemuBuilder) setupUefi(secureBoot bool) error {
return nil
}


// VirtioChannelRead allocates a virtio-serial channel that will appear in
// the guest as /dev/virtio-ports/<name>. The guest can write to it, and
// the host can read.
Expand Down
63 changes: 3 additions & 60 deletions src/cmdlib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,55 +47,6 @@ case $arch in
esac
export DEFAULT_TERMINAL

COSA_PRIVILEGED=
has_privileges() {
if [ -z "${COSA_PRIVILEGED:-}" ]; then
if [ -n "${FORCE_UNPRIVILEGED:-}" ]; then
info "Detected FORCE_UNPRIVILEGED; using virt"
COSA_PRIVILEGED=0
elif ! capsh --print | grep -q 'Bounding.*cap_sys_admin'; then
info "Missing CAP_SYS_ADMIN; using virt"
COSA_PRIVILEGED=0
elif [ "$(id -u)" != "0" ] && ! sudo true; then
info "Missing sudo privs; using virt"
COSA_PRIVILEGED=0
else
COSA_PRIVILEGED=1
fi
export COSA_PRIVILEGED
fi
[ ${COSA_PRIVILEGED} == 1 ]
}

preflight() {
depcheck

# See https://pagure.io/centos-infra/issue/48
if test "$(umask)" = 0000; then
fatal "Your umask is unset, please use umask 0022 or so"
fi
}

preflight_kvm() {
# permissions on /dev/kvm vary by (host) distro. If it's
# not writable, recreate it.

if test -z "${COSA_NO_KVM:-}"; then
if ! test -c /dev/kvm; then
fatal "Missing /dev/kvm; you can set COSA_NO_KVM=1 to bypass this at the cost of performance."
fi
if ! [ -w /dev/kvm ]; then
if ! has_privileges; then
fatal "running unprivileged, and /dev/kvm not writable"
else
sudo rm -f /dev/kvm
sudo mknod /dev/kvm c 10 232
sudo setfacl -m u:"$USER":rw /dev/kvm
fi
fi
fi
}

# runvm generates and runs a minimal VM which we use to "bootstrap" our build
# process. It mounts the workdir via virtiofs. If you need to add new packages into
# the vm, update `vmdeps.txt`.
Expand Down Expand Up @@ -203,6 +154,9 @@ EOF

qemuexec_args=(osbuildbootc qemuexec -m ${memory_default} --auto-cpus -U \
--console-to-file "${runvm_console}" --bind-rw "${workdir},workdir")
if [ -n "${OSBUILD_NO_KVM:-}" ]; then
qemuexec_args+=("--disable-kvm")
fi

base_qemu_args=(-drive 'if=none,id=root,format=raw,snapshot=on,file='"${vmbuilddir}"'/root,index=1' \
-device 'virtio-blk,drive=root' \
Expand Down Expand Up @@ -237,14 +191,3 @@ EOF

return "${rc}"
}

jq_git() {
# jq_git extracts JSON elements generated using prepare_git_artifacts.
# ARG1 is the element name, and ARG2 is the location of the
# json document.
jq -rM ".git.$1" "${2}"
}

sha256sum_str() {
sha256sum | cut -f 1 -d ' '
}

0 comments on commit a158106

Please sign in to comment.