When deploying applications on AWS, manually setting up instances every time can be time-consuming. Instead, we can create a pre-configured Amazon Machine Image (AMI) using Packer and Ansible, allowing us to launch instances that are ready to go with minimal setup.
This article explains how to use Packer to build an AWS AMI and Ansible to configure the instance during the build process.
Why Use Packer and Ansible?
- Packer automates the AMI creation process, ensuring consistency and repeatability.
- Ansible allows us to configure the AMI with required software and settings in a declarative manner.
- Using both together helps create a golden image that is secure, optimized, and production-ready.
Repo: https://github.com/man20820/packer-ansible-nginx
Prerequisites
Before getting started, ensure you have the following:
- An AWS account with necessary permissions to create AMIs.
- Packer installed
- Ansible installed
- IAM Credentials configured via ~/.aws/credentials or environment variables.
Folder Structure
❯ tree . ├── files │ └── default ├── nginx.pkr.hcl └── nginx.yaml 1 directory, 3 files
Create the Ansible Playbook
on this article, i will create nginx for example. you can customize your needs..
nginx.yaml
--- - name: Install and Configure Nginx hosts: all become: yes # Run as sudo tasks: - name: Install Nginx on Debian-based systems apt: name: nginx state: present update_cache: yes when: ansible_os_family == "Debian" - name: Install Nginx on RHEL-based systems yum: name: nginx state: present when: ansible_os_family == "RedHat" - name: Start and Enable Nginx Service systemd: name: nginx state: started enabled: yes - name: Deploy Custom Nginx Configuration copy: src: files/default dest: /etc/nginx/sites-available/default owner: root group: root mode: '0644' notify: Restart Nginx handlers: - name: Restart Nginx systemd: name: nginx state: restarted
Create the Packer Template
packer { required_plugins { amazon = { source = "github.com/hashicorp/amazon" version = "~> 1.2.8" } ansible = { version = ">= 1.1.2" source = "github.com/hashicorp/ansible" } } } source "amazon-ebs" "custom-ami" { ami_name = "nginx" instance_type = "t3.micro" region = "ap-southeast-3" source_ami = "ami-0d22ac6a0e117cefe" ssh_username = "ubuntu" tags = { Name = "nginx" } } build { sources = ["source.amazon-ebs.custom-ami"] provisioner "ansible" { playbook_file = "nginx.yaml" user = "ubuntu" } }
Packer Init
❯ packer init nginx.pkr.hcl Installed plugin github.com/hashicorp/amazon v1.2.9 in "/home/man20820/.config/packer/plugins/github.com/hashicorp/amazon/packer-plugin-amazon_v1.2.9_x5.0_linux_amd64" Installed plugin github.com/hashicorp/ansible v1.1.2 in "/home/man20820/.config/packer/plugins/github.com/hashicorp/ansible/packer-plugin-ansible_v1.1.2_x5.0_linux_amd64"
Packer Validate
❯ packer validate nginx.pkr.hcl The configuration is valid.
Packer Build
❯ packer build nginx.pkr.hcl amazon-ebs.custom-ami: output will be in this color. ==> amazon-ebs.custom-ami: Prevalidating any provided VPC information ==> amazon-ebs.custom-ami: Prevalidating AMI Name: nginx amazon-ebs.custom-ami: Found Image ID: ami-0d22ac6a0e117cefe ==> amazon-ebs.custom-ami: Creating temporary keypair: packer_67a656ad-546e-a192-4ecb-cf375be35b6a ==> amazon-ebs.custom-ami: Creating temporary security group for this instance: packer_67a656ae-a0cb-d56c-06d6-d7efe4945837 ==> amazon-ebs.custom-ami: Authorizing access to port 22 from [0.0.0.0/0] in the temporary security groups... ==> amazon-ebs.custom-ami: Launching a source AWS instance... amazon-ebs.custom-ami: Instance ID: i-053db8a5cf0dda0ce ==> amazon-ebs.custom-ami: Waiting for instance (i-053db8a5cf0dda0ce) to become ready... ==> amazon-ebs.custom-ami: Using SSH communicator to connect: 108.137.130.187 ==> amazon-ebs.custom-ami: Waiting for SSH to become available... ==> amazon-ebs.custom-ami: Connected to SSH! ==> amazon-ebs.custom-ami: Provisioning with Ansible... amazon-ebs.custom-ami: Setting up proxy adapter for Ansible.... ==> amazon-ebs.custom-ami: Executing Ansible: ansible-playbook -e packer_build_name="custom-ami" -e packer_builder_type=amazon-ebs --ssh-extra-args '-o IdentitiesOnly=yes' -e ansible_ssh_private_key_file=/tmp/ansible-key2513666039 -i /tmp/packer-provisioner-ansible4145009209 /home/man20820/workspace/Belajar/packer/nginx.yaml amazon-ebs.custom-ami: amazon-ebs.custom-ami: PLAY [Install and Configure Nginx] ********************************************* amazon-ebs.custom-ami: amazon-ebs.custom-ami: TASK [Gathering Facts] ********************************************************* amazon-ebs.custom-ami: [WARNING]: Platform linux on host default is using the discovered Python amazon-ebs.custom-ami: interpreter at /usr/bin/python3.12, but future installation of another Python amazon-ebs.custom-ami: interpreter could change the meaning of that path. See amazon-ebs.custom-ami: https://docs.ansible.com/ansible- amazon-ebs.custom-ami: core/2.17/reference_appendices/interpreter_discovery.html for more information. amazon-ebs.custom-ami: ok: [default] amazon-ebs.custom-ami: amazon-ebs.custom-ami: TASK [Install Nginx on Debian-based systems] *********************************** amazon-ebs.custom-ami: changed: [default] amazon-ebs.custom-ami: amazon-ebs.custom-ami: TASK [Install Nginx on RHEL-based systems] ************************************* amazon-ebs.custom-ami: skipping: [default] amazon-ebs.custom-ami: amazon-ebs.custom-ami: TASK [Start and Enable Nginx Service] ****************************************** amazon-ebs.custom-ami: ok: [default] amazon-ebs.custom-ami: amazon-ebs.custom-ami: TASK [Deploy Custom Nginx Configuration] *************************************** amazon-ebs.custom-ami: changed: [default] amazon-ebs.custom-ami: amazon-ebs.custom-ami: RUNNING HANDLER [Restart Nginx] ************************************************ amazon-ebs.custom-ami: changed: [default] amazon-ebs.custom-ami: amazon-ebs.custom-ami: PLAY RECAP ********************************************************************* amazon-ebs.custom-ami: default : ok=5 changed=3 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 amazon-ebs.custom-ami: ==> amazon-ebs.custom-ami: Stopping the source instance... amazon-ebs.custom-ami: Stopping instance ==> amazon-ebs.custom-ami: Waiting for the instance to stop... ==> amazon-ebs.custom-ami: Creating AMI nginx from instance i-053db8a5cf0dda0ce amazon-ebs.custom-ami: AMI: ami-0d11b275bef9afba6 ==> amazon-ebs.custom-ami: Waiting for AMI to become ready... ==> amazon-ebs.custom-ami: Skipping Enable AMI deprecation... ==> amazon-ebs.custom-ami: Adding tags to AMI (ami-0d11b275bef9afba6)... ==> amazon-ebs.custom-ami: Tagging snapshot: snap-0d58bc0e8cabd1cb6 ==> amazon-ebs.custom-ami: Creating AMI tags amazon-ebs.custom-ami: Adding tag: "Name": "nginx" ==> amazon-ebs.custom-ami: Creating snapshot tags ==> amazon-ebs.custom-ami: Terminating the source AWS instance... ==> amazon-ebs.custom-ami: Cleaning up any extra volumes... ==> amazon-ebs.custom-ami: No volumes to clean up, skipping ==> amazon-ebs.custom-ami: Deleting temporary security group... ==> amazon-ebs.custom-ami: Deleting temporary keypair... Build 'amazon-ebs.custom-ami' finished after 3 minutes 45 seconds. ==> Wait completed after 3 minutes 45 seconds ==> Builds finished. The artifacts of successful builds are: --> amazon-ebs.custom-ami: AMIs were created: ap-southeast-3: ami-0d11b275bef9afba6
Now we have new nginx ami…
Validate
Deploy EC2 using new ami
access the ip to test nginx configuration…
Thank you…