aboutsummaryrefslogtreecommitdiff
path: root/README
blob: fa29a0b286e0cf86a5fdb8fdd0773d54f4107cf1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
alpine-qemu-install
===================
Unattended install of Alpine Linux onto a disk image, driven entirely over the
serial console. No keypresses, no graphics, no interaction.


What it does
------------
Given an Alpine virt ISO and a disk image you created beforehand, the script:

  - extracts the kernel, initramfs, and modloop from the ISO
  - builds an apkovl overlay containing the kernel modules and a first-boot
    script
  - boots that kernel under QEMU with the disk attached as /dev/vda
  - runs setup-alpine non-interactively against a pre-baked answer file
  - patches the installed root password, SSH key, and serial getty
  - powers the guest off when finished

The disk image is the target. It appears as /dev/vda inside the guest and is
erased. After install the layout is vda1=boot, vda2=swap, vda3=root.


Requirements
------------
On the host:

  - 7z (7zip or p7zip-full; extracting the modloop squashfs needs it)
  - GNU tar
  - openssl
  - qemu-system-x86_64

KVM is used automatically when /dev/kvm is writable, otherwise the install
runs under plain emulation (slower, but works). You also need an x86_64
Alpine virt ISO and a disk image created up front with qemu-img. qcow2 is
recommended: it allocates sparsely and supports snapshots. Any other format
qemu-img writes also works, since QEMU detects it.


Usage
-----
Create a disk, then run the install:

    qemu-img create -f qcow2 disk.qcow2 2G
    ROOT_PASSWORD=changeme \
        ./alpine-qemu-install alpine-virt-3.20.0-x86_64.iso disk.qcow2

The install log streams to your terminal. When it reaches the end the guest
powers off and the script exits. Boot the resulting image however you like,
for example:

    qemu-system-x86_64 -m 1024 -nographic -drive file=disk.qcow2,if=virtio


Configuration
-------------
Configuration is by environment variable. Only ROOT_PASSWORD is required.

  - ROOT_PASSWORD  root password for the installed system (required)
  - ROOT_PUBKEY    an authorized_keys line; enables root SSH login
  - SSHD           openssh, dropbear, or none (default openssh)
  - VM_HOSTNAME    installed hostname (default alpine)
  - APK_MIRROR     apk mirror base URL
                   (default https://dl-cdn.alpinelinux.org/alpine)
  - RAM_MB         guest memory in MB during install (default 1024)
  - SMP            guest CPU count during install (default 2)

The mirror must be reachable during install: setup-alpine fetches packages
before the disk is even partitioned.


How it works
------------
QEMU's vvfat is unreliable for the ~150 MB modloop file, and a failed
modloop mount leaves the initramfs without /lib/modules, so setup-alpine
cannot modprobe, partition, or run post-install scripts. To avoid that path,
the script unpacks the modloop squashfs on the host and ships the modules
inside the apkovl overlay instead. Only one small file goes on the vvfat
drive: the apkovl tarball itself.

The first-boot work runs from /etc/local.d/autoinstall.start via the default
runlevel's local service. It removes itself before setup-disk copies the
overlay onto the target, so the trigger never fires on the installed system.


Debugging
---------
The install is fully visible. QEMU runs with -nographic, so everything the
first-boot script does is logged to ttyS0, which is your terminal. The script
runs under set -x, so each command is printed before it runs.

QEMU runs with -no-reboot, so on success or failure the guest stays down and
the full log remains on screen. To leave QEMU manually, press Ctrl-a then x.

The guest reports distinct success and failure values through qemu's
isa-debug-exit device. The script exits 0 only when the guest reported
completion, 3 when the first-boot script failed, and 1 when qemu stopped
without any result, including a manual Ctrl-a x.

Common failures:

  - "need 7z" or "need qemu-system-x86_64": install the missing host tool.
  - "modloop layout changed": install 7zip or p7zip-full, or the ISO changed
    and the modloop extraction needs updating.
  - "/dev/vda did not appear": the disk image was not attached or is missing.
  - apk fetch errors: the mirror is unreachable or APK_MIRROR is wrong.


Security
--------
ROOT_PASSWORD is hashed on the host; openssl reads it on stdin, so the
plaintext never reaches the guest, the apkovl, the set -x install log, or
a process listing. The hash is kept out of the log too, but any crypt hash
can be attacked offline, so pick a real password for images you keep. Root
SSH login is key-only: ROOT_PUBKEY installs the key, and Alpine's default
PermitRootLogin prohibit-password refuses password logins over SSH.