Docker. For devs.

run
compose

build

RUN

why?

  • yet another package manager
  • reproducible environment
  • isolated and disposable units

docker pull

docker create

docker start

docker run

docker ps

docker exec

docker stop

docker rm

 

docker run [-a|--attach[=[]]] [--add-host[=[]]] [--blkio-weight[=[BLKIO-WEIGHT]]] [--blkio-weight-device[=[]]] [--cpu-shares[=0]] [--cap-add[=[]]] [--cap-drop[=[]]]
       [--cgroup-parent[=CGROUP-PATH]] [--cidfile[=CIDFILE]] [--cpu-count[=0]] [--cpu-percent[=0]] [--cpu-period[=0]] [--cpu-quota[=0]] [--cpu-rt-period[=0]] [--cpu-rt-runtime[=0]] [--cpus[=0.0]]
       [--cpuset-cpus[=CPUSET-CPUS]] [--cpuset-mems[=CPUSET-MEMS]] [-d|--detach] [--detach-keys[=[]]] [--device[=[]]] [--device-cgroup-rule[=[]]] [--device-read-bps[=[]]] [--device-read-iops[=[]]]
       [--device-write-bps[=[]]] [--device-write-iops[=[]]] [--dns[=[]]] [--dns-option[=[]]] [--dns-search[=[]]] [-e|--env[=[]]] [--entrypoint[=ENTRYPOINT]] [--env-file[=[]]] [--expose[=[]]]
       [--group-add[=[]]] [-h|--hostname[=HOSTNAME]] [--help] [--init] [-i|--interactive] [--ip[=IPv4-ADDRESS]] [--ip6[=IPv6-ADDRESS]] [--ipc[=IPC]] [--isolation[=default]]
       [--kernel-memory[=KERNEL-MEMORY]] [-l|--label[=[]]] [--label-file[=[]]] [--link[=[]]] [--link-local-ip[=[]]] [--log-driver[=[]]] [--log-opt[=[]]] [-m|--memory[=MEMORY]]
       [--mac-address[=MAC-ADDRESS]] [--memory-reservation[=MEMORY-RESERVATION]] [--memory-swap[=LIMIT]] [--memory-swappiness[=MEMORY-SWAPPINESS]] [--mount[=[MOUNT]]] [--name[=NAME]]
       [--network-alias[=[]]] [--network[="bridge"]] [--oom-kill-disable] [--oom-score-adj[=0]] [-P|--publish-all] [-p|--publish[=[]]] [--pid[=[PID]]] [--userns[=[]]] [--pids-limit[=PIDS_LIMIT]]
       [--privileged] [--read-only] [--restart[=RESTART]] [--rm] [--security-opt[=[]]] [--storage-opt[=[]]] [--stop-signal[=SIGNAL]] [--stop-timeout[=TIMEOUT]] [--shm-size[=[]]] [--sig-proxy[=true]]
       [--sysctl[=[]]] [-t|--tty] [--tmpfs[=[CONTAINER-DIR[:OPTIONS]]] [-u|--user[=USER]] [--ulimit[=[]]] [--uts[=[]]] [-v|--volume[=[[HOST-DIR:]CONTAINER-DIR[:OPTIONS]]]] [--volume-driver[=DRIVER]]
       [--volumes-from[=[]]] [-w|--workdir[=WORKDIR]] IMAGE [COMMAND] [ARG...]

-it

--interactive --tty

-d

--detach

> docker run --detach \
  --name pgres \
  -p 5432:5432 \
  -v $PWD/pgdata:/var/lib/postgresql/data \
  postgres:10-alpine

--name

if needed later

--rm

dispose immediately

> docker run -d \
  --name pgres \
  -p 5432:5432 \
  -v $PWD/pgdata:/var/lib/postgresql/data \
  postgres:10-alpine

-v

--volume

-p

--publish, not --port ;)

