0% found this document useful (0 votes)
26 views

03-Introduction-to-Docker

Uploaded by

yw113job
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

03-Introduction-to-Docker

Uploaded by

yw113job
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 136

Introduction to

Docker
CSCI-GA 2820, Graduate Division, Computer Science

Instructor:
John J Rofrano
Senior Technical Staff Member | DevOps Champion
IBM T.J. Watson Research Center
[email protected] (@JohnRofrano)
1
Introduction to Docker

THE PERFECT STORM

Cultural Change
Loose Coupling/Binding
Automated Pipeline
RESTful APIs
Everything as Code
Designed to resist failures
Immutable Infrastructure
Test by break / fail fast
DevOps Microservices

AGILITY

Containers Portability
Developer Centric
Ecosystem enabler
Fast startup

@JohnRofrano 2
Introduction to Docker

THE PERFECT STORM: Containers

Cultural Change
Loose Coupling/Binding
Automated Pipeline
RESTful APIs
Everything as Code
Designed to resist failures
Immutable Infrastructure
Test by break / fail fast
DevOps Microservices

Containers Portability
Developer Centric
Ecosystem enabler
Fast startup

@JohnRofrano 3
Introduction to Docker

What Will You Learn?

• What Docker is and isn’t


• Why would you use Docker
• How to use Existing Docker Images
• How to Create your own Docker Images from Docker les

@JohnRofrano 4
fi
Introduction to Docker

Source for This Lab

• Make sure you start Docker Desktop !


• The source for this lab can be found on GitHub at:

git clone https://github.com/nyu-devops/lab-docker.git


cd lab-docker
code .

@JohnRofrano 5
Introduction to Docker

The Lure of
Containers

@JohnRofrano
Introduction to Docker

The Shipping Industry's Solution to Transporting Cargo


(post-1960)
How do you ship cargo of variable sizes efficiently?
• Give the customer a standard sized container
• They can put anything they want in it, but it's their responsibility for what is inside of it
• Build transport ships that can efficiently hold these containers at scale
• Cargo size no longer matters because you only deal with the standard container

@JohnRofrano 7
Introduction to Docker

The IT Industry's Solution to Deploying Applications

How do you deploy applications with variable dependencies?


• Give the developer a standard container
• They can put anything they want in it, but it's their responsibility for what is inside of it
• Build a programmable infrastructure that can efficiently run these containers at scale
• Application dependencies no longer matters because you only deal with the container

+ +
kubernetes

@JohnRofrano 8
Introduction to Docker

Docker Containers
• Docker is a light-weight container service that runs on Linux
• File system overlay
• One Process Space
• One Network Interface
• Shares the Linux kernel with other containers and processes
• Containers encapsulate a run-time environment
• Almost no overhead
• Containers spin up in seconds not minutes like VMs
• Native performance because there is no emulation
• Package only what you need

@JohnRofrano 9
Introduction to Docker

Docker Concepts

• Docker is a platform for developers and


sysadmins to develop, deploy, and run
applications with containers
• The use of Linux containers to deploy
applications is called containerization
• Containers are not new, but Docker make
their use for easily deploying applications
simple

@JohnRofrano 10
Introduction to Docker

Benefits of Containers

• Great isolation
• Great manageability
• Container encapsulates implementation
technology
• Efficient resource utilization
• Fast deployment

@JohnRofrano 11
Introduction to Docker

Containers Enable Immutable Delivery

Build once... run anywhere


• The same binary that a developer runs on their laptop,
runs in production
• All dependencies are package in the container
• Facilitates rolling updates with immediate roll-back
• Consistency limits side-effects

@JohnRofrano 12
Introduction to Docker

Containers
Docker made containers easily
consumable

are not
new

@JohnRofrano 13
Introduction to Docker

Containers are just Linux Capabilities Under the Covers

• Containers are:
- Linux® processes
- with isolation and resource
confinement cpu cpu cpu cpu
cgroups
memory memory memory memory
- that enable you to run processes processes processes processes
sandboxed applications mounts mounts mounts mounts namespaces
networking networking networking networking
- on a shared host kernel
root filesystem root filesystem root filesystem root filesystem chroot
- using cgroups, namespaces, and
chroot Docker Daemon

OS Kernel
@JohnRofrano 14
Introduction to Docker

Docker Containers are just Linux...

• cgroups - Control Groups allow you to control how much resources are allocated to a
process (e.g., memory, cpu. etc.)
• namespaces - control access to what you can see (e.g., processes, mounts, networking, etc.).
What you can't see, you can't access!
• chroot - Allows you to change the root lesystem. This allows the apparent root to be any
linux lesystem whether it be ubuntu, opensuse, redhat or otherwise (i.e., overlay lesystem)

@JohnRofrano 15
fi
fi
fi
Introduction to Docker

Put another way

• Docker Containers allow you to control


- What resources a process can see
- What resources a process can control
- What lesystem a process uses

@JohnRofrano 16
fi
Introduction to Docker

Containers and Virtual Machines

• A container runs natively on Linux and shares the kernel of the host machine with other
containers
- It runs a discrete process, taking no more memory than any other executable, making it
lightweight
• By contrast, a virtual machine (VM) runs a full-blown “guest” operating system with virtual
access to host resources through a hypervisor
- In general, VMs provide an environment with more resources than most applications need

@JohnRofrano 17
Introduction to Docker

Containers vs Virtual Machines


Virtual Machines are heavy-weight emulations of Containers are light-weight process
real hardware The app looks like it’s running on the Host
OS

@JohnRofrano 18
Introduction to Docker

Container
Adoption

19

@JohnRofrano
Introduction to Docker

Container
Adoption
has Grown
75% in 2018

@JohnRofrano 20
Introduction to Docker

Container
Adoption
Continues
to Grow

@JohnRofrano 21
Introduction to Docker

Host Density
is 3x Higher
(16 pods vs 5 tasks)

On average, Kubernetes organizations run


16 pods per host, while organizations using
Amazon Elastic Container Service (ECS) run
5 tasks per host.

@JohnRofrano 22
Introduction to Docker

Large
Enterprises
are Leading
the Way

@JohnRofrano 23
Introduction to Docker

90% of
Containers are
using
Orchestration

Kubernetes is now the fastest-growing orchestration technology


@JohnRofrano 24
Introduction to Docker

OpenShift
Adoption
Grew 28%

@JohnRofrano 25
Introduction to Docker

The
average
Container
lives for 2
days!

In organizations running an orchestrator, the typical lifetime


of a container is about 12 hours. At organizations without
orchestration, the average container lives for 6 days.

@JohnRofrano 26
Introduction to Docker

Top Image Usage

@JohnRofrano 27
Introduction to Docker

Remember: Containers are Cattle and not Pets

• Pets are given names like pussinboots.cern.sh


• They are unique, lovingly hand raised and cared for
• When they get ill, you nurse them back to health

• Cattle are given numbers like vm0042.cern.ch


• They are almost identical to other cattle
• When they get ill, you get another one

@JohnRofrano 28
Introduction to Docker

Containers are:

• Flexible: Even the most complex applications can be containerized


• Lightweight: Containers leverage and share the host kernel
• Interchangeable: You can deploy updates and upgrades on-the- y
• Portable: You can build locally, deploy to the cloud, and run
anywhere
• Scalable: You can increase and automatically distribute container
replicas

@JohnRofrano 29 https://docs.docker.com/get-started/#images-and-containers

fl
Introduction to Docker

Containers are Scaled on Demand

• Cloud Native Microservices use redundancy for


resiliency
• Containers are spun up as needed and destroyed
when no longer needed kubernetes
• This why containers should be immutable and
stateless
A A A … B B

Horizontal Scaling →
@JohnRofrano
30
Introduction to Docker

Vertical vs Horizontal Scalling

A B

A B A A A … B

Vertical Scaling ↑ Horizontal Scaling →


Make servers bigger Make more servers

@JohnRofrano 31
Introduction to Docker

Containers in
Practice

32

@JohnRofrano
Introduction to Docker

Where do Docker @ 20,000 feet


Containers
Come From?

33
@JohnRofrano
Introduction to Docker

Images and containers

• A container is launched by running an image


• An image is an executable package that includes everything needed to run an application--
the code, a runtime, libraries, environment variables, and con guration les
• A container is a runtime instance of an image i.e., what the image becomes in memory when
executed (that is, an image with state, or a user process)
• You can see a list of your running containers with the command, docker ps, just as you
would in Linux

https://docs.docker.com/get-started/#images-and-containers
@JohnRofrano 34

fi
fi
Introduction to Docker

Docker Hub Hosts Official and Community Images

http://hub.docker.com
• Contains 13 million+ Docker images
with almost every software you can
imagine
• Usually “official” images come from
the creator of the software
• Most have documentation on how
to best use them

@JohnRofrano 35
Introduction to Docker

Images Include Documentation

Documentation
• Each image has documentation on
how to use it
• From simply running the container
• To forwarding ports, mapping
storage, etc.

@JohnRofrano 36
Introduction to Docker

Nginx installed and running with one command

Nginx running in a container


We can run nginx as a web server with the
command:

$ docker run -d -p 8080:80 nginx:alpine


Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
6a5a5368e0c2: Pull complete
20a0fbbae148: Pull complete
2fbd37c8684b: Pull complete
Digest:
sha256:e40499ca855c9edfb212e1c3ee1a6ba8b2d873a294d897b4840d49f94d20487c
Status: Downloaded newer image for nginx:latest
0d48962ddc380c421851fb808b9b3007c0c9c614bd08ae7e732955ddaa4c7b4a

Since we don’t have a local nginx image it will be


pulled from Docker hub the first time

@JohnRofrano 37
Introduction to Docker

Docker Provides Portable Isolated Environments

• Docker gives you portable isolated environments


• You could have an application that requires Python 3.6 running in one
container
• With an application that requires Python 2.7 running in another
• Completely isolated from each other will no chance of library
collisions

@JohnRofrano 38
Introduction to Docker Steps for a Fresh Installation of MySQL
1.Adding the MySQL APT Repository
Wordpress First, add the MySQL APT repository to your system's software repository list. Follow these steps:
• Go to the download page for the MySQL APT repository at https://dev.mysql.com/downloads/repo/apt/.

and MySQL
• Select and download the release package for your Linux distribution.
• Install the downloaded release package with the following command, replacing version-specific-package-
name with the name of the downloaded package (preceded by its path, if you are not running the command
inside the folder where the package is):

Traditional shell> sudo dpkg -i /PATH/version-specific-package-name.deb

Installation
For example, for version w.x.y-z of the package, the command is:

Famous 5-Minute Installation shell> sudo dpkg -i mysql-apt-config_w.x.y-z_all.deb


