Compare commits

...

161 commits

Author SHA1 Message Date
Kroese
9546b11150
docs: Add input types (#245) 2025-04-23 12:56:20 +02:00
Kroese
ffc4bb39c2
docs: Add quotes around $PWD (#244) 2025-04-16 12:05:26 +02:00
Kroese
41da658176
build: Workflow file (#243) 2025-04-14 20:34:51 +02:00
Kroese
caa7bc311d
feat: Detect Docker Desktop (#242) 2025-04-08 07:59:16 +02:00
Kroese
72738ce2a3
build: Add e2fsprogs package (#241) 2025-04-06 00:39:53 +02:00
Kroese
d5cb0b8c71
fix: Remove obsolete packages (#240) 2025-04-06 00:28:51 +02:00
Kroese
038c4c6e14
fix: Refactor USB (#239) 2025-04-06 00:14:39 +02:00
Kroese
f89cb831c4
build: Use debian download mirror (#238) 2025-04-04 22:28:20 +02:00
Kroese
a100af1fc5
build: Pin qemu-efi-aarch64 (#237) 2025-04-04 21:41:45 +02:00
Kroese
56cb411a23
build: Remove ovmf (#236) 2025-04-04 21:17:26 +02:00
Kroese
7622677489
fix: Downgrade ovmf to 2024.11 (#235) 2025-04-04 01:14:23 +02:00
Kroese
18dee3c07d
docs: Disk pass-through (#234) 2025-04-03 10:27:02 +02:00
Kroese
105db123af
feat: Default to alpine (#233) 2025-04-03 01:32:34 +02:00
Kroese
846c232bd0
fix: Check if serial is readable (#232) 2025-03-28 20:14:19 +01:00
Kroese
0e5cca6a1e
docs: Github Codespaces (#231) 2025-03-27 01:46:34 +01:00
Kroese
cd018a0cca
feat: Validate BIOS serial (#230) 2025-03-27 01:08:17 +01:00
Kroese
be36019608
build: Add dmidecode (#229) 2025-03-27 00:26:27 +01:00
Kroese
8f70833e1f
fix: Increase number of USB ports (#228) 2025-03-26 19:29:04 +01:00
Kroese
29adf083b7
docs: Github Codespaces (#227) 2025-03-25 14:43:33 +01:00
Kroese
95848f01a0
feat: Remove non-printable characters (#226) 2025-03-24 13:57:49 +01:00
Kroese
469875fed4
docs: KVM information (#225) 2025-03-20 23:21:50 +01:00
Kroese
5659b0245d
docs: Compatiblity chart (#224) 2025-03-20 23:04:36 +01:00
Kroese
4177dcd59b
docs: Add Podman (#223) 2025-03-20 20:07:28 +01:00
Kroese
ca650b2ffc
feat: Platform variable (#222) 2025-03-20 10:08:21 +01:00
Kroese
61a0db36b4
build: Ignore missing files (#221) 2025-03-20 02:51:14 +01:00
Kroese
ad2458ea42
build: Refactor shared code (#220) 2025-03-20 02:49:36 +01:00
Kroese
226ecd081a
fix: User-mode networking (#219) 2025-03-19 13:17:16 +01:00
Kroese
5b8d5059e5
feat: Add devcontainer (#218) 2025-03-19 08:56:32 +01:00
Kroese
e0a5657ad5
feat: Display nameservers (#217) 2025-03-18 19:20:36 +01:00
Kroese
ea81b4751a
docs: Operating Systems (#216) 2025-03-18 14:22:38 +01:00
Kroese
b54b4986dd
docs: Codespaces (#215) 2025-03-18 14:21:42 +01:00
Kroese
68aebafaf3
feat: Refactor helper functions (#214) 2025-03-18 12:58:11 +01:00
Kroese
e75dceb3b6
feat: Add devcontainer (#213) 2025-03-18 11:20:37 +01:00
Kroese
3b9e436c3d
fix: Remove port 80 (#212) 2025-03-18 05:07:29 +01:00
Kroese
66b70a8fe1
feat: IPv6 support (#211) 2025-03-18 03:56:08 +01:00
Kroese
f15feef69b
feat: Switch to port 80 (#210) 2025-03-17 16:42:58 +01:00
Kroese
824c7a42f4
fix: Fallback to POSIX fallocate (#209) 2025-03-17 11:11:21 +01:00
Kroese
87fbfecd92
docs: Readme (#208) 2025-03-16 14:31:43 +01:00
Kroese
b6eee86366
docs: Networking (#207) 2025-03-16 14:16:12 +01:00
Kroese
7014ab3ac9
feat: Multi-platform definitions (#206) 2025-03-16 09:05:27 +01:00
Kroese
d582f6543e
docs: Readme (#205) 2025-03-16 06:29:10 +01:00
Kroese
1abc636ede
feat: Select operating systems (#204) 2025-03-15 14:00:44 +01:00
Kroese
120171e826
feat: Verify clock source (#203) 2025-03-15 03:27:33 +01:00
Kroese
36cd38da73
docs: Add debug info (#202) 2025-03-14 19:56:06 +01:00
Kroese
de2512f480
fix: Format filesizes (#201) 2025-03-14 18:27:04 +01:00
Kroese
e3c54ca9a1
feat: Validate configured RAM (#200) 2025-03-14 14:43:45 +01:00
Kroese
318271db1c
docs: File sharing (#199) 2025-03-14 14:12:20 +01:00
Kroese
462fcfdf75
feat: Support file sharing (#198) 2025-03-14 06:57:32 +01:00
Kroese
85acaee0f4
feat: Validate configured RAM (#197) 2025-03-13 11:37:43 +01:00
Kroese
98a411c9f5
feat: Check CPU core configuration (#196) 2025-03-13 10:47:59 +01:00
Kroese
a63295d1c1
build: Update noVNC to v1.6.0 (#195) 2025-03-12 21:36:55 +01:00
Kroese
ca83662154
feat: Validate specified size (#194) 2025-03-12 21:12:16 +01:00
Kroese
edac315970
docs: Use relative paths (#193) 2025-03-12 17:10:00 +01:00
Kroese
1eaf327d19
docs: Kubernetes deployment (#192) 2025-03-07 00:43:06 +01:00
Kroese
2d56154644
fix: Network shutdown (#191) 2025-03-05 04:59:09 +01:00
Kroese
65cea83713
fix: Do not set MTU size for legacy Windows versions (#190) 2025-03-04 15:38:28 +01:00
Kroese
3ea684141d
fix: Gateway MAC generation (#189) 2025-03-03 13:54:59 +01:00
Kroese
bb77556ae8
feat: Set MTU size for TAP interface (#188) 2025-03-03 13:41:36 +01:00
Kroese
79b8aad8f3
feat: Automaticly match MTU size (#187) 2025-03-03 12:21:03 +01:00
Kroese
e2c5182162
docs: Readme (#186) 2025-03-01 14:21:00 +01:00
Kroese
0188a8f8a4
docs: Readme (#185) 2025-03-01 14:16:07 +01:00
Kroese
65fd7c839c
feat: Check path to boot.iso (#184) 2025-02-28 03:55:17 +01:00
Kroese
03115137c8
feat: Allow bridge networks (#183) 2025-02-27 11:51:38 +01:00
Kroese
cef08413e3
fix: Add e2fsprogs package (#182) 2025-02-26 22:28:31 +01:00
Kroese
50831e9f17
docs: Update links (#181) 2025-02-25 15:43:20 +01:00
Kroese
63afa68a5c
feat: Make app name configurable (#180) 2025-02-25 15:10:56 +01:00
Kroese
69ece08bcc
fix: Generate local MAC address (#179) 2025-02-25 05:50:39 +01:00
Kroese
71810373f9
fix: Preserve gateway MAC address (#178) 2025-02-24 03:36:28 +01:00
Kroese
14a0beddf2
feat: Add restart policy (#177) 2025-02-17 09:12:41 +01:00
Kroese
eb2c9cf437
feat: Implement password protection (#176) 2025-02-15 04:35:03 +01:00
Kroese
724a8cb720
feat: Implement password protection (#175) 2025-02-15 02:23:04 +01:00
Kroese
885ca224ff
feat: Remove existing TAP interface (#174) 2025-02-14 20:17:50 +01:00
Kroese
2f0bc64fd5
docs: Add restart policy (#173) 2025-02-10 00:16:57 +01:00
Kroese
4cbec8a9b5
feat: Improve CPU detection (#172) 2025-02-06 01:50:29 +01:00
Kroese
2ff8e929b5
feat: Remove fixed addressing (#171) 2025-01-15 23:14:48 +01:00
Kroese
cb548a0cfb
fix: Display fallback (#170) 2024-12-20 15:02:20 +01:00
Kroese
1091fc9dca
fix: TUN device error (#168) 2024-12-03 11:46:32 +01:00
Kroese
5b3a1d3fc1
docs: Add TUN device (#167) 2024-12-01 17:37:51 +01:00
Kroese
55db344c71
feat: Make network adapter configurable (#166) 2024-11-26 20:00:09 +01:00
Kroese
9ec698830e
feat: Improved network error handling (#165) 2024-11-20 16:24:50 +01:00
Kroese
ded63e0e52
feat: Improve CPU detection (#164) 2024-11-18 13:33:12 +01:00
Kroese
cc57dce4d1
feat: Use relative paths for noVNC (#163) 2024-11-15 04:31:39 +01:00
Kroese
57c5812085
feat: Support UUID flag (#162) 2024-11-15 04:14:39 +01:00
Kroese
68710fa750
docs: Compatibility chart (#161) 2024-11-13 03:39:24 +01:00
Kroese
d949351542
docs: Add Kubernetes URL (#160) 2024-11-13 03:38:26 +01:00
Kroese
42f5e53211
docs: Add compatibility chart (#159) 2024-11-13 03:28:06 +01:00
Kroese
608fb6bb25
fix: Disable HTTP keepalives (#158) 2024-11-13 02:49:07 +01:00
Kroese
06a7ea9090
docs: Readme (#157) 2024-11-13 00:33:02 +01:00
Kroese
4d1c1c476b
feat: Support image commit (#156) 2024-11-13 00:26:59 +01:00
Kroese
c244483847
feat: Rename host to kernel (#155) 2024-11-11 16:26:51 +01:00
Kroese
508ed449c4
docs: KVM troubleshooting (#154) 2024-11-11 14:22:22 +01:00
Kroese
8d3e2d8216
docs: Display output information (#153) 2024-11-11 13:01:45 +01:00
Kroese
64cb61d439
docs: Display output information (#152) 2024-11-11 12:52:51 +01:00
Kroese
5984834dbf
feat: Display unknown filesystem (#151) 2024-11-10 14:59:00 +01:00
Kroese
9c6fbe9ea8
feat: Improve CPU detection (#150) 2024-11-10 11:20:22 +01:00
Kroese
52c89503cc
feat: Use automatic CD-ROM interface for legacy boot (#149) 2024-11-10 11:19:20 +01:00
Kroese
e6af7e9782
feat: Make USB optional (#148) 2024-10-19 22:17:06 +02:00
Kroese
57f20481c7
feat: Make USB optional (#147) 2024-10-19 22:08:57 +02:00
Kroese
71eaf160f7
build: Use latest Debian image (#146) 2024-10-19 22:04:47 +02:00
Kroese
944924ab95
feat: Improve CPU detection (#145) 2024-10-15 10:29:02 +02:00
Kroese
518b815ba2
feat: Improve CPU detection (#144) 2024-10-14 18:47:24 +02:00
Kroese
26403222ba
feat: Support Rockchip Orange Pi 5 Plus (#143) 2024-10-13 00:30:58 +02:00
Kroese
3f3d32f820
feat: Add NVME disk type (#142) 2024-10-07 15:14:33 +02:00
Kroese
a7a6d0a7ee
feat: Add NVME device (#141) 2024-10-07 14:26:23 +02:00
Kroese
40e583f1b4
fix: Remove scsi parameter from virtio-blk-pci (#140) 2024-10-01 21:52:59 +02:00
Kroese
50ddafa884
build: Pin Debian version (#139) 2024-09-27 14:39:52 +02:00
Kroese
e1703d1493
fix: Split ports correctly (#138) 2024-09-10 13:06:55 +02:00
Kroese
9ed7b80038
fix: Port forwarding warning (#137) 2024-09-05 18:53:57 +02:00
Kroese
d842775e28
docs: Update package URL (#136) 2024-09-03 15:12:56 +02:00
Kroese
7e45d9fd30
docs: Update package URL (#135) 2024-08-27 18:03:33 +02:00
Kroese
4142b4ac5b
fix: Progress calculation (#134) 2024-08-18 17:53:59 +02:00
Kroese
6595bc7c34
fix: Check lscpu output (#133) 2024-08-18 03:30:59 +02:00
Kroese
540821ce5d
build: Environment variables (#132) 2024-08-18 02:12:14 +02:00
Kroese
49e41f2a1e
docs: Fix badge (#131) 2024-08-13 20:54:59 +02:00
Kroese
1438222f1c
build: Update noVNC to v1.5.0 (#130) 2024-06-18 16:45:52 +02:00
dependabot[bot]
f9fa7efd71
build(deps): Bump docker/build-push-action from 5 to 6 (#128)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 12:17:42 +02:00
Kroese
0f50e3d4be
docs: Networking (#127) 2024-06-16 06:20:45 +02:00
Kroese
36dac0f0bf
fix: Don't set script with file descriptor (#125) 2024-06-14 04:42:33 +02:00
Kroese
1e851b3c82
docs: Features (#124) 2024-06-14 04:03:45 +02:00
Kroese
c0e935daa6
feat: Create data disk for external image (#123) 2024-06-14 02:49:45 +02:00
Kroese
25d033632f
docs: Removed Kubevirt dependancy (#121) 2024-06-13 19:47:24 +02:00
Kroese
cea30ec530
docs: Relative links (#122) 2024-06-13 19:46:31 +02:00
Kroese
91b1d23aa3
fix: Assume GB when no unit is present (#120) 2024-06-13 19:01:45 +02:00
Kroese
4e5cfa4eb7
docs: Add markdown alerts (#119) 2024-06-13 18:47:37 +02:00
Kroese
c6ed03f331
feat: Support download of disk images (#118) 2024-06-12 22:36:39 +02:00
Kroese
bdd0f1a1a7
feat: Detect EFI-compatible images (#117) 2024-06-12 04:42:40 +02:00
Kroese
c2a7932d8e
docs: Add GHCR badge (#116) 2024-06-11 23:38:34 +02:00
Kroese
e6c610a4e8
docs: Add GHCR badge (#115) 2024-06-11 23:33:01 +02:00
Kroese
642979e03c
docs: Features (#114) 2024-06-11 23:06:59 +02:00
Kroese
130d032614
docs: Features (#113) 2024-06-11 22:38:29 +02:00
Kroese
6e5de3669b
docs: Readme (#112) 2024-06-11 22:01:58 +02:00
Kroese
78e66a7f99
docs: Add icons (#111) 2024-06-11 21:08:26 +02:00
Kroese
0caf956e17
docs: KVM information (#110) 2024-06-11 19:53:10 +02:00
Kroese
4d65cd247a
feat: Implement usermode networking (#109) 2024-06-11 01:46:34 +02:00
Kroese
9a04245ed2
docs: Readme (#108) 2024-06-09 22:14:09 +02:00
Kroese
e8d407938c
fix: Do not use IO threading for SATA disks (#107) 2024-06-09 18:33:32 +02:00
Kroese
392ae1bfe1
feat: Use SATA disks for legacy devices (#105) 2024-06-09 17:28:28 +02:00
Kroese
e38d479a37
docs: Mention Windows container (#104) 2024-06-08 18:48:43 +02:00
Kroese
159402de8f
fix: CPU pinning for Orange Pi (#103) 2024-06-07 13:08:30 +02:00
Kroese
89e46404f5
feat: Use virtioblk for CD-ROM devices (#102) 2024-06-05 17:53:12 +02:00
Kroese
e7b7a7a83f
feat: Print QEMU version on boot (#100) 2024-06-02 20:58:07 +02:00
Kroese
781060bbd2
feat: CPU pinning on Rockchip Orange Pi 5 (#99) 2024-06-02 19:47:46 +02:00
Kroese
b862a76ba1
feat: CPU pinning for Rockchip Orange Pi 5 (#98) 2024-06-02 19:38:14 +02:00
Kroese
d530bc26d4
feat: Add automatic device type (#97) 2024-05-26 22:57:27 +02:00
Kroese
9eb0b703f1
fix: Do not ignore unrecognized bootmodes (#96) 2024-05-26 13:34:43 +02:00
Kroese
7234632a74
docs: Updated issue templates (#95) 2024-05-25 14:09:03 +02:00
Kroese
07fbc9f8d1
docs: Resource limits (#93) 2024-05-25 12:46:26 +02:00
Kroese
528cce9d1a
feat: Mount drivers ISO (#94) 2024-05-25 12:46:06 +02:00
Kroese
2314ad8dca
feat: Mount additional ISO (#92) 2024-05-24 22:17:48 +02:00
Kroese
09694075b6
feat: Detect number of physical CPU sockets (#91) 2024-05-23 02:22:58 +02:00
Kroese
08cc4a7cf1
fix: Detect device type from machine (#90) 2024-05-22 21:17:18 +02:00
Kroese
6e2e6acfd7
docs: Drivers (#89) 2024-05-22 21:12:53 +02:00
Kroese
6ca072aae4
feat: Detect empty boot variable (#88) 2024-05-22 17:02:38 +02:00
Kroese
e9087a6eb3
feat: Allow booting without ISO file (#87) 2024-05-22 12:19:54 +02:00
Kroese
95b8acc301
docs: Docker CLI example (#86) 2024-05-22 07:57:17 +02:00
Kroese
7d3dc13958
fix: Don't mount cd-rom when empty (#85) 2024-05-21 13:05:59 +02:00
Kroese
e40ae8d06c
feat: Add support for USB booting (#84) 2024-05-21 12:12:43 +02:00
Kroese
38830c6f7a
feat: Add support for USB booting (#83) 2024-05-21 12:00:45 +02:00
Kroese
5eb3645401
feat: Add support for IDE drives (#82) 2024-05-21 09:29:46 +02:00
Kroese
79a75ee9f5
feat: Add support for IDE disk drives (#81) 2024-05-21 09:28:12 +02:00
Kroese
97b4a558df
feat: Support Kubernetes interfaces (#80) 2024-05-21 07:54:54 +02:00
20 changed files with 471 additions and 1427 deletions

6
.devcontainer.json Normal file
View file

@ -0,0 +1,6 @@
{
"name": "qemu",
"service": "qemu",
"forwardPorts": [8006],
"dockerComposeFile": "compose.yml"
}

View file

@ -1,35 +1,12 @@
name: "\U0001F6A8 Technical issue" name: "\U0001F6A8 Technical issue"
description: When you're experiencing problems using the container description: When you're experiencing problems using the container
body: body:
- type: checkboxes
attributes:
label: Is there no existing issue for this?
description: Please search to see if no solution was already provided before.
options:
- label: I have searched the existing issues
required: true
- type: input
id: cpu
attributes:
label: Machine specifications
description: The processor and RAM amount in your machine.
placeholder: e.g. Raspberry Pi 5 / 8 GB
validations:
required: true
- type: input - type: input
id: os id: os
attributes: attributes:
label: Operating system label: Operating system
description: The distribution and kernel version (as shown by `uname -a`). description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04 / Kernel 6.8.0-22-generic placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: input
id: docker
attributes:
label: Docker version
description: The version of the Docker engine (as shown by `docker -v`).
placeholder: e.g. 26.0.1
validations: validations:
required: true required: true
- type: textarea - type: textarea
@ -44,6 +21,7 @@ body:
attributes: attributes:
label: Docker compose label: Docker compose
description: The compose file (or otherwise the `docker run` command used). description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations: validations:
required: true required: true
- type: textarea - type: textarea
@ -51,6 +29,7 @@ body:
attributes: attributes:
label: Docker log label: Docker log
description: The logfile of the container (as shown by `docker logs qemu`). description: The logfile of the container (as shown by `docker logs qemu`).
render: shell
validations: validations:
required: true required: true
- type: textarea - type: textarea

View file

@ -3,13 +3,6 @@ description: Suggest an idea for improving the container
title: "[Feature]: " title: "[Feature]: "
labels: ["enhancement"] labels: ["enhancement"]
body: body:
- type: checkboxes
attributes:
label: Is there no existing feature request for this?
description: Please search to see if the feature was not already requested before.
options:
- label: I have searched the existing feature requests
required: true
- type: textarea - type: textarea
id: problem id: problem
attributes: attributes:

View file

@ -3,35 +3,12 @@ description: Create a report to help us improve the container
title: "[Bug]: " title: "[Bug]: "
labels: ["bug"] labels: ["bug"]
body: body:
- type: checkboxes
attributes:
label: Is there no existing bug report for this?
description: Please search to see if the bug was not already reported before.
options:
- label: I have searched the existing bug reports
required: true
- type: input
id: cpu
attributes:
label: Machine specifications
description: The processor and RAM amount in your machine.
placeholder: e.g. Raspberry Pi 5 / 8 GB
validations:
required: true
- type: input - type: input
id: os id: os
attributes: attributes:
label: Operating system label: Operating system
description: The distribution and kernel version (as shown by `uname -a`). description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04 / Kernel 6.8.0-22-generic placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: input
id: docker
attributes:
label: Docker version
description: The version of the Docker engine (as shown by `docker -v`).
placeholder: e.g. 26.0.1
validations: validations:
required: true required: true
- type: textarea - type: textarea
@ -46,6 +23,7 @@ body:
attributes: attributes:
label: Docker compose label: Docker compose
description: The compose file (or otherwise the `docker run` command used). description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations: validations:
required: true required: true
- type: textarea - type: textarea
@ -53,6 +31,7 @@ body:
attributes: attributes:
label: Docker log label: Docker log
description: The logfile of the container (as shown by `docker logs qemu`). description: The logfile of the container (as shown by `docker logs qemu`).
render: shell
validations: validations:
required: true required: true
- type: textarea - type: textarea

View file

@ -46,16 +46,16 @@ jobs:
with: with:
context: git context: git
images: | images: |
${{ secrets.DOCKERHUB_REPO }}
ghcr.io/${{ github.repository }} ghcr.io/${{ github.repository }}
${{ secrets.DOCKERHUB_REPO }}
tags: | tags: |
type=raw,value=latest,priority=100 type=raw,value=latest,priority=100
type=raw,value=${{ vars.MAJOR }}.${{ vars.MINOR }} type=raw,value=${{ vars.MAJOR }}.${{ vars.MINOR }}
labels: | labels: |
org.opencontainers.image.title=${{ vars.NAME }} org.opencontainers.image.title=${{ vars.NAME }}
env: env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- -
@ -73,7 +73,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- -
name: Build Docker image name: Build Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v6
with: with:
context: . context: .
push: true push: true
@ -112,6 +112,6 @@ jobs:
connection_url: ${{secrets.MAIL_CONNECTION}} connection_url: ${{secrets.MAIL_CONNECTION}}
subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed
body: | body: |
The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully! The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully!
See https://github.com/${{ github.repository }}/actions for more information. See https://github.com/${{ github.repository }}/actions for more information.

View file

@ -14,7 +14,7 @@ jobs:
name: Run ShellCheck name: Run ShellCheck
uses: ludeeus/action-shellcheck@master uses: ludeeus/action-shellcheck@master
env: env:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 SHELLCHECK_OPTS: -x --source-path=src -e SC1091 -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153
- -
name: Lint Dockerfile name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.1.0 uses: hadolint/hadolint-action@v3.1.0

View file

@ -1,7 +1,10 @@
ARG VERSION_ARG="latest"
FROM qemux/qemu:${VERSION_ARG} AS src
FROM debian:trixie-slim FROM debian:trixie-slim
ARG VERSION_ARG="0.0" ARG VERSION_ARG="0.0"
ARG VERSION_VNC="1.4.0" ARG VERSION_VNC="1.6.0"
ARG DEBCONF_NOWARNINGS="yes" ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive" ARG DEBIAN_FRONTEND="noninteractive"
@ -10,8 +13,13 @@ ARG DEBCONF_NONINTERACTIVE_SEEN="true"
RUN set -eu && \ RUN set -eu && \
apt-get update && \ apt-get update && \
apt-get --no-install-recommends -y install \ apt-get --no-install-recommends -y install \
bc \
jq \
tini \ tini \
wget \ wget \
7zip \
curl \
fdisk \
nginx \ nginx \
procps \ procps \
seabios \ seabios \
@ -19,13 +27,19 @@ RUN set -eu && \
iproute2 \ iproute2 \
apt-utils \ apt-utils \
dnsmasq \ dnsmasq \
xz-utils \
net-tools \ net-tools \
e2fsprogs \
qemu-utils \ qemu-utils \
iputils-ping \
genisoimage \
ca-certificates \ ca-certificates \
netcat-openbsd \ qemu-system-arm && \
qemu-system-arm \
qemu-efi-aarch64 && \
apt-get clean && \ apt-get clean && \
mkdir -p /etc/qemu && \
echo "allow br0" > /etc/qemu/bridge.conf && \
wget "https://snapshot.debian.org/archive/debian/20250128T092032Z/pool/main/e/edk2/qemu-efi-aarch64_2024.11-5_all.deb" -O /tmp/aavmf.deb -q --timeout=10 && \
dpkg -i /tmp/aavmf.deb && \
mkdir -p /usr/share/novnc && \ mkdir -p /usr/share/novnc && \
wget "https://github.com/novnc/noVNC/archive/refs/tags/v${VERSION_VNC}.tar.gz" -O /tmp/novnc.tar.gz -q --timeout=10 && \ wget "https://github.com/novnc/noVNC/archive/refs/tags/v${VERSION_VNC}.tar.gz" -O /tmp/novnc.tar.gz -q --timeout=10 && \
tar -xf /tmp/novnc.tar.gz -C /tmp/ && \ tar -xf /tmp/novnc.tar.gz -C /tmp/ && \
@ -36,20 +50,19 @@ RUN set -eu && \
echo "$VERSION_ARG" > /run/version && \ echo "$VERSION_ARG" > /run/version && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY --chmod=755 ./src /run/ COPY --from=src /run/*.sh /run
COPY --from=src /var/www /var/www
COPY --from=src /usr/share/novnc /usr/share/novnc
COPY --from=src /etc/nginx/sites-enabled /etc/nginx/sites-enabled
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu-docker/master/web/index.html /var/www/index.html COPY --chmod=755 ./src /run/
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu-docker/master/web/js/script.js /var/www/js/script.js
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu-docker/master/web/css/style.css /var/www/css/style.css
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu-docker/master/web/img/favicon.svg /var/www/img/favicon.svg
ADD --chmod=744 https://raw.githubusercontent.com/qemus/qemu-docker/master/web/nginx.conf /etc/nginx/sites-enabled/web.conf
VOLUME /storage VOLUME /storage
EXPOSE 22 5900 8006 EXPOSE 22 5900 8006
ENV CPU_CORES "1" ENV BOOT="alpine"
ENV RAM_SIZE "1G" ENV CPU_CORES="2"
ENV DISK_SIZE "16G" ENV RAM_SIZE="2G"
ENV BOOT "http://example.com/image.iso" ENV DISK_SIZE="16G"
ENTRYPOINT ["/usr/bin/tini", "-s", "/run/entry.sh"] ENTRYPOINT ["/usr/bin/tini", "-s", "/run/entry.sh"]

View file

@ -3,11 +3,15 @@ services:
container_name: qemu container_name: qemu
image: qemux/qemu-arm image: qemux/qemu-arm
environment: environment:
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" BOOT: "alpine"
devices: devices:
- /dev/kvm - /dev/kvm
- /dev/net/tun
cap_add: cap_add:
- NET_ADMIN - NET_ADMIN
ports: ports:
- 8006:8006 - 8006:8006
volumes:
- ./qemu:/storage
restart: always
stop_grace_period: 2m stop_grace_period: 2m

View file

@ -1,61 +1,86 @@
---
apiVersion: v1 apiVersion: v1
kind: PersistentVolumeClaim kind: PersistentVolumeClaim
metadata: metadata:
name: qemu-pvc name: qemu-pvc
spec: spec:
accessModes: accessModes:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: 16Gi storage: 16Gi
--- ---
apiVersion: v1 apiVersion: apps/v1
kind: Pod kind: Deployment
metadata: metadata:
name: qemu name: qemu
labels: labels:
name: qemu name: qemu
spec: spec:
terminationGracePeriodSeconds: 120 # the Kubernetes default is 30 seconds and it may be not enough replicas: 1
containers: selector:
- name: qemu matchLabels:
image: qemux/qemu-arm app: qemu
ports: template:
- containerPort: 8006 metadata:
protocol: TCP labels:
resources: app: qemu
limits: spec:
devices.kubevirt.io/kvm: 1 containers:
securityContext: - name: qemu
privileged: true image: qemux/qemu-arm
env: env:
- name: BOOT - name: BOOT
value: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" value: "alpine"
- name: RAM_SIZE
value: 1G
- name: CPU_CORES
value: "1"
- name: DISK_SIZE - name: DISK_SIZE
value: "16G" value: "16G"
volumeMounts: ports:
- containerPort: 8006
name: http
protocol: TCP
- containerPort: 5900
name: vnc
protocol: TCP
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- mountPath: /storage - mountPath: /storage
name: storage name: storage
volumes: - mountPath: /dev/kvm
- name: storage name: dev-kvm
persistentVolumeClaim: - mountPath: /dev/net/tun
claimName: qemu-pvc name: dev-tun
terminationGracePeriodSeconds: 120
volumes:
- name: storage
persistentVolumeClaim:
claimName: qemu-pvc
- hostPath:
path: /dev/kvm
name: dev-kvm
- hostPath:
path: /dev/net/tun
type: CharDevice
name: dev-tun
--- ---
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: qemu name: qemu
spec: spec:
type: NodePort internalTrafficPolicy: Cluster
selector:
name: qemu
ports: ports:
- name: tcp-8006 - name: http
protocol: TCP
port: 8006 port: 8006
protocol: TCP
targetPort: 8006 targetPort: 8006
nodePort: 48006 - name: vnc
port: 5900
protocol: TCP
targetPort: 5900
selector:
app: qemu
type: ClusterIP

248
readme.md
View file

@ -7,25 +7,24 @@
[![Build]][build_url] [![Build]][build_url]
[![Version]][tag_url] [![Version]][tag_url]
[![Size]][tag_url] [![Size]][tag_url]
[![Package]][pkg_url]
[![Pulls]][hub_url] [![Pulls]][hub_url]
</div></h1> </div></h1>
QEMU in a docker container for running ARM-based virtual machines, for devices like the Raspberry Pi 5 and many others. Docker container for running ARM-based virtual machines using QEMU, for devices like the Raspberry Pi 5 and many others.
It uses high-performance QEMU options (like KVM acceleration, kernel-mode networking, IO threading, etc.) to achieve near-native speed. ## Features ✨
Note: for KVM acceleration you need a Linux-based operating system, as it's not available on MacOS unfortunately. - Web-based viewer to control the machine directly from your browser
## Features - Supports `.iso`, `.img`, `.qcow2`, `.vhd`, `.vhdx`, `.vdi`, `.vmdk` and `.raw` disk formats
- Multi-platform - High-performance options (like KVM acceleration, kernel-mode networking, IO threading, etc.) to achieve near-native speed
- KVM acceleration
- Web-based viewer
## Usage ## Usage 🐳
Via Docker Compose: ##### Via Docker Compose:
```yaml ```yaml
services: services:
@ -33,54 +32,122 @@ services:
container_name: qemu container_name: qemu
image: qemux/qemu-arm image: qemux/qemu-arm
environment: environment:
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" BOOT: "alpine"
devices: devices:
- /dev/kvm - /dev/kvm
- /dev/net/tun
cap_add: cap_add:
- NET_ADMIN - NET_ADMIN
ports: ports:
- 8006:8006 - 8006:8006
volumes:
- ./qemu:/storage
restart: always
stop_grace_period: 2m stop_grace_period: 2m
``` ```
Via Docker CLI: ##### Via Docker CLI:
```bash ```bash
docker run -it --name qemu -e "BOOT=http://example.com/image.iso" -p 8006:8006 --device=/dev/kvm --cap-add NET_ADMIN qemux/qemu-arm docker run -it --rm --name qemu -e "BOOT=alpine" -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/qemu:/storage" --stop-timeout 120 qemux/qemu-arm
``` ```
Via Kubernetes: ##### Via Kubernetes:
```shell ```shell
kubectl apply -f kubernetes.yml kubectl apply -f https://raw.githubusercontent.com/qemus/qemu-arm/refs/heads/master/kubernetes.yml
``` ```
## FAQ ##### Via Github Codespaces:
* ### How do I use it? [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/qemus/qemu)
## FAQ 💬
### How do I use it?
Very simple! These are the steps: Very simple! These are the steps:
- Set the `BOOT` environment variable to the URL of an ISO image you want to install. - Set the `BOOT` variable to the [operating system](#how-do-i-select-the-operating-system) you want to install.
- Start the container and connect to [port 8006](http://localhost:8006) using your web browser. - Start the container and connect to [port 8006](http://127.0.0.1:8006/) using your web browser.
- You will see the screen and can now install the OS of your choice using your keyboard and mouse. - You will see the screen and can now install the OS of your choice using your keyboard and mouse.
Enjoy your brand new machine, and don't forget to star this repo! Enjoy your brand new machine, and don't forget to star this repo!
* ### How do I change the storage location? ### How do I select the operating system?
You can use the `BOOT` environment variable in order to specify the operating system that will be downloaded:
```yaml
environment:
BOOT: "alpine"
```
Select from the values below:
| **Value** | **Operating System** | **Size** |
|---|---|---|
| `alma` | Alma Linux | 1.7 GB |
| `alpine` | Alpine Linux | 60 MB |
| `cachy` | CachyOS | 2.6 GB |
| `centos` | CentOS | 6.4 GB |
| `debian` | Debian | 3.7 GB |
| `fedora` | Fedora | 2.9 GB |
| `gentoo` | Gentoo | 1.3 GB |
| `kali` | Kali Linux | 3.4 GB |
| `nixos` | NixOS | 2.4 GB |
| `suse` | OpenSUSE | 1.0 GB |
| `oracle` | Oracle Linux | 1.0 GB |
| `rocky` | Rocky Linux | 1.9 GB |
| `ubuntu` | Ubuntu Desktop | 3.3 GB |
| `ubuntus` | Ubuntu Server | 2.7 GB |
### How can I use my own image?
If you want to download an operating system that is not in the list above, you can set the `BOOT` variable to the URL of the image:
```yaml
environment:
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso"
```
The `BOOT` URL accepts files in any of the following formats:
| **Extension** | **Format** |
|---|---|
| `.img` | Raw |
| `.raw` | Raw |
| `.iso` | Optical |
| `.qcow2` | QEMU |
| `.vmdk` | VMware |
| `.vhd` | VirtualPC |
| `.vhdx` | Hyper-V |
| `.vdi` | VirtualBox |
It will also accept files such as `.img.gz`, `.qcow2.xz`, `.iso.zip` and many more, because it will automaticly extract compressed files.
Alternatively you can use a local image file directly, by binding it in your compose file:
```yaml
volumes:
- ./example.iso:/boot.iso
```
This way you can supply either a `/boot.iso`, `/boot.img` or a `/boot.qcow2` file. The value of `BOOT` will be ignored in this case.
### How do I change the storage location?
To change the storage location, include the following bind mount in your compose file: To change the storage location, include the following bind mount in your compose file:
```yaml ```yaml
volumes: volumes:
- /var/qemu:/storage - ./qemu:/storage
``` ```
Replace the example path `/var/qemu` with the desired storage folder. Replace the example path `./qemu` with the desired storage folder or named volume.
* ### How do I change the size of the disk? ### How do I change the size of the disk?
To expand the default size of 16 GB, add the `DISK_SIZE` setting to your compose file and set it to your preferred capacity: To expand the default size of 16 GB, add the `DISK_SIZE` setting to your compose file and set it to your preferred capacity:
@ -89,47 +156,85 @@ kubectl apply -f kubernetes.yml
DISK_SIZE: "128G" DISK_SIZE: "128G"
``` ```
This can also be used to resize the existing disk to a larger capacity without any data loss. > [!TIP]
> This can also be used to resize the existing disk to a larger capacity without any data loss.
* ### How do I boot a local image? ### How do I change the amount of CPU or RAM?
By default, the container will be allowed to use a maximum of 2 CPU cores and 2 GB of RAM.
If you want to adjust this, you can specify the desired amount using the following environment variables:
You can use a local file directly, and skip the download altogether, by binding it in your compose file in this way:
```yaml ```yaml
volumes: environment:
- /home/user/example.iso:/boot.iso RAM_SIZE: "8G"
CPU_CORES: "4"
``` ```
Replace the example path `/home/user/example.iso` with the filename of the desired ISO file. ### How do I increase the display resolution?
* ### How do I boot a x86 image? For maximum compatibility, the display output will be a simple framebuffer by default. While this isn't the most optimal, it doesn't require any drivers.
If your guest OS bundles the `virtio-gpu` driver (as most Linux distributions do), you can add the following to your compose file:
You can use [qemu-docker](https://github.com/qemus/qemu-docker/) to run x86 and x64 images on ARM. ```yaml
environment:
VGA: "virtio-gpu"
```
* ### How do I verify if my system supports KVM? to add a virtual graphics cards to your machine that allows for higher resolutions.
> [!NOTE]
> Using this method your screen will stay black during the boot process, until the point where the driver is actually loaded.
### How do I boot Windows?
To verify if your system supports KVM, run the following commands: Use [dockur/windows-arm](https://github.com/dockur/windows-arm) instead, as it includes all the drivers required during installation, amongst many other features.
### How do I boot x86/x64 images?
You can use the [qemu](https://github.com/qemus/qemu/) container to run x86 and x64 images on ARM.
### How do I verify if my system supports KVM?
First check if your software is compatible using this chart:
| **Product** | **Linux** | **Win11** | **Win10** | **macOS** |
|---|---|---|---|---|
| Docker CLI | ✅ | ✅ | ❌ | ❌ |
| Docker Desktop | ❌ | ✅ | ❌ | ❌ |
| Podman CLI | ✅ | ✅ | ❌ | ❌ |
| Podman Desktop | ✅ | ✅ | ❌ | ❌ |
After that you can run the following commands in Linux to check your system:
```bash ```bash
sudo apt install cpu-checker sudo apt install cpu-checker
sudo kvm-ok sudo kvm-ok
``` ```
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS. If you receive an error from `kvm-ok` indicating that KVM cannot be used, please check whether:
* ### How do I increase the amount of CPU or RAM? - the virtualization extensions (`Intel VT-x` or `AMD SVM`) are enabled in your BIOS.
By default, a single CPU core and 1 GB of RAM are allocated to the container. - you enabled "nested virtualization" if you are running the container inside a virtual machine.
If there arises a need to increase this, add the following environment variables: - you are not using a cloud provider, as most of them do not allow nested virtualization for their VPS's.
```yaml If you did not receive any error from `kvm-ok` but the container still complains about a missing KVM device, it could help to add `privileged: true` to your compose file (or `sudo` to your `docker` command) to rule out any permission issue.
environment:
RAM_SIZE: "4G" ### How do I expose network ports?
CPU_CORES: "4"
```
* ### How do I assign an individual IP address to the container? You can expose ports just by adding them to your compose file. If you want to be able to connect to the SSH service of the machine for example, you would add it like this:
```yaml
ports:
- 2222:22
```
This will make port 2222 on your host redirect to port 22 of the virtual machine.
### How do I assign an individual IP address to the container?
By default, the container uses bridge networking, which shares the IP address with the host. By default, the container uses bridge networking, which shares the IP address with the host.
@ -163,13 +268,14 @@ kubectl apply -f kubernetes.yml
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default. An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround. > [!IMPORTANT]
> This IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
* ### How can the VM acquire an IP address from my router? ### How can the VM acquire an IP address from my router?
After configuring the container for macvlan (see above), it is possible for the VM to become part of your home network by requesting an IP from your router, just like a real PC. After configuring the container for [macvlan](#how-do-i-assign-an-individual-ip-address-to-the-container), it is possible for the VM to become part of your home network by requesting an IP from your router, just like a real PC.
To enable this mode, add the following lines to your compose file: To enable this mode, in which the container and the VM will have separate IP addresses, add the following lines to your compose file:
```yaml ```yaml
environment: environment:
@ -180,9 +286,7 @@ kubectl apply -f kubernetes.yml
- 'c *:* rwm' - 'c *:* rwm'
``` ```
Please note that in this mode, the container and the VM will each have their own separate IPs. The container will keep the macvlan IP, and the VM will use the DHCP IP. ### How do I add multiple disks?
* ### How do I add multiple disks?
To create additional disks, modify your compose file like this: To create additional disks, modify your compose file like this:
@ -191,23 +295,23 @@ kubectl apply -f kubernetes.yml
DISK2_SIZE: "32G" DISK2_SIZE: "32G"
DISK3_SIZE: "64G" DISK3_SIZE: "64G"
volumes: volumes:
- /home/example:/storage2 - ./example2:/storage2
- /mnt/data/example:/storage3 - ./example3:/storage3
``` ```
* ### How do I pass-through a disk? ### How do I pass-through a disk?
It is possible to pass-through disk devices directly by adding them to your compose file in this way: It is possible to pass-through disk devices or partitions directly by adding them to your compose file in this way:
```yaml ```yaml
devices: devices:
- /dev/sdb:/disk1 - /dev/sdb:/disk1
- /dev/sdc:/disk2 - /dev/sdc1:/disk2
``` ```
Use `/disk1` if you want it to become your main drive, and use `/disk2` and higher to add them as secondary drives. Use `/disk1` if you want it to become your main drive, and use `/disk2` and higher to add them as secondary drives.
* ### How do I pass-through a USB device? ### How do I pass-through a USB device?
To pass-through a USB device, first lookup its vendor and product id via the `lsusb` command, then add them to your compose file like this: To pass-through a USB device, first lookup its vendor and product id via the `lsusb` command, then add them to your compose file like this:
@ -218,7 +322,24 @@ kubectl apply -f kubernetes.yml
- /dev/bus/usb - /dev/bus/usb
``` ```
* ### How can I provide custom arguments to QEMU? ### How do I share files with the host?
To share files with the host, first ensure that your guest OS has `9pfs` support compiled in or available as a kernel module. If so, add the following volume to your compose file:
```yaml
volumes:
- ./example:/shared
```
Then start the container and execute the following command in the guest:
```shell
mount -t 9p -o trans=virtio shared /mnt/example
```
Now the `./example` directory on the host will be available as `/mnt/example` in the guest.
### How can I provide custom arguments to QEMU?
You can create the `ARGUMENTS` environment variable to provide additional arguments to QEMU at runtime: You can create the `ARGUMENTS` environment variable to provide additional arguments to QEMU at runtime:
@ -227,14 +348,23 @@ kubectl apply -f kubernetes.yml
ARGUMENTS: "-device usb-tablet" ARGUMENTS: "-device usb-tablet"
``` ```
## Stars If you want to see the full command-line arguments used, you can set:
```yaml
environment:
DEBUG: "Y"
```
## Stars 🌟
[![Stars](https://starchart.cc/qemus/qemu-arm.svg?variant=adaptive)](https://starchart.cc/qemus/qemu-arm) [![Stars](https://starchart.cc/qemus/qemu-arm.svg?variant=adaptive)](https://starchart.cc/qemus/qemu-arm)
[build_url]: https://github.com/qemus/qemu-arm/ [build_url]: https://github.com/qemus/qemu-arm/
[hub_url]: https://hub.docker.com/r/qemux/qemu-arm/ [hub_url]: https://hub.docker.com/r/qemux/qemu-arm/
[tag_url]: https://hub.docker.com/r/qemux/qemu-arm/tags [tag_url]: https://hub.docker.com/r/qemux/qemu-arm/tags
[pkg_url]: https://github.com/qemus/qemu-arm/pkgs/container/qemu-arm
[Build]: https://github.com/qemus/qemu-arm/actions/workflows/build.yml/badge.svg [Build]: https://github.com/qemus/qemu-arm/actions/workflows/build.yml/badge.svg
[Size]: https://img.shields.io/docker/image-size/qemux/qemu-arm/latest?color=066da5&label=size [Size]: https://img.shields.io/docker/image-size/qemux/qemu-arm/latest?color=066da5&label=size
[Pulls]: https://img.shields.io/docker/pulls/qemux/qemu-arm.svg?style=flat&label=pulls&logo=docker [Pulls]: https://img.shields.io/docker/pulls/qemux/qemu-arm.svg?style=flat&label=pulls&logo=docker
[Version]: https://img.shields.io/docker/v/qemux/qemu-arm/latest?arch=arm64&sort=semver&color=066da5 [Version]: https://img.shields.io/docker/v/qemux/qemu-arm/latest?arch=arm64&sort=semver&color=066da5
[Package]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fipitio.github.io%2Fbackage%2Fqemus%2Fqemu-arm%2Fqemu-arm.json&query=%24.downloads&logo=github&style=flat&color=066da5&label=pulls

View file

@ -2,69 +2,115 @@
set -Eeuo pipefail set -Eeuo pipefail
# Docker environment variables # Docker environment variables
: "${BIOS:=""}" # Bios file : "${BIOS:=""}" # BIOS file
: "${SECURE:="off"}" # Secure boot
BOOT_OPTS=""
BOOT_DESC="" BOOT_DESC=""
SECURE=",secure=off" BOOT_OPTS=""
DIR="/usr/share/qemu" [ -n "$BIOS" ] && BOOT_MODE="custom"
case "${BOOT_MODE,,}" in case "${BOOT_MODE,,}" in
uefi) "uefi" | "" )
BOOT_MODE="uefi"
ROM="AAVMF_CODE.no-secboot.fd" ROM="AAVMF_CODE.no-secboot.fd"
VARS="AAVMF_VARS.fd" VARS="AAVMF_VARS.fd"
;; ;;
secure) "secure" )
SECURE=",secure=on" SECURE="on"
BOOT_DESC=" securely" BOOT_DESC=" securely"
ROM="AAVMF_CODE.secboot.fd" ROM="AAVMF_CODE.secboot.fd"
VARS="AAVMF_VARS.fd" VARS="AAVMF_VARS.fd"
;; ;;
windows) "windows" )
ROM="AAVMF_CODE.no-secboot.fd" ROM="AAVMF_CODE.no-secboot.fd"
VARS="AAVMF_VARS.fd" VARS="AAVMF_VARS.fd"
BOOT_OPTS="-rtc base=localtime" BOOT_OPTS="-rtc base=localtime"
;; ;;
windows_secure) "windows_secure" )
SECURE=",secure=on" SECURE="on"
BOOT_DESC=" securely" BOOT_DESC=" securely"
ROM="AAVMF_CODE.ms.fd" ROM="AAVMF_CODE.ms.fd"
VARS="AAVMF_VARS.ms.fd" VARS="AAVMF_VARS.ms.fd"
BOOT_OPTS="-rtc base=localtime" BOOT_OPTS="-rtc base=localtime"
;; ;;
"legacy" )
BOOT_DESC=" with SeaBIOS"
;;
"custom" )
BOOT_OPTS="-bios $BIOS"
BOOT_DESC=" with custom BIOS file"
;;
*) *)
info "Unknown boot mode '${BOOT_MODE}', defaulting to 'uefi'" error "Unknown BOOT_MODE, value \"${BOOT_MODE}\" is not recognized!"
BOOT_MODE="uefi" exit 33
ROM="AAVMF_CODE.no-secboot.fd"
VARS="AAVMF_VARS.fd"
;; ;;
esac esac
if [ -n "$BIOS" ]; then case "${BOOT_MODE,,}" in
"uefi" | "secure" | "windows" | "windows_secure" )
BOOT_OPTS="$BOOT_OPTS -bios $DIR/$BIOS" AAVMF="/usr/share/AAVMF/"
return 0 DEST="$STORAGE/${BOOT_MODE,,}"
if [ ! -s "$DEST.rom" ] || [ ! -f "$DEST.rom" ]; then
[ ! -s "$AAVMF/$ROM" ] || [ ! -f "$AAVMF/$ROM" ] && error "UEFI boot file ($AAVMF/$ROM) not found!" && exit 44
rm -f "$DEST.rom"
dd if=/dev/zero "of=$DEST.rom" bs=1M count=64 status=none
dd "if=$AAVMF/$ROM" "of=$DEST.rom" conv=notrunc status=none
fi
if [ ! -s "$DEST.vars" ] || [ ! -f "$DEST.vars" ]; then
[ ! -s "$AAVMF/$VARS" ] || [ ! -f "$AAVMF/$VARS" ] && error "UEFI vars file ($AAVMF/$VARS) not found!" && exit 45
rm -f "$DEST.vars"
dd if=/dev/zero "of=$DEST.vars" bs=1M count=64 status=none
dd "if=$AAVMF/$VARS" "of=$DEST.vars" conv=notrunc status=none
fi
BOOT_OPTS+=" -drive file=$DEST.rom,if=pflash,unit=0,format=raw,readonly=on"
BOOT_OPTS+=" -drive file=$DEST.vars,if=pflash,unit=1,format=raw"
;;
esac
MSRS="/sys/module/kvm/parameters/ignore_msrs"
if [ -e "$MSRS" ]; then
result=$(<"$MSRS")
result="${result//[![:print:]]/}"
if [[ "$result" == "0" ]] || [[ "${result^^}" == "N" ]]; then
echo 1 | tee "$MSRS" > /dev/null 2>&1 || true
fi
fi fi
AAVMF="/usr/share/AAVMF/" CLOCKSOURCE="tsc"
DEST="$STORAGE/${BOOT_MODE,,}" [[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter"
CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource"
if [ ! -s "$DEST.rom" ] || [ ! -f "$DEST.rom" ]; then if [ ! -f "$CLOCK" ]; then
[ ! -s "$AAVMF/$ROM" ] || [ ! -f "$AAVMF/$ROM" ] && error "UEFI boot file ($AAVMF/$ROM) not found!" && exit 44 warn "file \"$CLOCK\" cannot not found?"
rm -f "$DEST.rom" else
dd if=/dev/zero "of=$DEST.rom" bs=1M count=64 status=none result=$(<"$CLOCK")
dd "if=$AAVMF/$ROM" "of=$DEST.rom" conv=notrunc status=none result="${result//[![:print:]]/}"
case "${result,,}" in
"${CLOCKSOURCE,,}" ) ;;
"kvm-clock" ) info "Nested KVM virtualization detected.." ;;
"hyperv_clocksource_tsc_page" ) info "Nested Hyper-V virtualization detected.." ;;
"hpet" ) warn "unsupported clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
*) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
esac
fi fi
if [ ! -s "$DEST.vars" ] || [ ! -f "$DEST.vars" ]; then SM_BIOS=""
[ ! -s "$AAVMF/$VARS" ] || [ ! -f "$AAVMF/$VARS" ] && error "UEFI vars file ($AAVMF/$VARS) not found!" && exit 45 PS="/sys/class/dmi/id/product_serial"
rm -f "$DEST.vars"
dd if=/dev/zero "of=$DEST.vars" bs=1M count=64 status=none
dd "if=$AAVMF/$VARS" "of=$DEST.vars" conv=notrunc status=none
fi
BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.rom,if=pflash,unit=0,format=raw,readonly=on" if [ -s "$PS" ] && [ -r "$PS" ]; then
BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.vars,if=pflash,unit=1,format=raw"
BIOS_SERIAL=$(<"$PS")
BIOS_SERIAL="${BIOS_SERIAL//[![:alnum:]]/}"
if [ -n "$BIOS_SERIAL" ]; then
SM_BIOS="-smbios type=1,serial=$BIOS_SERIAL"
fi
fi
return 0 return 0

View file

@ -1,22 +1,37 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
: "${UUID:=""}"
: "${SERIAL:="mon:stdio"}" : "${SERIAL:="mon:stdio"}"
: "${USB:="qemu-xhci,id=xhci"}" : "${USB:="qemu-xhci,id=xhci,p2=7,p3=7"}"
: "${MONITOR:="telnet:localhost:7100,server,nowait,nodelay"}" : "${MONITOR:="telnet:localhost:7100,server,nowait,nodelay"}"
: "${SMP:="$CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"}"
DEF_OPTS="-nodefaults" DEF_OPTS="-nodefaults"
SERIAL_OPTS="-serial $SERIAL" SERIAL_OPTS="-serial $SERIAL"
USB_OPTS="-device $USB -device usb-kbd -device usb-tablet" CPU_OPTS="-cpu $CPU_FLAGS -smp $SMP"
RAM_OPTS=$(echo "-m ${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g') RAM_OPTS=$(echo "-m ${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
CPU_OPTS="-cpu $CPU_FLAGS -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
MON_OPTS="-monitor $MONITOR -name $PROCESS,process=$PROCESS,debug-threads=on" MON_OPTS="-monitor $MONITOR -name $PROCESS,process=$PROCESS,debug-threads=on"
MAC_OPTS="-machine type=${MACHINE}${SECURE},dump-guest-core=off${KVM_OPTS}" MAC_OPTS="-machine type=${MACHINE},secure=${SECURE},dump-guest-core=off${KVM_OPTS}"
DEV_OPTS="-object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
[[ "${BOOT_MODE,,}" != "windows"* ]] && DEV_OPTS="$DEV_OPTS -device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $USB_OPTS $NET_OPTS $DISK_OPTS $BOOT_OPTS $DEV_OPTS $ARGUMENTS" [ -n "$UUID" ] && MAC_OPTS+=" -uuid $UUID"
[ -n "$SM_BIOS" ] && MAC_OPTS+=" $SM_BIOS"
DEV_OPTS="-object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0"
if [[ "${BOOT_MODE,,}" != "windows"* ]]; then
DEV_OPTS+=" -device virtio-balloon-pci,id=balloon0,bus=pcie.0"
fi
if [ -d "/shared" ] && [[ "${BOOT_MODE,,}" != "windows"* ]]; then
DEV_OPTS+=" -fsdev local,id=fsdev0,path=/shared,security_model=none"
DEV_OPTS+=" -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=shared"
fi
[ -n "$USB" ] && [[ "${USB,,}" != "no"* ]] && USB_OPTS="-device $USB -device usb-kbd -device usb-tablet"
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS ${USB_OPTS:-} $NET_OPTS $DISK_OPTS $BOOT_OPTS $DEV_OPTS $ARGUMENTS"
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ') ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
if [[ "${DISPLAY,,}" == "web" ]]; then if [[ "${DISPLAY,,}" == "web" ]]; then
@ -37,17 +52,27 @@ fi
if [[ "$RAM_CHECK" != [Nn]* ]]; then if [[ "$RAM_CHECK" != [Nn]* ]]; then
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}') RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
AVAIL_GB=$(( RAM_AVAIL/1073741824 )) AVAIL_MEM=$(formatBytes "$RAM_AVAIL")
if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
error "Your configured RAM_SIZE of $WANTED_GB GB is too high for the $AVAIL_GB GB of memory available, please set a lower value." msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $AVAIL_MEM of memory available, please set a lower value."
exit 17 [[ "${FS,,}" != "zfs" ]] && error "$msg" && exit 17
fi info "$msg"
else
if (( (RAM_WANTED + (RAM_SPARE * 3)) > RAM_AVAIL )); then if (( (RAM_WANTED + (RAM_SPARE * 3)) > RAM_AVAIL )); then
warn "your configured RAM_SIZE of $WANTED_GB GB is very close to the $AVAIL_GB GB of memory available, please consider a lower value." msg="your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is very close to the $AVAIL_MEM of memory available, please consider a lower value."
if [[ "${FS,,}" != "zfs" ]]; then
warn "$msg"
else
info "$msg"
fi
fi
fi fi
fi fi
if [[ "$DEBUG" == [Yy1]* ]]; then
printf "Arguments:\n\n%s\n\n" "${ARGS// -/$'\n-'}"
fi
return 0 return 0

View file

@ -1,537 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Docker environment variables
: "${DISK_IO:="native"}" # I/O Mode, can be set to 'native', 'threads' or 'io_turing'
: "${DISK_FMT:=""}" # Disk file format, can be set to "raw" (default) or "qcow2"
: "${DISK_FLAGS:=""}" # Specifies the options for use with the qcow2 disk format
: "${DISK_CACHE:="none"}" # Caching mode, can be set to 'writeback' for better performance
: "${DISK_DISCARD:="on"}" # Controls whether unmap (TRIM) commands are passed to the host.
: "${DISK_ROTATION:="1"}" # Rotation rate, set to 1 for SSD storage and increase for HDD
[ ! -f "$BOOT" ] || [ ! -s "$BOOT" ] && BOOT="/dev/null"
DISK_OPTS="-object iothread,id=io2"
DISK_OPTS="$DISK_OPTS -drive id=cdrom0,media=cdrom,if=none,format=raw,readonly=on,file=$BOOT"
DISK_OPTS="$DISK_OPTS -device virtio-scsi-pci,id=scsi0,iothread=io2,addr=0x5"
DISK_OPTS="$DISK_OPTS -device scsi-cd,bus=scsi0.0,drive=cdrom0,bootindex=$BOOT_INDEX"
DRIVERS="/drivers.iso"
[ ! -f "$DRIVERS" ] || [ ! -s "$DRIVERS" ] && DRIVERS="$STORAGE/drivers.iso"
[ ! -f "$DRIVERS" ] || [ ! -s "$DRIVERS" ] && DRIVERS="/run/drivers.iso"
if [ -f "$DRIVERS" ]; then
DISK_OPTS="$DISK_OPTS -drive id=cdrom1,media=cdrom,if=none,format=raw,readonly=on,file=$DRIVERS -device usb-storage,drive=cdrom1"
fi
fmt2ext() {
local DISK_FMT=$1
case "${DISK_FMT,,}" in
qcow2)
echo "qcow2"
;;
raw)
echo "img"
;;
*)
error "Unrecognized disk format: $DISK_FMT" && exit 78
;;
esac
}
ext2fmt() {
local DISK_EXT=$1
case "${DISK_EXT,,}" in
qcow2)
echo "qcow2"
;;
img)
echo "raw"
;;
*)
error "Unrecognized file extension: .$DISK_EXT" && exit 78
;;
esac
}
getSize() {
local DISK_FILE=$1
local DISK_EXT DISK_FMT
DISK_EXT=$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')
DISK_FMT=$(ext2fmt "$DISK_EXT")
case "${DISK_FMT,,}" in
raw)
stat -c%s "$DISK_FILE"
;;
qcow2)
qemu-img info "$DISK_FILE" -f "$DISK_FMT" | grep '^virtual size: ' | sed 's/.*(\(.*\) bytes)/\1/'
;;
*)
error "Unrecognized disk format: $DISK_FMT" && exit 78
;;
esac
}
isCow() {
local FS=$1
if [[ "${FS,,}" == "btrfs" ]]; then
return 0
fi
return 1
}
supportsDirect() {
local FS=$1
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
return 1
fi
return 0
}
createDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local DATA_SIZE DIR SPACE FA
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
rm -f "$DISK_FILE"
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Check free diskspace
DIR=$(dirname "$DISK_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( DATA_SIZE > SPACE )); then
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
error "Not enough free space to create a $DISK_DESC of $DISK_SPACE in $DIR, it has only $SPACE_GB GB available..."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
html "Creating a $DISK_DESC image..."
info "Creating a $DISK_SPACE $DISK_TYPE $DISK_DESC image in $DISK_FMT format..."
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
if isCow "$FS"; then
if ! touch "$DISK_FILE"; then
error "$FAIL" && exit 77
fi
{ chattr +C "$DISK_FILE"; } || :
fi
if [[ "$ALLOCATE" == [Nn]* ]]; then
# Create an empty file
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 77
fi
else
# Create an empty file
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 77
fi
fi
fi
;;
qcow2)
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
if ! qemu-img create -f "$DISK_FMT" -o "$DISK_PARAM" -- "$DISK_FILE" "$DATA_SIZE" ; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 70
fi
;;
esac
if isCow "$FS"; then
FA=$(lsattr "$DISK_FILE")
if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for $DISK_DESC image $DISK_FILE on ${FS^^} filesystem (returned $FA)"
fi
fi
return 0
}
resizeDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local CUR_SIZE DATA_SIZE DIR SPACE
CUR_SIZE=$(getSize "$DISK_FILE")
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
local REQ=$((DATA_SIZE-CUR_SIZE))
(( REQ < 1 )) && error "Shrinking disks is not supported yet, please increase ${DISK_DESC^^}_SIZE." && exit 71
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Check free diskspace
DIR=$(dirname "$DISK_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( REQ > SPACE )); then
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
error "Not enough free space to resize $DISK_DESC to $DISK_SPACE in $DIR, it has only $SPACE_GB GB available.."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 74
fi
fi
local GB=$(( (CUR_SIZE + 1073741823)/1073741824 ))
MSG="Resizing $DISK_DESC from ${GB}G to $DISK_SPACE..."
info "$MSG" && html "$MSG"
local FAIL="Could not resize the $DISK_TYPE $DISK_FMT $DISK_DESC image from ${GB}G to $DISK_SPACE ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
if [[ "$ALLOCATE" == [Nn]* ]]; then
# Resize file by changing its length
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
error "$FAIL" && exit 75
fi
else
# Resize file by allocating more space
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
error "$FAIL" && exit 75
fi
fi
fi
;;
qcow2)
if ! qemu-img resize -f "$DISK_FMT" "--$DISK_ALLOC" "$DISK_FILE" "$DATA_SIZE" ; then
error "$FAIL" && exit 72
fi
;;
esac
return 0
}
convertDisk() {
local SOURCE_FILE=$1
local SOURCE_FMT=$2
local DST_FILE=$3
local DST_FMT=$4
local DISK_BASE=$5
local DISK_DESC=$6
local FS=$7
[ -f "$DST_FILE" ] && error "Conversion failed, destination file $DST_FILE already exists?" && exit 79
[ ! -f "$SOURCE_FILE" ] && error "Conversion failed, source file $SOURCE_FILE does not exists?" && exit 79
local TMP_FILE="$DISK_BASE.tmp"
rm -f "$TMP_FILE"
if [[ "$ALLOCATE" != [Nn]* ]]; then
local DIR CUR_SIZE SPACE
# Check free diskspace
DIR=$(dirname "$TMP_FILE")
CUR_SIZE=$(getSize "$SOURCE_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( CUR_SIZE > SPACE )); then
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $DIR, it has only $SPACE_GB GB available..."
error "Please free up some disk space or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
html "Converting $DISK_DESC to $DST_FMT..."
info "Converting $DISK_DESC to $DST_FMT, please wait until completed..."
local CONV_FLAGS="-p"
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
if [[ "$DST_FMT" != "raw" ]]; then
if [[ "$ALLOCATE" == [Nn]* ]]; then
CONV_FLAGS="$CONV_FLAGS -c"
fi
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
fi
# shellcheck disable=SC2086
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
rm -f "$TMP_FILE"
error "Failed to convert $DISK_TYPE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
fi
if [[ "$DST_FMT" == "raw" ]]; then
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Work around qemu-img bug
CUR_SIZE=$(stat -c%s "$TMP_FILE")
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE"; then
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
fi
fi
fi
rm -f "$SOURCE_FILE"
mv "$TMP_FILE" "$DST_FILE"
if isCow "$FS"; then
FA=$(lsattr "$DST_FILE")
if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for $DISK_DESC image $DST_FILE on ${FS^^} filesystem (returned $FA)"
fi
fi
html "Conversion of $DISK_DESC completed..."
info "Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
return 0
}
checkFS () {
local FS=$1
local DISK_FILE=$2
local DISK_DESC=$3
local DIR FA
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
if [[ "${FS,,}" == "overlay"* ]]; then
info "Warning: the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
fi
if [[ "${FS,,}" == "fuse"* ]]; then
info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
fi
if ! supportsDirect "$FS"; then
info "Warning: the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if isCow "$FS"; then
if [ -f "$DISK_FILE" ]; then
FA=$(lsattr "$DISK_FILE")
if [[ "$FA" != *"C"* ]]; then
info "Warning: COW (copy on write) is not disabled for $DISK_DESC image file $DISK_FILE, this is recommended on ${FS^^} filesystems!"
fi
fi
fi
return 0
}
createDevice () {
local DISK_ID=$1
local DISK_FILE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local DISK_FMT=$5
local DISK_IO=$6
local DISK_CACHE=$7
local result="-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on"
result="$result \
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
echo "$result"
return 0
}
addDisk () {
local DISK_BASE=$1
local DISK_EXT=$2
local DISK_DESC=$3
local DISK_SPACE=$4
local DISK_INDEX=$5
local DISK_ADDRESS=$6
local DISK_FMT=$7
local DISK_IO=$8
local DISK_CACHE=$9
local DISK_ID="userdata$DISK_INDEX"
local DISK_FILE="$DISK_BASE.$DISK_EXT"
local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE OPTS
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
[ -z "$DISK_SPACE" ] && DISK_SPACE="16G"
DISK_SPACE=$(echo "${DISK_SPACE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
if (( DATA_SIZE < 1 )); then
error "Invalid value for ${DISK_DESC^^}_SIZE: $DISK_SPACE" && exit 73
fi
FS=$(stat -f -c %T "$DIR")
checkFS "$FS" "$DISK_FILE" "$DISK_DESC" || exit $?
if ! supportsDirect "$FS"; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
if ! [ -s "$DISK_FILE" ] ; then
if [[ "${DISK_FMT,,}" != "raw" ]]; then
PREV_FMT="raw"
else
PREV_FMT="qcow2"
fi
PREV_EXT=$(fmt2ext "$PREV_FMT")
if [ -s "$DISK_BASE.$PREV_EXT" ] ; then
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
fi
fi
if [ -s "$DISK_FILE" ]; then
CUR_SIZE=$(getSize "$DISK_FILE")
if (( DATA_SIZE > CUR_SIZE )); then
resizeDisk "$DISK_FILE" "$DISK_SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
fi
else
createDisk "$DISK_FILE" "$DISK_SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
fi
OPTS=$(createDevice "$DISK_ID" "$DISK_FILE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE")
DISK_OPTS="$DISK_OPTS $OPTS"
return 0
}
addDevice () {
local DISK_DEV=$1
local DISK_DESC=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local DISK_ID="userdata$DISK_INDEX"
[ -z "$DISK_DEV" ] && return 0
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
local OPTS
OPTS=$(createDevice "$DISK_ID" "$DISK_DEV" "$DISK_INDEX" "$DISK_ADDRESS" "raw" "$DISK_IO" "$DISK_CACHE")
DISK_OPTS="$DISK_OPTS $OPTS"
return 0
}
html "Initializing disks..."
DISK1_FILE="$STORAGE/data"
DISK2_FILE="/storage2/data2"
DISK3_FILE="/storage3/data3"
DISK4_FILE="/storage4/data4"
if [ -z "$DISK_FMT" ]; then
if [ -f "$DISK1_FILE.qcow2" ]; then
DISK_FMT="qcow2"
else
DISK_FMT="raw"
fi
fi
DISK_EXT=$(fmt2ext "$DISK_FMT")
if [ -z "$ALLOCATE" ]; then
ALLOCATE="N"
fi
if [[ "$ALLOCATE" == [Nn]* ]]; then
DISK_TYPE="growable"
DISK_ALLOC="preallocation=off"
else
DISK_TYPE="preallocated"
DISK_ALLOC="preallocation=falloc"
fi
: "${DISK2_SIZE:=""}"
: "${DISK3_SIZE:=""}"
: "${DISK4_SIZE:=""}"
: "${DEVICE:=""}" # Docker variables to passthrough a block device, like /dev/vdc1.
: "${DEVICE2:=""}"
: "${DEVICE3:=""}"
: "${DEVICE4:=""}"
[ -z "$DEVICE" ] && [ -b "/disk" ] && DEVICE="/disk"
[ -z "$DEVICE" ] && [ -b "/disk1" ] && DEVICE="/disk1"
[ -z "$DEVICE2" ] && [ -b "/disk2" ] && DEVICE2="/disk2"
[ -z "$DEVICE3" ] && [ -b "/disk3" ] && DEVICE3="/disk3"
[ -z "$DEVICE4" ] && [ -b "/disk4" ] && DEVICE4="/disk4"
[ -z "$DEVICE" ] && [ -b "/dev/disk1" ] && DEVICE="/dev/disk1"
[ -z "$DEVICE2" ] && [ -b "/dev/disk2" ] && DEVICE2="/dev/disk2"
[ -z "$DEVICE3" ] && [ -b "/dev/disk3" ] && DEVICE3="/dev/disk3"
[ -z "$DEVICE4" ] && [ -b "/dev/disk4" ] && DEVICE4="/dev/disk4"
if [ -n "$DEVICE" ]; then
addDevice "$DEVICE" "device" "3" "0xa" || exit $?
else
addDisk "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xa" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE2" ]; then
addDevice "$DEVICE2" "device2" "4" "0xb" || exit $?
else
addDisk "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xb" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE3" ]; then
addDevice "$DEVICE3" "device3" "5" "0xc" || exit $?
else
addDisk "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xc" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE4" ]; then
addDevice "$DEVICE4" "device4" "6" "0xd" || exit $?
else
addDisk "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "6" "0xd" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
html "Initialized disks successfully..."
return 0

View file

@ -3,29 +3,25 @@ set -Eeuo pipefail
# Docker environment variables # Docker environment variables
: "${VGA:=""}" # VGA adaptor : "${VGA:="ramfb"}" # VGA adaptor
: "${DISPLAY:="web"}" # Display type : "${DISPLAY:="web"}" # Display type
if [[ "${BOOT_MODE,,}" != "windows" ]]; then [[ "$DISPLAY" == ":0" ]] && DISPLAY="web"
[ -z "$VGA" ] && VGA="virtio-gpu"
else
[ -z "$VGA" ] && VGA="ramfb"
fi
case "${DISPLAY,,}" in case "${DISPLAY,,}" in
vnc) "vnc" )
DISPLAY_OPTS="-display vnc=:0 -device $VGA" DISPLAY_OPTS="-display vnc=:0 -device $VGA"
;; ;;
web) "web" )
DISPLAY_OPTS="-display vnc=:0,websocket=5700 -device $VGA" DISPLAY_OPTS="-display vnc=:0,websocket=5700 -device $VGA"
;; ;;
ramfb) "ramfb" )
DISPLAY_OPTS="-display vnc=:0,websocket=5700 -device ramfb" DISPLAY_OPTS="-display vnc=:0,websocket=5700 -device ramfb"
;; ;;
disabled) "disabled" )
DISPLAY_OPTS="-display none -device $VGA" DISPLAY_OPTS="-display none -device $VGA"
;; ;;
none) "none" )
DISPLAY_OPTS="-display none" DISPLAY_OPTS="-display none"
;; ;;
*) *)

View file

@ -1,13 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
APP="QEMU" : "${APP:="QEMU"}"
SUPPORT="https://github.com/qemus/qemu-arm" : "${MACHINE:="virt"}"
: "${PLATFORM:="arm64"}"
: "${SUPPORT:="https://github.com/qemus/qemu-arm"}"
cd /run cd /run
. utils.sh # Load functions
. reset.sh # Initialize system . reset.sh # Initialize system
. install.sh # Get bootdisk . define.sh # Define images
. install.sh # Download image
. disk.sh # Initialize disks . disk.sh # Initialize disks
. display.sh # Initialize graphics . display.sh # Initialize graphics
. network.sh # Initialize network . network.sh # Initialize network
@ -17,7 +21,11 @@ cd /run
trap - ERR trap - ERR
info "Booting image${BOOT_DESC}..." version=$(qemu-system-aarch64 --version | head -n 1 | cut -d '(' -f 1 | awk '{ print $NF }')
info "Booting image${BOOT_DESC} using QEMU v$version..."
[[ "$DEBUG" == [Yy1]* ]] && set -x if [ -z "$CPU_PIN" ]; then
exec qemu-system-aarch64 ${ARGS:+ $ARGS} exec qemu-system-aarch64 ${ARGS:+ $ARGS}
else
exec taskset -c "$CPU_PIN" qemu-system-aarch64 ${ARGS:+ $ARGS}
fi

View file

@ -1,58 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Check if running with interactive TTY or redirected to docker log
if [ -t 1 ]; then
progress="--progress=bar:noscroll"
else
progress="--progress=dot:giga"
fi
file="/boot.iso" && [ -f "$file" ] && [ -s "$file" ] && BOOT="$file" && return 0
file="/boot.img" && [ -f "$file" ] && [ -s "$file" ] && BOOT="$file" && return 0
file=$(find "$STORAGE" -maxdepth 1 -type f -iname boot.iso -printf "%f\n" | head -n 1)
[ -z "$file" ] && file=$(find "$STORAGE" -maxdepth 1 -type f -iname boot.img -printf "%f\n" | head -n 1)
[ -n "$file" ] && file="$STORAGE/$file"
[ -f "$file" ] && [ -s "$file" ] && BOOT="$file" && return 0
if [ -z "$BOOT" ]; then
error "No boot disk specified, set BOOT= to the URL of an ISO file." && exit 64
fi
base=$(basename "$BOOT")
[ -n "$base" ] && file="$STORAGE/$base"
[ -f "$file" ] && [ -s "$file" ] && BOOT="$file" && return 0
base=$(basename "${BOOT%%\?*}")
: "${base//+/ }"; printf -v base '%b' "${_//%/\\x}"
base=$(echo "$base" | sed -e 's/[^A-Za-z0-9._-]/_/g')
[ -n "$base" ] && file="$STORAGE/$base"
[ -f "$file" ] && [ -s "$file" ] && BOOT="$file" && return 0
TMP="$STORAGE/${base%.*}.tmp"
rm -f "$TMP"
msg="Downloading $base..."
info "$msg" && html "$msg"
/run/progress.sh "$TMP" "" "Downloading $base ([P])..." &
{ wget "$BOOT" -O "$TMP" -q --timeout=10 --show-progress "$progress"; rc=$?; } || :
fKill "progress.sh"
(( rc == 4 )) && error "Failed to download $BOOT , network failure!" && exit 60
(( rc != 0 )) && error "Failed to download $BOOT , reason: $rc" && exit 60
[ ! -s "$TMP" ] && error "Failed to download $BOOT" && exit 61
html "Download finished successfully..."
size=$(stat -c%s "$TMP")
if ((size<100000)); then
error "Invalid ISO file: Size is smaller than 100 KB" && exit 62
fi
mv -f "$TMP" "$file"
return 0

View file

@ -1,348 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Docker environment variables
: "${MAC:=""}"
: "${DHCP:="N"}"
: "${NETWORK:="Y"}"
: "${HOST_PORTS:=""}"
: "${VM_NET_DEV:=""}"
: "${VM_NET_TAP:="qemu"}"
: "${VM_NET_MAC:="$MAC"}"
: "${VM_NET_HOST:="QEMU"}"
: "${DNSMASQ_OPTS:=""}"
: "${DNSMASQ:="/usr/sbin/dnsmasq"}"
: "${DNSMASQ_CONF_DIR:="/etc/dnsmasq.d"}"
ADD_ERR="Please add the following setting to your container:"
# ######################################
# Functions
# ######################################
configureDHCP() {
# Create the necessary file structure for /dev/vhost-net
if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then
chmod 660 /dev/vhost-net
fi
fi
# Create a macvtap network for the VM guest
{ ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge ; rc=$?; } || :
if (( rc != 0 )); then
error "Cannot create macvtap interface. Please make sure that the network type is 'macvlan' and not 'ipvlan',"
error "that your kernel is recent (>4) and supports it, and that the container has the NET_ADMIN capability set." && exit 16
fi
while ! ip link set "$VM_NET_TAP" up; do
info "Waiting for MAC address $VM_NET_MAC to become available..."
sleep 2
done
local TAP_NR TAP_PATH MAJOR MINOR
TAP_NR=$(</sys/class/net/"$VM_NET_TAP"/ifindex)
TAP_PATH="/dev/tap${TAP_NR}"
# Create dev file (there is no udev in container: need to be done manually)
IFS=: read -r MAJOR MINOR < <(cat /sys/devices/virtual/net/"$VM_NET_TAP"/tap*/dev)
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && exit 18
[[ ! -e "$TAP_PATH" ]] && [[ -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH"
if [[ ! -e "$TAP_PATH" ]]; then
{ mknod "$TAP_PATH" c "$MAJOR" "$MINOR" ; rc=$?; } || :
(( rc != 0 )) && error "Cannot mknod: $TAP_PATH ($rc)" && exit 20
fi
{ exec 30>>"$TAP_PATH"; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && exit 21
fi
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "VHOST can not be found ($rc). $ADD_ERR --device=/dev/vhost-net" && exit 22
fi
NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30"
return 0
}
configureDNS() {
# dnsmasq configuration:
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-range=$VM_NET_IP,$VM_NET_IP --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite --dhcp-option=option:netmask,255.255.255.0"
# Create lease file for faster resolve
echo "0 $VM_NET_MAC $VM_NET_IP $VM_NET_HOST 01:$VM_NET_MAC" > /var/lib/misc/dnsmasq.leases
chmod 644 /var/lib/misc/dnsmasq.leases
# Set DNS server and gateway
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
# Add DNS entry for container
DNSMASQ_OPTS="$DNSMASQ_OPTS --address=/host.lan/${VM_NET_IP%.*}.1"
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
[[ "$DEBUG" == [Yy1]* ]] && set -x
if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then
error "Failed to start dnsmasq, reason: $?" && exit 29
fi
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
return 0
}
getPorts() {
local list=$1
local vnc="5900"
local web="8006"
[ -z "$list" ] && list="$web" || list="$list,$web"
if [[ "${DISPLAY,,}" == "vnc" ]] || [[ "${DISPLAY,,}" == "web" ]]; then
[ -z "$list" ] && list="$vnc" || list="$list,$vnc"
fi
[ -z "$list" ] && echo "" && return 0
if [[ "$list" != *","* ]]; then
echo " ! --dport $list"
else
echo " -m multiport ! --dports $list"
fi
return 0
}
configureNAT() {
# Create the necessary file structure for /dev/net/tun
if [ ! -c /dev/net/tun ]; then
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
if mknod /dev/net/tun c 10 200; then
chmod 666 /dev/net/tun
fi
fi
if [ ! -c /dev/net/tun ]; then
error "TUN device missing. $ADD_ERR --device /dev/net/tun --cap-add NET_ADMIN" && exit 25
fi
# Check port forwarding flag
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null; rc=$?; } || :
if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24
fi
fi
local tables="The 'ip_tables' kernel module is not loaded. Try this command: sudo modprobe ip_tables iptable_nat"
local tuntap="The 'tun' kernel module is not available. Try this command: 'sudo modprobe tun' or run the container with 'privileged: true'."
# Create a bridge with a static IP for the VM guest
VM_NET_IP='20.20.20.21'
{ ip link add dev dockerbridge type bridge ; rc=$?; } || :
if (( rc != 0 )); then
error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && exit 23
fi
ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge
while ! ip link set dockerbridge up; do
info "Waiting for IP address to become available..."
sleep 2
done
# QEMU Works with taps, set tap to the bridge created
if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then
error "$tuntap" && exit 31
fi
while ! ip link set "$VM_NET_TAP" up promisc on; do
info "Waiting for TAP to become available..."
sleep 2
done
ip link set dev "$VM_NET_TAP" master dockerbridge
# Add internet connection to the VM
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
exclude=$(getPorts "$HOST_PORTS")
if ! iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE; then
error "$tables" && exit 30
fi
# shellcheck disable=SC2086
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp${exclude} -j DNAT --to "$VM_NET_IP"
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"
if (( KERNEL > 4 )); then
# Hack for guest VMs complaining about "bad udp checksums in 5 packets"
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill > /dev/null 2>&1 || true
fi
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
if [ -c /dev/vhost-net ]; then
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
(( rc == 0 )) && NET_OPTS="$NET_OPTS,vhost=on,vhostfd=40"
fi
configureDNS
return 0
}
closeNetwork() {
# Shutdown nginx
nginx -s stop 2> /dev/null
fWait "nginx"
[[ "$NETWORK" != [Yy1]* ]] && return 0
exec 30<&- || true
exec 40<&- || true
if [[ "$DHCP" == [Yy1]* ]]; then
ip link set "$VM_NET_TAP" down || true
ip link delete "$VM_NET_TAP" || true
else
local pid="/var/run/dnsmasq.pid"
[ -s "$pid" ] && pKill "$(<"$pid")"
ip link set "$VM_NET_TAP" down promisc off || true
ip link delete "$VM_NET_TAP" || true
ip link set dockerbridge down || true
ip link delete dockerbridge || true
fi
return 0
}
checkOS() {
local name
local os=""
name=$(uname -a)
[[ "${name,,}" == *"darwin"* ]] && os="MacOS"
[[ "${name,,}" == *"microsoft"* ]] && os="Windows"
if [ -n "$os" ]; then
error "You are using Docker Desktop for $os which does not support macvlan, please revert to bridge networking!"
return 1
fi
return 0
}
getInfo() {
if [ -z "$VM_NET_DEV" ]; then
# Automaticly detect the default network interface
VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
[ -z "$VM_NET_DEV" ] && VM_NET_DEV="eth0"
fi
if [ ! -d "/sys/class/net/$VM_NET_DEV" ]; then
error "Network interface '$VM_NET_DEV' does not exist inside the container!"
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
fi
if [ -z "$MAC" ]; then
local file="$STORAGE/$PROCESS.mac"
[ -s "$file" ] && MAC=$(<"$file")
if [ -z "$MAC" ]; then
# Generate MAC address based on Docker container ID in hostname
MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
echo "${MAC^^}" > "$file"
fi
fi
VM_NET_MAC="${MAC^^}"
VM_NET_MAC="${VM_NET_MAC//-/:}"
if [[ ${#VM_NET_MAC} == 12 ]]; then
m="$VM_NET_MAC"
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi
if [[ ${#VM_NET_MAC} != 17 ]]; then
error "Invalid MAC address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
fi
GATEWAY=$(ip r | grep default | awk '{print $3}')
IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
return 0
}
# ######################################
# Configure Network
# ######################################
if [[ "$NETWORK" != [Yy1]* ]]; then
NET_OPTS=""
return 0
fi
getInfo
html "Initializing network..."
if [[ "$DEBUG" == [Yy1]* ]]; then
info "Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC"
[ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf
echo
fi
if [[ "$DHCP" == [Yy1]* ]]; then
! checkOS && exit 19
if [[ "$GATEWAY" == "172."* ]]; then
warn "your gateway IP starts with 172.* which is often a sign that you are not on a macvlan network (required for DHCP)!"
fi
# Configuration for DHCP IP
configureDHCP
else
if [[ "$GATEWAY" != "172."* ]]; then
! checkOS && exit 19
fi
# Configuration for static IP
configureNAT
fi
NET_OPTS="$NET_OPTS -device virtio-net-pci,romfile=,netdev=hostnet0,mac=$VM_NET_MAC,id=net0"
html "Initialized network successfully..."
return 0

View file

@ -4,13 +4,29 @@ set -Eeuo pipefail
# Docker environment variables # Docker environment variables
: "${KVM:="Y"}" : "${KVM:="Y"}"
: "${CPU_PIN:=""}"
: "${CPU_FLAGS:=""}" : "${CPU_FLAGS:=""}"
: "${CPU_MODEL:=""}" : "${CPU_MODEL:=""}"
: "${DEF_MODEL:="neoverse-n1"}" : "${DEF_MODEL:="neoverse-n1"}"
if [[ "${ARCH,,}" != "arm64" ]]; then if [[ "$CPU" == "Cortex A53" ]] && [[ "$CORES" == "6" ]]; then
# Pin to performance cores on Rockchip Orange Pi 4
[ -z "$CPU_PIN" ] && CPU_PIN="4,5"
fi
if [[ "$CPU" == "Cortex A55" ]] && [[ "$CORES" == "8" ]]; then
# Pin to performance cores on Rockchip Orange Pi 5
[ -z "$CPU_PIN" ] && CPU_PIN="4,5,6,7"
fi
if [[ "$CPU" == "Rockchip RK3588"* ]] && [[ "$CORES" == "8" ]]; then
# Pin to performance cores on Rockchip Orange Pi 5 Plus
[ -z "$CPU_PIN" ] && CPU_PIN="4,5,6,7"
fi
if [[ "${ARCH,,}" != "arm64" ]]; then
KVM="N" KVM="N"
warn "your CPU architecture is ${ARCH} and cannot provide KVM acceleration for ARM64 instructions, this will cause a major loss of performance." warn "your CPU architecture is ${ARCH^^} and cannot provide KVM acceleration for ARM64 instructions, this will cause a major loss of performance."
fi fi
if [[ "$KVM" != [Nn]* ]]; then if [[ "$KVM" != [Nn]* ]]; then
@ -18,25 +34,29 @@ if [[ "$KVM" != [Nn]* ]]; then
KVM_ERR="" KVM_ERR=""
if [ ! -e /dev/kvm ]; then if [ ! -e /dev/kvm ]; then
KVM_ERR="(device file missing)" KVM_ERR="(/dev/kvm is missing)"
else else
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(no write access)" KVM_ERR="(/dev/kvm is unwriteable)"
fi fi
fi fi
if [ -n "$KVM_ERR" ]; then if [ -n "$KVM_ERR" ]; then
KVM="N" KVM="N"
if [[ "$OSTYPE" =~ ^darwin ]]; then if [[ "$OSTYPE" =~ ^darwin ]]; then
warn "you are using MacOS which has no KVM support, this will cause a major loss of performance." warn "you are using macOS which has no KVM support, this will cause a major loss of performance."
else else
if grep -qi Microsoft /proc/version; then kernel=$(uname -a)
warn "you are using Windows 10 which has no KVM support, this will cause a major loss of performance." case "${kernel,,}" in
else *"microsoft"* )
error "KVM acceleration not available $KVM_ERR, this will cause a major loss of performance." error "Please bind '/dev/kvm' as a volume in the optional container settings when using Docker Desktop." ;;
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)." *"synology"* )
[[ "$DEBUG" != [Yy1]* ]] && exit 88 error "Please make sure that Synology VMM (Virtual Machine Manager) is installed and that '/dev/kvm' is binded to this container." ;;
fi *)
error "KVM acceleration is not available $KVM_ERR, this will cause a major loss of performance."
error "See the FAQ for possible causes, or continue without it by adding KVM: \"N\" (not recommended)." ;;
esac
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi fi
fi fi
@ -65,7 +85,7 @@ else
fi fi
if [[ "${BOOT_MODE,,}" == "windows" ]]; then if [[ "${BOOT_MODE,,}" == "windows" ]]; then
MACHINE="$MACHINE,virtualization=on" MACHINE+=",virtualization=on"
fi fi
fi fi

View file

@ -1,38 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
file="$1"
total="$2"
body=$(escape "$3")
info="/run/shm/msg.html"
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
while true
do
if [ -s "$file" ]; then
bytes=$(du -sb "$file" | cut -f1)
if (( bytes > 1000 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]]; then
size=$(numfmt --to=iec --suffix=B "$bytes" | sed -r 's/([A-Z])/ \1/')
else
size=$(printf '%.1f\n' "$((bytes*100*100/total))e-2")
size="$size%"
fi
echo "${body//(\[P\])/($size)}"> "$info"
fi
fi
sleep 1 & wait $!
done

View file

@ -1,199 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "${1:-}" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: ${1:-}" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m " "Warning: ${1:-}" "\E[0m\n" >&2; }
trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
[ ! -f "/run/entry.sh" ] && error "Script must run inside Docker container!" && exit 11
[ "$(id -u)" -ne "0" ] && error "Script must be executed with root privileges." && exit 12
echo " Starting $APP for Docker v$(</run/version)..."
echo " For support visit $SUPPORT"
# Docker environment variables
: "${BOOT:=""}" # URL of the ISO file
: "${DEBUG:="N"}" # Disable debugging
: "${MACHINE:="virt"}" # Machine selection
: "${ALLOCATE:=""}" # Preallocate diskspace
: "${ARGUMENTS:=""}" # Extra QEMU parameters
: "${CPU_CORES:="1"}" # Amount of CPU cores
: "${RAM_SIZE:="1G"}" # Maximum RAM amount
: "${RAM_CHECK:="Y"}" # Check available RAM
: "${DISK_SIZE:="16G"}" # Initial data disk size
: "${BOOT_INDEX:="10"}" # Boot index of CD drive
: "${BOOT_MODE:="uefi"}" # Boot in UEFI mode
# Helper variables
PROCESS="${APP,,}"
PROCESS="${PROCESS// /-}"
STORAGE="/storage"
INFO="/run/shm/msg.html"
PAGE="/run/shm/index.html"
TEMPLATE="/var/www/index.html"
FOOTER1="$APP for Docker v$(</run/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
SYS=$(uname -r)
HOST=$(hostname -s)
KERNEL=$(echo "$SYS" | cut -b 1)
MINOR=$(echo "$SYS" | cut -d '.' -f2)
ARCH=$(dpkg --print-architecture)
CPU=$(lscpu | grep -m 1 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
# Check system
if [ ! -d "/dev/shm" ]; then
error "Directory /dev/shm not found!" && exit 14
else
[ ! -d "/run/shm" ] && ln -s /dev/shm /run/shm
fi
# Check folder
if [ ! -d "$STORAGE" ]; then
error "Storage folder ($STORAGE) not found!" && exit 13
fi
# Read memory
RAM_SPARE=500000000
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
RAM_TOTAL=$(free -b | grep -m 1 Mem: | awk '{print $2}')
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
RAM_WANTED=$(numfmt --from=iec "$RAM_SIZE")
AVAIL_GB=$(( RAM_AVAIL/1073741824 ))
TOTAL_GB=$(( (RAM_TOTAL + 1073741823)/1073741824 ))
WANTED_GB=$(( (RAM_WANTED + 1073741823)/1073741824 ))
# Print system info
SYS="${SYS/-generic/}"
FS=$(stat -f -c %T "$STORAGE")
FS="${FS/ext2\/ext3/ext4}"
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
echo " CPU: ${CPU} | RAM: $AVAIL_GB/$TOTAL_GB GB | DISK: $SPACE_GB GB (${FS}) | HOST: ${SYS}..."
echo
# Check memory
if [[ "$RAM_CHECK" != [Nn]* ]]; then
if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
error "Your configured RAM_SIZE of $WANTED_GB GB is too high for the $AVAIL_GB GB of memory available, please set a lower value."
exit 17
fi
fi
# Helper functions
isAlive() {
local pid=$1
if kill -0 "$pid" 2>/dev/null; then
return 0
fi
return 1
}
pKill() {
local pid=$1
{ kill -15 "$pid" || true; } 2>/dev/null
while isAlive "$pid"; do
sleep 0.2
done
return 0
}
fWait() {
local name=$1
while pgrep -f -l "$name" >/dev/null; do
sleep 0.2
done
return 0
}
fKill() {
local name=$1
{ pkill -f "$name" || true; } 2>/dev/null
fWait "$name"
return 0
}
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
html()
{
local title
local body
local script
local footer
title=$(escape "$APP")
title="<title>$title</title>"
footer=$(escape "$FOOTER1")
body=$(escape "$1")
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
[ -n "${2:-}" ] && script="$2" || script=""
local HTML
HTML=$(<"$TEMPLATE")
HTML="${HTML/\[1\]/$title}"
HTML="${HTML/\[2\]/$script}"
HTML="${HTML/\[3\]/$body}"
HTML="${HTML/\[4\]/$footer}"
HTML="${HTML/\[5\]/$FOOTER2}"
echo "$HTML" > "$PAGE"
echo "$body" > "$INFO"
return 0
}
addPackage() {
local pkg=$1
local desc=$2
if apt-mark showinstall | grep -qx "$pkg"; then
return 0
fi
MSG="Installing $desc..."
info "$MSG" && html "$MSG"
DEBIAN_FRONTEND=noninteractive apt-get -qq update
DEBIAN_FRONTEND=noninteractive apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null
return 0
}
# Start webserver
cp -r /var/www/* /run/shm
html "Starting $APP for Docker..."
nginx -e stderr
return 0