3.28.2018

Docker Cheat Sheet

List docker images
$ docker images

Run an image to make a container (terminal interactive - bash shell)
$ docker run -ti ubuntu:latest bash

List containers
$ docker ps

Stop a container
$ docker stop musing_easley

List stopped containers
$ docker ps --filter "status=exited"

List all containers
$ docker ps -a

Create a new image and tag
$ docker commit [container_id]
$ docker tag [image_id] [image_name]
OR do in one shot:
$ docker commit [container_id] [image_name]

=== Running Things in Docker ===

Delete container when exits
$ docker run --rm -ti ubuntu sleep 5
$ docker run -ti ubuntu bash -c "sleep 3; echo all done"

Start a detached container - leave containers running
$ docker run -d -ti ubuntu bash

Attach to running container
$ docker attach [container_name]

Detach from a container - leave container running
Ctrl+p, Ctrl+q

=== Run more things in a Container ===

Start a shell on a running container (Great for debugging and DB admin)
$ docker exec -ti simpleapp_redis_1 sh

=== Looking at Container Output ===

Look at output
$ docker logs [container_name]

=== Stopping and Removing Containers ===

Kill a container
$ docker kill [container_name]

Remove container
$ docker rm musing_easley

Remove all stopped containers
$ docker rm $(docker ps -a -q)

=== Resource Constraints ===

Memory limits
$ docker run --memory maximum-allowed-memory image-name command

CPU Limits
$ docker run --cpu-shares (relative to other containers)
$ docker run --cpu-quota (to limit it in general)

=== Lessons from the Field ===
1.  Dont let your containers fetch dependencies when they start.
2.  Dont leave important things in unnamed stopped containers.

=== Exposing Ports ===

Expose ports like "-p [outside:inside]"
$ docker run --rm -ti -p 45678:45678 -p 45679:45679 --name echo-server ubuntu:20.04 bash

host.docker.internal - special DNS name which resolves to the internal IP address used by the host, cause localhost wont work.

Exposing ports dynamically (dont specify outside port)
$ docker run --rm -ti -p 45678 -p 45679 --name echo-server ubuntu:20.04 bash

Look which outside port it assigned
$ docker port echo-server

Exposing UDP ports
$ docker run -p outside:inside/protocol (tcp/udp)
$ docker run -p 1234:1234/udp

=== Container Networking ===

Look at existing networks
$ docker network ls

Create a new network
$ docker network create [network_name]
$ docker network create learning

Put machines in the network
$ docker run --rm -ti --net learning --name catserver ubuntu:20.04 bash

Connect networks together
$ docker network connect [network1] [network2]

=== Images ===

List images
$ docker images

Create image
$ docker commit [container_id] my-image-name

Tag image
$ docker commit [container_id] my-image-name:version-tag
$ docker commit 1d622ef86b13 my-new-image:v2.1

Example of name structure:
registry.example.com:port/organization/image-name:version-tag

Cleaning up - delete images
$ docker rmi image-name:tag
$ docker rmi image-id

=== Volumes - Sharing data between containers and the host ===

Persistent - data is permanent
Ephemeral - not permanent

Volumes are not part of images

Make a local host folder that is shared with a container
$ mkdir /Users/sdelacruz/example
$ docker run -ti -v /Users/sdelacruz/example:/shared-folder ubuntu:20.04 bash
root@d492826b8e97:/# touch /shared-folder/sample
$ ls example/
sample

Sharing Data between Containers

volumes-from
Shared "discs" that exist only as long as they are being used

Container 1:
$ docker run -ti -v /shared-data ubuntu:20.04 bash
root@90a67521af1c:/# echo hello > /shared-data/data-file

List running container
$ docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
90a67521af1c        ubuntu:20.04        "bash"              47 seconds ago      Up 46 seconds                           inspiring_benz

Container 2:
$ docker run -ti --volumes-from inspiring_benz ubuntu:20.04 bash
root@c880cb8099aa:/# ls /shared-data/
data-file

When exiting both containers, the shared volumes will be GONE (Ephemeral)

=== Docker Registries ===

Registries manage and distribute images

Finding images
$ docker search ubuntu

Using Docker Hub
$ docker login

Pull and Push
$ docker pull debian:sid
$ docker tag debian:sid [docker-io-login]/[image-name]:[tag-name]
e.g., $ docker tag debian:sid thearthur/test-image-name:v99.9
$ docker push [docker-io-login]/[image-name]:[tag-name]
e.g., $ docker push thearthur/test-image-name:v99.9

REMEMBER:
1. Dont push images with sensitive info like passwords!  Clean up images.
2. Be aware of what containers being fetched, make sure coming from trusted sources.

=== Docker Files ===

Small program to create an image
Dockerfiles are not shell scripts
Processes you start on one line will not be running on the next line

Run docker file to create image
$ docker build -t name-of-resulting-image .

=== The most basic Dockerfile ===
FROM busybox
RUN echo "building simple docker image."
CMD echo "hello container"

=== Another example ===
FROM debian:sid
RUN apt-get -y update
RUN apt-get install nano
CMD ["bin/nano", "/tmp/notes"]

$ docker build -t example/nanoer .
$ docker run --rm -ti example/nanoer

=== Adding a File through Docker Build ===
(continuing from previous step)
FROM example/nanoer
ADD notes.txt /notes.text
CMD ["/bin/nano", "/notes.txt"]

$ docker build -t example/notes .

=== Dockerfile Syntax ===
FROM - Which image to download and start from, must be first command in Dockerfile
e.g., FROM java:8

MAINTAINER - defines author of this Dockerfile
e.g., MAINTAINER Firstname Lastname <email@example.com>

RUN - runs the command line, waits for it to finish, and saves the result
e.g., RUN unzip install.zip /opt/install/
e.g., RUN echo hello docker

ADD
- Add local files
e.g., ADD run.sh /run.sh

- Adds the contents of tar archives
e.g., ADD project.tar.gz /install/

- Works with URLs
e.g, ADD https://project.example.com/download/1.0/project.rpm /project/

END - sets environment variables, both during the build and when running the result
e.g., ENV DB_HOST=db.production.example.com

ENTRYPOINT - specifies the start of the command to run

CMD - specifies the whole command to run

Shell Form
e.g., nano notes.txt

Exec Form
e.g., ["/bin/nano", "notes.txt"]

EXPOSE - maps a port into the container
e.g., EXPOSE 8080

VOLUME - defines shared or ephemeral volumes
e.g., VOLUME ["/host/path" "/container/path/"]
e.g., VOLUME ["/shared-data"]

Avoid defining shared folders in Dockerfiles

WORKDIR - sets the directory the container starts in
e.g., WORKDIR /install/

USER - sets which user the container will run as
e.g., USER arthur
e.g., USER 1000

=== Multi-Project (Multi-stage??) Dockerfiles ===
FROM ubuntu:20.04 as builder
RUN apt-get update
RUN apt-get -y install curl
RUN curl https://google.com | wc -c > google-size

FROM alpine
COPY --from=builder /google-size /google-size
ENTRYPOINT echo google is this big; cat google-size

=== Preventing Golden Image Problem ===
Include installers in your project
Have a canonical build that builds everything completely from scratch
Tag your builds with the git hash of the code that built it
Use small base images, such as Alpine
Build images you share publicly from Dockerfiles, always
Dont ever leave passwords in layers; delete files in the same step

=== Registry ===
Docker Registry
Nexus

Run your own registry
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
$ docker tag ubuntu:20.04 localhost:5000/mycompany/my-ubuntu:99
$ docker push localhost:5000/mycompany/my-ubuntu:99

Storage Options
-local storage
-Amazon/Google/Microsoft

Save images to local
$ docker save -o my-images.tar.gz debian:sid busybox ubuntu:20.04

Load images from local
$ docker load -i my-images.tar.gz

=== Orchestration ===
Start containers - and restart them if they fail
Service discovery - allow them to find each other
Resource allocation - match containers to computers

=== Docker Compose ===
Single machine coordination
Designed for testing and development, but not for production
Brings up all containers, volumes, networks, etc. with one command

=== Kubernetes ===
For large deployments
Containers run programs
Pods group containers together
Services make pods available to others
Labels are used for very advanced service discovery
Advantages of Kubernetes
	- Makes scripting large operations possible with the kubectl command
    - Very flexible overlay networking
    - Runs equally well on your hardware or a cloud provider
    - Built-in service discovery
    
=== EC2 Container Service (ECS) ===
Task definitions - define a set of containers that always run together
Tasks - actually makes a container run right now
Services and exposes it to the Net
Advantages of ECS
	- Connects load balancers (ELBs) to services
    - Can create your own host instances in AWS
    - Make your instances start the agent and join the cluster
    - Pass the docker control socket into the agent
    - Provides docker repos - and its easy to run your own repo
    - Containers (tasks) can be part of CloudFormation stacks
    
Others:
Docker Swarm
Google Kubernetes Engine
Azure Kubernetes Service