# 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 "firstname.lastname@example.org" 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@example.com> RUN apt-get update RUN apt-get -y install telnet openssh-server
# 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 firstname.lastname@example.org 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@example.com FROM centos:latest RUN useradd -ms /bin/bash user # this will not give an issue - order of execution MATTERS RUN echo 'EXPORT 22.214.171.124/24' >> /etc/exports.list # making up exports.list USER user # below will give an issue - order of execution MATTERS RUN echo 'EXPORT 126.96.36.199/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 firstname.lastname@example.org FROM centos:latest RUN useradd -ms /bin/bash user # this will not give an issue - order of execution MATTERS RUN echo 'EXPORT 188.8.131.52/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@example.com 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 firstname.lastname@example.org 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@example.com 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 firstname.lastname@example.org 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
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
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
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
ls the tar file, it will give you details about the image/container.
docker load --input centos.latest.tar
If we have
gzip a tar file, we can also load it directly from the
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.
docker push image
Of course, to bring it back down, you will hit
docker pull name
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.