> docker run -d \
  --name pgres \
  --publish 5432:5432 \
  --volume $PWD/pgdata:/var/lib/postgresql/data \
  postgres:10-alpine

--link

connect containers

--env

environment variables

> docker run -d \
  --name pgres \
  -p 5432:5432 \
  -v $PWD/pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD_FILE=/run/secrets/postgres-passwd \
  postgres:10-alpine


> docker run -it --rm \
  --link pgres:db \
  postgres psql -h db -U postgres

image

registry/owner/name:tag

command

arguments

entry point

> docker run -d \
  --name pgres \
  -p 5432:5432 \
  -v $PWD/pgdata:/var/lib/postgresql/data \
  postgres:10-alpine



> docker run -it --rm \
  --link pgres:db \
  postgres psql -h db -U postgres
> docker run -d --name pgres \
  -p 5432:5432 \
  -v $PWD/pgdata:/var/lib/postgresql/data \
  postgres:10-alpine


> docker run -it --rm \
  -p 8081:80 \
  -e PGADMIN_DEFAULT_EMAIL=user@domain.com \
  -e PGADMIN_DEFAULT_PASSWORD=password \
  --link pgres \
  dpage/pgadmin4


> docker run -it --rm \
  --link pgres \
  postgres psql -U postgres

what's going on

kernel tools (cgroups, namespaces, etc)

docker engine

RUNTIME

base layer

OS layer

framework layer

other layers

IMAGE

R/W layer

process PID 1

CONTAINER

image

  • file system snapshot
  • immutable
  • shared layers

container

  • instance of an image
  • 1 running process
  • R/W layer

peek into container

> sudo ps


> docker attach pgres


> docker exec -it pgres sh


> docker logs pgres

COMPOSE

why?

  • run multiple containers
  • file is more readable than shell
  • natural documentation
  • isolated network
> docker run -d --name pgres \
  -p 5432:5432 \
  -v $PWD/pgdata:/var/lib/postgresql/data \
  postgres:10-alpine


> docker run -it --rm \
  -p 8081:80 \
  -e PGADMIN_DEFAULT_EMAIL=user@domain.com \
  -e PGADMIN_DEFAULT_PASSWORD=password \
  --link pgres \
  dpage/pgadmin4


> docker run -it --rm \
  --link pgres \
  postgres psql -U postgres
version: '2'
services:
  pgres:
    image: "postgres:10-alpine"
  app:
    image: "bigtruedata/sbt:0.13.15-alpine-2.12.3"
    volumes:
      - ~/.ivy2/:/root/.ivy2
      - ./:/app/
    command: sbt run
    ports:
      - "9000:9000"
    stdin_open: true
    environment:
      - DB_URL=jdbc:postgres:pgres:5432/public

docker-compose up

nice details

  • --links not required
  • relative paths
  • extend:
  • env_file:
  • build:
version: '2'
services:
  pgres:
    image: "postgres:10-alpine"
  app:
    build: .
    ports:
      - "9000:9000"

BUILD

why?

  • one tool to build them all
  • caching

caching!

  • stable / reproducible
  • fast
  • small footprint

Dockerfile

FROM node:9.5.0-alpine
CMD npm test           
COPY package.json .      
RUN npm install        
COPY app.spec.js .    

Dockerfile

FROM node:9.5.0-alpine
CMD npm test             #  0B                cached
COPY package.json .      #  320B              cached
RUN npm install          #  4.36MB, ~3 sec    cached
COPY app.spec.js .       #  1.33kB

layer cache

Text

layer_payload = sha256(
  parent_layer_id,
  layer_command,
  filesystem_changes,
);

layer_id = layer_payload in store 
  ? store(layer_payload)
  : layer(layer_payload, current_timestamp);

cache gotchas

  • only local layers
  • mtime is ignored
  • no build-time volumes

build java

