<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">\documentclass[onecolumn,letterpaper,11pt]{article}

%===================================================================
% Include common packages, environments, counters etc
\input{common_latex/common_latex_packages}
\input{common_latex/common_latex_lab_format}
\input{common_latex/common_latex_definitions}
%===================================================================
\setcounter{tocdepth}{2}
%===================================================================

\begin{document}
\wikidoc{file=Lab.DockerUbuntu}
\wikidoc{auth=mikerb@mit.edu}
\helplevelsubsec

%===================================================================
% Build the Cover Page in an environment style easy for wiki parsing
\begin{labcover}
\labtitle{Docker Lab 2 - Working with Ubuntu Images and Containers}
\vspace{0.2in}
%\labcourse{Pavlab: Getting Started with Docker Containers}
\vspace{0.5in}
\labpng{0.35}{figures/docker_ubuntu.png}
\vspace{0.25in}
\labdate{May 20th, 2020}
\vspace{0.23in}
\labauth{Michael Benjamin, mikerb@mit.edu}
\labauth{Department of Mechanical Engineering}
\labauth{MIT, Cambridge MA 02139}
\labtoc{small}
\labtocdepth{2}
\end{labcover}

%===================================================================
% Add a blank page so first body page is on the right when doubleside
\blankpage

%===================================================================
% Begin the body of the text
%===================================================================
\section{Overview and Objectives}
%===================================================================

\begin{labinfo}
%\labinfoheader{Topics:}
\begin{packed_itemize}[2]
\item Goal - Obtain a Ubuntu image from Docker Hub
\item Goal - 
\item Goal - Obtain your first Docker images
\item Goal - Start your first Docker containers
\item Goal - Become comfortable knowing the state of local images and containers
\end{packed_itemize}
\end{labinfo}

%=======================================================================
\section{Ubuntu Images}
%=======================================================================

Initially we focus on Ubuntu Linux images since our lab has been working with
Ubuntu on physical machines for some years, and a couple of our motivating
use cases are tied to Ubuntu. So in this short lab we will work with Ubuntu
images and containers and gain familiarity with how to augment the initial
containers, and create newly augmented images suitable for the work we
have in mind.

%=======================================================================
\subsection{Getting Ubuntu Images from Docker Hub}

Ubuntu images for several releases may be obtained from Docker Hub:

