# Pull the latest Ubuntu image
docker pull ubuntu:latest
# Create a container from the Ubuntu image
docker create --name my-ubuntu-container ubuntu:latest
# Run a container and access its shell
docker run -it --name my-running-container ubuntu:latest /bin/bash
# List all containers, running and stopped
docker ps -a
# Stop a container
docker stop my-running-container
# Start a stopped container
docker start my-running-container
# Access the shell of a running container
docker exec -it my-running-container /bin/bash
# View logs from a container
docker logs my-running-container
# Remove a container
docker rm my-running-container
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
# requirements.txt
Flask
pip install -r requirements.txt
python app.py
# Containerizing a Single-Container App with Docker
This guide demonstrates the steps to containerize a simple application using Docker.
## Prerequisites
- Docker installed on your machine.
## Step 1: Create a Dockerfile
Create a `Dockerfile` in the root directory of your project with the following content:
```Dockerfile
# Use an official Python runtime as a parent image
FROM python:3.8-slim
# Set the working directory in the container
WORKDIR /usr/src/app
# Copy the current directory contents into the container at /usr/src/app
COPY . .
# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "./app.py"]
docker build -t my-single-container-app .
docker run -p 80:80 my-single-container-app
create a docker-compose.yml
## Step 2: Create a Dockerfile
Refer to the previously provided Dockerfile for a Python Flask application.
## Step 3: Create a `docker-compose.yml` File
Create a `docker-compose.yml` in your project directory with the following content:
```yaml
version: '3.8'
services:
web:
build: .
ports:
- "80:80"
environment:
- FLASK_ENV=development
volumes:
- .:/usr/src/app
This defines a single service called web which will be built using the Dockerfile in the current directory. It binds the host's port 4000 to the container's port 80.
docker-compose up --build
Let's experiment with how creating some data within a container at runtime behaves!
# Build a container image with ubuntu image as base and ping installed
docker build --tag my-ubuntu-image -<<EOF
FROM ubuntu:22.04
RUN apt update && apt install iputils-ping --yes
EOF
# Run a container based on that image
docker run -it --rm my-ubuntu-image
# Confirm that ping was pre-installed
ping google.com -c 1 # Success!
# Create a container from the ubuntu image
docker run -it --rm ubuntu:22.04
# Make a directory and store a file in it
mkdir my-data
echo "Hello from the container!" > /my-data/hello.txt
# Confirm the file exists
cat my-data/hello.txt
exit
If we then create a new container, (as expected) the file does not exist!
# Create a container from the ubuntu image
docker run -it --rm ubuntu:22.04
# Check if the file exists
cat my-data/hello.txt # Produces error: `cat: my-data/hello.txt: No such file or directory`
We can use volumes and mounts to safely persist the data.
# create a named volume
docker volume create my-volume
# Create a container and mount the volume into the container filesystem
docker run -it --rm --mount source=my-volume,destination=/my-data/ ubuntu:22.04
# There is a similar (but shorter) syntax using -v which accomplishes the same
docker run -it --rm -v my-volume:/my-data ubuntu:22.04
# Now we can create and store the file into the location we mounted the volume
echo "Hello from the container!" > /my-data/hello.txt
cat my-data/hello.txt
exit
We can now create a new container and mount the existing volume to confirm the file persisted:
# Create a new container and mount the volume into the container filesystem
docker run -it --rm --mount source=my-volume,destination=/my-data/ ubuntu:22.04
cat my-data/hello.txt # This time it succeeds!
exit
Where is this data located? On linux it would be at /var/lib/docker/volumes... but remember, on docker desktop, Docker runs a linux virtual machine.
# Create a container from the ubuntu image
docker run --interactive --tty --rm ubuntu:22.04
# Try to ping google.com
ping google.com -c 1 # This results in `bash: ping: command not found`
# Install ping
apt update
apt install iputils-ping --yes
ping google.com -c 1 # This time it succeeds!
exit
Let's try that again:
docker run -it --rm ubuntu:22.04
ping google.com -c 1 # It fails! 🤔
It fails the second time because we installed it into that read/write layer specific to the first container, and when we tried again it was a separate container with a separate read/write layer!
We can give the container a name so that we can tell docker to reuse it:
# Create a container from the ubuntu image (with a name and WITHOUT the --rm flag)
docker run -it --name my-ubuntu-container ubuntu:22.04
# Install & use ping
apt update
apt install iputils-ping --yes
ping google.com -c 1
exit
# List all containers
docker container ps -a | grep my-ubuntu-container
docker container inspect my-ubuntu-container
# Restart the container and attach to running shell
docker start my-ubuntu-container
docker attach my-ubuntu-container
# Test ping
ping google.com -c 1 # It should now succeed! 🎉
exit
We generally never want to rely on a container to persist the data, so for a dependency like this, we would want to include it in the image:
# Build a container image with ubuntu image as base and ping installed
docker build --tag my-ubuntu-image -<<EOF
FROM ubuntu:22.04
RUN apt update && apt install iputils-ping --yes
EOF
# Run a container based on that image
docker run -it --rm my-ubuntu-image
# Confirm that ping was pre-installed
ping google.com -c 1 # Success! 🥳
"a text document that contains all the commands a user could call on the command line to assemble an image"
- Start with an operating system
- Install language runtime
- Install application dependencies
- Setup execution environment
- Run application
https://docs.docker.com/engine/reference/builder
This lab shows how you can develop locally with a project that has multiple projects in it. Then create a release version of the Image to push to a production environment. This demonstration should be shown during Deck 2 and after slide 13.
- Make sure Docker extension is installed
- Students version of code: http://tinyurl.com/yrvy4but
- Working version of code: http://tinyurl.com/uh677wv6
-
Download the student version to the Downloads folder on the VM
-
Extract downloaded file
-
Open/Setup Docker
-
Open VSCode and select extracted folder
-
Explain to add the Dockerfile at the root where the solution file is
-
Hand type the values into the Dockerfile while using the comments from the supplied file located here link to explain the steps as you type in the code
-
After entering the values in the Dockerfile open a Terminal window. Shortcut is CTRL `
-
Execute the following to
docker build -t f1api . -
Debug if necessary
-
Show deployed Image in Docker
-
Ask students if they memorize all the commands yet
-
Then open SLN file in Visual Studio 2022
-
Right click API Project file. Add in Dockerfile automatically by selected Docker support
-
Select Target OS as Linux
-
Show students the generated Dockerfile`
-
Debug using Docker
-
Visual Studio shows the running containers
-
Show the swagger interface automatically generated
-
Click on the Ports tab and show the exposed ports