sbt stage
docker build . -t myapp
FROM openjdk:10-jre-slim
EXPOSE 9000
CMD /app/bin/dev-null
COPY ./target/universal/stage /app/
FROM openjdk:10-jre-slim
EXPOSE 9000
CMD /app/bin/dev-null
COPY ./target/universal/stage /app/
FROM openjdk:10-jre-slim
EXPOSE 9000                             # 0B    cached
CMD /app/bin/dev-null                   # 0B    cached
COPY ./target/universal/stage /app/     # 47MB

FROM bigtruedata/sbt as builder
WORKDIR /build
COPY . .
RUN sbt stage


FROM openjdk:10-jre-slim
EXPOSE 9000
CMD /app/bin/dev-null
COPY --from=builder /build/target/universal/stage /app/
FROM bigtruedata/sbt as builder
WORKDIR /build                      # 0s    cached
COPY . .                            # 0s
RUN sbt stage                       # ~6m


FROM openjdk:10-jre-slim
EXPOSE 9000                                               # 0B    cached
CMD /app/bin/dev-null                                     # 0B    cached
COPY --from=builder /build/target/universal/stage /app/   # 47MB


FROM gradle:4.5.1-jdk-alpine
WORKDIR /
COPY build.gradle settings.gradle ./
RUN gradle stage
COPY conf conf
COPY app app
RUN gradle stage
RUN rm build/stage/playBinary/lib/devnull*.jar

FROM openjdk:10-jre-slim
CMD /app/bin/playBinary
COPY --from=0 /build/stage/playBinary /app/
COPY --from=0 /build/distributionJars/playBinary/*.jar /app/lib/
FROM gradle:4.5.1-jdk-alpine
ENV GRADLE_USER_HOME=.gradle2                               #
USER root                                                   # 0B     cached
WORKDIR /                                                   # 0B     cached
COPY build.gradle settings.gradle ./                        # 661B   cached
RUN mkdir conf && touch conf/routes && gradle stage         # 188MB  cached  ~120s
COPY conf conf                                              # 1.9kB  cached
COPY app app                                                # 4.5kB
RUN gradle stage                                            # 50MB           ~20s
RUN rm build/stage/playBinary/lib/devnull*.jar              # 0B

FROM openjdk:10-jre-slim
CMD rm -f /app/RUNNING_PID && /app/bin/playBinary                   # 0B     cached
COPY --from=0 /build/stage/playBinary /app/                         # 49MB   cached
COPY --from=0 /build/distributionJars/playBinary/*.jar /app/lib/    # 34kB

docker build

like a pro

  • optimize builds

  • don't over-optimize

  • consider custom base images

  • look for " ---> Using cache"

  • docker history [image]

  • docker inspect [image]

tricks and gotchas

beware of VOLUME

FROM gradle
ADD build.gradle .
RUN gradle stage \
 && ls .gradle
RUN ls .gradle

jar/zip

+

mtime

=

cache miss! 

java

+

--memory

=

OOM! 

add some UI


-v /tmp/.X11-unix:/tmp/.X11-unix
FROM gradle:4.5.1-jdk-alpine
ENV GRADLE_USER_HOME=.gradle2                               #
USER root                                                   # 0B     cached
WORKDIR /                                                   # 0B     cached
COPY build.gradle settings.gradle ./                        # 661B   cached
RUN mkdir conf && touch conf/routes && gradle stage         # 188MB  cached  ~120s
COPY conf conf                                              # 1.9kB  cached
COPY app app                                                # 4.5kB
RUN gradle stage                                            # 50MB           ~20s
RUN rm build/stage/playBinary/lib/devnull*.jar              # 0B

FROM openjdk:10-jre-slim
CMD rm -f /app/RUNNING_PID && /app/bin/playBinary                   # 0B     cached
COPY --from=0 /build/stage/playBinary /app/                         # 49MB   cached
COPY --from=0 /build/distributionJars/playBinary/*.jar /app/lib/    # 34kB

THANKS!

Docker. For devs.

By Artem Sinicyn

Docker. For devs.

  • 74