In an earlier post, I provided details on how I use terraform to manage virtual machines in my Proxmox installation. This time, we’re going to deploy Linux Containers to Proxmox via Terraform.
Why LXC? For workloads that do not require a full virtual machine, LXC provides a lightweight virtualization technology that uses the host’s kernel This makes LXC containers more resource efficient, faster to start, and more performant than a virtual machine. Each container operates in its own namespace, offering application isolation with its own network stack, process space, and mount points.
Why not LXC? Anything that gets too deep into playing with kernel bits - such as nested virtualization, using certain devices, etc - will likely have a bad time. That’s not to say you shouldn’t try them - I mean where is the fun in that? - but you should be ready to endure failure.
Proxmox provides a variety of basic templates for the most common Linux distributions, as well as
Turnkey Linux container images. These templates can be viewed and downloaded from
the Proxmox command line using the pveam
utility. Since disk is cheap, I just have an ansible playbook that I run
periodically that finds all the available templates and downloads them:
---
- hosts: all
gather_facts: no
tasks:
- name: Update the list of container images
command: pveam update
become: yes
- name: Get list of available templates
shell: "pveam available"
register: available_templates
- name: Download templates
shell: "pveam download iris {{ item.split()[1] }}"
loop: "{{ available_templates.stdout_lines }}"
ignore_errors: yes
become: yes
- name: List all installed container templates
shell: "pveam list local"
register: installed_templates
- name: Output all installed container templates
debug:
var: installed_templates.stdout_lines
We’re going to use the same terraform provide that we used for our VM deployment - Telmate - because it also provides us with the ability to manage containers.
It’s important to note that there are some differences between containers and vms. For one, the containers all are
logged into as the root
user. The console can be accessed on the host system, or via the proxmox gui. You can provide
a password during the installation process, or if you are accessing over the network you can use an ssh key that is
provided at provision time.
So, let’s get to deploying some containers!
First, we set our variables:
# Proxmox API configuration
proxmox_api_url = "https://<proxmox-api-url>"
proxmox_username = "<username>@<auth-realm>"
proxmox_password = "<password>"
proxmox_tls_insecure = "<true-or-false>"
# Container configuration
container_count = <number-of-containers>
name_prefix = "<container-name-prefix>"
template = "<template-location>"
storage = "<storage-location>"
user_password = "<user-password>"
ssh_keys = "<sshkeys-in-heredoc-form"
# Resource allocation
cores = <number-of-cores>
disk_size = "<disk-size>"
memory = <memory-size>
# Network configuration
network_model = "<network-model>"
network_bridge = "<network-bridge>"
network_ipv4 = "<network-ipv4>"
# Node configuration
node = [
"<node1>", "<node2>", "<node3>"
]
Then, we have our main terraform file:
terraform {
required_providers {
proxmox = {
source = "telmate/proxmox"
version = ">= 2.0.0"
}
}
}
variable "proxmox_api_url" {
description = "The API URL for the Proxmox provider."
type = string
}
variable "proxmox_username" {
description = "The user for the Proxmox provider."
type = string
}
variable "proxmox_password" {
description = "The password for the Proxmox provider."
type = string
sensitive = true
}
variable "user_password" {
description = "The password for the LXC user."
type = string
sensitive = true
}
variable "proxmox_tls_insecure" {
description = "Whether to disable TLS verification for the Proxmox provider."
type = bool
}
variable "storage" {
description = "The storage to use for the containers."
type = string
}
variable "name_prefix" {
description = "The prefix for the name of the containers."
type = string
}
variable "node" {
description = "The node where you want the containers to be created at."
type = list(string)
}
variable "container_count" {
description = "The number of containers to create."
type = number
}
variable "template" {
description = "The template to use for creating the containers."
type = string
}
variable "memory" {
description = "The amount of memory for the containers."
type = number
}
variable "cores" {
description = "The number of cores for the containers."
type = number
}
variable "disk_size" {
description = "The disk size for the containers."
type = string
}
variable "network_model" {
description = "The network model for the containers."
type = string
}
variable "network_bridge" {
description = "The network bridge for the containers."
type = string
}
variable "network_ipv4" {
description = "The IPv4 address for the containers."
type = string
}
variable "ssh_keys" {
description = "The SSH keys to use for the VMs."
type = string
}
provider "proxmox" {
pm_api_url = var.proxmox_api_url
pm_user = var.proxmox_username
pm_password = var.proxmox_password
pm_tls_insecure = var.proxmox_tls_insecure
}
resource "proxmox_lxc" "example_container" {
count = var.container_count
hostname = "${var.name_prefix}${count.index}"
ostemplate = var.template
unprivileged = true
target_node = var.node[count.index % length(var.node)]
memory = var.memory
cores = var.cores
password = var.user_password
onboot = true
hastate = "started"
ssh_public_keys = var.ssh_keys
rootfs {
storage = var.storage
size = var.disk_size
}
network {
name = "eth0"
bridge = var.network_bridge
ip = var.network_ipv4
ip6 = "auto"
}
}
output "container_name" {
description = "The names of the created containers"
value = [for i in proxmox_lxc.example_container : i.hostname]
}
Just like with our other example, to run, you simply update the variables file with your parameters and then do the normal “terraform plan / terraform apply” dance, being sure to pass the variables file along:
$ terraform plan -var-file="variables.tfvars"
$ terraform apply -var-file="variables.tfvars"
When you are done, you can simply remove your deployed infrastructure with:
$ terraform destroy -var-file="variables.tfvars"