




/var/run/docker.sock)export DOCKER_HOST=... to talk to remote engine listening on TCP portdocker group to allow non-root users access to the docker
UNIX socketdocker image <command> and container handling through
docker container <command>. There are legacy commands that still can be
used, e. g. docker pull == docker image pull and docker run ==
docker container run.$ docker --version
Docker version 26.0.0, build 2ae903e
$ docker info
Client: Docker Engine - Community
Version: 26.0.0
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.13.1
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.25.0
Path: /usr/libexec/docker/cli-plugins/docker-compose
Server:
Containers: 51
Running: 49
Paused: 0
Stopped: 2
Images: 49
Server Version: 26.0.0
Storage Driver: overlay2
Backing Filesystem: xfs...
Commands shown:
docker run <image>
docker run -it <image> <command>
docker run -d <image> <command>
docker attach
# Ctrl+P,Q to detach
docker stop <container>
docker kill <container>
docker images
docker ps -a
docker pull <image>
docker pull <image:tag>

ID (e.g. 15895ef0b3b2) or name:tag
(e.g. fedora:latest)docker push to internal image registrydocker pull/docker run
ping)/var/lib/docker (depending on storage driver)latest

aufs, devicemapper, …)Commands shown:
docker pull <image>
docker pull -a <image>
docker images
docker history <image>
docker rmi <image>
hello-world image in a new containerdocker run --name <name>docker stop (sends SIGTERM to PID 1), docker kill
(sends SIGKILL to PID 1) and docker restartwhich are realized using Kernel Namespaces
cgroups are used to limit resource usage (CPU, network, etc.)init, so child processes are not terminated
gracefullyCommands shown:
docker run --name <name> <image> <command>
docker run -it <image> <command>
docker run -d <image> <command>
docker run --rm <image>
docker exec -it <container> <command>
docker top <container>
docker attach <container>
docker start <container>
docker stop <container>
docker restart <container>
docker ps
docker ps -a
docker rm <container>
docker create --name <container> <image>
docker tag <image> <tag>
docker inspect <container>
docker port <container>
docker logs [-f] <container>
docker commit <container> <image>[:<tag>]
docker save -o <file> <image>
tar -tf <file>
docker rmi <image>
docker load -i <file>
docker run -p <public port>:<internal port> <image>
docker run -v <local path>:<container path> <image>
ping in the backgroundalpine imagealpine image with ping 8.8.8.8 commandpingubuntu container and step into itcurl and exitcurl_example:1.0curl https://www.google.com
Dockerfile (casing matters!)FROM <base image>[:<tag>] (which can be scratch)LABEL maintainer "<name and email>")COPY, ADDRUNEXPOSEVOLUMESUSERENVENTRYPOINT, CMD# Commentsdocker commit after each line)COPY and ADD,
RUN is cached based on line following RUNBUILD_ARGs.dockerignore filesENTRYPOINT statementdocker run <image> <args>ENTRYPOINT script./docker-entrypoint.sh teamcity-server run is the defaultdocker run -it agross/teamcity bash.dockerignore fileRUN statementsupervisord and the like)Sort multi-line arguments and indent 4 spaces:
RUN apt-get update && apt-get install --yes \
cvs \
git \
mercurial \
subversion
FROM: Use current official repositoriesRUN: Split long or complex RUN statements across multiple lines separated
RUN command-1 && \
command-2 && \
command-3
RUN apt-get upgradeUse the JSON array format for CMD to prevent an additional shell as PID 1
CMD ["executable", "param1", "param2", "..."]
CMD ["apache2", "-DFOREGROUND"]
CMD ["perl", "-de0"]
CMD ["python"]
CMD ["php", "-a"]
ENTRYPOINT only when requiredEXPOSE the usual ports for your applicationsCOPY over ADDLeverage the build cache, disable if necessary:
docker build --no-cache=true -t <image>[:<tag>] .
# Will use cache unless requirements.txt change.
COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
# Will use cache unless any file changes.
COPY . /tmp/
Do not use ADD to download files, although it’s possible. Use RUN with
curl, unzip/... and rm instead to keep images small:
# Bad - 3 layers.
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
# Good - 1 layer.
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
gosu when required to run as non-rootDockerfile in a running container, REPL-styleHEALTHCHECK in the Dockerfile or run containers with
--health-{cmd,interval,timeout,retries}VOLUMEsCommands shown:
docker build .
docker build --tag <image>:<tag> .
docker build --build-arg <arg>=<value>
docker run --env <var>=<value>
docker run -p <external port>:<internal port> <image>
docker run -p <external port>:<internal port>/udp <image>
docker run -p <ip address>:<external port>:<internal port> <image>
docker run -P <image>
docker port <container>
Dockerfile for https://github.com/agross/docker-hello-appTHE_ANSWER=42THE_ANSWER is thereCreate a new file index.jade in the current directory:
html
body Content from the host
/app/views/ directory with the
directory that contains the index.jade file above/app/views/index.jade (e.g. using echo)index.jade on your hostdocker login [<server>] (login info is persisted)
if you want to use docker push <image><hub user name>/<repo>[:<tag>] to be able to pushdocker run -d -p 5000:5000 --name registry registrydocker login [<server>]
docker push <image>
hello under your user account on Docker Hub<hub user name>/hellohttps://hub.docker.com/r/<hub user name>/hello/tags/ for your uploaded
image
docker volume ls
docker volume create <name>
docker run -d <image>
docker run -d -v <name>:<mount point> <image> <command>
pingsalpine with sh -c 'ping 8.8.8.8 > /data/ping.txt' with /data being
mounted to the pings volumealpine container that mounts pings and inspect pings.txt
contents using tail -f--networkhelloagross/hello on the hello network, but --name them
differently (one and two) and to not publish portsone and two, look for network settingshello networkone or two and try to ping the otherRun nginx on the hello network
docker run --rm -d --name nginx --network hello -p 80:80 nginx
Write a nginx config file (hello.conf) that uses one and two as
upstreams:
upstream hello {
server one:8080;
server two:8080;
}
server {
listen 80;
location / {
proxy_pass http://hello;
}
}
Restart nginx, this time with the conf above bind-mounted to
/etc/nginx/conf.d/default.conf
docker run -d --name nginx --network hello -p 80:80 -v $PWD/hello.conf:/etc/nginx/conf.d/default.conf nginx
wordpress and mariadbRun a MariaDB container on the network from step 2 and inject some environment variables:
MARIADB_ROOT_PASSWORD=secret
MARIADB_DATABASE=wordpress
MARIADB_USER=wordpress
MARIADB_PASSWORD=wordpress
Is there a better way than multiple --env parameters? Hint: Use a file.
Run WordPress on the network from step 2 and tell it where it can find the database server:
WORDPRESS_DB_HOST=<mariadb container name>:3306
WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_PASSWORD=wordpress
docker-compose!docker compose use-casesdocker compose creates a per-composition network by default, named after
the current directory (unless docker compose -p <name> ... is specified).docker compose up runs it finds any containers from previous runs and
reuses the volumes from the old container (i.e. data is restored).docker compose reuses
existing containers because it caches the configuration bits that were used to
create a container.Variables in the docker-compose.yaml file can be used to customize the
composition for different environments.
web:
ports:
- "${EXTERNAL_PORT}:5000"
Override settings for different environments,
e.g. production.yml containing changes specific for production:
docker compose -f docker-compose.yml -f production.yml up -d
docker-compose scale <service>=<instances>docker composeSince WordPress cannot run without a database connection we need to ensure that the database is ready to accept connections before WordPress starts. But Docker does not really care about startup order and service readiness. There are several solutions to this problem. Some involve using external tools like:
Using these external tools require you to change a container’s ENTRYPOINT or
CMD (depending on how the image defines those). This change involves defining
the dependency using the external tool and also telling the external tool what
it means to start e.g. WordPress.
Docker’s builtin method, which is only available to docker-compose.yaml files
using version: 2 (e.g 2.x), is to define a HEALTHCHECK-based dependency.
Here the dependent container (database) must define healthiness and the
depending container (WordPress) can then define its dependency to be satisfied
if the dependent is healthy.
services:
db:
image: mysql
# MySQL does not come with a HEALTHCHECK, so we need to define our own.
healthcheck:
# This check tests weather MySQL is ready to accept connections.
test: ["CMD", "mysql", "--user", "root", "--password=secret", "--execute", "SELECT 1;"]
# Allow 15 seconds for MySQL initialization before running the first check.
start_period: 15s
app:
image: wordpress
# Start the WordPress container after the database is healthy.
depends_on:
db:
condition: service_healthy
You may use either method in the next exercise.
my-wordpress and enter itdocker-compose.yamlPaste the following:
services:
mariadb:
image: mariadb
environment:
MARIADB_ROOT_PASSWORD: secret
volumes:
- ./wp/db/conf:/etc/mysql/conf.d:ro
- ./wp/db/data:/var/lib/mysql
# Required because of "condition: service_healthy" below.
healthcheck:
test: ["CMD", "mariadb", "-uroot", "-psecret", "-e", "SELECT 1;"]
start_period: 5s
interval: 5s
wordpress:
image: wordpress:php7.0
# Define "db" alias for the mariadb service.
links:
- mariadb:db
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_PASSWORD: secret
ports:
- 80:80
restart: always
volumes:
- ./wp/data:/var/www/html/wp-content
# Define startup order.
depends_on:
mariadb:
condition: service_healthy
smtp:
condition: service_started
smtp:
image: mwader/postfix-relay
restart: always
environment:
POSTFIX_myhostname: example.com
docker compose updocker-compose.yaml such that the php7.1 tag is used for wordpressRebuild and restart the WordPress container:
docker compose up --no-deps -d wordpress
mariadb to 2 instancesmariadb using docker compose exec. In which instance did you
step?mariadb instances are there?down the application and remove all containers, networks, etc.logs for the composition and for a single servicekill $(pgrep -f apache). Is the container restarted? Why?docker compose stop)Add a new top-level section:
volumes:
wp-db-conf:
wp-db-data:
wp-data:
volumes: to use volume mounts instead of bind mounts.
E.g. - ./wp/mariadb/data:/var/lib/mysql becomes - wp-db-data:/var/lib/mysqlagross/hello needs a databasedocker-compose.yaml file that builds a composition of
agross/hello’s source
code at https://github.com/agross/docker-hello
and e.g. MariaDB?