<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jason Andrews</title>
    <description>The latest articles on Forem by Jason Andrews (@jasonrandrews).</description>
    <link>https://forem.com/jasonrandrews</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F263634%2F8acbf3a0-dfa6-4976-a637-388155b54d39.jpeg</url>
      <title>Forem: Jason Andrews</title>
      <link>https://forem.com/jasonrandrews</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jasonrandrews"/>
    <language>en</language>
    <item>
      <title>AWS Graviton migration with Kiro CLI and the Arm MCP server</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Mon, 12 Jan 2026 23:46:59 +0000</pubDate>
      <link>https://forem.com/aws-builders/aws-graviton-migration-with-kiro-cli-and-the-arm-mcp-server-38fd</link>
      <guid>https://forem.com/aws-builders/aws-graviton-migration-with-kiro-cli-and-the-arm-mcp-server-38fd</guid>
      <description>&lt;p&gt;AWS Graviton processors offer price-performance benefits, but migrating applications from x86 to the Arm architecture can feel like extra work. You might wonder about compatibility issues, performance implications, or simply where to start with the migration process.&lt;/p&gt;

&lt;p&gt;The Arm MCP server paired with Kiro CLI makes a good migration companion. Instead of manually researching compatibility matrices, hunting through documentation, or guessing about architecture-specific dependencies, you get an AI assistant that understands Arm migration.&lt;/p&gt;

&lt;p&gt;This article explains how to set up Kiro CLI with the Arm MCP server and discover how it transforms migration questions into simple conversations. You'll see how to verify Docker image compatibility, get guidance on software porting considerations, and leverage tools that detect x86-specific code in your applications.&lt;/p&gt;

&lt;p&gt;By the end, you'll have an environment that makes Graviton migration feel less like detective work. Whether you're planning your first migration or optimizing an existing Arm deployment, this setup will save time and increase confidence in the migration process. &lt;/p&gt;

&lt;h2&gt;
  
  
  Quick setup
&lt;/h2&gt;

&lt;p&gt;Before diving into Graviton migration, you need Kiro CLI installed on your system.&lt;/p&gt;

&lt;p&gt;Before installing Kiro CLI, make sure you have unzip installed. &lt;/p&gt;

&lt;p&gt;For Ubuntu run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt install unzip -y
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the package manager for other Linux distributions or Homebrew on macOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Kiro CLI
&lt;/h3&gt;

&lt;p&gt;The fastest way to get Kiro CLI running is with a single curl command that handles the entire installation process. This method works seamlessly on both Arm Linux and macOS systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;curl -fsSL https://cli.kiro.dev/install | bash
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer will download the appropriate version for your system and prompt you about updating your shell configuration. &lt;/p&gt;

&lt;p&gt;If you're on macOS you can use Homebrew as an alternative installation option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;brew install kiro-cli
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verifying your installation
&lt;/h3&gt;

&lt;p&gt;Once the installation completes, confirm everything is working by checking the version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;kiro-cli version
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;kiro-cli 1.23.1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms Kiro CLI is properly installed and ready to use. The version number may be different depending on when you install it, but seeing any version output means you're good to proceed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker prerequisite
&lt;/h3&gt;

&lt;p&gt;You'll also need Docker running on your system since the Arm MCP server runs as a containerized service. If you don't have Docker installed yet, you can download it from the &lt;a href="https://www.docker.com/get-started/" rel="noopener noreferrer"&gt;Docker website&lt;/a&gt;. The Arm MCP server image will be pulled automatically during the configuration step, so you don't need to download anything manually right now.&lt;/p&gt;

&lt;p&gt;If you are running on Linux, you can use the simple install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;curl -fsSL get.docker.com -o get-docker.sh &amp;amp;&amp;amp; sh get-docker.sh
&lt;/span&gt;&lt;span class="gp"&gt;sudo usermod -aG docker $&lt;/span&gt;USER &lt;span class="p"&gt;;&lt;/span&gt; newgrp docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MCP server configuration
&lt;/h2&gt;

&lt;p&gt;Now that Kiro CLI is installed, you need to connect it to the Arm MCP server that provides the specialized knowledge and tools for Graviton migration. This server runs as a Docker container and integrates with Kiro CLI through a simple configuration file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Arm MCP server
&lt;/h3&gt;

&lt;p&gt;The Arm MCP server comes pre-packaged as a Docker image. Pull the latest version with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker pull armlimited/arm-mcp:latest
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This downloads the container image, which includes the Arm-specific knowledge base, migration tools, and compatibility databases you'll need for your Graviton migration projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the connection
&lt;/h3&gt;

&lt;p&gt;Kiro CLI connects to MCP servers through a configuration file that defines how to launch and communicate with each server. &lt;/p&gt;

&lt;p&gt;Create the configuration directory and file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;mkdir -p ~/.kiro/settings
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use an editor to create the MCP configuration file at &lt;code&gt;~/.kiro/settings/mcp.json&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arm_mcp_server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--rm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--pull=always"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/ubuntu:/workspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arm-mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"armlimited/arm-mcp:latest"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration tells Kiro CLI to launch the Arm MCP server using Docker with several important settings. The &lt;code&gt;--pull=always&lt;/code&gt; flag ensures you're always using the latest version of the server, while the volume mount (&lt;code&gt;-v /home/ubuntu:/workspace&lt;/code&gt;) gives the server access to your directory so it can analyze your codebase directly. You can modify the mounted directory for your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding volume mounting
&lt;/h3&gt;

&lt;p&gt;The volume mounting is important for migration work. When you run Kiro CLI from within a project directory, the Arm MCP server can examine your actual code files, Dockerfiles, dependency manifests, and build configurations. This enables it to provide specific recommendations about your codebase rather than general migration advice.&lt;/p&gt;

&lt;p&gt;For example, if you're working on a Node.js application and run Kiro CLI from your project root, the server can analyze your &lt;code&gt;package.json&lt;/code&gt; file to identify potentially problematic dependencies or suggest Arm-optimized alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification and connection testing
&lt;/h2&gt;

&lt;p&gt;With your configuration in place, it's time to verify that everything is working correctly. This verification process ensures both Kiro CLI and the Arm MCP server are properly connected and ready for your migration work.&lt;/p&gt;

&lt;p&gt;Start Kiro CLI to initiate the connection to the Arm MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;kiro-cli
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first startup may take a moment as Docker starts the container and initializes the connection. You'll see Kiro CLI's prompt once everything is ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠ 0 of 1 mcp servers initialized. Servers still loading:
 - arm_mcp_server
⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀     ⢀⣴⣶⣶⣦⡀⠀⠀⠀⢀⣴⣶⣦⣄⡀⠀⠀⢀⣴⣶⣶⣦⡀⠀⠀⢀⣴⣶⣶⣶⣶⣶⣶⣶⣶⣶⣦⣄⡀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣶⣶⣶⣶⣶⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀    ⢰⣿⠋⠁⠈⠙⣿⡆⠀⢀⣾⡿⠁⠀⠈⢻⡆⢰⣿⠋⠁⠈⠙⣿⡆⢰⣿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠻⣦⠀⠀⠀⠀⣴⡿⠟⠋⠁⠀⠀⠀⠈⠙⠻⢿⣦⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀    ⢸⣿⠀⠀⠀⠀⣿⣇⣴⡿⠋⠀⠀⠀⢀⣼⠇⢸⣿⠀⠀⠀⠀⣿⡇⢸⣿⠀⠀⠀⢠⣤⣤⣤⣤⣄⠀⠀⠀⠀⣿⡆⠀⠀⣼⡟⠀⠀⠀⠀⣀⣀⣀⠀⠀⠀⠀⢻⣧⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀    ⢸⣿⠀⠀⠀⠀⣿⡿⠋⠀⠀⠀⢀⣾⡿⠁⠀⢸⣿⠀⠀⠀⠀⣿⡇⢸⣿⠀⠀⠀⢸⣿⠉⠉⠉⣿⡇⠀⠀⠀⣿⡇⠀⣼⡟⠀⠀⠀⣰⡿⠟⠛⠻⢿⣆⠀⠀⠀⢻⣧⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀    ⢸⣿⠀⠀⠀⠀⠙⠁⠀⠀⢀⣼⡟⠁⠀⠀⠀⢸⣿⠀⠀⠀⠀⣿⡇⢸⣿⠀⠀⠀⢸⣿⣶⣶⡶⠋⠀⠀⠀⠀⣿⠇⢰⣿⠀⠀⠀⢰⣿⠀⠀⠀⠀⠀⣿⡆⠀⠀⠀⣿⡆
⠀⠀⠀⠀⠀⠀⠀    ⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠹⣷⡀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⣿⡇⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣼⠟⠀⢸⣿⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⣿⡇
⠀⠀⠀⠀⠀⠀⠀    ⢸⣿⠀⠀⠀⠀⠀⣠⡀⠀⠀⠹⣷⡄⠀⠀⠀⢸⣿⠀⠀⠀⠀⣿⡇⢸⣿⠀⠀⠀⠀⣤⣄⠀⠀⠀⠀⠹⣿⡅⠀⠀⠸⣿⠀⠀⠀⠸⣿⠀⠀⠀⠀⠀⣿⠇⠀⠀⠀⣿⠇
⠀⠀⠀⠀⠀⠀⠀    ⢸⣿⠀⠀⠀⠀⣾⡟⣷⡀⠀⠀⠘⣿⣆⠀⠀⢸⣿⠀⠀⠀⠀⣿⡇⢸⣿⠀⠀⠀⠀⣿⡟⣷⡀⠀⠀⠀⠘⣿⣆⠀⠀⢻⣧⠀⠀⠀⠹⣷⣦⣤⣤⣾⠏⠀⠀⠀⣼⡟
⠀⠀⠀⠀⠀⠀⠀    ⢸⣿⠀⠀⠀⠀⣿⡇⠹⣷⡀⠀⠀⠈⢻⡇⠀⢸⣿⠀⠀⠀⠀⣿⡇⢸⣿⠀⠀⠀⠀⣿⡇⠹⣷⡀⠀⠀⠀⠈⢻⡇⠀⠀⢻⣧⠀⠀⠀⠀⠉⠉⠉⠀⠀⠀⠀⣼⡟
⠀⠀⠀⠀⠀⠀⠀    ⠸⣿⣄⡀⢀⣠⣿⠇⠀⠙⣷⡀⠀⢀⣼⠇⠀⠸⣿⣄⡀⢀⣠⣿⠇⠸⣿⣄⡀⢀⣠⣿⠇⠀⠙⣷⡀⠀⠀⢀⣼⠇⠀⠀⠀⠻⣷⣦⣄⡀⠀⠀⠀⢀⣠⣴⣾⠟
⠀⠀⠀⠀⠀⠀⠀    ⠀⠈⠻⠿⠿⠟⠁⠀⠀⠀⠈⠻⠿⠿⠟⠁⠀⠀⠈⠻⠿⠿⠟⠁⠀⠀⠈⠻⠿⠿⠟⠁⠀⠀⠀⠈⠻⠿⠿⠟⠁⠀⠀⠀⠀⠀⠈⠙⠻⠿⠿⠿⠿⠟⠋⠁

╭─────────────────────────────── Did you know? ────────────────────────────────╮
│                                                                              │
│   If you want to file an issue to the Kiro CLI team, just tell me, or run    │
│                                kiro-cli issue                                │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯

Model: Auto (/model to change)


&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now verify the Arm MCP server connection by listing its available tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;/tools
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output listing the available MCP server tools. The exact tool names and descriptions may vary slightly depending on the version, but you should see several tools related to Arm migration and compatibility analysis.&lt;/p&gt;

&lt;p&gt;This output confirms that Kiro CLI has successfully connected to the Arm MCP server and can access all its migration tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowledge base exploration
&lt;/h2&gt;

&lt;p&gt;Now that you have Kiro CLI connected to the Arm MCP server, let's explore its knowledge capabilities through some migration scenarios. Rather than diving straight into code analysis, you'll start by asking the kinds of questions that come up during real migration planning sessions.&lt;/p&gt;

&lt;p&gt;With this setup, you can have natural conversations about technical topics. Instead of hunting through documentation or trying to piece together information from multiple sources, you ask your questions and get Arm-focused answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Graviton software porting considerations
&lt;/h3&gt;

&lt;p&gt;Let's start with a fundamental question that every migration project faces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;What are the key software porting considerations when migrating applications to AWS Graviton processors?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Arm MCP server provides a detailed response covering the essential areas you need to evaluate. The response includes guidance on dependency compatibility, performance optimization opportunities, and common migration patterns. You'll receive specific recommendations about compiler flags, library alternatives, and testing strategies that apply directly to your Graviton migration project.&lt;/p&gt;

&lt;p&gt;This response demonstrates the MCP server's understanding of migration challenges and provides actionable guidance you can immediately apply to your projects. Notice how it covers both technical requirements and practical implementation considerations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking software compatibility
&lt;/h3&gt;

&lt;p&gt;You can also ask about specific software and check if it's available on Graviton. &lt;/p&gt;

&lt;p&gt;For teams working with Microsoft technologies, .NET compatibility is often a primary concern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;What versions of .NET are compatible with AWS Graviton processors, and are there any specific considerations for .NET applications?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server provides specific version information and migration guidance. You'll receive details about .NET 6 and later versions' native Arm64 support, performance optimization recommendations, and guidance on handling dependencies that may need attention during migration. You can even ask for a recommended version and find out that it may be better to go with .NET 8 because it has a longer support window compared to .NET 9.&lt;/p&gt;

&lt;p&gt;This level of detail helps you make informed decisions about software versions. &lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Aperf installation guidance
&lt;/h3&gt;

&lt;p&gt;For performance analysis and optimization work, you might need specialized tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;How do I install and use Aperf for performance analysis on AWS Graviton instances?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server provides installation and usage guidance. You'll receive step-by-step installation instructions and configuration recommendations on Graviton instances.&lt;/p&gt;

&lt;p&gt;These three examples show the breadth and depth of knowledge available through the Arm MCP server. Whether you're planning a migration, troubleshooting compatibility issues, or optimizing performance, you have access to a knowledge base tailored for Arm and Graviton environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced migration tools
&lt;/h2&gt;

&lt;p&gt;Beyond answering migration questions, the Arm MCP server provides tools that analyze your actual codebase and infrastructure configurations. These capabilities transform abstract migration advice into concrete, actionable recommendations specific to your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dockerfile analysis
&lt;/h3&gt;

&lt;p&gt;One of the most useful tools for containerized applications is the Dockerfile compatibility checker. Instead of manually reviewing your container configurations for Arm compatibility issues, you can get automated analysis with specific recommendations.&lt;/p&gt;

&lt;p&gt;When you have a Dockerfile in your current project directory, you can ask the MCP server to analyze it for potential Arm compatibility issues. The server examines your Dockerfile and provides detailed feedback about base image compatibility, identifies potential problems like x86-specific binaries or native libraries, and suggests optimization opportunities for multi-architecture builds.&lt;/p&gt;

&lt;p&gt;This analysis saves time and provides specific line-by-line guidance. The MCP server understands common patterns that cause Arm compatibility issues and suggests practical solutions that fit into existing development workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  x86-specific dependencies
&lt;/h3&gt;

&lt;p&gt;For applications with complex dependency trees, the server can scan your codebase to identify potentially problematic x86-specific dependencies before you encounter runtime issues.&lt;/p&gt;

&lt;p&gt;The server can analyze your project files and dependency manifests to identify compatibility concerns across your entire technology stack. It examines package files, build configurations, and scripts to flag dependencies that may need attention before moving to Graviton. The analysis provides specific version recommendations and alternative packages, along with estimated migration effort, making the migration process more predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You've learned how Kiro CLI paired with the Arm MCP server transforms AWS Graviton migration into a guided conversation that makes it easier to get started. &lt;/p&gt;

&lt;p&gt;The setup you've completed gives you access to migration knowledge, from high-level architectural considerations to specific dependency compatibility issues. The automated tools for Dockerfile analysis and x86 dependency detection catch potential problems before they impact your deployment timeline, while the knowledge base provides context and solutions for the challenges you'll encounter.&lt;/p&gt;

&lt;p&gt;The combination of conversational AI assistance and analysis tools represents a shift in how migration projects can be approached. You can now iterate quickly, validate assumptions immediately, and make informed decisions with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started with AWS T4g instances
&lt;/h2&gt;

