mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-23 11:00:25 +00:00
Merge pull request #116 from nathanleclaire/bake_ami
[WIP] Add structure to enable baking Moby Linux AMI
This commit is contained in:
commit
9cd184e420
14
alpine/Dockerfile.ami
Normal file
14
alpine/Dockerfile.ami
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
RUN apk add --update \
|
||||||
|
python \
|
||||||
|
py-pip \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
e2fsprogs \
|
||||||
|
jq \
|
||||||
|
syslinux
|
||||||
|
RUN pip install -U awscli
|
||||||
|
COPY aws/bake-ami.sh .
|
||||||
|
|
||||||
|
ENTRYPOINT ["./bake-ami.sh"]
|
@ -48,6 +48,13 @@ initrd-arm.img: Dockerfile.armhf
|
|||||||
docker-compose build arm
|
docker-compose build arm
|
||||||
docker-compose run --rm -T arm /bin/mkinitrd.sh > $@
|
docker-compose run --rm -T arm /bin/mkinitrd.sh > $@
|
||||||
|
|
||||||
|
ami: initrd.img
|
||||||
|
$(MAKE) -C kernel
|
||||||
|
$(MAKE) -C packages
|
||||||
|
docker-compose build ami
|
||||||
|
docker-compose run --rm -T ami clean
|
||||||
|
docker-compose run --rm -T ami bake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f initrd.img initrd.img.gz initrd-arm.img Dockerfile.armhf etc/inittab
|
rm -f initrd.img initrd.img.gz initrd-arm.img Dockerfile.armhf etc/inittab
|
||||||
rm -f mobylinux-bios.iso mobylinux-efi.iso mobylinux.efi
|
rm -f mobylinux-bios.iso mobylinux-efi.iso mobylinux.efi
|
||||||
|
1
alpine/aws/.gitignore
vendored
Normal file
1
alpine/aws/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.out
|
220
alpine/aws/bake-ami.sh
Executable file
220
alpine/aws/bake-ami.sh
Executable file
@ -0,0 +1,220 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script to automate creation and snapshotting of a Moby AMI. Currently, it's
|
||||||
|
# intended to be invoked from an instance running in the same region as the
|
||||||
|
# target AMI will be in, since it directly mounts the created EBS volume as a
|
||||||
|
# device on this running instance.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TAG_KEY=moby-bake
|
||||||
|
INSTANCE_METADATA_API_ENDPOINT=http://169.254.169.254/latest/meta-data/
|
||||||
|
|
||||||
|
# TODO(nathanleclaire): This could be calculated dynamically to avoid conflicts.
|
||||||
|
EBS_DEVICE=/dev/xvdb
|
||||||
|
|
||||||
|
function arrowecho () {
|
||||||
|
echo " --->" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function current_instance_az () {
|
||||||
|
curl -s ${INSTANCE_METADATA_API_ENDPOINT}/placement/availability-zone
|
||||||
|
}
|
||||||
|
|
||||||
|
function current_instance_id () {
|
||||||
|
curl -s ${INSTANCE_METADATA_API_ENDPOINT}/instance-id
|
||||||
|
}
|
||||||
|
|
||||||
|
# We tag resources created as part of the build to ensure that they can be
|
||||||
|
# cleaned up later.
|
||||||
|
function tag () {
|
||||||
|
arrowecho "Tagging $1"
|
||||||
|
aws ec2 create-tags --resources "$1" --tags Key=${TAG_KEY},Value= >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_device () {
|
||||||
|
arrowecho "Waiting for EBS device to appear in build container"
|
||||||
|
|
||||||
|
while [[ ! -e ${EBS_DEVICE} ]]; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# This heredoc might be confusing at first glance, so here is a detailed
|
||||||
|
# summary of what each line does:
|
||||||
|
#
|
||||||
|
# n - create new partition
|
||||||
|
# p - make it a primary partition
|
||||||
|
# 1 - it should be partition #1
|
||||||
|
# \n - use default first cylinder
|
||||||
|
# \n - use default last cylinder
|
||||||
|
# a - toggle a partition as bootable
|
||||||
|
# 1 - do the 1st partition specifically
|
||||||
|
# w - write changes and exit
|
||||||
|
arrowecho "Formatting boot partition"
|
||||||
|
fdisk ${EBS_DEVICE} >/dev/null << EOF
|
||||||
|
n
|
||||||
|
p
|
||||||
|
1
|
||||||
|
|
||||||
|
|
||||||
|
a
|
||||||
|
1
|
||||||
|
w
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# To ensure everything went smoothly, print the resulting partition table.
|
||||||
|
echo
|
||||||
|
arrowecho "Printing device partition contents"
|
||||||
|
fdisk -l ${EBS_DEVICE}
|
||||||
|
|
||||||
|
ROOT_PARTITION="${EBS_DEVICE}1"
|
||||||
|
ROOT_PARTITION_MOUNT="/mnt/moby"
|
||||||
|
|
||||||
|
# Mount created root partition, format it as ext4, and copy over the needed
|
||||||
|
# files for boot (syslinux configuration, kernel binary, and initrd.img)
|
||||||
|
arrowecho "Making filesystem on partition 1"
|
||||||
|
mke2fs -t ext4 ${ROOT_PARTITION}
|
||||||
|
|
||||||
|
arrowecho "Mounting partition filesystem"
|
||||||
|
mkdir ${ROOT_PARTITION_MOUNT}
|
||||||
|
mount -t ext4 ${ROOT_PARTITION} ${ROOT_PARTITION_MOUNT}
|
||||||
|
|
||||||
|
arrowecho "Copying image and kernel binary to partition"
|
||||||
|
|
||||||
|
# Get files needed to boot in place.
|
||||||
|
cp /mnt/syslinux.cfg ${ROOT_PARTITION_MOUNT}
|
||||||
|
cp /mnt/kernel/vmlinuz64 ${ROOT_PARTITION_MOUNT}
|
||||||
|
cp /mnt/initrd.img ${ROOT_PARTITION_MOUNT}
|
||||||
|
|
||||||
|
# From http://www.syslinux.org/wiki/index.php?title=EXTLINUX:
|
||||||
|
#
|
||||||
|
# "Note that EXTLINUX installs in the filesystem partition like a
|
||||||
|
# well-behaved bootloader :). Thus, it needs a master boot record in the
|
||||||
|
# partition table; the mbr.bin shipped with SYSLINUX should work well."
|
||||||
|
|
||||||
|
# Thus, this step installs syslinux on the mounted filesystem (partition
|
||||||
|
# 1).
|
||||||
|
arrowecho "Installing syslinux to partition"
|
||||||
|
extlinux --install ${ROOT_PARTITION_MOUNT}
|
||||||
|
|
||||||
|
# Format master boot record in partition table on target device.
|
||||||
|
arrowecho "Copying MBR to partition table in target device"
|
||||||
|
dd if=/usr/share/syslinux/mbr.bin of=${EBS_DEVICE} bs=440 count=1
|
||||||
|
|
||||||
|
umount ${ROOT_PARTITION_MOUNT}
|
||||||
|
|
||||||
|
arrowecho "Checking device/partition sanity"
|
||||||
|
fdisk -l ${EBS_DEVICE}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bake_image () {
|
||||||
|
# Create a new EBS volume. We will format this volume to boot into Moby
|
||||||
|
# initrd via syslinux in MBR. That formatted drive can then be snapshotted
|
||||||
|
# and turned into an AMI.
|
||||||
|
VOLUME_ID=$(aws ec2 create-volume \
|
||||||
|
--size 1 \
|
||||||
|
--availability-zone $(current_instance_az) | jq -r .VolumeId)
|
||||||
|
|
||||||
|
tag ${VOLUME_ID}
|
||||||
|
|
||||||
|
aws ec2 wait volume-available --volume-ids ${VOLUME_ID}
|
||||||
|
|
||||||
|
arrowecho "Attaching volume"
|
||||||
|
aws ec2 attach-volume \
|
||||||
|
--volume-id ${VOLUME_ID} \
|
||||||
|
--device ${EBS_DEVICE} \
|
||||||
|
--instance-id $(current_instance_id) >/dev/null
|
||||||
|
|
||||||
|
aws ec2 wait volume-in-use --volume-ids ${VOLUME_ID}
|
||||||
|
|
||||||
|
format_device
|
||||||
|
|
||||||
|
arrowecho "Taking snapshot!"
|
||||||
|
|
||||||
|
# Take a snapshot of the volume we wrote to.
|
||||||
|
SNAPSHOT_ID=$(aws ec2 create-snapshot \
|
||||||
|
--volume-id ${VOLUME_ID} \
|
||||||
|
--description "Snapshot of Moby device for AMI baking" | jq -r .SnapshotId)
|
||||||
|
|
||||||
|
tag ${SNAPSHOT_ID}
|
||||||
|
|
||||||
|
arrowecho "Waiting for snapshot completion"
|
||||||
|
|
||||||
|
aws ec2 wait snapshot-completed --snapshot-ids ${SNAPSHOT_ID}
|
||||||
|
|
||||||
|
# Convert that snapshot into an AMI as the root device.
|
||||||
|
IMAGE_ID=$(aws ec2 register-image \
|
||||||
|
--name "Moby Linux" \
|
||||||
|
--description "The best OS for running Docker" \
|
||||||
|
--architecture x86_64 \
|
||||||
|
--root-device-name "${EBS_DEVICE}" \
|
||||||
|
--virtualization-type "hvm" \
|
||||||
|
--block-device-mappings "[
|
||||||
|
{
|
||||||
|
\"DeviceName\": \"${EBS_DEVICE}\",
|
||||||
|
\"Ebs\": {
|
||||||
|
\"SnapshotId\": \"${SNAPSHOT_ID}\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]" | jq -r .ImageId)
|
||||||
|
|
||||||
|
tag ${IMAGE_ID}
|
||||||
|
|
||||||
|
# Boom, now you (should) have a Moby AMI.
|
||||||
|
arrowecho "Created AMI: ${IMAGE_ID}"
|
||||||
|
|
||||||
|
echo ${IMAGE_ID} >/mnt/aws/ami_id.out
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean_tagged_resources () {
|
||||||
|
if [[ -d /mnt/moby ]]; then
|
||||||
|
rm -rf /mnt/moby
|
||||||
|
fi
|
||||||
|
|
||||||
|
VOLUME_ID=$(aws ec2 describe-volumes --filters "Name=tag-key,Values=$TAG_KEY" | jq -r .Volumes[0].VolumeId)
|
||||||
|
if [[ ${VOLUME_ID} == "null" ]]; then
|
||||||
|
arrowecho "No volume found, skipping"
|
||||||
|
else
|
||||||
|
arrowecho "Detaching volume"
|
||||||
|
aws ec2 detach-volume --volume-id ${VOLUME_ID} >/dev/null
|
||||||
|
aws ec2 wait volume-available --volume-ids ${VOLUME_ID}
|
||||||
|
arrowecho "Deleting volume"
|
||||||
|
aws ec2 delete-volume --volume-id ${VOLUME_ID} >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE_ID=$(aws ec2 describe-images --filters "Name=tag-key,Values=$TAG_KEY" | jq -r .Images[0].ImageId)
|
||||||
|
if [[ ${IMAGE_ID} == "null" ]]; then
|
||||||
|
arrowecho "No image found, skipping"
|
||||||
|
else
|
||||||
|
arrowecho "Deregistering previously baked AMI"
|
||||||
|
|
||||||
|
# Sometimes describe-images does not return null even if the found
|
||||||
|
# image cannot be deregistered
|
||||||
|
#
|
||||||
|
# TODO(nathanleclaire): More elegant solution?
|
||||||
|
aws ec2 deregister-image --image-id ${IMAGE_ID} >/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
SNAPSHOT_ID=$(aws ec2 describe-snapshots --filters "Name=tag-key,Values=$TAG_KEY" | jq -r .Snapshots[0].SnapshotId)
|
||||||
|
if [[ ${SNAPSHOT_ID} == "null" ]]; then
|
||||||
|
arrowecho "No snapshot found, skipping"
|
||||||
|
else
|
||||||
|
arrowecho "Deleting volume snapshot"
|
||||||
|
aws ec2 delete-snapshot --snapshot-id ${SNAPSHOT_ID}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
bake)
|
||||||
|
bake_image
|
||||||
|
;;
|
||||||
|
clean)
|
||||||
|
clean_tagged_resources
|
||||||
|
;;
|
||||||
|
regions)
|
||||||
|
# TODO(nathanleclaire): Propogate created image (if existing) to every
|
||||||
|
# possible region / AZ
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
arrowecho "Command $1 not found. Usage: ./bake-ami.sh [bake|clean|regions]"
|
||||||
|
esac
|
35
alpine/aws/run-instance.sh
Executable file
35
alpine/aws/run-instance.sh
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Quick script to boot an instance from generated AMI. Intended to be invoked
|
||||||
|
# from "alpine" directory.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTANCE_ID=$(cat ./aws/instance_id.out)
|
||||||
|
aws ec2 terminate-instances --instance-id ${INSTANCE_ID} || true
|
||||||
|
|
||||||
|
if [[ ! -f ./aws/ami_id.out ]]; then
|
||||||
|
echo "AMI ID to launch instance from not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
AMI_ID=$(cat ./aws/ami_id.out)
|
||||||
|
|
||||||
|
echo "Running instance from ${AMI_ID}"
|
||||||
|
|
||||||
|
INSTANCE_ID=$(aws ec2 run-instances --image-id ${AMI_ID} --instance-type t2.nano | jq -r .Instances[0].InstanceId)
|
||||||
|
|
||||||
|
aws ec2 create-tags --resources ${INSTANCE_ID} --tags Key=Name,Value=moby-boot-from-ami
|
||||||
|
|
||||||
|
echo "Running instance ${INSTANCE_ID}"
|
||||||
|
echo ${INSTANCE_ID} >./aws/instance_id.out
|
||||||
|
|
||||||
|
echo "Waiting for instance boot log to become available"
|
||||||
|
|
||||||
|
INSTANCE_BOOT_LOG="null"
|
||||||
|
while [[ ${INSTANCE_BOOT_LOG} == "null" ]]; do
|
||||||
|
INSTANCE_BOOT_LOG=$(aws ec2 get-console-output --instance-id ${INSTANCE_ID} | jq -r .Output)
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
aws ec2 get-console-output --instance-id ${INSTANCE_ID} | jq -r .Output
|
@ -26,3 +26,13 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.armhf
|
dockerfile: Dockerfile.armhf
|
||||||
network_mode: bridge
|
network_mode: bridge
|
||||||
|
ami:
|
||||||
|
privileged: true
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.ami
|
||||||
|
network_mode: bridge
|
||||||
|
volumes:
|
||||||
|
- .:/mnt
|
||||||
|
- $HOME/.aws:/root/.aws:ro
|
||||||
|
- /dev:/dev
|
||||||
|
@ -26,7 +26,10 @@ mknod -m 666 zero c 1 5
|
|||||||
mknod -m 666 tty c 5 0
|
mknod -m 666 tty c 5 0
|
||||||
mknod -m 600 console c 5 1
|
mknod -m 600 console c 5 1
|
||||||
|
|
||||||
|
mknod -m 600 tty0 c 4 11
|
||||||
|
mknod -m 600 tty1 c 4 12
|
||||||
mknod -m 600 ttyS0 c 4 64
|
mknod -m 600 ttyS0 c 4 64
|
||||||
|
mknod -m 600 hvc0 c 229 2
|
||||||
mknod -m 600 fuse c 10 229
|
mknod -m 600 fuse c 10 229
|
||||||
|
|
||||||
# we are using sata emulation at present
|
# we are using sata emulation at present
|
||||||
@ -44,6 +47,8 @@ mknod -m 600 sdb3 b 8 19
|
|||||||
mknod -m 600 sdb4 b 8 20
|
mknod -m 600 sdb4 b 8 20
|
||||||
mknod -m 600 sdb5 b 8 21
|
mknod -m 600 sdb5 b 8 21
|
||||||
mknod -m 600 sdb6 b 8 22
|
mknod -m 600 sdb6 b 8 22
|
||||||
|
mknod -m 600 xvdf b 8 23
|
||||||
|
mknod -m 600 xvdf1 b 8 24
|
||||||
|
|
||||||
# mount points in /dev
|
# mount points in /dev
|
||||||
mkdir pts mqueue shm
|
mkdir pts mqueue shm
|
||||||
|
7
alpine/syslinux.cfg
Normal file
7
alpine/syslinux.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
DEFAULT linux
|
||||||
|
TIMEOUT 0
|
||||||
|
PROMPT 0
|
||||||
|
LABEL linux
|
||||||
|
KERNEL /vmlinuz64
|
||||||
|
INITRD /initrd.img
|
||||||
|
APPEND root=/dev/xvdb1 console=hvc0 console=tty0 console=tty1 console=ttyS0
|
Loading…
Reference in New Issue
Block a user