\vspace{0.2in}
\urlx{https://hub.docker.com/\_/ubuntu/}
\vspace{0.2in}

\noindent
This should bring you to a page that contains content similar to that shown below.
Each of these entries represent a distinct image from a particular Ubuntu release.
The terms on each line are tags that may be used with the \var{ubuntu} image name
to get the desired release.

\vspace{0.15in}
\begin{figure}[H]
  \centering 
  \includegraphics[width=0.68\textwidth]{figures/docker_ubuntu_tags.png}
  \caption{{\bf Ubuntu Image Tags:} Various releases of Ubuntu are available
    with the corresponding tags.}
\label{fig_ubuntu tags}
\end{figure}
\vspace{0.1in}

\noindent
For example, to get the Ubuntu 20.04 LTS image:


\vspace{0.15in}
\begin{consoleverb}
$ docker pull ubuntu:20.04
\end{consoleverb}
\vspace{0.05in}

\begin{consoleverb}
$ docker images
REPOSITORY          TAG        IMAGE ID          CREATED          SIZE
ubuntu              20.04      1d622ef86b13      3 weeks ago      73.9MB
\end{consoleverb}
\vspace{0.15in}

\noindent
Alternatively, to pull the image, and launch a container, with bash prompt, all on
one command, the below command can be used. 

\vspace{0.15in}
\begin{consoleverb}
$ docker run -it ubuntu:20.04 bash
root@3420dffd5c43:/# ls
bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr
\end{consoleverb}
\vspace{0.15in}

\noindent
Note the bash shell prompt is of the form
\var{"user@machine:pwd\#"}. The container starts as the \var{"root"}
user, and the machine name is the Container ID,
\var{"3420dffd5c43"}. The Container ID will be different on your
system.  The present working directory is \var{"/"}.

\vspace{0.15in}
\noindent
There is not yet much that can be done with this container until
further steps are taken to install packages or personal software. You
can type \var{exit} at any time to stop the container and return to
the shell prompt of your local file system. The container can be
launched again by repeating the above \cmd{docker run} command. But
any changes made prior to exiting the container will be lost, since
the image has not changed, and each \cmd{docker run} will create a new
container in exactly the same starting state. (Wrapping my head around
this idea was an early challenge for me.)

%=======================================================================
\subsection{Installing Packages and Confirming Release Info}

Users accustomed to installing Ubuntu from scratch on a local computer,
or virtual machine, may be surprised at how few utilities are installed
on this container. This container is very thin, by design. The first time
I launched a Ubuntu container like the above, the first thing I wanted to
do was run the \cmd{lsb\_release} command to verify the Ubuntu release
information. Unfortunately, this utility was not installed, and needs to
be installed first:

\vspace{0.15in}
\begin{consoleverb}
root@3420dffd5c43:/# apt-get update
...
Reading package lists... Done
root@3420dffd5c43:/# apt-get install lsb-release
\end{consoleverb}
\vspace{0.15in}

\vspace{0.1in}
\noindent
Note that first the \cmd{apt-get update} command needed to be run to update
the internal list of packages available, since initially the list of
packages is completely empty.  Then the \cmd{lsb\_release} utility was
obtained from the \var{lsb-release} package. Now we can run
\cmd{lsb\_release} and verify that we are indeed working with the
\var{20.04} release:


\vspace{0.15in}
\begin{consoleverb}
root@3420dffd5c43:/# lsb_release -a 
LSB Version:    core-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch
Distributor ID: Ubuntu
Description:    Ubuntu 20.04 LTS
Release:        20.04
Codename:       focal
\end{consoleverb}


%=======================================================================
\subsection{Obtaining a Larger Set of Utilities with One Install Command}


Our plan is to continue to work with super thin Ubuntu images and containers,
only installing what is needed.


\vspace{0.15in}
\noindent
But... it's worth noting that more familiar tool install
configurations can be obtained easily using a {\em meta-package}
[4]. The meta-package itself does not install anything. Instead, it is
a link to several other packages that will be installed as
dependencies.  Here two useful options, the second one providing even
more than the first:

\vspace{0.15in}
\begin{consoleverb}
root@3420dffd5c43:/# apt-get update
root@3420dffd5c43:/# apt-get -y install --no-install-recommends ubuntu-minimal
or
root@3420dffd5c43:/# apt-get -y install --no-install-recommends ubuntu-standard
\end{consoleverb}
\vspace{0.15in}

\noindent
Another useful meta-package is \var{build-essential}, [4]. This
package includes five packages crucial to compiling software:
\var{g++}, \var{gcc}, \var{libc6-dev}, \var{make}, \var{dpkg-dev}

\vspace{0.15in}
\begin{consoleverb}
root@3420dffd5c43:/# apt-get update
root@3420dffd5c43:/# apt-get -y install build-essential
\end{consoleverb}
\vspace{0.15in}

\noindent
Recall the \var{-y} argument to \var{apt-get} ensures that all user prompts
for confirmation in the install process will take on the default
values automatically.  See [1] and [2] for more info on the Ubuntu packages.

%=======================================================================
\newpage \section{Interacting with Ubuntu Containers}
%=======================================================================

Once a Ubuntu image has been pulled to the local computer, containers can be
run, paused, stopped, restarted, unpaused and so on. Furthermore, there are
options for interacting with a running container. They are discussed here.

%=======================================================================
\subsection{Running and Exiting from Ubuntu Containers}

Let's start by running Ubuntu container as before:

\vspace{0.15in}
\begin{consoleverb}
$ docker run -it ubuntu:20.04 bash
root@3420dffd5c43:/#
\end{consoleverb}
\vspace{0.15in}

\noindent
What happens when we \cmd{exit} this container? 

\vspace{0.15in}
\begin{consoleverb}
root@3420dffd5c43:/# exit
$ docker container ls -a
CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
78312b579cf2    ubuntu:20.04    "bash"     4 mins ago    Exited (0) 2 sec ago   big_leavitt
\end{consoleverb}
\vspace{0.15in}


\noindent
The \cmd{docker container ls -a} command confirmed that the container has been exited, but it
hasn't been removed. 

\noindent
What happens if these two steps are repeated?

\vspace{0.15in}
\begin{consoleverb}
$ docker run -it ubuntu:20.04 bash
root@3420dffd5c43:/# exit
$ docker container ls -a
CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
a3c6bdc864f6    ubuntu:20.04    "bash"     8 secs ago    Exited (0) 3 sec ago   hardcore_tesla
78312b579cf2    ubuntu:20.04    "bash"     4 mins ago    Exited (0) 2 min ago   big_leavitt
\end{consoleverb}
\vspace{0.15in}

\noindent
The \cmd{docker container ls -a} command indicates that a {\em new} container was created,
from the same image, and that both containers remain, and both have been exited.

%=======================================================================
\subsection{Running, Restarting and Reconnecting to a Ubuntu Container}

\noindent
It is possible to restart and return to either of the above two containers:

\vspace{0.15in}
\begin{consoleverb}
$ docker container restart a3c6bdc864f6
a3c6bdc864f6 
$ docker exec -it a3c6bdc864f6 bash
root@a3c6bdc864f6:/#
\end{consoleverb}
\vspace{0.15in}

\noindent
First the container needs to be restarted. The \cmd{docker container restart} command above
could have also been given the container name, \var{hardcore\_tesla}, instead of the container
ID. The \cmd{exec} command runs a new command in a running container [3]. 

\noindent
In another terminal window you can see the change in container state:

\vspace{0.15in}
\begin{consoleverb}
$ docker container ls -a
CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
a3c6bdc864f6    ubuntu:20.04    "bash"     8 secs ago    Up 5 seconds           hardcore_tesla
78312b579cf2    ubuntu:20.04    "bash"     4 mins ago    Exited (0) 2 min ago   big_leavitt
\end{consoleverb}
\vspace{0.15in}


\noindent
And finally, the restarted container may also be exited, or stopped, from outside the
container. In the second (local) terminal window used above, try running the command:

\vspace{0.15in}
\begin{consoleverb}
$ docker container stop a3c6bdc864f6
$ docker container ls -a
CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
a3c6bdc864f6    ubuntu:20.04    "bash"     2 mins ago    Exited (0) 5 sec ago   hardcore_tesla
78312b579cf2    ubuntu:20.04    "bash"     4 mins ago    Exited (0) 2 min ago   big_leavitt
\end{consoleverb}
\vspace{0.15in}

\noindent
In the first terminal window, it can be noted that the container has exited, and the shell
prompt is the local shell prompt. Exactly as if one had typed \cmd{exit} in the container
window itself.

%=======================================================================
\subsection{Running, Pausing, Unpausing a Ubuntu Container}

It is possible to {\em pause} a running Ubuntu container rather than stopping it:


\vspace{0.15in}
\begin{consoleverb}
$ docker container ls -a
CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
a3c6bdc864f6    ubuntu:20.04    "bash"     18 mins ago   Up 15 minutes          hardcore_tesla
$ docker container pause a3c6bdc864f6
$ docker container ls -a
CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
a3c6bdc864f6    ubuntu:20.04    "bash"     18 mins ago   Up 15 minutes (Paused) hardcore_tesla
\end{consoleverb}
\vspace{0.15in}

\noindent
If you had a bash session going in another terminal window with the now paused container, you
will notice that the keyboard is non-responsive. The container can be un-paused with: 

\vspace{0.15in}
\begin{consoleverb}
$ docker container unpause a3c6bdc864f6
$ docker container ls -a
CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
a3c6bdc864f6    ubuntu:20.04    "bash"     19 mins ago   Up 16 minutes          hardcore_tesla
\end{consoleverb}
\vspace{0.15in}

\noindent
Once the container is unpaused, any keystrokes that were typed in the terminal of the paused
container will be immediately applied upon un-pause.

\vspace{0.1in}
\noindent
{\bf HINT:} It is convenient to see the effects of starting, stopping,
exiting containers etc, by re-running the \var{"docker container ls
  -a"} command. As a further convenience use a terminal window to
auto-refresh this output as you're experimenting in other terminal
windows, with the \cmd{watch} command:

\vspace{0.15in}
\begin{consoleverb}
$ watch docker container ls -a
Every 2.0s: docker container ls -a                         sausalito: Sat Jun 11 14:37:56 2022

CONTAINER ID    IMAGE           COMMAND    CREATED       STATUS                 NAMES
a3c6bdc864f6    ubuntu:20.04    "bash"     19 mins ago   Up 16 minutes          hardcore_tesla
\end{consoleverb}
\vspace{0.15in}

\noindent
This is similar to the \cmd{top} command in GNU/Linux. Just exit with \var{ctrl-c}.



%=======================================================================
\newpage \section{Removing Images and Containers}
%=======================================================================

So far in this lab we have explored how to:

\vspace{0.1in}
\begin{packed_itemize}
\item Download (pull) Ubuntu images from Docker Hub to our local computer
\item Launch (run) a Ubuntu container from an image and have a bash session
\item Stop, restart and reconnect to a container
\item Pause and unpause a container
\end{packed_itemize}
\vspace{0.1in}

\noindent
The last topic for the lab involves {\em removing} things. Personally
I like to always know how to get back to my starting state. After this
discussion you should feel confident that you can create as many
images and containers as you like, experiment freely with them, and
easily get back to a clean starting state.

\vspace{0.1in}

\noindent
As before, we will work with Ubuntu images and containers. We will exlore:

\vspace{0.1in}
\begin{packed_itemize}
\item How to remove images and containers from our local computer
\item What happens when we try to remove a running container
\item What happens when we try to remove an image related to a running container
\item How to remove all containers with a single command
\item How to remove all images with a single command
\end{packed_itemize}
\vspace{0.1in}

%=======================================================================
\subsection{Simple Removing of Containers}

A straight-forward example of removing a container is below. A new container is created
with a bash session.

\vspace{0.15in}
\begin{consoleverb}
$ docker run -it ubuntu:20.04 bash
root@3420dffd5c43:/#
\end{consoleverb}
\vspace{0.15in}

\noindent
In a second terminal window this container can be seen with \cmd{docker container ls}:

\vspace{0.15in}
\begin{consoleverb}
$ docker container ls
CONTAINER ID     IMAGE            COMMAND    CREATED        STATUS      NAMES
4c548ea0fdc2     ubuntu:20.04     "bash"     3 secs ago     Up 2 secs   sad_jane
\end{consoleverb}
\vspace{0.15in}

\noindent
Back in the first terminal, we exit, and note that it is still listed, but its status
is {\em Exited}, and we have to use the \cmd{-a} argument in \cmd{docker container ls -a}
to see this container listed:

\vspace{0.15in}
\begin{consoleverb}
root@3420dffd5c43:/# exit
$ docker container ls
CONTAINER ID     IMAGE            COMMAND    CREATED        STATUS                   NAMES
$ docker container ls -a 
CONTAINER ID     IMAGE            COMMAND    CREATED        STATUS                   NAMES
4c548ea0fdc2     ubuntu:20.04     "bash"     3 mins ago     Exited (0) 2 secs agoe   sad_jane
\end{consoleverb}
\vspace{0.15in}

\noindent
The container has not been {\em removed}. If we wanted, this container
could still be restarted and reconnected to a new bash session. But
we'll remove it instead. To remove the container:

\vspace{0.15in}
\begin{consoleverb}
$ docker container rm 4c548ea0fdc2 
4c548ea0fdc2 
$ docker container ls -a 
CONTAINER ID     IMAGE            COMMAND    CREATED        STATUS                   NAMES
\end{consoleverb}
\vspace{0.15in}

%=======================================================================
\subsection{Automatically Removing a Container}

An even simpler way to remove a container is to arrange to have it
removed automatically as soon as the container is stopped (exited). To
do this, just include the \cmd{--rm} argument when the container is
launched (started):

\vspace{0.15in}
\begin{consoleverb}
$ docker run --rm -it ubuntu:20.04 bash
root@3420dffd5c43:/# exit
$ docker container ls -a
CONTAINER ID     IMAGE            COMMAND    CREATED        STATUS                   NAMES
\end{consoleverb}
\vspace{0.15in}

%=======================================================================
\subsection{Removing a Running or Paused Container}

Normally the action to remove a container should be taken only on a
container that has been stopped. Let's see what happens when we try to
remove a container that is still running. In the first terminal:

\vspace{0.15in}
\begin{consoleverb}
$ docker run -it ubuntu:20.04 bash
root@e538ef4d8e9e:/# 
\end{consoleverb}
\vspace{0.15in}

\noindent
In a second terminal window, try to remove the container:

\vspace{0.15in}
\begin{consoleverb}
$ docker rm e538ef4d8e9e
Error response from daemon: You cannot remove a running container
e538ef4d8e9e6c0d0e242647a0e234ad0886862b192f40c3752b97b23b0bf186. Stop the
container before attempting removal or force remove
\end{consoleverb}
\vspace{0.15in}

\noindent
The removal will not carried out. Note the full UUID for the container
in the error message. Recall the shortened container ID,
\var{e538ef4d8e9e}, is just the first 12 characters of the longer 64
character UUID.
\vspace{0.1in}

\noindent
As the error message indicates, the removal can be forced, and this is done
with:

\vspace{0.15in}
\begin{consoleverb}
$ docker rm --force e538ef4d8e9e
e538ef4d8e9e
\end{consoleverb}
\vspace{0.15in}

\noindent
The same situation applies if the container were paused instead of
running.  As a general practice, we will try to avoid using
\cmd{--force} in any of our attempts to remove a container by ensuring
they are stopped (exited) first.

%=======================================================================
\subsection{Removing an Image}

Removing an image is straight-forward when there are no containers running
created from that image. In the case above, for example, a Ubuntu container
was created:

\vspace{0.15in}
\begin{consoleverb}
$ docker run -it ubuntu:20.04 bash
root@8df9aee15e5b:/# 
\end{consoleverb}
\vspace{0.15in}

\noindent
In a second terminal window, the container can be seen, and the image that created it:

\vspace{0.15in}
\begin{consoleverb}
$ docker containers ls
CONTAINER ID        IMAGE          COMMAND    CREATED          STATUS         NAMES
8df9aee15e5b        ubuntu:20.04   "bash"     12 secs ago      Up 12 secs     quirky_joe
$ docker images
REPOSITORY          TAG            IMAGE ID         CREATED          SIZE
ubuntu              20.04          1d622ef86b13     4 hours ago      73.9MB
\end{consoleverb}
\vspace{0.15in}

\noindent
Removing the image is straight-forward with the \cmd{docker container rm} command,
providing it either the Image ID or the Image name. First the container is stopped and
removed:

\vspace{0.15in}
\begin{consoleverb}
$ docker container stop 8df9aee15e5b
8df9aee15e5b
$ docker container rm 8df9aee15e5b
8df9aee15e5b
$ docker image rm 1d622ef86b13
1d622ef86b13
$ docker images
REPOSITORY          TAG            IMAGE ID         CREATED          SIZE
\end{consoleverb}
\vspace{0.15in}

%=======================================================================
\subsection{Removing an Image with Running Containers}

An image cannot be removed if there are any containers attached to it, whether the
container is running, paused, or stopped. If you'd like to try, you will see
something like this:

\vspace{0.15in}
\begin{consoleverb}
$ docker rmi 1d622ef86b13
Error response from daemon: conflict: unable to delete 1d622ef86b13 (cannot be forced) - image 
is being used by running container 9b3db02a3e3d
\end{consoleverb}
\vspace{0.15in}

\noindent
Just remove the container first.

%=======================================================================
\subsection{Remove all Containers}

To remove all containers (running, paused or stopped), the below command
can be used. It uses the output of the \cmd{docker ps -aq} command which
just returns the list of Docker container IDs:

\vspace{0.15in}
\begin{consoleverb}
$ docker ps -aq
9b3db02a3e3d
50a674ab9d1e
f868dea6b7a0
\end{consoleverb}
\vspace{0.15in}

\noindent
The output of the above command is then used as input in the below one-liner
to remove all containers. 

\vspace{0.15in}
\begin{consoleverb}
$ docker rm -f $(docker ps -aq)
\end{consoleverb}
\vspace{0.15in}

\noindent
The \cmd{-f} argument of course will force remove all containers, even if
they are still running or paused.

\vspace{0.15in}

\noindent
FYI, a bit trickier command below can be used to remove all containers
(running, paused or stopped) based on a Docker image name. The below
will remove all containers attached to the image \var{"ubuntu:20.4"}:

\vspace{0.15in}
\begin{consoleverb}
# docker ps -a | awk '{ print $1,$2 }' | grep ubuntu:20.04 | awk '{print $1 }' | xargs -I {} docker rm {}
\end{consoleverb}
\vspace{0.15in}


%=======================================================================
\subsection{Remove all Images}




%=======================================================================
\newpage \section{Revisiting Container State with Unbuntu Containers}
%=======================================================================

There are at least five distinct states associated with containers:

\begin{packed_itemize}
\item {\em Created}: A created container is one that has been
  initialized with the docker create command but hasnâ€™t been started
  yet.

\item {\em Running}:

\item {\em Paused}:

\item {\em Stopped/Exited}: The exited status is commonly referred to
  as {\em stopped} and indicates there are no running processes inside
  the container (this is also true of a created container, but an
  exited container will have already been started at least once). A
  container exits when its main processes exits. An exited container
  can be restarted with the docker start command. A stopped container
  is not the same as an image. A stopped container will retain changes
  to its settings, metadata, and filesystem, including runtime
  configuration such as IP address that are not stored in images. The
  restarting state is rarely seen in practice and occurs when the
  Docker engine attempts to restart a failed container, [.

\item {\em Dead}:
\end{packed_itemize}


\Large
\noindent
{\bf URL References}
\footnotesize

\vspace{0.1in}


\noindent
[1] \urlx{https://packages.ubuntu.com/bionic/ubuntu-minimal}

\noindent
[2] \urlx{https://packages.ubuntu.com/bionic/ubuntu-standard}

\noindent
[3] \urlx{https://docs.docker.com/engine/reference/commandline/exec/}

\noindent
[4] \urlx{https://pimylifeup.com/ubuntu-build-essential/}

\end{document}

</pre></body></html>