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 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:
|
||||
rm -f initrd.img initrd.img.gz initrd-arm.img Dockerfile.armhf etc/inittab
|
||||
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: .
|
||||
dockerfile: Dockerfile.armhf
|
||||
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 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 hvc0 c 229 2
|
||||
mknod -m 600 fuse c 10 229
|
||||
|
||||
# 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 sdb5 b 8 21
|
||||
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
|
||||
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