├── .gitignore ├── README.md ├── cloud-init ├── meta-data └── user-data ├── scripts ├── cleanup.sh └── install.sh └── ubuntu.pkr.hcl /.gitignore: -------------------------------------------------------------------------------- 1 | # built images 2 | *.img 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # packer-ubuntu-cloud-image 2 | 3 | Build Ubuntu virtual machine images using [Packer qemu builder](https://developer.hashicorp.com/packer/plugins/builders/qemu) with the Ubuntu [Cloud Images](https://cloud-images.ubuntu.com/) as the disk image source. 4 | Ubuntu cloud images are conventient to build fast and produce cloud-init friendly images. 5 | 6 | ## Dependencies 7 | 8 | * Install [Hashicorp Packer](https://www.packer.io/) 9 | * Install [Qemu](https://www.qemu.org/download/) 10 | * Install a compatible ISO generation tool (`xorriso`, `mkisofs`, `hdiutil`, or `oscdimg`). See [Packer qemu docs](https://developer.hashicorp.com/packer/plugins/builders/qemu#cd-configuration) for more information. 11 | 12 | ## Building Images 13 | 14 | Update the `scripts/install.sh` script to manage what packages are installed during image provisioning. By default, `qemu-guest-agent` and `docker-ce` are installed. 15 | 16 | ### Build Default Ubuntu Version 17 | 18 | Install required plugins: 19 | 20 | ```shell 21 | $ packer init ubuntu.pkr.hcl 22 | ``` 23 | 24 | Run the Packer build. By default an Ubuntu 22.04 (jammy) image is built: 25 | 26 | ```shell 27 | $ packer build ubuntu.pkr.hcl 28 | ==> qemu.ubuntu: Retrieving ISO 29 | ==> qemu.ubuntu: Trying https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img 30 | ... 31 | ==> qemu.ubuntu: Gracefully halting virtual machine... 32 | ==> qemu.ubuntu: Converting hard drive... 33 | Build 'qemu.ubuntu' finished after 1 minute 56 seconds. 34 | 35 | ==> Wait completed after 1 minute 56 seconds 36 | 37 | ==> Builds finished. The artifacts of successful builds are: 38 | --> qemu.ubuntu: VM files in directory: output-jammy 39 | ``` 40 | 41 | Generated images will be in `output-/ubuntu-.img`. 42 | 43 | ```shell 44 | $ ls -lh output-jammy 45 | total 962M 46 | -rw-r--r-- 1 user user 963M Feb 5 14:53 ubuntu-jammy.img 47 | ``` 48 | 49 | ### Build Specific Ubuntu Version 50 | 51 | Pass a packer variable `ubuntu_version` to set the Ubuntu cloud image to use as a source. 52 | See available versions on the [Ubuntu Cloud Images](https://cloud-images.ubuntu.com/) page. 53 | 54 | For example, pass `-var ubuntu_version=focal` to build with the Ubuntu 20.04 "focal" image: 55 | 56 | ```shell 57 | $ packer build -var ubuntu_version=focal ubuntu.pkr.hcl 58 | ==> qemu.ubuntu: Retrieving ISO 59 | ==> qemu.ubuntu: Trying https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img 60 | ... 61 | ==> qemu.ubuntu: Gracefully halting virtual machine... 62 | ==> qemu.ubuntu: Converting hard drive... 63 | Build 'qemu.ubuntu' finished after 1 minute 55 seconds. 64 | 65 | ==> Wait completed after 1 minute 55 seconds 66 | 67 | ==> Builds finished. The artifacts of successful builds are: 68 | --> qemu.ubuntu: VM files in directory: output-focal 69 | ``` 70 | 71 | ## Troubleshooting 72 | 73 | Pass or set the environment variable `PACKER_LOG=1` to provide additional debug logging output to help troubleshoot build issues. 74 | 75 | ```shell 76 | $ PACKER_LOG=1 packer build ubuntu.pkr.hcl 77 | 2023/02/05 14:48:44 [INFO] Packer version: 1.8.5 [go1.19.4 linux amd64] 78 | 2023/02/05 14:48:44 [TRACE] discovering plugins in /usr/bin 79 | 2023/02/05 14:48:44 [TRACE] discovering plugins in /home/user/.config/packer/plugins 80 | 2023/02/05 14:48:44 [TRACE] discovering plugins in . 81 | 2023/02/05 14:48:44 [INFO] PACKER_CONFIG env var not set; checking the default config file path 82 | ... 83 | 84 | ``` 85 | -------------------------------------------------------------------------------- /cloud-init/meta-data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nbarnum/packer-ubuntu-cloud-image/9f999c1cca66aaf34bad2d8f736f9b23405d85ef/cloud-init/meta-data -------------------------------------------------------------------------------- /cloud-init/user-data: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | password: ubuntu 3 | ssh_pwauth: true 4 | chpasswd: 5 | expire: false 6 | -------------------------------------------------------------------------------- /scripts/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | echo "==> remove SSH keys used for building" 3 | rm -f /home/ubuntu/.ssh/authorized_keys 4 | rm -f /root/.ssh/authorized_keys 5 | 6 | echo "==> Clear out machine id" 7 | truncate -s 0 /etc/machine-id 8 | 9 | echo "==> Remove the contents of /tmp and /var/tmp" 10 | rm -rf /tmp/* /var/tmp/* 11 | 12 | echo "==> Truncate any logs that have built up during the install" 13 | find /var/log -type f -exec truncate --size=0 {} \; 14 | 15 | echo "==> Cleanup bash history" 16 | rm -f ~/.bash_history 17 | 18 | echo "remove /usr/share/doc/" 19 | rm -rf /usr/share/doc/* 20 | 21 | echo "==> remove /var/cache" 22 | find /var/cache -type f -exec rm -rf {} \; 23 | 24 | echo "==> Cleanup apt" 25 | apt-get -y autoremove 26 | sudo apt-get clean 27 | sudo rm -rf /var/lib/apt/lists/* 28 | 29 | echo "==> force a new random seed to be generated" 30 | rm -f /var/lib/systemd/random-seed 31 | 32 | echo "==> Clear the history so our install isn't there" 33 | rm -f /root/.wget-hsts 34 | 35 | export HISTSIZE=0 36 | -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | echo "==> waiting for cloud-init to finish" 4 | while [ ! -f /var/lib/cloud/instance/boot-finished ]; do 5 | echo 'Waiting for Cloud-Init...' 6 | sleep 1 7 | done 8 | 9 | echo "==> updating apt cache" 10 | sudo apt-get update -qq 11 | 12 | echo "==> upgrade apt packages" 13 | sudo apt-get upgrade -y -qq 14 | 15 | echo "==> installing qemu-guest-agent" 16 | sudo apt-get install -y -qq qemu-guest-agent 17 | 18 | echo "==> installing docker-ce" 19 | 20 | sudo apt-get install -y \ 21 | ca-certificates \ 22 | curl \ 23 | gnupg \ 24 | lsb-release 25 | 26 | sudo mkdir -p /etc/apt/keyrings 27 | 28 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 29 | 30 | echo \ 31 | "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ 32 | $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 33 | 34 | sudo apt-get update -qq 35 | 36 | sudo apt-get install -y \ 37 | docker-ce \ 38 | docker-ce-cli \ 39 | containerd.io \ 40 | docker-compose-plugin 41 | -------------------------------------------------------------------------------- /ubuntu.pkr.hcl: -------------------------------------------------------------------------------- 1 | packer { 2 | required_plugins { 3 | qemu = { 4 | source = "github.com/hashicorp/qemu" 5 | version = "~> 1" 6 | } 7 | } 8 | } 9 | 10 | variable "qemu_accelerator" { 11 | type = string 12 | default = "kvm" 13 | description = "Qemu accelerator to use. On Linux use kvm and macOS use hvf." 14 | } 15 | 16 | variable "ubuntu_version" { 17 | type = string 18 | default = "jammy" 19 | description = "Ubuntu codename version (i.e. 20.04 is focal and 22.04 is jammy)" 20 | } 21 | 22 | source "qemu" "ubuntu" { 23 | accelerator = var.qemu_accelerator 24 | cd_files = ["./cloud-init/*"] 25 | cd_label = "cidata" 26 | disk_compression = true 27 | disk_image = true 28 | disk_size = "10G" 29 | headless = true 30 | iso_checksum = "file:https://cloud-images.ubuntu.com/${var.ubuntu_version}/current/SHA256SUMS" 31 | iso_url = "https://cloud-images.ubuntu.com/${var.ubuntu_version}/current/${var.ubuntu_version}-server-cloudimg-amd64.img" 32 | output_directory = "output-${var.ubuntu_version}" 33 | shutdown_command = "echo 'packer' | sudo -S shutdown -P now" 34 | ssh_password = "ubuntu" 35 | ssh_username = "ubuntu" 36 | vm_name = "ubuntu-${var.ubuntu_version}.img" 37 | qemuargs = [ 38 | ["-m", "2048M"], 39 | ["-smp", "2"], 40 | ["-serial", "mon:stdio"], 41 | ] 42 | } 43 | 44 | build { 45 | sources = ["source.qemu.ubuntu"] 46 | 47 | provisioner "shell" { 48 | // run scripts with sudo, as the default cloud image user is unprivileged 49 | execute_command = "echo 'packer' | sudo -S sh -c '{{ .Vars }} {{ .Path }}'" 50 | // NOTE: cleanup.sh should always be run last, as this performs post-install cleanup tasks 51 | scripts = [ 52 | "scripts/install.sh", 53 | "scripts/cleanup.sh" 54 | ] 55 | } 56 | } 57 | --------------------------------------------------------------------------------