In this post we run a python program in a Docker container sourced from the user guide. Look at the various commands that come into play when administering containers, and then briefly setup some real world applications with Docker.
This will be the second post on Docker following on from Docker – Installing and Running (1). If you’re brand new to Docker then the first post linked helps to introduce some of its concepts and theory to better understand the utilities it can provide.
1 – Example Container Application
Pull this training image from the Docker user guide:
[alert-announce]
- $ docker run -d -P training/webapp python app.py
[/alert-announce]
The -d
option tells Docker to daemonise and run the container in the background. -P
maps any required network ports inside the container to your host, and the Python application inside is also executed at the end.
Run the Docker process command to see running container details:
[alert-announce]
- $ docker ps
[/alert-announce]
The “webapp” image container shows network ports that have been mapped as part of the image configuration:
[alert-announce]
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- b8a16d8e94cc training/webapp “python app.py” 2 minutes ago Up 2 minutes 0.0.0.0:32768->5000/tcp nostalgic_knuth
[/alert-announce]
In my example here port 5000
(the default Python Flask port) inside the container has been exposed on the host ephemeral TCP port 32768
. Ephemeral port ranges are temporary short lived port numbers which typically range anywhere from 32768 to 61000. These are dynamically used and are never set in stone.
The Docker image decides all this for us, but as an aside it’s also possible to manually sets the ports to use by a container.
This command assigns port 80
on the local host to port 5000
inside the container:
[alert-announce]
- $ docker run -d -p 80:5000 training/webapp python app.py
[/alert-announce]
It’s important never to map ports in a 1:1 fashion i.e. 5000->5000/tcp
as if we needed multiple containers running the same image, the traffic will use the same host port (5000
) and only be accessible one instance at a time.
If you like you can check the original Python docker container’s port is working by accessing:
http://localhost:32768 or http://your.hosts.ip.address:32768 in a browser.
Where the port number 32768
is set to your own example container’s ephemeral port.
Another way to see this example containers image’s port configuration is:
[alert-announce]
- $ docker port <container-name>
[/alert-announce]
Showing:
[alert-announce]
Output
- 32768->5000/tcp
[/alert-announce]
To see the front-facing host machine’s mapped ports individually add the number of the internal port to the end of the command:
[alert-announce]
- $ docker port <container-name> 5000
[/alert-announce]
Which shows:
[alert-announce]
Output
- 0.0.0.0:32768
[/alert-announce]
Now we have this example container up and running we’ll go through multiple administrative commands that are important for when working with containers. These commands if you wish can be tested with the example container, or even better with multiple instances of it. Each and ever command shown may not be completely applicable, however.
2 – Administrative Commands
Here’s a list of select Docker commands to refer to when playing around with or monitoring containers. There are even more to check out as this list is by no means exhaustive.
A few core commands were already mentioned in Docker – Installing and Running (1) so it won’t appear here.
The first command allows you to attach to a running container interactively using the container’s ID or name:
[alert-announce]
- $ docker attach
[/alert-announce]
You can detach again from the container and leave it running with CTRL
+ P
or CTRL
+ Q
for a quiet exit.
To list the changed files and directories in a container᾿s filesystem use diff:
[alert-announce]
- $ docker diff <container-name>
[/alert-announce]
Where in the output the three “event types” are tagged as either:
A
– AddD
– DeleteC
– Change
For real-time container and image activity begin a feed of event output with:
[alert-announce]
- $ docker events
[/alert-announce]
The exec command runs a command of your choosing inside a container without dropping you down into a shell inside the container.
This example creates a container named ubuntu_bash
and starts a Bash session that runs the touch
command:
[alert-announce]
- $ docker exec -d ubuntu_bash touch /tmp/execWorks
[/alert-announce]
Backing up a containers internal file-system as a tar archive is carried out using the “export“ command:
[alert-announce]
- $ docker export <container-name> > backup-archive.tar
[/alert-announce]
Show the internal history of an image with human readable -H
values:
[alert-announce]
- $ docker history -H <image-name>
[/alert-announce]
To display system wide Docker info and statistics use:
[alert-announce]
- $ docker -D info
[/alert-announce]
Return low-level information on a container or image using inspect:
[alert-announce]
- $ docker inspect
[/alert-announce]
You can filter with the inspect
command by adding the parameters described on the previously linked page.
Use SIGKILL
to kill a running container, caution as usual is advised with this:
[alert-announce]
- $ docker kill <container-name>
[/alert-announce]
Pause and unpause all running processes in a Docker container:
[alert-announce]
- $ docker pause
- $ docker unpause
[/alert-announce]
If the auto-generated names are not to your taste rename containers like this:
[alert-announce]
- $ docker rename <container-name> <new-name>
[/alert-announce]
Alternatively when first creating/running a container --name
sets the name from the onset:
[alert-announce]
- $ docker run –name <container-name> -d <image-name>
[/alert-announce]
Enter a real-time live feed of one or more containers resource usage stats:
[alert-announce]
- $ docker stats <container-name>
[/alert-announce]
Docker has its own top command for containers, to see the running processes inside:
[alert-announce]
- $ docker top <container-name>
[/alert-announce]
That’s all for these. Some real-world examples of running images from the official Docker Hub repositories are now covered briefly to serve as realistic examples for how you might want to use Docker and its containerisation.
Be mindful that these are not walk-throughs on fully setting up each service, but general starting points for each.
3 – Ghost Image Container
“Ghost is a free and open source blogging platform written in JavaScript.”
To pull the image itself:
[alert-announce]
- $ docker pull ghost
[/alert-announce]
To run a basic Ghost instance named ghost-blog-name
on the mapped port 2368
use:
[alert-announce]
- $ docker run –name <container-name> -p 8080:2368 -d ghost
[/alert-announce]
Then access the blog via http://localhost:8080 or http://your.hosts.ip.address:8080 in a browser.
The image can also be pointed to existing Ghost content on your local host:
[alert-announce]
- $ docker run –name <container-name> -v /path/to/ghost/blog:/var/lib/ghost ghost
[/alert-announce]
Check out Docker Hub – Ghost
4 – irssi Image Container
“irssi is a terminal based IRC client for UNIX systems.”
I’m not sure about the benefits of running your irssi client through Docker but to serve as another example we’ll go through the Docker Hub provided setup process:
Create an interactive shell session in a new container named whatever you choose whilst setting an environment variable named TERM
that is retrieved from the host. The user ID is set with -u
and group ID is set with the -g
option:
[alert-announce]
- $ docker run -it –name -e TERM -u $(id -u):$(id -g) \
[/alert-announce]
Then stop the log driver to avoid storing “useless interactive terminal data”:
[alert-announce]
- > –log-driver=none \
[/alert-announce]
Mount and bind the hosts /.irssi
config home directory to the internal container equivalent:
[alert-announce]
- > -v $HOME/.irssi:/home/user/.irssi:ro \
[/alert-announce]
Mount and bind the hosts /localtime
directory to the internal container equivalent:
[alert-announce]
- > -v /etc/localtime:/etc/localtime:ro \
[/alert-announce]
Pull down and apply all the previous commands to the irssi
image from Docker Hub:
[alert-announce]
- > irssi
[/alert-announce]
As everyone who uses irssi has their own configuration for the program this image does not come with any provided pre-sets. So you have to set this up yourself. Other than this you are dropped into the irssi session within the new container.
Check out Docker Hub – irssi
5 – MongoDB Image Container
“MongoDB document databases provide high availability and easy scalability.”
The standard command to pull the image and container is one we’re familiar with by now:
[alert-announce]
- $ docker run –name -d mongo
[/alert-announce]
This image is configured to expose port 27017 (Mongo’s default port), so linking other containers to it will make it automatically available.
In brief, this is how to link a new container to a Mongo container named mongo-container-name
. The image at the end is the application/service the new container will run:
[alert-announce]
- $ docker run –name <new-container-name> –link <mongo-container-name>:mongo -d <image-name>
[/alert-announce]
Using inspect
with grep
shows the link:
[alert-announce]
- $ docker inspect nginx-container | grep -i -A1 “links”
[/alert-announce]
With the output in my case being:
[alert-announce]
Output
- “Links”: [
- “/mongo-container:/nginx-container/mongo”
[/alert-announce]
Check out Docker Hub – MongoDB
6 – NGINX Image Container
“Nginx (pronounced “engine-x”) is an open source reverse proxy server for HTTP, HTTPS, SMTP, POP3, and IMAP protocols, as well as a load balancer, HTTP cache, and a web server (origin server).”
As usual like with all these images to download/pull:
[alert-announce]
- $ docker pull nginx
[/alert-announce]
A basic example is given of some static HTML content served from a directory (~/static-content-dir
) that has been mounted onto the NGINX hosting directory within the new container:
[alert-announce]
- $ docker run –name <container-name> -v ~/static-content-dir:/usr/share/nginx/html:ro -P -d nginx
[/alert-announce]
Whichever port is auto-assigned to the NGINX container can be used to access the static HTML content.
Find out the port number using either docker ps
or:
[alert-announce]
- $ docker run –name <container-name> -v ~/static-content-dir:/usr/share/nginx/html:ro -P -d nginx
[/alert-announce]
For our purpose here we want the second line’s port which in my case is 327773
– as shown:
[alert-announce]
Output
- 443/tcp -> 0.0.0.0:32772
- 80/tcp -> 0.0.0.0:32773
[/alert-announce]
http://localhost:32773 or http://your.hosts.ip.address:32773 in a browser on the localhost now returns:
The same idea but with a Dockerfile
is better, one that is located in the directory containing our static HTML content:
[alert-announce]
- $ vim ~/static-content-dir/Dockerfile
[/alert-announce]
Type in:
[alert-announce]
~/static-content-dir/Dockerfile
- FROM nginx
- COPY . /usr/share/nginx/html
[/alert-announce]
Then build a new image with the Dockerfile
and give it a suitable name; nginx-custom-image
is what I’m using for this example:
[alert-announce]
- $ docker build -t nginx-custom-image ~/static-content-dir/
[/alert-announce]
If this is successful output in this form is given:
[alert-announce]
- Sending build context to Docker daemon 6.372 MB
- Step 1 : FROM nginx
- —> 5328fdfe9b8e
- Step 2 : COPY . /usr/share/nginx/html
- —> a4bf297e4dcc
- Removing intermediate container 7a213493723d
- Successfully built a4bf297e4dcc
[/alert-announce]
All that’s left is to run the custom built image, this time with a more typical, user provided port number:
[alert-announce]
- $ docker run -it –name <container-name> -p 8080:80 -d nginx-custom-image
[/alert-announce]
Again accessing http://localhost:8080 or http://your.hosts.ip.address:8080 in a browser on the localhost shows the static HTML web pages:
Check out Docker Hub – NGINX
7 – Apache httpd (2.4) Image Container
To serve static HTML content in a directory named static-content-dir
on port 32775
of the local host machine we can use:
[alert-announce]
- $ docker run -it –name -v ~/static-content-dir:/usr/local/apache2/htdocs/ -p 32755:80 -d httpd:2.4
[/alert-announce]
Visiting http://localhost:32755 or http://your.hosts.ip.address:32755 in a browser on the localhost then returns:
With a Dockerfile for configuration, custom setups can be applied. Create the Dockerfile
in the project directory where the static content is hosted from:
[alert-announce]
- $ vim ~/static-content-dir/Dockerfile
[/alert-announce]
Add lines like the below, where line 2 copies a httpd config file from the current working directory, to the internal container’s version. And line 3 copies the entirety of the current working directory (the static HTML files) to the Apache container’s web hosting directory:
[alert-announce]
~/static-content-dir/Dockerfile
- FROM httpd:2.4
- COPY ./my-httpd.conf /usr/local/apache2/conf/httpd.conf
- COPY . /usr/local/apache2/htdocs/
[/alert-announce]
Note: If the
my-httpd:2.4
configuration file is missing, the next command to build the image will fail.
Build the new custom Apache image defined in the Dockerfile
and give it the name custom-apache-image
which you can of course change if you like:
[alert-announce]
- $ docker build -t custom-apache-image ~/static-content-dir/
[/alert-announce]
Successful output for the image build sequence looks like this (or similar):
[alert-announce]
Output
- Sending build context to Docker daemon 6.372 MB
- Step 1 : FROM httpd:2.4
- —> 1a49ac676c05
- Step 2 : COPY . /usr/local/apache2/htdocs/
- —> f7052ffe8190
- Removing intermediate container 53311d3ac0a5
- Successfully built f7052ffe8190
[/alert-announce]
Lastly, start and run a new container using the custom generated image on port 32756
of the localhost machine:
[alert-announce]
Output
- $ docker run -it –name <container-name> -p 32756:80 -d custom-apache-image
[/alert-announce]
Visiting http://localhost:32756 or http://your.hosts.ip.address:32756 in a browser on the localhost now returns:
Check out Docker Hub – httpd
8 – Jenkins Image Container
Create a new directory in your user’s home directory for the Jenkins config files. This will be mounted and mapped to the container’s equivalent configuration space:
[alert-announce]
- $ mkdir ~/jenkins_home
[/alert-announce]
Run the Jenkins image mapping the two internal ports to ephermal ports on the host side, whilst syncing the config directory we just created to the new container:
[alert-announce]
- $ docker run –name <container-name> -p 32790:8080 -p 32791:50000 -v ~/jenkins_home:/var/jenkins_home -d jenkins
[/alert-announce]
Jenkins can be seen at the first port number we mapped. In my example it was 32790
meaning a URL of http://localhost:32790 or http://your.hosts.ip.address:32790 in a browser takes us to the Jenkins application page:
Check out Docker Hub – Jenkins
Remember that there are unofficial image repositories to be found on Docker Hub too, and potentially elsewhere when made available.
The third post on Docker talks a bit more about administration with Docker. As well as details based around how to network containers together.