Incus Challenges
These are here for anybody new who wants to try and learn more about terraform / incus by doing.
These challenges were created in part using AI. If something does not make sense reach out to me @Hugh Sweazy on discord.
Challenge 1: Launch a Single Instance
Difficulty: Easy
Goal: Get comfortable with the basic workflow of defining an Incus instance in Terraform, launching it, and destroying it.
Make sure to create a profile and associate it with all your resouces
Tasks:
- Create a Terraform configuration file (main.tf).
- Define a resource of type incus_instance to create an Ubuntu container. Use the default ubuntu/22.04 image.
- Name the instance my-first-container.
- Push the code to gitlab and let the pipeline run.
- Check the plan output and see if everything checks out.
- Run the apply pipeline job
- After a successful apply job run check the Incus UI, make sure to select your profile in the top left.
- Once confirmed, run terraform destroy to clean up the resource.
Challenge 2: Networking and Instance Communication
Difficulty: Medium
Goal: Understand how to create custom networks and connect multiple instances to them.
Make sure to create a profile and associate it with all your resouces
Tasks:
- Define an incus_network resource to create a new bridge network named private-net.
- Define two incus_instance resources, instance-1 and instance-2.
- Attach both instances to the private-net you created.
- Assign static IPv4 addresses to each instance within the network's subnet (e.g., 10.0.1.10 for instance-1 and 10.0.1.11 for instance-2). You may need to configure the network's IP range.
- Use a provisioner "remote-exec" block within the instance-1 resource to run a command that pings instance-2's IP address to verify connectivity.
- Apply the configuration and check the output to ensure the ping was successful.
- Destroy the resources.
Challenge 3: Configuration with Profiles and Cloud-Init
Difficulty: Medium
Goal: Learn how to apply a common configuration to instances using Incus profiles and customize them at launch with cloud-init.
Make sure to create a profile and associate it with all your resouces
Tasks:
- Define an incus_profile resource named web-server-profile.
- In this profile, set resource limits, for example, limits.cpu \= "1" and limits.memory \= "512MB".
- Define a single incus_instance named web-server.
- Assign the web-server-profile to this instance.
- In the incus_instance resource, use the user_data argument to provide a cloud-init configuration.
- The cloud-init script should perform the following actions:
- Update package lists (apt-get update).
- Install the nginx web server (apt-get install -y nginx).
- Start and enable the nginx service.
- Apply the configuration and use incus exec web-server -- systemctl status nginx to verify that Nginx is running inside the container.
- Destroy the resources.
Challenge 4: Managing Storage
Difficulty: Hard
Goal: Understand how to create and manage dedicated storage volumes and attach them to instances, which is crucial for stateful applications.
Make sure to create a profile and associate it with all your resouces
Tasks:
- Manually create a new storage pool if you only have the default. For example: incus storage create data dir.
- In your Terraform configuration, define an incus_storage_volume resource.
- Name the volume app-data.
- Assign it to the data storage pool you created.
- Define an incus_instance named database-server.
- Use the incus_storage_volume_attachment resource to attach the app-data volume to the database-server instance.
- Specify the attachment path inside the container as /mnt/data.
- Use a provisioner "remote-exec" to create a file on the attached volume, for example: touch /mnt/data/test.txt.
- Apply the configuration.
- Verify the volume is attached and the file exists by running incus exec database-server -- ls /mnt/data.
- Destroy the resources.
Challenge 5: Dynamic Inventory for Ansible
Difficulty: Hard
Goal: Integrate Terraform with another tool, Ansible. This challenge involves creating multiple instances and dynamically generating a configuration file that another tool can use.
Make sure to create a profile and associate it with all your resouces
Tasks:
- Use the count meta-argument in your incus_instance resource block to create three identical instances with a common prefix (e.g., web-prod-1, web-prod-2, web-prod-3).
- Ensure these instances are connected to a network where they have predictable IP addresses.
- Use the local_file resource from the hashicorp/local provider to generate an Ansible inventory file named inventory.ini.
- The content of the local_file resource should be dynamically generated using Terraform's template syntax.
- The inventory file should have a group named [webservers].
-
Iterate through the created Incus instances and add each instance's IP address to the [webservers] group. The result should look something like this:
[webservers]
10.0.1.21
10.0.1.22
10.0.1.23 -
Apply the configuration and verify that the inventory.ini file is created correctly in your project directory.
- (Bonus) Write a simple Ansible playbook to install a package on the webservers group and run it using ansible-playbook -i inventory.ini my-playbook.yml to confirm your dynamic inventory works.
- Destroy all resources.