diff --git a/.envrc b/.envrc index f65976beb..d2d94d2c7 100644 --- a/.envrc +++ b/.envrc @@ -1,5 +1,4 @@ export SETUP_DIR=$(pwd) -export KUBECONFIG=$HOME/.kube/provisioner-k8s.config dotenv .env PATH_add bin \ No newline at end of file diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 754a8a4b8..69f792ba8 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -20,4 +20,5 @@ jobs: run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com + - run: sudo apt install -y libjpeg-turbo-progs - run: task docs:publish diff --git a/.gitignore b/.gitignore index f970ef597..ce187a4a3 100755 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,7 @@ result /dist/ /.task -incus-images/output +images/**/output/ docs/.obsidian .pub_blog_temp/ .pub_min_cache/ diff --git a/3rdparty/kubie.hcl b/3rdparty/kubie.hcl new file mode 100644 index 000000000..d4cefc75a --- /dev/null +++ b/3rdparty/kubie.hcl @@ -0,0 +1,20 @@ +description = "A more powerful alternative to kubectx and kubens" +binaries = ["kubie"] +source = "https://github.com/sbstp/kubie/releases/download/v${version}/kubie-${os}-${arch}" +homepage = "https://blog.sbstp.ca/introducing-kubie/" + +on unpack { + rename { from = "${root}/kubie-${os}-${arch}" to = "${root}/kubie" } +} + +version "0.24.1" { + auto-version { + github-release = "sbstp/kubie" + } +} + +sha256sums = { + "https://github.com/sbstp/kubie/releases/download/v0.24.1/kubie-linux-amd64": "5135683bd544284468d46951ba91febfea55d19db914863c479b9c0fcc9b8da1", + "https://github.com/sbstp/kubie/releases/download/v0.24.1/kubie-darwin-amd64": "03763534cc442e90833b1a5e4ef98dd2f85cb81a7e6a366d7d77e95806eed1d9", + "https://github.com/sbstp/kubie/releases/download/v0.24.1/kubie-darwin-arm64": "b485539a2fe2cd97c498f14f29a158e059880b330774c029d5668bc19acd2e39", +} \ No newline at end of file diff --git a/Taskfile.yml b/Taskfile.yml index cabff6d9b..1c09f579f 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,10 +1,18 @@ version: "3" includes: + images:ipxe-vm: + taskfile: ./images/ipxe-vm/Taskfile.yml + dir: ./images/ipxe-vm + services:windmill: taskfile: ./services/windmill/Taskfile.yml dir: ./services/windmill + services:tinkerbell: + taskfile: ./services/tinkerbell/Taskfile.yml + dir: ./services/tinkerbell + tasks: devenv:secrets: desc: Install secrets for the devenv @@ -91,14 +99,14 @@ tasks: - docker build --platform="linux/amd64" -t ghcr.io/vgijssel/setup/spacelift-runner-ansible:latest . - docker push ghcr.io/vgijssel/setup/spacelift-runner-ansible:latest - incus-images:pikvm:prepare_disk: + images:pikvm:prepare_disk: desc: Download and extract the PiKVM disk image - dir: incus-images + dir: images cmds: - packer build -only='prepare_disk.*' -on-error=ask . - incus-images:pikvm:build: + images:pikvm:build: desc: Build an Incus container from the PiKVM disk image - dir: incus-images + dir: images cmds: - packer build -only='build_image.*' -on-error=ask . diff --git a/bin/.kubens-0.9.5.pkg b/bin/.kubie-0.24.1.pkg similarity index 100% rename from bin/.kubens-0.9.5.pkg rename to bin/.kubie-0.24.1.pkg diff --git a/bin/kubens b/bin/kubens deleted file mode 120000 index eb39c35cb..000000000 --- a/bin/kubens +++ /dev/null @@ -1 +0,0 @@ -.kubens-0.9.5.pkg \ No newline at end of file diff --git a/bin/kubie b/bin/kubie new file mode 120000 index 000000000..59ead7230 --- /dev/null +++ b/bin/kubie @@ -0,0 +1 @@ +.kubie-0.24.1.pkg \ No newline at end of file diff --git a/devenv/deploys/terminal/files/.kube/kubie.yaml b/devenv/deploys/terminal/files/.kube/kubie.yaml new file mode 100644 index 000000000..aee1fbd72 --- /dev/null +++ b/devenv/deploys/terminal/files/.kube/kubie.yaml @@ -0,0 +1,70 @@ +shell: zsh +default_editor: code + +configs: + include: + - ~/.lima/**/kubeconfig.yaml + - ~/.lima/**/kubeconfig.yml + - ~/.kube/configs/*.yml + - ~/.kube/configs/*.yaml + +# Prompt settings. +prompt: + # Disable kubie's custom prompt inside of a kubie shell. This is useful + # when you already have a prompt displaying kubernetes information. + # Default: false + disable: false + + # When using recursive contexts, show depth when larger than 1. + # Default: true + show_depth: true + + # When using zsh, show context and namespace on the right-hand side using RPS1. + # Default: false + zsh_use_rps1: false + + # When using fish, show context and namespace on the right-hand side. + # Default: false + fish_use_rprompt: false + + # When using xonsh, show context and namespace on the right-hand side. + # Default: false + xonsh_use_right_prompt: false + +# Behavior +behavior: + # Namespace validation and switching behavior. Set to "false" if you do not have + # the right to list namespaces. + # Valid values: + # true: Make sure the namespace exists with `kubectl get namespaces`. + # false: Switch namespaces without validation. + # partial: Check for partial matches when running `kubie ns ` + # and no exact match is found: + # - if exactly one namespace partially matches, switch to that namespace + # - if multiple namespaces partially match, select from those + # Default: true + validate_namespaces: true + + # Enable or disable the printing of the 'CONTEXT => ...' headers when running + # `kubie exec`. + # Valid values: + # auto: Prints context headers only if stdout is a TTY. Piping/redirecting + # kubie output will auto-disable context headers. + # always: Always prints context headers, even if stdout is not a TTY. + # never: Never prints context headers. + # Default: auto + print_context_in_exec: auto + +# Optional start and stop hooks +hooks: + # A command hook to run when a CTX is started. + # This example re-labels your terminal window + # Default: none + start_ctx: > + echo -en "\033]1; `kubie info ctx`|`kubie info ns` \007" + + # A command hook to run when a CTX is stopped + # This example sets the terminal back to the shell name + # Default: none + stop_ctx: > + echo -en "\033]1; $SHELL \007" diff --git a/devenv/deploys/terminal/tasks/install_terminal.py b/devenv/deploys/terminal/tasks/install_terminal.py index c6dee6ba0..39a5c6356 100644 --- a/devenv/deploys/terminal/tasks/install_terminal.py +++ b/devenv/deploys/terminal/tasks/install_terminal.py @@ -41,6 +41,7 @@ def install_terminal(): ".zprofile", ".profile", ".terminal_env", + ".kube/kubie.yaml", ] for terminal_file in terminal_files: diff --git a/devenv/deploys/utilities/tasks/install_utilities.py b/devenv/deploys/utilities/tasks/install_utilities.py index 4c36eeddf..e3973616d 100644 --- a/devenv/deploys/utilities/tasks/install_utilities.py +++ b/devenv/deploys/utilities/tasks/install_utilities.py @@ -19,6 +19,8 @@ def install_utilities(): "slack", "obsidian", "gimp", + "utm", + "cirruslabs/cli/tart", ] for utility in utilities: @@ -42,6 +44,7 @@ def install_utilities(): "incus", "hermit", "whalebrew", + "lima", ], present=True, update=False, diff --git a/devenv/deploys/workflow/tasks/install_workflow.py b/devenv/deploys/workflow/tasks/install_workflow.py index 4708c9ee0..8a986cfd5 100644 --- a/devenv/deploys/workflow/tasks/install_workflow.py +++ b/devenv/deploys/workflow/tasks/install_workflow.py @@ -72,6 +72,10 @@ def install_workflow(): value=False, ) + # Tart has been installed. You might want to reduce the default DHCP lease time + # from 86,400 to 600 seconds to avoid DHCP shortage when running lots of VMs daily: + # defaults write /Library/Preferences/SystemConfiguration/com.apple.InternetSharing.default.plist bootpd -dict DHCPLeaseTimeSecs -int 600 + server.shell( name="Restart macOS Dock", commands=["killall Dock"], diff --git a/incus-images/Dockerfile b/images/distrobuilder-image/Dockerfile similarity index 94% rename from incus-images/Dockerfile rename to images/distrobuilder-image/Dockerfile index 2d7f762b3..d8da4998d 100644 --- a/incus-images/Dockerfile +++ b/images/distrobuilder-image/Dockerfile @@ -3,11 +3,11 @@ # Copied from https://github.com/f-bn/containers-images/blob/main/distrobuilder/Dockerfile # --- Build stage --- -FROM docker.io/golang:1.22.3 AS build +FROM docker.io/golang:1.22.7 AS build ARG TARGETOS ARG TARGETARCH -ARG VERSION=3.0 +ARG VERSION=3.1 ENV GOOS=${TARGETOS} ENV GOARCH=${TARGETARCH} @@ -44,6 +44,7 @@ RUN set -ex ; \ xz-utils \ ca-certificates \ p7zip-full \ + gpg \ zstd ; \ apt clean all ; \ rm -rf /var/lib/apt/lists/* diff --git a/images/ipxe-efi/Dockerfile b/images/ipxe-efi/Dockerfile new file mode 100644 index 000000000..bf401c112 --- /dev/null +++ b/images/ipxe-efi/Dockerfile @@ -0,0 +1,24 @@ +# iPXE doesn't work on arm64 so forcing amd64 +FROM --platform=linux/amd64 ubuntu:noble + +RUN apt-get update && apt-get install -y \ + git \ + gcc \ + binutils \ + make \ + perl \ + mtools \ + genisoimage \ + liblzma-dev \ + syslinux-common \ + isolinux \ + gcc-aarch64-linux-gnu \ + binutils-aarch64-linux-gnu + +RUN mkdir -p /opt && cd /opt && git clone https://github.com/ipxe/ipxe.git +WORKDIR /opt/ipxe/src + +# Warm the cache by building the default ipxe.efi target +RUN make CROSS=aarch64-linux-gnu- bin-arm64-efi/ipxe.efi + +ADD embedded.ipxe . \ No newline at end of file diff --git a/images/ipxe-efi/embedded.ipxe b/images/ipxe-efi/embedded.ipxe new file mode 100644 index 000000000..2852729b8 --- /dev/null +++ b/images/ipxe-efi/embedded.ipxe @@ -0,0 +1,71 @@ +#!ipxe + +:start +echo Attempting to obtain a DHCP lease... +dhcp || goto dhcp_fail +echo DHCP lease obtained successfully. +echo +echo + +# Get the ipxe variables from: https://ipxe.org/cfg +echo *** Network device settings *** +echo mac: ${mac} +echo chip: ${chip} +echo +echo *** IPv4 settings *** +echo ip: ${ip} +echo netmask: ${netmask} +echo gateway: ${gateway} +echo dns: ${dns} +echo domain: ${domain} +echo +echo *** Boot settings *** +echo filename: ${filename} +echo next-server: ${next-server} +echo +echo *** Host settings *** +echo hostname: ${hostname} +echo uuid: ${uuid} +echo user-class: ${user-class} +echo manufacturer: ${manufacturer} +echo product: ${product} +echo serial: ${serial} +echo asset: ${asset} +echo +echo *** Miscellaneous settings *** +echo buildarch: ${buildarch} +echo cpumodel: ${cpumodel} +echo cpuvendor: ${cpuvendor} +echo cwduri: ${cwduri} +echo cwuri: ${cwuri} +echo dhcp-server: ${dhcp-server} +echo platform: ${platform} +echo sysmac: ${sysmac} +echo version: ${version} +echo +echo + +echo Attempting to boot from 'filename': '${filename}' + +isset ${filename} || goto filename_fail +chain ${filename} || goto chain_fail +echo Boot succeeded! +goto end + +:dhcp_fail +echo DHCP failed. Retrying in 5 seconds... +sleep 5 +goto start + +:filename_fail +echo Filename not set. Retrying in 5 seconds... +sleep 5 +goto start + +:chain_fail +echo Boot failed. Retrying in 5 seconds... +sleep 5 +goto start + +:end +echo Script finished. This should never happen unless manually exited. diff --git a/images/ipxe-efi/ipxe-efi.pkr.hcl b/images/ipxe-efi/ipxe-efi.pkr.hcl new file mode 100644 index 000000000..3cc772abd --- /dev/null +++ b/images/ipxe-efi/ipxe-efi.pkr.hcl @@ -0,0 +1,53 @@ +packer { + required_plugins { + docker = { + version = ">= 1.1.1" + source = "github.com/hashicorp/docker" + } + } +} + +variable "output_dir" { + type = string + default = "output" +} + +locals { + output_path = "${path.root}/${var.output_dir}" + ipxe_target = "bin-arm64-efi/ipxe.efi" + ipxe_output_path = "${local.output_path}/ipxe.efi" +} + +source "docker" "ipxe" { + # We're going to throw away the container afterwards because + # we're only interested in the generated artifact. + discard = true + build { + path = "Dockerfile" + } +} + +build { + name = "build_image" + sources = ["source.docker.ipxe"] + + provisioner "shell" { + inline = [ + "make EMBED=embedded.ipxe CROSS=aarch64-linux-gnu- ${local.ipxe_target}", + ] + } + + provisioner "file" { + source = "/opt/ipxe/src/${local.ipxe_target}" + destination = local.ipxe_output_path + direction = "download" + } + + post-processors { + post-processor "artifice" { + files = [ + local.ipxe_output_path, + ] + } + } +} \ No newline at end of file diff --git a/images/ipxe-vm/Taskfile.yml b/images/ipxe-vm/Taskfile.yml new file mode 100644 index 000000000..146fc849d --- /dev/null +++ b/images/ipxe-vm/Taskfile.yml @@ -0,0 +1,7 @@ +version: "3" + +tasks: + build: + desc: Build the ipxe-vm image + cmds: + - packer build -var 'ipxe_efi=../ipxe-efi/output/ipxe.efi' -on-error=ask . diff --git a/images/ipxe-vm/ipxe-vm.pkr.hcl b/images/ipxe-vm/ipxe-vm.pkr.hcl new file mode 100644 index 000000000..5297006a8 --- /dev/null +++ b/images/ipxe-vm/ipxe-vm.pkr.hcl @@ -0,0 +1,92 @@ +packer { + required_plugins { + docker = { + version = ">= 1.1.1" + source = "github.com/hashicorp/docker" + } + } +} + +variable "ipxe_efi" { + type = string +} + +variable "output_dir" { + type = string + default = "output" +} + +locals { + output_path = "${path.root}/${var.output_dir}" + ipxe_efi_path = var.ipxe_efi + + image_distribution = "ubuntu" + image_release = "noble" + image_description = "Image for iPXE booting." + image_architecture = "arm64" + image_serial = formatdate("YYYYMMDD_hhmm", timestamp()) + + # Following naming convention from https://linuxcontainers.org/distrobuilder/docs/latest/reference/image/ + image_name = "${local.image_distribution}-${local.image_release}-${local.image_architecture}-${local.image_serial}" + image_file_name = "disk.qcow2" + + output_image_path = "${local.output_path}/${local.image_file_name}" + build_image_path = "/build/${local.image_file_name}" + + distrobuilder_content = templatefile("${path.root}/ipxe-vm.yml.pkrtpl.hcl", { + image_settings = { + distribution = local.image_distribution, + release = local.image_release, + description = local.image_description, + architecture = local.image_architecture, + serial = local.image_serial, + name = local.image_name, + }, + }) +} + +source "docker" "distrobuilder" { + # We're going to throw away the container afterwards because + # we're only interested in the generated artifact. + discard = true + build { + path = "../distrobuilder-image/Dockerfile" + } + container_dir = "/build" + + # Needs to be privileged to do a loop mount on the partitions + privileged = true +} + +build { + name = "build_image" + sources = ["source.docker.distrobuilder"] + + provisioner "file" { + destination = "/build/ipxe.efi" + source = local.ipxe_efi_path + } + + provisioner "file" { + content = local.distrobuilder_content + destination = "/build/ipxe-vm.yml" + } + + provisioner "shell" { + inline = [ + "distrobuilder build-incus --disable-overlay --type split --vm /build/ipxe-vm.yml /build/", + ] + } + + provisioner "file" { + source = local.build_image_path + destination = local.output_image_path + direction = "download" + } + + post-processors { + post-processor "artifice" { + files = [local.output_image_path] + } + } +} \ No newline at end of file diff --git a/images/ipxe-vm/ipxe-vm.yml.pkrtpl.hcl b/images/ipxe-vm/ipxe-vm.yml.pkrtpl.hcl new file mode 100644 index 000000000..3fab1066e --- /dev/null +++ b/images/ipxe-vm/ipxe-vm.yml.pkrtpl.hcl @@ -0,0 +1,533 @@ +${yamlencode({ + "image": image_settings, +})} + +source: + downloader: debootstrap + same_as: gutsy + # url: http://archive.ubuntu.com/ubuntu/ + url: http://ports.ubuntu.com/ubuntu-ports + keys: + # 0x790BC7277767219C42C86F933B4FE6ACC0B21F32 + - |- + -----BEGIN PGP PUBLIC KEY BLOCK----- + + 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 + =384X + -----END PGP PUBLIC KEY BLOCK----- + + # 0xf6ecb3762474eda9d21b7022871920d1991bc93c + - |- + -----BEGIN PGP PUBLIC KEY BLOCK----- + + xsFNBFufwdoBEADv/Gxytx/LcSXYuM0MwKojbBye81s0G1nEx+lz6VAUpIUZnbkq + dXBHC+dwrGS/CeeLuAjPRLU8AoxE/jjvZVp8xFGEWHYdklqXGZ/gJfP5d3fIUBtZ + HZEJl8B8m9pMHf/AQQdsC+YzizSG5t5Mhnotw044LXtdEEkx2t6Jz0OGrh+5Ioxq + X7pZiq6Cv19BohaUioKMdp7ES6RYfN7ol6HSLFlrMXtVfh/ijpN9j3ZhVGVeRC8k + KHQsJ5PkIbmvxBiUh7SJmfZUx0IQhNMaDHXfdZAGNtnhzzNReb1FqNLSVkrS/Pns + AQzMhG1BDm2VOSF64jebKXffFqM5LXRQTeqTLsjUbbrqR6s/GCO8UF7jfUj6I7ta + LygmsHO/JD4jpKRC0gbpUBfaiJyLvuepx3kWoqL3sN0LhlMI80+fA7GTvoOx4tpq + VlzlE6TajYu+jfW3QpOFS5ewEMdL26hzxsZg/geZvTbArcP+OsJKRmhv4kNo6Ayd + yHQ/3ZV/f3X9mT3/SPLbJaumkgp3Yzd6t5PeBu+ZQk/mN5WNNuaihNEV7llb1Zhv + Y0Fxu9BVd/BNl0rzuxp3rIinB2TX2SCg7wE5xXkwXuQ/2eTDE0v0HlGntkuZjGow + DZkxHZQSxZVOzdZCRVaX/WEFLpKa2AQpw5RJrQ4oZ/OfifXyJzP27o03wQARAQAB + zUJVYnVudHUgQXJjaGl2ZSBBdXRvbWF0aWMgU2lnbmluZyBLZXkgKDIwMTgpIDxm + dHBtYXN0ZXJAdWJ1bnR1LmNvbT7CwXgEEwEKACIFAlufwdoCGwMGCwkIBwMCBhUI + AgkKCwQWAgMBAh4BAheAAAoJEIcZINGZG8k8LHMQAKS2cnxz/5WaoCOWArf5g6UH + beOCgc5DBm0hCuFDZWWv427aGei3CPuLw0DGLCXZdyc5dqE8mvjMlOmmAKKlj1uG + g3TYCbQWjWPeMnBPZbkFgkZoXJ7/6CB7bWRht1sHzpt1LTZ+SYDwOwJ68QRp7DRa + Zl9Y6QiUbeuhq2DUcTofVbBxbhrckN4ZteLvm+/nG9m/ciopc66LwRdkxqfJ32Cy + q+1TS5VaIJDG7DWziG+Kbu6qCDM4QNlg3LH7p14CrRxAbc4lvohRgsV4eQqsIcdF + kuVY5HPPj2K8TqpY6STe8Gh0aprG1RV8ZKay3KSMpnyV1fAKn4fM9byiLzQAovC0 + LZ9MMMsrAS/45AvC3IEKSShjLFn1X1dRCiO6/7jmZEoZtAp53hkf8SMBsi78hVNr + BumZwfIdBA1v22+LY4xQK8q4XCoRcA9G+pvzU9YVW7cRnDZZGl0uwOw7z9PkQBF5 + KFKjWDz4fCk+K6+YtGpovGKekGBb8I7EA6UpvPgqA/QdI0t1IBP0N06RQcs1fUaA + QEtz6DGy5zkRhR4pGSZn+dFET7PdAjEK84y7BdY4t+U1jcSIvBj0F2B7LwRL7xGp + SpIKi/ekAXLs117bvFHaCvmUYN7JVp1GMmVFxhIdx6CFm3fxG8QjNb5tere/YqK+ + uOgcXny1UlwtCUzlrSaPwsFzBBABCgAdFiEEFT8cnvE5X78ANS6NC/uEfz8nL1sF + AlufxEMACgkQC/uEfz8nL1tuFw/9GgaeggvCn15QplABa86OReJARxnAxpaL223p + LkgAbBYAOT7PmTjwwHCqGeJZGLzAQsGLc6WkQDegewQCMWLp+1zOHmUBHbZPsz3E + 76Ac381FAXhZBj8MLbcyOROsKYKZ9M/yGerMpVx4B8WNb5P+t9ttAwwAR/lNs5OS + 3lpV4nkwIzvxA6Wnq0gWKBL/9rc7sL+qWeJDnQEkq1Z/dNBbgIWktDtqeIXFldgj + YOX+x1RN81beLVDtRLoOU0IkQsFGaOOb0o2x8/dmYM2cXuchNGYmdY2Z5jeLI1F0 + dzCR+CRUEDFdr0cF94USgVGWyCoaHdABTRD5e/uIEySL0T9ym93RNBtoc9gPENFB + 2ASMJgkMNINiV82alPjYYrbs+ZVHuLQIgd+qw/N6zwLtVDgo2Pc6FXZpqmSjRRmt + BRJuv+VnDBeAOstl0QloRm5gRBp/wgt93E1Ah+QJRVuMQFqz0nPZWTwfcGagmSEu + rWiKX8n2FFYkiLfyUW0335TN88Z99+gvQ+AySAFu8ReT/lQzAPRPNRLjpAk5e1Fu + MzQYoBJcYwP0sjAIO1AWmguPI1KLfnVnXnsT5JYMbG2DCLHI/OIvnpRq8v955glZ + 5L9aq8bNnOwC2BK6MVUspbJRpGLQ29hbeH8jnRPOPQ+Sbwa2C8/ZSoBa/L6JGl5R + DaOLQ1w= + =VTg2 + -----END PGP PUBLIC KEY BLOCK----- + +files: + - path: /etc/hostname + generator: hostname + + - path: /etc/hosts + generator: hosts + + - path: /etc/resolvconf/resolv.conf.d/original + generator: remove + + - path: /etc/resolvconf/resolv.conf.d/tail + generator: remove + + - path: /etc/machine-id + generator: dump + + - path: /var/lib/dbus/machine-id + generator: remove + + - name: meta-data + generator: cloud-init + variants: + - cloud + + - name: network-config + generator: cloud-init + variants: + - cloud + + - name: user-data + generator: cloud-init + variants: + - cloud + + - name: vendor-data + generator: cloud-init + variants: + - cloud + + - name: ext4 + generator: fstab + types: + - vm + + - generator: copy + source: ipxe.efi + path: /boot/efi/EFI/ipxe/ipxe.efi + + - path: /etc/default/grub.d/50-incus.cfg + generator: dump + # Forcing a menu to appear for 5 seconds + content: |- + GRUB_RECORDFAIL_TIMEOUT=5 + GRUB_TIMEOUT=5 + GRUB_TIMEOUT_STYLE=menu + GRUB_CMDLINE_LINUX_DEFAULT="$${GRUB_CMDLINE_LINUX_DEFAULT} console=tty1 console=ttyS0" + GRUB_TERMINAL=console + GRUB_DEFAULT=ipxe + types: + - vm + + # Add ipxe to the grub menu + - path: /etc/grub.d/40_custom + generator: dump + content: |- + #!/bin/sh + exec tail -n +3 $0 + menuentry "ipxe" { + set root='hd0,gpt1' # Adjust this to match the partition containing ipxe.efi + chainloader /EFI/ipxe/ipxe.efi + } + types: + - vm + + - path: /etc/sudoers.d/90-incus + generator: dump + mode: 0440 + content: |- + # User rules for ubuntu + ubuntu ALL=(ALL) NOPASSWD:ALL + variants: + - default + +packages: + manager: apt + update: true + cleanup: true + sets: + - packages: + - fuse3 + - openssh-client + - openssh-server + - sudo + - vim + - language-pack-en + - grub-efi-arm64-signed + # to help debug using limactl + - cloud-init + - shim-signed + - linux-image-virtual + - cloud-guest-utils + action: install + + - packages: + - os-prober + action: remove + + repositories: + - name: sources.list + url: |- + deb http://archive.ubuntu.com/ubuntu ${image_settings.release} main restricted universe multiverse + deb http://archive.ubuntu.com/ubuntu ${image_settings.release}-updates main restricted universe multiverse + deb http://security.ubuntu.com/ubuntu ${image_settings.release}-security main restricted universe multiverse + architectures: + - amd64 + - i386 + + - name: sources.list + url: |- + deb http://ports.ubuntu.com/ubuntu-ports ${image_settings.release} main restricted universe multiverse + deb http://ports.ubuntu.com/ubuntu-ports ${image_settings.release}-updates main restricted universe multiverse + deb http://ports.ubuntu.com/ubuntu-ports ${image_settings.release}-security main restricted universe multiverse + architectures: + - armhf + - arm64 + - powerpc + - powerpc64 + - ppc64el + - riscv64 + +actions: + - trigger: post-unpack + action: |- + #!/bin/sh + set -eux + + # Make sure systemd doesn't think it's running. + [ ! -d /run/systemd ] && exit 0 + rm -Rf /run/systemd/system + chattr +i /run/systemd + + - trigger: post-packages + action: |- + #!/bin/sh + set -eux + + # Remove the immutable flag. + [ ! -d /run/systemd ] && exit 0 + chattr -i /run/systemd + + - trigger: post-update + action: |- + #!/bin/sh + set -eux + + # Create the ubuntu user account + getent group sudo >/dev/null 2>&1 || groupadd --system sudo + useradd --create-home -s /bin/bash -G sudo -U ubuntu + + # Set the password for the ubuntu user account + echo "ubuntu:ubuntu" | chpasswd + variants: + - default + + - trigger: post-packages + action: |- + #!/bin/sh + set -eux + + # Enable systemd-networkd + systemctl enable systemd-networkd + + # Disable UA attach + systemctl mask ua-auto-attach + + - trigger: post-packages + action: |- + #!/bin/sh + set -eux + + # Ensure /etc/resolv.conf is symlinked to /run/systemd/resolve/stub-resolv.conf + ln -sf ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf + releases: + - noble + - oracular + + - trigger: post-packages + action: |- + #!/bin/sh + set -eux + + # Make sure the locale is built and functional + locale-gen en_US.UTF-8 + update-locale LANG=en_US.UTF-8 + + # Cleanup underlying /run + mount -o bind / /mnt + rm -rf /mnt/run/* + umount /mnt + + # Cleanup temporary shadow paths + rm /etc/*- + + - trigger: post-files + action: |- + #!/bin/sh + set -eux + + TARGET="x86_64" + [ "$(uname -m)" = "aarch64" ] && TARGET="arm64" + + update-grub + + # This will create EFI/BOOT + grub-install --uefi-secure-boot --target="$${TARGET}-efi" --no-nvram --removable + + # This will create EFI/ubuntu + grub-install --uefi-secure-boot --target="$${TARGET}-efi" --no-nvram + + update-grub + types: + - vm + + - trigger: post-files + action: |- + #!/bin/sh + set -eux + + # Automatic disk resize + cat << EOF > /etc/systemd/system/incus-growpart.service + [Unit] + Description=Incus - grow root partition + + [Service] + Type=oneshot + ExecStartPre=-/usr/bin/growpart /dev/sda 2 + ExecStart=/sbin/resize2fs /dev/sda2 + + [Install] + WantedBy=default.target + EOF + + systemctl enable incus-growpart + types: + - vm + variants: + - default + - desktop + +mappings: + architecture_map: debian diff --git a/incus-images/pikvm.pkr.hcl b/images/pikvm-lxc/pikvm.pkr.hcl similarity index 100% rename from incus-images/pikvm.pkr.hcl rename to images/pikvm-lxc/pikvm.pkr.hcl diff --git a/incus-images/pikvm.yaml.pkrtpl.hcl b/images/pikvm-lxc/pikvm.yaml.pkrtpl.hcl similarity index 100% rename from incus-images/pikvm.yaml.pkrtpl.hcl rename to images/pikvm-lxc/pikvm.yaml.pkrtpl.hcl diff --git a/services/tinkerbell/Taskfile.yml b/services/tinkerbell/Taskfile.yml new file mode 100644 index 000000000..4a2753e7d --- /dev/null +++ b/services/tinkerbell/Taskfile.yml @@ -0,0 +1,22 @@ +version: "3" + +tasks: + dev: + desc: Start the tinkerbell development environment + cmds: + - limactl delete -f tinkerbell-lima || true + - limactl start ./tinkerbell-lima.yaml + - KUBECONFIG="$HOME/.kube/configs/tinkerbell-dev.yaml" kubectl config rename-context default tinkerbell-dev + - helmfile apply --wait + - kubie exec tinkerbell-dev tink kubectl apply -f hardware.yaml -f template.yaml -f ubuntu-download.yaml -f workflow.yaml + + # For console output use: + # minicom -D unix#/Users/maarten/.lima/ipxe-lima/serial.sock + # + # For shell access use: + # limactl shell ipxe-lima + ipxe: + desc: Start the ipxe machine + cmds: + - limactl delete -f ipxe-lima || true + - limactl start ./ipxe-lima.yaml diff --git a/services/tinkerbell/hardware.yaml b/services/tinkerbell/hardware.yaml new file mode 100644 index 000000000..cb26d9c82 --- /dev/null +++ b/services/tinkerbell/hardware.yaml @@ -0,0 +1,19 @@ +apiVersion: tinkerbell.org/v1alpha1 +kind: Hardware +metadata: + name: machine1 + namespace: tink +spec: + disks: + - device: /dev/vda + interfaces: + - dhcp: + arch: aarch64 + ip: + address: 192.168.104.4 + gateway: 192.168.104.2 + netmask: 255.255.255.0 + mac: 52:55:55:38:6f:53 + netboot: + allowPXE: true + allowWorkflow: true diff --git a/services/tinkerbell/helmfile.yaml b/services/tinkerbell/helmfile.yaml new file mode 100644 index 000000000..1bc9ce967 --- /dev/null +++ b/services/tinkerbell/helmfile.yaml @@ -0,0 +1,7 @@ +releases: + - name: tink + chart: oci://ghcr.io/tinkerbell/charts/stack + version: 0.6.2 + namespace: tink + values: + - ./values.yaml diff --git a/services/tinkerbell/ipxe-lima.yaml b/services/tinkerbell/ipxe-lima.yaml new file mode 100644 index 000000000..73b5a931d --- /dev/null +++ b/services/tinkerbell/ipxe-lima.yaml @@ -0,0 +1,25 @@ +vmType: qemu +minimumLimaVersion: 1.0.0 + +arch: aarch64 + +images: + - location: ../../images/ipxe-vm/output/disk.qcow2 + arch: aarch64 + +user: + name: ubuntu + comment: ubuntu + +vmOpts: + qemu: + minimumVersion: 9.2.0 + +os: Linux +networks: + - lima: user-v2 +plain: true +nestedVirtualization: false + +# Need at least 2GiB memory to unpack the ram disk for HookOS +memory: 2GiB diff --git a/services/tinkerbell/template.yaml b/services/tinkerbell/template.yaml new file mode 100644 index 000000000..55e7ccddc --- /dev/null +++ b/services/tinkerbell/template.yaml @@ -0,0 +1,101 @@ +apiVersion: tinkerbell.org/v1alpha1 +kind: Template +metadata: + name: ubuntu +spec: + data: | + version: "0.1" + name: ubuntu + global_timeout: 1800 + tasks: + - name: "os installation" + worker: "{{ .device_1 }}" + volumes: + - /dev:/dev + - /dev/console:/dev/console + - /lib/firmware:/lib/firmware:ro + actions: + - name: "stream ubuntu image" + image: quay.io/tinkerbell/actions/image2disk:latest + timeout: 600 + environment: + DEST_DISK: {{ index .Hardware.Disks 0 }} + IMG_URL: "http://{{ .artifact_server_ip_port }}/jammy-server-cloudimg-arm64.raw.gz" + COMPRESSED: true + - name: "grow-partition" + image: quay.io/tinkerbell/actions/cexec:latest + timeout: 90 + environment: + BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}1 + FS_TYPE: ext4 + CHROOT: y + DEFAULT_INTERPRETER: "/bin/sh -c" + CMD_LINE: "growpart {{ index .Hardware.Disks 0 }} 1 && resize2fs {{ index .Hardware.Disks 0 }}1" + - name: "install openssl" + image: quay.io/tinkerbell/actions/cexec:latest + timeout: 90 + environment: + BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}1 + FS_TYPE: ext4 + CHROOT: y + DEFAULT_INTERPRETER: "/bin/sh -c" + CMD_LINE: "apt -y update && apt -y install openssl" + - name: "create user" + image: quay.io/tinkerbell/actions/cexec:latest + timeout: 90 + environment: + BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}1 + FS_TYPE: ext4 + CHROOT: y + DEFAULT_INTERPRETER: "/bin/sh -c" + CMD_LINE: "useradd -p $(openssl passwd -1 tink) -s /bin/bash -d /home/tink/ -m -G sudo tink" + - name: "enable ssh" + image: quay.io/tinkerbell/actions/cexec:latest + timeout: 90 + environment: + BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}1 + FS_TYPE: ext4 + CHROOT: y + DEFAULT_INTERPRETER: "/bin/sh -c" + CMD_LINE: "ssh-keygen -A; systemctl enable ssh.service; echo 'PasswordAuthentication yes' > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf" + - name: "disable apparmor" + image: quay.io/tinkerbell/actions/cexec:latest + timeout: 90 + environment: + BLOCK_DEVICE: {{ index .Hardware.Disks 0 }}1 + FS_TYPE: ext4 + CHROOT: y + DEFAULT_INTERPRETER: "/bin/sh -c" + CMD_LINE: "systemctl disable apparmor; systemctl disable snapd" + - name: "write netplan" + image: quay.io/tinkerbell/actions/writefile:latest + timeout: 90 + environment: + DEST_DISK: {{ index .Hardware.Disks 0 }}1 + FS_TYPE: ext4 + DEST_PATH: /etc/netplan/config.yaml + CONTENTS: | + network: + version: 2 + renderer: networkd + ethernets: + id0: + match: + name: en* + dhcp4: true + UID: 0 + GID: 0 + MODE: 0644 + DIRMODE: 0755 + + # For some reason kexec does not work, so reboot now + - name: "reboot" + image: ghcr.io/jacobweinstock/waitdaemon:latest + timeout: 90 + pid: host + command: ["reboot"] + environment: + IMAGE: alpine + WAIT_SECONDS: 10 + volumes: + - /var/run/docker.sock:/var/run/docker.sock diff --git a/services/tinkerbell/tinkerbell-lima.yaml b/services/tinkerbell/tinkerbell-lima.yaml new file mode 100644 index 000000000..0974fb3bd --- /dev/null +++ b/services/tinkerbell/tinkerbell-lima.yaml @@ -0,0 +1,66 @@ +# Deploy kubernetes via k3s (which installs a bundled containerd). +# $ limactl start ./k3s.yaml +# $ limactl shell k3s kubectl +# +# It can be accessed from the host by exporting the kubeconfig file; +# the ports are already forwarded automatically by lima: +# +# $ export KUBECONFIG=$(limactl list k3s --format 'unix://{{.Dir}}/copied-from-guest/kubeconfig.yaml') +# $ kubectl get no +# NAME STATUS ROLES AGE VERSION +# lima-k3s Ready control-plane,master 69s v1.21.1+k3s1 +# +# This template requires Lima v0.7.0 or later. + +images: + # Try to use release-yyyyMMdd image if available. Note that release-yyyyMMdd will be removed after several months. + - location: https://cloud-images.ubuntu.com/releases/24.04/release-20241119/ubuntu-24.04-server-cloudimg-amd64.img + arch: x86_64 + digest: sha256:b63f266fa4bdf146dea5b0938fceac694cb3393688fb12a048ba2fc72e7bfe1b + - location: https://cloud-images.ubuntu.com/releases/24.04/release-20241119/ubuntu-24.04-server-cloudimg-arm64.img + arch: aarch64 + digest: sha256:6e1f90d3e81b90202b46c3573590867e575e504af2c63dd5c9b529f174e3d793 + # Fallback to the latest release image. + # Hint: run `limactl prune` to invalidate the cache + - location: https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img + arch: x86_64 + - location: https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-arm64.img + arch: aarch64 + +# Mounts are disabled in this template, but can be enabled optionally. +mounts: [] + +# containerd is managed by k3s, not by Lima, so the values are set to false here. +containerd: + system: false + user: false + +provision: + - mode: system + script: | + #!/bin/sh + if [ ! -d /var/lib/rancher/k3s ]; then + curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik,servicelb,metrics-server,local-storage server --write-kubeconfig-mode 644" sh - + fi + +probes: + - script: | + #!/bin/bash + set -eux -o pipefail + if ! timeout 30s bash -c "until test -f /etc/rancher/k3s/k3s.yaml; do sleep 3; done"; then + echo >&2 "k3s is not running yet" + exit 1 + fi + hint: | + The k3s kubeconfig file has not yet been created. + Run "limactl shell k3s sudo journalctl -u k3s" to check the log. + If that is still empty, check the bottom of the log at "/var/log/cloud-init-output.log". +copyToHost: + - guest: /etc/rancher/k3s/k3s.yaml + host: "{{.Home}}/.kube/configs/tinkerbell-dev.yaml" + deleteOnStop: true +vmType: qemu +networks: + - lima: user-v2 + +memory: 1GiB diff --git a/services/tinkerbell/ubuntu-download.yaml b/services/tinkerbell/ubuntu-download.yaml new file mode 100644 index 000000000..056fb499b --- /dev/null +++ b/services/tinkerbell/ubuntu-download.yaml @@ -0,0 +1,55 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: download-image +data: + entrypoint.sh: |- + #!/usr/bin/env bash + # This script is designed to download a cloud image file (.img) and then convert it to a .raw.gz file. + # This is purpose built so non-raw cloud image files can be used with the "image2disk" action. + # See https://artifacthub.io/packages/tbaction/tinkerbell-community/image2disk. + set -euxo pipefail + if ! which pigz qemu-img &>/dev/null; then + apk add --update pigz qemu-img + fi + image_url=$1 + file=$2/${image_url##*/} + file=${file%.*}.raw.gz + if [[ ! -f "$file" ]]; then + wget "$image_url" -O image.img + qemu-img convert -O raw image.img image.raw + pigz "$file" + rm -f image.img image.raw + fi +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: download-ubuntu-jammy +spec: + template: + spec: + containers: + - name: download-ubuntu-jammy + image: bash:5.2.2 + command: [/script/entrypoint.sh] + args: + [ + https://cloud-images.ubuntu.com/daily/server/jammy/current/jammy-server-cloudimg-arm64.img, + /output, + ] + volumeMounts: + - mountPath: /output + name: hook-artifacts + - mountPath: /script + name: configmap-volume + restartPolicy: OnFailure + volumes: + - name: hook-artifacts + persistentVolumeClaim: + claimName: hook-artifacts + - name: configmap-volume + configMap: + defaultMode: "0700" + name: download-image diff --git a/services/tinkerbell/values.yaml b/services/tinkerbell/values.yaml new file mode 100644 index 000000000..b3ba0a0dd --- /dev/null +++ b/services/tinkerbell/values.yaml @@ -0,0 +1,16 @@ +# https://github.com/tinkerbell/charts/blob/main/tinkerbell/stack/README.md +global: + # The trusted proxies are the IP addresses of the nodes in the cluster. + trustedProxies: [192.168.104.1] + + # The public IP should be a free IP address in the network, not already taken by another device. + publicIP: 192.168.104.100 + +smee: + dhcp: + enabled: true + name: smee-dhcp + # There is already an existing DHCP server in the network + # so we're using the proxy mode + # See: https://github.com/tinkerbell/smee + mode: proxy diff --git a/services/tinkerbell/workflow.yaml b/services/tinkerbell/workflow.yaml new file mode 100644 index 000000000..4603d1f0d --- /dev/null +++ b/services/tinkerbell/workflow.yaml @@ -0,0 +1,10 @@ +apiVersion: tinkerbell.org/v1alpha1 +kind: Workflow +metadata: + name: playground-workflow +spec: + templateRef: ubuntu + hardwareRef: machine1 + hardwareMap: + device_1: 52:55:55:38:6f:53 + artifact_server_ip_port: 192.168.104.100:8080