Preparing a complete Docker container with Python app

November 12th, 2016 by Alex No comments »

So you made a complex Python application (for example, a web server). You want to make sure it runs on any Linux distribution, and doesn’t interfere with existing applications running on the server. This is where you can pack your app into a Docker container.

For simplicity, let’s assume you have a very simple application with only main.py and a pip requirements.txt. To make our app docker-ready, we need to only add one new file called Dockerfile with no extension. The file will contain a base image requirement for our application and a command to run:

FROM python:3.5.2-onbuild
CMD [ "python", "./main.py" ]

I’ve put a simple print("Hello from main.py") inside the main.py. You can use other python version if your script depends on older 2.*. As usual, all the available versions on are available on docker hub https://hub.docker.com/_/python/. Plus, the Dockerfile can have additional installation steps for your application. Say, you require an external video processing library, or a PDF generation library. In that case you can extend Dockerfile by adding RUN .. commands:

FROM python:3.5.2-onbuild
# for simplicity, just check some main applications versions 
RUN git --version
RUN cpp --version
CMD [ "python", "./main.py" ]

Now let’s run the build.

docker build -t python-app:1.0.0 .

This will build the current folder (hence the .), and -tag it with the name python-app version 1.0.0.

In this case we will see the build running, and we will also see the version of Git and C++ compiler. The result will look something like:

Step 2 : RUN git --version
 ---> Running in 31b703447adc
git version 2.1.4
 ---> 79cc684f89e5
Removing intermediate container 31b703447adc
Step 3 : RUN cpp --version
 ---> Running in 223979db4455
cpp (Debian 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

This means they are there and running fine and you can use them. Now let’s run our script:

docker run -it --rm --name my-app python-app:1.0.0

If everything was fine (which it should be) then you should see:

Hello from main.py

That’s it, you now have made a Dockerfile with your app, which everyone can run on any system.

Getting started with Docker command line

November 4th, 2016 by Alex No comments »

Docker is a nice virtualization and “containerization” tool, which allows you to deploy different services on any machine regardless of hardware the service was developed on, and regardless where it is deployed.

Let’s take a look at the common commands we can use to play around. In this post I assume that you installed docker.

So first, the Docker Hub is located at https://hub.docker.com/explore/ – this is the place where you can find ready docker containers to use for your projects or to derive from.

We will start with a simple Ubuntu version 16.04 in a docker.

docker run -it ubuntu:16.04 bash

If everything was fine, you will see something like

Unable to find image 'ubuntu:16.04' locally
16.04: Pulling from library/ubuntu
 
6bbedd9b76a4: Pull complete
fc19d60a83f1: Pull complete
de413bb911fd: Pull complete
2879a7ad3144: Pull complete
668604fde02e: Pull complete
Digest: sha256:2d44ae143feeb36f4c898d32ed2ab2dffeb3a573d2d8928646dfc9cb7deb1315
Status: Downloaded newer image for ubuntu:16.04
root@35d0ef121e1d:/#

This means everything was fine and now we are in bash of Ubuntu 16.04. So what we did:

docker run is the command to run an image, -it means we want to allocate a pseudo-tty and keep the shell listening for our input. Next, ubuntu:16.04 is the name of image to run, and bash is the command to run instantly after the container is up.

Let’s continue discovering.

docker run -d -p 27017:27017 --name database mongo

Here we run the latest mongo image, expose the container port with parameter -p 27017 to host port 27017, run it in background with -d and name the container database. But how to connect to that MongoDB database? What’s the URL? Since we are using dockers, we need to get the IP address of the docker machine. If you have docker-machine installed, run

docker-machine ip <name>

The result might look like 192.168.59.103 or something like that. Of course, replace <name> with your docker-machine name (you can have multiple different names). If you have older boot2docker instead of docker-machine, then it’s boot2docker ip

Now we can connect to our container by using that IP + the port 27017.

mongo 192.168.59.103:27017

Now we can play with real mongo database and not worry about breaking your main OS. When you want to run the fresh MongoDB again, start and remove the container:

docker stop database
docker rm database

This should totally remove the container. If you run the last docker run command again, you will notice how fast the container was created – because the image is already there and running a whole new database takes a mere second only. That’s the beauty of Docker.

To see a list of containers running, use

docker ps

If some container died or was stopped, you can see it if you run

docker ps -a

To stop all containers, you can use bash arrays like this

docker stop $(docker ps -q)

You might notice the new -q parameter – this means “quiet” and it will output only the container names. If you want to remove all containers, the command will be

docker rm $(docker ps -qa)

Here, -a is for all, and -q is for quiet.

Another important feature is folder mounting. This allows us to expose the host folder to container, moreover the folder changes inside the container will be reflected in the host OS. This makes it possible to easily deploy host files (say, git checkout a repository and run a server in one step). Consider this more advanced command:

docker run -p 80:80 -p 443:443 -v `pwd`:/var/www/html -d --name=apache eboraas/apache

So let’s see what happens here. First, we will expose port 80 (for http) and port 443 (for https) from container to host, then we will mount the current working directory with parameter -v (`pwd` will get resolved to current working dir when you run it). The mounting parameter has a format of /hostpath:/containerpath and paths can’t be relative. -d will run container in detached mode, which allows us to continue using the terminal after this. If you run this in a folder with file named index.html, and then navigate browser to the IP address of the docker machine (in your case it was http://192.168.59.103), you should see the contents of index.html served by apache that we just deployed in 1 single line. That’s docker magic.

So that should get you up and ready with the basics. Now go to the hub, explore the public containers and try to accept the fact that it is so easy to create wonderful stuff nowadays 🙂

Get a random ID string in MongoDB

December 22nd, 2015 by Alex No comments »

Sometimes you need to make an ID a string while inserting some data in MongoDB. This is very simple, you just need to create a Mongo object id like this:

db.mycollection.insert({ _id: ObjectId().valueOf(), other_field: 123 });

Test server Accept-Range with cURL

June 22nd, 2015 by Alex No comments »

In case you want to make sure your videos on your very own web server can handle seeking, here is a very simple command to test it:

curl -r 1-20000 http://myurl.mp4 -o test.mp4

If the result test.mp4 is 20KB, it works.

Enable Apache2 mod_rewrite on Linux

September 22nd, 2014 by Alex No comments »

There is a special tool for that, called a2enmod, so we can just run

a2enmod rewrite

Or sudo if you are not root

sudo a2enmod rewrite

Then, restart apache

service apache2 restart