Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script for bootstrapping a FreeBSD to be ready with Docker #1

Open
3 tasks
rtyler opened this issue Sep 6, 2017 · 5 comments
Open
3 tasks

Script for bootstrapping a FreeBSD to be ready with Docker #1

rtyler opened this issue Sep 6, 2017 · 5 comments

Comments

@rtyler
Copy link
Member

rtyler commented Sep 6, 2017

We need a script which can be run on a machine's first boot which can:

  • Load the necessary kernel modules: zfs, pf, linux, linux64
  • Ensure a ZFS mount is created at /usr/docker. See these instructions
  • Fetch the FreeBSD/Docker binaries, either via a committed sysutils/docker-freebsd port or by simply grabbing compiled binaries from github.com/freebsd-docker/docker.
@freebsdfrau
Copy link
Contributor

I believe we should put these things into the /usr/local/etc/rc.d/docker script so that when you have docker_enable=YES in rc.conf(5) that "service docker start" is run at boot and these checks/actions happen as pre-conditions to starting docker. The source for the /usr/local/etc/rc.d/docker script is ports/head/sysutils/docker-freebsd/files/docker.in in the FreeBSD subversion tree.

I've started working on them. For example, module requirements:

for module in \
        zfs \
        pf \
        linux \
        linux64 \
; do
        kldstat -qm $module || kldload $module || die
done

ZFS requirements:

: ${docker_zpool_name:=zroot}
: ${docker_zpool_file=/usr/local/dockerfs}
: ${docker_zpool_file_size:=4G}
: ${docker_zfs_dir:=/usr/docker}
: ${docker_zfs_name:=docker}

name=docker
rcvar=docker_enable

[ -e "$docker_zfs_dir" ] || mkdir -p "$docker_zfs_dir"

dd_blocksize=
dd_count=
fs_type=
make_zfs=
zfs_mountpoint=
zfs_name=
zpool_name=
zpool_size=

#
# If ZFS filesystem is already mounted on $docker_zfs_dir, do nothing.
# If $docker_zfs_dir is inside existing ZFS filesystem, create new filesystem.
# Otherwise, create $docker_zpool_file to contain pool and filesystem.
#
fstype=$( df -T "$docker_zfs_dir" 2> /dev/null | awk 'NR>1,$0=$2' )
case "$fstype" in
zfs)
        zfs_mountpoint=$( zfs get -Ho value mountpoint "$docker_zfs_dir" )
        zfs_name=$( zfs get -Ho name mountpoint "$docker_zfs_dir" )
        [ "$docker_zfs_dir" = "$zfs_mountpoint" ] || make_zfs=filesystem
        ;;
*)
        zfs_name="$docker_zpool_name"
        make_zfs=pool
esac
zpool_name="${zfs_name%%/*}"

#
# Setup ZFS pool if required
#
case "$make_zfs" in
pool)
        #
        # Expand desired pool size to bytes
        #
        zpool_size=$( awk -v size="$docker_zpool_file_size" '
                BEGIN {
                        suffixen = "KMGTPEZYXWV" # ... Yotta Xenna Weka Vendeka
                        size = toupper(size)
                        sub(sprintf("[^[:digit:].%s].*", suffixen), "", size)
                        if (match(size, sprintf("[%s]", suffixen))) {
                                suffix = substr(size, RSTART, 1)
                                size = substr(size, 1, RSTART - 1)
                                match(suffixen, suffix)
                                size = size * 1024 ** RSTART
                        }
                        printf "%i\n", size
                        exit
                }
        ' )

        #
        # Get blocksize/count for dd(1)
        #
        dd_blocksize=1
        dd_count="$zpool_size"
        if [ "$dd_count" -gt 1048576 ]; then
                dd_blocksize=1m
                dd_count=$(( $dd_count / 1048576 ))
        elif [ "$dd_count" -gt 1024 ]; then
                dd_blocksize=1k
                dd_count=$(( $dd_count / 1024 ))
        fi

        #
        # Initialize the file using dd(1) piped through dpv(1)
        #
        msg="Creating ZFS pool file ($docker_zpool_file_size size) ..."
        exec 3>&1 4>&2
        dd if=/dev/zero bs="$dd_blocksize" count="$dd_count" 2> /dev/null | (
                exec 2>&1 >&3
                trap '
                        exec >&4 2>&1
                        echo
                        echo "User interrupt caught. Cleaning up ..."
                        rm -fv "$docker_zpool_file"
                ' INT
                if [ -t 1 ]; then
                        dpv -o /dev/stderr \
                                -b "$name" \
                                -t "dd(1)" \
                                -w -p "$msg\n" \
                                -- $zpool_size:"$docker_zpool_file"
                else
                        echo "$msg"
                        cat >&2
                fi
        ) > "$docker_zpool_file"

        #
        # Create zpool
        #
        echo "Creating ZFS pool from file $docker_zpool_file ..."
        zpool create "$docker_zpool_name" "$docker_zpool_file"
        ;;
esac

#
# Setup ZFS filesystem
#
if [ "$make_zfs" ]; then
        echo "Creating ZFS filesystem $zpool_name/$docker_zfs_name ..."
        zfs create -o mountpoint="$docker_zfs_dir" \
                "$zpool_name/$docker_zfs_name"
fi

And since this would be part of the rc.d script which is installed by the port, the last item should be handled "out of the box."

@rtyler
Copy link
Member Author

rtyler commented Sep 6, 2017

@freebsdfrau That looks really reasonable to me, the only concern I have is about the default size of the zpool if ZFS isn't already present. How easy would it be for a user to resize that zpool if they needed to later down the road? (I'm not the most ZFS savvy)

@freebsdfrau
Copy link
Contributor

These code snippets are written in the context of being in an rc.d script (e.g., /usr/local/etc/rc.d/docker installed as part of the port or pkg).

At the top, take note of the following "underrides" (default values that should be overridden using sysrc(8) or by manually editing rc.conf(5)):

: ${docker_zpool_name:=zroot}
: ${docker_zpool_file=/usr/local/dockerfs}
: ${docker_zpool_file_size:=4G}
: ${docker_zfs_dir:=/usr/docker}
: ${docker_zfs_name:=docker}

All those values are defaults which can be overridden in rc.conf(5).

For example, one would be able to run:

sysrc docker_zpool_file_size=20G

Before then running:

service docker start

@lifanov
Copy link

lifanov commented Sep 7, 2017

You totally can grow file-backed ZFS pool post-provision.
trucate + autoexpand=on

@freebsdfrau
Copy link
Contributor

We're picking up things here: https://reviews.freebsd.org/D12270

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants