{"id":140,"date":"2024-06-13T10:38:37","date_gmt":"2024-06-13T10:38:37","guid":{"rendered":"https:\/\/cloudtechner.com\/blog\/?p=140"},"modified":"2024-06-13T11:15:32","modified_gmt":"2024-06-13T11:15:32","slug":"building-immutable-azure-infra-with-packer","status":"publish","type":"post","link":"https:\/\/cloudtechner.com\/blog\/building-immutable-azure-infra-with-packer\/","title":{"rendered":"Building Immutable Azure Infra with Packer"},"content":{"rendered":"\n<p>Author : <a href=\"https:\/\/www.linkedin.com\/in\/mayank0012\">Mayank Sharma<\/a>, Associate Engineer &#8211; CloudDevOps<\/p>\n\n\n<div class=\"taxonomy-post_tag wp-block-post-terms\"><a href=\"https:\/\/cloudtechner.com\/blog\/tag\/azure\/\" rel=\"tag\">Azure<\/a><span class=\"wp-block-post-terms__separator\">, <\/span><a href=\"https:\/\/cloudtechner.com\/blog\/tag\/cloud\/\" rel=\"tag\">Cloud<\/a><span class=\"wp-block-post-terms__separator\">, <\/span><a href=\"https:\/\/cloudtechner.com\/blog\/tag\/devops\/\" rel=\"tag\">DevOps<\/a><span class=\"wp-block-post-terms__separator\">, <\/span><a href=\"https:\/\/cloudtechner.com\/blog\/tag\/infrastructure-as-a-code\/\" rel=\"tag\">Infrastructure as a Code<\/a><span class=\"wp-block-post-terms__separator\">, <\/span><a href=\"https:\/\/cloudtechner.com\/blog\/tag\/packer\/\" rel=\"tag\">Packer<\/a><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3ae4\">Introduction<\/h3>\n\n\n\n<p id=\"77e8\">In the age of DevOps and rapid application delivery, ensuring reliable and consistent infrastructure is crucial. Here\u2019s where immutable infrastructure shines. This approach treats servers as immutable entities, deploying new instances with the desired configuration instead of modifying existing ones.<\/p>\n\n\n\n<p id=\"c087\">Packer, a powerful tool by HashiCorp, excels at creating these golden images \u2014 reusable templates containing the operating system, applications, and configurations for your servers. Let\u2019s delve into how Packer empowers building immutable infrastructure.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"0950\">What is Packer?<\/h3>\n\n\n\n<p id=\"a76e\">Using a single source configuration, Packer is a community program that generates identical machine images for several platforms. Packer is a lightweight, highly performant operating system-crosser that can create machine images for many platforms at once. Unlike Chef or Puppet, Packer does not take the place of configuration management. In fact, Packer has the ability to add software to images while building them by using tools like Chef or Puppet.<\/p>\n\n\n\n<p id=\"ae82\">An operating system and installed applications that are already configured are contained in a single static unit called a machine image, which is used to swiftly generate new computers that are operational. Every platform has a different format for machine images. Examples include OVF exports for VirtualBox, VMDK\/VMX documents for VMware, and AMIs for EC2.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"dca5\">Why Use Packer?<\/h3>\n\n\n\n<p id=\"4663\">Pre-baked system images have a number of advantages, however maximum had been not able to gain from them due to the fact image had been too tedious to create and manage. There were either no existing tools to automate the creation of machine images or they had too high of a learning curve. The result is that, prior to Packer, creating machine images threatened the agility of operations teams, and therefore aren\u2019t used, despite the massive benefits.<\/p>\n\n\n\n<p id=\"e12c\">Packer changes all of this. Packer automates the advent of any kind of machine image. It embraces cutting-edge configuration control with the aid of using encouraging you to apply a framework including Chef or Puppet to put in and configure the software program inside your Packer-made images.<\/p>\n\n\n\n<p id=\"afae\">In different words: Packer brings pre-baked images into the present day age, unlocking untapped ability and beginning new opportunities.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:1400\/1*tAFQN-JjCzL__PM7GAAtaA.png\" alt=\"\" style=\"object-fit:cover\"\/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"f19d\">Advantages of Using Packer<\/h3>\n\n\n\n<p id=\"7fa1\"><strong>Super fast infrastructure deployment&nbsp;<\/strong>\u2014 Utilizing Packer images enables the launch of fully provisioned and configured machines in a matter of seconds, rather than the typical duration of several minutes or hours. This efficiency significantly benefits both production and development environments. In development, virtual machines can be initiated almost instantaneously, thereby eliminating the extended provisioning times traditionally required.<\/p>\n\n\n\n<p id=\"68a9\"><strong>Multi-provider portability<\/strong><em>&nbsp;<\/em>\u2014 By creating identical images for multiple platforms, Packer facilitates seamless deployment across various environments. Production can be run on AWS, staging and QA can be managed on a private cloud such as OpenStack, and development can be conducted using desktop virtualization solutions like VMware or VirtualBox. This approach ensures that each environment operates with an identical machine image, providing unparalleled portability and consistency.<\/p>\n\n\n\n<p id=\"3ddd\"><strong>Improved stability &#8211;<\/strong>Packer installs and configures all the software for a machine at the time the image is built. If there are bugs in these scripts, they\u2019ll be caught early, rather than several minutes after a machine is launched.<\/p>\n\n\n\n<p id=\"5c44\"><strong>Greater testability<\/strong><em>&nbsp;<\/em>\u2014 After a machine image is built, that machine image can be quickly launched and smoke tested to verify that things appear to be working. If they are, you can be confident that any other machines launched from that image will function properly.<\/p>\n\n\n\n<p id=\"ade0\">Packer makes it extremely easy to take advantage of all these benefits.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"8b8c\">How to Install Packer<\/h3>\n\n\n\n<p id=\"c642\">Packer is encapsulated within a single binary executable. To create an image with Packer, you can download and install the software through one of the following methods<\/p>\n\n\n\n<ul>\n<li>Download the Packer binary for macOS, Linux, or Windows<\/li>\n\n\n\n<li>Install using Homebrew by executing&nbsp;<code>brew install packer<\/code><\/li>\n\n\n\n<li>Install using apt-get by executing&nbsp;<code>apt-get install packer<\/code><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:1394\/1*EY0v20nLGwRtlu4us2Kwwg.png\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"bf52\"><strong>Packer Commands<\/strong><\/h3>\n\n\n\n<ol>\n<li><strong>packer init<\/strong>: The&nbsp;<code>packer init<\/code>&nbsp;command initializes a new Packer configuration. It creates a new Packer template with default settings in the current directory. This command is useful when starting a new project or if you want to create a new Packer configuration file from scratch. It ensures that you have a valid configuration file to start with. Example usage:&nbsp;<strong>packer init<\/strong><\/li>\n\n\n\n<li><strong>packer fmt<\/strong>: The&nbsp;<code>packer fmt<\/code>&nbsp;command formats Packer configuration files according to the standard style conventions. It helps maintain consistency and readability across different configuration files. Running&nbsp;<code>packer fmt<\/code>&nbsp;automatically adjusts the indentation, spacing, and formatting of the configuration files to match the prescribed style. Example usage:&nbsp;<strong>packer fmt example.pkr.hcl<\/strong><\/li>\n\n\n\n<li><strong>packer validate<\/strong>: The&nbsp;<code>packer validate<\/code>&nbsp;command checks the syntax and configuration of a Packer template file without actually building an image. It verifies that the configuration file is correctly written and doesn&#8217;t contain any syntax errors or invalid settings. This command is useful for detecting issues early in the development process.<br>Example usage:&nbsp;<strong>packer validate example.pkr.hcl<\/strong><\/li>\n\n\n\n<li><strong>packer build<\/strong>: The&nbsp;<code>packer build<\/code>&nbsp;command initiates the image building process based on the specified Packer configuration file. It launches the build process, which involves creating instances, provisioning them, and generating machine images according to the defined configuration. This is the primary command used to create machine images with Packer.<br>Example usage:&nbsp;<strong>packer build example.pkr.hcl<\/strong><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"a32d\"><strong>Building Immutable Images with Packer<\/strong><\/h3>\n\n\n\n<p id=\"5004\">In this sample usecase, we are creating azure ubuntu image having ngnix application by leveraging packer capabilites.<\/p>\n\n\n\n<ol>\n<li><strong>Define Configuration:<\/strong>&nbsp;First we need to create the file azure&nbsp;<strong><em>plugins.pkr.hcl&nbsp;<\/em><\/strong>where the&nbsp;<code>packer<\/code>&nbsp;block specifies the required plugins. Here, we need the&nbsp;<code>azure<\/code>&nbsp;plugin.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>packer {<br>  required_plugins {<br>    azure = {<br>      source  = \"github.com\/hashicorp\/azure\"<br>      version = \"~&gt; 2\"<br>    }<br>  }<br>}<\/code><\/pre>\n\n\n\n<ul>\n<li>Now we need to create the second file&nbsp;<strong><em>azure.pkr.hcl&nbsp;<\/em><\/strong>The file starts with a&nbsp;<code>source<\/code>&nbsp;block named&nbsp;<code>azure-arm vm<\/code>, which defines the Azure ARM virtual machine source for the Packer image.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>source azure-arm vm {<br>  client_id       = var.client_id<br>  client_secret   = var.client_secret<br>  subscription_id = var.subscription_id<br>  tenant_id       = var.tenant_id<br><br>  location                          = var.primary_location<br>  managed_image_name                = \"${var.image_name}-${var.image_version}\"<br>  managed_image_resource_group_name = var.gallery_resource_group<br><br>  shared_image_gallery_destination {<br>    subscription        = var.subscription_id<br>    resource_group      = var.gallery_resource_group<br>    gallery_name        = var.gallery_name<br>    image_name          = var.image_name<br>    image_version       = var.image_version<br>    replication_regions = &#91;<br>      var.primary_location,<br>      \"East US\"<br>    ]<br><br>  }<br><br>  communicator                      = \"ssh\"<br>  os_type                           = \"Linux\"<br>  image_offer                       = \"0001-com-ubuntu-server-focal\"<br>  image_publisher                   = \"Canonical\"<br>  image_sku                         = \"20_04-lts-gen2\"<br><br>  vm_size                           = \"Standard_DS2_v2\"<br><br>  allowed_inbound_ip_addresses      = &#91;var.agent_ipaddress]<br><br>}<\/code><\/pre>\n\n\n\n<ul>\n<li>Inside this block, various attributes are set to configure the Azure VM.<\/li>\n\n\n\n<li><code>client_id<\/code>,&nbsp;<code>client_secret<\/code>,&nbsp;<code>subscription_id<\/code>, and&nbsp;<code>tenant_id<\/code>&nbsp;are used for authentication and authorization to Azure.<\/li>\n\n\n\n<li><code>location<\/code>&nbsp;specifies the Azure region where the virtual machine will be created.<\/li>\n\n\n\n<li><code>managed_image_name<\/code>&nbsp;and&nbsp;<code>managed_image_resource_group_name<\/code>&nbsp;define the name and resource group of the managed image that will be created.<\/li>\n\n\n\n<li><code>shared_image_gallery_destination<\/code>&nbsp;specifies the destination for the shared image gallery where the managed image will be stored.<\/li>\n\n\n\n<li><code>communicator<\/code>&nbsp;is set to&nbsp;<code>\"ssh\"<\/code>, indicating that SSH will be used for communication with the VM.<\/li>\n\n\n\n<li><code>os_type<\/code>&nbsp;specifies the operating system type of the VM, which is set to&nbsp;<code>\"Linux\"<\/code>.<\/li>\n\n\n\n<li><code>image_offer<\/code>,&nbsp;<code>image_publisher<\/code>, and&nbsp;<code>image_sku<\/code>&nbsp;specify the details of the Azure Marketplace image used for creating the VM.<\/li>\n\n\n\n<li><code>vm_size<\/code>&nbsp;defines the size of the VM.<\/li>\n\n\n\n<li><code>allowed_inbound_ip_addresses<\/code>&nbsp;specifies the list of IP addresses allowed to connect to the VM.<\/li>\n\n\n\n<li>Remember to replace placeholders like&nbsp;<code>var.client_id<\/code>,&nbsp;<code>var.client_secret<\/code>,&nbsp;<code>var.subscription_id<\/code>, and&nbsp;<code>var.tenant_id<\/code>&nbsp;with your actual Azure authentication details.<\/li>\n\n\n\n<li>Now we need to create the third file&nbsp;<strong><em>build.pkr.hcl&nbsp;<\/em><\/strong>The file starts with a&nbsp;<code>build<\/code>&nbsp;block, indicating that you&#8217;re defining a build configuration.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>build {<br>  sources = &#91;<br>    \"source.azure-arm.vm\"<br>  ]<br><br>  provisioner shell {<br>    execute_command = local.execute_command<br>    \/\/ inline = &#91;\"apt update\"]<br>    script = \"bootstrap.sh\"<br>  }<br><br>  provisioner shell {<br>    execute_command = local.execute_command<br>    inline = &#91;\"\/usr\/sbin\/waagent -force -deprovision+user &amp;&amp; export HISTSIZE=0 &amp;&amp; sync\"]<br>    only = &#91;\"azure-arm\"]<br>  }<br><br>}<\/code><\/pre>\n\n\n\n<ul>\n<li>Inside the&nbsp;<code>build<\/code>&nbsp;block, there&#8217;s a&nbsp;<code>sources<\/code>&nbsp;attribute, which specifies the source for the build. In this case, it&#8217;s&nbsp;<code>\"source.azure-arm.vm\"<\/code>, indicating that it&#8217;s building a virtual machine image for Azure using Azure Resource Manager (ARM).<\/li>\n\n\n\n<li>Following the&nbsp;<code>sources<\/code>&nbsp;attribute, there are two&nbsp;<code>provisioner<\/code>&nbsp;blocks. Provisioners are used to configure the machine image after it&#8217;s been created.<\/li>\n\n\n\n<li>The first&nbsp;<code>provisioner<\/code>&nbsp;block is using the&nbsp;<code>shell<\/code>&nbsp;provisioner, which executes shell commands on the machine. It specifies the&nbsp;<code>script<\/code>&nbsp;attribute as&nbsp;<code>\"bootstrap.sh\",<\/code>&nbsp;indicating that it will execute the&nbsp;<code>bootstrap.sh<\/code>&nbsp;script. Where the script will update then it will install the nginx.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update<br>sudo apt install nginx<\/code><\/pre>\n\n\n\n<p id=\"f7e6\">The&nbsp;<code>execute_command<\/code>&nbsp;attribute is set to&nbsp;<code>local.execute_command<\/code>.in local.pkr.hcl we are providing the executable command<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>locals {<br>  execute_command = \"chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'\"<br>}<\/code><\/pre>\n\n\n\n<ul>\n<li>The second&nbsp;<code>provisioner<\/code>&nbsp;block is also using the&nbsp;<code>shell<\/code>&nbsp;provisioner, but it&#8217;s using the&nbsp;<code>inline<\/code>&nbsp;attribute to specify inline shell commands directly within the configuration. These commands seem to deprovision the Azure VM and clear command history post azure image creation. The&nbsp;<code>only<\/code>&nbsp;attribute restricts this provisioner to run only on the Azure ARM build.<\/li>\n\n\n\n<li>Now we need to Create the&nbsp;<strong><em>variables.pkr.hcl<\/em><\/strong><\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>variable subscription_id {<br>  type = string<br>}<br>variable tenant_id {<br>  type = string<br>}<br>variable client_id {<br>  type = string<br>}<br>variable client_secret {<br>  type = string<br>}<br>variable primary_location {<br>  type = string<br>}<br>variable image_name {<br>  type = string<br>}<br>variable image_version {<br>  type = string<br>}<br>variable gallery_resource_group {<br>  type = string<br>}<br>variable gallery_name {<br>  type = string<br>}<br>variable agent_ipaddress {<br>  type = string<br>}<\/code><\/pre>\n\n\n\n<ul>\n<li>Each&nbsp;<code>variable<\/code>&nbsp;block defines a variable that can be used in Packer configuration files to parameterize values.<\/li>\n\n\n\n<li>The&nbsp;<code>type<\/code>&nbsp;attribute specifies the data type of each variable. In this case, all variables are of type&nbsp;<code>string<\/code>, meaning they will accept string values.<\/li>\n\n\n\n<li>By defining these variables separately in a&nbsp;<code>variables.pkr.hcl<\/code>&nbsp;file, it allows for better organization and separation of concerns in Packer configuration files. It also enables users to easily customize the configuration by providing values for these variables, making the configuration more flexible and reusable.<\/li>\n<\/ul>\n\n\n\n<p id=\"5969\"><strong>Building the Image:<\/strong>&nbsp;Once the configuration is defined, run the&nbsp;<code>packer build<\/code>&nbsp;command. Packer provisions the machine based on your specifications, Before runing the packer build you need to run the packer init, packer fmt, packer validate and at the final you have to run packer build that will create the azure image and that image will store in the shared image gallery as mention above in step-2.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"07f8\"><strong>Conclusion:-<\/strong><\/h3>\n\n\n\n<p id=\"8d1b\">Packer is a valuable tool for building immutable infrastructure. It streamlines the creation of consistent and secure machine images, promoting a reliable and efficient infrastructure management approach. By incorporating Packer into your DevOps workflow, you can ensure a faster, more secure, and more manageable infrastructure for your applications.<\/p>\n\n\n\n<p id=\"686b\"><strong><em>References<\/em><\/strong>:<strong><em>&nbsp;<\/em><\/strong><a href=\"https:\/\/developer.hashicorp.com\/packer\/docs\/intro\/why\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/developer.hashicorp.com\/packer\/docs\/<\/a><\/p>\n\n\n\t<div id=\"respond\" class=\"comment-respond wp-block-post-comments-form\">\n\t\t<h3 id=\"reply-title\" class=\"comment-reply-title\">Leave a Reply <small><a rel=\"nofollow\" id=\"cancel-comment-reply-link\" href=\"\/blog\/wp-json\/wp\/v2\/posts\/140#respond\" style=\"display:none;\">Cancel reply<\/a><\/small><\/h3><form action=\"https:\/\/cloudtechner.com\/blog\/wp-comments-post.php\" method=\"post\" id=\"commentform\" class=\"comment-form\"><p class=\"comment-notes\"><span id=\"email-notes\">Your email address will not be published.<\/span> <span class=\"required-field-message\">Required fields are marked <span class=\"required\">*<\/span><\/span><\/p><p class=\"comment-form-comment\"><label for=\"comment\">Comment <span class=\"required\">*<\/span><\/label> <textarea id=\"comment\" name=\"comment\" cols=\"45\" rows=\"8\" maxlength=\"65525\" required=\"required\"><\/textarea><\/p><p class=\"comment-form-author\"><label for=\"author\">Name <span class=\"required\">*<\/span><\/label> <input id=\"author\" name=\"author\" type=\"text\" value=\"\" size=\"30\" maxlength=\"245\" autocomplete=\"name\" required=\"required\" \/><\/p>\n<p class=\"comment-form-email\"><label for=\"email\">Email <span class=\"required\">*<\/span><\/label> <input id=\"email\" name=\"email\" type=\"text\" value=\"\" size=\"30\" maxlength=\"100\" aria-describedby=\"email-notes\" autocomplete=\"email\" required=\"required\" \/><\/p>\n<p class=\"comment-form-url\"><label for=\"url\">Website<\/label> <input id=\"url\" name=\"url\" type=\"text\" value=\"\" size=\"30\" maxlength=\"200\" autocomplete=\"url\" \/><\/p>\n<p class=\"comment-form-cookies-consent\"><input id=\"wp-comment-cookies-consent\" name=\"wp-comment-cookies-consent\" type=\"checkbox\" value=\"yes\" \/> <label for=\"wp-comment-cookies-consent\">Save my name, email, and website in this browser for the next time I comment.<\/label><\/p>\n<p class=\"form-submit\"><span class=\"bloghash-submit-form-button\"><input name=\"submit\" type=\"submit\" id=\"submit\" class=\"submit\" value=\"Post Comment\" \/><\/span> <input type='hidden' name='comment_post_ID' value='140' id='comment_post_ID' \/>\n<input type='hidden' name='comment_parent' id='comment_parent' value='0' \/>\n<\/p><\/form>\t<\/div><!-- #respond -->\n\t\n\n\n<p><a href=\"https:\/\/medium.com\/@mayank.sharma_20385?source=post_page-----4801cec0ce45--------------------------------\"><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Author : Mayank Sharma, Associate Engineer &#8211; CloudDevOps Introduction In the age of DevOps and rapid application delivery, ensuring reliable and consistent infrastructure is crucial. Here\u2019s where immutable infrastructure shines.&hellip;<\/p>\n","protected":false},"author":1,"featured_media":156,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[69,22,18,23,70,71],"tags":[95,10,39,67,96],"_links":{"self":[{"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/posts\/140"}],"collection":[{"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/comments?post=140"}],"version-history":[{"count":5,"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/posts\/140\/revisions"}],"predecessor-version":[{"id":161,"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/posts\/140\/revisions\/161"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/media\/156"}],"wp:attachment":[{"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/media?parent=140"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/categories?post=140"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudtechner.com\/blog\/wp-json\/wp\/v2\/tags?post=140"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}