<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Virtual Machines on Digi Hunch</title><link>https://static.digihunch.com/tag/virtual-machines/</link><description>Recent content in Virtual Machines on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 08 Apr 2025 14:46:49 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/virtual-machines/index.xml" rel="self" type="application/rss+xml"/><item><title>Azure Deets</title><link>https://static.digihunch.com/2021/10/notes-on-azure/</link><pubDate>Mon, 25 Oct 2021 23:13:52 -0400</pubDate><guid>https://static.digihunch.com/2021/10/notes-on-azure/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-azure-lesson.webp" alt="Featured image of post Azure Deets" /&gt;&lt;p class="wp-block-paragraph"&gt;Both Azure and AWS are leading players in public cloud. AWS developed a lot of SMB customer in technology. Azure attracted many enterprises from their on-prem customers. In addition to clienteles, their models to manage resources in the cloud are also different in several aspects. While this post is by no means a comprehensive comparison, it serves as a refresher on how Azure is different from AWS in cloud engineering.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-subscription-and-resource-group"&gt;Subscription and Resource Group&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both subscription and resource group are means to manage resources in group. Subscription is associated with a credit card and groups resource financially. Resource group groups resources logically. A subscription can have multiple resource groups, as illustrated &lt;a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources"&gt;here&lt;/a&gt; in the hierarchy map.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-cli"&gt;Azure CLI&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are two CLI tools: Azure PowerShell for PowerShell users, and Azure CLI for Linux users. The distinction is not clear, because PowerShell can also run on multiple platforms such as &lt;a href="https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-macos?view=powershell-7.2"&gt;MacOS&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-linux?view=powershell-7.2"&gt;Linux&lt;/a&gt;. On the other hand, Linux Bash can run on Windows (e.g. using &lt;a href="https://static.digihunch.com/2020/06/wsl2-environment-on-windows-10/"&gt;WSL2&lt;/a&gt;). The different lies more in the command nomenclature. For example, to list subscriptions, the PowerShell Cmdlets reads:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Get-AzSubscription&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The Azure CLI comes much cleaner:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;az account list&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The command and argument naming in Azure CLI align with Linux commands. I prefer Azure CLI for its succinctness. When looking up VM skus, we can use this command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;az vm list-skus -l eastus2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The return is a JSON document. In advanced use cases, we can filter the result by using jq utility. Alternatively, we can filter the result and groom the output with &lt;a href="https://jmespath.org/"&gt;jmespath&lt;/a&gt; query, just like AWS CLI. For example, in eastus2 region, we look for instances that:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Has virtualMachines as resource Type&lt;/li&gt;&#10;&lt;li&gt;Has AcceleratedNetworking enabled&lt;/li&gt;&#10;&lt;li&gt;Has EncryptionAtHostSupported enabled&lt;/li&gt;&#10;&lt;li&gt;Has PremiumIO enabled &lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For each of the result, we print out:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;number of vCPUs&lt;/li&gt;&#10;&lt;li&gt;Memory size&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For this use case we will have to provide a JMESPath query as below, then output the result as a table:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;az vm list-skus -l eastus2 --query &lt;span style="color:#e6db74"&gt;&amp;#34;[?resourceType==&amp;#39;virtualMachines&amp;#39; &amp;amp;&amp;amp; capabilities[?name==&amp;#39;AcceleratedNetworkingEnabled&amp;#39; &amp;amp;&amp;amp; value==&amp;#39;True&amp;#39;] &amp;amp;&amp;amp; capabilities[?name==&amp;#39;EncryptionAtHostSupported&amp;#39; &amp;amp;&amp;amp; value==&amp;#39;True&amp;#39;] &amp;amp;&amp;amp; capabilities[?name==&amp;#39;PremiumIO&amp;#39; &amp;amp;&amp;amp; value==&amp;#39;True&amp;#39;]].{Name:name,vCPUs:capabilities[?name==&amp;#39;vCPUs&amp;#39;].value|[0],MemoryGB:capabilities[?name==&amp;#39;MemoryGB&amp;#39;].value|[0]}&amp;#34;&lt;/span&gt; --output table&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The result looks like this:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="578" height="584" src="https://static.digihunch.com/wp-content/uploads/2022/06/image-10.png" alt="" class="wp-image-5548"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I use variations of the command above very often to find out the best instance for AKS nodes. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-infrastructure-as-code"&gt;Infrastructure as Code&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The native infrastructure as code option is &lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview"&gt;ARM&lt;/a&gt; (Azure Resource Manager) template in JSON format. It is extremely wordy and perhaps why Azure later developed &lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview#:~:text=Bicep%20is%20a%20domain%2Dspecific,and%20support%20for%20code%20reuse.&amp;amp;text=A%20Bicep%20file%20declares%20Azure,programming%20commands%20to%20create%20resources."&gt;Bicep&lt;/a&gt; as the second generation of IaC tool. Terraform has a provider for Azure as well. For comparison among ARM, Terraform and Bicep, I have written a blog &lt;a href="https://medium.com/slalom-build/how-azure-bicep-is-different-d89322d5fe3a"&gt;post&lt;/a&gt; for Slalom build covering more details.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-networking"&gt;Networking &lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://devblogs.microsoft.com/premier-developer/differentiating-between-azure-virtual-network-vnet-and-aws-virtual-private-cloud-vpc/#:~:text=A%20subnet%20is%20public%20if,and%20subnets%20for%20each%20region."&gt;Here&lt;/a&gt; is a great post comparing Azure Network with AWS.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;At a high level, &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-networks-overview"&gt;Azure Virtual Network&lt;/a&gt; (or VNet) is the equivalent of VPC in Amazon. Likewise, peering can be configured between VNets. As to subnet, Azure is different because there is no conceptual distinction between public subnet and private subnet. In AWS, public subnet is subnet attached with an Internet Gateway via a network route. So &amp;#8220;private&amp;#8221; or &amp;#8220;public&amp;#8221; are in terms of outbound traffic. On the other side, Azure does not distinguish between private or public subnet. Resources connected to a VNet have access out to the Internet by default. As to inbound traffic, you can make a VM available on Internet by giving it a public IP (same as AWS). You can make it available to other VNet, by configuring a service endpoint. Customers typically need &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-networks-udr-overview#custom-routes"&gt;custom routes&lt;/a&gt; to redirect outbound traffic (e.g. through firewall). In VPC, subnets are mapped to availability zones one-to-one, whereas in Azure, a subnet may traverse multiple availability zones.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With Azure, it is also important to understand &lt;a href="https://medium.com/awesome-azure/azure-difference-between-azure-private-links-and-azure-service-endpoints-private-links-vs-service-endpoints-8fb0f80ca196#:~:text=Service%20endpoint%20%E2%80%94%20It%20remains%20a,who%20connects%20to%20your%20service."&gt;difference&lt;/a&gt; between Azure service endpoint and Azure private endpoint:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Azure service endpoint: provides connectivity to Azure services over n optimized route over the Azure backbone network. Traffic will leave your VNet.&lt;/li&gt;&#10;&lt;li&gt;Azure private endpoint: a NIC that uses private IP from your VNet. This NIC connects you privately and securely to a service powered by Azure Private Link. By enabling a private endpoint, you&amp;#8217;re bringing the service into your VNet.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On security group, we can associated a network security group with a network interface, or with a subnet. In contrast, in AWS, a security group can only be associated with an instance&amp;#8217;s network interface.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-bastion-and-jump-box"&gt;Azure Bastion and Jump Box&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is a managed service called Azure Bastion. It is a SSH/RDP proxy fully managed as PaaS. However, its use case is virtual machines. It cannot be used to access other services. For example, if you create a private AKS cluster, then you need a command terminal to access the API server. This is not what Azure Bastion can do. Instead, you either need a virtual machine in the AKS network as jump box.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The alternative is an Azure Cloud Shell, which will require storage but can be configured to be placed inside of a V-Net. However, Azure Cloud Shell is not running inside of a full-fledged Linux operating system. You cannot install commands.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To create a bastion host, e.g. without public IP address, use the following CLI command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;az vm create -n MyBastion -g AutomationTest --image UbuntuLTS --subnet suitable-porpoise-node-subnet --vnet-name suitable-porpoise-vnet --ssh-key-values ~/.ssh/id_rsa.pub --authentication-type ssh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;If the bastion host is needed with a public Ip, configure the network security group accordingly. The AZ CLI command above will create a VM, with an OS user named after the command line terminal user.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-iam"&gt;IAM&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-whatis"&gt;Azure AD&lt;/a&gt; is a managed identity service. &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-compare-azure-ad-to-ad"&gt;Here&lt;/a&gt; is the difference between Active Directory and Azure AD.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure &lt;a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/overview"&gt;RBAC&lt;/a&gt; is a mechanism for authorization. Just like IAM policies, Azure RBAC enforces permissions using role assignment, which consists of:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;security principal ( user, group, service principal, or managed idenity)&lt;/li&gt;&#10;&lt;li&gt;role definition: defines what actions is allowed and what is not allowed&lt;/li&gt;&#10;&lt;li&gt;scope: the object of the action&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To enforce RBAC, one needs to create role assignment objects, each specifying principal, role, and scope.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-service-principle-and-managed-identity"&gt;Service Principle and Managed Identity&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The two concepts may appear confusing. I find &lt;a href="https://devblogs.microsoft.com/devops/demystifying-service-principals-managed-identities/"&gt;this article&lt;/a&gt; a great reference to demystify them. The takeaway is: service principle is the equivalent of service account in old Active Directory. Managed identity is a service principle automatically managed by a resource. Managed identity can be user assigned or system assigned.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Managed Identity is a &amp;#8220;wrapper&amp;#8221; around a service principal. It is automatically created and automatically rotated. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-azure-devops"&gt;Azure DevOps &lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I think of Azure DevOps (ADO) of a managed pipeline implementation, with a repository (just like BitBucket), a board to manage tickets (similar to JIRA), Wiki (just like Confluence), Artifactory. The Pipelines is the part that&amp;#8217;s similar to Jenkins. ADO calls a build pipeline a &lt;em&gt;Pipeline&lt;/em&gt;, and a release/deployment pipeline a &lt;em&gt;Release&lt;/em&gt;. A pipeline and a release are fundamentally the same but they are used in different ways. A pipeline&amp;#8217;s input is usually the code repository, and the output is artifact. A release&amp;#8217;s input is usually an artifact, and it connects to infrastructure in different environments. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ADO has its own ecosystem for plugins, managed under Visual Studio &lt;a href="https://marketplace.visualstudio.com/azuredevops"&gt;marketplace&lt;/a&gt;. Many extensions are open-source. If you are not happy with an extension, you can publish your own extension to market place. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-logging-and-monitoring"&gt;Logging and Monitoring&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure Monitor manages metrics, logs and alerts. To further analyze logs, create a log analytics workspaces, where you can run Kusto queries. You can create a workbook and embed Kusto queries into visual objects on the workbook.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-storage"&gt;Storage&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure manages storage resources under storage account. The resource classes include Blob (object), File, Queue, Table and Disk (block). They have a few acronyms on redundancy levels.&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-very-light-gray-to-cyan-bluish-gray-gradient-background has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Redundancy Option&lt;/td&gt;&lt;td&gt;Data Copy&lt;/td&gt;&lt;td&gt;Access level&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LRS &amp;#8211; Locally redundant&lt;/td&gt;&lt;td&gt;synchronously copy your data three times within the AZ in the primary region.&lt;/td&gt;&lt;td&gt;Write is acknowledged after three synchronous writes.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ZRS &amp;#8211; Zone-redundant&lt;/td&gt;&lt;td&gt;synchronously copy your data across three AZs in the primary region.&lt;br&gt;your data is still accessible for both read and write even if one AZ becomes unavailable.&lt;/td&gt;&lt;td&gt;&lt;meta charset="utf-8"&gt;Write is acknowledged after three synchronous writes.&lt;br&gt;If an AZ becomes unavailable, Azure undertakes networking updates (e.g. DNS re-pointing). Application may perceive a blip where re-try policies may help.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GRS &amp;#8211; Geo-redundant&lt;/td&gt;&lt;td&gt;LRS in primary region +&lt;br&gt;asynchronously copy your data to a single AZ in the secondary region + LRS in secondary region&lt;br&gt;&lt;/td&gt;&lt;td&gt;your data in the secondary region isn&amp;#8217;t available for read or write access unless there is a failover to the secondary region.&lt;br&gt;for read access to the secondary region, configure your storage account to use RA-GRS (read-access geo-redundant storage)&lt;br&gt;If the primary region becomes unavailable, you can choose to fail over to the secondary region. After the failover has completed, the secondary region becomes the primary region, and you can again read and write data.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GZRS &amp;#8211; Geo-zone-redundant&lt;/td&gt;&lt;td&gt;ZRS in primary region +&lt;br&gt;asynchronously copy your data to a single AZ in the secondary region + LRS in secondary region&lt;/td&gt;&lt;td&gt;&lt;meta charset="utf-8"&gt;your data in the secondary region isn&amp;#8217;t available for read or write access unless there is a failover to the secondary region.&lt;br&gt;for read access to the secondary region, configure your storage account to use RA-GZRS (read-access geo-zone-redundant storage)&lt;br&gt;If the primary region becomes unavailable, you can choose to fail over to the secondary region. After the failover has completed, the secondary region becomes the primary region, and you can again read and write data.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The disaster recovery and failover happens at storage &lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-disaster-recovery-guidance#understand-the-account-failover-process"&gt;account level&lt;/a&gt;.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/10/logging-and-monitoring-in-kubernetes-with-plg-stack/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Logging and Monitoring in Kubernetes with PLG stack&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/11/infrastructure-deployment-in-terraform-2-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Infrastructure deployment in Terraform 2/2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Infrastructure deployment in Terraform 1/2</title><link>https://static.digihunch.com/2021/08/scalable-infrastructure-deployment-in-terraform/</link><pubDate>Wed, 11 Aug 2021 21:44:00 -0400</pubDate><guid>https://static.digihunch.com/2021/08/scalable-infrastructure-deployment-in-terraform/</guid><description>&lt;p class="wp-block-paragraph"&gt;Terraform is an excellent Infrastructure-as-Code (IaC) tool based on Hashicorp Configuration Language (HCL). Compared to JSON or YAML based declarative templates (e.g. CloudFormation and ARM), HCL is more concise, thanks to the flexibility of HCL. On the other hand, HCL is not as flexible as general purpose languages. For that sake, I see HCL as semi-declarative IaC. This post is my notes about best practices with Terraform development, from the context of AWS, but also applies to other cloud platforms.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Complex Types&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are three primitive types (string, number and bool) that forms collection types and structural types. Here are some common ones:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;list: element may repeat, and order is maintained:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;orange&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;banana&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;orange&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;apple&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;set: elements are unique and unordered&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;apple&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;banana&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;orange&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;tuple: each element has its own type&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, 15, true&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;object: defined by a schema with named attributes each with its own type&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;John&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; age &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;list of object&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alloc_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0b7271a3219bc1fc2&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subnet_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0c02af76c2c3e46fa&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alloc_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0440c334c48d4247f&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subnet_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;02652e69fa2a71de8&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;map of string&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; property &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attribute &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;map of object&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; objkey1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alloc_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0b7271a3219bc1fc2&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subnet_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0c02af76c2c3e46fa&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; objkey2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alloc_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0440c334c48d4247f&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subnet_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;02652e69fa2a71de8&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Whenever applicable, Terraform converts types implicitly or explicitly. For example, when a list or tuple is converted to set, all elements are converted to string and duplicates are removed. Object and map are very similar. Map of string can be converted to object if the attributes comply with the schema. Additional attributes not in the schema are discarded.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;HCL Types is similar to Python&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although being totally different beasts, the complex types between HCL and Python are similar, to the point I suspect the HCL design is influenced by Python. I summarize the similarities as such:&lt;/p&gt;&#10;&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Python Types&lt;/td&gt;&lt;td&gt;list []&lt;/td&gt;&lt;td&gt;tuple ()&lt;/td&gt;&lt;td&gt;set {}&lt;/td&gt;&lt;td&gt;dict {}&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Terraform Types&lt;/td&gt;&lt;td&gt;list []&lt;/td&gt;&lt;td&gt;tuple []&lt;/td&gt;&lt;td&gt;set []&lt;/td&gt;&lt;td&gt;map {}&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ordered&lt;/td&gt;&lt;td&gt;Y&lt;br&gt;You can access item by index&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;N &lt;br&gt;you cannot access an item by index or key; however you can loop over all itmes&lt;/td&gt;&lt;td&gt;N&lt;br&gt;key-value pair that allows you to access item by key&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;changeable (mutable)&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;N&lt;br&gt;You cannot update, add or remove items&lt;/td&gt;&lt;td&gt;Y&lt;br&gt;Add or remove only. no change to existing elements&lt;/td&gt;&lt;td&gt;Keys must remain unique or the values get overwritten;&lt;br&gt;Values are mutable&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;allow duplicate elements&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;N&lt;/td&gt;&lt;td&gt;Keys must be unique; values don&amp;#8217;t have to&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In Python, list and tuple allow elements of mixed types but in IaC like Terraform we mostly don&amp;#8217;t need mixed types. In Terraform, an object is a map without a defined type. In most situations, lists and tuples behave identically, as do maps and objects.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another area of similarity is with the comprehension of list and dict/maps. In Python for example, &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## Supposed you need to create a list:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lst&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; x &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lst&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(x&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(lst)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### that can be simplified as the following to create the list:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lst &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [x&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; x &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## You can even add contidion&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;even_numbers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[num &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; num &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; num&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## You can introduce function calls:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;words &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;python&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;list&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;comprehension&amp;#34;&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lengths &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [len(word) &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; word &lt;span style="color:#f92672"&gt;in&lt;/span&gt; words]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## You can even combine two lists&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lst1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lst2&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pair&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[[i,j] &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; lst1 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; j &lt;span style="color:#f92672"&gt;in&lt;/span&gt; lst2]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(pair)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## With dict, it&amp;#39;s similar&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;evens&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{x:x&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; x &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; x&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(evens)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In Terraform, we use similar techniques:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; s &lt;span style="color:#f92672"&gt;in&lt;/span&gt; var&lt;span style="color:#f92672"&gt;.&lt;/span&gt;list : upper(s)] &lt;span style="color:#75715e"&gt;# build a tuple/list from a list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; k, v &lt;span style="color:#f92672"&gt;in&lt;/span&gt; var&lt;span style="color:#f92672"&gt;.&lt;/span&gt;map : length(k) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; length(v)] &lt;span style="color:#75715e"&gt;# build a list from a map&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; s &lt;span style="color:#f92672"&gt;in&lt;/span&gt; var&lt;span style="color:#f92672"&gt;.&lt;/span&gt;list : s &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; upper(s)} &lt;span style="color:#75715e"&gt;# build a map from a list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; s &lt;span style="color:#f92672"&gt;in&lt;/span&gt; var&lt;span style="color:#f92672"&gt;.&lt;/span&gt;list : upper(s) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; s &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;] &lt;span style="color:#75715e"&gt;# build a tuple/list from a list with condition &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note that the documentation of Terraform doesn’t explicitly call them out as comprehensions. However, it&amp;#8217;s exactly the same idea as comprehensions in Python. Even the &lt;code&gt;range()&lt;/code&gt; function exists both in Python and Terraform.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="modularization"&gt;Modularization&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Modules allows you to group related resources together. They can also be re-used and called by other modules. It is fairly straightforward to create a module:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;put the resource declarations into a sub-directory&lt;/li&gt;&#10;&lt;li&gt;define input and output in the directory&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;However, the introduction of module complicates the directory structure and variable referencing, which is important to take into account before starting creating modules. This &lt;a href="https://www.terraform.io/docs/language/modules/develop/index.html#when-to-write-a-module"&gt;guideline&lt;/a&gt; has further discussion about when to create a module. I re-wrote the terraform templates in &lt;a href="https://github.com/digihunch/orthweb/tree/main/terraform"&gt;Orthweb project&lt;/a&gt; to leverage modularization wherever possible, but there is still some stand-alone resource (e.g. random_id) not belonging to any module. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To reference resources across modules, you need to import those resources (using &lt;a href="https://www.terraform.io/docs/language/data-sources/index.html"&gt;data source&lt;/a&gt;) from within the module. There are a couple of ways. You may pass the argument of data source as input variable, or you can leverage the filter capability of data source. Let&amp;#8217;s look at one example of each mechanism.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the example below, we import a subnet by subnet id:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-hcl" data-lang="hcl"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aws_subnet&amp;#34; &amp;#34;private_subnet&amp;#34;&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;private_subnet_id&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In the example below, we import a subnet by filtering from all subnets in the VPC by tag:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-hcl" data-lang="hcl"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aws_subnet&amp;#34; &amp;#34;private_subnet&amp;#34;&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vpc_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;vpc_id&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;filter&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tag:Name&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;Private&amp;#34;&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;There are pros and cons of each approach. A module with mechanism 1 is more transferrable across different environment, because the ID of subnet is explicitly provided. However, authors needs to manage those explicit variables with code. Mechanism 2 fetches target resources with filter. It depends on a well-implemented tagging policy in the resource farm.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Terraform &lt;a href="https://registry.terraform.io/"&gt;Registry&lt;/a&gt; (since 2017) contains a lot of pre-built modules for each backend platform (e.g. &lt;a href="https://registry.terraform.io/browse/modules?provider=aws"&gt;AWS&lt;/a&gt;). If you find any module that can be used in your project, the module repo can be referenced directly by Git repository URL. You should be aware of the risk of this practice though. Many platforms are keen to publish modules for their platform. Anyone can &lt;a href="https://www.terraform.io/docs/language/modules/develop/publish.html"&gt;publish their own modules&lt;/a&gt; to the community as well.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can quickly generate module documentation with &lt;a href="https://terraform-docs.io/"&gt;terraform-docs&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="local-execution"&gt;Local Execution&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Local execution is the basic workflow mode which is mostly seen with very small collaboration team. In this mode, the developer executes terraform binary (Terraform CLI) from their workstation (e.g. Laptop). The Terraform CLI converts code into API calls to interface cloud provider. The most frequently used commands (from terraform directory) are:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;terraform init&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;terraform plan&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;terraform apply&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The init command initializes the working directory. The plan command figures out the delta between code and infrastructure. It outlines the changes it is about to make. The apply command commits the change. The documentation of Terraform CLI commands is &lt;a href="https://www.terraform.io/docs/cli/commands/index.html"&gt;here&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Terraform keeps track of the infrastructure it manages in state file. &lt;a href="https://www.terraform.io/docs/language/state/purpose.html"&gt;This&lt;/a&gt; article explains the purpose of state. State management collaboration difficult with local execution because the state file by default is created in the working directory on user&amp;#8217;s workstation. Although the state file can be configured to be stored in a shared location such as S3, it still requires a mechanism to &lt;a href="https://www.terraform.io/docs/language/state/locking.html"&gt;lock&lt;/a&gt; the state in a multi-developer collaboration.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In large operations, the same code base in Terraform, is usually used to created several different sets of infrastructures, for example, in different geographic regions. So it is a 1-to-many relationship between the code repo and the infrastructure state. To further complicate things, each state might have been deployed using different revisions of the code. To overcome that challenge, Terraform introduced the concept of &lt;a href="https://www.terraform.io/docs/language/state/workspaces.html"&gt;workspace&lt;/a&gt;, which is essentially an instance of state describing a particular group of infrastructure being managed by the same source code. When there are many workspaces, it becomes tricky to manage them with CLI &lt;a href="https://www.terraform.io/docs/cli/commands/workspace/index.html"&gt;commands&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;State management is a major challenge that needs to be solved for team collaboration in local execution workflow. Each state must use the same revision of Terraform code. You can use Git in combination as a workaround to that limitation but the point is you cannot tie a workspace to a commit with the workspace &lt;a href="https://www.terraform.io/docs/cli/commands/workspace/index.html"&gt;commands&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In some enterprise environment, the execution is from a VM (e.g. ADO agent on-premise) without Internet access, which poses another challenge. First, we need to pre-load required providers manually. The enterprise needs a proxy solution to safely download packages from &lt;a href="https://releases.hashicorp.com/terraform/"&gt;Hashicorp website&lt;/a&gt;. One good option is &lt;a href="https://www.sonatype.com/products/repository-oss"&gt;Nexus Repository&lt;/a&gt;, with both open-source and pro supports. It is a full-function artifactory repo that can host helm repo, apt repo, yum repo, etc. Second, we also need to configure Terraform so it picks up providers locally. Managing &lt;a href="https://www.terraform.io/cli/plugins"&gt;plugins&lt;/a&gt; without Internet access requires understanding of the order in which Terraform tries to load plugins during initialization. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="remote-execution"&gt;Remote Execution&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In remote execution, the code is executed in Terraform Enterprise or Terraform Cloud. Both are remote web servers. The difference is that Terraform Enterprise is self-hosted service, requiring IT specialist to &lt;a href="https://www.terraform.io/docs/cli/commands/workspace/index.html"&gt;install&lt;/a&gt; and maintain Terraform Enterprise. Terraform Cloud on the other hand, is a managed SaaS service. The &lt;a href="https://www.hashicorp.com/products/terraform/pricing"&gt;pricing model&lt;/a&gt; includes a free plan for small number of users.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="1696" height="1004" src="https://static.digihunch.com/wp-content/uploads/2021/07/image.png" alt="" class="wp-image-2486" style="width:683px;height:404px"/&gt;&lt;figcaption class="wp-element-caption"&gt;Terraform workspace configuration&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In Terraform Enterprise or Cloud, the remote execution is organized in workspaces. You need to create an organization, and then create workspace under the organization in order to execute code. With each workflow, you can specify version control system (VCS) and subdirectory, to tell the workspace where to fetch Terraform code from. The workspace also allows you to define secrets and variables specific to the workspace. When you execute a workspace plan, the secrets and variables are passed from workspace to the execution logic.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="1480" height="1056" src="https://static.digihunch.com/wp-content/uploads/2021/07/image-1.png" alt="" class="wp-image-2487" style="width:533px;height:380px"/&gt;&lt;figcaption class="wp-element-caption"&gt;Terraform Workspace Variable configuration&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You will also need to design the Terraform code in a way to work seamlessly with the secrets and variables loaded from the workspace. The variable declaration in code should match the definition in workspace. There are already a number of variables that came in handy. Check out this &lt;a href="https://www.terraform.io/docs/cli/config/environment-variables.html"&gt;guide&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Each execution is referred to as a &amp;#8220;run&amp;#8221;, with its own run id. A workspace involves may runs, which may succeed or fail. Each run pulls a specific commit of the source repository, and goes through stages such as plan, and apply. The UI from each run result list out the status of each result, in a very easy to read format.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="2318" height="1046" src="https://static.digihunch.com/wp-content/uploads/2021/07/image-2.png" alt="" class="wp-image-2489"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The state data is persisted in the web server as they were generated. Therefore the collaborator do not need to worry about managing state with CLI tools. If there are files that you do not want picked up by the execution engine, their locations can be added to a file .terraformignore. Refer to &lt;a href="https://www.terraform.io/docs/language/settings/backends/remote.html#excluding-files-from-upload-with-terraformignore"&gt;this&lt;/a&gt; guide.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="aws-profile"&gt;AWS profile&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Local execution still has a lot of use cases in enterprises such as testing with temporary resources. A common challenge is authentication. As discussed, Terraform CLI picks up identity information from AWS CLI and authenticates its way into the backend to run API calls against. So AWS CLI must be configured correctly with the sufficient permission to provision resources. On the other hand, enterprises usually offload IAM to an identity store, such as AzureAD, Okta, etc. Putting those together, the pattern of authentication and authorization usually looks like this:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;User logs on via SSO (e.g. &lt;a href="https://static.digihunch.com/2020/03/saml-security-assertion-markup-language/"&gt;SAML&lt;/a&gt;). The validation response gives a name of an IAM role.&lt;/li&gt;&#10;&lt;li&gt;Upon successful authentication, user takes the IAM role. The role does not have any capability, except for assuming a second IAM role.&lt;/li&gt;&#10;&lt;li&gt;The second IAM role (the functional role) grants user the permission to do its business.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The steps above, can be carried out in AWS console, or with AWS cli using &lt;a href="https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role.html"&gt;assume-role&lt;/a&gt; command. However, when we put Terraform in the picture, it becomes a little involving because the credential information is updated whenever the functional role is assumed, and the assume-role command takes a pretty long argument.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To skip typing the long command every time, there are some handy tools, such as &lt;a href="https://github.com/sportradar/aws-azure-login"&gt;aws-azure-login&lt;/a&gt;. An even better tool that works with a variety of identity stores is &lt;a href="https://github.com/Versent/saml2aws"&gt;saml2aws&lt;/a&gt;. The tool allows you to configure identity backend, assume the functional role, and update credential information in aws credential file, all with a single command. The AWS CLI configuration reads:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;region &lt;span style="color:#f92672"&gt;=&lt;/span&gt; us&lt;span style="color:#f92672"&gt;-&lt;/span&gt;east&lt;span style="color:#f92672"&gt;-&lt;/span&gt;1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output &lt;span style="color:#f92672"&gt;=&lt;/span&gt; json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cli_history &lt;span style="color:#f92672"&gt;=&lt;/span&gt; enabled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cli_pager &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;role_session_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; functional_operation&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;profile function_user&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source_profile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;role_session_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; functional_operation&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;role_arn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; arn:aws:iam::9998887766:role&lt;span style="color:#f92672"&gt;/&lt;/span&gt;admin&lt;span style="color:#f92672"&gt;-&lt;/span&gt;access&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;region &lt;span style="color:#f92672"&gt;=&lt;/span&gt; us&lt;span style="color:#f92672"&gt;-&lt;/span&gt;east&lt;span style="color:#f92672"&gt;-&lt;/span&gt;1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In Terraform provider, we need to tell it to assume that role as well:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;provider &lt;span style="color:#e6db74"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; region &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; assume_role {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; role_arn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;arn:aws:iam::9998887766:role/admin-access&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;terraform&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This will ensure Terraform assumes appropriate role before doing its job.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="aws-ec2-ssh-key-pair"&gt;AWS EC2 SSH Key Pair&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RSA key authentication for SSH should be used for Linux Instances. When creating an EC2 instance, we give it our public key so we can then later authenticate through SSH. If the key is already stored in AWS, we just need to tell EC2 the name of the key, in the key_name property. If the code is likely to be executed from several different places by different users, then we can write the code so it picks up public key from user&amp;#8217;s workstation (~/.ssh/id_rsa.pub). Here is an example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;variable &lt;span style="color:#e6db74"&gt;&amp;#34;local_pubkey_file&amp;#34;&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; string&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;~/.ssh/id_rsa.pub&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data &lt;span style="color:#e6db74"&gt;&amp;#34;local_file&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pubkey&amp;#34;&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; filename &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pathexpand(var.&lt;span style="color:#a6e22e"&gt;local_pubkey_file&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;resource &lt;span style="color:#e6db74"&gt;&amp;#34;aws_key_pair&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;user-pubkey&amp;#34;&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; key_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;runner-pubkey&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; public_key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; data.&lt;span style="color:#a6e22e"&gt;local_file&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;pubkey&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;resource &lt;span style="color:#e6db74"&gt;&amp;#34;aws_instance&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bastion&amp;#34;&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; instance_type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;t2.micro&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; key_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; aws_key_pair.&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;pubkey.&lt;span style="color:#a6e22e"&gt;key_name&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;For remote execution, we can even add an option to pass public key in as variable, to override the key file variable. For an example, check out my &lt;a href="https://github.com/digihunch/orthweb/tree/main/terraform"&gt;orthweb&lt;/a&gt; project.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To upload files to EC2 instance from Terraform execution environment, we can use the file provisioner with ssh as connection type. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/07/helm-configuration-management-for-kubernetes-resources/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Helm – Configuration Management for Kubernetes Resources&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/08/docker-desktop-a-single-node-kubernetes-cluster/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Single-node Kubernetes cluster – docker desktop&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Virtualization 2 of 4 – Graphics Computing</title><link>https://static.digihunch.com/2020/08/virtualization-of-graphics-computing-resource/</link><pubDate>Sat, 01 Aug 2020 18:24:00 -0400</pubDate><guid>https://static.digihunch.com/2020/08/virtualization-of-graphics-computing-resource/</guid><description>&lt;p class="wp-block-paragraph"&gt;We covered hypervisor in previous post. In this article we focus on the virtualization of graphics computing resource.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;GPU vs CPU&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;GPU is a specialized type of microprocessor primarily designed for quick image rendering. GPU appeared as a response to graphically intense applications that put a burden on the CPU and degrated computer performance. They became a way to offload those tasks from CPUs, but modern graphics processors are powerful enough to perform rapid mathematical calculations for many other purposes apart from rendering.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;CPU consists of a few cores (up to 23) optimized for sequential serial processing, which is designed to maximize the performance of a single task within a job. GPU uses thousands of smaller and more efficient cores for massively parallel architecture aimed at handling multiple functions at the same time. Typical uses cases for GPUs, in addition to graphics display, includes Games, 3D visualization, Image processing, big data and deep machine learning.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://www.apps4rent.com/wp-content/uploads/2018/04/cpu-vs-gpu.jpg" alt="GPU vs CPU | What's better?"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Moving to virtualization world, the most primitive mechanism for graphics acceleration is Soft 3D, which is commonly used in virtual desktops, or DaaS (desktop as a service). The Software 3D renderer (Soft 3D) uses the Soft 3D graphics driver to provide support for software-accelerated 3D graphics without any physical GPUs being installed in the ESXi host. With respect to GPU in virtualized environment, VMware developed a few technologies.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;vSGA (Virtual Shared Graphics Acceleration)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The physical GPUs in the server are virtualized and shared across multiple guest VMs. This option involves installing an Nvidia driver into the hypervisor itself, and each guest VM uses a &lt;span style="text-decoration: underline;"&gt;proprietary VMware SVGA 3D driver&lt;/span&gt; that communicates with the Nvidia driver in ESX. The biggest limitation here is that these drivers only work with DirectX up to 9.0c, and OpenGL up to 2.1. This technology was introduced in early 2013 and is used in light workload for knowledge worker, such as PowerPoint, Visio and web browsing.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full is-resized"&gt;&lt;img loading="lazy" decoding="async" width="572" height="664" src="https://static.digihunch.com/wp-content/uploads/2024/07/vSGA.png" alt="" class="wp-image-11412" style="width:443px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2024/07/vSGA.png 572w, https://static.digihunch.com/wp-content/uploads/2024/07/vSGA-258x300.png 258w" sizes="auto, (max-width: 572px) 100vw, 572px" /&gt;&lt;figcaption class="wp-element-caption"&gt;vSGA&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;h3 class="wp-block-heading"&gt;vDGA (Virtual Dedicated Graphics Acceleration)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;vDGA, also known as &amp;#8220;GPU passthrough&amp;#8221;. It provides each VM with unrestricted, fully dedicated access to one of the host&amp;#8217;s GPUs. The hypervisor is drilling a direct hole in itself between the GPU and the guest. This technology allows you to present an internal PCI GPU directly to a VM guest. The device acts as if it were directly driven by the VM guest, and the guest detects the PCI device as if it were physically connected, using the &amp;#8220;real&amp;#8221; driver. There is no special drivers in the hypervisor. vDGA offers the highest level of performance for users with the most intensive graphics computing needs.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full is-resized"&gt;&lt;img loading="lazy" decoding="async" width="444" height="588" src="https://static.digihunch.com/wp-content/uploads/2024/07/passthrough.png" alt="" class="wp-image-11417" style="width:304px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2024/07/passthrough.png 444w, https://static.digihunch.com/wp-content/uploads/2024/07/passthrough-227x300.png 227w" sizes="auto, (max-width: 444px) 100vw, 444px" /&gt;&lt;figcaption class="wp-element-caption"&gt;GPU passthrough&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The main advantage to vDGA is that since the GPU is passed through to the guest and the guest uses regular Nvidia drivers, it fully supports everything the Nvidia driver can do natively. This enables all versions of DirectX, OpenGL and even CUDA. The downside is that vDGA is expensive, since you need one GPU per user. There is also a lack of vMotion support. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;VMware added support for vDGA in late 2013. The target market is high-end users with intensive graphical applications (oil&amp;amp;gas, scientific simulations, CAD/CAM, etc&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;vGPU (Virtual GPU)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;vGPU is also known as Virtual Shared Pass-Through Graphics Acceleration. This technology sites somewhere in between the two previously introduced, as an option to strike a balance between cost-effectiveness and resource-sharing. It is essentially vDGA but with multiple users per GPU, instead of one-to-one mapping. Like vDGA, with vGPU you install the real Nvidia driver in guest VMs, and the hypervisor passes the graphics commands directly to the hypervisor without any translation.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;vGPU gives you all that plus the ability to share a GPU across up to 8 VMs. The idea of vGPU is that you get better performance than vSGA option, with a portion of cost when compared to vDGA. The use case for vGPU will be the higher-end knowledge workers who need real &amp;#8220;GPU&amp;#8221; access but don&amp;#8217;t need full-on multi-thousand dollar graphics workstations.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="489" height="337" src="https://static.digihunch.com/wp-content/uploads/2020/07/image-5.png" alt="" class="wp-image-1190" style="width:429px;height:auto"/&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;VMware partners with Nvidia on vGPU development. Below is the use-case chart from previous VMware white paper:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="900" height="590" src="https://static.digihunch.com/wp-content/uploads/2020/08/Deploying_Hardware_Accelerated_Graphics_View_Horizon.webp" alt="" class="wp-image-13153" srcset="https://static.digihunch.com/wp-content/uploads/2020/08/Deploying_Hardware_Accelerated_Graphics_View_Horizon.webp 900w, https://static.digihunch.com/wp-content/uploads/2020/08/Deploying_Hardware_Accelerated_Graphics_View_Horizon-300x197.webp 300w, https://static.digihunch.com/wp-content/uploads/2020/08/Deploying_Hardware_Accelerated_Graphics_View_Horizon-768x503.webp 768w" sizes="auto, (max-width: 900px) 100vw, 900px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The diagram below illustrates the architecture of virtual GPU (NVIDIA Grid):&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="734" height="690" src="https://static.digihunch.com/wp-content/uploads/2024/07/GRID.png" alt="" class="wp-image-11414" srcset="https://static.digihunch.com/wp-content/uploads/2024/07/GRID.png 734w, https://static.digihunch.com/wp-content/uploads/2024/07/GRID-300x282.png 300w" sizes="auto, (max-width: 734px) 100vw, 734px" /&gt;&lt;figcaption class="wp-element-caption"&gt;high-level architecture of GRID vGPU&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The best &lt;a href="https://techzone.vmware.com/resource/deploying-hardware-accelerated-graphics-vmware-horizon-7"&gt;white paper&lt;/a&gt; about the three technologies and their use cases is on VMware website.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Identify Graphics driver&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On Linux VM, we can simply use lspci to identify graphics driver.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@ghrender ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# lspci | grep VGA&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;03:00.0 VGA compatible controller: Matrox Electronics Systems Ltd. Integrated Matrox G200eW3 Graphics Controller &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rev 04&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3b:00.0 VGA compatible controller: NVIDIA Corporation GP104GL &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Quadro P5000&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rev a1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;In the result, the far left column is specified domain, e.g. 3b:00.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;To display details on graphics card by specified domain (3b:00.0 for example) with memory information:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@ghrender ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# lspci -v -s 3b:00.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3b:00.0 VGA compatible controller: NVIDIA Corporation GP104GL &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Quadro P5000&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rev a1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;prog-if &lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;VGA controller&lt;span style="color:#f92672"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Subsystem: NVIDIA Corporation Device 11b2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Flags: bus master, fast devsel, latency 0, IRQ 190, NUMA node &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Memory at ab000000 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;32-bit, non-prefetchable&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;16M&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Memory at 382fe0000000 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;64-bit, prefetchable&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;256M&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Memory at 382ff0000000 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;64-bit, prefetchable&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;32M&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;I/O ports at &lt;span style="color:#ae81ff"&gt;6000&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;128&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;virtual&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Expansion ROM at ac080000 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;disabled&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;512K&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;60&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Power Management version &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;68&lt;span style="color:#f92672"&gt;]&lt;/span&gt; MSI: Enable+ Count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1/1 Maskable- 64bit+&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;78&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Express Legacy Endpoint, MSI &lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;100&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Virtual Channel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;250&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Latency Tolerance Reporting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;128&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Power Budgeting &amp;lt;?&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;420&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Advanced Error Reporting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;600&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Vendor Specific Information: ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0001&lt;/span&gt; Rev&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; Len&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;024&lt;/span&gt; &amp;lt;?&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Capabilities: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;900&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#75715e"&gt;#19&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Kernel driver in use: nvidia&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;Kernel modules: nouveau, nvidia_drm, nvidia&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The lshw command can also identify onboard Intel/AMD or Nvidia dedicated GPU:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@ghrender ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# lshw -C display&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; *-display&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; description: VGA compatible controller&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; product: Integrated Matrox G200eW3 Graphics Controller&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vendor: Matrox Electronics Systems Ltd.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; physical id: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bus info: pci@0000:03:00.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version: &lt;span style="color:#ae81ff"&gt;04&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; bits&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clock: 66MHz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; capabilities: pm vga_controller bus_master cap_list rom&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; configuration: driver&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mgag200 latency&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;64&lt;/span&gt; maxlatency&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; mingnt&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resources: irq:16 memory:91000000-91ffffff memory:92808000-9280bfff memory:92000000-927fffff&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; *-display&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; description: VGA compatible controller&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; product: GP104GL &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Quadro P5000&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vendor: NVIDIA Corporation&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; physical id: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bus info: pci@0000:3b:00.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version: a1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt; bits&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clock: 33MHz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; capabilities: pm msi pciexpress vga_controller bus_master cap_list rom&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; configuration: driver&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nvidia latency&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resources: iomemory:382f0-382ef iomemory:382f0-382ef irq:190 memory:ab000000-abffffff memory:382fe0000000-382fefffffff memory:382ff0000000-382ff1ffffff ioport:6000&lt;span style="color:#f92672"&gt;(&lt;/span&gt;size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;128&lt;span style="color:#f92672"&gt;)&lt;/span&gt; memory:ac080000-ac0fffff&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/07/overview-of-virtualization/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Virtualization 1 of 4 – Hypervisor&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/08/java-garbage-collection/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Java Garbage Collection&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Virtualization 1 of 4 – Hypervisor</title><link>https://static.digihunch.com/2020/07/overview-of-virtualization/</link><pubDate>Mon, 27 Jul 2020 22:52:00 -0400</pubDate><guid>https://static.digihunch.com/2020/07/overview-of-virtualization/</guid><description>&lt;p class="wp-block-paragraph"&gt;In broad terms, virtualization of computing resource is about isolation of resources, at different levels. There are five levels of virtualization:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Application level, such as JVM, .NET CLR&lt;/li&gt;&#10;&lt;li&gt;Library (user-level API) level&lt;/li&gt;&#10;&lt;li&gt;Operating system level, such as LXC, Docker, OpenVZ&lt;/li&gt;&#10;&lt;li&gt;Hardware abstraction layer (HAL) level, such as VMware, Xen, etc&lt;/li&gt;&#10;&lt;li&gt;Instruction set architecture (ISA) level&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In my context I deal mostly with OS level and HAL (hardware abstraction layer) level of virtualization. In loose terms, the word &lt;em&gt;containerization&lt;/em&gt; refers to &lt;span style="text-decoration: underline;"&gt;OS level virtualization&lt;/span&gt;, while the word &lt;em&gt;virtualization&lt;/em&gt; is exclusively reserved for &lt;span style="text-decoration: underline;"&gt;HAL level virtualization&lt;/span&gt;, also referred to as &lt;span style="text-decoration: underline;"&gt;hypervisor-based virtualization&lt;/span&gt;. This post will just focus on this family of technology and loosely refers to it as virtualization.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Virtualization technology evolved from on-premise data centre environment and now is the backbone of cloud computing. The challenges of IT operation in the era of virtualization involves managing VM sprawling, investigating performance issues, planning capacity and addressing storage I/O block. The idea of virtualization is sharing (thus isolating) resources for better utilization, leading to better return on investment. This posting is to cover only the very basics of virtualization.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-hypervisor"&gt;Hypervisor&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hypervisor is the software layer which provides the capability to run multiple virtual machines on the same physical host. It is broken down into two categories:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Type I hypervisor (aka bare metal hypervisor)&lt;/strong&gt;: directly run on physical hardware. They control the hardware as well as manage the virtual machines. For example, Linux KVM, VMware ESXi, Xen and Microsoft Hyper-V&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Type II hypervisor&lt;/strong&gt;: runs as an application or service on top of the host operating system, which is installed on the bare metal. Guest operating system calls need to traverse via the host operating system stack to reach hardware resource. For example, Oracle Virtual Box, VMware Fusion and Linux Containers (LXC)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter"&gt;&lt;img decoding="async" src="https://img.vembu.com/wp-content/uploads/2019/12/Hypervisor-Types.png" alt="Type-1 vs Type-2 Hypervisor"/&gt;&lt;figcaption class="wp-element-caption"&gt;Hypervisor Types&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;h3 class="wp-block-heading" id="h-virtualization-techniques"&gt;Virtualization Techniques&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The most primitive form of technology that can be arguably categorized under virtualization is hardware emulation, where a piece of (more accessible) hardware imitates another (less accessible). The architecture limits itself in functional testing only, and is not built for performance or production at all.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The original virtualization technology deals with CPU and memory virtualization. In this well-written &lt;a href="https://github.com/skonstantinov89/books/blob/master/Understanding%20Full%20Virtualization%2C%20Paravirtualization%2C%20and%20Hardware%20Assist.pdf"&gt;whitepaper &lt;/a&gt;fromVMware, there are three CPU virtualization techniques introduced for x86 architecture.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The x86 architecture offers four levels of privilege known as Ring 0,1,2 and 3 to operating system and applications to manage access to the computer hardware. User-level applications typically run in Ring 3, the OS must execute its privileged instructions in Ring 0 since it needs to have direct access to memory and hardware. The two main challenges with virtualizing x86 architecture are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;A virtualization layer between hardware operating system who expects Ring 0 privilege;&lt;/li&gt;&#10;&lt;li&gt;Some instructions with different semantics when not executed in Ring 0 cannot be virtualized effectively. They need to be translated at runtime.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These challenges makes true virtualization of x86 architecture impossible and thus VMware developed three alternative technologies.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Full_virtualization"&gt;&lt;strong&gt;Full virtualization&lt;/strong&gt;&lt;/a&gt; (using binary translation): virtual machine presents a complete simulation of the actual hardware environment so that an unmodified guest OS can run in isolation. The Guest OS is not aware that the underlying environment it is running on is virtualized, and issues hardware calls to communicate with (what it thinks as) hardware. The virtual processors have to understand guest CPU instruction, and reproduce the equivalent CPU instructions of the host machine. VMware&amp;#8217;s technology to address this is called &lt;strong&gt;Binary Translation&lt;/strong&gt;. This overhead makes true full virtualization difficult to achieve. In real life, a virtual environment that provides &amp;#8220;enough representation of the underlying hardware&amp;#8221; can be considered to provide full virtualization as long as it allows guest OS to run without modification. Full virtualization comes with a performance penalty. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Paravirtualization"&gt;&lt;strong&gt;Paravirtualization &lt;/strong&gt;&lt;/a&gt;(aka OS assisted virtualization): refers to communication between the guest OS and the hypervisor to improve performance and efficiency. In this technology, guest OS is modified with an interface to host hardware to be able to communicate and operate seamlessly. Since the guest OS is modified, the VM does not need to be a complete simulation of the hardware. The modified guest OS knows it is running on a virtualized environment, and (vm driver) makes API calls (known as &amp;#8216;hyper calls&amp;#8217;) to the hypervisor. This allows para-virtualization technology to achieve performance closer to non-virtualized environment. However, since paravirtualization cannot support unmodified operating systems, its compatibility and portability is poor. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Hardware-assisted_virtualization"&gt;&lt;strong&gt;Hardware-Assisted Virtualization&lt;/strong&gt;&lt;/a&gt;: hardware vendors such as Intel and AMD both have developed extensions (new features) to simplify virtualization techniques, for example, the introduction of privileged instructions with new CPU execution mode feature to allow hypervisor to run in a new root mode below ring 0. This removed the need for full virtualization and paravirtualization. With VMware originally as a promoter of full virtualization and Xen for paravirtualization, most virtualization technologies today utilizes hardware-assisted virtualization feature, for example, Linux KVM, VMware workstation, VMware fusion, Xen, VirtualBox, etc. Intel&amp;#8217;s virtualization extension is VT-x. AMD&amp;#8217;s counterpart is AMD-V technology.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To virtualize memory, another level of memory virtualization is required (similar to the virtual memory support in Linux). Hypervisor is responsible for mapping guest physical memory to the actual machine memory, and it uses shadow page tables to accelerate the mappings, usually at a performance cost.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-popular-hypervisors"&gt;Popular hypervisors&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the market there are a few popular hypervisor technologies. They are all type 1 hypervisors:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Xen"&gt;Xen &lt;/a&gt;is an open-source &lt;a href="https://xenproject.org/"&gt;hypervisor project&lt;/a&gt; originally developed in Cambridge University, licensed under GPLv2. . Based on that, Citrix developed its commercial product XenServer, a bare-metal virtualization platform with enterprise-grade features for x86 and AMD environments. Oracle VM is another commercial implementation of Xen. The Xen project also supports many cloud platforms such as Openstack, Cloudstac, etc. Xen project supports paravirtualization (Xen-PV) as well as hardware-assisted virtualization (Xen-HVM) for virtualization of X86, IA64, ARM and other CPU architectures. The earlier versions does not support memory overcommit (aka &amp;#8220;dynamic memory optimization&amp;#8221;, &amp;#8220;memory &lt;a href="https://static.digihunch.com/2020/05/understanding-where-the-memory-goes-on-linux-vm/"&gt;ballooning&lt;/a&gt;&amp;#8220;, or as Citrix calls it &amp;#8220;dynamic memory control, DMC&amp;#8221;). This delivers better performance but also has higher budgetary requirement on hardware since there isn&amp;#8217;t room for over-subscription. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hyper-V is a Microsoft product. It executes in high CPU privilege (Microsoft calls it ring -1 which is equivalent to root mode as Intel calls it). On the guest VM, OS kernel and drivers run in ring 0, application rin in ring 3. This eliminates the need for binary translation. Hyper-V does not support memory overcommit either. Hyper-V is well integrated with Windows platform. It supports Linux as well although with some performance penalty.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Linux KVM (Kernel-based Virtual Machine) is a full open-source virtualization solution for GNU/Linux. What makes KVM a special hypervisor is that it uses a loadable kernel module kvm.ko that turns itself into a hypervisor and provides VMs with direct access to the hardware. So it is a type 1 hypervisor despite of the presence of Linux OS. KVM also contains a processor specific module, kvm-intel.ko or kvm-amd.ko. KVM leverages qemu to access devices. Because KVM runs as a process inside of Linux OS, KVM can use many existing feature in Linux kernel. Redhat has an enterprise solution based on KVM.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="850" height="414" src="https://static.digihunch.com/wp-content/uploads/2023/01/Comparison-of-Xen-KVM-and-QEMU.png" alt="" class="wp-image-7813" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/Comparison-of-Xen-KVM-and-QEMU.png 850w, https://static.digihunch.com/wp-content/uploads/2023/01/Comparison-of-Xen-KVM-and-QEMU-300x146.png 300w, https://static.digihunch.com/wp-content/uploads/2023/01/Comparison-of-Xen-KVM-and-QEMU-768x374.png 768w" sizes="auto, (max-width: 850px) 100vw, 850px" /&gt;&lt;figcaption class="wp-element-caption"&gt;Xen vs KVM&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;VMware &lt;a href="https://en.wikipedia.org/wiki/VMware_ESXi"&gt;ESXi &lt;/a&gt;is VMware&amp;#8217;s premium hypervisor product (not open-source) and is available for &lt;s&gt;free download&lt;/s&gt;, although the advanced features are not free. (Update no free download link &lt;a href="https://www.reddit.com/r/vmware/comments/1amtzvc/esxi_hypervisor_free_gone/"&gt;anymore&lt;/a&gt;.) VMware &lt;a href="https://static.digihunch.com/2018/07/overview-of-vsphere/"&gt;vSphere&lt;/a&gt; is virtualization platform built on top of ESXi, including a whole family of virtualization products.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-market-segments-and-players"&gt;Market segments and players&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Virtualization involves many market segments such as virtual desktop infrastructure (VDI, for desktop virtualization), server virtualization is the predominant domain in the virtualization of data centre environment. This effort led to Hyper-Converged Infrastructure (HCI) where almost all the traditional hardware resources are software-defined through the virtualization layer. The management of infrastructure is abstracted away from the physical hardware management. The three most fundamental areas in HCI are:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Server (compute) virtualization: the previous section covers the virtualization of memory and x86 CPU, which are the main focus on computing resource virtualization. Additionally, graphics computing resources can be virtualized today. Example products include: VMware vShpere (compute virtualization based on ESXi hypervisor).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Storage_virtualization"&gt;Storage Virtualization&lt;/a&gt;&lt;/strong&gt;: the technology to abstract physical data storage resource to make them appear as if they were a centralized resource. Storage virtualization takes place at three levels depending on the use case: block-level, file-level and object level. Example products include: VMWare vSAN (vSphere-native storage), HPE 3PAR (Tier-1 storage), EMC VxRail, PureStorage Flash Array (Tier 1), etc. Storage Virtualization enables &lt;a href="https://en.wikipedia.org/wiki/Software-defined_storage"&gt;&lt;strong&gt;Software-Defined Storage&lt;/strong&gt; &lt;/a&gt;&lt;strong&gt;(SDS)&lt;/strong&gt;, the provisioning and management of data storage independent of the underlying hardware.&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Network_virtualization"&gt;Network Virtualization&lt;/a&gt;&lt;/strong&gt;: the technology to abstract network resources that were traditionally delivered in hardware to software. Network virtualization decouples network services from the underlying hardware management and allows virtual provisioning of an entire network. VLAN is a classic example of network virtualization. There are also various overlay technologies such as VXLAN, which provides an industry framework for overlaying virtualized layer 2 network over layer 3 network (used in Docker network) using an encapsulation mechanism and a control plane. Example products include: VMware NSX Data Center (L2-L7 network and security virtualization platform), Cisco ACI, Palo Alto Panorama. Network Virtualization enables &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Software-defined_networking"&gt;Software-Defined Network&lt;/a&gt; (SDN)&lt;/strong&gt;, an approach to network management that enables dynamic, programmatically efficient network configuration in order to improve network performance and monitoring, making it more like cloud computing than traditional network management.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-delivery-model"&gt;Delivery model&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Virtualization allows managed service providers (MSPs) to deliver IT service in the following three models:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Iaas (Infrastructure as a Service)&lt;/strong&gt;: MSP delivers VM to customers.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;PaaS (Platform as a Service)&lt;/strong&gt;: MSP delivers environments to customers (e.g. Database as a Service, managed RabbitMQ service, etc).&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;SaaS (Software as a Service)&lt;/strong&gt;: MSP delivers entire application for the customer.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter is-resized"&gt;&lt;img decoding="async" src="https://www.redhat.com/cms/managed-files/iaas_focus-paas-saas-diagram-1200x1046.png" alt="What is IaaS?" style="width:608px;height:388px"/&gt;&lt;figcaption class="wp-element-caption"&gt;IT service delivery models enabled by virtualization technology&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Since virtualization is the backbone of cloud computing. This model is also referred to as cloud computing delivery model.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-virtualization-and-containerization"&gt;Virtualization and Containerization&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These two concepts are similar and could be confusing to beginners. Both provide a mechanism to isolate computing resource for different applications, for the purpose of higher utilization of resource. The difference lies in how and where the isolation is made. Virtualization requires a guest operating system per VM (OS level isolation), whereas the container technology isolates application processes along with its runtime into a container (dependency level isolation), using some new Linux kernel features such as &lt;em&gt;namespaces &lt;/em&gt;and &lt;em&gt;cgroups&lt;/em&gt;. All containers make their system calls to the container engine on the host operating system. So they share a kernel on the same host. In this sense, container engine running on OS could be considered as type 2 hypervisor.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://dzone.com/storage/temp/10561741-vm-container-figure1.jpg" alt="Image title"/&gt;&lt;figcaption class="wp-element-caption"&gt;From VMs to containers&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;VMware is a major player in enterprise data centre virtualization, which is facing fierce competition from public and private cloud vendors. VMware also has its own private cloud services. Docker is the most popular container technology that conforms to the specifications of Open Container Initiative (OCI), a governance structure for industry standards around container formats and runtimes.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-virtualization-and-cloud"&gt;Virtualization and Cloud&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Among public cloud vendors, AWS &lt;a href="https://cloudacademy.com/blog/aws-ami-hvm-vs-pv-paravirtual-amazon/"&gt;EC2 &lt;/a&gt;used Xen PV and Xen HVM in its earlier implementations. It has transitioned to AWS bare metal. The history is well summarized &lt;a href="http://www.brendangregg.com/blog/2017-11-29/aws-ec2-virtualization-2017.html"&gt;here&lt;/a&gt;. Microsoft Azure runs Azure Hypervisor as the native hypervisor in Azure Cloud Services platform. It is a customized version of Microsoft Hyper-V specifically for Azure platform. With GCP, Google &lt;a href="https://cloud.google.com/compute/docs/faq"&gt;Compute Engine&lt;/a&gt; (GCE) instance runs VMs on KVM as hypervisor. It can also enable nested virtualization.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The scope of cloud computing is evolving overtime. It originally only refers to a business model of offering IT services (in one of the three delivery models outlined above) based on virtualization technology. Therefore I cannot make comparison between a technology and a business model. Today, with public cloud vendor extending their offerings (with various managed services and platforms) and people&amp;#8217;s misuse of the terms, the buzz-word &amp;#8220;cloud&amp;#8221; seems to suggest anything that is offered in public cloud service. The essence still remain the same where managed services and managed platforms are built on top of virtualized compute unit under the hood, which are driven by virtualization technologies.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/07/zookeeper-and-kafka-overview/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kafka high-level Overview&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/08/virtualization-of-graphics-computing-resource/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Virtualization 2 of 4 – Graphics Computing&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>