Using Linuxkit to Build an AWS Image (AMI)

Linuxkit is one of the tools developed by Docker and Docker community. I recently created a video “An Overall View On Docker & Its Ecosystem — Docker, Swarm, Kubernetes, Moby, Containerd, RunC ..” in which I made a quick presentation about Linuxkit:

You may be interested in getting my free guide 10 Great Tips To Learn Docker an joining DevOpsLinks community.

I was playing with Linuxkit and I wanted to share with you the steps to create an AWS image using this tool.

Configure AWS

You need to have an AWS account with your AWS credentials configured.

apt-get install -y aws-cli
aws configure

The second thing you need to do is setting up the region you’re going to use fr this tutorial:

export AWS_REGION=eu-west-1

Install Go

Follow the instructions in the official guide here

Install LinuxKit

go get -u github.com/linuxkit/linuxkit/src/cmd/linuxkit

You can also install it from the source:

mkdir -p ~/temp/
cd ~/temp/
git clone https://github.com/linuxkit/linuxkit
cd ~/temp/linuxkit

Build and install

make clean
make
make install

After executing the last command, copy the executable under the system bin directory:

cp ~/temp/linuxkit/bin/* /usr/local/bin

If you’re using a Mac:

brew tap linuxkit/linuxkit
brew install --HEAD linuxkit

Building The First Image

We are going to use one of the examples:

ls -l  examples/
total 96
-rw-rw-r-- 1 eon01 eon01 889 janv. 26 01:55 aws.yml
-rw-rw-r-- 1 eon01 eon01 552 janv. 26 01:55 azure.yml
-rw-rw-r-- 1 eon01 eon01 1576 janv. 26 01:55 cadvisor.yml
-rw-rw-r-- 1 eon01 eon01 1030 janv. 26 01:55 docker-for-mac.md
-rw-rw-r-- 1 eon01 eon01 4333 janv. 26 01:55 docker-for-mac.yml
-rw-rw-r-- 1 eon01 eon01 1341 janv. 26 01:55 docker.yml
-rw-rw-r-- 1 eon01 eon01 970 janv. 26 01:55 gcp.yml
-rw-rw-r-- 1 eon01 eon01 906 janv. 26 01:55 getty.yml
-rw-rw-r-- 1 eon01 eon01 1288 janv. 26 01:55 hostmount-writeable-overlay.yml
-rw-rw-r-- 1 eon01 eon01 445 janv. 26 01:55 minimal.yml
-rw-rw-r-- 1 eon01 eon01 455 janv. 26 01:55 node_exporter.yml
-rw-rw-r-- 1 eon01 eon01 938 janv. 26 01:55 openstack.yml
-rw-rw-r-- 1 eon01 eon01 538 janv. 26 01:55 packet.arm64.yml
-rw-rw-r-- 1 eon01 eon01 947 janv. 26 01:55 packet.yml
-rw-rw-r-- 1 eon01 eon01 876 janv. 26 01:55 redis-os.yml
-rw-rw-r-- 1 eon01 eon01 745 janv. 26 01:55 sshd.yml
-rw-rw-r-- 1 eon01 eon01 994 janv. 26 01:55 swap.yml
-rw-rw-r-- 1 eon01 eon01 853 janv. 26 01:55 tpm.yml
-rw-rw-r-- 1 eon01 eon01 711 janv. 26 01:55 vmware.yml
-rw-rw-r-- 1 eon01 eon01 986 janv. 26 01:55 vpnkit-forwarder.yml
-rw-rw-r-- 1 eon01 eon01 563 janv. 26 01:55 vsudd-containerd.yml
-rw-rw-r-- 1 eon01 eon01 970 janv. 26 01:55 vultr.yml
-rw-rw-r-- 1 eon01 eon01 2208 janv. 26 01:55 wireguard.yml

As you may guess, the example we’re going to use is:

aws.yml

In order to create a raw image, use:

linuxkit build -format aws examples/aws.yml

This is the content of the the aws.yml:

kernel:
image: linuxkit/kernel:4.9.78
cmdline: "console=ttyS0"
init:
- linuxkit/init:v0.2
- linuxkit/runc:v0.2
- linuxkit/containerd:v0.2
- linuxkit/ca-certificates:v0.2
onboot:
- name: sysctl
image: linuxkit/sysctl:v0.2
- name: dhcpcd
image: linuxkit/dhcpcd:v0.2
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
- name: metadata
image: linuxkit/metadata:v0.2
services:
- name: rngd
image: linuxkit/rngd:v0.2
- name: sshd
image: linuxkit/sshd:v0.2
binds:
- /run/config/ssh/authorized_keys:/root/.ssh/authorized_keys
- name: nginx
image: nginx:alpine
capabilities:
- CAP_NET_BIND_SERVICE
- CAP_CHOWN
- CAP_SETUID
- CAP_SETGID
- CAP_DAC_OVERRIDE
binds:
- /etc/resolv.conf:/etc/resolv.conf
trust:
org:
- linuxkit
- library

The yaml format specifies the image to be built:

  • kernel specifies a kernel Docker image, containing a kernel and a filesystem tarball, eg containing modules. The example kernels are built from kernel/
  • init is the base init process Docker image, which is unpacked as the base system, containing init, containerd, runc and a few tools. Built from pkg/init/
  • onboot are the system containers, executed sequentially in order. They should terminate quickly when done.
  • services is the system services, which normally run for the whole time the system is up
  • files are additional files to add to the image

(source)

You can more information about how to use yaml to create your custom image here.

Pushing the image to AWS

VM Import (the service we are going to use to push the image to AWS) requires a role to perform certain operations in your account, such as downloading disk images from an Amazon S3 bucket.

You must create a role named vmimport with a trust relationship policy document that allows VM Import to assume the role, and you must attach an IAM policy to the role.

(more details here)

Create a file called:

trust-policy.json

Insert the following policy:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "vmie.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals":{
"sts:Externalid": "vmimport"
}
}
}
]
}

Now execute:

aws iam create-role --role-name vmimport --assume-role-policy-document file://trust-policy.json

Create a bucket:

aws s3 mb s3://disk-image-file-bucket

Create a file named

role-policy.json

Add this policy :

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::disk-image-file-bucket"
]
},
{
"Effect": "Allow",
"Action":[
"ec2:ModifySnapshotAttribute",
"ec2:CopySnapshot",
"ec2:RegisterImage",
"ec2:Describe*",
"ec2:FullAccess"
],
"Resource": "*"
}
]
}

Now execute:

aws iam put-role-policy --role-name vmimport --policy-name vmimport --policy-document file://role-policy.json

Finally, push the image:

linuxkit push aws -bucket disk-image-file-bucket aws.raw

You should of course change disk-image-file-bucket by the name of the bucket you created.

If you need to set a timeout on the latest operation:

linuxkit push aws -bucket bucketname -timeout 1200 aws.raw

This operation will use the raw image and push it to the bucket, then create an AMI that you an find in your list of your custom AWS AMI.

Running an AWS instance using this image

You can simply execute:

linuxkit run aws aws

Or use AWS console to create an EC2 machine using the new AMI.

Connect Deeper

If you liked this article, you’ll like my training Painless Docker, give it a try.

You may be interested in getting my free guide 10 Great Tips To Learn Docker an joining DevOpsLinks community.