Running Bottle Apps in Docker Containers on macOS

Post updated by Matt Makai on June 05, 2018. Originally posted on June 04, 2018.

It can be confusing to figure out how to use Docker containers in your Python and Bottle development environment workflow. This tutorial will quickly show you the exact steps to get Docker up and running on macOS with a working Bottle web application

Our Tools

This tutorial is written for Python 3. It may work with Python 2 but it has not been testing with that soon-to-be deprecated 2.7 version. You should really be using Python 3, preferrably the latest release which is currently 3.6.5.

Docker for Mac is necessary to run Docker containers. I recommend that you use the stable release unless you have an explicit purpose for the edge channel.

Within the Docker container we will use:

All for the Dockerfile and the Bottle project are available open source under the MIT license on GitHub under the docker-bottle-mac directory of the blog-code-examples repository.

Installing Docker on macOS

We must install Docker before we can spin up our containers. Jump to the next section if you already have Docker for Mac installed and working on your computer.

On your Mac, download the Docker Community Edition (CE) for Mac installer.

Download the Docker Community Edition for Mac.

Open Finder and go to the downloads folder where the installation file is located. Follow the installation steps and open Terminal when the installer finishes.

Test your Docker installation by running the docker command along with the --version flag:

docker --version

If Docker is installed correctly you should see the following output:

Docker version 18.03.1-ce, build 9ee9f40

Note that Docker runs through a system agent you can find in the menu bar.

Docker agent in the menu bar.

Docker is now installed so we can run a container and write a simple Bottle application to test running an app within the container.


Docker needs to know what we want in our container so we specify an image using a Dockerfile.

# this is an official Python runtime, used as the parent image
FROM python:3.6.5-slim

# set the working directory in the container to /app

# add the current directory to the container as /app
ADD . /app

# execute everyone's favorite pip command, pip install -r
RUN pip install --trusted-host -r requirements.txt

# unblock port 80 for the Bottle app to run on

# execute the Flask app
CMD ["python", ""]

Save the Dockerfile and then on the commandline run:

docker build -t bottledock .

The above docker build file uses the -t flag to tag the image with the name of bottledock.

If the build worked successfully the shell will show some completed output like the following:

$ docker build -t bottledock .
Sending build context to Docker daemon  16.38kB
Step 1/6 : FROM python:3.6.5-slim
3.6.5-slim: Pulling from library/python
f2aa67a397c4: Pull complete 
19cc085bc22b: Pull complete 
83bd7790bc68: Pull complete 
8b3329adba1b: Pull complete 
d0a8fd6eb5d0: Pull complete 
Digest: sha256:56100f5b5e299f4488f51ea81cc1a67b5ff13ee2f926280eaf8e527a881afa61
Status: Downloaded newer image for python:3.6.5-slim
 ---> 29ea9c0b39c6
Step 2/6 : WORKDIR /app
Removing intermediate container 627538eb0d39
 ---> 26360255c163
Step 3/6 : ADD . /app
 ---> 9658b91b29db
Step 4/6 : RUN pip install --trusted-host -r requirements.txt
 ---> Running in f0d0969f3066
Collecting bottle==0.12.13 (from -r requirements.txt (line 1))
  Downloading (70kB)
Building wheels for collected packages: bottle
  Running bdist_wheel for bottle: started
  Running bdist_wheel for bottle: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/76/a0/b4/2a3ee1a32d0506931e558530258de1cc04b628eff1b2f008e0
Successfully built bottle
Installing collected packages: bottle
Successfully installed bottle-0.12.13
Removing intermediate container f0d0969f3066
 ---> 0534575c8067
Step 5/6 : EXPOSE 80
 ---> Running in 14e49938d3be
Removing intermediate container 14e49938d3be
 ---> 05e087d2471d
Step 6/6 : CMD ["python", ""]
 ---> Running in ca9738bfd06a
Removing intermediate container ca9738bfd06a
 ---> 9afb4f01e0d3
Successfully built 9afb4f01e0d3
Successfully tagged bottledock:latest

We can also see the image with the docker image ls command. Give that a try now:

docker image ls

Our tag name should appear in the images list:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
bottledock          latest              9afb4f01e0d3        About a minute ago   145MB

Our image is ready to load as a container so we can code a short Bottle web app for testing and then further development.

Coding A Bottle Web App

It is time to code a simple "Hello, World!"-style Bottle app to test running Python code within our Docker container. Within the current project directory, create a file named with the following contents:

import bottle
from bottle import route, run

app = bottle.default_app()

def hello_world():
    return "Hello, world! (From Full Stack Python)"

if __name__ == "__main__":
    run(host="", port=8080, debug=True, reloader=True)

The above code returns a simple "Hello, world!" message when executed by the Bottle development server and contacted by a client.

We need just one more file to specify our bottle dependency. Create a requirements.txt file within the same directory as


Make sure both the and requirements.txt file are saved then we can give the code a try.

Running the Container

Now that we have our image in hand along with the Python code in a file we can run the image as a container with the docker run command. Execute the following command, making sure to replace the absolute path for the volume to your own directory.

docker run -p 5000:8080 --volume=/Users/matt/devel/py/blog-code-examples/docker-bottle-macapp bottledock

If you receive the error python: can't open file '': [Errno 2] No such file or directory then you likely did not change /Users/matt/devel/py/bottledocker to the directory where your project files, especially, are located.

Bottle web app responding to requests from within a Docker container.

Everything worked when you see a simple text-based HTTP response like what is shown above in the screenshot of my Chrome browser.

What's Next?

We just installed Docker and wrote a Bottle web app to run inside a container. That is just the beginning of how you can integrate Docker into your workflow.

Next up take a look at the Bottle, Docker and deployment pages for more tutorials.

Questions? Let me know via a GitHub issue ticket on the Full Stack Python repository, on Twitter @fullstackpython or @mattmakai.

Do you see a typo, syntax issue or just something that's confusing in this blog post? Fork this page's source on GitHub and submit a pull request with a fix or file an issue ticket on GitHub.

Sign up for a monthly email with Full Stack Python tutorials. No spam ever.

Sponsored By

Digital Ocean logo.

Easily deploy your Python web apps to Digital Ocean's reliable cloud computing platform.

Okta logo.

Secure and manage identities in your Python web apps with Okta.

Mapbox logo.

Easily build maps, search and navigation into your Python applications with Mapbox.

Scout logo

Scout monitors the performance of your Python apps, identifying slow queries, memory bloat, and more. Free during Tech Preview.

Real Python logo

Upgrade your Python skills by reading Real Python's awesome programming email newsletter.

Matt Makai 2012-2018