Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 111 lines (81 sloc) 3.49 KB
#!/usr/bin/env python2.7
"""Docker From Scratch Workshop - Level 1: Chrooting into an image.
Goal: Let's get some filesystem isolation with good ol' chroot.
Usage:
running:
rd.py run -i ubuntu /bin/sh
will:
fork a new child process that will:
- unpack an ubuntu image into a new directory
- chroot() into that directory
- exec '/bin/sh'
while the parent waits for it to finish.
"""
from __future__ import print_function
import os
import tarfile
import uuid
import click
import traceback
import linux
def _get_image_path(image_name, image_dir, image_suffix='tar'):
return os.path.join(image_dir, os.extsep.join([image_name, image_suffix]))
def _get_container_path(container_id, container_dir, *subdir_names):
return os.path.join(container_dir, container_id, *subdir_names)
def create_container_root(image_name, image_dir, container_id, container_dir):
"""Create a container root by extracting an image into a new directory
Usage:
new_root = create_container_root(
image_name, image_dir, container_id, container_dir)
@param image_name: the image name to extract
@param image_dir: the directory to lookup image tarballs in
@param container_id: the unique container id
@param container_dir: the base directory of newly generated container
directories
@retrun: new container root directory
@rtype: str
"""
image_path = _get_image_path(image_name, image_dir)
container_root = _get_container_path(container_id, container_dir, 'rootfs')
assert os.path.exists(image_path), "unable to locate image %s" % image_name
if not os.path.exists(container_root):
os.makedirs(container_root)
with tarfile.open(image_path) as t:
# Fun fact: tar files may contain *nix devices! *facepalm*
members = [m for m in t.getmembers()
if m.type not in (tarfile.CHRTYPE, tarfile.BLKTYPE)]
t.extractall(container_root, members=members)
return container_root
@click.group()
def cli():
pass
def contain(command, image_name, image_dir, container_id, container_dir):
# TODO: would you like to do something before chrooting?
# print('Created a new root fs for our container: {}'.format(new_root))
# TODO: chroot into new_root
# TODO: something after chrooting? (HINT: try running: sudo python rd.py run -i ubuntu -- /bin/sh)
os.execvp(command[0], command)
@cli.command(context_settings=dict(ignore_unknown_options=True,))
@click.option('--image-name', '-i', help='Image name', default='ubuntu')
@click.option('--image-dir', help='Images directory',
default='/workshop/images')
@click.option('--container-dir', help='Containers directory',
default='/workshop/containers')
@click.argument('Command', required=True, nargs=-1)
def run(image_name, image_dir, container_dir, command):
container_id = str(uuid.uuid4())
pid = os.fork()
if pid == 0:
# This is the child, we'll try to do some containment here
try:
contain(command, image_name, image_dir, container_id,
container_dir)
except Exception:
traceback.print_exc()
os._exit(1) # something went wrong in contain()
# This is the parent, pid contains the PID of the forked process
# wait for the forked child, fetch the exit status
_, status = os.waitpid(pid, 0)
print('{} exited with status {}'.format(pid, status))
if __name__ == '__main__':
cli()
You can’t perform that action at this time.