General
Stop Hardcoding IPs: Dynamic K3s Cluster Setup with Terraform & Multipass
As DevOps engineers, we love automation. But we often hit a “Chicken and Egg” problem when building infrastructure: How do I configure Server B with Server A’s IP address, if Server A hasn’t even been created yet?
In this guide, we won’t just build a lightweight Kubernetes (K3s) cluster using Multipass and WSL. We are going to solve this dynamic configuration problem using one of Terraform’s most powerful features: the templatefile function.
By the end of this tutorial, you will have a running local lab and a solid understanding of how to inject dynamic data into your startup scripts.
1. The Setup & Prerequisites
Before we dive into the code, let’s quickly understand the tool that powers our infrastructure.
What is Multipass?
Developed by Canonical (the creators of Ubuntu), Multipass is a lightweight VM manager designed specifically for developers. Unlike heavy GUI-based tools, it spins up cloud-style Ubuntu instances in seconds.
It achieves this speed and efficiency by utilizing your operating system’s native hypervisor:
Hyper-V on Windows
KVM on Linux
QEMU/HyperKit on macOS
I’m going to assume you already have your development environment ready to go.
To follow along, you should have:
Multipass installed on Windows (handling the VMs)
Terraform installed inside WSL (Ubuntu)
WSL 2 active and running
A Quick Sanity Check for WSL Users
Even if both tools are installed, Terraform inside WSL might not “see” Multipass running on Windows because they live in different environments.
Before we start, make sure you’ve bridged the gap.
If multipass version fails inside your WSL terminal, run this quick fix to link the Windows executable to your Linux path:
Now that our tools are talking to each other, let’s focus on the code.
2. The Challenge: Dynamic IPs in Infrastructure
Imagine you are building a Kubernetes cluster.
You launch a Master Node. It gets a random IP from the DHCP.
You launch a Worker Node.
The Worker needs to run a “join command” that includes the Master’s IP.
If you were doing this manually, you would copy-paste the IP.
But in Terraform (IaC), we want zero manual intervention.
We need a way to tell Terraform:
“Wait for the Master to finish, grab its IP, write it into the Worker’s script, and THEN launch the Worker.”
This is exactly what templatefile does.
Terraform Tooltip: Understanding templatefile
Before we implement it, let’s briefly define what this function actually does.
What is it?
templatefile(path, vars) is a built-in Terraform function that reads a text file and renders it based on a set of variables you provide.
What is it used for?
It is primarily used to generate dynamic configuration files, shell scripts, or cloud-init data where the values (like IPs, Database URLs, or passwords) are not known until runtime.
Why use it?
It keeps your code clean.
Instead of writing messy, long shell scripts inside your main.tf using "heredoc" syntax, you can keep your scripts in separate files (like .sh or .yaml) and just inject the necessary data when Terraform runs.
Which Provider Are We Using?
To make this orchestration work on our local machine, we leverage the Multipass Provider, specifically larstobi/multipass.
Multipass is a lightweight VM manager by Canonical that uses native hypervisors like Hyper-V on Windows or QEMU on Linux.
By using this provider, Terraform can treat local VMs just like cloud instances, allowing us to automate the creation, resource allocation, and cloud-init execution of our Ubuntu nodes with ease.
3. The Solution: templatefile in Action
Let’s look at how we implemented this logic in our Terraform files.
Step A: The Template — worker_setup.tftpl
First, we create a shell script but save it with the .tftpl extension.
This is our "blueprint."
Instead of hardcoding values, we use placeholders like ${master_ip}.
Notice we aren’t writing 192.168.x.x.
We are writing variables that don't exist yet!
Step B: The Rendering — main.tf
Now, inside our Terraform code, we use the templatefile function to fill in the blanks dynamically.
What Is Happening Here?
1. Terraform builds the master instance first.
2. It grabs the new dynamic IP:
multipass_instance.master.ipv4
3. It reads worker_setup.tftpl.
4. It replaces ${master_ip} with the actual IP address.
5. It saves the result as a new file called worker_setup_rendered.yaml.
Step C: The Deployment
Finally, when the Worker node launches, it uses this rendered file, which now contains the correct, real-time connection details.

4. Why Use master_setup.yaml?
For the Master node, the setup is simpler since it doesn’t need to know anyone else’s IP.
We use a standard cloud-init YAML file.
A key detail here is running the install command in the background using &.
Why?
Because K3s installation might take a minute.
If we don’t push it to the background, Terraform might think the provisioning script is “stuck” and time out.
5. Launching the Lab
Now, let’s fire it up.
Open your terminal in the folder containing your .tf files.
Initialize Providers
Apply the Configuration
Watch the logs closely.
You will see the local_file resource being created after the master but before the worker.
This is the dependency graph at work.
6. Verifying the Cluster
Once Terraform finishes (usually in 2–3 minutes), let’s verify our lab environment.
Log Into the Master Node
Check the Kubernetes Nodes
You should see something like this:

Congratulations! You have successfully orchestrated a dynamic infrastructure where servers configure themselves based on real-time data.
Conclusion
While setting up a Kubernetes lab is useful, understanding Terraform templatefile is the real takeaway here.
We moved away from static configurations to a dynamic setup where:
1. Infrastructure Is Flexible
IP addresses can change, and the code still works.
2. Setup Is Automated
No manual copy-pasting of tokens or IPs.
3. Code Is Clean
Logic is separated from configuration.
You can use this same pattern for generating Ansible inventories, load balancer configs, or any scenario where Server B needs to know about Server A.
Source: https://medium.com/@ysnhasturk/stop-hardcoding-ips-dynamic-k3s-cluster-setup-with-terraform-multipass-6f511995df3e






