Network Security Spring 2021

Containers are a popular way to package and deploy software in a repeatable, portable, and (ideally) deterministic way. Virtually all of your assignment solutions will be submitted as a source archive and container definition that, when processed with a tool like docker, will produce a container image. This container image is what will be evaluated for grading. Therefore, it’s rather important for your grade that you are able to build container images.

Building and Running Containers

Containers are a relatively new virtualization approach where multiple user-spaces are multiplexed on top of a single OS kernel. The kernel, such as Linux, uses namespaces to isolate container filesystems, network interfaces and configuration, and even users from other containers and the host environment. Containers have the advantage of incurring less overhead than traditional hypervisor-based virtualization, but on the other hand present a much larger attack surface than the hypercall interface provided by a hypervisor. Due to their efficiency, containers have become the dominant service deployment mechanism in cloud environments.

There are multiple container ecosystems available; however, Docker remains extremely popular, with implementations available for every major OS. In this class, we will standardize on Docker, and in particular on the Docker engine and command-line interface.

Building a Docker Image

Docker images are built from a specification expressed as a Dockerfile. A Dockerfile contains a sequence of directives that allow users to perform actions like setting a base image, adding files to an image from a build context, setting the default working directory, setting the default program to run when launching an image, and much more.

Given a Dockerfile, an image can be built using docker build from the shell. For instance, to build an image called my_image from a Dockerfile located in the current directory as well as a build context rooted at the current directory:

$ docker build -t my_image .

See docker help build for more information.

Running a Docker Container

Once an image has been built, one or more containers can be launched from a single image. For example, three containers running /bin/bash in my_image can be launched with a given name (--name) and stdin (-i) and a TTY (-t) connected to bash.

$ docker run -it --name my_image_1 --rm my_image /bin/bash
$ docker run -it --name my_image_2 --rm my_image /bin/bash
$ docker run -it --name my_image_3 --rm my_image /bin/bash

Additionally, after each container exits (whether by exiting the shell or forcefully terminating the container with docker stop in another shell), the container instance will be automatically removed (--rm).

There is a multitude of useful options that can be given to control how containers execute. See docker help run for more information.

Lab Objectives

  1. Read the reference documentation for docker build and Dockerfiles.
  2. Write a Dockerfile that builds an image with the following properties.
    1. Based on alpine:latest
    2. Working directory is /tmp
    3. Default user is nobody
    4. When launched with docker run [docker options...] ${image_name}, echos the email address of the group submitter

Submission Instructions

Package your group’s solution as a gzipped TAR archive. Your solution should expand to the following directory structure.

$ tree -F containers
├── Dockerfile
└── src/

Submit the solution archive to Canvas.