summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormo khan <mo.khan@gmail.com>2020-10-23 16:56:34 -0600
committermo khan <mo.khan@gmail.com>2020-10-23 16:56:34 -0600
commit214586544d4e51a26bed4fa14ea74393e885099b (patch)
treec0f4b9cf521b40e51f53f55b06452b06c82973a2
parent143c894c905ec365c7d6118eb66aa2ab7b948ea9 (diff)
Rewrite presentation to tell a story
-rw-r--r--Makefile2
-rw-r--r--README.md641
-rw-r--r--examples/001/Dockerfile1
-rw-r--r--examples/001/docker-exec.sh2
-rw-r--r--examples/001/hello.rb2
5 files changed, 474 insertions, 174 deletions
diff --git a/Makefile b/Makefile
index e780f3e..17df9e9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,3 @@
run:
pipenv install
- pipenv run lookatme --theme=dark --style=vim --live README.md
+ pipenv run lookatme --theme=light --live README.md
diff --git a/README.md b/README.md
index 05b298d..651d1f2 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,138 @@
---
title: Developing with Docker
author: gitlab.com/xlgmokha/developing-with-docker
-date: 2020-06-10
+date: 2020-10-24
---
-# Developing with Docker - Mo Khan | Software Engineer | Composition Analysis | GitLab
+# Developing with Docker
+Mo Khan | Software Developer | GitLab
```text
- How
- to
- Docker
- better?
- ## .
- ## ## ## ==
- ## ## ## ## ## ===
- /"""""""""""""""""\___/ ===
- { / ===-
- \______ O __/
- \ \ __/
- \____\_______/
+ Building
+ smaller
+ Docker
+ images?
+ ## .
+ ## ## ## ==
+ ## ## ## ## ## ===
+ /"""""""""""""""""\___/ ===
+ { / ===-
+ \______ O __/
+ \ \ __/
+ \____\_______/
```
+# whoami
+
+Software developer from Calgary, AB, Canada.
+
+* GitLab
+* Cisco
+* ThoughtWorks
+
+# Why?
+
+License scanning at GitLab.
+
+1. Scan target project for lock files (Gemfile.lock, Pipfile.lock etc)
+2. Install project tools (Ruby 2.7.2, Python 3.8.4)
+3. Install project dependencies (Rails, Django)
+
+```bash
+ モ ls ~/development/gitlab | grep lock
+ Gemfile.lock
+ Pipfile.lock
+ yarn.lock
+```
+
+Ship a Docker image:
+
+* Multiple versions of Ruby, Python etc
+* Package managers for different languages
+* Omnibus package of scanner code
+* System packages/dependencies (libpq-dev, libsqlite3-dev etc)
+
+Multiple Languages/Versions:
+
+* Dotnet Core
+* Golang
+* Java
+* Mono
+* NodeJS
+* PHP
+* Python
+* Ruby
+* Rust
+
+Multiple Package Managers:
+
+* Bundler
+* pip
+* pipenv
+* gradle
+* maven
+
+Large Docker images
+
+* slow downloads
+* more disk space is required
+* more bandwidth is consumed
+
+# Overview
+
+```text
+ -------------
+ | git |
+ ------------- ----------------
+ | main | --> | gitlab-runner |
+ | feature-a | ----------------
+ | feature-b | |
+ ------------- | (launch container)
+ V
+ ---------------
+ | | <----- 10GB ------
+ | Docker Host | --------- |
+ | | | |
+ --------------- | |
+ | download |
+ V | |
+ -------------- V |
+ | License | ------------ |
+ | scanner | | registry | -|
+ -------------- ------------
+```
+
+License scanner
+
+1. Search for lockfiles
+2. Install desired version of language tools
+3. Install packages via package manager
+4. Scan for licenses
+5. Export JSON report
+
+# Zoom in
+
+How did you shrink the image from 10GB down to 1GB?
+
+```text
+ ---------------
+ | | <----- 10GB ------
+ | Docker Host | --------- |
+ | | | |
+ --------------- | |
+ | download |
+ V | |
+ -------------- V |
+ | License | ------------ |
+ | scanner | | registry | -|
+ -------------- ------------
+```
+
+Also added
+
+* Support for more languages and versions.
+* Support for limited connectivity environments.
+
# Agenda
* Definitions
@@ -30,19 +142,19 @@ date: 2020-06-10
* Optimize
```text
-< What are we going to talk about? >
- ----------------------------------
- \
- \
- \
- ## .
- ## ## ## ==
- ## ## ## ## ===
- /""""""""""""""""___/ ===
- ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
- \______ o __/
- \ \ __/
- \____\______/
+ < What are we going to talk about? >
+ ----------------------------------
+ \
+ \
+ \
+ ## .
+ ## ## ## ==
+ ## ## ## ## ===
+ /""""""""""""""""___/ ===
+ ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
+ \______ o __/
+ \ \ __/
+ \____\______/
```
# Definitions
@@ -58,7 +170,14 @@ A class defines the behaviour and data associated with the class.
```ruby
class Person
- def fist_bump(other_person)
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def hug(other)
+ puts "#{name} 🤗 #{other.name}"
end
end
```
@@ -69,8 +188,8 @@ You can't do much with a class until you create
an instance of one.
```ruby
-mo = Person.new
-you = Person.new
+ mo = Person.new("mo")
+ me = Person.new("me")
```
# Definitions - Objects
@@ -80,7 +199,7 @@ methods on the object. An object can interact
with other objects.
```ruby
-mo.first_bump(you)
+ mo.hugs(me)
```
# Definitions - Container
@@ -93,28 +212,6 @@ Similar to how an object is an instance of a class.
| Class | Image |
| Object | Container |
-# Identifiers
-
-Classes can be identified by their name.
-Images can be identified by their image Id or `name:tag`
-
-Objects can be identified by their `object_id` in Ruby.
-Containers can be identified by their container Id or a name.
-
-| Ruby | Docker |
-| -- | -- |
-| Person | Image ID |
-| mo.object_id | Container ID |
-
-# Image identifier
-
-`[registry]name:tag`
-
-If the registry is omitted, then docker.io is assumed.
-
-* registry.gitlab.com/gitlab-org/security-products/license-management:latest
-* alpine:latest
-
# Definitions - Registry
Registry: stores images and makes them available to others
@@ -160,46 +257,16 @@ curl -s -i https://registry-1.docker.io/v2/alpine/tags/list
https://docs.docker.com/get-started/overview/#docker-architecture
-# /var/run/docker.sock
-
-```bash
-$ curl --unix-socket /var/run/docker.sock http://localhost/images/json
-```
-
-```terminal32
-curl -i --unix-socket /var/run/docker.sock http://localhost/images/json
-```
-
-# $ docker version
-
-The docker CLI is an HTTP client that can connect to Unix or TCP sockets.
-
-```terminal32
-docker version
-```
-
-# $ docker image ls
-
-```terminal32
-docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
-```
-
-# $ docker ps
+# $ docker run -it alpine:latest cat /etc/os-release
-```terminal32
-docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Status}}"
+```terminal8
+docker run -it alpine:latest cat /etc/os-release
```
-# $ docker run -it alpine:latest cat /etc/os-release
-
1. check if "alpine:latest" is on docker host
1. download "alpine:latest" from registry to docker host
1. start a container using the "alpine:latest" image
-```terminal32
-docker run -it alpine:latest cat /etc/os-release
-```
-
# Dockerfile
```file
@@ -222,14 +289,7 @@ lang: docker
# COPY "hello.rb"
-Copy "hello.rb" from the host to
-"/usr/local/bin/hello" within the Docker image.
-
-```file
-path: examples/001/Dockerfile
-relative: true
-lang: docker
-```
+Copy "hello.rb" from the host to "/usr/local/bin/hello" in the Docker image.
```bash
$ cat examples/001/hello.rb
@@ -270,7 +330,7 @@ lines:
# docker build -t developing-with-docker:latest examples/001/
```terminal32
-time docker build -t developing-with-docker:latest examples/001/
+docker build --network=host -t developing-with-docker:latest examples/001/
```
# docker run developing-with-docker:latest
@@ -279,24 +339,6 @@ time docker build -t developing-with-docker:latest examples/001/
docker run developing-with-docker:latest
```
-# docker run -it developing-with-docker:latest /bin/sh
-
-```terminal32
-docker run -it developing-with-docker:latest /bin/sh
-```
-
-# docker ps
-
-```terminal32
-docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Status}}"
-```
-
-# docker exec -it <imageid> /bin/sh
-
-```terminal32
-bash -i examples/001/docker-exec.sh
-```
-
# dive
Useful for identifying bloat.
@@ -305,103 +347,360 @@ https://github.com/wagoodman/dive
* Displays each layer
* Allows investigating files that are added/removed/changed in each layer
-```terminal32
-bash examples/001/dive-exec.sh developing-with-docker
-```
+# dive original
-# docker pull registry.gitlab.com/gitlab-org/security-products/license-management:latest
+```bash
+│ Layers ├──────────────────────────────────────────────────────────────────────────── ┃ ● Current Layer Contents ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+Cmp Size Command Permission UID:GID Size Filetree
+ 5.6 MB FROM 5a96ef02e9cab83 drwxr-xr-x 0:0 841 kB ├─⊕ bin
+ 40 B #(nop) COPY file:253d38e67af26b201caf4e271248576ba6a7da0431f5ddee20c5c6df5 drwxr-xr-x 0:0 0 B ├── dev
+ 16 MB apk add ruby drwxr-xr-x 0:0 383 kB ├─⊕ etc
+ 40 B chmod +x /usr/local/bin/hello drwxr-xr-x 0:0 0 B ├── home
+ drwxr-xr-x 0:0 3.9 MB ├─⊕ lib
+│ Layer Details ├───────────────────────────────────────────────────────────────────── drwxr-xr-x 0:0 0 B ├─⊕ media
+ drwxr-xr-x 0:0 0 B ├── mnt
+Tags: (unavailable) drwxr-xr-x 0:0 0 B ├── opt
+Id: e19b1e8ac9df6c9165f82c5e278f4d8b4839c8e6727001a12477e3947ffd83ea dr-xr-xr-x 0:0 0 B ├── proc
+Digest: sha256:aebe0431f34491da1f2785934e4190cfb9fbba01fc1aeff69f13c139a6ccac65 drwx------ 0:0 0 B ├── root
+Command: drwxr-xr-x 0:0 0 B ├── run
+apk add ruby drwxr-xr-x 0:0 226 kB ├─⊕ sbin
+ drwxr-xr-x 0:0 0 B ├── srv
+│ Image Details ├───────────────────────────────────────────────────────────────────── drwxr-xr-x 0:0 0 B ├── sys
+ drwxrwxrwx 0:0 0 B ├── tmp
+ drwxr-xr-x 0:0 14 MB ├─⊕ usr
+Total Image size: 21 MB drwxr-xr-x 0:0 1.8 MB └─⊕ var
+Potential wasted space: 532 kB
+Image efficiency score: 98 %
+
+Count Total Space Path
+ 2 428 kB /etc/ssl/certs/ca-certificates.crt
+ 2 79 kB /lib/apk/db/installed
+ 2 25 kB /lib/apk/db/scripts.tar
+ 2 288 B /lib/apk/db/triggers
+ 2 123 B /etc/apk/world
+ 2 80 B /usr/local/bin/hello
+ 2 0 B /lib/apk/db/lock
+ 2 0 B /var/cache/misc
+```
+
+# dive - layers
-* More layers == more parallel downloads
-* Smaller layers == faster downloads per layer
+```bash
+│ Layers ├─────────────────────────────────────────────────────────
+Cmp Size Command
+ 5.6 MB FROM 5a96ef02e9cab83
+ 40 B #(nop) COPY file:253d38e67af26b201caf4e271248576ba6a7da
+ 16 MB apk add ruby
+ 40 B chmod +x /usr/local/bin/hello
-```terminal32
-bash -i examples/001/docker-large-download.sh
-```
+│ Layer Details ├──────────────────────────────────────────────────
-# docker build -t big-image:latest examples/002/
+Tags: (unavailable)
+Id: e19b1e8ac9df6c9165f82c5e278f4d8b4839c8e6727001a12477e3947ff
+Digest: sha256:aebe0431f34491da1f2785934e4190cfb9fbba01fc1aeff69f13
+Command:
+apk add ruby
-```file
-path: examples/002/Dockerfile
-relative: true
-lang: docker
-```
+│ Image Details ├──────────────────────────────────────────────────
-```terminal32
-time docker build -t big-image:latest examples/002/
-```
-# docker image ls
+Total Image size: 21 MB
+Potential wasted space: 532 kB
+Image efficiency score: 98 %
-```terminal32
-docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
+Count Total Space Path
+ 2 428 kB /etc/ssl/certs/ca-certificates.crt
+ 2 79 kB /lib/apk/db/installed
+ 2 25 kB /lib/apk/db/scripts.tar
+ 2 288 B /lib/apk/db/triggers
+ 2 123 B /etc/apk/world
+ 2 80 B /usr/local/bin/hello
+ 2 0 B /lib/apk/db/lock
+ 2 0 B /var/cache/misc
```
-# dive big-image:latest
+# dive - layer details
-```terminal32
-bash examples/001/dive-exec.sh big-image
+```bash
+┃ ● Current Layer Contents ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+Permission UID:GID Size Filetree
+drwxr-xr-x 0:0 841 kB ├─⊕ bin
+drwxr-xr-x 0:0 0 B ├── dev
+drwxr-xr-x 0:0 383 kB ├─⊕ etc
+drwxr-xr-x 0:0 0 B ├── home
+drwxr-xr-x 0:0 3.9 MB ├─⊕ lib
+drwxr-xr-x 0:0 0 B ├─⊕ media
+drwxr-xr-x 0:0 0 B ├── mnt
+drwxr-xr-x 0:0 0 B ├── opt
+dr-xr-xr-x 0:0 0 B ├── proc
+drwx------ 0:0 0 B ├── root
+drwxr-xr-x 0:0 0 B ├── run
+drwxr-xr-x 0:0 226 kB ├─⊕ sbin
+drwxr-xr-x 0:0 0 B ├── srv
+drwxr-xr-x 0:0 0 B ├── sys
+drwxrwxrwx 0:0 0 B ├── tmp
+drwxr-xr-x 0:0 14 MB ├─⊕ usr
+drwxr-xr-x 0:0 1.8 MB └─⊕ var
+```
+
+# docker pull - back then
+
+```bash
+2.8.0: Pulling from gitlab-org/security-products/license-management
+0a01a72a686c: Pull complete
+cc899a5544da: Pull complete
+19197c550755: Pull complete
+716d454e56b6: Pull complete
+4a00dd5b28fc: Pull complete
+e039d25729bf: Pull complete
+930b12354a74: Pull complete
+5c0b45be82b1: Pull complete
+2174b0b17785: Pull complete
+79e1fdae2dfc: Extracting [================> ] 322MB/396.1MB
+2c46852653ff: Download complete
+40e535af8764: Download complete
+0c1954047133: Download complete
+080be37ae17e: Download complete
+4179fc4ef96a: Download complete
+87d7bc66884f: Download complete
+581b5a43e64d: Download complete
+a754f2766934: Download complete
+c1e41c3670fe: Download complete
+e782eb3070d9: Download complete
+50d1fb4b55b2: Download complete
+276696690bcf: Download complete
+5eec42d5363b: Download complete
+2296aa2193e9: Download complete
+5fe4c102c0bc: Download complete
+97390612da81: Downloading [=====> ] 81.05MB/174MB
+311b1e270e29: Downloading [===========> ] 42.12MB/189.4MB
+53dfbd975f60: Downloading [=> ] 25.36MB/843.4MB
+3dd2acdebe0f: Waiting
+d548f098494f: Waiting
+da1cc42017ff: Waiting
+cfc3cd025ca9: Waiting
+69ea647e6c07: Waiting
+1e27d5f85aa2: Waiting
+94cf5e06627d: Waiting
+30e1f788589d: Waiting
+d9238ec317d1: Waiting
+e17797fa5e82: Waiting
+9003b36c1e4e: Waiting
+```
+
+# Start with a minimal base image
+
+```Dockerfile
+FROM licensefinder/license_finder:5.6.2
```
-# docker build -t small-image:latest examples/003/
+```bash
+REPOSITORY TAG SIZE
+debian stable-slim 69.2MB
+licensefinder/license_finder 5.6.2 3.63GB
+```
+
+```Dockerfile
+FROM debian:stable-slim
+```
+
+# Be picky
+
+*Warning: The content below may be considered offensive.*
+
+```Dockerfile
+RUN apt-get update && apt-get install -y \
+ build-essential \
+ curl \
+ git-core \
+ sudo \
+ unzip \
+ wget
+RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
+ apt-get -y install nodejs
+RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - && \
+ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list && \
+ apt-get update && \
+ apt-get install yarn
+RUN apt-get install -y python rebar
+RUN apt-get install -y python-pip && \
+ pip install --upgrade pip==$PIP_INSTALL_VERSION
+RUN apt-get install -y locales
+RUN wget https://packages.erlang-solutions.com/erlang-solutions_${MIX_VERSION}_all.deb && \
+ sudo dpkg -i erlang-solutions_${MIX_VERSION}_all.deb && \
+ sudo rm -f erlang-solutions_${MIX_VERSION}_all.deb && \
+ sudo apt-get update && \
+ sudo apt-get install -y esl-erlang && \
+ sudo apt-get install -y elixir
+RUN apt-get install -y python-dev && \
+ pip install --ignore-installed six --ignore-installed colorama --ignore-installed requests --ignore-installed chardet --ignore-installed urllib3 --upgrade setuptools && \
+ pip install conan
+RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF &&\
+ echo "deb https://download.mono-project.com/repo/ubuntu stable-xenial main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list &&\
+ apt-get update &&\
+ apt-get install -y mono-complete &&\
+ curl -o /usr/local/bin/nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe &&\
+ echo "alias nuget=\"mono /usr/local/bin/nuget.exe\"" >> ~/.bash_aliases
+RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb &&\
+ sudo dpkg -i packages-microsoft-prod.deb &&\
+ sudo apt-get update &&\
+ sudo apt-get install -y dotnet-runtime-2.1
+```
+
+# Group 'apt-get install' together
+
+```Dockerfile
+COPY config/install.sh /opt/install.sh
+RUN bash /opt/install.sh
+```
-* Collapse layers
-* Cleanup unnecessary artifacts
-* Deflate files within layers
-* Inflate files when container is launched
+```bash
+#!/bin/bash
+apt-get install -y --no-install-recommends \
+ apt-transport-https \
+ autoconf \
+ automake \
+ bsdmainutils \
+ bzip2 \
+ ca-certificates \
+ cmake \
+ curl \
+ gnupg2 \
+ make \
+ pkg-config \
+ re2c \
+ rebar \
+ zstd
+```
+
+*note: avoid installing build tools if you can*
+
+# Deflate
+
+Compress directories that are large during build time.
-```file
-path: examples/003/Dockerfile
-relative: true
-lang: docker
-```
+```bash
+#!/bin/bash
-```file
-path: examples/003/run.sh
-relative: true
-lang: sh
-```
+function deflate() {
+ local file=$1
+ local dir=$2
+ local zstd_command="/usr/bin/zstd -19 -T0"
+ tar --use-compress-program "$zstd_command" -cf "$file" "$dir"
+}
-```terminal32
-time docker build -t small-image:latest examples/003/
+cd /opt
+deflate /opt/asdf.tar.zst asdf
+
+cd /usr/lib
+deflate /usr/lib/gcc.tar.zst gcc
+deflate /usr/lib/mono.tar.zst mono
+deflate /usr/lib/rustlib.tar.zst rustlib
+
+cd /usr/share
+deflate /usr/share/dotnet.tar.zst dotnet
```
-# docker image ls
+# Inflate
-```terminal32
-docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
+Decompress directories when the container is launched
+by hooking into the ENTRYPOINT.
+
+```Dockerfile
+ENTRYPOINT ["/run.sh"]
```
-# dive small-image:latest
+```bash
+#!/bin/bash
+
+function inflate() {
+ local file=$1
+ local to_dir=$2
+ if [ -f "$file" ]; then
+ tar --use-compress-program zstd -xf "$file" -C "$to_dir"
+ rm "$file"
+ fi
+}
-```terminal32
-bash examples/001/dive-exec.sh small-image
+inflate /opt/asdf.tar.zst /opt
+inflate /usr/lib/gcc.tar.zst /usr/lib
+inflate /usr/lib/mono.tar.zst /usr/lib
+inflate /usr/lib/rustlib.tar.zst /usr/lib
+inflate /usr/share/dotnet.tar.zst /usr/share
+
+sh "$@"
```
-# docker run -it small-image:latest
+# Build specialized packages
-```terminal32
-docker run -it small-image:latest
+```ruby
+build do
+ env = with_standard_compiler_flags(with_embedded_path)
+ configure_command = [
+ "--disable-debug-env",
+ "--disable-dtrace",
+ "--disable-install-capi",
+ "--disable-install-doc",
+ "--disable-install-rdoc",
+ "--disable-jit-support",
+ "--enable-shared",
+ "--prefix=#{install_dir}",
+ "--with-out-ext=coverage,dbm,readline,rdoc,win32,win32ole,sdbm",
+ "--without-gdbm",
+ "--without-gmp",
+ "--without-jemalloc",
+ "--without-tk",
+ "--without-valgrind"
+ ]
+ configure(*configure_command, env: env)
+ make "-j #{workers}", env: env
+ make "-j #{workers} install", env: env
+end
```
-# docker image ls
+```bash
+# ls -lh /opt/toolcache/ruby-* | awk '{ print $5 " " $9 }'
+5.3M /opt/toolcache/ruby-2.4.10_2.4.10-1_amd64.deb
+5.3M /opt/toolcache/ruby-2.4.5_2.4.5-1_amd64.deb
+5.3M /opt/toolcache/ruby-2.4.9_2.4.9-1_amd64.deb
+5.4M /opt/toolcache/ruby-2.5.8_2.5.8-1_amd64.deb
+5.6M /opt/toolcache/ruby-2.6.0_2.6.0-1_amd64.deb
+5.6M /opt/toolcache/ruby-2.6.1_2.6.1-1_amd64.deb
+5.6M /opt/toolcache/ruby-2.6.2_2.6.2-1_amd64.deb
+5.6M /opt/toolcache/ruby-2.6.3_2.6.3-1_amd64.deb
+5.6M /opt/toolcache/ruby-2.6.4_2.6.4-1_amd64.deb
+5.6M /opt/toolcache/ruby-2.6.5_2.6.5-1_amd64.deb
+5.6M /opt/toolcache/ruby-2.6.6_2.6.6-1_amd64.deb
+5.7M /opt/toolcache/ruby-2.7.0_2.7.0-1_amd64.deb
+5.7M /opt/toolcache/ruby-2.7.1_2.7.1-1_amd64.deb
+5.7M /opt/toolcache/ruby-2.7.2_2.7.2-1_amd64.deb
+```
+
+# Results
-```terminal32
-docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
+```bash
+REPOSITORY TAG SIZE
+analyzers/license-finder 3.28.1 1.4GB
+analyzers/license-finder 2.8.0 9.83GB
+analyzers/license-finder 1.5.0 4.06GB
```
# Summary
* Keep each layer small
* More layers provides opportunity for more parallel downloads
+* Download will block on the largest layer.
+* Too many layers can cause too many parallel downloads
+* Try to collapse layers by grouping logical things together
+* Cleanup unnecessary artifacts in each layer
+* Deflate files when building layers
+* Inflate files when container is launched
-# Fin
-
-Thank you for your time
+Thank you
[gitlab.com/xlgmokha/developing-with-docker](https://gitlab.com/xlgmokha/developing-with-docker)
-
-## Feedback
+# Feedback
* people will know what Docker is
* watch the screen from different sizes
diff --git a/examples/001/Dockerfile b/examples/001/Dockerfile
index f5f827d..3657293 100644
--- a/examples/001/Dockerfile
+++ b/examples/001/Dockerfile
@@ -1,4 +1,5 @@
FROM alpine:latest
COPY hello.rb /usr/local/bin/hello
+RUN apk add ruby
RUN chmod +x /usr/local/bin/hello
CMD ["hello"]
diff --git a/examples/001/docker-exec.sh b/examples/001/docker-exec.sh
index 39478b2..25c1085 100644
--- a/examples/001/docker-exec.sh
+++ b/examples/001/docker-exec.sh
@@ -3,4 +3,4 @@
set -e
image_id="$(docker ps | grep developing | awk '{ print $1 }' | tail -n1)"
-docker exec -it "$image_id" /bin/sh
+docker exec -it --network=host "$image_id" /bin/sh
diff --git a/examples/001/hello.rb b/examples/001/hello.rb
index 0a6e058..e772410 100644
--- a/examples/001/hello.rb
+++ b/examples/001/hello.rb
@@ -1,3 +1,3 @@
#!/usr/bin/env ruby
-puts "Hello World"
+puts "Hello, World!"