Skip to content

2020

Build private docker registry

If you do not want publish your docker to public registry(e.g. dockerhub, aws, aliyun etc). You can use a local/private registry. Docker provide docker registry(which is is a docker image)

A good reference by digital ocean how to set up a private docker reigstry on ubuntu 18.04 And Deploy a registry server

Publish image to private registry

Note: need a https server, or add "insecure-registries":[true] in /etc/docker/demon.json

docker tag mydocker:v0.1-11 private.docker.domain.name.com:5000/mydocker:v0.3-11
docker push private.docker.domain.name.com:5000/mydocker:v0.3-11

Harbor

Trusted cloud native repository for Kubernetes Installation: [How To Install Harbor Docker Image Registry on CentOS / Debian / Ubuntu] (https://sxi.io/how-to-install-harbor-docker-image-registry-on-centos-debian-ubuntu/)

Harbor login

Harbor projects

Dockerfile

We can use * storage volume * docker exec, * ansible (and similer software) * docker run with options, * container based on container * etc

to build a customized a docker. But with dockerfile it is easy to build a customized docker.

Share system variable

As discussed early, we can use a infrastructure container to share system variable to other container. (e.g use consul) and generate configure file based on system variable. e.g. a nginx file in /etc/nginx/conf.d/

# server.config

{
  server_name $MY_NGX_SERVER_NAME;
  listen $NGX_IP:$NGX_PORT;
  root $WEB_ROOT;
}

Dockerfile

  • Source code for building Docker images. It contains all the comnands to assemble a image
  • Use docker build to access dockerfile

Dockerfile format

  • # Comment
  • INSTRUCTION arguments
    • Instruction is NOT casesensitive, but it is a convention to use UPPERCASE to distinguish them from arguments more easily
  • Docker runs instructions in a Dockerfile in order
  • The first instruction must be FROM in order to specify the Base Docker Image from which your are building.

Docker ignore file .dockerignore

Same as .gitignore

Environment variable and replacement

  • env variable (declared with ENV statement) can also be used in instructions as variables to be interpreted by Dockerfile
  • Env variable are notated in Dockerfile with $variable_name or ${variable_name}
  • ${variable_name} support bash modifiers
  • ${var:-word} if var is set, return var value, otherwise return word
  • ${var:+word} if var is set, return word value, otherwise return empty

Dockerfile instructions

FROM

  • Need to be first un-comment statement.
  • Base image can be either local image or docker registry (e.g docker hub)
  • Syntax (either)
    • FROM \[:] (repository is image name e.g nginx, redis, or ray-x/busybox-httpd)
    • FROM \@\ e.g.
      FROM busybox:latest
      

MAINTAINER (depreacted)

e.g MAINTAINER "rayxu <rayx@rayx.me>"

LABELS

  • Usage: LABEL <key>=<value> [<key>=<value> ...]
  • The LABEL instruction adds metadata to an image in format of key=value e.g MAINTAINER="rayxu <rayx@rayx.me>"

COPY

  • Syntax:
    • COPY \ [\ …] \
    • COPY [“\“, … “\“]
  • Copies new files or directories from and adds them to the filesystem of the image at the path \.
  • \ may contain wildcards and matching will be done using Go’s filepath.Match rules.
  • \ is an absolute path, or a path relative to WORKDIR.
  • If \ doesn’t exist, it is created along with all missing directories in its path.
  • If space existed in \ use “” e.g. “my src folder”

ADD

ADD is similar to COPY, expects that it can add and unzip compressed file (gz, Z, bz2, zip). It also can fetch files from URL e.g. ADD http://nginx.org/download/nginx-1.18.0.tar.gz /usr/local/ or nginx-1.18.0.tar.gz /usr/local (will untar to /usr/local, docker will have /usr/local/nginx-1.18.0) * Syntax: * ADD \ [\ …] \ * ADD [“\“, … “\“] * Same as COPY 1~5 bullet points * to un-compress, \ must not end with / * If use ADD ["<src>", ... "<dest>"] and wildcard existed in src, \ should end with / if \ not end with / it will be treat as a single file instead of a dir

WORKDIR

The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile. If the WORKDIR doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile instruction. * Syntax: * WORKDIR /path/to/workdir

  • WORKDIR can be used multiple time
    WORKDIR /usr
    RUN pwd  #output /usr
    WORKDIR /bin   
    RUN pwd # output /bin
    
  • WORKDIR instruction can resolve environment variables
    ENV DIRPATH /path
    WORKDIR $DIRPATH/$DIRNAME
    

VOLUME

The VOLUME instruction creates a mount point(volume) and marks it as holding externally mounted volumes from native host or other containers. * Syntax: * VOLUME \ e.g. VOLUME /var/log * VOLUME [“\“] e.g. VOLUME [“/opt”] * VOLUME is used to share folder between Docker and host/other dockers * Docker VOLUME is similar to -v option in docker run command. Difference is that VOLUME does not specify the directory mapping. Normally is uses to gether the logs in container. More specific, VOLUME /var/log will expose the folder to a folder like /var/lib/docker/volumes/3207....84e4 and docker container will know the mapping. Any logs in /var/log in docker will also appear in /var/lib/docker/volumes/3207....84e4

EXPOSE

Specify the port/protocol container listens on at runtime. * Syntax: EXPOSE \ [\/\…] * e.g

EXPOSE 11211/upp 11211/tcp 2 323/tcp EXPOSE 80 (default tcp) Check the port with docker port image-name

ENV

ENV sets the environment variable \ to the value \. Note ENV is set in docker build also it will be passed to docker run The ENV setup can be overwrite with docker run -e <key>=<value> * Syntax: ENV \ \ ENV \=\

  • Refer to the env variable with $variable_name or ${variable_name}
  • e.g ENV myName John Doe equal to ENV myName="John Doe"

ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy * To set a value for a single command, use RUN \=\ \

RUN

Run the executable in docke durning docker build. The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.

  • Syntax
  • RUN \ (shell form, /bin/sh -c \)
  • RUN [“executable”, “param1”, “param2”] (exec form)
  • Shell form PID not 1 and can not receive Unix signals
  • Usage
    ADD http://nginx.org/download/nginx-1.18.0.tar.gz /usr/local/src
    RUN cd /usr/local/src && \
    tar xf nginx-1.18.0.tar.gz
    
  • exec form does not support shell operator (e.g wildcard, &, >, | etc) to use shell , you need to run RUN ["/bin/bash", "-c", "<command>", "<argument1>", "<argument2>" ... ]

nohub, exec

Tp prevent demon stop after shell stops, need to use nohub or exec.

Note: nohub command exec: replaces the current process image with a new process image. This means it replace nohub: no hungup, Run a Command or Shell-Script Even after You Logout

CMD

The main purpose of a CMD is to provide defaults for an executing container. e.g. buxybox default CMD is /usr/sh, nginx default is nginx * Syntax * CMD [“executable”,”param1”,”param2”] (exec form, this is the preferred form) * CMD [“param1”,”param2”] (as default parameters to ENTRYPOINT) * CMD command param1 param2 (shell form) * If multipule CMD provided, only the last one is effective * To build a busybox httpd, which is correct: * Pitfull * CMD /bin/httpd -f -h \({WEB_ROOT} * CMD ["/bin/httpd", "-f", "-h", "\)”] * CMD [“/bin/sh”, “-c”, “/bin/httpd”, “-f”, “-h ${WEB_ROOT}”] * CMD [“/bin/sh”, “-c”, “/bin/httpd”, “-f”, “-h /opt/data/web”] * form 1, you can not enter interative mode with -it, If you need to inspect, need to run `docker exec ‘/bin/sh’ * form 2, will not work, ${WEB_ROOT} not found * form 3, will not work, start and then exit(httpd is a backend deamon sh -c httpd will return so PID 1 will exit too, this will stop the container) * form 4, will not work, start and then exit(same as above)

ENTRYPOINT

An ENTRYPOINT allows you to configure a container that will run as an executable. * Syntax * ENTRYPOINT [“executable”, “param1”, “param2”] (exec form) * ENTRYPOINT command param1 param2 * Command line arguments to docker run \ will be appended after all elements in an exec form ENTRYPOINT, and will override all elements specified using CMD. This allows arguments to be passed to the entry point, i.e., docker run \ -d will pass the -d argument to the entry point. You can override the ENTRYPOINT instruction using the docker run –entrypoint flag. * The shell form prevents any CMD or run command line arguments from being used, but has the disadvantage that your ENTRYPOINT will be started as a subcommand of /bin/sh -c, which does not pass signals. This means that the executable will not be the container’s PID 1 - and will not receive Unix signals - so your executable will not receive a SIGTERM from docker stop \.

  • Only the last ENTRYPOINT instruction in the Dockerfile will have an effect.
  • docker run --entrypoint <cmd> <args> overwrite the ENTRYPOINT in dockerfile
  • ENTRYPOINT solve the issue that CMD ["/bin/sh", "-c", "/bin/httpd", "-f", "-h /opt/data/web"] has ENTRYPOINT /bin/httpd -f =h /opt/data/web will not exit
  • If both CMD and ENTRYPOINT exists, arguments of CMD will be pass to ENTRYPOINT as argument
    CMD["/bin/httpd", "-f", "-h", "/opt/data/web"]
    ENTRYPOINT /bin/sh -c
    
    is eqal to
    ENTRYPOINT /bin/sh -c /bin/sh -c /bin/httpd -f -h /opt/data/web
    
    CMD["/bin/httpd", "-f", "-h", "/opt/data/web"]
    ENTRYPOINT ["/bin/sh", "-c"]
    
    is eqal to
    ENTRYPOINT /bin/sh -c /bin/httpd -f -h /opt/data/web
    
    if you run docker run --name bbxhttpd -it -P bbxhttpd:v0.1 "ls /opt"

“ls /opt” will overwrite CMD["/bin/httpd", "-f", "-h", "/opt/data/web"]

  • Use ENTRYPOINT to set ENV var and start deamon

file: entrypoint.sh

#!/bin/sh
cat >  /etc/nginx/conf.d/www.conf << EOF
server {
  server_name ${HOSTNAME};
   listen${IP:-0.0.0.0}:${PORT:-80}
  root ${NGX_DOC_ROOT:-/usr/share/nginx/html}
}
EOF
exec "$@"   # PID=1

file Dockerfile

FROM nginx:1.18-alpine
ENV NGX_ROOT="/usr/data/html"
ADD index.html ${NGX_ROOT}
ADD entrypoint.sh /bin/
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]

Run:

$ docker build -t nginx_demo:v0.1 ./
$ docker run --name ngx1 --rm -P nginx_demo:v0.1
login into docker
$ docker exec -it ngx1 /bin/sh
# ps
PID  USER  TIME  COMMAND
1    ROOT  0:00  nginx: master proccess /usr/bin/nginx -g daemon off; 

You will see nginx started and use ROOT user. That is not good for security reason

# ### USER User name for RUN, CMD, ENTRYPOINT * Syntax * USER \[:\] * USER \[:\] * check /etc/passwd for \

HEALTHCHECK

The HEALTHCHECK instruction tells Docker how to test a container to check that it is still working. (e.g. not responding, infinite loop) Syntax * HEALTHCHECK [OPTIONS] CMD command (check container health by running a command inside the container) * The options that can appear before CMD are: * –interval=DURATION (default: 30s) * –timeout=DURATION (default: 30s) * –start-period=DURATION (default: 0s) * –retries=N (default: 3) * Response: * 0: success - the container is healthy and ready for use * 1: unhealthy - the container is not working correctly * 2: reserved - do not use this exit code * HEALTHCHECK NONE (disable any healthcheck inherited from the base image) example:

HEALTHCHECK --interval=5m --timeout=5s --start-period = 1m\
  CMD curl -f http://localhost/ || exit 1

A more complex example

FROM nginx:1.18-alpine
ENV NGX_ROOT="/usr/data/html"
ADD index.html ${NGX_ROOT}
ADD entrypoint.sh /bin/
EXPOSE 80
HEALTHCHECK --start-period = 3s --interval=10 --timeout=1s CMD wget -O - -q http://{IP:-0.0.0.0}:${PORT:-80}/
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
The check result will show in console:
docker run --name web1 --rm -P -e "PORT=8080" ngx:v0.1
127.0.0.1 - - [10/May/2020:18:11:20 +0000] "GET / HTTP/1.1" 200 32 "-" "Wget" "-"
127.0.0.1 - - [10/May/2020:18:11:23 +0000] "GET / HTTP/1.1" 200 32 "-" "Wget" "-"

SHELL

The SHELL instruction allows the default shell used for the shell form of commands to be overridden. The default shell on Linux is [“/bin/sh”, “-c”], and on Windows is [“cmd”, “/S”, “/C”]. The SHELL instruction must be written in JSON form in a Dockerfile. * Syntax * SHELL [“executable”, “parameters”] * Example * SHELL ["powershell", "-command"] * SHELL ["/usr/bin/zsh", "-c"]

STOPSIGNAL

sets the system call signal that will be sent to the container to exit. * Syntex * STOPSIGNAL signal

ARG

The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the –build-arg = flag. If a user specifies a build argument that was not defined in the Dockerfile, the build outputs a warning. This provide a way to use one dockerfile to meet different requirement * Syntex * ARG \[=\]

example:

...

ARG auther="ray-x"
LABEL maintainer="${auther}"
...
Use –build-arg to pass the ARG in docker build --build-arg auther="ray-x rayx@mail.com"

ONBUILD

The ONBUILD instruction adds a trigger instruction to be executed at a later time, when the image is used as the base for another build. The trigger will be executed in the context of the downstream build, as if it had been inserted immediately after the FROM instruction in the downstream Dockerfile. * Syntax * ONBUILD \ * ONBUILD can not use in ONBUILD ONBUILD ONBUILD CMD ["ls"] is illegal * Use onbuild tag for base image has onbuild * COPY, ADD may not work....(different context)

e.g. docker nginx1:v0-onbuild

...
ONBUILD ADD http://nginx.org/download/nginx-1.18.0.tar.gz /usr/local/src

FROM nginx1:v0-onbuild

Docker storage

Quote from docker.com “Copy-on-write is a strategy of sharing and copying files for maximum efficiency. If a file or directory exists in a lower layer within the image, and another layer (including the writable layer) needs read access to it, it just uses the existing file. The first time another layer needs to modify the file (when building the image or running the container), the file is copied into that layer and modified. This minimizes I/O and the size of each of the subsequent layers. These advantages are explained in more depth below.”

COW is low efficiency and thus I/O intensive application will need to mount data volume from host to docker.

Storage volume will help data persistency after docker image removed. Also split data with binary executable.

Bind mounts

A volume that points to a user specified location on host file system bind mount /my/bind/volume -> (bind) to host /user/configured/directory

Docker managed volume

Docker deamon creates managed volumes in a portion of host’s file system that owned by docker `var/lib/docker/vfs/dir/

Usage: Use -v to use volume

  • Dockage-managed volume:
  • docker run -it –name bbox1 -v /data busybox
  • docker inspect -f {{.Mounts}} bbox1
    • Inspect bbox1 container volume, volume id and directory in host ([{volume bb23e94e907dc29f3e62deddd332520d34f489177c5bbd5b03a8a75426430a19 /var/lib/docker/volumes/bb23e94e907dc29f3e62deddd332520d34f489177c5bbd5b03a8a75426430a19/_data /data local true }] )
  • Bind mount volume
  • docker run -it –name bbox2 -v HOSTDIR:VOLUMEDIR busybox e.g. docker run -it --name bbox2 -v /data/volumes/b2:/data busybox
  • docker inspect -f {{.Mounts}} bbox2
    • output: [{bind /data/volumes/b2 /data true rprivate}]

Share folder and joint container with -v and --volumes-from

  • User case duplicate setup/data:
  • Container A startup and access file/setup F in host.
  • Container B startup and access F through container A
  • Container C startup and access F through container A
  • Container A could stop/pause
  • Network duplication
  • Container A startup and startup network network1 and loopback and filesystem
  • Container Nginx started up and use A to access network1 and loopback and nginx setup
  • container tomcat started up and use A to access loopback and tomcat setup
  • container mysql started up and use A to loopback and data volume
  • Application server started up and use A to access loopback

Instruction example

Startup a infrastructure container infrcon access host folder /data/infracon/volume docker run --name infracon -it -v /data/infracon/volume/:/data/web/html busybox

Startup httpd docker run --name httpd --network container:infracon --volumes-from infracon -it bosybox

Useful docker commands

Some most used docker commands. On ubuntu, if docker install with snap, add /snap/bin/ to PATH

Most docker command should have two levels. But for comparability reason commands can be both top level command and command with sub commands.

e.g.

docker pull nginx should be docker image pull nginx in latest docker versions. I will use docker [image] pull to indicate the command can either be docker image pull or docker pull

Docker image vs container

From article How to Automate Docker Deployments An image is an inert, immutable, file that’s essentially a snapshot of a container. Images are created with the build command, and they’ll produce a container when started with run.

Useful commands

Command Command description Command example
docker [COMMAND] --help man page for docker
docker version version number
docker info docker info (build, file system etc)
docker inspect NAME|ID low-level information on Docker objects
docker search Search a image by name search nginx image docker search nginx
docker [image] pull Pull a image by name pull nginx image docker image pull nginx or to specific a version docker image pull nginx:stable-alpine or docker image pull nginx:1.16.1-alpine
docker [image] ls list downloaded images
docker [image] rmi image-id remove docker images
docker [image] rm container-id remove docker images
docker [container] ls equal to docker ps COMMAND field indicate the current running process in the container -a display stopped container
docker network ls list available networks by default started container will be added to bridge(NAT) network
docker run IMAGE run a docker image
  • IMAGE image name, e.g nginx, nginx:nginx:alpin if not available in local, will download
  • –name [imagename]
  • –rm [remove after stop]
  • -it run in interactive mode and allocate a TTY
  • -d detach mode, for demons
docker stop/start stop/start a docker container start can only used to start a stopped container -ai interactive
docker kill send kill -9 to container(image name)and force it stop. container will be in exited status docker stop will send 15
docker [container] rm delete a container container status need to be exited
docker exec Run a command in a running container

Play around

docker run --name kvstore -d redis:6-alpine

docker ps
docker pause kvstore
docker unpause kvstore
docker container logs kvstore  #get logs
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
633a89c3f23e redis:6-alpine “docker-entrypoint.s…” 5 seconds ago Up 44 econds 6379/tcp kvstore

login into the docker and run bin/sh

docker exec -it kvstore  /bin/sh
/data #

Docker cheat sheet

A good summary Docker Cheet Sheet

Base command

from latest cmd line reference Docker(base command)

Docker container life cycle Docker Events Explained

And this one: Docker Events Explained