Skip to content

Creating an instance with Ansible

This tutorial shows how to create an instance and run an nginx web server on Breqwatr Cloud using Ansible.

Prerequisites

  • Python 3 and pip on your Ansible host.
  • Ansible installed (see Install Ansible below).
  • The openstack.cloud Ansible collection (installed below).
  • The Ansible host connected to the same internal network as the instance it will deploy. The host's public key is used as the key pair injected into the new instance.
python3 -m venv ~/ansible-openstack
source ~/ansible-openstack/bin/activate

Install Ansible

You can use your Linux distribution's package manager:

sudo apt install ansible       # Ubuntu/Debian
sudo dnf install ansible       # RHEL / Fedora / Rocky / Alma

Or use pip on any operating system:

pip install ansible

Install the openstack.cloud collection

ansible-galaxy collection install openstack.cloud
pip install ansible openstacksdk

Place a clouds.yaml file

Ansible's openstack.cloud collection reads credentials from clouds.yaml. Don't hand-roll one — download a ready-made file from the Portal's Application credentials page (the same file works for Ansible, Terraform, and the OpenStack CLI). Move it to either of:

  • A working directory next to your playbooks (the collection picks it up from the current dir).
  • The shared user location at ~/.config/openstack/clouds.yaml (or %APPDATA%\openstack\clouds.yaml on Windows) so every tool that reads clouds.yaml shares one file.

The downloaded entry is named breqwatr. Tell the openstack.cloud modules which entry to use by setting OS_CLOUD once in your shell:

export OS_CLOUD=breqwatr

or by passing cloud: breqwatr on every module call (the modules support both).

Steps

1. Create the playbooks

The following playbook create-server.yaml will create:

  • A security group for HTTP and one for SSH
  • Matching ingress rules
  • A v1.c1r4 instance
---
- name: Create a new instance and attach it to a network
  hosts: localhost
  connection: local
  gather_facts: false

  vars:
    # Server variables
    server_name: test-ansible
    image_id: 533cf45e-7284-4594-84a7-13d64065b7d2
    flavor_name: v1.c1r4
    keypair_name: ansible
    volume_size_gb: 20
    network_name: cloud-docs-net

    # Security groups
    sg_ssh: ssh-ansible
    sg_http: http-hello-world

  tasks:
    - name: Create SSH security group
      openstack.cloud.security_group:
        state: present
        name: "{{ sg_ssh }}"
        description: Security group for SSH

    - name: Create SSH security group rule
      openstack.cloud.security_group_rule:
        security_group: "{{ sg_ssh }}"
        protocol: tcp
        port_range_min: 22
        port_range_max: 22
        remote_ip_prefix: 0.0.0.0/0

    - name: Create HTTP security group
      openstack.cloud.security_group:
        state: present
        name: "{{ sg_http }}"
        description: Security group for HTTP

    - name: Create HTTP security group rule
      openstack.cloud.security_group_rule:
        security_group: "{{ sg_http }}"
        protocol: tcp
        port_range_min: 80
        port_range_max: 80
        remote_ip_prefix: 0.0.0.0/0

    - name: Create the server
      openstack.cloud.server:
        state: present
        name: "{{ server_name }}"
        image: "{{ image_id }}"
        key_name: "{{ keypair_name }}"
        flavor: "{{ flavor_name }}"
        timeout: 200
        nics:
          - net-name: "{{ network_name }}"
        security_groups:
          - "{{ sg_http }}"
          - "{{ sg_ssh }}"
          - default
        boot_from_volume: true
        volume_size: "{{ volume_size_gb }}"
        auto_ip: false

    - name: Get server information
      openstack.cloud.server_info:
        server: "{{ server_name }}"
      register: server_info

    - name: Extract private IP address
      set_fact:
        private_ip: "{{ server_info.servers[0].addresses[network_name][0].addr }}"

    - name: Display server IP address
      debug:
        msg: "Server {{ server_name }} private IP: {{ private_ip }}"

For installing nginx, create install-nginx.yaml:

---
- name: Install and configure nginx
  hosts: test-ansible
  become: true
  tasks:
    - name: Install nginx
      ansible.builtin.dnf:
        name: nginx
        state: present
        update_cache: yes

    - name: Enable and start nginx
      ansible.builtin.systemd:
        name: nginx
        state: started
        enabled: true

    - name: Create test index page
      ansible.builtin.copy:
        dest: /usr/share/nginx/html/index.html
        content: "<h1>Nginx is working</h1>"

For cleanup, create cleanup.yaml:

---
- name: Clean up server and security groups
  hosts: localhost
  connection: local

  vars:
    # Resources to delete
    server_name: "test-ansible"
    security_groups:
      - "http-hello-world"
      - "ssh-ansible"

  tasks:
    - name: Remove server (if present)
      openstack.cloud.server:
        name: "{{ server_name }}"
        state: absent

    - name: Remove security groups (if present)
      openstack.cloud.security_group:
        name: "{{ item }}"
        state: absent
      loop: "{{ security_groups }}"

2. Run the create-server playbook

ansible-playbook create-server.yaml

This will create the instance and output its IP address. Copy the IP and create an inventory file:

Note: The ansible_user depends on the Linux distribution cloud image you deploy.

test-ansible  ansible_host=<ip-address> ansible_user=almalinux

Replace <ip-address> with the IP of your instance and save the file.

3. Install nginx on the instance

ansible-playbook -i inventory install-nginx.yaml

Verification

Type the IP address of your instance into your browser. You should see the Nginx test page titled "Nginx is working".

Cleanup

To remove the instance and the security groups you just created:

ansible-playbook cleanup.yaml

This removes the security groups http-hello-world and ssh-ansible, and any instance in your project named test-ansible.

Next steps