&lt;p&gt;AWS T4g instances powered by Graviton processors are available in the AWS Free Tier through December 31, 2026. This gives you an extended opportunity to test your applications, validate performance improvements, and gain hands-on experience with Graviton without incurring costs.&lt;/p&gt;

&lt;p&gt;The free tier includes 750 hours per month of t4g.micro instances, providing ample time to experiment with your migration workflow and validate the guidance you receive from the Arm MCP server. You can use this to test containerized applications, benchmark performance differences, and refine your migration approach before committing to production deployments.&lt;/p&gt;

&lt;p&gt;For complete details about T4g instance specifications and free tier eligibility, visit the &lt;a href="https://aws.amazon.com/ec2/instance-types/t4/" rel="noopener noreferrer"&gt;AWS T4g instances page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ready to dive deeper into Arm development and migration capabilities? The Arm MCP server offers additional tools and knowledge bases that can accelerate your Graviton adoption journey. Explore the &lt;a href="https://developer.arm.com/servers-and-cloud-computing/arm-mcp-server" rel="noopener noreferrer"&gt;documentation, examples, and features&lt;/a&gt; to continue learning.&lt;/p&gt;

</description>
      <category>kiro</category>
      <category>aws</category>
      <category>arm</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Improve Performance with 64K Memory Pages on AWS Graviton Processors</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Fri, 28 Nov 2025 03:38:02 +0000</pubDate>
      <link>https://forem.com/aws-builders/improve-performance-with-64k-memory-pages-on-aws-graviton-processors-ifa</link>
      <guid>https://forem.com/aws-builders/improve-performance-with-64k-memory-pages-on-aws-graviton-processors-ifa</guid>
      <description>&lt;p&gt;If you're running memory intensive workloads on AWS Graviton processors, you may want to investigate 64K pages. One commonly overlooked optimization is switching from the default 4K memory pages to 64K pages. This kernel configuration change can reduce memory management overhead and improve performance for some workloads.&lt;/p&gt;

&lt;p&gt;This article explains what memory pages are and shows how to switch between 4K and 64K pages on Ubuntu 24.04.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Memory Pages?
&lt;/h2&gt;

&lt;p&gt;Memory pages are the standardized containers used to organize and move data around. The operating system and the CPU's Memory Management Unit (MMU) use a page table to track which virtual memory addresses map to physical RAM locations. This is how operating systems like Linux provide virtual memory that is larger than the physical memory of the system. &lt;/p&gt;

&lt;p&gt;To speed up these lookups, CPUs use a fast cache called a Translation Lookaside Buffer (TLB). Every memory access first checks the TLB. If the mapping isn't there (a TLB miss), the CPU must perform a "page table walk" to fetch it from main memory, which can involve multiple memory accesses and add latency.&lt;/p&gt;

&lt;p&gt;On x86 systems, 4K pages are standard. AWS Graviton processors support multiple page sizes. The Arm architecture supports 4K, 16K, and 64K pages, but Linux distributions typically support 4k and 64k.  This flexibility lets you optimize for your specific workload.&lt;/p&gt;

&lt;p&gt;NOTE: If you want to try 16K pages you can run &lt;a href="https://asahilinux.org/" rel="noopener noreferrer"&gt;Asahi Linux&lt;/a&gt; on Apple Silicon.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Performance Impact of Page Size
&lt;/h2&gt;

&lt;p&gt;Changing page size creates a cascading effect on system performance:&lt;/p&gt;

&lt;p&gt;With 4K pages, you need more TLB entries to map the same amount of memory. This increases TLB misses and page-table-walk overhead. With 64K pages, each TLB entry covers 16x more memory, which reduces TLB pressure and can improve TLB hit rates.&lt;/p&gt;

&lt;p&gt;Disk I/O and DMA operations often perform better with larger pages because fewer page boundaries are crossed during transfers. This means fewer interrupts and larger DMA bursts.&lt;/p&gt;

&lt;p&gt;The kernel's page management structures scale with the number of pages. Fewer pages mean less memory spent on bookkeeping.&lt;/p&gt;

&lt;p&gt;The drawback of larger pages is that for small, varied allocation patterns, more memory is consumed. This is known as internal fragmentation. For example, if a 2KB process is allocated a 64K page, 62KB of that page's memory is wasted.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note on Huge Pages vs. Base Page Size
&lt;/h2&gt;

&lt;p&gt;It's important to distinguish the 64K page size on Arm from the "Transparent Huge Pages" (THP) feature in Linux. THP is a system that tries to dynamically allocate large 2MB pages on top of a standard 4K base page size. The 64K page support on Graviton changes the &lt;em&gt;base&lt;/em&gt; page size for all memory management, which is a fundamental, system-wide setting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Workloads Benefit from 64K Pages?
&lt;/h2&gt;

&lt;p&gt;64K pages are most effective for applications that work with large, contiguous memory regions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Databases&lt;/strong&gt;: Large buffer pools and cache systems (PostgreSQL, MySQL, Redis)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big Data Processing&lt;/strong&gt;: Spark, Hadoop, and data analytics workloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine Learning&lt;/strong&gt;: Training and inference with large datasets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video Processing&lt;/strong&gt;: Encoding, transcoding, and streaming applications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Performance Computing&lt;/strong&gt;: Scientific simulations and numerical computing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-Memory Caching&lt;/strong&gt;: Memcached, Redis with large datasets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conversely, stick with 4K pages for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web servers handling many small requests&lt;/li&gt;
&lt;li&gt;Microservices with small memory footprints&lt;/li&gt;
&lt;li&gt;Applications with highly fragmented memory access patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Switch to 64K Pages on AWS Graviton
&lt;/h2&gt;

&lt;p&gt;You can experiment with 64K pages in a non-production environment to see if they help your applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ubuntu 24.04 on AWS Graviton
&lt;/h3&gt;

&lt;p&gt;Ubuntu makes this easy with a pre-built 64K kernel package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Check your current page size&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;getconf PAGESIZE
&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4096
6.14.0-1016-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Install the 64K kernel&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; linux-generic-64k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Configure GRUB to use the 64K kernel by default&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"GRUB_FLAVOUR_ORDER=generic-64k"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/default/grub.d/local-order.cfg
&lt;span class="nb"&gt;sudo &lt;/span&gt;update-grub
&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Verify the change&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After reboot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;getconf PAGESIZE
&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;65536
6.8.0-48-generic-64k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;To revert to 4K pages:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"GRUB_FLAVOUR_ORDER=generic"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/default/grub.d/local-order.cfg
&lt;span class="nb"&gt;sudo &lt;/span&gt;update-grub
&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find instructions for more Linux distributions in the Arm Learning Path &lt;a href="https://learn.arm.com/learning-paths/servers-and-cloud-computing/arm_linux_page_size/" rel="noopener noreferrer"&gt;Explore performance gains by increasing the Linux kernel page size on Arm&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring the Impact
&lt;/h2&gt;

&lt;p&gt;After switching to 64K pages, benchmark your application to measure the impact. Key metrics to monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TLB miss rate&lt;/strong&gt;: Use &lt;code&gt;perf stat&lt;/code&gt; to measure TLB misses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application throughput&lt;/strong&gt;: Measure requests/second or transactions/second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt;: Monitor p50, p95, and p99 latencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory usage&lt;/strong&gt;: Check for any increase in memory consumption&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance Gains
&lt;/h2&gt;

&lt;p&gt;Performance gains depend on the specific workload characteristics, but the potential gains make this optimization worth testing for suitable workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AWS Graviton processors offer optimization opportunities not available on x86 systems. Switching to 64K memory pages is a kernel change that can deliver performance improvements for memory-intensive workloads without making any code changes.&lt;/p&gt;

&lt;p&gt;It is important to understand your workload characteristics and test thoroughly. If you're working with large datasets, databases, or high-throughput applications on AWS Graviton, testing 64K pages is recommended.&lt;/p&gt;

&lt;p&gt;If you are running AWS Graviton instances, make sure to check out the &lt;a href="https://github.com/aws/aws-graviton-getting-started" rel="noopener noreferrer"&gt;AWS Graviton Technical Guide&lt;/a&gt; for more optimization tips.&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>linux</category>
      <category>performance</category>
      <category>aws</category>
    </item>
    <item>
      <title>Create and run Windows on Arm virtual machines on AWS Graviton processors using QEMU and KVM</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Tue, 11 Nov 2025 15:18:44 +0000</pubDate>
      <link>https://forem.com/aws-builders/create-and-run-windows-on-arm-virtual-machines-on-aws-graviton-processors-using-qemu-and-kvm-310j</link>
      <guid>https://forem.com/aws-builders/create-and-run-windows-on-arm-virtual-machines-on-aws-graviton-processors-using-qemu-and-kvm-310j</guid>
      <description>&lt;p&gt;Windows application developers are currently adding support for the Arm architecture because they want to enable native app performance on new Windows on Arm Copilot+ PCs. &lt;/p&gt;

&lt;p&gt;If you are looking for ways to build and test Windows on Arm software, you have several options to choose from.  You can run Windows on Arm on a laptop, you can use cloud-based virtual machines, or you can leverage CI/CD platforms like GitHub Actions to access Windows on Arm. &lt;/p&gt;

&lt;p&gt;Another option is to create Windows on Arm virtual machines directly on Amazon EC2 instances running AWS Graviton processors. &lt;/p&gt;

&lt;p&gt;Read on to find out how to install and run Windows on Arm virtual machines on a Graviton-based EC2 instance. I have created two bash scripts to streamline the creation and management of your virtual machines. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare your system for Windows on Arm virtual machines
&lt;/h2&gt;

&lt;p&gt;Here are the steps you can use to run Windows on Arm on an Amazon EC2 instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an EC2 instance with AWS Graviton processors&lt;/li&gt;
&lt;li&gt;Install and configure VNC&lt;/li&gt;
&lt;li&gt;Confirm KVM is available&lt;/li&gt;
&lt;li&gt;Install software dependencies&lt;/li&gt;
&lt;li&gt;Create a Windows virtual machine&lt;/li&gt;
&lt;li&gt;Run a Windows virtual machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end, you will have a functional Windows desktop accessible using a VNC client from your local computer. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create a bare-metal EC2 instance
&lt;/h2&gt;

&lt;p&gt;You can use Graviton2, Graviton3, or Graviton4 processors. Graviton2 performance is sufficient for most Windows development. Use Graviton3 or Graviton4 if you want faster performance and features such as SVE2 (scalable vector extension), BFloat16 (16-bit floating point), and I8MM (8-bit integer multiplication).&lt;/p&gt;

&lt;p&gt;In your AWS account, create a &lt;code&gt;c6g.metal&lt;/code&gt; instance type and set up SSH connectivity running Ubuntu 24.04. Make sure to use at least 128 GB of storage to allow for virtual machine disk images. Each instance of Windows requires approximately 40 GB of storage. You can also use other bare-metal instances such as &lt;code&gt;m6g.metal&lt;/code&gt; and &lt;code&gt;r6g.metal&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To create the instance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch a new EC2 instance from the AWS Console&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Ubuntu Server 24.04 LTS&lt;/strong&gt; as the AMI (make sure to select the Arm version)&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;c6g.metal&lt;/code&gt; as the instance type&lt;/li&gt;
&lt;li&gt;Configure a security group that allows SSH (port 22) from your IP address&lt;/li&gt;
&lt;li&gt;Create or select an existing SSH key pair for authentication&lt;/li&gt;
&lt;li&gt;In storage settings, allocate at least 128 GB for the root volume&lt;/li&gt;
&lt;li&gt;Launch the instance and wait for it to enter the "running" state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Make sure you can SSH to the instance using your SSH key. &lt;/p&gt;

&lt;p&gt;Confirm that you can access your instance and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt update
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are now ready to get started installing software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install and configure VNC
&lt;/h2&gt;

&lt;p&gt;Virtual Network Computing (VNC) is a tool used to connect to a remote Linux desktop. Running Windows requires a desktop environment to see the installation process and to interact with the Windows desktop.&lt;/p&gt;

&lt;p&gt;You can install VNC on your EC2 instance. VNC is a client-server application. A VNC server runs on a remote machine (the EC2 instance). A VNC client runs on the local machine (your laptop) and connects to the remote server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the VNC server and xfce4 desktop
&lt;/h3&gt;

&lt;p&gt;To use VNC, you need to install a VNC server on your EC2 instance. There are multiple VNC servers, one good option is &lt;a href="https://tigervnc.org/" rel="noopener noreferrer"&gt;TigerVNC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You also need Linux desktop software. There are many options for this, but using &lt;a href="https://www.xfce.org/" rel="noopener noreferrer"&gt;xfce4&lt;/a&gt; provides a minimal install with good performance.&lt;/p&gt;

&lt;p&gt;Install the desktop software:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt-get install xfce4 xfce4-goodies xorg dbus-x11 x11-xserver-utils xfce4-terminal -y
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the VNC server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt-get install tigervnc-standalone-server tigervnc-common -y
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure a VNC password
&lt;/h3&gt;

&lt;p&gt;Run the &lt;code&gt;vncpasswd&lt;/code&gt; command to set a password for VNC. This is not the password for your user account, but for the VNC client to connect to the VNC server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;vncpasswd
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember the password for later when you connect the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure the desktop startup for VNC
&lt;/h3&gt;

&lt;p&gt;Use a text editor to create a file named &lt;code&gt;$HOME/.vnc/xstartup&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;/bin/sh
&lt;span class="go"&gt;unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
exec startxfce4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give the file executable permission:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;chmod +x $&lt;/span&gt;HOME/.vnc/xstartup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set up a systemd service to manage VNC
&lt;/h3&gt;

&lt;p&gt;To create a systemd service to start the VNC server, create the file &lt;code&gt;/etc/systemd/system/vncserver@.service&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;sudo&lt;/code&gt; or root privileges because this file is in a system directory.&lt;/p&gt;

&lt;p&gt;Your username should be &lt;code&gt;ubuntu&lt;/code&gt;, but if it is not, change the &lt;code&gt;User&lt;/code&gt; value to match your username after you create the new file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Remote desktop service (VNC)&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;syslog.target network.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="py"&gt;PAMName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;login&lt;/span&gt;
&lt;span class="py"&gt;PIDFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/%u/.vnc/%H%i.pid&lt;/span&gt;
&lt;span class="py"&gt;ExecStartPre&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/bin/sh -c '/usr/bin/vncserver -kill :%i &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 || : '&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/vncserver :%i -localhost no -geometry 1440x900 -alwaysshared -fg&lt;/span&gt;
&lt;span class="py"&gt;ExecStop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/vncserver -kill :%i&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start the VNC service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo systemctl start vncserver@1.service
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To stop the VNC service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo systemctl stop vncserver@1.service
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To restart the VNC service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo systemctl restart vncserver@1.service
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use port forwarding via SSH to connect to VNC
&lt;/h3&gt;

&lt;p&gt;The default port for the first instance of VNC is &lt;code&gt;5901&lt;/code&gt;. SSH port forwarding is a good solution for accessing the Linux desktop on a cloud machine. This way, no additional ports need to be opened in the security group.&lt;/p&gt;

&lt;p&gt;SSH to your remote Linux machine. &lt;/p&gt;

&lt;p&gt;Substitute your private key file and the public IP address of the remote machine in the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;ssh -i &amp;lt;private_key&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-L&lt;/span&gt; 5901:localhost:5901 ubuntu@&amp;lt;public_ip_address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once connected via SSH, use a VNC client to connect. &lt;a href="https://sourceforge.net/projects/tigervnc/files/stable/" rel="noopener noreferrer"&gt;Download&lt;/a&gt; and install a TigerVNC client for your computer.&lt;/p&gt;

&lt;p&gt;Open the VNC client and enter the following for the VNC server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;localhost:5901
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be prompted for the password you created earlier with &lt;code&gt;vncpasswd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A remote Linux desktop should appear on your local computer. When you are finished, close the VNC client first and then exit the SSH connection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0pxeiqrir50in6ihjh6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0pxeiqrir50in6ihjh6.png" alt=" " width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install other software dependencies
&lt;/h2&gt;

&lt;p&gt;Next, install the software you need to create a Windows on Arm virtual machine using QEMU and KVM. Before installing the software, confirm KVM is available on your EC2 instance. A bare-metal Graviton instance is used so that KVM is available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify KVM support
&lt;/h2&gt;

&lt;p&gt;Kernel-based Virtual Machine (KVM) support is required for hardware-accelerated virtualization and optimal virtual machine (VM) performance on Arm systems. Without KVM, your VMs run significantly slower because they rely on software emulation instead of using Arm's hardware virtualization features.&lt;/p&gt;

&lt;p&gt;KVM is a virtualization infrastructure built into the Linux kernel that allows you to run virtual machines with near-native performance. It leverages Arm's hardware virtualization extensions to provide efficient CPU virtualization, while QEMU handles device emulation and management.&lt;/p&gt;

&lt;p&gt;Verify your system supports KVM by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt install cpu-checker -y
kvm-ok
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If KVM is available, you will see the messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO: /dev/kvm exists
KVM acceleration can be used
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your CPU supports hardware virtualization&lt;/li&gt;
&lt;li&gt;The KVM kernel module is loaded&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;/dev/kvm&lt;/code&gt; device exists &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add your user account to the KVM group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;sudo usermod -a -G kvm $&lt;/span&gt;USER
&lt;span class="go"&gt;newgrp kvm
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install required software
&lt;/h3&gt;

&lt;p&gt;The Windows on Arm scripts require several software packages. &lt;/p&gt;

&lt;p&gt;Install the packages using the Linux package manager, including QEMU and Remmina, the remote desktop software used to connect to Windows VMs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt update
sudo apt install qemu-system-arm qemu-utils genisoimage wget curl jq uuid-runtime seabios remmina remmina-plugin-rdp  -y
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have the required software to create a Windows on Arm virtual machine on your EC2 instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started with the Windows on Arm VM automation scripts
&lt;/h2&gt;

&lt;p&gt;A GitHub project provides two Bash scripts. &lt;/p&gt;

&lt;p&gt;Start by cloning the project repository from GitHub to your Arm Linux system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;git clone https://github.com/jasonrandrews/win11arm.git
cd win11arm
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project includes two Bash scripts. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VM create script: &lt;code&gt;create-win11-vm.sh&lt;/code&gt; handles all VM creation tasks&lt;/li&gt;
&lt;li&gt;VM run script: &lt;code&gt;run-win11-vm.sh&lt;/code&gt; manages VM execution and connectivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All configuration is available using command-line options. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new Windows virtual machine
&lt;/h2&gt;

&lt;p&gt;To create a new VM, run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;./create-win11-vm.sh all $&lt;/span&gt;HOME/win11-vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single command executes all required virtual machine creation steps as explained in the previous section.&lt;/p&gt;

&lt;p&gt;The VM data is stored in the &lt;code&gt;$HOME/win11-vm&lt;/code&gt; directory, and Windows will install automatically without any user intervention.&lt;/p&gt;

&lt;p&gt;The product key used in the scripts is a generic key provided by Microsoft, which allows installation. This key is for testing purposes only and does not activate Windows. If you plan to continue using Windows beyond installation, you should replace it with a genuine product key.&lt;/p&gt;

&lt;p&gt;Once the VM creation is complete, you'll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;QEMU closed successfully.
Windows installation should be complete!
You can now use: ./run-win11-vm.sh $HOME/win11-vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Windows on Arm VM is now ready to use. &lt;/p&gt;

&lt;h2&gt;
  
  
  Run your newly created Windows 11 virtual machine
&lt;/h2&gt;

&lt;p&gt;After your Windows 11 Arm VM is created, launching it is simple with the unified run script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;./run-win11-vm.sh $&lt;/span&gt;HOME/win11-vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single command handles the entire VM startup and connection process automatically. &lt;/p&gt;

&lt;p&gt;The script performs three key steps. It does the following: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks if the VM is already running&lt;/li&gt;
&lt;li&gt;Starts the VM in headless mode if required&lt;/li&gt;
&lt;li&gt;Connects you through RDP using Remmina&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the virtual machine starts you will see it on your Linux desktop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjwjaii9ewpc5hvznu6h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjwjaii9ewpc5hvznu6h0.png" alt=" " width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You now have a running Windows on Arm virtual machine running on an AWS Graviton-based EC2 instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  VM shutdown
&lt;/h2&gt;

&lt;p&gt;The preferred method is to shut down Windows normally from within the virtual machine.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the Start button in Windows&lt;/li&gt;
&lt;li&gt;Select Power → Shut down&lt;/li&gt;
&lt;li&gt;Wait for Windows to complete shutdown&lt;/li&gt;
&lt;li&gt;The VM automatically stops when Windows finishes shutting down&lt;/li&gt;
&lt;li&gt;Remmina exits automatically when the connection closes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should avoid killing QEMU directly, as it may corrupt the VM disk. Also, avoid exiting Remmina prematurely, as it may leave the VM running in the background.&lt;/p&gt;

&lt;p&gt;More details about command-line arguments and how the scripts work are available in &lt;a href="https://learn.arm.com/learning-paths/laptops-and-desktops/win11-vm-automation/" rel="noopener noreferrer"&gt;Automate Windows on Arm virtual machine deployment with QEMU and KVM on Arm Linux&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
      <category>microsoft</category>
      <category>arm</category>
    </item>
    <item>
      <title>Use the Amazon Q Developer CLI on AWS Graviton</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Sat, 05 Apr 2025 16:10:16 +0000</pubDate>
      <link>https://forem.com/aws-builders/use-the-amazon-q-developer-cli-on-aws-graviton-oe</link>
      <guid>https://forem.com/aws-builders/use-the-amazon-q-developer-cli-on-aws-graviton-oe</guid>
      <description>&lt;p&gt;Amazon Q Developer CLI is a command-line tool for Amazon Q, a generative AI-powered assistant. You can use it to ask questions about AWS architecture, resources, and general development tasks. &lt;/p&gt;

&lt;p&gt;It supports multiple operating systems, including Arm-based Linux distributions, and runs on AWS Graviton processors.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should I do before installing Amazon Q Developer CLI?
&lt;/h2&gt;

&lt;p&gt;You need a Builder ID to use the Amazon Q Developer CLI. If you don't have one, visit &lt;a href="https://community.aws/builderid" rel="noopener noreferrer"&gt;Do more with AWS Builder ID&lt;/a&gt; and click &lt;strong&gt;Sign up with Builder ID&lt;/strong&gt; to create your AWS Builder ID. &lt;/p&gt;

&lt;p&gt;This guide explains how to install Amazon Q Developer CLI on macOS and Arm Linux distributions, such as Ubuntu and Amazon Linux 2023.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I download and install Amazon Q Developer CLI?
&lt;/h2&gt;

&lt;p&gt;The CLI is invoked using the &lt;code&gt;q&lt;/code&gt; command. &lt;/p&gt;

&lt;h3&gt;
  
  
  How do I install Amazon Q Developer CLI on macOS?
&lt;/h3&gt;

&lt;p&gt;Install &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; if it's not already available on your computer.&lt;/p&gt;

&lt;p&gt;Then install the Q CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;brew install amazon-q
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How do I install the Q CLI on Arm Linux?
&lt;/h3&gt;

&lt;p&gt;The easiest way to install the Q CLI on any Arm Linux distribution is to download and run the installer. &lt;/p&gt;

&lt;p&gt;Before starting, ensure that &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;unzip&lt;/code&gt; are available on your computer. &lt;/p&gt;

&lt;p&gt;For Debian-based distributions such as Ubuntu, use the commands below. For other Linux distributions, use the appropriate package manager to install &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;unzip&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt update
sudo apt install curl unzip -y
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Download the zip file with &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;curl --proto '=https' --tlsv1.2 -sSf "https://desktop-release.codewhisperer.us-east-1.amazonaws.com/latest/q-aarch64-linux.zip" -o "q.zip"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract the installer and run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;unzip q.zip
bash ./q/install.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll then be prompted about updating your shell config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;✔ Do you want q to modify your shell config (you will have to manually do this otherwise)? 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To automate the install, add the &lt;code&gt;--no-confirm&lt;/code&gt; flag to the &lt;code&gt;install.sh&lt;/code&gt; command. &lt;/p&gt;

&lt;p&gt;If you're using a Linux distribution with an older version of the GNU C Library - or one that does not use it at all, such as Alpine - you can download an alternative package built with the musl C library and has no external dependencies. &lt;/p&gt;

&lt;p&gt;Substitute the &lt;code&gt;curl&lt;/code&gt; command above with this one and use the same install instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;curl "https://desktop-release.codewhisperer.us-east-1.amazonaws.com/latest/q-aarch64-linux-musl.zip" -o "q.zip"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How do I confirm the Q CLI is working?
&lt;/h3&gt;

&lt;p&gt;You now have the latest version of the Amazon Q Developer CLI installed. &lt;/p&gt;

&lt;p&gt;Confirm the CLI is available by invoking the &lt;code&gt;q&lt;/code&gt; command to print the version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;q version
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The version is printed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;q 1.7.2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How can I configure my AWS account to get the most from the Q CLI?
&lt;/h2&gt;

&lt;p&gt;The Q CLI can answer questions and solve problems related to your AWS resources and help you develop faster on AWS. To get the maximum benefit, you can configure the AWS CLI to use your account. &lt;/p&gt;

&lt;p&gt;Follow the &lt;a href="http://learn.arm.com/install-guides/aws_access_keys/" rel="noopener noreferrer"&gt;AWS CLI Install Guide&lt;/a&gt; and the &lt;a href="http://learn.arm.com/install-guides/aws_access_keys/" rel="noopener noreferrer"&gt;AWS Credentials Install Guide&lt;/a&gt; to set up the AWS CLI and generate and configure access keys. &lt;/p&gt;

&lt;p&gt;This allows you to use the Amazon Q Developer CLI to ask questions and solve issues specific to your AWS account. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is an example of using the Q CLI?
&lt;/h2&gt;

&lt;p&gt;You can use &lt;code&gt;q chat&lt;/code&gt; to find information about your AWS resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;q chat
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the chat session starts you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Hi, I'm Amazon Q. Ask me anything.

Things to try
• Fix the build failures in this project.
• List my s3 buckets in us-west-2.
• Write unit tests for my application.
• Help me understand my git status

/acceptall    Toggles acceptance prompting for the session.
/profile      (Beta) Manage profiles for the chat session
/context      (Beta) Manage context files for a profile
/help         Show the help dialogue
/quit         Quit the application
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, you can ask for the IP address of an EC2 instance instead of going to the AWS console or looking up the AWS CLI command to get it. &lt;/p&gt;

&lt;p&gt;An example is shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmynl810bbcjt3iwnmwq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmynl810bbcjt3iwnmwq.gif" alt="Image description" width="946" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I set the Q CLI context to tailor responses?
&lt;/h2&gt;

&lt;p&gt;The Q CLI reads your context when you start it. If you provide more information about yourself, you will get tailored responses that match your development environment.&lt;/p&gt;

&lt;p&gt;There are multiple options to store context.&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;/context&lt;/code&gt; command to see the possible locations to store your context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;/context show
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The help information is printed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current profile: default

global:
    .amazonq/rules/**/*.md
    README.md
    AmazonQ.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, you can create a new file to store your context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;mkdir -p ~/.amazonq/rules/context
&lt;/span&gt;&lt;span class="gp"&gt;echo "I am an Arm Linux developer. I prefer Ubuntu and other Debian based distributions. I don't use any x86 computers so please provide all information assuming I'm working on Arm Linux. Sometimes I use macOS and Windows on Arm, but please only provide information about these operating systems when I ask for it." &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/.amazonq/rules/context/context.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you invoke &lt;code&gt;q chat&lt;/code&gt; you can confirm your context information was read by asking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;did you read my context information?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response confirms the context file was read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Yes, I've read your context information. I understand that you're an Arm Linux developer who prefers 
Ubuntu and other Debian-based distributions. You don't use x86 computers, so I should provide 
information assuming you're working on Arm Linux. You sometimes use macOS and Windows on Arm, but I 
should only provide information about those operating systems when you specifically ask for it.

I'll keep this context in mind when answering your questions, focusing on Arm Linux-specific 
information and Debian-based distributions by default.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it a try by asking questions such as &lt;code&gt;how do I install the aws cli?&lt;/code&gt; and check that the answers match the provided context. &lt;/p&gt;

&lt;p&gt;You're ready to use the Q CLI. For more AWS content, check out &lt;a href="https://learn.arm.com/learning-paths/servers-and-cloud-computing/?cloud-service-providers=aws" rel="noopener noreferrer"&gt;Arm Learning Paths&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>arm</category>
      <category>ai</category>
      <category>linux</category>
    </item>
    <item>
      <title>Managed, self-hosted Arm runners for GitHub Actions using AWS Graviton Processors</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Thu, 19 Sep 2024 03:44:34 +0000</pubDate>
      <link>https://forem.com/aws-builders/managed-self-hosted-arm-runners-for-github-actions-using-aws-graviton-processors-5g94</link>
      <guid>https://forem.com/aws-builders/managed-self-hosted-arm-runners-for-github-actions-using-aws-graviton-processors-5g94</guid>
      <description>&lt;h2&gt;
  
  
  What is GitHub Actions?
&lt;/h2&gt;

&lt;p&gt;GitHub Actions is a popular CI/CD platform used to build, test, and deploy software directly from GitHub repositories. It supports a wide range of workflows, enabling you to define custom automation using YAML configuration files. With GitHub Actions, you can run workflows on various environments, including managed, self-hosted runners on cloud-based virtual machines like Amazon EC2. &lt;/p&gt;

&lt;p&gt;Increasingly, software is being migrated to and developed on the Arm architecture. Managed, self-hosted Arm runners for Amazon EC2 using AWS Graviton processors is a great way to use GitHub Actions on Arm.&lt;/p&gt;

&lt;p&gt;The three primary benefits of GitHub Actions on managed, self-hosted runners are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native performance: Execute build and test cycles directly on AWS Graviton processors. This eliminates the complexities associated with instruction emulation and cross-compilation.&lt;/li&gt;
&lt;li&gt;Integrated Workflow: Experience a seamless integration within the familiar GitHub Actions environment without complexity infrastructure management. &lt;/li&gt;
&lt;li&gt;Cost-effectiveness: Enjoy the convenience of GitHub Actions combined with the ability to select specific Graviton-based EC2 instance types for best price performance. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are interested in GitHub Actions on AWS Graviton processors, you can install RunOn, a self-hosted runner manager in your AWS account. &lt;/p&gt;

&lt;p&gt;To do this, you will need an AWS account and a GitHub personal or organization account. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is RunsOn for GitHub Actions?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://runs-on.com" rel="noopener noreferrer"&gt;RunsOn&lt;/a&gt; is a self-hosted runner manager for GitHub Actions that you can install in your own AWS account. It will automatically spawn EC2 VMs as self-hosted runners for your GitHub Actions workflows.&lt;/p&gt;

&lt;p&gt;Runners are launched in less than 30 seconds, and you can select any of the instance types offered by AWS, including Arm instances with AWS Graviton processors. With Graviton processors, you can run GitHub Actions on Neoverse N1, Neoverse V1, and Neoverse V2 processors.&lt;/p&gt;

