Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build my own custom Ubuntu ISO with docker

As a background, I have a custom Ubuntu LiveUSB that will automatically boot into "Try it" and the OS will have pre-installed apps that I have burned into the ISO itself.

It works great, but I keep running into problems automating the process.

Rather than doing it by hand every time, (because my bash scripts keep getting different results when I try again for the first time in a while) I was thinking of generating a docker image with the unpacked files from the ISO ready for modification, then run a container with a script in a volume (docker run -v $(pwd)/bin:/data myimage /data/myscript.sh) that would modify the contents, pack it back up into an ISO and save the ISO in /data for me to grab and distribute.

FROM ubuntu:16.04

MAINTAINER Myself

ENV ISO_FILE="ubuntu-16.04.3-desktop-amd64.iso" \
    OS_VERSION="16.04.3"

RUN apt-get update && apt-get install -y curl

RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get install -y squashfs-tools genisoimage gnupg2 \
                       nodejs rsync build-essential libc6-dev-i386 \
                       wget

# Make directories
RUN mkdir /data
RUN mkdir -p /root/workspace

# Download ubuntu iso
WORKDIR /root/workspace
RUN wget http://releases.ubuntu.com/$OS_VERSION/$ISO_FILE
RUN wget http://releases.ubuntu.com/$OS_VERSION/SHA256SUMS
RUN wget http://releases.ubuntu.com/$OS_VERSION/SHA256SUMS.gpg

# Check hash (default /bin/sh errors out)
RUN /bin/bash -c "sha256sum -c <(grep $ISO_FILE SHA256SUMS)"

# Check signatures
RUN gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 0xFBB75451 0xEFE21092
RUN gpg2 --verify SHA256SUMS.gpg SHA256SUMS

# Create mount
RUN mkdir mnt

# Here is where the docker build fails
RUN mount -o loop $ISO_FILE mnt

# Extract official DVD
RUN mkdir extract-cd
RUN rsync --exclude=/casper/filesystem.squashfs -a mnt/ extract-cd
RUN unsquashfs mnt/casper/filesystem.squashfs
RUN mv squashfs-root edit
RUN umount mnt

# Insert buildscript and make it executable
COPY bin/buildscript.sh /root/workspace/edit/buildscript.sh
RUN chmod +x edit/buildscript.sh

# Prepare to chroot into unsquashed ubuntu image, and run buildscript.sh
RUN mount -o bind /run/ edit/run
RUN mount --bind /dev/ edit/dev
RUN chroot edit/ ./buildscript.sh

# unmount the mountpoints and delete the buildscript.
RUN umount edit/dev
RUN umount edit/run
RUN rm edit/buildscript.sh

And the buildscript.sh I run in chroot inside the builder (or fail to run) is:

#!/bin/bash

mount -t proc none /proc
mount -t sysfs none /sys
mount -t devpts none /dev/pts
export HOME=/root
export LC_ALL=C
add-apt-repository "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) universe multiverse"
curl -sL https://deb.nodesource.com/setup_8.x | bash -
apt install -y nodejs
apt upgrade -y
apt install -y chromium-browser git
apt install -y language-pack-ja language-pack-gnome-ja language-pack-ja-base language-pack-gnome-ja-base
localectl set-locale LANG=ja_JP.UTF-8 LANGUAGE="ja_JP:ja"
source /etc/default/locale
mkdir src
apt autoclean
rm -rf /tmp/* ~/.bash_history
umount /proc || umount -lf /proc
umount /sys
umount /dev/pts
exit

Since this didn't work, I found online that build-run-commit method might work... so I changed the end of the dockerfile to the following

# Create mount
RUN mkdir mnt
RUN mkdir extract-cd
COPY bin/buildscript.sh /root/workspace/buildscript.sh
COPY bin/build_run_step2.sh /root/workspace/build_run_step2.sh
RUN chmod +x buildscript.sh
RUN chmod +x build_run_step2.sh

and then the "run" step of build run commit is the build_run_step2.sh which has the following (run with --privileged)

#!/bin/bash

cd /root/workspace

mount -o loop $ISO_FILE mnt

# Extract official DVD
rsync --exclude=/casper/filesystem.squashfs -a mnt/ extract-cd
unsquashfs mnt/casper/filesystem.squashfs
mv squashfs-root edit
umount mnt

mv ./buildscript.sh edit/buildscript.sh

# Prepare to chroot into unsquashed ubuntu image, and run buildscript.sh
mount -o bind /run/ edit/run
mount --bind /dev/ edit/dev
chroot edit/ ./buildscript.sh

# unmount the mountpoints and delete the buildscript.
umount edit/dev
umount edit/run
rm edit/buildscript.sh

Which works... but then I run into a problem:

Running apt-get update gets errors:

W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/xenial/InRelease  Temporary failure resolving 'archive.ubuntu.com'
W: Failed to fetch http://security.ubuntu.com/ubuntu/dists/xenial-security/InRelease  Temporary failure resolving 'security.ubuntu.com'
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/xenial-updates/InRelease  Temporary failure resolving 'archive.ubuntu.com'

and checking ping gets me "no host found" while chrooted.

So One major question and one smaller question (if the major question has no answer):

  1. How can I use docker to create an image with an opened up liveCD ready for customizing and then use docker run on that image to chroot, modify, repackage, and extract the new iso? (I know the commands to do that normally, so rather, I am wondering if/why all these things are not working in docker... aka what are the limitations of chrooting in docker?)
  2. How can I get the chroot system within the container to reach dns so it can run the updates via URLS? (I attempted ping 8.8.8.8 from within the chroot in the container and the pings were coming back fine.)
like image 955
user3074620 Avatar asked Oct 17 '22 21:10

user3074620


1 Answers

So incase anyone finds this post. The way to resolve the dns issue is to make sure your resolv.conf file in the chroot is actually pointing to a proper dns servers. Some apps like cubic already do this for you.

like image 98
Alex Painemilla Avatar answered Oct 21 '22 00:10

Alex Painemilla