Python Console App with Docker

Today I want to write about dockerizing a python app, for instance, a python script.

Let’s imagine we want to run this script in different machines and we can’t control what python version they have, or even worse, we don’t know if python is installed or not, and what dependencies they have installed.

Docker helps us separate the code from the infrastructure so this blog post will be about this.

Create the Python script

Let’s create a simple python script. We’ll call the file script.py inside a src folder of the project.

#src/script.py

print('hello world!')

Create the Dockerfile

#Dockerfile

FROM python:3.6

RUN mkdir /application
WORKDIR "/application"

# Upgrade pip
RUN pip install --upgrade pip

# Update
RUN apt-get update \
    && apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

ADD requirements.txt /application/
ADD src/script.py /application/

RUN pip install -r /application/requirements.txt

CMD [ "python", "script.py" ]

FROM tells Docker which image you base your image on. In the example, Python 3.

RUN tells Docker which additional commands to execute in bash console. In the example, we create a folder called application and we later install the requirements with the pip library we installed earlier.

CMD tells Docker to execute the command when the image loads. In the example, our python script.

How to run

In your console, build the docker image

docker build -t python-script .

And then run it

docker run python-blog-scraper

You should now get a ‘hello world’ printed 🙂

Requirements

You might ask yourself, why not just run the script, i.e python script.py from the console? My answer to that is, because of the requirements. As I mentioned earlier, systems change and it’s not realistic to think that you’ll always have the python version you need with the pip requirements installed.

So let’s test this out with some requirements.

#requirements.txt

requests
beautifulsoup4

Now let’s use these requirements in our script. For instance, let’s make a GET request to my blog and let’s scrape the contents of it, maybe the title of the blog posts and the first sentence. Print these in our console.

Note: Scraping is better done with Selenium in my opinion, but just as an example, let’s just use beatifulsoup’s library.

#blog-scraper.py
import requests
from bs4 import BeautifulSoup


class BlogPost:
    title = None
    first_sentence = None

    def __init__(self, title, first_sentence):
        self.title = title
        self.first_sentence = first_sentence

    def __str__(self):
        return str(self.title) + '\n' + str(self.first_sentence)


def scrape(url):
    r = requests.get(url)

    if r.status_code == 200:
        soup = BeautifulSoup(r.content, features="html.parser")
        # print(soup.prettify())

        for article in soup.find_all('article', attrs={'class': 'post'}):
            title = article.find('h2', attrs={'class': 'entry-title'}).string
            first_sentence = article.find('div', attrs={'class': 'entry-content'}).find('p').string

            blog_post = BlogPost(
                title=title,
                first_sentence=first_sentence
            )
            print(blog_post)
            print('------------------------------')
    else:
        print('Whoops! Something went wrong!')


scrape("https://blog.joeymasip.com/")

For readability, I created a model that has the information we want to keep to print later. We’re printing as we run the loop here, not saving anything to an array or database (this is just as an example so we can use libraries we just installed). Also, I renamed this blog-scraper.py, so don’t forget to update your Dockerfile!

#Dockerfile
#...
ADD requirements.txt /application/
ADD src/blog-scraper.py /application/

RUN pip install -r /application/requirements.txt

CMD [ "python", "blog-scraper.py" ]
#...

Now let’s rebuild the image and run it.

docker build -t python-script .
docker run python-blog-scraper

And there we have it, you should have the blog posts being printed in your console!

Conclusion and Resources

As you can see, we’ve added requirements and packaged everything in a Docker image, so we can easily deploy this simple app to any machine that has docker installed and run it with no requirement missing or version issues.

I’ve uploaded the source code in GitHub here.
Link to Python library Beautifulsoup docs.
Link to Python library Requests docs.

Happy coding! 🙂