- Docker Deep Dive
- Docker Basics
- The Dockerfile, Builds and Network Configuration
- Docker commands and structures
- ---- Inspect Container Processes
- ---- Previous Container Management
- ---- Controlling Port Exposure on Containers
- ---- Naming Containers
- ---- Docker Events
- ---- Managing and Removing Base Images
- ---- Saving and Loading Docker Images
- ---- Image History
- ---- Take Control of Our Tags
- ---- Pushing to Docker Hub
- Integration and Use Cases
# i: interactive, t: tty, d: daemon mode
docker run -i -t -d ubuntu:latest /bin/bash
# to attach to the container and edit the container
docker attach container_name
Once you are attached to a container, anytime you create files, it is now part of that container!
You can do all of your updates etc.
From here, we can commit to create a base image.
docker commit -m "This is a new image" -a "[email protected]" dok/ubusshd:v1
Once this is commited, it is now put to a base container! Yay!
Let's create a simple Dockerfile to give some info about us.
# Dockerfile - example Ubuntu example with SSH already installed
FROM ubuntu:latest
MAINTAINER okeeffed <[email protected]>
RUN apt-get update
RUN apt-get -y install telnet openssh-server
For building:
# build a Dockerfile from the current location
docker build -t="dok/ubusshdonly:v2" .
top # shows the processes
docker logs container_name #shows history for container
docker exec container name /bin/cat /etc/profile
docker run container name /bin/bash -c "while true; do echo HELLO; sleep 1; done"
docker run -d -p 80:80 nginx:latest
# Dockerfile based on the latest CentOS 7 image - non-priviledged user entry
MAINTAINER [email protected]
FROM centos:latest
RUN useradd -ms /bin/bash user
USER user
To connect as the root, you just need to start the container and run docker exec -u 0 -it sleepy_allen /bin/bash
Order of Execution
We had to run a super user command to add the User. Now let's say we want to run another command.
# Dockerfile based on the latest CentOS 7 image - non-priviledged user entry
MAINTAINER [email protected]
FROM centos:latest
RUN useradd -ms /bin/bash user
# this will not give an issue - order of execution MATTERS
RUN echo 'EXPORT 129.168.0.0/24' >> /etc/exports.list # making up exports.list
USER user
# below will give an issue - order of execution MATTERS
RUN echo 'EXPORT 129.168.0.0/24' >> /etc/exports.list # making up exports.list
Example, let's install Java through the Dockerfile!
# Dockerfile based on the latest CentOS 7 image - non-priviledged user entry
MAINTAINER [email protected]
FROM centos:latest
RUN useradd -ms /bin/bash user
# this will not give an issue - order of execution MATTERS
RUN echo 'EXPORT 129.168.0.0/24' >> /etc/exports.list # making up exports.list
RUN yum update -y
RUN yum install -y net-tools wget
RUN cd ~ && wget --no-cookies --no-check-certificate --header "url"
RUN yum localinstall -y ~/java_file.rpm
USER user
RUN cd ~ && echo "export JAVA_HOME=/usr/java/jdk1.8.0/jre" >> /home/user/.bashrc
# generates env variable for everyone
ENV JAVA_BIN /usr/java/jdk1.8.0/jre/bin
Command generally sets the default command to run when there is nothing specified when container starts up.
# Dockerfile based on the latest CentOS 7 image - non-priviledged user entry
MAINTAINER [email protected]
FROM centos:latest
RUN useradd -ms /bin/bash user
CMD 'echo' 'This is a custom container message'
USER user
The entrypoint itself will ALWAYS be the concrete default application everytime that the container is created.
CMD
will only run when there is no argument, whereas ENTRYPOINT
will always run.
FROM centos:latest
MAINTAINER [email protected]
RUN useradd -ms /bin/bash user
ENTRYPOINT echo "This command will display this message on EVERY container that is run from it"
USER user
EXPOSE will allow us to expose our ports.
The follow image will allow us to build a webserver and run it from basics.
FROM centos:latest
MAINTAINER [email protected]
RUN yum update -y
RUN yum install -y httpd net-tools
RUN echo "This is a custom index file built during the image creation" > /var/www/html/index.html
ENTRYPOINT apachectl "-DFOREGROUND"
However, if we don't expose any ports, then using -P
won't automatically expose those ports. We can still forcably expose ports using `docker run --name apacheweb -d -p 8080:80 container
To auto-expose, we can do this...
FROM centos:latest
MAINTAINER [email protected]
RUN yum update -y
RUN yum install -y httpd net-tools
RUN echo "This is a custom index file built during the image creation" > /var/www/html/index.html
EXPOSE 80
ENTRYPOINT apachectl "-DFOREGROUND"
How do we work with mounts and file systems?
We can mount using -v
for mounting volumes.
Scenario One: Create a directory at launchtime called mydata
docker run -it --name voltest1 -v /mydata centos:latest /bin/bash
# once logged in
df -h # shows that there is a mounted file
# back from host OS terminal
cd /var/lib/docker # will show us the volumes folder
# if we docker inspect the container
# it will show us the volume and the source
Once we have things that are mounted, we can access them from the container and anything that we edit in the underlying host, we can see in the container!
We can't do this from the Dockerfile, because the base image is designed to be portable.
Thanks to Docker Swarm and Kubernetes, it has become easier to manage the Docker Network.
When you run a docker instance, it will auto pull the next available address.
# this will list all of the associated networks with the current host
docker network ls
docker network ls --no-trunc # to see the full address
docker network inspect bridge
Creating Docker network configs
To see things like a man
page for docker, you essential just put dashes between multi-word commands.
man docker-network-create
will bring up the network create manual.
docker network create --subnet 10.1.0.0/24 --gateway 10.1.0.1 mybridge01 # /24 is everything in that network
docker network ls
# the new bridge adapter is now there
# to remove the bridge
docker network rm mybridge01
# subnet itself can be 10.1.[1-254].[1-254] while ip-range is 10.1.4.[1-254]
# that is class b and class c respectively
docker network create --subnet 10.1.0.0/16 --gateway 10.1.0.1 --ip-range=10.1.4.0/24 --driver=bridge --label=host4network bridge04
If you then inspect the new above network config, it will have those settings within that inspect config.
So how do we now use this new network?
docker run -it --name nettest1 --net bridge04 --ip 10.1.4.100 centos:latest /bin/bash
# if we docker inspect nettest1 | grep IP we can see the address set at 10.1.4.100
From the outside, we can run docker exec
to get some more details about the container itself.
docker exec container_name /bin/ps aux | grep bash
We can use docker top
to see the top command run on a container.
docker top container_name
Let's execute a command to install sshd
. We could attach to container and do so, but we have a few options. Instead of attaching, we could do the following:
docker exec -i -t container_name /bin/bash
This will ensure that the container doesn't stop, but will actually run two instances of bash
. We can verify this by looking at the container processes.
So far, this can give us a momentary snap shot.
See the history of previous processes and performances
We can use docker stats
to see a live set of information for that container.
dock stats container_name
This will keep a view that is constantly updated to see what is going on.
Just to see the previous containers not running with just their ids, we can run docker ps -a -q
Of course, for removing older containers, we can docker rm
previous containers.
We can also remove containers from the /var/lib/docker
folder as the super user. If you do it this way, you want to ensure that you have systemctl stop/restart docker
to ensure that there aren't any issues with Docker.
In this example, start up a nginx container in daemon mode without remapping the ports.
Again, we can inspect this container to find the IP etc. We know that we can get anything remapped to the localhost currently because there is no remapping.
In contrast, we can use -P
to expose the ports and it will auto remap to high port value.
-p 8080:80
will be use defining the port that we want to expose it to.
If we want to define a certain interface eg. localhost...
docker run -itd -p 127.0.01:8081:80 nginx:latest
would ONLY allow localhost to access this site.
To rename containers, we can run docker rename currentname newname
- you can even rename container IDs, although there is likely no point.
You can also rename running containers!
How can we monitor certain events?
Startup a few containers.
When we interact with them, certain events are generated.
If we run docker events
, it will begin a program to wait and register certain events.
If we run docker events --since '1h'
, we can then see all the events that have happened in the last hour.
If we run just docker events
and run a dok exec -it mycontainerid /bin/bash
command, we will then see those events registered. This is useful for debugging and monitoring the entire host.
We may not care about every event though. What happens if we just care about an attachment?
docker events --filter <keyword>
can then be used to filter for events we care about.
docker events --filter event=attach
We can also filter for multiple events with multiple --filter event=<event>
If you remove an image by name, then if there is a double up of the same ID, it will just remove the named image - however an ID removal will warn you if they share the ID. They only way to remove all of them is to use the force -f
flag.
Saving
When we pull images, we can pull from local or from Docker Hub. You will use base of an official release usually etc.
How can we manage our custom images? We can tar
any file and migrate it to another compute etc.
docker commit containername centos:mine
This will allow us to save the image but remove the containers!
We can use
docker save --output centos.latest.tar centos:latest
If you ls
the tar file, it will give you details about the image/container.
Restoring
docker load --input centos.latest.tar
If we have gzip
a tar file, we can also load it directly from the .tar.gz
file.
How can we get the history of the base image?
docker history imagename
This will give us a list of commands etc.
Changes in the container is what is kept in storage layering.
docker tag imageid mine/centos:v1.0
- this will create a new image with the repo tag.
docker tag mine/centos:v1.0 dok.example.com/centos:v1.0b
will do the same.
docker login --username=name
throw in the password and you'll be authenticated.
One authenticated, docker push image
Of course, to bring it back down, you will hit docker pull name
Prerequisites
So far, we have not had a specific purpose for Docker containers. These following examples are for real world use cases.
Set up a web farm with two Apache web nodes on port 80 - both sharing one or more file systems.
Part One