&lt;p&gt;RunsOn is free for non-commercial projects. For commercial projects, a 15-day demo license is available (see &lt;a href="https://runs-on.com/pricing/" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  What do I need to use RunsOn in my AWS account?
&lt;/h2&gt;

&lt;p&gt;You need the following to install RunsOn in your AWS account: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The name of your GitHub organization. If you are using a personal account, this is your GitHub username.&lt;/li&gt;
&lt;li&gt;A license key. This is a string you obtain from RunsOn by e-mail.&lt;/li&gt;
&lt;li&gt;An e-mail address you want to use to receive notifications from RunsOn.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do I install RunsOn?
&lt;/h2&gt;

&lt;p&gt;Follow this three-step process to install RunsOn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect to your AWS account: &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use your AWS credentials to log in to the AWS console for the account where you would like to set up RunsOn.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create the CloudFormation stack and GitHub app for RunsOn by following the official &lt;a href="https://runs-on.com/guides/install/" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The installation guide has a link at the top to obtain the license key. &lt;/p&gt;

&lt;p&gt;Once you have your key, proceed with the installation guide by selecting the AWS region you would like to use, creating the CloudFormation stack, and installing the GitHub app. &lt;/p&gt;

&lt;p&gt;The installation process takes about 10 minutes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At the end of the installation, follow the link to the deployed App Runner service endpoint, and you should see a page indicating that your installation is successful. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point you can start using RunsOn to spawn runners for your GitHub Actions workflows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3t1y3rreiq3jga40hju.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3t1y3rreiq3jga40hju.jpg" alt="RunsOn success page" width="676" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I execute GitHub Actions workflows?
&lt;/h2&gt;

&lt;p&gt;After installing RunsOn, you can execute jobs on Arm-based runners by modifying your GitHub Actions workflow files.&lt;/p&gt;

&lt;p&gt;If you have existing GitHub Actions workflow files, you can simply change the &lt;code&gt;runs-on&lt;/code&gt; setting.&lt;/p&gt;

&lt;p&gt;For example, if you have a workflow file with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  runs-on: ubuntu-22.04
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can change the &lt;code&gt;runs-on&lt;/code&gt; value as shown below to invoke a new runner in your AWS account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  runs-on:
    - runs-on
    - runner=1cpu-linux-arm64
    - run-id=${{ github.run_id }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runner is now a Graviton-based EC2 instance with 1 vCPU running Ubuntu 22.04.&lt;/p&gt;

&lt;p&gt;After about 30 seconds, you will see the job running on an Arm-based runner from your AWS account. The EC2 instance will be created, used, and terminated so you only pay for the time the workflow was running.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I specify other EC2 instance types?
&lt;/h3&gt;

&lt;p&gt;You can also select other instance types, such as Graviton3 or Graviton4, by using the &lt;code&gt;family&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;runs-on&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;runner=2cpu-linux-arm64&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;family=r8g&lt;/span&gt; &lt;span class="c1"&gt;# Graviton4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run-id=${{ github.run_id }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can learn more about the supported Linux runners in the &lt;a href="https://runs-on.com/runners/linux/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you would like to further customize the CPU count, RAM, disk sizes, and more, you can review the &lt;a href="https://runs-on.com/configuration/job-labels/" rel="noopener noreferrer"&gt;job labels&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you show me a complete GitHub Actions example using RunsOn?
&lt;/h2&gt;

&lt;p&gt;If you don't have existing workflow files or want to try RunsOn by creating a new repository, you can run the commands below at a shell prompt. You will need Git (&lt;code&gt;git&lt;/code&gt;) and the GitHub CLI (&lt;code&gt;gh&lt;/code&gt;) installed. Refer to the &lt;a href="https://cli.github.com/" rel="noopener noreferrer"&gt;GitHub CLI installation instructions&lt;/a&gt; if you don't have the &lt;code&gt;gh&lt;/code&gt; command installed.&lt;/p&gt;

&lt;p&gt;Create a new directory for the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;mkdir actions-test ;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;actions-test
&lt;span class="go"&gt;git init
mkdir -p .github/workflows
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a text editor to save the workflow file below as a file named &lt;code&gt;test.yml&lt;/code&gt; in the &lt;code&gt;.github/workflows/&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;      
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;runs-on&lt;/span&gt;      
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;runner=1cpu-linux-arm64&lt;/span&gt;      
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run-id=${{ github.run_id }}&lt;/span&gt;    
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;      
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "Hello from your Arm runner!"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the workflow file to the repository, and commit the changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;git add .github/workflows/test.yml
git commit -m "initial commit for actions test"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authorize GitHub so you can access your account from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;gh auth login
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a browser or authentication token to authorize your GitHub account.&lt;/p&gt;

&lt;p&gt;Create the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;gh repo create actions-test --private --source=. --remote=origin
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the project to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;git push -u origin master
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;git push&lt;/code&gt; command will trigger the GitHub Action to run. &lt;/p&gt;

&lt;p&gt;You can use a browser to view the Actions tab for the repository and see the job. &lt;/p&gt;

&lt;p&gt;You can also see the result from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;gh run list
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the output and find the ID. The output will be similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STATUS  TITLE                            WORKFLOW  BRANCH  EVENT  ID           ELAPSED  AGE                
✓       initial commit for actions test  test      master  push   10777854144  43s      about 6 minutes ago
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Print the log for the run. Substitute your job ID for the example ID shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;gh run view 10777854144 --log
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see numerous details about the run, including architecture, instance name, region, instance type, and the name of the AMI (disk image).&lt;/p&gt;

&lt;p&gt;You will also see that the instance is a spot instance (for lowest price).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build   Set up job  2024-09-09T17:05:20.0155475Z Current runner version: '2.319.1'
build   Set up job  2024-09-09T17:05:20.0163810Z Runner name: 'runs-on--i-03421942a716b3f2a--vPaXOcNxGv'
build   Set up job  2024-09-09T17:05:20.0164922Z Runner group name: 'Default'
build   Set up job  2024-09-09T17:05:20.0165868Z Machine name: 'ip-10-1-44-45'
build   Set up job  2024-09-09T17:05:20.0187255Z ##[group]Runner Instance
build   Set up job  2024-09-09T17:05:20.0188268Z |       INFO        |                      VALUE                      |
build   Set up job  2024-09-09T17:05:20.0189375Z |-------------------|-------------------------------------------------|
build   Set up job  2024-09-09T17:05:20.0190247Z | SSH               | ssh runner@XX.XX.XXX.XX                         |
build   Set up job  2024-09-09T17:05:20.0191195Z | DefaultAdmins     | []                                              |
build   Set up job  2024-09-09T17:05:20.0194359Z | Region            | us-west-2                                       |
build   Set up job  2024-09-09T17:05:20.0195723Z | AvailabilityZone  | us-west-2c                                      |
build   Set up job  2024-09-09T17:05:20.0196761Z | Version           | v2.5.0                                          |
build   Set up job  2024-09-09T17:05:20.0197751Z | Runner            | runs-on--i-03421942a716b3f2a--vPaXOcNxGv        |
build   Set up job  2024-09-09T17:05:20.0198675Z | InstanceId        | i-03421942a716b3f2a                             |
build   Set up job  2024-09-09T17:05:20.0199804Z | InstanceType      | m7g.medium                                      |
build   Set up job  2024-09-09T17:05:20.0200853Z | InstanceLifecycle | spot                                            |
build   Set up job  2024-09-09T17:05:20.0201845Z | InstanceRAM       | 3810.47 MiB                                     |
build   Set up job  2024-09-09T17:05:20.0202929Z | InstanceCPU       | 1 cores                                         |
build   Set up job  2024-09-09T17:05:20.0203988Z | InstanceDisk1     | /=/dev/nvme0n1p1                                |
build   Set up job  2024-09-09T17:05:20.0204948Z |                   | Free=31.16GiB Used=7.41GiB                      |
build   Set up job  2024-09-09T17:05:20.0205963Z | ImageId           | ami-0657d9a6ae629cc71                           |
build   Set up job  2024-09-09T17:05:20.0207032Z | ImageName         | runs-on-v2.2-ubuntu22-full-arm64-20240907064532 |
build   Set up job  2024-09-09T17:05:20.0208066Z | Platform          | linux                                           |
build   Set up job  2024-09-09T17:05:20.0209048Z | Architecture      | arm64                                           |
build   Set up job  2024-09-09T17:05:20.0210029Z | Has preinstall    | false                                           |
build   Set up job  2024-09-09T17:05:20.0211070Z | PrivateIp         | 10.1.44.45                                      |
build   Set up job  2024-09-09T17:05:20.0212487Z | Debug             | false                                           |
build   Set up job  2024-09-09T17:05:20.0213565Z | BucketCacheName   | runs-on-s3bucketcache-wdz50kvdwgnk              |
build   Set up job  2024-09-09T17:05:20.0214516Z ##[endgroup]
build   Set up job  2024-09-09T17:05:20.0215051Z ##[group]Timings
build   Set up job  2024-09-09T17:05:20.0215788Z |         TIME         |         STEP         |  DIFF   | TOTAL  |
build   Set up job  2024-09-09T17:05:20.0216832Z |----------------------|----------------------|---------|--------|
build   Set up job  2024-09-09T17:05:20.0217838Z | 2024-09-09T17:04:45Z | workflow-job-created | 0ms     | 0.0s   |
build   Set up job  2024-09-09T17:05:20.0218934Z | 2024-09-09T17:04:48Z | webhook-received     | 3400ms  | 3.40s  |
build   Set up job  2024-09-09T17:05:20.0219949Z | 2024-09-09T17:04:48Z | instance-launched    | 26ms    | 3.43s  |
build   Set up job  2024-09-09T17:05:20.0221067Z | 2024-09-09T17:04:50Z | instance-pending     | 1572ms  | 5.00s  |
build   Set up job  2024-09-09T17:05:20.0222055Z | 2024-09-09T17:05:08Z | agent-booting        | 18683ms | 23.68s |
build   Set up job  2024-09-09T17:05:20.0223051Z | 2024-09-09T17:05:08Z | agent-metadata       | 21ms    | 23.70s |
build   Set up job  2024-09-09T17:05:20.0224084Z | 2024-09-09T17:05:08Z | agent-userdata       | 215ms   | 23.92s |
build   Set up job  2024-09-09T17:05:20.0225112Z | 2024-09-09T17:05:08Z | runner-env           | 37ms    | 23.96s |
build   Set up job  2024-09-09T17:05:20.0226129Z | 2024-09-09T17:05:08Z | runner-setup-hooks   | 0ms     | 23.96s |
build   Set up job  2024-09-09T17:05:20.0227166Z | 2024-09-09T17:05:10Z | runner-disk-setup    | 1091ms  | 25.05s |
build   Set up job  2024-09-09T17:05:20.0228160Z | 2024-09-09T17:05:10Z | runner-setup-agent   | 48ms    | 25.10s |
build   Set up job  2024-09-09T17:05:20.0229734Z | 2024-09-09T17:05:10Z | runner-chown-user    | 0ms     | 25.10s |
build   Set up job  2024-09-09T17:05:20.0230634Z ##[endgroup]
build   Set up job  2024-09-09T17:05:20.0248725Z Testing runner upgrade compatibility
build   Set up job  2024-09-09T17:05:20.6787659Z ##[group]GITHUB_TOKEN Permissions
build   Set up job  2024-09-09T17:05:20.6789958Z Contents: read
build   Set up job  2024-09-09T17:05:20.6790702Z Metadata: read
build   Set up job  2024-09-09T17:05:20.6791251Z Packages: read
build   Set up job  2024-09-09T17:05:20.6791826Z ##[endgroup]
build   Set up job  2024-09-09T17:05:20.6796044Z Secret source: Actions
build   Set up job  2024-09-09T17:05:20.6796849Z Prepare workflow directory
build   Set up job  2024-09-09T17:05:20.7586035Z Prepare all required actions
build   Set up job  2024-09-09T17:05:20.7901878Z Complete job name: build
build   Set up runner   2024-09-09T17:05:20.9495781Z A job started hook has been configured by the self-hosted runner administrator
build   Set up runner   2024-09-09T17:05:21.0909000Z ##[group]Run '/opt/runs-on/pre.sh'
build   Set up runner   2024-09-09T17:05:21.0944129Z shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
build   Set up runner   2024-09-09T17:05:21.0944878Z ##[endgroup]
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1884436Z ##[group]Run echo "Hello from your Arm runner!"
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1885273Z echo "Hello from your Arm runner!"
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1914580Z shell: /usr/bin/bash -e {0}
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1915072Z env:
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1915428Z   RUNS_ON_AGENT_ARCH: arm64
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1916056Z   RUNS_ON_RUNNER_NAME: runs-on--i-03421942a716b3f2a--vPaXOcNxGv
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1916751Z   RUNS_ON_AGENT_USER: runner
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1917378Z   RUNS_ON_S3_BUCKET_CACHE: runs-on-s3bucketcache-wdz50kvdwgnk
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1918075Z   RUNS_ON_AWS_REGION: us-west-2
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1918665Z   ACTIONS_RUNNER_HOOK_JOB_STARTED: /opt/runs-on/pre.sh
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.1919277Z ##[endgroup]
build   Run echo "Hello from your Arm runner!"  2024-09-09T17:05:21.2054907Z Hello from your Arm runner!
build   Complete job    2024-09-09T17:05:21.2297627Z Cleaning up orphan processes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are now able to run GitHub Actions workflows on Graviton-based EC2 instances in your AWS account.&lt;/p&gt;

&lt;p&gt;You will get regular e-mail from RunsOn showing your usage and cost. It costs a few cents per day for the App Runner service, plus the cost of the EC2 instances used to run workflows.&lt;/p&gt;

&lt;p&gt;Follow the &lt;a href="https://runs-on.com/guides/uninstall/" rel="noopener noreferrer"&gt;Uninstall Guide&lt;/a&gt; if you don't want to continue using RunsOn. &lt;/p&gt;

&lt;p&gt;Utilizing managed, self-hosted Arm runners is a great solution if you need specific hardware such as the Graviton3 or Graviton4 processors.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://learn.arm.com" rel="noopener noreferrer"&gt;Arm Learning Paths&lt;/a&gt; for more content on AWS Graviton processors and the Arm architecture.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
      <category>github</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Investigate performance with Process Watch on AWS Graviton processors</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Mon, 19 Aug 2024 20:29:12 +0000</pubDate>
      <link>https://forem.com/aws-builders/investigate-performance-with-process-watch-on-aws-graviton-processors-4970</link>
      <guid>https://forem.com/aws-builders/investigate-performance-with-process-watch-on-aws-graviton-processors-4970</guid>
      <description>&lt;p&gt;Process Watch displays the instruction mix of the processes running on your Linux system. It recently added support for the Arm architecture, and works well on AWS Graviton processors. It can be used to quickly identify application usage of floating point, NEON, SVE, and SVE2 vector instructions.&lt;/p&gt;

&lt;p&gt;After analyzing a running system or application with Process Watch you may be able to increase performance by recompiling applications, updating libraries, or generally finding ways to improve performance using vector instructions. &lt;/p&gt;

&lt;p&gt;Read on to find out how to install and use Process Watch. &lt;/p&gt;

&lt;h2&gt;
  
  
  What software is required to build Process Watch?
&lt;/h2&gt;

&lt;p&gt;The Process Watch source code is available on GitHub. &lt;/p&gt;

&lt;p&gt;You will need various tools to build Process Watch from source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMake&lt;/li&gt;
&lt;li&gt;Clang&lt;/li&gt;
&lt;li&gt;LLVM&lt;/li&gt;
&lt;li&gt;libelf&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The instructions below are for an AWS Graviton-based EC2 instance running Ubuntu 24.04. You can modify them as needed for your Linux distribution.&lt;/p&gt;

&lt;p&gt;To install the required tools run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt-get update
sudo apt-get install libelf-dev cmake clang llvm llvm-dev python-is-python3 -y
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where is the Process Watch source code?
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;git&lt;/code&gt; to clone the Process Watch repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;git clone --recursive https://github.com/intel/processwatch.git
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to include the &lt;code&gt;--recursive&lt;/code&gt; option to clone all submodules.&lt;/p&gt;

&lt;p&gt;If you are curious, the submodules are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/libbpf/bpftool.git" rel="noopener noreferrer"&gt;bpftool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/andikleen/pmu-tools.git" rel="noopener noreferrer"&gt;pmu-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/codeplea/tinyexpr.git" rel="noopener noreferrer"&gt;tinyexpr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/capstone-engine/capstone.git" rel="noopener noreferrer"&gt;capstone&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Change to the repository directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;cd processwatch
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is the best way to build Process Watch?
&lt;/h2&gt;

&lt;p&gt;To build Process Watch, run the build script included in the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;./build.sh -b
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compiling dependencies...
  No system bpftool found! Compiling libbpf and bpftool...
  Compiling capstone...
Building the 'insn' BPF program:
  Gathering BTF information for this kernel...
  Compiling the BPF program...
  Stripping the object file...
  Generating the BPF skeleton header...
Linking the main Process Watch binary...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have the &lt;code&gt;processwatch&lt;/code&gt; binary in the top-level directory of the repository.&lt;/p&gt;

&lt;p&gt;For convenience, copy it to a common place included in your search path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo cp ./processwatch /usr/local/bin
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Do I need to run Process Watch as root?
&lt;/h2&gt;

&lt;p&gt;You can run Process Watch as a non-root user, but it requires the modifications shown below, which decreases system security.&lt;/p&gt;

&lt;p&gt;To enable non-root users to run Process Watch, you need to run the 3 commands below. If you want to run Process Watch with &lt;code&gt;sudo&lt;/code&gt; you can skip these 3 commands and go to the next section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo setcap CAP_PERFMON,CAP_BPF=+ep /usr/local/bin/processwatch
sudo sysctl -w kernel.perf_event_paranoid=-1
sudo sysctl kernel.unprivileged_bpf_disabled=0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How do I run Process Watch?
&lt;/h2&gt;

&lt;p&gt;Process Watch accepts a number of command-line arguments. You can view these by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo processwatch -h
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usage: processwatch [options]

options:
  -h          Displays this help message.
  -v          Displays the version.
  -i &amp;lt;int&amp;gt;    Prints results every &amp;lt;int&amp;gt; seconds.
  -n &amp;lt;num&amp;gt;    Prints results for &amp;lt;num&amp;gt; intervals.
  -c          Prints all results in CSV format to stdout.
  -p &amp;lt;pid&amp;gt;    Only profiles &amp;lt;pid&amp;gt;.
  -m          Displays instruction mnemonics, instead of categories.
  -s &amp;lt;samp&amp;gt;   Profiles instructions with a sampling period of &amp;lt;samp&amp;gt;.
  -f &amp;lt;filter&amp;gt; Can be used multiple times. Defines filters for columns. Defaults to 'FPARMv8', 'NEON', 'SVE' and 'SVE2'.
  -l          Prints all available categories, or mnemonics if -m is specified.
  -d          Prints only debug information.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without any options Process Watch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prints results every two seconds&lt;/li&gt;
&lt;li&gt;Prints results until it is killed (using Ctrl+C)&lt;/li&gt;
&lt;li&gt;Prints all results in a table format on &lt;code&gt;stdout&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Profiles all running processes&lt;/li&gt;
&lt;li&gt;Displays counts for the default filters, which are 'FPARMv8', 'NEON', 'SVE', and 'SVE2'&lt;/li&gt;
&lt;li&gt;Sets the sample period to every 10000 events&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What does the Process Watch output look like?
&lt;/h2&gt;

&lt;p&gt;You can run Process Watch with no arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo ./processwatch
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PID      NAME             FPARMv8  NEON     SVE      SVE2     %TOTAL   TOTAL
ALL      ALL              0.00     0.29     0.00     0.00     100.00   346
17400    processwatch     0.00     0.36     0.00     0.00     80.64    279
254      systemd-journal  0.00     0.00     0.00     0.00     13.01    45
542      irqbalance       0.00     0.00     0.00     0.00     2.60     09
544      rs:main Q:Reg    0.00     0.00     0.00     0.00     2.02     07
560      snapd            0.00     0.00     0.00     0.00     1.16     04
296      multipathd       0.00     0.00     0.00     0.00     0.58     02

PID      NAME             FPARMv8  NEON     SVE      SVE2     %TOTAL   TOTAL
ALL      ALL              3.57     12.86    0.00     0.00     100.00   140
17400    processwatch     3.73     13.43    0.00     0.00     95.71    134
4939     sshd             0.00     0.00     0.00     0.00     2.86     04
296      multipathd       0.00     0.00     0.00     0.00     0.71     01
560      snapd            0.00     0.00     0.00     0.00     0.71     01

PID      NAME             FPARMv8  NEON     SVE      SVE2     %TOTAL   TOTAL
ALL      ALL              1.18     5.12     0.00     0.00     100.00   254
17400    processwatch     1.19     5.16     0.00     0.00     99.21    252
6651     packagekitd      0.00     0.00     0.00     0.00     0.39     01
4939     sshd             0.00     0.00     0.00     0.00     0.39     01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New output comes every two seconds, and the next samples are appended to the bottom of the output.&lt;/p&gt;

&lt;p&gt;Use Ctrl+C to end &lt;code&gt;processwatch&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I use Process Watch to identify applications which could run faster?
&lt;/h2&gt;

&lt;p&gt;To see an example of how Process Watch can be used, use a text editor to save the Python code below into a file named &lt;code&gt;zip.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;

&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16384&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;largefile&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;largefile.gz&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f_in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
                &lt;span class="n"&gt;f_out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;f_out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Zip complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Python code reads a file named &lt;code&gt;largefile&lt;/code&gt; and writes a compressed version as &lt;code&gt;largefile.gz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To create the input file, use the &lt;code&gt;dd&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;dd if=/dev/zero of=largefile count=1M bs=1024
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, use a text editor to save the script below in a file named &lt;code&gt;run1.sh&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

python ./zip.py &amp;amp;
&lt;span class="nv"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;processwatch &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$pid&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; 1 &lt;span class="nt"&gt;-i&lt;/span&gt; 2 &lt;span class="nt"&gt;-f&lt;/span&gt; HasCRC &lt;span class="nt"&gt;-f&lt;/span&gt; HasNEON &amp;amp;
&lt;span class="nv"&gt;pid2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;30
&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nv"&gt;$pid2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the script and see that it starts the Python code to compress &lt;code&gt;largefile&lt;/code&gt; and then attaches &lt;code&gt;processwatch&lt;/code&gt; to monitor for CRC and NEON instructions. The sample rate is every 1 second and the output is printed every 2 seconds. &lt;/p&gt;

&lt;p&gt;File compression is a task that runs best when CRC instructions are used. No CRC instructions indicates an opening for performance improvement. &lt;/p&gt;

&lt;p&gt;Run the script using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;bash ./run1.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Process Watch output will start to print on &lt;code&gt;stdout&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The output is similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PID      NAME             CRC      NEON     %TOTAL   TOTAL   
ALL      ALL              0.00     1.63     100.00   25466   
1226     python           0.00     1.63     100.00   25466  

PID      NAME             CRC      NEON     %TOTAL   TOTAL   
ALL      ALL              0.00     1.96     100.00   23224   
1226     python           0.00     1.96     100.00   23224   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that no CRC instructions are shown. This is because the version of &lt;code&gt;zlib&lt;/code&gt; supplied by the Linux distribution is not compiled with CRC instructions. &lt;/p&gt;

&lt;p&gt;You can confirm this by running &lt;code&gt;objdump&lt;/code&gt; to disassemble the library and look for crc32 instructions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;objdump -d /usr/lib/aarch64-linux-gnu/libz.so.1 | awk -F" " '{print $&lt;/span&gt;3&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;' | grep crc32 | wc -l
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the result is 0 then there are no crc32 instructions used in the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is there a way to use CRC instructions for file compression?
&lt;/h2&gt;

&lt;p&gt;If there are no crc32 instructions in zlib then you can use zlib-cloudflare to increase application performance.&lt;/p&gt;

&lt;p&gt;To build and install zlib-cloudflare download and build using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;git clone https://github.com/cloudflare/zlib.git
cd zlib &amp;amp;&amp;amp; ./configure
make &amp;amp;&amp;amp; sudo make install
cd ..
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the new library installed, use a text editor to save a new bash script with the code below to the file &lt;code&gt;run2.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LD_PRELOAD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/lib/libz.so python ./zip.py &amp;amp;
&lt;span class="nv"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;processwatch &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$pid&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; 1 &lt;span class="nt"&gt;-i&lt;/span&gt; 2 &lt;span class="nt"&gt;-f&lt;/span&gt; HasCRC &lt;span class="nt"&gt;-f&lt;/span&gt; HasNEON &amp;amp;
&lt;span class="nv"&gt;pid2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;10
&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nv"&gt;$pid2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the new &lt;code&gt;libz.so&lt;/code&gt; is used and the CRC and NEON instructions are again printed every 2 seconds. &lt;/p&gt;

&lt;p&gt;Run the new script using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;bash ./run2.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time the CRC instructions are used, and the performance is significantly faster. &lt;/p&gt;

&lt;p&gt;The output is similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PID      NAME             CRC      NEON     %TOTAL   TOTAL   
ALL      ALL              17.40    1.80     100.00   25246   
1251     python           17.40    1.80     100.00   25246   

PID      NAME             CRC      NEON     %TOTAL   TOTAL   
ALL      ALL              17.33    2.54     100.00   23556   
1251     python           17.33    2.54     100.00   23556   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What else can I do with Process Watch?
&lt;/h2&gt;

&lt;p&gt;Besides CRC instructions, you can use Process Watch to look for NEON, SVE, and SVE2 instructions. These are all vector extensions in Arm processors used to increase application performance. &lt;/p&gt;

&lt;p&gt;To see examples of NEON and SVE refer to the &lt;a href="https://learn.arm.com/learning-paths/servers-and-cloud-computing/processwatch/using-processwatch/" rel="noopener noreferrer"&gt;Using Process watch&lt;/a&gt; Arm Learning Path. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>performance</category>
      <category>linux</category>
      <category>arm</category>
    </item>
    <item>
      <title>Install Aperf for performance analysis on AWS Graviton processors</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Fri, 05 Jan 2024 17:16:33 +0000</pubDate>
      <link>https://forem.com/aws-builders/install-aperf-for-performance-analysis-on-aws-graviton-processors-4bfm</link>
      <guid>https://forem.com/aws-builders/install-aperf-for-performance-analysis-on-aws-graviton-processors-4bfm</guid>
      <description>&lt;p&gt;APerf (AWS Perf) is an open source command line performance analysis tool which saves time by collecting information which is normally collected by multiple tools such as &lt;code&gt;perf&lt;/code&gt;, &lt;code&gt;sysstat&lt;/code&gt;, and &lt;code&gt;sysctl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;APerf was recently created by AWS to help with Linux performance analysis.&lt;/p&gt;

&lt;p&gt;In addition to the CLI, APerf includes an HTML view to visualize the collected data. &lt;/p&gt;

&lt;h2&gt;
  
  
  Before you begin
&lt;/h2&gt;

&lt;p&gt;APerf works on Linux and is available as a single binary. &lt;/p&gt;

&lt;p&gt;APerf works best if &lt;code&gt;perf&lt;/code&gt; is installed. Refer to the &lt;a href="https://learn.arm.com/install-guides/perf"&gt;Perf for Linux on Arm&lt;/a&gt; install guide for instructions.&lt;/p&gt;

&lt;p&gt;This article provides a quick solution to install APerf on AWS Graviton processors.&lt;/p&gt;

&lt;p&gt;Confirm you are using Graviton:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;uname -m
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aarch64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Download and install APerf
&lt;/h2&gt;

&lt;p&gt;The easiest way to install APerf is to download a release from GitHub, extract it, and setup your &lt;code&gt;PATH&lt;/code&gt; environment variable or copy the executable to a directory already in your search path. &lt;/p&gt;

&lt;p&gt;Visit the &lt;a href="https://github.com/aws/aperf/releases/"&gt;releases page&lt;/a&gt; to see a list of available releases. &lt;/p&gt;

&lt;p&gt;You can also download a release from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;wget https://github.com/aws/aperf/releases/download/v0.1.9-alpha/aperf-v0.1.9-alpha-aarch64.tar.gz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract the release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;tar xvfz aperf-v0.1.9-alpha-aarch64.tar.gz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the path to &lt;code&gt;aperf&lt;/code&gt; in your &lt;code&gt;.bashrc&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;echo 'export PATH="$&lt;/span&gt;PATH:&lt;span class="nv"&gt;$HOME&lt;/span&gt;/aperf-v0.1.9-alpha-aarch64&lt;span class="s2"&gt;"' &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;span class="go"&gt;source ~/.bashrc
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can copy the &lt;code&gt;aperf&lt;/code&gt; executable to a directory already in your search path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo cp aperf-v0.1.9-alpha-aarch64/aperf /usr/local/bin 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm &lt;code&gt;aperf&lt;/code&gt; is installed by printing the version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;aperf --version
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should print the version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aperf 0.1.0 (0c4f58c)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verify APerf is working
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create and view a report
&lt;/h3&gt;

&lt;p&gt;To confirm APerf is working, start it for 10 seconds and take a sample every 1 second.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;aperf record -i 1 -p 10 -r run1 --profile
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 10 seconds &lt;code&gt;aperf&lt;/code&gt; completes and you see a directory named &lt;code&gt;run1&lt;/code&gt; and a tar file named &lt;code&gt;run1.tar.gz&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Next, generate a report from the recorded data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;aperf report -r run1 -n report1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name of the report is &lt;code&gt;report1&lt;/code&gt; and you will see a &lt;code&gt;report1&lt;/code&gt; directory and a tar file named &lt;code&gt;report1.tar.gz&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The tar files are useful if you want to copy them to another machine.&lt;/p&gt;

&lt;p&gt;Using a web browser, open the file &lt;code&gt;index.html&lt;/code&gt; in the &lt;code&gt;report1/&lt;/code&gt; directory. To open the file use &lt;code&gt;Ctrl+O&lt;/code&gt; for Linux and Windows and use &lt;code&gt;⌘+O&lt;/code&gt; for macOS.&lt;/p&gt;

&lt;p&gt;The report is now visible in the browser. &lt;/p&gt;

&lt;p&gt;There are a number of tabs on the left side showing the collected data. &lt;/p&gt;

&lt;p&gt;You can browse the data and see what has been collected. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh166eguwlyb7epido1g5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh166eguwlyb7epido1g5.png" alt="Image description" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Kernel Config and Sysctl Data tabs are blank unless you click No.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create and view a report containing 2 runs
&lt;/h3&gt;

&lt;p&gt;To demonstrate comparing 2 runs, create a second run with &lt;code&gt;aperf record&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;aperf record -i 1 -p 10 -r run2 --profile
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 10 seconds &lt;code&gt;aperf&lt;/code&gt; completes and you see a directory named &lt;code&gt;run2&lt;/code&gt; and a tar file named &lt;code&gt;run2.tar.gz&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Generate a report with both the first and second runs included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;aperf report -r run1 -r run2 -n compare
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name of the report is &lt;code&gt;compare&lt;/code&gt; and you will see a &lt;code&gt;compare&lt;/code&gt; directory and a tar file named &lt;code&gt;compare.tar.gz&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;index.html&lt;/code&gt; file in the &lt;code&gt;compare/&lt;/code&gt; directory to see the 2 runs side by side. &lt;/p&gt;

&lt;p&gt;A screenshot is shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ik54gpi7zq0luzx3wra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ik54gpi7zq0luzx3wra.png" alt="Image description" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use an HTTP server
&lt;/h3&gt;

&lt;p&gt;If you are doing performance analysis on an EC2 instance without a remote desktop, you can view the APerf reports from your local browser by running a simple web server on the remote machine.&lt;/p&gt;

&lt;p&gt;In the directory with the report data and the &lt;code&gt;index.html&lt;/code&gt; file run a simple web server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;python -m http.server 3000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure port 3000 is open on the remote system. &lt;/p&gt;

&lt;p&gt;You can open the port in your security group or use SSH to forward port 3000.&lt;/p&gt;

&lt;p&gt;To use SSH (substitute your SSH key name and IP address):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;ssh -i your-key.pem -L 3000:localhost:3000 ubuntu@your-ec2-ip 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use SSH port forwarding, open your browser to &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;If you use the security group, enter the IP address of the EC2 instance followed by &lt;code&gt;:3000&lt;/code&gt; in your browser address bar.&lt;/p&gt;

&lt;p&gt;You will see the same APerf report, and avoid the need to copy files to your local machine from the remote system for viewing.&lt;/p&gt;

&lt;p&gt;You are ready to use APerf for performance analysis on AWS Graviton processors.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://learn.arm.com"&gt;https://learn.arm.com&lt;/a&gt; for more Graviton related content. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>performance</category>
    </item>
    <item>
      <title>Use AWS Graviton processors on AWS Fargate with Copilot</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Fri, 17 Nov 2023 23:01:18 +0000</pubDate>
      <link>https://forem.com/aws-builders/use-aws-graviton-processors-on-aws-fargate-with-copilot-1n6p</link>
      <guid>https://forem.com/aws-builders/use-aws-graviton-processors-on-aws-fargate-with-copilot-1n6p</guid>
      <description>&lt;p&gt;&lt;a href="https://aws.github.io/copilot-cli/"&gt;AWS Copilot CLI&lt;/a&gt; is an open source command line interface for running containers on AWS App Runner, Amazon Elastic Container Service (ECS), and AWS Fargate. &lt;/p&gt;

&lt;p&gt;You can use Copilot to run containers on Fargate’s serverless compute with Graviton2 processors and benefit from improved price performance. &lt;/p&gt;

&lt;p&gt;Graviton is not the default for Copilot, but read on to find out how to change the architecture to Arm.&lt;/p&gt;

&lt;h1&gt;
  
  
  Before you begin
&lt;/h1&gt;

&lt;p&gt;You will need Docker and Copilot on your local computer to follow the instructions below.&lt;/p&gt;

&lt;p&gt;Your local computer can be Linux or macOS.&lt;/p&gt;

&lt;p&gt;There are plenty of places to find Docker installation instructions. One option is the &lt;a href="https://learn.arm.com/install-guides/docker/"&gt;Docker install guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will also need an AWS account. &lt;/p&gt;

&lt;p&gt;To create an account, go to &lt;a href="https://aws.amazon.com"&gt;https://aws.amazon.com&lt;/a&gt; and click on &lt;strong&gt;Create an AWS Account&lt;/strong&gt; in the top right corner. Follow the instructions to register. See the &lt;a href="https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html"&gt;Creating an AWS account documentation&lt;/a&gt; for full instructions.&lt;/p&gt;

&lt;p&gt;Make sure to configure your access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. Refer to &lt;a href="https://learn.arm.com/install-guides/aws_access_keys/"&gt;AWS Credentials&lt;/a&gt; for a quick summary of how to run &lt;code&gt;aws configure&lt;/code&gt;. The install guide also covers how to install the AWS CLI. Make a note of the AWS region you set with &lt;code&gt;aws configure&lt;/code&gt; so you can see the resources created by Copilot in the AWS console.&lt;/p&gt;

&lt;p&gt;If you are using Docker on Linux you will need to install QEMU to build container images for both the &lt;code&gt;arm64&lt;/code&gt; and the &lt;code&gt;amd64&lt;/code&gt; architectures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt-get install qemu-user-static
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker Desktop for macOS includes the ability to build for multiple architectures, so you don't need to do anything extra.&lt;/p&gt;

&lt;p&gt;To install Copilot on Arm Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo curl -Lo /usr/local/bin/copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux-arm64 \
   &amp;amp;&amp;amp; sudo chmod +x /usr/local/bin/copilot \
   &amp;amp;&amp;amp; copilot --help
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To install Copilot on macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-darwin &amp;amp;&amp;amp; chmod +x copilot &amp;amp;&amp;amp; sudo mv copilot /usr/local/bin/copilot &amp;amp;&amp;amp; copilot --help
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Create an example application
&lt;/h1&gt;

&lt;p&gt;To try Copilot on Graviton2 processors, you can use the same Go application used in &lt;a href="https://dev.to/aws-builders/multi-architecture-kubernetes-clusters-on-amazon-eks-2nol"&gt;Multi-architecture Kubernetes clusters on Amazon EKS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Use an editor to create the 3 files below.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;hello.go&lt;/code&gt; with the contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Copyright 2022 Google LLC&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// Licensed under the Apache License, Version 2.0 (the "License");&lt;/span&gt;
&lt;span class="c"&gt;// you may not use this file except in compliance with the License.&lt;/span&gt;
&lt;span class="c"&gt;// You may obtain a copy of the License at&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;//      http://www.apache.org/licenses/LICENSE-2.0&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// Unless required by applicable law or agreed to in writing, software&lt;/span&gt;
&lt;span class="c"&gt;// distributed under the License is distributed on an "AS IS" BASIS,&lt;/span&gt;
&lt;span class="c"&gt;// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;/span&gt;
&lt;span class="c"&gt;// See the License for the specific language governing permissions and&lt;/span&gt;
&lt;span class="c"&gt;// limitations under the License.&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"runtime"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello from CPU PLATFORM:%s/%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GOOS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GOARCH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a file named &lt;code&gt;go.mod&lt;/code&gt; with the following two lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;arm&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="m"&gt;1.21&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a third file named &lt;code&gt;Dockerfile&lt;/code&gt; with the contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Build: 1st stage&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.21-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; TARCH&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; hello.go .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go build &lt;span class="nt"&gt;-o&lt;/span&gt; /hello &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apk add &lt;span class="nt"&gt;--update&lt;/span&gt; &lt;span class="nt"&gt;--no-cache&lt;/span&gt; file &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    file /hello

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Release: 2nd stage&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /hello /hello&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--update&lt;/span&gt; &lt;span class="nt"&gt;--no-cache&lt;/span&gt; file
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "/hello" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application listens on port 8080 and prints the architecture of the machine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deploy the application with Copilot
&lt;/h1&gt;

&lt;p&gt;You can deploy the application with a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;copilot init --app go-arch               \
  --name api                             \
  --type 'Load Balanced Web Service'     \
  --dockerfile './Dockerfile'            \
  --env test                             \
  --port 8080                            \
  --deploy
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default architecture is &lt;code&gt;amd64&lt;/code&gt;. The &lt;code&gt;copilot&lt;/code&gt; command builds the container on your local machine for &lt;code&gt;amd64&lt;/code&gt;, pushes it to the container registry, and creates everything needed to run on AWS Fargate. &lt;/p&gt;

&lt;p&gt;You can also specify an existing container image using &lt;code&gt;--image&lt;/code&gt; instead of &lt;code&gt;--dockerfile&lt;/code&gt;. Make sure the image is a multi-architecture image supporting both &lt;code&gt;arm64&lt;/code&gt; and &lt;code&gt;amd64&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While you are waiting for the command to complete you can look in your AWS account and see the resources created in AWS S3, CloudFormation, and ECS.&lt;/p&gt;

&lt;p&gt;When the &lt;code&gt;copilot&lt;/code&gt; command completes, the URL of the load balancer is printed.&lt;/p&gt;

&lt;p&gt;Visit the URL in your browser and see the printed message.&lt;/p&gt;

&lt;p&gt;To access the application from the command line, run &lt;code&gt;curl&lt;/code&gt; with the URL. &lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;curl -w '\n' http://go-arc-Publi-UvaFr7DQF5ud-988490958.us-west-2.elb.amazonaws.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello from CPU PLATFORM:linux/amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also check running status using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;copilot svc status
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found only one deployed service api in environment test
Task Summary

  Running   ██████████  1/1 desired tasks are running
  Health    ██████████  1/1 passes HTTP health checks
            ██████████  1/1 passes container health checks

Tasks

  ID        Status      Revision    Started At     Cont. Health  HTTP Health
  --        ------      --------    ----------     ------------  -----------
  7779652d  RUNNING     1           7 minutes ago  HEALTHY       HEALTHY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Migrate to Graviton
&lt;/h1&gt;

&lt;p&gt;To move from &lt;code&gt;amd64&lt;/code&gt; to &lt;code&gt;arm64&lt;/code&gt; edit the file &lt;code&gt;copilot/api/manifest.yml&lt;/code&gt; and change the &lt;code&gt;platform&lt;/code&gt; entry from &lt;code&gt;linux/x86_64&lt;/code&gt; to &lt;code&gt;linux/arm64&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you don't have a &lt;code&gt;platform&lt;/code&gt; entry, add one after the existing entries. Either way, you should have this line in your &lt;code&gt;manifest.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux/arm64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are now ready to run on Graviton2.&lt;/p&gt;

&lt;p&gt;Save the file and redeploy the application using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;copilot svc deploy 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copilot rebuilds the container image for the &lt;code&gt;arm64&lt;/code&gt; architecture, pushes the image to the container registry and deploys the new image.&lt;/p&gt;

&lt;p&gt;If you look in your AWS console and visit the task configuration in ECS, you will see the task now shows &lt;code&gt;ARM64&lt;/code&gt; as the architecture.&lt;/p&gt;

&lt;p&gt;Visit the URL again using a browser or the same &lt;code&gt;curl&lt;/code&gt; command and the message prints &lt;code&gt;arm64&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello from CPU PLATFORM:linux/arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Open a shell in the container
&lt;/h1&gt;

&lt;p&gt;If you need to troubleshoot a container, you can use Copilot to connect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;copilot svc exec
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Answer yes to install the Session Manager plugin, and you have a shell into the running container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Starting session with SessionId: ecs-execute-command-0f1f212e5ff00ec05
/ # 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can make changes to the container and do any needed investigation. Copilot is an easy way to connect to running containers. &lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;You have deployed a containerized application on Fargate running AWS Graviton2 processors using Copilot. The Copilot CLI makes it much easier to create the required resources and easily make changes using the &lt;code&gt;manifest.yml&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;There doesn't seem to be a way to specify &lt;code&gt;arm64&lt;/code&gt; on the initial &lt;code&gt;copilot init&lt;/code&gt; command, but it would be a useful enhancement. &lt;/p&gt;

&lt;h1&gt;
  
  
  Clean up the AWS resources
&lt;/h1&gt;

&lt;p&gt;Delete the resources created by Copilot by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;copilot app delete
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>aws</category>
      <category>docker</category>
      <category>arm</category>
      <category>ecs</category>
    </item>
    <item>
      <title>Multi-architecture Kubernetes clusters on Amazon EKS</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Mon, 30 Oct 2023 21:01:12 +0000</pubDate>
      <link>https://forem.com/aws-builders/multi-architecture-kubernetes-clusters-on-amazon-eks-2nol</link>
      <guid>https://forem.com/aws-builders/multi-architecture-kubernetes-clusters-on-amazon-eks-2nol</guid>
      <description>&lt;p&gt;AWS Graviton processors continue to deliver price performance for cloud workloads. Migrating Kubernetes applications can be tricky, but AWS and Docker provide tools to make the process easier.&lt;/p&gt;

&lt;p&gt;You can experiment with multi-architecture clusters to better understand the price performance benefits, and select the best hardware for the task. Multi-architecture clusters also ease migration when some software components are not available for the Arm architecture. &lt;/p&gt;

&lt;p&gt;Refer to the &lt;a href="https://armkeil.blob.core.windows.net/developer/Files/pdf/white-paper/arm-whitepaper-insiders-guide-to-building-a-multi-arch-infrastructure.pdf"&gt;The Insider’s Guide to Building a Multi-Arch Infrastructure&lt;/a&gt; for more information on the benefits of multi-architecture Kubernetes clusters.&lt;/p&gt;

&lt;h1&gt;
  
  
  Multi-architecture Kubernetes clusters
&lt;/h1&gt;

&lt;p&gt;A multi-architecture Kubernetes cluster runs workloads on multiple hardware architectures, typically arm64 and amd64 (using Docker terminology).&lt;/p&gt;

&lt;p&gt;To learn more about multi-architecture Kubernetes you can create a cluster in Amazon EKS and gain some practical experience with arm64 and amd64 nodes. This will also help you understand multi-architecture container images. &lt;/p&gt;

&lt;h1&gt;
  
  
  Before you begin
&lt;/h1&gt;

&lt;p&gt;You will need &lt;code&gt;docker&lt;/code&gt;, &lt;code&gt;eksctl&lt;/code&gt; and &lt;code&gt;kubectl&lt;/code&gt; on your local computer to try out the steps below.&lt;/p&gt;

&lt;p&gt;Your local computer can be Windows, Linux, or macOS. The instructions generally assume Linux. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.arm.com/install-guides/multipass/"&gt;Multipass&lt;/a&gt; from Canonical is a great tool for Linux virtual machines if you use macOS.&lt;/p&gt;

&lt;p&gt;You can refer to the &lt;a href="https://learn.arm.com/install-guides/kubectl/"&gt;Kubectl install guide&lt;/a&gt; and the &lt;a href="https://learn.arm.com/install-guides/eksctl/"&gt;AWS EKS CLI install guide&lt;/a&gt; for installation details. The guides provide details for Arm Linux machines, but links to installation information about other platforms are also provided. &lt;/p&gt;

&lt;p&gt;There are plenty of places to find Docker installation instructions. One option is the &lt;a href="https://learn.arm.com/install-guides/docker/"&gt;Docker install guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will also need an AWS account. &lt;/p&gt;

&lt;p&gt;To create an account, go to &lt;a href="https://aws.amazon.com"&gt;https://aws.amazon.com&lt;/a&gt; and click on &lt;strong&gt;Create an AWS Account&lt;/strong&gt; in the top right corner. Follow the instructions to register. See the &lt;a href="https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html"&gt;Creating an AWS account documentation&lt;/a&gt; for full instructions.&lt;/p&gt;

&lt;p&gt;Make sure to configure your access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. Refer to &lt;a href="https://learn.arm.com/install-guides/aws_access_keys/"&gt;AWS Credentials&lt;/a&gt; for a quick summary of how to run &lt;code&gt;aws configure&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Multi-architecture containers
&lt;/h1&gt;

&lt;p&gt;Before you can try out a multi-architecture Kubernetes cluster, you need a multi-architecture container image. &lt;/p&gt;

&lt;p&gt;Multi-architecture container images are the easiest way to deploy applications, and hide the underlying hardware architecture. Building multi-architecture images is slightly more complex compared to building single-architecture images.&lt;/p&gt;

&lt;p&gt;Docker provides two ways to create multi-architecture images:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker buildx&lt;/code&gt; builds both architectures at the same time&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker manifest&lt;/code&gt; builds each architecture separately and joins them together into a multi-architecture image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read more about how to create container images in the article &lt;a href="https://dev.to/aws-builders/using-docker-manifest-to-create-multi-arch-images-on-aws-graviton-processors-1320"&gt;Using Docker manifest to create multi-arch images on AWS Graviton processors&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is a simple Go application you can use to learn about multi-architecture Kubernetes clusters.&lt;/p&gt;

&lt;p&gt;Use your favorite text editor to create a file named &lt;code&gt;hello.go&lt;/code&gt; with the contents below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Copyright 2022 Google LLC&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// Licensed under the Apache License, Version 2.0 (the "License");&lt;/span&gt;
&lt;span class="c"&gt;// you may not use this file except in compliance with the License.&lt;/span&gt;
&lt;span class="c"&gt;// You may obtain a copy of the License at&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;//      http://www.apache.org/licenses/LICENSE-2.0&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// Unless required by applicable law or agreed to in writing, software&lt;/span&gt;
&lt;span class="c"&gt;// distributed under the License is distributed on an "AS IS" BASIS,&lt;/span&gt;
&lt;span class="c"&gt;// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;/span&gt;
&lt;span class="c"&gt;// See the License for the specific language governing permissions and&lt;/span&gt;
&lt;span class="c"&gt;// limitations under the License.&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"runtime"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello from image NODE:%s, POD:%s, CPU PLATFORM:%s/%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NODE_NAME"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POD_NAME"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GOOS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GOARCH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a file named &lt;code&gt;go.mod&lt;/code&gt; with the following two lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;arm&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="m"&gt;1.21&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a third file named &lt;code&gt;Dockerfile&lt;/code&gt; with the contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; T&lt;/span&gt;

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Build: 1st stage&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.21-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder &lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; TARCH&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; hello.go .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; go build &lt;span class="nt"&gt;-o&lt;/span&gt; /hello &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apk add &lt;span class="nt"&gt;--update&lt;/span&gt; &lt;span class="nt"&gt;--no-cache&lt;/span&gt; file &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    file /hello   

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Release: 2nd stage&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ${T}alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /hello /hello&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--update&lt;/span&gt; &lt;span class="nt"&gt;--no-cache&lt;/span&gt; file
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "/hello" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker buildx
&lt;/h2&gt;

&lt;p&gt;With the three text files created, you can build the container using &lt;code&gt;docker buildx&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Before you start, log in to Docker Hub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the commands below to build the image, and make sure to substitute your own Docker ID instead of &lt;code&gt;jasonrandrews&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker buildx create &lt;span class="nt"&gt;--use&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; builder
docker buildx build &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64,linux/arm64 &lt;span class="nt"&gt;-t&lt;/span&gt; jasonrandrews/go-arch-x:1.0 &lt;span class="nt"&gt;--push&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the commands are complete, you will see the new image in your Docker Hub account. Note, this is the &lt;code&gt;go-arch-x&lt;/code&gt; repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker manifest
&lt;/h2&gt;

&lt;p&gt;You can also use &lt;code&gt;docker manifest&lt;/code&gt; to create a multi-architecture image from two single-architecture images. This is an alternative way to to build the multi-architecture image, but you can also use it to learn how to deploy a container image that only supports one architecture.&lt;/p&gt;

&lt;p&gt;Substitute your Docker ID instead of &lt;code&gt;jasonrandrews&lt;/code&gt; and run these commands on an amd64 machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build for amd64&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; jasonrandrews/go-arch:amd64 &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;TARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64 &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64/ &lt;span class="nb"&gt;.&lt;/span&gt;
docker push jasonrandrews/go-arch:amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitute your Docker ID instead of &lt;code&gt;jasonrandrews&lt;/code&gt; and run these commands on an arm64 machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build for arm64&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; jasonrandrews/go-arch:arm64 &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;TARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm64 &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm64v8/ &lt;span class="nb"&gt;.&lt;/span&gt;
docker push jasonrandrews/go-arch:arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After building individual containers for each architecture, merge them into a single image by running the commands below on either architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker manifest create jasonrandrews/go-arch:1.0 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--amend&lt;/span&gt; jasonrandrews/go-arch:arm64 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--amend&lt;/span&gt; jasonrandrews/go-arch:amd64
docker manifest push &lt;span class="nt"&gt;--purge&lt;/span&gt; jasonrandrews/go-arch:1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have two single-architecture images in your Docker Hub account and the combined multi-architecture image in the same repository. Note, this is the &lt;code&gt;go-arch&lt;/code&gt; repository.&lt;/p&gt;

&lt;p&gt;In the sections below, you will learn how to deploy the images in Amazon EKS.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create a multi-architecture Kubernetes cluster
&lt;/h1&gt;

&lt;p&gt;You can use &lt;code&gt;eksctl&lt;/code&gt; to create a cluster with multiple architectures.&lt;/p&gt;

&lt;p&gt;First, use a text editor to create a text file &lt;code&gt;cluster.yaml&lt;/code&gt; with the contents below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eksctl.io/v1alpha5&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterConfig&lt;/span&gt;

&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cluster1&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

&lt;span class="na"&gt;nodeGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ng-1&lt;/span&gt;
    &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t2.micro&lt;/span&gt;
    &lt;span class="na"&gt;desiredCapacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;volumeSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ng-2&lt;/span&gt;
    &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t4g.small&lt;/span&gt;
    &lt;span class="na"&gt;desiredCapacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;volumeSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The instance types above take advantage of free tier and the T4g free trial. &lt;/p&gt;

&lt;p&gt;Run the &lt;code&gt;eksctl&lt;/code&gt; command with the yaml file to create an EKS cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl create cluster &lt;span class="nt"&gt;-f&lt;/span&gt; cluster.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cluster includes two amd64 nodes and two arm64 nodes.&lt;/p&gt;

&lt;p&gt;It takes 15-20 minutes to launch the cluster so take a break while it is created.&lt;/p&gt;

&lt;p&gt;When the cluster is ready check the nodes by running &lt;code&gt;kubectl&lt;/code&gt; on your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output shows four nodes, but doesn't print the architecture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                             STATUS   ROLES    AGE    VERSION
ip-192-168-11-18.ec2.internal    Ready    &amp;lt;none&amp;gt;   106s   v1.27.5-eks-43840fb
ip-192-168-27-254.ec2.internal   Ready    &amp;lt;none&amp;gt;   71s    v1.27.5-eks-43840fb
ip-192-168-32-244.ec2.internal   Ready    &amp;lt;none&amp;gt;   106s   v1.27.5-eks-43840fb
ip-192-168-61-31.ec2.internal    Ready    &amp;lt;none&amp;gt;   72s    v1.27.5-eks-43840fb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the architecture run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get node &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[*].status.nodeInfo.architecture}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output shows four nodes, two of each architecture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arm64 amd64 amd64 arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Kubernetes cluster is now ready to use, and you can deploy the Go app. &lt;/p&gt;

&lt;h1&gt;
  
  
  Create a service to deploy
&lt;/h1&gt;

&lt;p&gt;To deploy the application create a text file named &lt;code&gt;hello-service.yaml&lt;/code&gt; with the contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello-service&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
    &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
    &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the service by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; hello-service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service/hello-service created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Deploy the amd64 application
&lt;/h1&gt;

&lt;p&gt;You can deploy the amd64 container first to demonstrate a single-architecture container. &lt;/p&gt;

&lt;p&gt;Create a text file named &lt;code&gt;amd64-deployment.yaml&lt;/code&gt; with the contents below. Make sure to use your Docker ID instead of &lt;code&gt;jasonrandrews&lt;/code&gt; in the file. Notice that the container image is &lt;code&gt;go-arch:amd64&lt;/code&gt;. The amd64 image will only run on amd64 nodes. The nodeSelector is used to make sure the continer is only scheduled on amd64.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amd-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
        &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jasonrandrews/go-arch:amd64&lt;/span&gt;
        &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NODE_NAME&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spec.nodeName&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POD_NAME&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metadata.name&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300m&lt;/span&gt;
      &lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;kubernetes.io/arch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amd64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the amd64 container by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; amd64-deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the running deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output shows 1 pod running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                              READY   STATUS    RESTARTS   AGE
amd-deployment-7d4d44889d-vzhpd   1/1     Running   0          9s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the endpoint of the service run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output prints the IP address of the load balancer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME            TYPE           CLUSTER-IP       EXTERNAL-IP                                                               PORT(S)        AGE
hello-service   LoadBalancer   10.100.188.181   a5d50ef4f76f3414a9f7e6e91ada5447-1826701750.us-east-1.elb.amazonaws.com   80:30489/TCP   70s
kubernetes      ClusterIP      10.100.0.1       &amp;lt;none&amp;gt;                                                                    443/TCP        14m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm the amd64 application is running use &lt;code&gt;curl&lt;/code&gt; and substitute the endpoint of your load balancer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; http://a5d50ef4f76f3414a9f7e6e91ada5447-1826701750.us-east-1.elb.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output displays the hello message from the application and confirms the architecture is amd64.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello from image NODE:ip-192-168-32-244.ec2.internal, POD:amd-deployment-7d4d44889d-vzhpd, CPU PLATFORM:linux/amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the address of your load balancer (the http address) and use it for the &lt;code&gt;curl&lt;/code&gt; commands in the following sections. &lt;/p&gt;

&lt;h1&gt;
  
  
  Deploy the arm64 application
&lt;/h1&gt;

&lt;p&gt;Create a text file named &lt;code&gt;arm64-deployment.yaml&lt;/code&gt; with the contents below. Again, substitute your Docker ID and notice that the nodeSelector is now arm64.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arm-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
        &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jasonrandrews/go-arch:arm64&lt;/span&gt;
        &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NODE_NAME&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spec.nodeName&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POD_NAME&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metadata.name&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300m&lt;/span&gt;
      &lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;kubernetes.io/arch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arm64&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the arm64 container by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; arm64-deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the running deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the output shows both deployments, amd64 and arm64.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                              READY   STATUS    RESTARTS   AGE
amd-deployment-7d4d44889d-vzhpd   1/1     Running   0          3m1s
arm-deployment-5996f6b85d-wp8cv   1/1     Running   0          10s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the &lt;code&gt;curl&lt;/code&gt; command a few times and you will see a mix of amd64 and arm64 messages printed, depending on which node services the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; http://a5d50ef4f76f3414a9f7e6e91ada5447-1826701750.us-east-1.elb.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Deploy the multi-architecture application
&lt;/h1&gt;

&lt;p&gt;You can also deploy the multi-architecture image.&lt;/p&gt;

&lt;p&gt;Create a text file named &lt;code&gt;multi-arch-deployment.yaml&lt;/code&gt; with the contents below. Again, substitute your Docker ID. The image is the multi-architecture image created with &lt;code&gt;docker buildx&lt;/code&gt; and 6 replicas are specified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;multi-arch-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
        &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jasonrandrews/go-arch-x:1.0&lt;/span&gt;
        &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NODE_NAME&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spec.nodeName&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POD_NAME&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metadata.name&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the multi-architecture container by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; multi-arch-deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the running deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the output shows all three deployments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                                     READY   STATUS    RESTARTS   AGE
amd-deployment-7d4d44889d-vzhpd          1/1     Running   0          4m24s
arm-deployment-5996f6b85d-wp8cv          1/1     Running   0          93s
multi-arch-deployment-547684cd44-7w6vf   1/1     Running   0          7s
multi-arch-deployment-547684cd44-chcc8   1/1     Running   0          7s
multi-arch-deployment-547684cd44-kw966   1/1     Running   0          7s
multi-arch-deployment-547684cd44-r4789   1/1     Running   0          7s
multi-arch-deployment-547684cd44-vqwc7   1/1     Running   0          7s
multi-arch-deployment-547684cd44-w4x8d   1/1     Running   0          7s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test the appliation, run a loop of &lt;code&gt;curl&lt;/code&gt; commands and see the output messages from the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 10&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;curl &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; http://a5d50ef4f76f3414a9f7e6e91ada5447-1826701750.us-east-1.elb.amazonaws.com&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will show a variety of amd64 and arm64 messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello from image NODE:ip-192-168-32-244.ec2.internal, POD:multi-arch-deployment-547684cd44-w4x8d, CPU PLATFORM:linux/amd64
Hello from image NODE:ip-192-168-61-31.ec2.internal, POD:multi-arch-deployment-547684cd44-r4789, CPU PLATFORM:linux/arm64
Hello from image NODE:ip-192-168-61-31.ec2.internal, POD:multi-arch-deployment-547684cd44-r4789, CPU PLATFORM:linux/arm64
Hello from image NODE:ip-192-168-27-254.ec2.internal, POD:multi-arch-deployment-547684cd44-kw966, CPU PLATFORM:linux/arm64
Hello from image NODE:ip-192-168-61-31.ec2.internal, POD:multi-arch-deployment-547684cd44-chcc8, CPU PLATFORM:linux/arm64
Hello from image NODE:ip-192-168-27-254.ec2.internal, POD:arm-deployment-5996f6b85d-wp8cv, CPU PLATFORM:linux/arm64
Hello from image NODE:ip-192-168-32-244.ec2.internal, POD:multi-arch-deployment-547684cd44-w4x8d, CPU PLATFORM:linux/amd64
Hello from image NODE:ip-192-168-32-244.ec2.internal, POD:multi-arch-deployment-547684cd44-w4x8d, CPU PLATFORM:linux/amd64
Hello from image NODE:ip-192-168-32-244.ec2.internal, POD:multi-arch-deployment-547684cd44-w4x8d, CPU PLATFORM:linux/amd64
Hello from image NODE:ip-192-168-61-31.ec2.internal, POD:multi-arch-deployment-547684cd44-r4789, CPU PLATFORM:linux/arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have now deployed single-architecture images for amd64 and arm64 as well as six copies of a multi-architecture image. &lt;/p&gt;

&lt;p&gt;You can use the same techniques to incrementally migrate applications from amd64 to arm64 and invesigate the price performance provided by AWS Graviton processors. &lt;/p&gt;

&lt;h1&gt;
  
  
  Delete the clusters
&lt;/h1&gt;

&lt;p&gt;When you are done, make sure to delete all AWS resources. &lt;/p&gt;

&lt;p&gt;You can clean up with a single &lt;code&gt;eckctl&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl delete cluster &lt;span class="nt"&gt;-n&lt;/span&gt; cluster1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>Arm Learning Paths</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Tue, 27 Jun 2023 13:29:20 +0000</pubDate>
      <link>https://forem.com/aws-builders/arm-learning-paths-297k</link>
      <guid>https://forem.com/aws-builders/arm-learning-paths-297k</guid>
      <description>&lt;p&gt;One of the reasons I joined the &lt;a href="https://aws.amazon.com/developer/community/community-builders/" rel="noopener noreferrer"&gt;AWS Community Builders program&lt;/a&gt; is to share articles about AWS Graviton processors in the &lt;a href="https://dev.to/aws-builders"&gt;AWS Community Builders DEV organization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After joining, I got started right away, and I try to share a handful of original articles every year. I feel like the material is well received, and I have provided a meaningful contribution for those learning about Graviton processors and the Arm architecture.&lt;/p&gt;

&lt;p&gt;I am now entering my 4th year in the Community Builders program.&lt;/p&gt;

&lt;p&gt;Last year, I noticed that my past articles might need some updating as things have changed since 2020. Software versions change, Windows 10 is now Windows 11, and new Graviton-based EC2 instance types are available.&lt;/p&gt;

&lt;p&gt;I also learned that blogging is not exactly the same thing as publishing hands-on how-to content for developers, especially in the updating area. After some research and development into what else would be useful for software developers, I’m excited to share &lt;a href="https://learn.arm.com" rel="noopener noreferrer"&gt;Arm Learning Paths&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Learning Paths provide long-form, written how-to content for software developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;As a long-time blogger, I have written many articles linking news and events with new tools, hardware, and software as a way to learn.&lt;/p&gt;

&lt;p&gt;Over time, the news fades, but the technical content is still important. Readers wonder if the material is still correct or if they should search for something else. Some of my past articles are currently in this state.&lt;/p&gt;

&lt;p&gt;I knew I wanted to share more written how-to content, but didn't always feel like writing more blogs was the answer.&lt;/p&gt;

&lt;p&gt;Documentation is another way to deliver written how-to content, but documentation is tied to a product such as a tool, software library, or API. It doesn't always provide the context and big picture about how things work. Sometimes documentation provides too much information.&lt;/p&gt;

&lt;p&gt;About a year ago, my small team started investigating long-form, written how-to content at Arm. We found useful content in many places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Guides on developer.arm.com&lt;/li&gt;
&lt;li&gt;Blogs on community.arm.com&lt;/li&gt;
&lt;li&gt;Articles on general social media sites such as LinkedIn&lt;/li&gt;
&lt;li&gt;Community specific sites such as blog.tensorflow.org, hackster.io and dev.to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have written and read articles in all these places. They are all fine, but none of them felt like what I wanted to do.&lt;/p&gt;

&lt;p&gt;To find out more, we conducted interviews and did market research into what developer surveys tell us.&lt;/p&gt;

&lt;p&gt;From the research, we established a list of things we wanted developers to be able to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explore platforms, tools, and software available for the Arm architecture&lt;/li&gt;
&lt;li&gt;Learn from hands-on, how-to content grouped by target hardware platforms&lt;/li&gt;
&lt;li&gt;Find out what’s possible and explore what can be done with Arm&lt;/li&gt;
&lt;li&gt;Understand the context and alternatives when there are multiple ways to do a task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two key points stood out.&lt;/p&gt;

&lt;p&gt;We needed to provide an easy environment for creators to publish to a location with high traffic.&lt;/p&gt;

&lt;p&gt;Learning Paths must be a community project for everyone to participate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Learning Paths
&lt;/h2&gt;

&lt;p&gt;Last year, we started to prototype the Learning Path website with the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast, static website on an arm.com URL&lt;/li&gt;
&lt;li&gt;Easy publishing flow using markdown files&lt;/li&gt;
&lt;li&gt;Community contributions via GitHub&lt;/li&gt;
&lt;li&gt;Appropriate governance&lt;/li&gt;
&lt;li&gt;Timeless, quality content&lt;/li&gt;
&lt;li&gt;Free from direct marketing&lt;/li&gt;
&lt;li&gt;Always up to date&lt;/li&gt;
&lt;li&gt;Automated testing and maintenance&lt;/li&gt;
&lt;li&gt;Open-source license which complies with Arm open-source requirements&lt;/li&gt;
&lt;li&gt;Analytics and dashboard&lt;/li&gt;
&lt;li&gt;No content behind a login&lt;/li&gt;
&lt;li&gt;Meets performance, security, and accessibility requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have now completed the Learning Path website with the listed characteristics and are ready to share it with you.&lt;/p&gt;

&lt;p&gt;Over the approximately one year of development, we have had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;15+ contributors&lt;/li&gt;
&lt;li&gt;Over 2000 git commits&lt;/li&gt;
&lt;li&gt;90+ Learning Paths&lt;/li&gt;
&lt;li&gt;45+ Install Guides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The content is now available on &lt;a href="//learn.arm.com"&gt;learn.arm.com&lt;/a&gt; for you to review and share. All content is stored in a &lt;a href="https://github.com/ArmDeveloperEcosystem/arm-learning-paths" rel="noopener noreferrer"&gt;GitHub project&lt;/a&gt; and uses &lt;a href="https://www.gohugo.io" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt; to generate a static website. The website automatically updates when new content is reviewed and accepted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give it a try
&lt;/h2&gt;

&lt;p&gt;There are a number of Learning Paths covering AWS services in the &lt;a href="https://learn.arm.com/learning-paths/servers-and-cloud-computing/" rel="noopener noreferrer"&gt;Servers and Cloud Computing&lt;/a&gt; category. &lt;/p&gt;

&lt;p&gt;Please share &lt;a href="https://learn.arm.com" rel="noopener noreferrer"&gt;learn.arm.com&lt;/a&gt; in places you connect with software developers and tool providers.&lt;/p&gt;

&lt;p&gt;You can create a Learning Path or submit improvements via GitHub. Click the &lt;strong&gt;Create&lt;/strong&gt; button on the front page to find out more about how to create a Learning Path. &lt;/p&gt;

&lt;p&gt;Feel free to send me a message for a 10-minute quick start.&lt;/p&gt;

&lt;p&gt;Time will tell how well the concept is received, but I hope Learning Paths become another useful place for creators to publish and readers to learn.&lt;/p&gt;

&lt;p&gt;I will continue to write here in the AWS Community Builders DEV organization also. Congratulations to everyone for creating so many useful articles.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>arm</category>
    </item>
    <item>
      <title>Improve data compression performance on AWS Graviton processors</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Thu, 15 Sep 2022 02:06:00 +0000</pubDate>
      <link>https://forem.com/aws-builders/improve-data-compression-performance-on-aws-graviton-processors-1pg0</link>
      <guid>https://forem.com/aws-builders/improve-data-compression-performance-on-aws-graviton-processors-1pg0</guid>
      <description>&lt;p&gt;Applications in many programming languages perform data compression. They commonly rely on zlib for easy handling of gzip files. This article explains how to improve performance of applications using zlib on AWS Graviton processors. &lt;/p&gt;

&lt;p&gt;Most Linux distributions use zlib without any optimizations. For the Arm architecture, this means that CRC (cyclic redundancy check) instructions are not utilized for best performance. Installing and using a zlib which has been optimized may provide performance improvement for applications doing data compression. Let's see how to do it with an example Python application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cloudflare/zlib.git"&gt;Cloudflare zlib&lt;/a&gt; is one version which has optimizations included. There are other zlib versions which have been optimized. The process to use them should be similar.&lt;/p&gt;

&lt;p&gt;This can be done on any Graviton-based instance. I did it with Ubuntu 22.04.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confirm crc32 is included in the processor flags
&lt;/h3&gt;

&lt;p&gt;All AWS Graviton processors and most Armv8.0-A and above processors have support for CRC instructions.&lt;/p&gt;

&lt;p&gt;To check if a Linux system has support, use the lscpu command and look for crc32 in the listed flags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;lscpu | grep crc32
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the machine is confirmed to include crc32 it may benefit from zlib-cloudflare. &lt;/p&gt;

&lt;h3&gt;
  
  
  Check if the default zlib includes crc32 instructions
&lt;/h3&gt;

&lt;p&gt;Some Linux systems may already make use of crc32 in the default library. If the default zlib is already optimized, then using zlib-cloudflare may not have any impact on performance. &lt;/p&gt;

&lt;p&gt;Ubuntu and Debian Linux distributions put zlib in /usr/lib/aarch64-linux-gnu&lt;/p&gt;

&lt;p&gt;Other software tools are needed to build zlib, so install them now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt install -y build-essential
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check if there are any CRC instructions in a library, use objdump to disassemble and look for crc32 instructions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;objdump -d /usr/lib/aarch64-linux-gnu/libz.so.1 | awk -F" " '{print $&lt;/span&gt;3&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;' | grep crc32 | wc -l
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the result is 0 then there are no crc32 instructions used in the library. &lt;/p&gt;

&lt;h3&gt;
  
  
  Install Cloudflare zlib
&lt;/h3&gt;

&lt;p&gt;If there are no crc32 instructions in zlib then zlib-cloudflare may help application performance. &lt;/p&gt;

&lt;p&gt;To build and install zlib-cloudflare navigate to an empty directory and use these commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;mkdir tmp ;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;pushd &lt;/span&gt;tmp
&lt;span class="go"&gt;git clone https://github.com/cloudflare/zlib.git
cd zlib &amp;amp;&amp;amp; ./configure 
make &amp;amp;&amp;amp; sudo make install
popd
rm -rf tmp
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If successful, zlib-cloudflare is installed in /usr/local/lib&lt;/p&gt;

&lt;p&gt;Confirm the new zlib has crc32 instructions. The objdump command should return a non-zero number now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;objdump -d /usr/local/lib/libz.so  | awk -F" " '{print $&lt;/span&gt;3&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;' | grep crc32 | wc -l
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To install zlib somewhere else, use the prefix argument to select another location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;./configure --prefix=$&lt;/span&gt;HOME/zlib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This results in zlib being installed in $HOME/zlib instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring zlib
&lt;/h3&gt;

&lt;p&gt;Below is a simple C program to demonstrate zlib usage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"zlib.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;gzFile&lt;/span&gt; &lt;span class="n"&gt;myfile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zlibVersion&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="n"&gt;myfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gzopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"testfile.gz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"wb"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;gzprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"Hello gzipped file!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;gzclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myfile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the text above as a file named test.c and compile the example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;gcc test.c -o test -lz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the program and see the version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;./test
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The printed version will be a number such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;1.2.11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use ldd to see the location of the shared library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;ldd ./test
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output shows the shared libraries used by test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;linux-vdso.so.1 (0x0000ffff91026000)
&lt;/span&gt;&lt;span class="gp"&gt;libz.so.1 =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/lib/aarch64-linux-gnu/libz.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x0000ffff90fa0000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;libc.so.6 =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/lib/aarch64-linux-gnu/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x0000ffff90df0000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;/lib/ld-linux-aarch64.so.1 (0x0000ffff90fed000)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set LD_PRELOAD to use zlib-cloudflare
&lt;/h3&gt;

&lt;p&gt;To run test with zlib-cloudflare instead of the default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;LD_PRELOAD=/usr/local/lib/libz.so ./test
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LD_PRELOAD variable informs the linker to use these libraries before the default libraries. &lt;/p&gt;

&lt;p&gt;The version of zlib-cloudflare will be printed. It may be older than the default, but we are interested in crc32 and not using the latest.&lt;/p&gt;

&lt;p&gt;Next, let's see how to use zlib-cloudflare in an application doing data compression. We can use a Python example and measure the performance difference with zlib-cloudflare.&lt;/p&gt;

&lt;p&gt;Copy and save the file below as zip.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;

&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16384&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;largefile&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;largefile.gz&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f_in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;f_out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;f_out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Ubuntu 22.04, configure python to be python3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt install python-is-python3 -y
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a large file to compress
&lt;/h3&gt;

&lt;p&gt;The above Python code will read a file named &lt;strong&gt;largefile&lt;/strong&gt; and write a compressed version as &lt;strong&gt;largefile.gz&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To create the input file, use the dd command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;dd if=/dev/zero of=largefile count=1M bs=1024
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the example using the default zlib
&lt;/h3&gt;

&lt;p&gt;Run with the default zlib and time the execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;time python ./zip.py
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make a note of the runtime. &lt;/p&gt;

&lt;h3&gt;
  
  
  Run the example again with zlib-cloudflare
&lt;/h3&gt;

&lt;p&gt;This time, use LD_PRELOAD to change to zlib-cloudflare and check the performance difference. &lt;/p&gt;

&lt;p&gt;Adjust the path to libz.so as needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;time LD_PRELOAD=/usr/local/lib/libz.so python ./zip.py
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the shorter runtime when zlib-cloudflare is used.&lt;/p&gt;

&lt;p&gt;Using a c6g.large EC2 instance, the time with the original zlib is about 7.25 seconds and with zlib-cloudflare the time is about 2.66 seconds. &lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;If you have applications using zlib make sure to check alternative versions of the library. &lt;a href="https://github.com/cloudflare/zlib.git"&gt;Cloudflare zlib&lt;/a&gt; is a good one, and there may be others available. Watch the &lt;a href="https://github.com/aws/aws-graviton-getting-started"&gt;AWS Graviton Getting Started&lt;/a&gt; for the latest information.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>python</category>
    </item>
    <item>
      <title>Using Docker manifest to create multi-arch images on AWS Graviton processors</title>
      <dc:creator>Jason Andrews</dc:creator>
      <pubDate>Wed, 31 Aug 2022 17:33:48 +0000</pubDate>
      <link>https://forem.com/aws-builders/using-docker-manifest-to-create-multi-arch-images-on-aws-graviton-processors-1320</link>
      <guid>https://forem.com/aws-builders/using-docker-manifest-to-create-multi-arch-images-on-aws-graviton-processors-1320</guid>
      <description>&lt;p&gt;Docker manifest is an experimental command to build docker images which support multiple architectures. Let's see how it works and compare it to docker buildx.&lt;/p&gt;

&lt;p&gt;In 2019, &lt;a href="https://docs.docker.com/build/buildx" rel="noopener noreferrer"&gt;docker buildx&lt;/a&gt; was created as a way to build multi-architecture images. At the time, developers didn't have Arm in the cloud or on their desk. Projects were interested in the Arm architecture, but as a secondary option for AWS Graviton or even Raspberry Pi. With buildx, a single build command creates a multi-architecture image. In some cases, an Arm machine is not even needed for the build.&lt;/p&gt;

&lt;p&gt;Today, developers are using the Arm architecture on their desk and in the cloud. The trailblazing success of &lt;a href="https://aws.amazon.com/ec2/graviton/" rel="noopener noreferrer"&gt;AWS Graviton processors&lt;/a&gt; has motivated developers to try out Graviton for themselves. The popularity of Mac computers with Apple silicon means many developers have the same architecture on their desk. Today, I will explain how to build multi-arch images using the docker manifest command. I have found this to be the easiest way to create multi-arch images for many projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Docker buildx provides a build command to create images for multiple architectures. I’m primarily using arm64 and amd64. If you use other architectures, the concept can easily be extended. &lt;/p&gt;

&lt;p&gt;The challenge with buildx is that it uses emulation, cross-compilation, or a remote builder for the target architectures which do not match the build machine. Emulation works fine for building images which primarily copy and install files, but it can suffer from functional issues or performance problems for more complex image building. Sometimes cross-compilation is easy, but sometimes it is difficult. Using a remote builder is not convenient for testing changes. Changing the remote builder setup while testing can be confusing.  &lt;/p&gt;

&lt;p&gt;Docker buildx also confuses developers who are expecting a local image to immediately run after a successful build. Because buildx targets multiple architectures, it must be saved to a repository, not local storage. This requires a push to a repository and then a pull to run. There are some other workarounds, but the use model is different from what many developers expect. Searching Stack Overflow and GitHub confirms that a missing image after successfully running buildx is a common question.  &lt;/p&gt;

&lt;p&gt;I spend the majority of my time on the Arm architecture. A shrinking number of projects require amd64 support, but when they do, I find myself shying away from buildx. Docker buildx is one way to approach the challenges of multiple architectures, but docker manifest feels easier for me.  &lt;/p&gt;

&lt;p&gt;Let's see how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker manifest
&lt;/h3&gt;

&lt;p&gt;Docker includes an experimental feature called &lt;a href="https://docs.docker.com/engine/reference/commandline/manifest/" rel="noopener noreferrer"&gt;docker manifest&lt;/a&gt;. Please be aware the feature is experimental and not recommended for production use.&lt;/p&gt;

&lt;p&gt;Docker manifest provides a different way of working. It allows separate images to be built for each architecture, which can be joined into a multi-arch image when it's time to share. This enables me to build and test on any architecture and postpone using multi-arch until later. When it's time to share a multi-arch image, it can be created in seconds using docker manifest. Docker manifest also makes it easy to update one of the architectures without emulation or remote builders. &lt;/p&gt;

&lt;p&gt;Let’s do a quick comparison between buildx and docker manifest.&lt;/p&gt;

&lt;p&gt;Here is a small example Dockerfile.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

FROM alpine AS builder
RUN apk add build-base
WORKDIR /home
COPY hello.c .
RUN gcc "-DARCH=\"`uname -a`\"" hello.c -o hello

FROM alpine
WORKDIR /home
COPY --from=builder /home/hello .
CMD ["./hello"]


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The Dockerfile compiles and runs a hello world C program.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef ARCH
#define ARCH "Undefined"
#endif
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello Arm Developers, architecture from uname is %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ARCH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"32-bit userspace&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"64-bit userspace&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;default:&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unknown userspace&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Copy the Dockerfile and hello.c to your computer for the steps below. &lt;/p&gt;

&lt;p&gt;Let’s see how to use it with buildx to build a multi-architecture image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker buildx
&lt;/h3&gt;

&lt;p&gt;Using buildx involves setting up a builder and running the buildx command. &lt;/p&gt;

&lt;p&gt;Below is a script showing how to use buildx. Copy the file, change the HUBU variable to your Docker Hub username, and run the script to try it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;HUBU&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hubuser
&lt;span class="nv"&gt;IMG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hello-world

docker buildx create &lt;span class="nt"&gt;--name&lt;/span&gt; mybuilder
docker buildx use mybuilder
docker buildx build &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64,linux/arm64 &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$HUBU&lt;/span&gt;/&lt;span class="nv"&gt;$IMG&lt;/span&gt; &lt;span class="nt"&gt;--push&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The script automatically pushes the multi-arch image to Docker Hub. Without the push argument, the results will not be available. It’s easy enough to pull the image and run it, but with a larger image it does take time to push to the registry and pull it back.&lt;/p&gt;

&lt;p&gt;There are numerous tutorials about using buildx if you want to learn more. &lt;/p&gt;

&lt;h3&gt;
  
  
  Docker manifest
&lt;/h3&gt;

&lt;p&gt;The docker manifest command is useful to combine multiple existing images into a single multi-architecture image. &lt;/p&gt;

&lt;p&gt;To keep track of the images, I use the image tag to indicate the architecture. &lt;/p&gt;

&lt;p&gt;To build the same Dockerfile without buildx use this command. This produces a single image, just for the architecture of the current machine.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;docker build -t hello-world:$&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The image is available locally to run. On AWS Graviton, the tag will be aarch64 to differentiate it from the same command run on an x86_64 machine.&lt;/p&gt;

&lt;p&gt;After building an image on each machine you want to support, tag the images for a Docker Hub account and push. Again, change to your Docker Hub username to try it. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

docker tag hello-world:$(arch) jasonrandrews/hello-world:$(arch)
docker push jasonrandrews/hello-world:$(arch)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The image below shows both tags in Docker Hub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbln0sbg34cuc23c6ajbn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbln0sbg34cuc23c6ajbn.png" alt="Two images with architecture tags"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last step is to join the two tags into a single multi-architecture image. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

docker manifest create jasonrandrews/hello-world:latest \
--amend jasonrandrews/hello-world:aarch64 \
--amend jasonrandrews/hello-world:x86_64

docker manifest push --purge jasonrandrews/hello-world:latest


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The purge option is not needed the first time, but I found that to update one of the images and update the multi-arch image it was needed. &lt;/p&gt;

&lt;p&gt;After the manifest push, a new multi-arch image with the latest tag is available. Pulling hello-world:latest from either architecture now works, and a user doesn't need to pay attention to the computer they are using. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64kff8r14hhfecde1kei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64kff8r14hhfecde1kei.png" alt="Multi-arch image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;The experimental docker manifest command offers a way to create multi-architecture images by joining multiple images using a manifest. Docker manifest provides additional features not covered here, and is useful to create, inspect, and modify manifest lists. As the docker manifest command matures and developers increase AWS Graviton usage, it provides another way to build docker images.&lt;/p&gt;

&lt;p&gt;Give it a try and see how it works. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
