# The Docker Book
Things to checkout Shipyard, DockerUI, maDocker - UI's for docker
docker helpdocker info- get info from the server about current images and containers on the systemdocker-machine- tool to manage the virtual machine on mac osx. MUST NOT BE RUN AS SUDOdocker-machine ip- get ip address of the server (different depending if your running in windows/mac or linux)docker-machine status- check if docker is runningdocker-machine ls- get a list of all docker machinesdocker machine create --driver virtualbox <NAME>- create a new docker machine using the virtualbox driver with the provided nameeval "$(docker-machine env <NAME>)"- setup the current consule to use the docker machine provided by NAMEdocker ps -a- show all containers including ones that have stopped (-l option will show the last container) - it will also show network and port mapping informationdocker run -i -t <IMAGE>:<TAG> <COMMAND>- create and start a new container in interactive mode based off the ubuntu imagedocker run --name <NAME> ...- create and start a new container with a certain name (needs to be unique)docker run --name <NAME> -d- create and start in daemon mode (best for services and long running processes) - for background tasks. STDOUT doesnt goto terminaldocker run -p <PORT>... - run a container and map the exposed port in the container to a port defined . if no port is provided at run then one is randomly selected between 49000- 49900docker run -p <HOST-PORT>:<CONTAINER-PORT>- run container and map a host port to the containers exposed port ie. -p 8080:80docker run -P ...- expose all container ports and local portsdocker run -v <HOST_DIR>:<CONTAINER_DIR>- run the conatiner and mount a local directory to a directory in the containerdocker run -v <xxx>:<yyy>:ro/rw- Mount the volume with either read only or read write permissionsdocker run --link <CONTAINER_NAME>:<ALIAS>- run a container and link it directly to another container so that it could see it. give the connection an aliasdocker run -h <HOSTNAME>- run a container and set the hostname, this will end up in the hosts filedocker run --volumes-from <CHILD_NAME>docker run ... --log-opt max-size=10m- run a container with a max log size of 10 megs, other options available for log rotation such as max-file=xdocker port <ID> <CONF-EXPOSED-PORT>- show what real port is being mapped to the exposed portdocker start <NAME/ID>- start a container that already exists - it will start with the same options it was created withdocker stop <NAME/ID>- stops a running/daemonized container - sends the standard SIGTERM signaldocker kill <NAME/ID>- kills a running/daemonized container - sends the standard SIGKILL signaldocker attach <NAME/ID>- connect to the docker container that is currently runningdocker logs -f <NAME>- view the output of a container through its logs. You can use the optional -f flag to tail the logsdocker inspect <NAME>- get details about a containerdocker inspect -f "{{ .Volumes }}" <NAME>- get details on where the volumes are actually on diskdocker rm <ID>- delete a container. The container must not be running in order to delete itdocker rmi <IMAGE>- delete an image locallydocker images- list images available locallydocker image <USER>/<REPO>- list images in a repodocker pull <IMAGE>:<TAG>- download images from the hubdocker search <IMAGE>- do a search against the docker hub for an imagedocker login- login using your hub account (the id is NOT your email address)docker commit <ID/NAME> <USER>/<REPO>- do a local commit of an imagedocker commit .... -m '' -a 'author'docker push <USER>/<REPO>- push a locally commited image to the docker hubdocker build .- build the docker file in the current directory and give the image the latest tagdocker build -t="<USERNAME>/<IMAGENAME>:<VERISON>" .- build the docker image from the current directory and give it a tagdocker history <ID>- look at each layer of the image to see how it was builtdocker-compose up- use the current directories docker-compose.yml file to start up containers defined in the filedocker-compose up -d- run in detach modedocker-compose down- stop all the containersdocker-compose -f <FILENAME> up/down- docker compose with a defined filedocker swarm init --advertise-addr <MANAGER-IP>- start a swarm with the defined ip as the managerdocker swarm join-token worker- generate the token for a worker to join the swarmdocker swarm join --token <TOKEN> <IP:PORT>- join the swarmdocker swarm leave <NODE>- remove a worker node from the swarmdocker info- get the general state of the swarmdocker node ls- list all nodes in a docker swarmdocker node ps <NODE-NAME>- list running containers on a specific nodedocker node inpect <NODE-NAME>- print out node informationdocker node promote/demote <NODE-NAME>- promote or demote a node to/from managerdocker node remove <NODE-NAME>- remove a node from a swarmdocker service create --replicas <NO> --name <NAME> <IMAGE>- create a service from the manager and allow the manager to choose where to deploy the imagedocker service ps <NAME>- looks for all services with name in the swarmdocker buildx create --name <NAME> --use --bootstrap-this creates, sets it as the current builder (use) then starts it up (bootstrap)docker buildx ls- list all buildersdocker buildx stop <NAME>- stop a builderdocker buildx rm <NAME>- delete a builder by namedocker buildx build --push --platform linux/amd64,linux/arm/v7 --tag generalmeow/home-dashboard:latest .- this will use the new build container to build two versions of the image and push it to docker hub
- On a modern linux machine you don't need much. For latest Ubuntu, you could get away with configuring the repo then 'sudo apt-get install lxc-docker'
- Docker requires root level permissions when running, so most if not all commands will require sudo, unless you add your user to the docker group, look up the post installation instructions to do so
- When installing on ubuntu based systems, you need to configure the Uncomplicated Firewall (UFW) to get it working with a network bridge. This is because UFW drop forwarded packets. -- To do so, edit the /etc/default/ufw file and update the property "DEFAULT_FORWARD_POLICY" to "ACCEPT" then reload with 'sudo ufw reload'
- To start a new container, use the command:
docker run -it <IMAGE> <COMMAND>i.e.docker run -it ubuntu /bin/bash. -i makes STDIN open to the container, -t assign a pseudo tty to the container. - This command will look to a locally install image (ubuntu), if it doesn't find it, it will download it from the docker hub.
- Then it will run the command (/bin/bash) within it
- If the container doesn't exist yet, it will create it for you before running it.
- It will also setup networking, filesystem, ID, name and bridge interface to talk to the host
- You will have a command prompt for the container, once you exit it, the container will stop running
- Using the
docker ps -acommand will show you all containers - If you create a new container without a name, docker will provide one for you unless you provide one with the
--nameoption i.e.docker -run --name my_container -it. - Most docker commands can be run with a name rather than an id.
- Container names need to be unique
- To start a container that exists but has stopped, use the command
docker start <NAME/ID>i.edocker start my_container - Starting a container this way will start it like we did with the run command (in this case at the bash prompt)
- To reattach to this container in interactive mode use the attach commdn
docker attach <NAME/ID> - You can create and run daemonized containers with the -d option. These are best suited for service type applications.
docker run --name server -d ubuntu /bin/bash... - Running in daemon mode stops the output from going to the terminal, to see whats happening in a container use the command
docker logs <NAME>you can use it with the '-f' flag to tail and--tail 0 -fto tail without going through the entire log - You can look at the processes in a container with the
docker top <NAME> - You can stop a container with the
docker stop <NAME/ID>ordocker kill <NAME/ID>these will send SIGTERM or SIGKILL signals to the container - Getting details about a container can be done using:
docker inspect <NAME> - docker stores images, containers and container configuration under the
/var/lib/dockerdirectory - To delete containers use the following command:
docker rm <ID>. The container must not be running to delete it. docker run -h <HOSTNAME>runs a container and sets the hostname of the container to<HOSTNAME>docker -e <ENV>=<VALUE>set environment variables to be used within the docker file
- Docker uses a filesystem called the union file system
- union filesystems allow you to mount multiple systems and make it look as though its one file system.
- The docker file system consists of layers upon layers of file systems with the top most one being the one where you keep your changes
- Each layer is read only with the exception of the top most one
- The lowest FS is the one that contains the kernel and bootfs, then on top of that its the base image i.e. ubuntu, the a number of other layers can be on top of that
- As every layer is read only, any change to files in these file systems will result in a copy of the file into the writable layer than the changes are saved there. this is called "Copy on Write". This makes everything read only / static and changes that you want made only appear in the writable layer and is refered to
- Images are stored in repositories and repositories are stored in the docker hub.
- When using an image, you should always refer to it by the image name and its tag
- There are two types of repositories, top level ones which are maintained by docker and vendors i.e. redhat and ubuntu, then theres third party ones run by normal people.
- A user repository takes the form for
<USERNAME>/<REPO> - docker images can be downloaded manually using the command
docker pull <IMAGE> - and you can search for images to download using the command:
docker search <IMAGE> - There are two ways in which you can build your own images, use the
docker commitordocker buildwith a build file - Its generally recommended to use the build command with build file as its more flexible and 'powerful'
- To use 'docker commit' you would first need to log into your account on the command line with
docker login. This will then store your configuration in.docker/config.json - To use 'docker commit' you would need to customise a running container i.e. install apache. Then exit and the use the
docker commit <IMAGEID> <USER>/<REPO>command - The 'docker build' command is the recommended way of building docker images, it uses a docker file that uses DSL instructions to build the image
- By default, the directory containing the dockerfile is called the build environment aka build context. (the dot parameter when doing builc)
- The build context and its contents are uploaded to the docker daemon to build docker images, so that it has access to all files etc
- Example of a docker file
#Docker file version 1 - comment
FROM ubuntu:14.04 #this should always be the first instruction. this is known as the base image
MAINTAINER Paul hoang
ENV REFRESHED_AT 01-01-2016
RUN apt-get update
RUN apt-get install -y nginx
RUN echo 'Hi this is the conatiner' > /usr/share/nginx/html/index.html
EXPOSE 80 #This tell the daemon that port 80 is used to communicate with this container, this doesn automatically open it though, thats up to the run command to specify
- Each instruction is in upper case followed by an argument
- Each instruction adds a new layer to the image and commits
- If an instruction fails, since the last instruction committed, you can run the container and debug why it didn't work
- To do this get the ID of the image from the build output and use it with docker run i.e.
Step 3: RUN apt-get update
--->Running in <PREVIOUS-IMAGE-ID>
---><NEW IMAGE ID>
Step 4: failed
- docker run -t -i <NEW IMAGE ID> /bin/bash
... now debug
- To build the image, you must be within the build context and run the command
docker build -t=<REPO>/<IMAGENAME>:<VERSON> .the dot is to look at current dir for docker file - You can also define a git repo instead of the current directory as the source of the docker file
docker build git@github:<USER>/<REPO> .dockerIgnorefile is used as a list like.gitIgnoreto ignore files to send to the daemon- As each instruction is committed, it could be used as a cache if rerun. This causes issues if you want to make changes. if you want to clear the cache i.e you want to rerun the apt-get update step, one could build with the
--no-cacheoption i.e.docker build --no-cache - Another way to clear the cache is to use the ENV instruction. If this changes and you rebuild, it will clear the cache of all the instructions following the ENV instruction
##Docker file instructions
-
CMD ["<COMMAND>","ARG1 To Command", "Arg2"]
- specify a command to run in the container (much like the command defined when using docker run). it's recommended to use the array syntax for this instruction. the docker run command overrides this instruction if a command is provided at command line
-
ENTRYPOINT
- like the CMD instruction but the commands provided during the
docker runcommand is provided to the ENTRYPOINT instruction i.e. ENTRYPOINT ["apt-get install apache2"] and if we run the docker container with the following -docker run -ti <CONTAINERNAME> -y. This will provide ENTRYPOINT with an additional argument -y - ENTRYPOINT can also be overridden with the
--entrypointoption - When using an entrypoint that requires options from the command line, its always a good idea to also provide a CMD instruction to show the help options if nothing is provided i.e.
- like the CMD instruction but the commands provided during the
ENTRYPOINT ["wget"]
CMD ["-?"]
- WORKDIR this instruction defines the working directory for all instructions after it i.e.
WORKDIR /var/log/tomcat7
CMD ["cp", "./console.out", "/home"]
WORKDIR /opt/apache2/www/html
...
-
ENV
- sets environment variables i.e. ENV JAVA_VERSION 1.8.
- you can also provide environments via the command line with the -e flag i.e. docker run -ti -e "JAVA_VERSION=1.8" <CONTAINER_NAME> <CMD>
-
USER
- this instruction provides the container the user name in which the image should run as
- username or UUID can be provided here
- the -u flag can be used to provide a user during runtime
- the default user it root !!
-
VOLUME
- adds a volume to one or more containers
- used as persistent or shared storage
- used for things such as source code or db
- i.e. VOLUME ["/opt/project"]
- a volume can be shared even though the container sharing it isn't running
- removing a container will only remove the volume once all the containers using it are removed
- Does NOT remove the content of a directory inside the container if it already exists. Once mounted to the host directory, it will overlay its contents
-
ADD
- copy files or directories from the build environment to the image
- supports urls
- support .tar files and automatically unpacks them for you
- if destination folder doesn't exist, docker will create it with 0755 and UID of 0
- i.e. ADD apache.conf /etc/apache2/apache.conf
-
COPY
- like add but focused on copy files from the BUILD CONTEXT (the dir in which the docker build file lives)
- no support for extracting files
-
ON BUILD
- creates triggers to images
- used when an image is used as a base for another image
- it essentially adds new instructions to the image using this image by additing them straight after the FROM intruction
- i.e. ONBUILD ADD . ./badsdfds/sdfsdf
- You can save docker images to the docker hub with the push command i.e.
docker push <USER>/<IMAGE_NAME> - Automated builds are possible by connecting github or bitbucket to dockerhub and push the docker file to the github/bitbucket repo
- Removing images locally is done with the rmi command. i.e. sudo docker rmi <USER>/<IMAGE_NAME>
- Removing from the docker hub is hub via the web interface
- You can run your own docker register by using a image provided by docker or you can use a service like quay.io
- To run the standard docker provided registry, use command: sudo docker run -p 5000:5000 regristry
- Tag an image using its id with: docker images
docker tag <IMAGE-ID> <REGISTRY-DOMAIN-NAME>:5000/<USERNAME>/<IMAGENAME>docker push <REGISTRY-DOMAIN-NAME>:5000/<USERNAME>/<IMAGENAME>
- To mount a volume in your container, use the -v flag during run: docker run -ti -v <HOST_DIR>:<CONTAINER_DIR> ...
- where the host directory is the directory on the host machine you wish to mount
- where container directory is the directory to mount the host directory to
- You can connect containers in two ways.
- Use the docker networking stack
- This method involves connecting using the ip address that docker assigns to each container using its virutal interfaces (not recommended as these IP's change when the container restarts and it hard codes the ips in the parent container)
- Use the in built link method
- Use: sudo docker run -d --name myDatabasContainer <DB_IMAGE>
- Then: sudo docker run -ti --name myWebApp --link myDatabaseConatiner:dbConnection <WEBAPP_IMAGE>
- Prefered method, doesn't require you to expose the port of the child container (this case the DB) using the -p flag, exposed ports from the docker file are only exposed to the parent container
- Allows multuple containers to be linked this way
- Security benefit as the container isn't accessable from outside the host
- As an additional security option is to use the --icc=false flag, this will force the child container to only allow comms between containers using links
- Docker populates the link alias into the parent's /etc/hosts file and ENV variables i.e you will see xxx.xxx.xxx.xxx dbConnection in the hosts file. To view the environment variables, use the "env" command in a container.
- Use the docker networking stack
- Sharing volumes between containers can be done using the --volumes-from flag during run. This will allow the running container access to a VOLUME exposed in the child container.
- You will need to define in child container a VOLUME instruction or at least run the child container with the -v flag
- This will work even if the child container isn't running
- Deleting the child container will only delete the volume if all containers using the volume are deleted.
- To backup volumes, you can run a new container that backups the volume then removes itself. i.e. docker run -rm --volumes-from <CHILD_CONTAINER> -v $(pwd):/<DIR_TO_BK_TO> ubuntu tar -zcf /<DIR_TO_BK_TO>.tar.gz /<WHATEVER_YOU_WANT_TO_BACKUP>
- You can get ssh like access to any container using the command line too nsenter. Its available via a docker container
- To install nsenter run: docker run -v /usr/local/bin:/target jpetazzo/nsenter
- To run nsenter you need the process id PID of the container you wish to enter
- docker inspect "{{ .State.Pid }}" <CONTAINER>
- sudo nsenter --target <PID> --mount --uts --net --pid
- You can interact with docker using an API directly. (its restful)
- Registry API
- Docker Hub API
- Docker Remote API
- You can create docker images that will run for multiple architectures on a single machine
- To do so, you must use docker buildx which under the covers will use buildkit which is a new backend for docker
- To start off, you will need a builder container in which all the building will happen
docker buildx create --name mybuilder --use --bootstrapthis creates, sets it as the current builder (use) then starts it up (bootstrap)docker buildx build --push --platform linux/amd64,linux/arm/v7 --tag generalmeow/home-dashboard:latest .this will use the new build container to build two versions of the image and push it to docker hub- For the push to work, you will need to have been logged into your repo, use
docker loginto do so- Platforms that are supported are:
- linux/amd64
- linux/arm/v7
- linux/arm/v6
- Platforms that are supported are: