Cheat sheets for Docker
Cheat sheets for Docker
#Install
Docker
Docker: https://www.docker.com/products
wget -qO- https://get.docker.com/ | sh
Docker-Compose
Docker Compose: https://docs.docker.com/compose/install/
curl -L https://github.com/docker/compose/releases/download/1.23.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
#Basics
What are Containers
A virtual machine grabs CPU, MEM, DISKIO, NETWORK, etc. and slices it into virtual variants to build virtual machines that look and feel like real physical servers.
Docker on the other hand, instead of slicing physical resources it slices operating system resources. I.e. Process Namespace, Network Stack, File System. Every container gets its own version of those.
Docker creates more like a virtual operating system that share the same physical resources. Which is way more lightweight than virtual machines.
Version
docker -v
Shows Version of client and server.
Docker Client is the interface that takes commands and run the respective API calls to the Deamon.
Info
docker info
Shows what is going on on a host. I.e. running containers. Version info.
docker node ls
lists all docker nodes in a swarm
#Containers
Run
docker run hello-world
hello-world
here is the name of a docker image.
docker run -d --name web -p 80:8080 foo/bar
-d
: run in background--name web
: give it a friendly unique name-p 80:8080
: map a port inside the container (here 8080) to a port on the machine (here 80)foo/bar
: get the image named bar
from user foo
docker run -it --name temp ubuntu:latest /bin/bash
-it
: in interactive terminal mode (ssh inside the container)/bin/bash
: run bash process (give me a terminal that allows me to interact with that container)
You usually don’t do that.
Inside, you can run ctrl+P+Q
to quit without exiting the process.
start / stop / rm
docker start <container>
docker stop <container>
docker rm <container>
docker rm
completely removes it as opposed to stop
.
docker stop $(docker ps -aq)
runs docker stop against the output of docker ps -aq
:-aq
: all containers in quiet mode (q = just the IDs).
exec
docker exec <id> <command>
docker exec d63 node foo.js
Executes a command inside a running docker container
logs
docker logs <id>
Outputs the logs of that container
"SSH" (Bash) into a container
- Use docker ps to get the name of the existing container.
- Get a bash shell in the container.
docker exec -it <container name> /bin/bash
Note: Generically, use docker exec -it <container name> <command>
to execute whatever command you specify in the container.
#Container Volumes
docker run -p 80:8080 -v $(pwd):/var/www node
-v <host-location>:<location>
: create a volume. <location>
is the container volume (alias inside the container). <host-location>
is the location on your computer.$(pwd)
: current working directory.
docker inspect <container>
Will display the source/target location of mounted volumes. (in the Mounts:
area)
docker run -p <h-port>:<c-port> -v <h-location>:<c-location> -w "<location>" <image> <command>
# Example: docker run -p 80:8080 -v $(pwd):/var/www -w "/var/www" node npm start
-w "<location>"
: specifies the working directory inside the container (where the command will be run).<command>
: will be run after container creation. Example npm start
.
docker rm -v <container>
-v
: also removes the container that was created/managed by docker (outside of the container). Note: It will not remove your source code if you specified any.
#Container Communication
Legacy Linking
Linking containers by name:
- run container by name
- link to running container by name
repeat for additional containers
run container by name
docker run -d --name <name> <image>
# Example
docker run -d --name my-postgres postgres
-d
: run in background<name>
: give container a name
- link to running container by name
docker run -d -p <h-port>:<c-port> --link <c-name>:<alias> <username>/<imagename>
# Example
docker run -d -p 80:8080 --link my-postgres:postgres johndoe/foobar
--link
: links the container to a running container where <c-name>
is the container name and <alias>
an alias we give the container-link internally.
Like that containers can speak to each other.
For example: when you give the link an alias as we did in the example above. Inside that second container you can call that first container by calling the alias. Instead of for example localhost:5000
, you would do postgres:5000
.
Container Networks
Allows to isolate containers in groups.
- Create a bridge network
Add containers to that network
Create a bridge network
docker network create --driver <drivername> <network-name>
docker network create --driver bridge my_isolated_network
--driver
: a network driver type. It can even be cross host. Common is bridge
.
- Add containers to that network
docker run -d --net=<network-name> --name <name> <image>
docker run -d --net=my_isolated_network --name myMongo mongo
--net=<network-name>
: run container into that specific network--name
: give it a name to link to ("link" to this container by name / = server name to reference)
Note: linking === communicating
Official name of this technique: Container networking With Bridge Driver
.
Is used similarely as legacy linking when it comes to code.
Inspecting
docker network inspect my_isolated_network
will list information about the network, including linked containers
#Processes
docker ps
shows all running Processes
docker ps -a
shows all processes, running or not, active or exited.
docker ps -aq
List all processes running and not running but only their IDs (quiet)
#Images
docker images
See information on all images we have locally.
docker pull ubuntu
docker pull will just pull an image from https://hub.docker.com but not apply/run it immediately.
docker pull ubuntu:14.0.4
pulls an image of specific version.
docker rmi 4ab4c602aa5e
removes an image by ID (repository:tag would also be valid)
docker rmi $(docker images -q)
removes all images (rocker rmi => docker images -q (= all image ids))
#Custom Images
Dockerfile
Example Dockerfile:
FROM node
MAINTAINER John Doe
ENV NODE_ENV=production
ENV PORT=3000
COPY . /var/www
WORKDIR /var/www
VOLUME ["/foo/bar", "/logs"]
RUN npm install
EXPOSE $PORT
ENTRYPOINT ["node", "server.js"]
FROM
: a base image where it will be build ontopMAINTAINER
: name of the person maintaining that fileENV
: set environment variables for the containerCOPY
: will bake the code inside the volume layer of that imageWORKDIR
: where does it run the code?VOLUME
: attach one or more volumes from the docker host (the one environment that will run the image)RUN
: code to run when buildingEXPOSE
: ports to expose. $PORT
is the environment variable set earlier.ENTRYPOINT
: code to run when starting
Build an image
docker build -f <dockerfile> -t <username>/<imagetag> <context>
-t
/--t
: tag the build (to be found on dockerhost)context
: what context it will be build from (i.e. where the dockerfile is)-f
: where the dockerfile is located (and how it is named)
Usual flow for node:
rm -r node_modules
docker build -f Dockerfile -t johndoe/mynode .
Publish image to docker hub
docker push <username>/<imagetag>
Typical flow:
docker login
docker push <username>/<imagetag>
Pushes to a public repo on your dockerhub
Publish image to private docker repository
Instead of username use the repository location:
docker build -f <dockerfile> -t <location>/<imagetag> <context>
# Example: docker build -f dockerfile -t example.com/mynode .
docker login <uri>
# Example: docker login https://example.com
docker push <location>/<imagetag>
# Example: docker push example.com/mynode
#Docker Compose
Useful to manage automatically different lifecycles of services.
File
docker-compose.yml
version: "2"
services:
nginx:
container_name: nginx
build:
context: .
dockerfile: .docker/docker-nginx.dockerfile
links:
- node1:node1
- node2:node2
ports:
- "80:80"
- "443:443"
env_file:
- ././docker/env/app.${APP_ENV}.env
network:
- foo-network
node1:
container_name: node-foo-1
build:
context: .
dockerfile: .docker/node.dockerfile
# environment:
# NODE_ENV: development
# v--- use env_file to group several env variables inside (see below)
env_file:
- ././docker/env/app.${APP_ENV}.env
networks:
- foo-network
ports:
- "8080"
working_dir: /var/www/foo
volumes:
- .:/var/www/foo
node2:
container_name: node-foo-2
build:
context: .
dockerfile: .docker/node.dockerfile
env_file:
- ././docker/env/app.${APP_ENV}.env
networks:
- foo-network
ports:
- "8080"
working_dir: /var/www/foo
volumes:
- .:/var/www/foo
mongo:
container_name: mongo
image: mongo
build:
context: .
dockerfile: .docker/docker-mongo.dockerfile
ports:
- "27017:27017"
networks:
- foo-network
env_file:
- ././docker/env/app.${APP_ENV}.env
- ././docker/env/mongo.${APP_ENV}.env
networks:
nodeapp-network:
driver: bridge
Commands
docker-compose build
docker-compose up
docker-compose down
docker-compose logs
docker-compose ps
docker-compose stop
docker-compose rm
docker-compose scale <servicename>=<amount>
build
: builds the imagesup/down
: starts/stops the built images as containers (down also removes the containers docker-compose down --rmi all --volumes
will remove all containers, all their images and the docker managed volumes)logs
: shows the output of the containersps
: lists the servicesstop/start/rm
: stops/starts/removes the services
Note: you can also run all commands on a single service by adding the name. I.e. docker-compose up --no-deps node
. Latter will run the node container without any service dependencies.
Example structure
.docker/
config/
…
env/
app.development.env
> NODE_ENV=development
> Env2=foo
mongo.development.env
> MONGODB_ROOT_USERNAME=dbadmin
> MONGODB_ROOT_PASSWORD=password
> MONGODB_ROOT_ROLE=root
> MONGODB_USERNAME=webrole
> MONGODB_PASSWORD=password
> MONGODB_DBNAME=foo
> MONGODB_ROLE=readWrite
> NODE_ENV=development
mongo_scripts/
backup_job.sh
entrypoint.sh
first_run.sh
> applies env variables to mongodb
> ROOT_USER=${MONGODB_ROOT_USERNAME}
> ROOT_PASS=${MONGODB_ROOT_PASSWORD}
> ROOT_DB="admin"
> ROOT_ROLE=${MONGODB_ROOT_ROLE=root}
> …
run.sh
> scedule cron jobs for backup with backup_job.sh
> run first_run.sh
node_scripts/
…
redis_scripts/
…
docker-mongo.dockerfile
docker-nginx.dockerfile
docker-node.dockerfile
docker-redis.dockerfile
Example of setup on pluralsight:
https://app.pluralsight.com/player?course=docker-web-development&author=dan-wahlin&name=docker-web-development-m7&clip=5&mode=live
Dockerfile Examples
nginx
FROM nginx:latest
MAINTAINER foo
# copy custom nginx config
COPY ./.docker/config/nginx.conf /etc/nginx/nginx.conf
# copy public resources to nginx path
COPY ./public /var/www/public
EXPOSE 80 443
ENTRYPOINT ["nginx"]
node
FROM node:latest
MAINTAINER foo
WORKDIR /var/www/foo
RUN npm i -g pm2@latest
RUN mkdir -p /var/log/pm2
EXPOSE 8080
ENTRYPOINT ["pm2", "start", "server.js", "--name", "foo", "--log", "/var/log/pm2/pm2.log", "etc…"]
#Swarm
docker swarm init --advertise-addr <ip>:<port> --listen-addr <ip>:<port>
# Example: docker swarm init --advertise-addr 213.244.192.13:2377 --listen-addr 213.244.192.13:2377
--advertise-addr <ip>:<port>
: no matter how many NICs and IPs, this is the one to use for swarm related stuff as using the API--listen-addr <ip>:<port>
: what the node listens on for swarm manager traffic
All nodes will have to be able to reach this IP.
Any Port will work but native engine port is 2375
, secure engine is 2376
, so 2377
is the unofficial swarm port.
Also add these 2 commands to each manager and each worker.
Important: these IPs are the Worker/Managers OWN IPs (not the lead manager ip)
List nodes
docker node ls
lists all docker nodes in a swarm. Can only be run by managers
Add managers
docker swarm join-token manager
Gives the exact command to add managers to the swarm.
Managers are also acting as workers.
Add --advertise-addr <server-ip>:2377 --listen-addr <server-ip>:2377
at the end of the command. Make sure, that server-ip
is the IP of the server you’re currently on.
Add workers
docker swarm join-token worker
Gives the exact command to add workers to the swarm
Make worker a manager
docker node promote <id>
Promotes a worker to become a manager.
#Services
docker service <create | ls | ps | inspect | update | rm>
Inspect
docker service inspect --pretty <name>
Create
docker service create --name <name> -p <port>:<port> --replicas <amount> <image>
-p
: maps ports accross entire service
--replicas
: how many tasks inside the service (distribute task around X worker nodes in the network. When one goes down, anotherone takes over)
Remove
docker service rm <name>
removes the service
Scaling
docker service scale <name>=<amount>
Is an alias for: docker service update --replicas <amount> <name>
name
: the name of the service to scaleamount
: the amount of replicas it should have
Keep in mind. Adding new nodes to the deck does not automatically rescale the cluster.
Rolling updates
docker service update --image <image>:<version> --update-parallelism <number> --update-delay <time>s <service-name>
--update-parallelism 3
: update 3 tasks at a time
--update-delay 10s
: update 3 tasks every 10 seconds
Get service name -
$ docker service ls
Force-update/recreate it -
$ docker service update --force MY-APP_nginx
Stack (docker-compose service)
docker stack deploy --compose-file=docker-compose.yml
Same as docker-compose up -d
docker stack rm
Same as docker-compose down
#Useful
Create an ubuntu dev-environement in seconds:
docker run \
-e HOST_IP=$(ifconfig en0 | awk '/ *inet /{print $2}') \
-v $(pwd):/src \
-t -i \
ubuntu /bin/bash
Will start a docker ubuntu machine and bind some volume to src
into the machine. Now you can play around from within the terminal.
SSH into a running container
docker exec -it <container name> /bin/bash
Copy files from Docker container to host
docker cp <containerId>:/file/path/within/container /host/path/target
Own Private Docker-Registry
Create Docker Registry
mkdir ~/docker-registry && cd $_
mkdir data
vim docker-compose.yml
version: '3'
services:
registry:
image: registry:2
ports:
- "5000:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
- ./data:/data
Setup Nginx port forwarding
sudo vim /etc/nginx/sites-available/example.com
Find the existing location line. You need to forward traffic to port 5000, where your registry will be running. You also want to append headers to the request to the registry, which provide additional information from the server with each request and response. Delete the contents of the location section, and add the following content into that section:
location / {
# Do not allow connections from docker 1.5 and earlier
# docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
proxy_pass http://localhost:5000;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
sudo service nginx restart
cd ~/docker-registry
docker-compose up
Adding Authentification
sudo apt install apache2-utils -y
mkdir ~/docker-registry/auth && cd $_
Add a user:
htpasswd -Bc registry.password username
For any following user just do htpasswd registry.password username
Now edit the docker-compose.yml
:
...
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry
REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
...
volumes:
- ./auth:/auth
...
Starting Docker Registry as a Service
edit docker-compose.yml
...
registry:
restart: always
...
docker-compose up -d
Increasing File Upload Size for Nginx
sudo vim /etc/nginx/nginx.conf
...
http {
client_max_body_size 2000M;
...
}
...
sudo service nginx restart
Commands
- List all repositories (effectively images):
curl -X GET https://example.com/v2/_catalog
# {"repositories":["redis","ubuntu"]}
- List all tags for a repository:
curl -X GET https://example.com/v2/ubuntu/tags/list
# {"name":"ubuntu","tags":["14.04"]}
- Delete an Image
Remove the files locally (stored in the /data
folder).
Then run:
docker exec registry bin/registry garbage-collect --dry-run /etc/docker/registry/config.yml
#Troubleshooting
Permission denied
If you get following error:
docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.26/containers/create: dial unix /var/run/docker.sock: connect: permission denied.
See 'docker run --help'.
You’ll have to add your user to the docker
group:
sudo usermod -a -G docker <user>
Replace <user>
with your user account. (You can find your user account name by typing whoami
in the console)
And then restart your console (or open a new one) for the changes to take effect.