2022-04-22 11:26:48 +00:00
2022-04-21 16:28:50 +00:00
# d2vm (Docker to Virtual Machine)
2022-04-19 12:01:08 +00:00
2022-04-22 11:26:48 +00:00
[![Language: Go ](https://img.shields.io/badge/lang-Go-6ad7e5.svg?style=flat-square&logo=go )](https://golang.org/)
[![Go Reference ](https://pkg.go.dev/badge/go.linka.cloud/d2vm.svg )](https://pkg.go.dev/go.linka.cloud/d2vm)
[![Chat ](https://img.shields.io/badge/chat-matrix-blue.svg?style=flat-square&logo=matrix )](https://matrix.to/#/#d2vm:linka.cloud)
2022-04-19 12:01:08 +00:00
*Build virtual machine image from Docker images*
2022-04-21 16:33:32 +00:00
The project is heavily inspired by the [article ](https://iximiuz.com/en/posts/from-docker-container-to-bootable-linux-disk-image/ ) and the work done by [iximiuz ](https://github.com/iximiuz ) on [docker-to-linux ](https://github.com/iximiuz/docker-to-linux ).
Many thanks to him.
2022-04-19 12:01:08 +00:00
**Status**: *alpha*
2022-09-10 17:31:40 +00:00
[![asciicast ](https://asciinema.org/a/520132.svg )](https://asciinema.org/a/520132)
2022-04-22 10:35:26 +00:00
2022-04-19 12:01:08 +00:00
## Supported Environments:
2022-09-10 17:31:40 +00:00
**Only building Linux Virtual Machine images is supported.**
2022-04-21 16:28:50 +00:00
2022-09-13 13:53:06 +00:00
Starting from v0.1.0, **d2vm** automatically run build and convert commands inside Docker when not running on linux
or when running without *root* privileges.
*Note: windows should be working, but is totally untested.*
2022-05-20 14:36:36 +00:00
2022-04-21 16:28:50 +00:00
## Supported VM Linux distributions:
Working and tested:
2022-08-09 11:59:01 +00:00
- [x] Ubuntu (18.04+)
2023-03-01 12:29:10 +00:00
Luks support is available only on Ubuntu 20.04+
2022-08-09 11:59:01 +00:00
- [x] Debian (stretch+)
2023-03-01 12:29:10 +00:00
Luks support is available only on Debian buster+
2022-04-21 16:28:50 +00:00
- [x] Alpine
2022-08-09 11:59:01 +00:00
- [x] CentOS (8+)
2022-04-21 19:31:57 +00:00
Unsupported:
- [ ] RHEL
2022-04-21 16:28:50 +00:00
2022-04-26 12:59:33 +00:00
The program uses the `/etc/os-release` file to discover the Linux distribution and install the Kernel,
2022-04-21 16:28:50 +00:00
if the file is missing, the build cannot succeed.
2022-09-13 13:53:06 +00:00
Obviously, **Distroless** images are not supported.
## Prerequisites
### osx
- [Docker ](https://docs.docker.com/get-docker/ )
- [QEMU ](https://www.qemu.org/download/#macos ) (optional)
- [VirtualBox ](https://www.virtualbox.org/wiki/Downloads ) (optional)
### Linux
- [Docker ](https://docs.docker.com/get-docker/ )
- util-linux
- udev
- parted
- e2fsprogs
2023-09-11 16:51:09 +00:00
- dosfstools (when using fat32)
2022-09-13 13:53:06 +00:00
- mount
- tar
2023-09-11 16:51:09 +00:00
- extlinux (when using syslinux)
2022-09-13 13:53:06 +00:00
- qemu-utils
2023-02-28 11:02:57 +00:00
- cryptsetup (when using LUKS)
2022-09-13 13:53:06 +00:00
- [QEMU ](https://www.qemu.org/download/#linux ) (optional)
- [VirtualBox ](https://www.virtualbox.org/wiki/Linux_Downloads ) (optional)
2022-04-21 16:28:50 +00:00
## Getting started
2022-09-13 13:53:06 +00:00
### Install
#### With Docker
*Note: this will only work if both the source context (and Dockerfile) and the output directory are somewhere inside
the directory where you run the command.*
```bash
docker pull linkacloud/d2vm:latest
alias d2vm="docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock --privileged -v \$PWD:/d2vm -w /d2vm linkacloud/d2vm:latest"
```
```bash
2023-11-13 23:12:27 +00:00
which d2vm
2022-09-13 13:53:06 +00:00
d2vm: aliased to docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock --privileged -v $PWD:/d2vm -w /d2vm linkacloud/d2vm:latest
```
#### With Homebrew
2022-09-12 10:05:27 +00:00
```bash
brew install linka-cloud/tap/d2vm
```
2022-09-13 13:53:06 +00:00
#### From release
2022-04-21 16:28:50 +00:00
2022-09-12 07:23:33 +00:00
Download the latest release for your platform from the [release page ](https://github.com/linka-cloud/d2vm/releases/latest ).
2022-09-13 13:53:06 +00:00
Extract the tarball, then move the extracted *d2vm* binary to somewhere in your `$PATH` (`/usr/local/bin` for most users).
2022-09-12 07:23:33 +00:00
```bash
2022-09-13 13:53:06 +00:00
VERSION=$(git ls-remote --tags https://github.com/linka-cloud/d2vm |cut -d'/' -f 3|tail -n 1)
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$([ "$(uname -m)" = "x86_64" ] & & echo "amd64" || echo "arm64")
curl -sL "https://github.com/linka-cloud/d2vm/releases/download/${VERSION}/d2vm_${VERSION}_${OS}_${ARCH}.tar.gz" | tar -xvz d2vm
sudo mv d2vm /usr/local/bin/
2022-09-12 07:23:33 +00:00
```
2022-09-13 13:53:06 +00:00
#### From source
2022-09-10 17:31:40 +00:00
Clone the git repository:
2022-04-21 16:28:50 +00:00
```bash
2022-09-10 17:31:40 +00:00
git clone https://github.com/linka-cloud/d2vm & & cd d2vm
2022-04-21 16:28:50 +00:00
```
2022-09-10 17:31:40 +00:00
Install using the *make* , *docker* and the Go tool chain:
2022-04-21 16:28:50 +00:00
```bash
2022-09-12 07:23:33 +00:00
make install
```
The *d2vm* binary is installed in the `$GOBIN` directory.
```bash
which d2vm
/go/bin/d2vm
2022-04-21 16:28:50 +00:00
```
2022-09-12 08:01:04 +00:00
### Generate shell completion
The *d2vm* program supports shell completion for *bash* , *zsh* and *fish* .
It can be enabled by running the following command:
```bash
source < (d2vm completion $(basename $SHELL))
```
Or you can install the completion file in the shell completion directory by following the instructions:
```bash
d2vm completion $(basename $SHELL) --help
```
2022-04-21 16:28:50 +00:00
### Converting an existing Docker Image to VM image:
```bash
2022-05-20 14:36:36 +00:00
d2vm convert --help
2022-04-21 16:28:50 +00:00
```
```
Convert Docker image to vm image
Usage:
d2vm convert [docker image] [flags]
Flags:
2022-09-10 17:31:40 +00:00
--append-to-cmdline string Extra kernel cmdline arguments to append to the generated one
2023-09-11 16:51:09 +00:00
--boot-fs string Filesystem to use for the boot partition, ext4 or fat32
2023-02-22 16:26:32 +00:00
--boot-size uint Size of the boot partition in MB (default 100)
2023-09-13 13:37:29 +00:00
--bootloader string Bootloader to use: syslinux, grub, grub-bios, grub-efi, defaults to syslinux on amd64 and grub-efi on arm64
2023-02-15 10:06:52 +00:00
--force Override output qcow2 image
2022-09-10 17:31:40 +00:00
-h, --help help for convert
2023-02-28 11:02:57 +00:00
--keep-cache Keep the images after the build
--luks-password string Password to use for the LUKS encrypted root partition. If not set, the root partition will not be encrypted
2022-09-10 17:31:40 +00:00
--network-manager string Network manager to use for the image: none, netplan, ifupdown
-o, --output string The output image, the extension determine the image format, raw will be used if none. Supported formats: qcow2 qed raw vdi vhd vmdk (default "disk0.qcow2")
2023-02-15 10:06:52 +00:00
-p, --password string Optional root user password
2023-09-13 13:37:29 +00:00
--platform string Platform to use for the container disk image, linux/arm64 and linux/arm64 are supported (default "linux/amd64")
2022-09-10 17:31:40 +00:00
--pull Always pull docker image
2023-02-15 10:06:52 +00:00
--push Push the container disk image to the registry
2022-09-10 17:31:40 +00:00
--raw Just convert the container to virtual machine image without installing anything more
-s, --size string The output image size (default "10G")
2023-02-22 16:26:32 +00:00
--split-boot Split the boot partition from the root partition
2023-02-15 10:06:52 +00:00
-t, --tag string Container disk Docker image tag
2022-09-10 17:31:40 +00:00
Global Flags:
2023-02-15 10:06:52 +00:00
--time string Enable formated timed output, valide formats: 'relative (rel | r)', 'full (f)' (default "none")
2022-09-10 17:31:40 +00:00
-v, --verbose Enable Verbose output
2022-04-21 16:28:50 +00:00
```
Create an image based on the **ubuntu** official image:
```bash
sudo d2vm convert ubuntu -o ubuntu.qcow2 -p MyP4Ssw0rd
```
```
2022-09-10 17:31:40 +00:00
Pulling image ubuntu
Inspecting image ubuntu
No network manager specified, using distribution defaults: netplan
Docker image based on Ubuntu 22.04.1 LTS (Jammy Jellyfish)
Building kernel enabled image
Creating vm image
Creating raw image
Mounting raw image
Creating raw image file system
Copying rootfs to raw image
Setting up rootfs
Installing linux kernel
Unmounting raw image
Writing MBR
Converting to qcow2
2022-04-21 16:28:50 +00:00
```
You can now run your ubuntu image using the created `ubuntu.qcow2` image with **qemu** :
```bash
2022-09-10 17:31:40 +00:00
d2vm run qemu ubuntu.qcow2
2022-04-21 16:28:50 +00:00
```
```
SeaBIOS (version 1.13.0-1ubuntu1.1)
iPXE (http://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+BFF8C920+BFECC920 CA00
Booting from Hard Disk...
SYSLINUX 6.04 EDD 20191223 Copyright (C) 1994-2015 H. Peter Anvin et al
Now booting the kernel from SYSLINUX...
Loading /boot/vmlinuz... ok
Loading /boot/initrd.img...ok
[ 0.000000] Linux version 5.4.0-109-generic (buildd@ubuntu) (gcc version 9)
[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz ro root=UUID=b117d206-b8
[ 0.000000] KERNEL supported cpus:
[ 0.000000] Intel GenuineIntel
[ 0.000000] AMD AuthenticAMD
[ 0.000000] Hygon HygonGenuine
[ 0.000000] Centaur CentaurHauls
[ 0.000000] zhaoxin Shanghai
...
Welcome to Ubuntu 20.04.4 LTS!
[ 3.610631] systemd[1]: Set hostname to < localhost > .
[ 3.838984] systemd[1]: Created slice system-getty.slice.
[ OK ] Created slice system-getty.slice.
[ 3.845038] systemd[1]: Created slice system-modprobe.slice.
[ OK ] Created slice system-modprobe.slice.
[ 3.852054] systemd[1]: Created slice system-serial\x2dgetty.slice.
[ OK ] Created slice system-serial\x2dgetty.slice.
...
Ubuntu 20.04.4 LTS localhost ttyS0
localhost login:
```
Log in using the *root* user and the password configured at build time.
```
localhost login: root
Password:
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-109-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
root@localhost:~#
```
2022-08-09 11:59:01 +00:00
Type `poweroff` to shut down the vm.
2022-04-21 16:28:50 +00:00
### Building a VM Image from a Dockerfile
The example directory contains very minimalistic examples:
```bash
cd examples
```
*ubuntu.Dockerfile* :
```dockerfile
FROM ubuntu
RUN apt update & & apt install -y openssh-server & & \
2022-09-10 17:31:40 +00:00
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
2022-04-21 16:28:50 +00:00
```
Build the vm image:
The *build* command take most of its flags and arguments from the *docker build* command.
```bash
d2vm build --help
```
```
Build a vm image from Dockerfile
Usage:
d2vm build [context directory] [flags]
Flags:
2022-09-10 17:31:40 +00:00
--append-to-cmdline string Extra kernel cmdline arguments to append to the generated one
2023-09-11 16:51:09 +00:00
--boot-fs string Filesystem to use for the boot partition, ext4 or fat32
2023-02-22 16:26:32 +00:00
--boot-size uint Size of the boot partition in MB (default 100)
2023-09-13 13:37:29 +00:00
--bootloader string Bootloader to use: syslinux, grub, grub-bios, grub-efi, defaults to syslinux on amd64 and grub-efi on arm64
2022-09-10 17:31:40 +00:00
--build-arg stringArray Set build-time variables
-f, --file string Name of the Dockerfile
2023-02-15 10:06:52 +00:00
--force Override output qcow2 image
2022-09-10 17:31:40 +00:00
-h, --help help for build
2023-02-28 11:02:57 +00:00
--keep-cache Keep the images after the build
--luks-password string Password to use for the LUKS encrypted root partition. If not set, the root partition will not be encrypted
2022-09-10 17:31:40 +00:00
--network-manager string Network manager to use for the image: none, netplan, ifupdown
-o, --output string The output image, the extension determine the image format, raw will be used if none. Supported formats: qcow2 qed raw vdi vhd vmdk (default "disk0.qcow2")
2023-02-15 10:06:52 +00:00
-p, --password string Optional root user password
2023-09-13 13:37:29 +00:00
--platform string Platform to use for the container disk image, linux/arm64 and linux/arm64 are supported (default "linux/amd64")
--pull Always pull docker image
2023-02-15 10:06:52 +00:00
--push Push the container disk image to the registry
2022-09-10 17:31:40 +00:00
--raw Just convert the container to virtual machine image without installing anything more
-s, --size string The output image size (default "10G")
2023-02-22 16:26:32 +00:00
--split-boot Split the boot partition from the root partition
2023-02-15 10:06:52 +00:00
-t, --tag string Container disk Docker image tag
2022-09-10 17:31:40 +00:00
Global Flags:
2023-02-15 10:06:52 +00:00
--time string Enable formated timed output, valide formats: 'relative (rel | r)', 'full (f)' (default "none")
2022-09-10 17:31:40 +00:00
-v, --verbose Enable Verbose output
2022-04-21 16:28:50 +00:00
```
```bash
sudo d2vm build -p MyP4Ssw0rd -f ubuntu.Dockerfile -o ubuntu.qcow2 .
```
Or if you want to create a VirtualBox image:
```bash
2022-05-20 14:36:36 +00:00
sudo d2vm build -p MyP4Ssw0rd -f ubuntu.Dockerfile -o ubuntu.vdi .
2022-04-21 16:28:50 +00:00
```
2023-02-15 10:06:52 +00:00
### KubeVirt Container Disk Images
Using the `--tag` flag with the `build` and `convert` commands, you can create a
[Container Disk Image ](https://kubevirt.io/user-guide/virtual_machines/disks_and_volumes/#containerdisk ) for [KubeVirt ](https://kubevirt.io/ ).
The `--push` flag will push the image to the registry.
2022-04-21 16:28:50 +00:00
### Complete example
A complete example setting up a ZSH workstation is available in the [examples/full ](examples/full/README.md ) directory.
### Internal Dockerfile templates
You can find the Dockerfiles used to install the Kernel in the [templates ](templates ) directory.
### TODO / Questions:
- [ ] Create service from `ENTRYPOINT` `CMD` `WORKDIR` and `ENV` instructions ?
- [ ] Inject Image `ENV` variables into `.bashrc` or other service environment file ?
2022-05-20 14:36:36 +00:00
- [x] Use image layers to create *rootfs* instead of container ?
### Acknowledgments
The *run* commands are adapted from [linuxkit ](https://github.com/docker/linuxkit ).