Skip to content

Commit

Permalink
Template provisioning works!
Browse files Browse the repository at this point in the history
TODO:

* default user created by cloud-init is "ubuntu"
* mfisher user doesn't have expected pubkey. Should we _only_ use the
  cloud-init mechanism to create the user?
* Docker doesn't install correctly
  • Loading branch information
mfisher87 committed Jan 28, 2024
1 parent 6913be1 commit 2a5d7b3
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 33 deletions.
24 changes: 24 additions & 0 deletions src/vm-templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ their filename.
> **These should never be committed**, and are `.gitignore`d.

## Directory structure

In each template directory, there are additional files and directories.


### `http/` directory

This is where cloud-init config, which is hosted by a Packer HTTP server during
provisioning, lives.


## Usage

`cd` into a template directory and run a command to validate or build that template.
Expand All @@ -54,6 +65,19 @@ packer validate .
packer build .
```

This will create a VM template in Proxmox.


### Instantiating a VM from clone

Right-click the template and select "Clone". A "Linked clone" is fast, but depends on
the template. A "Full clone" is slower and independent.

:::{.callout-warning}
It is *very important* to set the IP config in the cloud-init settings of the new VM,
otherwise networking will fail.
:::


## References

Expand Down
80 changes: 50 additions & 30 deletions src/vm-templates/ubuntu-22.04/build.pkr.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,34 @@ source "proxmox-iso" "ubuntu-22-04" {
proxmox_url = "${var.proxmox_api_url}"
username = "${var.proxmox_api_token_id}"
token = "${var.proxmox_api_token_secret}"
insecure_skip_tls_verify = false
# NOTE: Self-signed / auto-generated PVE certs will fail (unknown authority)
# without this option:
# TODO: ACME certs
insecure_skip_tls_verify = true

node = "mrpl-vhost02"
vm_id = "10001"
# NOTE: Periods not allowed in VM names for DNS reasons
vm_name = "template-ubuntu-22-04"
template_description = "An Ubuntu Jammy (22.04) VM with users and many dependencies pre-installed"

iso_file = "https://releases.ubuntu.com/22.04.3/ubuntu-22.04.3-live-server-amd64.iso"
iso_checksum = "sha256:a4acfda10b18da50e2ec50ccaf860d7f20b389df8765611142305c0e911d16fd"
iso_url = "https://releases.ubuntu.com/22.04.3/ubuntu-22.04.3-live-server-amd64.iso"
iso_checksum = "sha256:a4acfda10b18da50e2ec50ccaf860d7f20b389df8765611142305c0e911d16fd"
iso_storage_pool = "iso"
unmount_iso = true

qemu_agent = true

scsi_controller = "virtio-scsi-pci"

cores = "1"
cores = "2"
sockets = "1"
memory = "2048"
memory = "4096"

cloud_init = true
# NOTE: By default, the storage pool of the boot disk is used:
# cloud_init_storage_pool = "local-lvm"
# NOTE: By default, the storage pool of the boot disk is used, but that's not working
# "cloud_init is set to true, but cloud_init_storage_pool is empty and could not be set automatically."
cloud_init_storage_pool = "local"

vga {
# NOTE: "std" is the same as "Default" in the proxmox GUI. Works fine. Why
Expand All @@ -49,7 +53,7 @@ source "proxmox-iso" "ubuntu-22-04" {
bridge = "vmbr0"
# MAC address is deterministic based on VM ID and NIC ID:
mac_address = "repeatable"
firewall = "false"
firewall = "true"
}

boot_command = [
Expand All @@ -69,13 +73,19 @@ source "proxmox-iso" "ubuntu-22-04" {
http_directory = "./http"

# TODO: Can't this just be "root"? What about a default var value?
# TODO: What is the minimal set we actually need??
# TODO: Create a temp provisioning user in addition to the user(s) that will
# be permanent.
ssh_username = "${var.ssh_username}"
ssh_password = "${var.ssh_password}"
ssh_private_key_file = "${var.ssh_private_key_file}"

ssh_handshake_attempts = 15
ssh_pty = true
# Time to wait for SSH to be ready:
ssh_timeout = "10m"
# NOTE: The whole OS install process must complete, so we need longer than
# the default 10m.
ssh_timeout = "20m"
}

build {
Expand Down Expand Up @@ -109,32 +119,42 @@ build {
}

# Configure cloud-init data sources (described in docs as a boot-time optimization):
# NOTE: The documentation for file provisioner
# (https://developer.hashicorp.com/packer/docs/provisioners/file) says
# this is the only way to get files to root-owned locations.
provisioner "file" {
source = "./99-pve.cfg"
destination = "/etc/cloud/cloud.cfg.d/99-pve.cfg"
destination = "/tmp/99-pve.cfg"
}

# Install docker per docs: https://docs.docker.com/engine/install/ubuntu/
provisioner "shell" {
inline = [
"sudo apt-get install -y ca-certificates curl gnupg",
"sudo install -m 0755 -d /etc/apt/keyrings",
"curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg",
"sudo chmod a+r /etc/apt/keyrings/docker.gpg",
"echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(source /etc/os-release && echo \"$VERSION_CODENAME\") stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null",
"sudo apt-get -y update",
"sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin",
]
}

# Clean up
provisioner "shell" {
execute_command = "echo -e '<user>' | sudo -S -E bash '{{ .Path }}'"
inline = [
"sudo userdel -r ${var.ssh_username}",
"sudo groupdel ${var.ssh_username}",
"sudo apt -y autoremove --purge",
"sudo apt -y clean",
"sudo apt -y autoclean",
"sudo mv /tmp/99-pve.cfg /etc/cloud/cloud.cfg.d/.",
]
}

# Install docker per docs: https://docs.docker.com/engine/install/ubuntu/
# TODO: Try NEEDRESTART_MODE to get past last step?? https://askubuntu.com/questions/1367139/apt-get-upgrade-auto-restart-services
# provisioner "shell" {
# inline = [
# "sudo apt-get install -y ca-certificates curl gnupg lsb-release",
# "sudo install -m 0755 -d /etc/apt/keyrings",
# "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg",
# "sudo chmod a+r /etc/apt/keyrings/docker.gpg",
# "echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null",
# "sudo apt-get -y update",
# "sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin",
# ]
# }

# # Clean up
# provisioner "shell" {
# inline = [
# "sudo userdel -r ${var.ssh_username}",
# "sudo groupdel ${var.ssh_username}",
# "sudo apt -y autoremove --purge",
# "sudo apt -y clean",
# "sudo apt -y autoclean",
# ]
# }
}
1 change: 1 addition & 0 deletions src/vm-templates/ubuntu-22.04/http/user-data
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ autoinstall:
user-data:
package_upgrade: true
timezone: "America/Denver"
ssh_pwauth: true
users:
- name: "mfisher"
groups: ["adm", "sudo"]
Expand Down
10 changes: 7 additions & 3 deletions src/vm-templates/ubuntu-22.04/vars.pkr.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ variable "proxmox_api_token_secret" {

variable "ssh_username" {
type = string
description = "The username used during provisioning"
default = "root"
description = "The username used during provisioning. MUST NOT be root, as SSH as root is disabled."
}

variable "ssh_password" {
type = string
description = "The password used during provisioning"
sensitive = true
}

# TODO: ...filepath?
variable "ssh_private_key_file" {
type = string
description = "I don't think we actually need this? I read that Packer will generate a keypair for provisioning."
Expand Down

0 comments on commit 2a5d7b3

Please sign in to comment.