Docker 101:
Build, Run, Deploy

Instructor: Mo Mansour

GDG PSUT

Outline

  • Introduction
    • What is Docker and Why
    • What is a Container and How it Works
    • Docker Containers vs. VMs vs Traditional Apps
    • Docker Images and Dockerfiles
    • Images vs. Containers
  • Getting Started
    • Installing Docker
    • Hello, world!
  • Docker CLI: Basic Operations
  • Working with Docker Images
    • Pulling Images: Docker Hub
    • Writing Dockerfiles
    • Building Images
    • Expose Ports to Local Network

Outline

  • Introduction
    • What is Docker and Why
    • What is a Container and How it Works
    • Docker Containers vs. VMs vs Traditional Apps
    • Docker Images and Dockerfiles
    • Images vs. Containers
  • Getting Started
    • Installing Docker
    • Hello, world!
  • Docker CLI: Basic Operations
  • Working with Docker Images
    • Pulling Images: Docker Hub
    • Writing Dockerfiles
    • Building Images
    • Expose Ports to Local Network
  • Docker Compose: A Brief Intro
  • Demo: A Simple HTTP Servers
  • Best Practices

Outline

  • Introduction
    • What is Docker and Why
    • What is a Container and How it Works
    • Docker Containers vs. VMs vs Traditional Apps
    • Docker Images and Dockerfiles
    • Images vs. Containers
  • Getting Started
    • Installing Docker
    • Hello, world!
  • Docker CLI: Basic Operations
  • Working with Docker Images
    • Pulling Images: Docker Hub
    • Writing Dockerfiles
    • Building Images
    • Expose Ports to Local Network
  • Docker Compose: A Brief Intro
  • Demo: A Simple HTTP Servers
  • Best Practices

Follow along!

Docker.. 🐋what's that?

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.

Umm cool.. But why?

Introduction

well, because of this:

Umm cool.. But why?

Introduction

  • "Works on my machine" problem solved:
    Dev environment will be exactly the same as prod environment, and exactly the same as everyone else's dev environment.
     
  • Faster and more efficient than traditional virtual machines.
     
  • Scales applications easily.
     
  • Simplifies dependency management.

Docker in the Wild

Introduction

Docker is everywhere... except on your laptop i guess

(let's fix that)

Containers

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.

Like.. Virtual Machines?

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

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.

Dockerfiles

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!

Images vs. Containers

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.

Images vs. Containers

Introduction

Installing Docker

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

Installing Docker

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.

Hello, world!

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/

Docker CLI:
Running Containers

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

Docker CLI:
Running Containers

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!

List Running Containers

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

Stopping & Removing Containers

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.

Restarting Containers

Docker CLI: The Basics

docker start <cont_id/name>

To bring a stopped container back to life

Listing Images

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

Removing Images

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.

Docker Hub

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.

Pulling 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`.

Pulling 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`.

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.

Make Your Own! - Dockerfiles

Working with Docker Images

To build your own image, you must first understand Dockerfiles and write one yourself.

jk lol it's so simple

Make Your Own! - Dockerfiles

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"]

Make Your Own! - Dockerfiles

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"]

More Dockerfiles Instructions

There are so many Dockerfile statements, the full list can be found here. Here are some of the most used ones.

Build Your Dockerfile

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.

Run the Container

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.

Run the Container

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.

Build Cache

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.

Build Cache

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.

Multi-Stage Dockerfiles

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: HTTP Server

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: HTTP Server

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.

Multi-Container Apps:
Docker Compose

Docker Compose - Intro

Docker compose lets you define and manage multi-container apps easily.

Why?

  • Define multiple containers together in a single YAML file.
  • Simplify running complex applications.
  • Run the whole app suite with a single command `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]

Examples and Demo

Docker Compose - Intro

[live]

Thank You!

GDG Docker Workshop

By Mo Mansour

GDG Docker Workshop

  • 52