Creating a custom CoreOS AMI from scratch using Ansible - Part 1

Installing CoreOS to disk is easy using the self-contained installation script as described in the CoreOS documentation.

The problem is that you cannot normally target the installation process on the disk the instance is booted from. On AWS, and additional EBS disk can be attached to the instance and used as the target installation device.

This first post will quickly explain how the process can be fully automated using the following tools:

A second post will soon describe how to customize the installation.

The process is the following:

  • Create a helper instance from an existing AMI (Amazon Linux) from the AWS Marketplace
  • Attach an 4GB EBS disk to it
  • Fetch the self-contained installation script from the github repository
  • Run it with the appropriate arguments to install the OSE on the EBS disk
  • Create a snapshot of the EBS disk on which CoreOs has been installed
  • Terminate the helper instance to avoid costs
  • Register an AMI from the snapshot

There are many ways to use Ansible. Here is a simple sequential playbook to illustrate the process. Define your own account-specific parameters and adapt to your region. It currently depends on the following https://github.com/ansible/ansible-modules-core/pull/4075.

---
# Simple CoreOS image creation playbook

- name: Bootstrap image process begins
  hosts: localhost
  connection: local
  gather_facts: False

  tasks:

    - name: Provision Helper Instance
      ec2:
         region: "eu-west-1"
         zone: "eu-west-1a"
         instance_type: "t2.micro"
         image: "ami-f9dd458a"
         key_name: "{{ key_name }}"
         group: "{{ sec_group_name }}"
         vpc_subnet_id: "{{ vpc_subnet_id }}"
         wait: true
         exact_count: 1
         count_tag:
            Name: "helper"
         volumes:
            - device_name: "/dev/xvda"
              volume_size: 8
              delete_on_termination: true
      register: ec2

    - name: Attach a 4 GB EBS volume to helper instance
      ec2_vol:
         region: "eu-west-1"
         zone: "eu-west-1a"
         instance: "{{ item.id }}"
         state: present
         volume_size: "4"
         device_name: "/dev/xvdb"
         delete_on_termination: yes
      with_items: "{{ ec2.instances }}"
      register: ec2_vol_bootdisk

    - name: Saving EBS volume id (required later to snapshot it)
      local_action: command echo {{ item.volume_id }}
      register: ec2_vol_bootdisk_id
      with_items: "{{ ec2_vol_bootdisk.results }}"

    - name: Wait for cloud-init process to setup SSH keys (could be optimized)
      pause: minutes=2

    - name: Add helper instance to running instances host group
      add_host: hostname={{ item.private_dns_name }} groupname=launched
      with_items: "{{ ec2.instances }}"


- name: Triggering installation process on helper instance
  hosts: launched
  remote_user: "ec2-user"
  gather_facts: False

  tasks:
  
    - name: Fetching custom installation script on the helper instance
      get_url: url=https://raw.githubusercontent.com/coreos/init/master/bin/coreos-install dest=/tmp/install.sh mode=755

    - name: Running installation script on helper instance
      shell: /tmp/install.sh -d /dev/xvdb >> install.log 2>&1 chdir=/tmp/
      become: true


- name: Creating AMI
  hosts: localhost
  connection: local
  gather_facts: False

  tasks:
  
    - name: Snapshotting AMI root device on EBS volume '{{ ec2_vol_bootdisk.results.volume_id }}'
      ec2_snapshot:
         region: "eu-west-1"
         volume_id: "{{ item.volume_id }}"
      register: snapshot_bootdisk
      with_items: "{{ ec2_vol_bootdisk.results }}"

    - name: Terminating helper instance '{{ec2.instances }}'
      ec2:
         region: "eu-west-1"
         zone: "eu-west-1a"
         instance_ids: "{{ item.id }}"
         state: absent
      with_items: "{{ ec2.instances }}"

    - name: Registering image
      ec2_ami:
        region: "{{ eu-west-1 }}"
        name: "CoreOS latest"
        description: "CoreOS - latest"
        snapshot_id: "{{ snapshot_bootdisk.results[0].snapshot_id }}"
        architecture: "x86_64"
        root_device_name: "/dev/xvda"
        virtualization_type: "hvm"
        sriov_net_support: "simple"
        delete_root_volume_on_termination: true
        volumes:
          - device_name: "/dev/xvda"
            snapshot: "{{ snapshot_bootdisk.results[0].snapshot_id }}"
            volume_size: "4"
            device_type: gp2
            delete_on_termination: true
      register: ec2_ami

    - name: ID of newly AMI created
      debug: msg="AMIID={{ ec2_ami.image_id }}"