# Build multi-CPU architecture compatible Container Images

<img src="https://i.giphy.com/media/IcZhFmufozDCij3p22/giphy.webp" style="display: block; margin: 0 auto;" /> 

Today, we are going to learn how we can build docker images for containers that will be compatible with the amd64 and arm64 CPU architecture types.

I chose these two CPU types because **amd64** is already widely used with our Linux/Windows/Mac Computers and **arm64** is getting popular nowadays, for example - new Mac computers are coming with Apple's in-house M1 processor which is arm64 based and if you talk about Cloud, AWS is offering various VMs which are powered by Graviton processors which are again arm64 based, So if your container images are able to run on these two kinds of CPUs, you will be able to utilize most of it. 

Along with that what I want is that we understand each and every word that we will be using.

---

### What is CPU?

CPU is short for Central Processing Unit, which is generally called processor(or microprocessor).

Also called the heart/brain of the computer. It performs all arithmetic and logical operations. 

Inside the CPU, there are transistors, which control the flow of electricity. You know, a CPU can perform millions of instructions per second but can only do one instruction at any given point in time. 

Then we have multi-core CPUs, each core is a sort of separate CPU, which can help the CPU to do multiple tasks simultaneously. 

Read these for more details on:
1. What is CPU - https://www.freecodecamp.org/news/what-is-cpu-meaning-definition-and-what-cpu-stands-for/
2. How does a CPU work - https://www.freecodecamp.org/news/how-does-a-cpu-work/

---

### What are ISA & Micro-architecture?

An **instruction set** is a group of commands for a central processing unit (CPU) in machine language.

Now, ISA (instruction set architecture) is a part of processor architecture. It works as an interface(communication rules) between hardware and software. It's a group of commands which are implemented in the processor's circuitry also called **microarchitecture**. 

Few examples of what ISA defines: 
1. How binary instructions are formatted
2. How RAM/ROM is accessed
3. Maximum bit length for all instructions

It helps us to separate hardware and software development without worrying about the other. 

ISA has two major classifications : 
1. **CISC - Complex instruction set computer**

It includes many specialized instructions. It will use fewer instructions but each instruction will take multiple machine cycles. 

2. **RISC - Reduced instruction set computer**

It uses a smaller, optimized set of generalized, simple instructions. It will use more number of instructions but each instruction will take one clock cycle. 

--- 

### What is amd64?

Before that let's see what is 32-bit/64-bit architecture - 
It simply defines that in a single **instruction cycle** (*fetch-decode-execute*) how much data a microprocessor can process.

32-bit means it can process 4 bytes of data and for 64-bit it is 8 bytes. 

**x86** is a family of instruction set architectures (ISA) for computer processors initially developed by Intel. (**86** comes from the microprocessor name which was **8086** )

AMD took this x86 architecture which could only support 32-bit and then added 64-bit computing capabilities, that's why it is known as **amd64**. Also referred to as, Intel 64, x86-64, x64.

---

### What is arm64, then?

Let's understand what are ARM Processors first. 

ARM stands for **Advance RISC Machine** - It is an ISA developed by a company called ARM Ltd. 

So, ARM Licenses the architecture to other companies so they can develop their custom processors. Example - Apple's Silicon processors. 

ARM Processors are generally used in smartphones, tablets, IoT devices, etc. due to their low power consumption and high-performance nature.
 
**So ARM64 is the 64-Bit version of ARM processors(aka ARMv8-A).**

--- 

### Back to Docker Image Building

So now as we have some sort of idea about CPUs, we can guess that when we build docker images on a machine with specific architecture(amd64 or arm64), it is compiled in a way that it can run only on that specific type of platforms. 

So what we will try to solve here is to build universal docker images, which can run on these platforms, without us worrying about the rebuilding of images.   


---

### Hands-On: Running Docker Image cross-platform

I built a docker image on my Macbook with an M1 Pro chip (arm64) and then tried to run it on an EC2 with an amd64 processor, this was the output : 


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660454463254/Q9ydqlFga.png align="left")

```
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested.

exec /docker-entrypoint.sh: exec format error
```

--- 

### Docker Buildx for the rescue!!!

<img src="https://i.giphy.com/media/7QxG5242BM12HQk1KR/giphy.webp">

`docker buildx` is a CLI plugin that enhances the existing docker build capabilities. (which uses another open-source project called [buildkit](https://github.com/moby/buildkit).)

*BuildKit is a toolkit for converting source code to **build artifacts** in an efficient, expressive, and repeatable manner.*

If you want to know more about `moby/buildkit` you can read this Introductory blog post: https://blog.mobyproject.org/introducing-buildkit-17e056cc5317

You can refer to this [Installation guide](https://github.com/docker/buildx#installing) on how to install `buildx` into your system, It comes pre-installed with Docker Desktop for Windows/macOS.


### Let's use buildx to build our docker images

#### Step-1: List existing builders

```bash
docker buildx ls
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660479961330/2cQQhEfZa.png align="left")

#### Step-2: Create a new builder to support multi-architecture
```bash
docker buildx create --name mybuilder --driver docker-container --use --bootstrap
```
 
We are instructing `docker` to create a new **buildx builder** named `mybuilder` which will use the `docker-container` driver (which supports multi-architecture builds), also instructing it to use this new builder, also instructing this to boot this builder which means it will pull necessary docker image to run this builder and run the builder container. (as our `driver` is **docker-container**) 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661830894788/ME-e1tWnF.png align="left")

#### Step-3: Create a Sample Dockerfile

Consider this simple Dockerfile, which intends to run an NGINX server 

**Dockerfile**

```Dockerfile
FROM nginx:stable-alpine

LABEL MAINTAINER="KRATIK JAIN"

COPY --chmod=0755 custom-web-page.sh /docker-entrypoint.d/

``` 

**custom-web-page<span>.</span>sh**

```sh
#!/bin/sh
uname -a > /usr/share/nginx/html/index.html
```

*what this script does is replaces default HTML with the output of `uname -a`, which prints out the system info like kernel info, Architecture, etc.*

#### Step-4: Build the container image using the buildx 
```
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t k4kratik/multi-platform:v1 --push .
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662869733025/Ao1lvLez3.png align="left")

Here you can notice the flag `--platform` & `--push`: here you are specifying the platforms for which you want to build the image, and you also wish to push the image once done. That's amazing as build and push commands are in just one command. Output also seems to be more verbose. 

#### Step-5: Run this docker image on various platforms
#### Step-5.1: Running on EC2 with `amd64` arch Ubuntu machine
```bash
docker run --rm -itd -p 30000:80 k4kratik/multi-platform:v1
``` 
Now hit the server endpoint and check the response 
```bash
curl localhost:30000
```

**Output**
```
Linux e14cc6b4eb86 5.15.0-1011-aws #14-Ubuntu SMP Wed Jun 1 20:54:22 UTC 2022 x86_64 Linux
```

#### Step-5.2: Running on Macbook Pro with `arm64` arch M1 Chip
```bash
docker run --rm -itd -p 30000:80 k4kratik/multi-platform:v1
``` 

Now hit the server endpoint and check the response
```bash
curl localhost:30000
```

**Output**
```
Linux 595316994de1 5.10.104-linuxkit #1 SMP PREEMPT Thu Mar 17 17:05:54 UTC 2022 aarch64 Linux
```

Notice the output from both of the machines and observe the second last string, for EC2, it was: `x86_64` and for Macbook it was `aarch64`
which means it pulled the image according to its CPU architecture.
 
#### Bonus: Inspect Images
Using the below command you can inspect the image to know more details about it and to know the platforms available:
```bash
docker buildx imagetools inspect k4kratik/multi-platform:v1
``` 
**Output**
```YAML
Name:      docker.io/k4kratik/multi-platform:v1
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:c534475bb099316622a719407a17e2da21d79d147e9f607b4a1262c2a6f3bb1a
           
Manifests: 
  Name:      docker.io/k4kratik/multi-platform:v1@sha256:1d321fb1d14afe61e6f5c9ea2fc7e1b20bddd347c98a1b09f9367a6c446898b9
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64
             
  Name:      docker.io/k4kratik/multi-platform:v1@sha256:47b6ffc133acac83fc70dd176606de8b033ae735d386160e6d68ee7d472119b3
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64
             
  Name:      docker.io/k4kratik/multi-platform:v1@sha256:89f7b675b538e2aafe060dda535a48311bd090c63d0e3bb0184a440a32079f7d
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7
```

#### Bonus: Pull/Run Image of a specific platform
You can use the following flag to pull or run an image of a specific platform

```bash
docker pull --platform linux/arm64 alpine:latest
```

```bash
docker run -itd --platform linux/arm64 nginx-alpine:latest
```

<p align="center">
<img src="https://i.giphy.com/media/l2QEdoFAgf1zmhEK4/giphy.webp">
</p>


Well, it was just scratching the surface. I hope it was helpful enough for you to get started on your feet so you can research and dig down further. 

See you in the next blog! 
:)

**Update**: I can not express my happiness when I got to know that many people are reacting to this blog and this blog got featured on [Hashnode](https://www.hashnode.com)

Thank you so much 🫶🏻 everyone! You just made my day 🥂

🛣

