Instructor: Mo Mansour
GDG PSUT
Docker is a platform for developing, shipping, and running applications in lightweight, portable containers.
Introduction
It enables developers to package applications with all their dependencies and run them consistently across different environments.
Introduction
well, because of this:
Introduction
Introduction
Docker is everywhere... except on your laptop i guess
(let's fix that)
A container is an isolated, lightweight environment that runs an application and its dependencies.
Introduction
Containers use the host operating system’s kernel but keep apps separate from each other.
Containers are faster than VMs.
Introduction
Containers share the host OS kernel (Linux), so no need for a full OS per container like VMs.
Containers are originally designed and have native support for Linux.
VMs have stronger isolation since it boots up a full OS per VM, and it emulates full hardware including the kernel, requiring more hardware resources to run.
No.
Docker images are like the blueprint for containers.
Introduction
They contain everything needed to run a container, including the OS, code, environment variables, and config files.
A Dockerfile is a file that defines instructions on how the Docker image should be built and how it should run.
Introduction
You can create a dockerfile by just creating a file called, Dockerfile!
An image is the blueprint while a container is an instance of that image.
Introduction
An image is a persistent and doesn't change (unless you modify the Dockerfile and rebuild the image again).
While the container's state can change.
You can have multiple containers running for the same image.
A Docker Image is like a recipe, while a Container is like the actual dish cooked from that recipe.
Introduction
Docker is available for Linux, macOS, and Windows, follow the guide for your platform here to install it.
Getting Started
if you haven't already installed it before this session
We'll use Docker CLI while learning Docker basics since it offers more flexibility in commands and it's faster.
Getting Started
but you can explore and use the graphical desktop version on your own later.
Let's run your first docker image! Type the following command in your terminal and you should see the output below.
Getting Started
docker run hello-world
$ docker run hello-world
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/
You've already seen your first Docker command which is this:
Docker CLI: The Basics
docker run <image_name>
This command runs a container of an existing image.
If the image does not exist on your system, Docker will download (pull) it from Docker Hub.
We'll learn what that is in the next section
Example:
Docker CLI: The Basics
docker run -p 8080:80 nginx
This runs the docker image of nginx web server, and maps port 80 (http) from inside the container to port 8080 on the host machine (your computer!).
Go to http://localhost:8080/
to see it up and running!
You can list running containers using this command:
Docker CLI: The Basics
docker ps
docker ps -a
shows all existing containers, active or not.
Helpful when you want to delete (or restart) old containers.
or
docker container ls
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
507d0839d8c1 nginx:latest "/docker-entrypoint.…" 8 minutes ago Up 3 seconds
PORTS NAMES
0.0.0.0:8080->80/tcp, [::]:8080->80/tcp dazzling_pike
Docker CLI: The Basics
docker stop <cont_id/name>
Find the container id or name from the previous command: docker ps -a
docker rm <cont_id/name>
To stop an active container
To remove a container
Tip: stop and remove unused containers regularly to free up system resources.
Docker CLI: The Basics
docker start <cont_id/name>
To bring a stopped container back to life
Docker CLI: The Basics
docker images
You can list images on your system (either built or downloaded) using
or
docker image ls
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
psutarchive-directus latest fde156a34729 4 days ago 657MB
postgres 17.2-alpine 2bf60600670f 2 weeks ago 278MB
Docker CLI: The Basics
docker rmi <image_id/name>
You can remove an image by simply using
or
docker image <image_id/name>
Tip: remove unneeded images regularly to free up storage.
You can't remove an image if it has a container (whether running or stopped), so you have to remove the container first.
Working with Docker Images
Docker Hub is a central repository service for docker images where devs can upload their images for others to use.
So far, the images you used to run containers such as hello-world
and nginx
were pulled from Docker Hub since you don't have them on your system.
You can explore it (and create an account if you need it) at hub.docker.com
It's like GitHub, but for Docker images, and you can find both official and community images.
Working with Docker Images
You can pull (i.e. download) images from Docker Hub by simply running this command
e.g. docker pull python
or docker pull python:3.10
docker pull <image_name>:<version/tag>
and optionally, you can define the image version (tags) after the image name. No tag means it'll pull the image tagged as `latest`.
You can pull (i.e. download) images from Docker Hub by simply running this command
e.g. docker pull python
or docker pull python:3.10
docker pull <image_name>:<version/tag>
and optionally, you can define the image version (tags) after the image name. No tag means it'll pull the image tagged as `latest`.
tags example on docker hub.
Remember: docker run <image>:<tag>
will automatically pull it from docker hub if it was not found on your system.
Working with Docker Images
tags example on docker hub.
Working with Docker Images
To build your own image, you must first understand Dockerfiles and write one yourself.
jk lol it's so simple
Working with Docker Images
Let's say you have a simple python script `app.py` which just prints "hello world" and you wanna run it in docker.
Let's start by making a file called `Dockerfile`, and then write the docker instructions to run this script.
# Dockerfile
# base image
FROM python:3.12
COPY app.py /app/
WORKDIR /app
# command to run the script (docker run)
CMD ["python", "app.py"]
Working with Docker Images
Let's say you have a simple python script `app.py` which just prints "hello world" and you wanna run it in docker.
Let's start by making a file called `Dockerfile`, and then write the docker instructions to run this script.
# Dockerfile
# base image
FROM python:3.12
COPY app.py /app/
WORKDIR /app
# command to run the script (docker run)
CMD ["python", "app.py"]
Let me break it down to you
Here you can define the base image; your starting point.
Depending on your needs, you can use linux distros like ubuntu
, debian
, or alpine
, databases such as postgres
and mysql
, and more.
Popular images usually have other variants defined as a tag.
Working with Docker Images
# Dockerfile
# base image
FROM python
COPY app.py /app/
WORKDIR /app
# command to run the script (docker run)
CMD ["python", "app.py"]
Let me break it down to you
Copies the app.py
file from your local machine to the container’s /app/
directory.
In this case, both the Dockerfile and app.py are in the same directory.
Working with Docker Images
# Dockerfile
# base image
FROM python
COPY app.py /app/
WORKDIR /app
# command to run the script (docker run)
CMD ["python", "app.py"]
Moves into the /app
directory inside the container.
To make sure that subsequent commands (like CMD
) run inside this directory.
Working with Docker Images
# Dockerfile
# base image
FROM python
COPY app.py /app/
WORKDIR /app
# command to run the script (docker run)
CMD ["python", "app.py"]
Specifies the default command to run when the container starts.
It can also be written as a normal command not a list,
e.g. CMD python app.py
if it's intended to run in the default shell /usr/bin/sh -c
Working with Docker Images
# copy local/remote files/dirs from src to the destination inside the image
ADD <src> ... <dest>
# for build-time variables (can be passed to docker build with --build-arg <varname>=<value>)
ARG name=value # value is optional
# ENV NAME_1=VALUE_1 NAME_2=VALUE_2 - to pass environment variables, they presist in the container's runtime
# can be set while running a container with `docker run -e NAME=VAL <image_name>`
ENV NODE_ENV=production
# EXPOSE $PORT - describes which ports your application is listening on, more of a documentation for image users
EXPOSE 8080
# RUN <some command> - to execute build commands
RUN apt-get update && apt-get install -y curl
# similar to CMD, but should be used when using the container as an executable to pass args
ENTRYPOINT ["executable", "param1", "param2"]
There are so many Dockerfile statements, the full list can be found here. Here are some of the most used ones.
Working with Docker Images
Now that you have the Dockerfile ready, you can go ahead with building the image
$ docker build -t my-image .
the `-t <some-name>
` is recommended to give your image a name (tag).
the `.` tells docker to use the Dockerfile in the current directory.
Working with Docker Images
simply run it with docker run
$ docker run my-image
You can set `--name <some-name>
` to give your container a name.
Working with Docker Images
simply run it with docker run
$ docker run my-image
Notice that our simple hello world python script exits immediately.
Try running docker ps
and docker ps -a
to see it as a stopped container.
Let's modify our app.py
to keep it running until we stop it.
You can set `--name <some-name>
` to give your container a name.
Working with Docker Images
$ docker run my-image
the `-t <some-name>
` is recommended to give your image a name (tag).
Notice that our simple hello world python script exits immediately.
Try running docker ps
and docker ps -a
to see it as a stopped container.
Let's modify our app.py
to keep it running until we stop it.
Something like
import time
while True:
print("hello from docker")
time.sleep(1)
Now rebuild the image and run it again but this time with a -d
flag.
$ docker run -d my-image
Working with Docker Images
Let's modify our app.py
to keep it running until we stop it.
Something like
import time
while True:
print("hello from docker")
time.sleep(1)
Now rebuild the image and run it again but this time with a -d
flag.
$ docker run -d my-image
You can check running containers with docker ps
to see your container there, try stopping it.
Working with Docker Images
Docker caches layers, meaning small changes won’t rebuild everything from scratch (saving time ⏳).
FROM ubuntu:latest
RUN apt-get update && apt-get install -y build-essentials
COPY main.c Makefile /src/
WORKDIR /src/
RUN make build
This example (from docker's docs) is a dockerfile for a C program.
Working with Docker Images
Docker caches layers, meaning small changes won’t rebuild everything from scratch (saving time ⏳).
FROM ubuntu:latest
RUN apt-get update && apt-get install -y build-essentials
COPY main.c Makefile /src/
WORKDIR /src/
RUN make build
This example (from docker's docs) is a dockerfile for a C program.
Each instruction in this Dockerfile translates to a layer in your final image. Think of image layers as a stack, with each layer adding more content on top of the layers that came before it:
Working with Docker Images
FROM ubuntu:latest
RUN apt-get update && apt-get install -y build-essentials
COPY main.c Makefile /src/
WORKDIR /src/
RUN make build
Each instruction in this Dockerfile translates to a layer in your final image. Think of image layers as a stack, with each layer adding more content on top of the layers that came before it:
Whenever a layer changes, it needs to be rebuilt and all the layers that come after it are also rebuilt. E.g. if you made a change on main.c
then the COPY
layer will run again when rebuilding the image.
Best Practices
A multi-stage dockerfile allows you to optimize your images by turning the build process into several steps.
Each stage begins with a new base, i.e a FROM <image>
statement.
You can select what you want to copy from each stage to the next one, so that in the final stage you have the minimal files/resources needed to run the docker container.
One of the most common multi-stage dockerfiles is having 2 stages, one for building the image (i.e. building the binary/app) and one for running it.
Demo: A Simple HTTP Server
You wanna try this simple HTTP server, but you don't have GoLang installed, Docker saves the day!
First you need to download the code from GitHub.
Demo: A Simple HTTP Server
Have a look at the Dockerfile and then build it.
You can set the port for your http server either with an environment variable PORT
or with the command line flag `-port
`.
Try running the container with both options.
Docker Compose - Intro
Docker compose lets you define and manage multi-container apps easily.
Why?
docker compose up
`.compose.yml
Docker Compose - Intro
Docker compose files use a YAML configuration file, in this file you can define everything your containers need to run (and to connect to each other).
Compose commands:
docker compose up [-d]
docker compose down
docker compose logs [-f]
Docker Compose - Intro
[live]