Here's the quick version of the instructions for those who are already
comfortable with performing such installations. More detailed instructions Note that the same package works on all supported Debian and Ubuntu platforms.
follow. • During the installation of the package, you will be asked to choose the versions of the MySQL server and other
If you are not comfortable with renaming files, step 3 is optional and you components (for example, the MySQL Workbench) that you want to install. If you are not sure which version to
can skip it as the install program will create the wp-config.php file for choose, do not change the default options selected for you. You can also choose none if you do not want a
you. particular component to be installed. After making the choices for all components, choose Ok to finish the
1. Download and unzip the WordPress package if you haven't already. configuration and installation of the release package.
2. Create a database for WordPress on your web server, as well as a You can always change your choices for the versions later; see Selecting a Major Release Version for
instructions.
MySQL (or MariaDB) user who has all privileges for accessing and
• Update package information from the MySQL APT repository with the following command (this step is
modifying it.
mandatory):
3. (Optional) Find and rename wp-config-sample.php to wp-
config.php, then edit the file (see Editing wp-config.php) and add shell> sudo apt-get update
your database information.
4. Upload the WordPress files to the desired location on your web
server: 2.Installing MySQL with APT
▪ If you want to integrate WordPress into the root of your domain Install MySQL by the following command:
(e.g. http://example.com/), move or upload all contents of
shell> sudo apt-get install mysql-server
the unzipped WordPress directory (excluding the WordPress
directory itself) into the root directory of your web server.
This installs the package for the MySQL server, as well as the packages for the client and for the database
▪ If you want to have your WordPress installation in its own common files. During the installation, you are asked to supply a password for the root user for your MySQL
subdirectory on your website (e.g. http://example.com/
installation.
blog/), create the blog directory on your server and upload the
contents of the unzipped WordPress package to the directory via
FTP. 3.Starting and Stopping the MySQL Server
▪ Note: If your FTP client has an option to convert file names to The MySQL server is started automatically after installation. You can check the status of the MySQL server with
lower case, make sure it's disabled. the following command:
5. Run the WordPress installation script by accessing the URL in a web
browser. This should be the URL where you uploaded the WordPress shell> sudo service mysql status
files.
▪ If you installed WordPress in the root directory, you should visit: Stop the MySQL server with the following command:
http://example.com/
shell> sudo service mysql stop
▪ If you installed WordPress in its own subdirectory called blog, for
example, you should visit: http://example.com/blog/ To restart the MySQL server, use the following command:
That's it! WordPress should now be installed.
shell> sudo service mysql start
39
@JohnRofrano
Introduction to Docker

Wordpress
and MySQL
with
Docker

docker run -d --name db mysql


docker run -d --link db -p 80:80 wordpress

40
@JohnRofrano
Introduction to Docker

Docker Compose

• Allows you to deploy multiple containers at the


same time
• Allows linking of containers together so that
they can talk to each other
• Containers can be managed easily using:
- docker-compose up
- docker-compose down

WordPress
@JohnRofrano 41
Introduction to Docker

Example docker-compose.yml file

From the web app, postgres is available at: postgres://db:5432


version: "3"
services:
web:
build: . Web application named "web"
ports: built from source
with port 8080 forwarded
- "8080:8080"
db:
image: postgres Postgres database named "db"
ports: with port 5432 forwarded
- "5432:5432"

@JohnRofrano 42
Introduction to Docker
version: '3'

Wordpress services:
wordpress:
Example image: wordpress
ports:
- "8080:80"
environment:
- WORDPRESS_DB_HOST=db
networks:
- overlay
depends_on:
- db

db:
image: mysql
volumes:
- wordpress-data:/var/lib/mysql/data
networks:
- overlay

volumes:
wordpress-data:

networks:
overlay:
@JohnRofrano 43
Introduction to Docker

Traditional Development Workflow

@JohnRofrano 44
Introduction to Docker

Containerized Development Workflow

@JohnRofrano 45
Introduction to Docker

This is a
Very • Significant time is spent trying to
Powerful make development, test, and
Concept production environments the same
• Docker allow the same container
that is built and tested in
development to run unchanged in
production
• You can literally deploy an entire
environment with a single command

46
@JohnRofrano
Introduction to Docker

Creating Your
Own Docker
Images

47

@JohnRofrano
Introduction to Docker

Images from Dockerfiles


FROM python:3.11-slim

# Create working folder


WORKDIR /app
• Whatever is needed to build the image is specified in
the Dockerfile and checked into GitHub # Install dependencies
("infrastructure as code") COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
• Anyone who uses this image is guaranteed to get the
same service instance # Copy the application contents
COPY service/ ./service/
• You can start from an operating system image and
install all of the prerequisites just like on a VM # Switch to a non-root user
• Then copy your application code and resolve and RUN useradd vagrant && chown -R vagrant /app
USER vagrant
library dependencies
• Finally add the command to run your application # Expose any ports the app needs
ENV FLASK_APP=service:app
ENV PORT 8080
EXPOSE $PORT

ENV GUNICORN_BIND 0.0.0.0:$PORT


CMD ["gunicorn", "--log-level=info", "service:app"]

@JohnRofrano 48
Introduction to Docker $ docker build -t hitcounter:1.0 .
Sending build context to Docker daemon 343kB
Step 1/12 : FROM python:3.11-slim

Docker build command


---> b281745b6df9
Step 2/12 : WORKDIR /app
---> Running in 99d82d26114e
Removing intermediate container 99d82d26114e
---> 59e8342ce6e8
Step 3/12 : COPY requirements.txt .
---> a4b662621da2

• The docker build command is used to build an image Step 4/12 : RUN pip install --no-cache-dir -r requirements.txt
---> Running in dfed65002625

from a Dockerfile Removing intermediate container dfed65002625


---> 9407105b63a9
Step 5/12 : COPY service/ ./service/
• Docker uses a layered filesystem and will reuse layers ---> 8882fa2453d8
Step 6/12 : RUN useradd vagrant && chown -R vagrant /app
that have previously been built and not modified ---> Running in fe275127eb35
Removing intermediate container fe275127eb35
---> bd9ee1cb3824
• It will even reuse layers across images Step 7/12 : USER vagrant
---> Running in 9ba19ac6279e
Removing intermediate container 9ba19ac6279e
• In the example on the right, all layers except the ---> c2c20ada1967
Step 8/12 : ENV FLASK_APP=service:app
application layer are cached resulting in a very quick ---> Running in ed417c65c016
Removing intermediate container ed417c65c016
build ---> 5035075d8b08
Step 9/12 : ENV PORT 8080
---> Running in a14281988d29
Removing intermediate container a14281988d29
---> 7dd2bd38eff9
Step 10/12 : EXPOSE $PORT
---> Running in cd333fe0d007
Removing intermediate container cd333fe0d007
---> 0e911d5d3561
Step 11/12 : ENV GUNICORN_BIND 0.0.0.0:$PORT
---> Running in 8bd23334a387
Removing intermediate container 8bd23334a387
---> d8e6af1f09a3
Step 12/12 : CMD ["gunicorn", "--log-level=info", "service:app"]
---> Running in e3baf72ff581
Removing intermediate container e3baf72ff581
---> 081b4418e068
Successfully built 081b4418e068
Successfully tagged hitcounter:1.0
@JohnRofrano 49
Introduction to Docker

Docker Layered Filesystem

• Docker uses a Copy-On-Write layered lesystem


- Only changes from the read-only layers are copied
• You can see the layers when you pull or push an image

$ docker pull ubuntu:15.04

15.04: Pulling from library/ubuntu


1ba8ac955b97: Pull complete
f157c4e5ede7: Pull complete
0b7e98f84c4c: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
Status: Downloaded newer image for ubuntu:15.04

@JohnRofrano 50
fi
Introduction to Docker

Images and Layers

• Each Docker image references a list of read-


only layers that represent lesystem
differences
• Layers are stacked on top of each other to
form a base for a container’s root lesystem
• When you create a new container, you add a
new, thin, writable layer on top of the
underlying stack
• All changes made to the running container -
such as writing new les, modifying existing
les, and deleting les - are written to this thin
writable container layer
@JohnRofrano 51
fi
fi
fi
fi
fi
Introduction to Docker

Base Image

• Start with a base image

Image base layer file1 file2

Docker container
(AUFS storage-driver demonstrating whiteout le)

@JohnRofrano 52
fi
Introduction to Docker

Container Layers are exposed to Top

• Files from the read-only layers below are visible to the top layer

Container top layer file1 file2

Image base layer file1 file2

Docker container
(AUFS storage-driver demonstrating whiteout le)

@JohnRofrano 53
fi
Introduction to Docker

Add Layers with more Files

• As you add layers more les become visible at the top layer

Container top layer file1 file2 file3

Image layer 1 file3

Image base layer file1 file2

Docker container
(AUFS storage-driver demonstrating whiteout le)

@JohnRofrano 54
fi
fi
Introduction to Docker

New Versions

• A new version of file1 is added and it hides the old file1 version

Container top layer file1 file2 file3 file4

Image layer 2 file1 file4

Image layer 1 file3

Image base layer


X
file1 file2

Docker container
(AUFS storage-driver demonstrating whiteout le)

@JohnRofrano 55
fi
Introduction to Docker

White-out Files

• Special les called "white-out" les are used to make les appear to be deleted

Container top layer file1 .wh.file2 file3 file4

X
Image layer 2 file1 file4

Image layer 1 file3

Image base layer


X
file1 file2

Docker container
(AUFS storage-driver demonstrating whiteout le)

@JohnRofrano 56
fi
fi
fi
fi
Introduction to Docker

How Layers are Reused

• Note when you provision with Vagrant how Redis:Alpine reuses Alpine layer:
==> default: Running provisioner: docker...
default: Installing Docker onto machine...
==> default: Pulling Docker images...
==> default: -- Image: alpine:latest
==> default: stdin: is not a tty
==> default: latest: Pulling from library/alpine Alpine layer is being reused
==> default: 3690ec4760f9: Pulling fs layer by Redis:Alpine
==> default: 3690ec4760f9: Verifying Checksum
==> default: 3690ec4760f9: Download complete
==> default: 3690ec4760f9: Pull complete
==> default: Digest: sha256:1354db23ff5478120c980eca1611a51c9f2b88b61f24283ee8200bf9a54f2e5c
==> default: Status: Downloaded newer image for alpine:latest
==> default: -- Image: redis:alpine
==> default: stdin: is not a tty
==> default: alpine: Pulling from library/redis
==> default: 3690ec4760f9: Already exists
==> default: 5e231f7bdf9d: Pulling fs layer
==> default: 5a74fb2950f8: Pulling fs layer
. . .

@JohnRofrano 57
Introduction to Docker

Docker Volumes

• Volumes are easier to back up or migrate than bind


mounts.
• You can manage volumes using Docker CLI commands
or the Docker API.
• Volumes work on both Linux and Windows containers.
• Volumes can be more safely shared among multiple
containers.
• Volume drivers let you store volumes on remote hosts
or cloud providers, to encrypt the contents of volumes,
or to add other functionality.
• New volumes can have their content pre-populated by
a container

@JohnRofrano 58
Introduction to Docker

Bind Mount Volumes for Redis

######################################################################
# Add Redis docker container
######################################################################
config.vm.provision "shell", inline: <<-SHELL
# Prepare Redis data share
sudo mkdir -p /var/lib/redis/data
sudo chown vagrant:vagrant /var/lib/redis/data
SHELL
Volume in container
# Add Redis docker container volume on the host
config.vm.provision "docker" do |d|
d.pull_images "redis:alpine"
d.run "redis:alpine",
args: "--restart=always -d --name redis -h redis -p 6379:6379 -v /var/lib/redis/data:/data"
end

@JohnRofrano 59
Introduction to Docker

Using a Docker Volume for Redis

• We simple give docker a name for the volume like: redis_data


• Docker manages this volume for us
Docker managed volume
on the host
# Add Redis docker container
config.vm.provision "docker" do |d|
d.pull_images "redis:alpine"
d.run "redis:alpine",
args: "--restart=always -d --name redis -h redis -p 6379:6379 -v redis_data:/data"
end

Volume in container

@JohnRofrano 60
Introduction to Docker

Docker volume ls

• We can use docker volume ls to list the volumes:


$ docker volume ls
DRIVER VOLUME NAME
local redis_volume

An example with named and un-named volumes


$ docker volume ls
DRIVER VOLUME NAME
local 4e469efb9599682f89ff417174256b752afd870c54546021a36d2955d379c4f5
local 87df74bab30c1a4e9f78d4e4a7771b69a2cc5b347d55184d3791204997eaa109
local 368efa07e9f64be73ace7d75c788a363433f3f2007b3de8b74972632d8fcab29
local cbd7d35d1695b927b59613ee7c9f2cb9b65ed6a9aecbf7745aa233552a9e24de
local mysql-data
local postgres-data
@JohnRofrano 61
Introduction to Docker

Use Minimal Images Whenever Possible

Docker Images
• Minimal images are more secure because they REPOSITORY TAG SIZE
have a smaller attack surface centos latest 202MB
debian stretch-slim 55.3MB
• Don't load anything into an image that you don't debian latest 101MB
need ubuntu
ubuntu
16.04
latest
117MB
86.7MB
• Minimal images load faster python 2-alpine 58.3MB
python 2.7-slim 120MB
• Alpine is only 4.4MB compared to Ubuntu 16.04 python 3.7-alpine 78.2MB
python 3.7-slim 143MB
at 117MB! bitnami/minideb latest 53.7MB
• PostgreSQL Alpine is 71MB vs 228MB alpine
alpine
latest
3.7
4.41MB
4.21MB
postgres alpine 71.6MB
postgres latest 228MB

@JohnRofrano 62
Introduction to Docker

Containers
should be... • Stateless
- All state should be maintained in a Database, Object Store, or
Persistent Volume

• Light Weight
- Only one process per container i.e., Container dies when
process dies

• Immutable
- Do not install an ssh daemon or any other means of entering
the container!

• Run from Docker Registry Images or Built from Dockerfiles


- Treated like code, versioned, and reconstituted when
needed… not built by hand!
63
@JohnRofrano
Introduction to Docker

What do we mean by Stateless?

• When we say STATE what do we mean?


- Any pieces of data about the client or transaction
- Could be the state of a session with the end-user
- These should be persisted somewhere (database, session cache,
etc.) but NOT in memory!

@JohnRofrano 64
Introduction to Docker

What Docker Is NOT?

• Docker is NOT a Virtual Machine!


- Resist the temptation of putting a monolith
in a container
- Resist the urge to run more than one
process per container
- It’s a bad idea to store state in a container
(just don’t do it!)

@JohnRofrano 65
Introduction to Docker

What Can you Do with Docker?

• You can run Containers from the Images in the Docker Registry (e.g., Docker Hub)
• You can build Docker Images that hold your applications and their dependancies
• You can create Docker Containers from those Docker images to run your applications
• You can share those Docker images via Docker Hub or your own Docker registry
• You can pull those images from the Docker registry to deploy them as Containers on a
server running Docker Engine
• You can even deploy those containers in the IBM Cloud Kubernetes Cloud!

@JohnRofrano 66
Hands-On

@JohnRofrano 67
Introduction to Docker

Focus for this Lab

• Bring up the lab environment with Docker


• Run a Container from an existing Docker Image
• Create a simple Docker le that spins up a Web Server
• Create a more complex Docker le and deploy it

@JohnRofrano 68
fi
fi
Introduction to Docker

Some Assembly Required

• Tools you will need to complete this lab:


- Computer running macOS, Linux, or
Windows
- Internet Access to download Docker Images
- Text Editor (e.g., Visual Studio Code)
- GitHub Account

@JohnRofrano 69
Introduction to Docker

Docker Desktop for Mac or Windows


https://www.docker.com/products/docker-desktop

@JohnRofrano 70
Introduction to Docker

Create Virtual Development Environment

• Using Visual Studio Code and Docker is the easiest way to prepare for this lab
• Make sure Docker Desktop or Rancher Desktop is running
• Just issue the following commands:

$ git clone https://github.com/nyu-devops/lab-docker.git


$ cd lab-docker
$ code .

@JohnRofrano 71
Introduction to Docker

What is in the Dev Environment?

• Creates an Python 3.11 container based on Debian 11 (Bullseye)


• Installs Docker Engine
• Pulls a Redis image
• Pulls a Python 3.11 image
• Installs Docker Compose

@JohnRofrano 72
Introduction to Docker

Test the Installation

• Let’s run a Docker “Hello World” container to test our installation:


(venv) vagrant@kubernetes:~$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world docker pulls hello-world from docker hub
1b930d010525: Pull complete
Digest: sha256:c3b4ada4687bbaa170745b3e4dd8ac3f194ca95b2d0518b417fb47e5879d9b5f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!


This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:


1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:


https://docs.docker.com/get-started/
@JohnRofrano 73
Introduction to Docker

What Did Docker Run Do?

• It checked the local Docker Image cache to see if hello-world was there

• If it was not, it downloaded the hello-world image from hub.docker.com

• Once downloaded it ran a hello-world container from the image

@JohnRofrano 74
Introduction to Docker

Docker Images

• We can run docker images to see what Images we have locall

These are from the


vscode@nyu:/app$ docker images Dev Environment
REPOSITORY TAG IMAGE ID CREATED SIZE
python 3.11-slim 5311e96648df 6 days ago 125MB
redis 6-alpine 34e1dc356a22 8 days ago 32.4MB
alpine latest 0ac33e5f5afa 8 days ago 5.57MB
hello-world latest 46331d942d63 3 weeks ago 9.14kB

Here is the hello-world image we just pulled

@JohnRofrano 75
Introduction to Docker

Working With Docker

• We can run docker ps to see what containers we have running


$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab46390b31b7 redis:6-alpine "docker-entrypoint.sh" 26 minutes ago Up 26 minutes 0.0.0.0:6379->6379/tcp redis

@JohnRofrano 76
Introduction to Docker

Working With Docker

• We can run docker ps to see what containers we have running


$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab46390b31b7 redis:6-alpine "docker-entrypoint.sh" 26 minutes ago Up 26 minutes 0.0.0.0:6379->6379/tcp redis

• We can use the -a switch to see all containers, even stopped ones
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9a25d7302cf0 hello-world "/hello" 17 minutes ago Exited (0) 17 minutes ago silly_boyd
ab46390b31b7 redis:6-alpine "docker-entrypoint.sh" 29 minutes ago Up 29 minutes 0.0.0.0:6379->6379/tcp redis

@JohnRofrano 77
Introduction to Docker

Remove Exited Containers

• We can remove a container that has exited with the command:


docker rm <container id> | <name>

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9a25d7302cf0 hello-world "/hello" 17 minutes ago Exited (0) 17 minutes ago silly_boyd
ab46390b31b7 redis:alpine "docker-entrypoint.sh" 29 minutes ago Up 29 minutes 0.0.0.0:6379->6379/tcp redis

$ docker rm silly_boyd Remove the container named “silly_boyd”


silly_boyd

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab46390b31b7 redis:alpine "docker-entrypoint.sh" 29 minutes ago Up 29 minutes 0.0.0.0:6379->6379/tcp redis

@JohnRofrano 78
Introduction to Docker

Remove Unwanted Images

• We can remove an image that we no longer with the:


docker rmi <image id> | <repository:tag>

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis alpine 906fffc0e2f4 35 hours ago 20.38 MB
alpine latest baa5d63471ea 39 hours ago 4.803 MB
hello-world latest c54a2cc56cbb 3 months ago 1.848 kB
$ docker rmi c54a2cc56cbb
Untagged: hello-world:latest Remove the image with id “c54a2cc56cbb”
Untagged: hello-world@sha256:0256e8a36e2070f7bf2d0b0763dbabdd67798512411de4cdcf9431a1feb60fd9
Deleted: sha256:c54a2cc56cbb2f04003c1cd4507e118af7c0d340fe7e2720f70976c4b75237dc
Deleted: sha256:a02596fdd012f22b03af6ad7d11fa590c57507558357b079c3e8cebceb4262d7

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis alpine 906fffc0e2f4 35 hours ago 20.38 MB
alpine latest baa5d63471ea 39 hours ago 4.803 MB

@JohnRofrano 79
Introduction to Docker

Creating
Containers
from Images

80

@JohnRofrano
Introduction to Docker

Lets Use an Existing Docker Image

• Docker Images can be used as-is as a quick way of providing middleware


• Let’s run NGINX without installing anything!

@JohnRofrano 81
Introduction to Docker

Where To Get Images?


https://hub.docker.com/_/nginx/

• Docker Hub
• Contains 1000’s of Docker
images with almost every Let’s use nginx to create a web site
software you can imagine
• Usually “of cial” images come
from the creator of the software
• Most have documentation on
how to best use them

@JohnRofrano 82
fi
Introduction to Docker

Most Images Have Documentation

Container docs will tell you how to run them

@JohnRofrano 83
Introduction to Docker

Let’s Run Nginx

• We can run nginx as a web server with the command:

docker run -d -p 8080:80 nginx:alpine

Run as a Daemon

$ docker run -d -p 8080:80 nginx:alpine


8e82325aa105cb0bc4f192649f01c32e988045bc59b5d036d5c90505f2cf662d

Map port 80 in container Run nginx from local cache or Docker Hub
to 8080 on the Host

@JohnRofrano 84
Introduction to Docker

NGINX will be Pulled

• Since we don’t have a local nginx image it will be pulled from Docker hub the rst time

$ docker run -d -p 8080:80 nginx:alpine

Unable to find image 'nginx:alpine' locally


alpine: Pulling from library/nginx
89d9c30c1d48: Already exists
110ad692b782: Pull complete
Digest: sha256:559cde0e812dba817c131173217712bf34c2c80a0b6892409cbcf7d760fca8be
Status: Downloaded newer image for nginx:alpine
53cee8d8cf12ca91e7b2fd9173d03772757c36851cf70a855210005e9fa9b26e

@JohnRofrano 85

fi
Introduction to Docker

In A Web browser

Goto http://localhost:8080/

@JohnRofrano 86
Introduction to Docker

Stop a Container

• We can stop the running container with the command:


docker stop <container name> | <container id>
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d48962ddc38 nginx:alpine "nginx -g 'daemon off" 4 minutes ago Up 4 minutes 443/tcp, 0.0.0.0:8080->80/tcp stoic_shaw
ab46390b31b7 redis:alpine "docker-entrypoint.sh" 51 minutes ago Up 51 minutes 0.0.0.0:6379->6379/tcp redis

$ docker stop stoic_shaw Stop container “stoic_shaw”


stoic_shaw

$ docker rm stoic_shaw
stoic_shaw
Remove container “stoic_shaw”

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab46390b31b7 redis:alpine "docker-entrypoint.sh" 52 minutes ago Up 52 minutes 0.0.0.0:6379->6379/tcp redis

@JohnRofrano 87
Introduction to Docker

Add Your Content To Nginx

• Add some content to /home/vscode


cd /home/vscode
echo '<html><body><h1>Hello World</h1></body></html>' > index.html

• We can map a local lesystem with the -v (volume) option:


docker run -d --name nginx -p 8080:80 -v /home/vscode:/usr/share/nginx/html:ro
nginx:alpine

@JohnRofrano 88
fi
Introduction to Docker

Check In A Web browser

Goto http://localhost:8080/

@JohnRofrano 89
Introduction to Docker

Dynamic Development

• You can now change the les in that folder and the changes will be re ected in the web
browser
• Try it and see...
• Then stop the container with:

$ docker stop nginx

$ docker rm nginx

@JohnRofrano 90
fi
fl
Introduction to Docker

Creating
Containers
from
Dockerfiles

91

@JohnRofrano
Introduction to Docker

Using A Dockerfile

• We can create a new Image from a Dockerfile


• The Dockerfile is just a text le that contains the commands to build the image
• This allows you to treat Images like code

@JohnRofrano 92
fi
Introduction to Docker

Create nginx from Dockerfile

• We can create a Docke le to add our own content to the image


• Create a le called Dockerfile and add the following two lines:

Start FROM the nginx image that’s in Docker Hub

FROM nginx:alpine
COPY content /usr/share/nginx/html

COPY the folder called 'content' to '/usr/share/nginx/html' inside the container

@JohnRofrano 93
fi
fi
Introduction to Docker

What is /usr/share/nginx/html?

• /usr/share/nginx/html is where nginx is looking for a web site


• We want to copy the contents of our local folder into this
• It will create a container that includes the web site

@JohnRofrano 94
Introduction to Docker

Create the Content

• Next create a content folder and move the index.html le into it


• Finally build the container
$ mkdir content
$ mv index.html content/
$ vi Dockerfile
$ docker build -t my-nginx .
Sending build context to Docker daemon 22.02 kB
Step 1 : FROM nginx
---> 0d409d33b27e
Step 2 : COPY content /usr/share/nginx/html
---> 16d63ce8beff
Removing intermediate container e286a6fd3eca
Successfully built 16d63ce8beff
$ docker run -d --name nginx -p 8080:80 my-nginx
765743b8ec5671761c3dd479026fd131ac11c9911b89046c87134a1cb2178218
@JohnRofrano 95

fi
Introduction to Docker

Check In A Web browser

Goto http://localhost:8080/

@JohnRofrano 96
Introduction to Docker

Stop and remove my-nginx

• Stop the nginx service are remove it

$ docker stop nginx

$ docker rm nginx

@JohnRofrano 97
Introduction to Docker

Containers should be small

• Its a good practice to use a tiny Linux


distribution for building containers
• Docker images should only contain the app
and it’s required libraries (not a whole OS!)
• Small distributions have a small attack surface
and are more secure
• Alpine is perfect for this base OS

@JohnRofrano 98
Introduction to Docker FROM python:3.11-slim

Project # Create working folder and install dependencies


WORKDIR /app
Dockerfile COPY requirements.txt .
RUN pip install -U pip wheel && \
pip install --no-cache-dir -r requirements.txt

# Copy the application contents


COPY wsgi.py .
COPY service/ ./service/

# Switch to a non-root user


RUN useradd --uid 1000 vagrant && chown -R vagrant /app
USER vagrant

# Expose any ports the app is expecting in the environment


ENV FLASK_APP=wsgi:app
ENV PORT 8080
EXPOSE $PORT

ENV GUNICORN_BIND 0.0.0.0:$PORT


ENTRYPOINT ["gunicorn"]
@JohnRofrano CMD ["--log-level=info",
99 "wsgi:app"]
Introduction to Docker

Run the app before building the image

• Use honcho start to start the service

$ cd /app

$ honcho start

[2019-11-20 00:54:33 +0000] [1] [INFO] Starting gunicorn 20.0.0


[2019-11-20 00:54:33 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1)
[2019-11-20 00:54:33 +0000] [1] [INFO] Using worker: sync
[2019-11-20 00:54:33 +0000] [9] [INFO] Booting worker with pid: 9
[2019-11-20 00:54:33 +0000] [9] [INFO] **********************************************************************
[2019-11-20 00:54:33 +0000] [9] [INFO] ************** H I T C O U N T E R S E R V I C E ***************
[2019-11-20 00:54:33 +0000] [9] [INFO] **********************************************************************
[2019-11-20 00:54:33 +0000] [9] [INFO] Service inititalized!

@JohnRofrano 100
Introduction to Docker

Check the Running Service @ localhost:8080

Goto http://localhost:8080

Select the /counters link

@JohnRofrano 101
Introduction to Docker

No counters yet

@JohnRofrano 102
Introduction to Docker

Create a counter

• Use http POST localhost:8080/counters/foo


$ http POST localhost:8080/counters/foo
HTTP/1.1 201 CREATED
Connection: close
Content-Length: 37
Content-Type: application/json
Date: Wed, 13 Apr 2022 20:41:51 GMT
Location: http://localhost:8080/counters/foo
Server: gunicorn

{
"counter": 0,
"name": "foo"
}

@JohnRofrano 103
Introduction to Docker

Increment the counter

• Use http PUT localhost:8080/counters/foo

$ http PUT localhost:8080/counters/foo


$ http PUT localhost:8080/counters/foo
$ http PUT localhost:8080/counters/foo
{
"counter": 3,
"name": "foo"
}

@JohnRofrano 104
Introduction to Docker

Check the counter

@JohnRofrano 105
Introduction to Docker

Stop the service

• Use Ctrl+C to stop the service

$ Ctrl+C

^C20:49:03 system | SIGINT received


20:49:03 system | sending SIGTERM to web.1 (pid 2532)
20:49:03 web.1 | [2022-04-13 20:49:03 +0000] [6310] [INFO] Worker exiting (pid: 6310)
20:49:03 web.1 | [2022-04-13 20:49:03 +0000] [2533] [INFO] Handling signal: term
20:49:03 web.1 | [2022-04-13 20:49:03 +0000] [2533] [WARNING] Worker with pid 6310 was
terminated due to signal 15
20:49:03 web.1 | [2022-04-13 20:49:03 +0000] [2533] [INFO] Shutting down: Master
20:49:03 system | web.1 stopped (rc=-15)

@JohnRofrano 106
Introduction to Docker

Build the image

• Use docker build to build an image

$ docker build -t hitcounter:1.0 .

@JohnRofrano 107
$ cd /app
Introduction to Docker $ docker build -t hitcounter:1.0 .

Sending build context to Docker daemon 443.4kB

Build the Step 1/9 : FROM python:3.11-slim


---> 07ee12a5eb2a
Step 2/9 : WORKDIR /app

Dockerfile ---> Running in c1e559050e81


Removing intermediate container c1e559050e81
---> 3038f6baa90d
Step 3/9 : COPY requirements.txt /app
---> f1f0fa408d34
Step 4/9 : RUN pip install --no-cache-dir -r requirements.txt
---> Running in 282e12ad02ff
Collecting Flask==1.1.1
Downloading https://files.pythonhosted.org/packages/9b/
93/628509b8d5dc749656a9641f4caf13540e2cdec85276964ff8f43bbb1d3b/Flask-1.1.1-py2.py3-none-any.whl (94kB)

... lots of python packages get installed here ...

Step 5/9 : COPY service/ /app/service/


---> 434eb6e1e911
Step 6/9 : ENV PORT 8080
---> Running in ae8c0dbce3b7
Removing intermediate container ae8c0dbce3b7
---> 38b81826fcec
Step 7/9 : EXPOSE $PORT
---> Running in 9a359968e7b3
Removing intermediate container 9a359968e7b3
---> a8e7d7e360f6
Step 8/9 : ENV GUNICORN_BIND 0.0.0.0:$PORT
---> Running in f4b72400abec
Removing intermediate container f4b72400abec
---> 813303bb1801
Step 9/9 : CMD ["gunicorn", "--log-level=info", "service:app"]
---> Running in 3b71a2ccbe1e
Removing intermediate container 3b71a2ccbe1e
---> 8ac3c707ab08
@JohnRofrano Successfully built 8ac3c707ab08 108
Successfully tagged hitcounter:1.0
Introduction to Docker

Check Your Images

• docker images

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hitcounter 1.0 8ac3c707ab08 2 minutes ago 239MB
python 3.9-slim 07ee12a5eb2a 4 days ago 179MB
nginx alpine b6753551581f 4 weeks ago 21.4MB
redis alpine 6f63d037b592 4 weeks ago 29.3MB
alpine latest 965ea09ff2eb 4 weeks ago 5.55MB
$

This is the new hit counter:1.0 image that you just built

@JohnRofrano 109
Introduction to Docker

Run the Container

• docker run --rm -p 8080:8080 hitcounter:1.0


$ docker run --rm -p 8080:8080 hitcounter:1.0

[2019-11-20 00:54:33 +0000] [1] [INFO] Starting gunicorn 20.0.0


[2019-11-20 00:54:33 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1)
[2019-11-20 00:54:33 +0000] [1] [INFO] Using worker: sync
[2019-11-20 00:54:33 +0000] [9] [INFO] Booting worker with pid: 9
[2019-11-20 00:54:33 +0000] [9] [INFO] **********************************************************************
[2019-11-20 00:54:33 +0000] [9] [INFO] ************** H I T C O U N T E R S E R V I C E ***************
[2019-11-20 00:54:33 +0000] [9] [INFO] **********************************************************************
[2019-11-20 00:54:33 +0000] [9] [INFO] Service inititalized!

@JohnRofrano 110
Introduction to Docker

Check the Running Service @ localhost:8080

Goto http://localhost:8080

Select the /counters link

@JohnRofrano 111
Introduction to Docker

What Happened?

@JohnRofrano 112
Introduction to Docker

Where is Redis?

• Redis is running in a container which responds to 127.0.0.1:6379 because we forwarded the


port to the local host
• You can talk to from the local host through it’s forwarded port
• Python running in a Container cannot talk to the local host and so it cannot talk to Redis
• We must link the containers together

@JohnRofrano 113
Introduction to Docker

Running in a VM

• Your code is running on localhost


• The container is exposed on localhost
• Your app sees the redis container docker run -d -p 6379:6379 redis

Redis Container

localhost:6379

lab-docker app local host

@JohnRofrano 114
Introduction to Docker

Running in a Container

• Your code is running in a container not on localhost


• Your app can no longer see redis
docker run -d -p 6379:6379 redis

hitcounter Container Redis Container

docker run -d hitcounter:1.0

localhost:6379

local host

@JohnRofrano 115
Introduction to Docker

Solution

• Use the --link command to link to redis container

• Your app can no now see redis


docker run -d --name redis —p 6379:6379 redis
--link redis
hitcounter Container Redis Container

docker run -d --link redis hitcounter:1.0

localhost:6379
Linkage is performed by name
local host

@JohnRofrano 116
Introduction to Docker

Add environment variable to match link

• We can use the --link command to tell lab-docker where redis is:
• We use an environment variable to give our app the new DATABASE_URI

docker run --rm -p 8080:8080 \


--link redis \
-e DATABASE_URI="redis://redis:6379/0" \
hitcounter:1.0

@JohnRofrano 117
Introduction to Docker

Linking Containers

$ docker run --rm -p 8080:8080 --link redis -e DATABASE_URI="redis://redis:6379/0" hitcounter:1.0

[2023-06-25 15:10:48 +0000] [1] [INFO] Starting gunicorn 20.1.0


[2023-06-25 15:10:48 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1)
[2023-06-25 15:10:48 +0000] [1] [INFO] Using worker: sync
[2023-06-25 15:10:48 +0000] [7] [INFO] Booting worker with pid: 7
[2023-06-25 15:10:48 +0000] [INFO] [log_handlers] Logging handler established
[2023-06-25 15:10:48 +0000] [INFO] [__init__] *************************************************************
[2023-06-25 15:10:48 +0000] [INFO] [__init__] ********** H I T C O U N T E R S E R V I C E **********
[2023-06-25 15:10:48 +0000] [INFO] [__init__] *************************************************************
[2023-06-25 15:10:48 +0000] [INFO] [__init__] Service initialized!
[2023-06-25 15:10:48 +0000] [INFO] [__init__] Initializing the Redis database
[2023-06-25 15:10:48 +0000] [INFO] [models] Attempting to connecting to Redis...
[2023-06-25 15:10:48 +0000] [INFO] [models] Connection established
[2023-06-25 15:10:48 +0000] [INFO] [models] Successfully connected to Redis
[2023-06-25 15:10:48 +0000] [INFO] [__init__] Connected!

@JohnRofrano 118
Introduction to Docker

Try Again

Goto http://localhost:8080/counters

@JohnRofrano 119
Introduction to Docker

Running Commands

• Start a container called "redis"

- docker run -d --name redis -p 6379:6379 redis:alpine


• Call redis-cli with parameters

- docker exec -it redis redis-cli incr mycounter

@JohnRofrano 120
Introduction to Docker

Multi-stage Builds

FROM python:3.11-slim as builder

WORKDIR /install
COPY requirements.txt /requirements.txt
RUN pip install --install-option="--prefix=/install" -r /requirements.txt

FROM python:3.11-slim
COPY --from=builder /install /usr/local

WORKDIR /app
COPY src .

CMD ["gunicorn", "-w 4", "wsgi:app"]


@JohnRofrano 121
Introduction to Docker

Docker Compose

• Allows you to deploy multiple containers at the same time


• Allows linking of containers together so that they can talk to each other
• Containers can be managed easily using tag names

@JohnRofrano 122
Introduction to Docker

docker-compose.yml

From the web app, postgres is available at: postgres://db:5432

version: "3"
services:
web:
build: .
ports:
- "8080:8080"
db:
image: postgres
ports:
- "5432:5432"

@JohnRofrano 123
Introduction to Docker version: '3'

Wordpress services:
wordpress:
Example image: wordpress
ports:
- "8080:80"
networks:
- overlay
restart: always

mysql:
image: mysql
volumes:
- wordpress-data:/var/lib/mysql/data
networks:
- overlay
restart: always

volumes:
wordpress-data:

networks:
@JohnRofrano overlay: 124
version: "3"
Introduction to Docker
services:
app:

Compose build: .
image: hitcounter:1.0

for our App container_name: hitcounter


ports:
- "8080:8080"
environment:
DATABASE_URI: "redis://:@redis:6379/0"
depends_on:
- redis
networks:
- web

redis:
image: redis:alpine
restart: always
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- web

volumes:
redis-data:

networks:
@JohnRofrano web: 125
Introduction to Docker

Stop existing Redis container

• We can bring down the existing Redis containers with:

$ docker stop redis


redis

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

@JohnRofrano 126
Introduction to Docker

Docker $ docker compose up -d

compose Creating
Creating
network "vagrant_web" with the default driver
volume "vagrant_redis-data" with default driver
Creating vagrant_redis_1 ... done
Creating hitcounter ... done

$ docker compose ps
• We can bring
up both Name Command State Ports
---------------------------------------------------------------------------------
containers hitcounter gunicorn --log-level=info ... Up 0.0.0.0:8080->8080/tcp
together: vagrant_redis_1 docker-entrypoint.sh redis ... Up 0.0.0.0:6379->6379/tcp

$ docker compose down

Stopping hitcounter ... done


Stopping vagrant_redis_1 ... done
Removing hitcounter ... done
Removing vagrant_redis_1 ... done
Removing network vagrant_web

@JohnRofrano 127
Introduction to Docker

Docker Compose management

• docker compose up
• docker compose build
• docker compose start | stop
• docker compose ps
• …and more

@JohnRofrano 128
Introduction to Docker
• If you want to see the commands that create the layers in your docker image you can
docker use the history option

history $ docker history hitcounter:1.0


IMAGE CREATED CREATED BY SIZE
d6d0aa01e77d 15 seconds ago /bin/sh -c #(nop) CMD ["gunicorn" "--log-le… 0B
0ab3d6deb2b7 15 seconds ago /bin/sh -c #(nop) ENV GUNICORN_BIND=0.0.0.0… 0B
0cfc9509778e 15 seconds ago /bin/sh -c #(nop) EXPOSE 8080 0B
cf14f70d51a5 15 seconds ago /bin/sh -c #(nop) ENV PORT=8080 0B
de8ae3be436f 16 seconds ago /bin/sh -c #(nop) COPY dir:72b9695da55ddcd17… 46.3kB
55336121980d 16 seconds ago /bin/sh -c pip install --no-cache-dir -r req… 21.1MB
eb61244b5956 22 seconds ago /bin/sh -c #(nop) COPY file:6afa89cc99483f80… 154B
b3b67de03a26 23 seconds ago /bin/sh -c #(nop) WORKDIR /app 0B
07ee12a5eb2a 5 days ago /bin/sh -c #(nop) CMD ["python3"] 0B
<missing> 5 days ago /bin/sh -c set -ex; savedAptMark="$(apt-ma… 7.42MB
<missing> 5 days ago /bin/sh -c #(nop) ENV PYTHON_GET_PIP_SHA256… 0B
<missing> 5 days ago /bin/sh -c #(nop) ENV PYTHON_GET_PIP_URL=ht… 0B
<missing> 5 days ago /bin/sh -c #(nop) ENV PYTHON_PIP_VERSION=19… 0B
<missing> 5 days ago /bin/sh -c cd /usr/local/bin && ln -s idle3… 32B
<missing> 5 days ago /bin/sh -c set -ex && savedAptMark="$(apt-… 94.9MB
<missing> 4 weeks ago /bin/sh -c #(nop) ENV PYTHON_VERSION=3.7.5 0B
<missing> 4 weeks ago /bin/sh -c #(nop) ENV GPG_KEY=0D96DF4D4110E… 0B
<missing> 4 weeks ago /bin/sh -c apt-get update && apt-get install… 7.03MB
<missing> 4 weeks ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B
<missing> 4 weeks ago /bin/sh -c #(nop) ENV PATH=/usr/local/bin:/… 0B
<missing> 4 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 4 weeks ago /bin/sh -c #(nop) ADD file:74b2987cacab5a6b0… 69.2MB

@JohnRofrano 129
Introduction to Docker

Useful Docker Commands

• Create a Docker le for your image


- vi Dockerfile
• Build an image with:
- docker build –t <your_image_name> .
• Run a container with:
- docker run -d --name <your_container_name> <your_image_name>
• Show the containers logs with:
- docker logs <your_container_name>
• Stop the container with:
- docker stop <your_container_name>
• Remove the container with:
- docker rm <your_container_name>
• Remove the image with:
- docker rmi <your_image_name>
@JohnRofrano 130
fi
Introduction to Docker

Useful Docker Flags

• Linking (--link <other>)


- You can link containers so that they don’t need to know each others ip addresses
• Volumes (-v <host>:<cont>)
- You can mount volumes so that data can remain outside of the container and keep the containers stateless
• Ports (–P or –p <host_port>:<cont_port>)
- You can map ports to expose them outside of the container <host>:<container>
• Hostname (-h <name>)
- Assigns a hostname to the container
• Daemon (-d)
- Run the container as a daemon process
• Fault Tolerance (--always-restart)
- Tells Docker to restart the container if the main process ever fails
• Environment Variables (-e <ENV_VAR>=xxx)
- Passes environment variables into a container at startup
@JohnRofrano 131
Introduction to Docker

Cleaning up Dangling Images

• Dangling images occur when a new images it build that supersedes it


• These images show <none> for their name and tag
• You can list them with: docker images -f dangling=true

$ docker images -f dangling=true


REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 3f7a53d3c3a3 5 seconds ago 63.3 MB

Dangling images that can be cleaned up

@JohnRofrano 132
Introduction to Docker

Remove All Dangling Images

• We can automatically remove all dangling images with the following command:

- docker image prune


$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y

Deleted: sha256:3f7a53d3c3a3a64ec79fea01747b97556c276bc851b65b8e24cfb1c2082d5cff
Deleted: sha256:d76a50fd288ec67ec7699bbb4f5b65b9f40b68790d1fb6c96ac39f60dddc146a
Deleted: sha256:56ee01767abea97505cef0646e4172cb18a36f06c4eff070ef09caa47be63564

@JohnRofrano 133
Introduction to Docker

Cleanup Docker Volumes

• Whenever you share a folder, Docker creates a volume


• You can list dangling volumes with:
- docker volume ls -f dangling=true
• You can remove all dangling volumes with:
- docker volume prune

@JohnRofrano 134
Introduction to Docker

Easy Way to Kill All Containers

• Here are two commands to quickly kill and remove all containers
(remember: "with great power comes great responsibility!)

docker kill $(docker ps -aq) &&


docker rm $(docker ps -aq)

@JohnRofrano 135
Introduction to Docker

Summary

• You just created your rst Docker containers


• You learned how to create our own Images
• You learned how to compose multiple
containers
• You can now check your Docker le into github
so that others can create the same containers
when working on your project.

@JohnRofrano 136
fi
fi

You might also like