|
| 1 | +title: First Steps with Bottle Apps in Docker Containers on macOS |
| 2 | +slug: first-steps-bottle-web-apps-docker-containers |
| 3 | +meta: Learn how to set up and develop a new Bottle web application within a Docker container. |
| 4 | +category: post |
| 5 | +date: 2018-06-04 |
| 6 | +modified: 2018-06-04 |
| 7 | +newsletter: False |
| 8 | +headerimage: /img/180604-bottle-docker/header.jpg |
| 9 | +headeralt: Bottle, Docker and Apple logos, copyright their respective owners. |
| 10 | + |
| 11 | + |
| 12 | +It can be confusing to figure out how to use [Docker](/docker.html) |
| 13 | +containers in your [Python](/why-use-python.html) and |
| 14 | +[Bottle](/flask.html) |
| 15 | +[development environment](/development-environments.html) workflow. |
| 16 | +This tutorial will quickly show you the exact steps to get Docker |
| 17 | +up and running on macOS with a working Bottle |
| 18 | +[web application](/web-development.html) |
| 19 | + |
| 20 | + |
| 21 | +## Our Tools |
| 22 | +This tutorial is written for [Python 3](/python-2-or-3.html). It may work with |
| 23 | +Python 2 but it has not been testing with that soon-to-be deprecated |
| 24 | +[2.7 version](https://pythonclock.org/). You should really be using Python 3, |
| 25 | +preferrably the latest release which is currently |
| 26 | +[3.6.5](https://www.python.org/downloads/release/python-365/). |
| 27 | + |
| 28 | +[Docker for Mac](https://docs.docker.com/docker-for-mac/install/) is necessary |
| 29 | +to run Docker containers. I recommend that you use the stable release unless |
| 30 | +you have an explicit purpose for the |
| 31 | +[edge channel](https://docs.docker.com/docker-for-mac/edge-release-notes/). |
| 32 | + |
| 33 | +Within the Docker container we will use: |
| 34 | + |
| 35 | +* Python 3, specifically the |
| 36 | + [slim-3.6.5 version](https://hub.docker.com/r/library/python/tags/) |
| 37 | + from [Docker Hub](https://hub.docker.com/) |
| 38 | +* [Bottle](/bottle.html) version 0.12.13 |
| 39 | + |
| 40 | +All for the Dockerfile and the Bottle project are available open source |
| 41 | +under the MIT license on GitHub under the |
| 42 | +[docker-bottle-mac directory](https://github.com/fullstackpython/blog-code-examples/tree/master/docker-bottle-mac) |
| 43 | +of the |
| 44 | +[blog-code-examples](https://github.com/fullstackpython/blog-code-examples) |
| 45 | +repository. |
| 46 | + |
| 47 | + |
| 48 | +## Installing Docker on macOS |
| 49 | +We must install Docker before we can spin up our containers. Jump to |
| 50 | +the next section if you already have Docker for Mac installed and working |
| 51 | +on your computer. |
| 52 | + |
| 53 | +On your Mac, |
| 54 | +[download the Docker Community Edition (CE) for Mac](https://www.docker.com/community-edition#/download) |
| 55 | +installer. |
| 56 | + |
| 57 | +<img src="/img/180309-flask-docker/docker-ce.jpg" width="100%" |
| 58 | + class="shot rnd" alt="Download the Docker Community Edition for Mac."> |
| 59 | + |
| 60 | +Find the newly-downloaded install within Finder and double click on the file. |
| 61 | +Follow the installation process, which includes granting administrative privileges |
| 62 | +to the installer. |
| 63 | + |
| 64 | +Open Terminal when the installer is done. Test your Docker installation with the |
| 65 | +`--version` flag: |
| 66 | + |
| 67 | +``` |
| 68 | +docker --version |
| 69 | +``` |
| 70 | + |
| 71 | +If Docker is installed correctly you should see the following output: |
| 72 | + |
| 73 | +``` |
| 74 | +Docker version 17.12.0-ce, build c97c6d6 |
| 75 | +``` |
| 76 | + |
| 77 | +Note that Docker runs through a system agent you can find in the menu bar. |
| 78 | + |
| 79 | +<img src="/img/180309-flask-docker/docker-agent.png" width="100%" |
| 80 | + class="shot rnd" alt="Docker agent in the menu bar."> |
| 81 | + |
| 82 | +I have found the Docker agent to take up some precious battery life |
| 83 | +on my Macbook Pro. If I am not developing and need to max battery time I will |
| 84 | +close down the agent and start it back up again when I am ready to code. |
| 85 | + |
| 86 | +Now that Docker is installed let's get to running a container and writing |
| 87 | +our Flask application. |
| 88 | + |
| 89 | + |
| 90 | +## Dockerfile |
| 91 | +Docker needs to know what we want in a container, which is where the |
| 92 | +`Dockerfile` comes in. |
| 93 | + |
| 94 | +``` |
| 95 | +# this is an official Python runtime, used as the parent image |
| 96 | +FROM python:3.6.4-slim |
| 97 | +
|
| 98 | +# set the working directory in the container to /app |
| 99 | +WORKDIR /app |
| 100 | +
|
| 101 | +# add the current directory to the container as /app |
| 102 | +ADD . /app |
| 103 | +
|
| 104 | +# execute everyone's favorite pip command, pip install -r |
| 105 | +RUN pip install --trusted-host pypi.python.org -r requirements.txt |
| 106 | +
|
| 107 | +# unblock port 80 for the Flask app to run on |
| 108 | +EXPOSE 80 |
| 109 | +
|
| 110 | +# execute the Flask app |
| 111 | +CMD ["python", "app.py"] |
| 112 | +``` |
| 113 | + |
| 114 | +Save the Dockerfile so that we can run our next command with the completed |
| 115 | +contents of the file. On the commandline run: |
| 116 | + |
| 117 | +``` |
| 118 | +docker build -t flaskdock . |
| 119 | +``` |
| 120 | + |
| 121 | +The above `docker build` file uses the `-t` flag to tag the image with |
| 122 | +the name of `flaskdock`. |
| 123 | + |
| 124 | +If the build worked successfully we can see the image in with the |
| 125 | +`docker image ls` command. Give that a try now: |
| 126 | + |
| 127 | +``` |
| 128 | +docker image ls |
| 129 | +``` |
| 130 | + |
| 131 | +We should then see our tag name in the images list: |
| 132 | + |
| 133 | +``` |
| 134 | +REPOSITORY TAG IMAGE ID CREATED SIZE |
| 135 | +flaskdock latest 24045e0464af 2 minutes ago 165MB |
| 136 | +``` |
| 137 | + |
| 138 | +Our image is ready to load up as a container so we can write a quick |
| 139 | +Flask app that we will use to test our environment by running it within |
| 140 | +the container. |
| 141 | + |
| 142 | + |
| 143 | +## Coding A Simple Flask app |
| 144 | +Time to put together a super simple "Hello, World!" Flask web app to test |
| 145 | +running Python code within our Docker container. Within the current |
| 146 | +project directory, create a file named `app.py` with the following contents: |
| 147 | + |
| 148 | +```python |
| 149 | +from flask import Flask, Response |
| 150 | + |
| 151 | + |
| 152 | +app = Flask(__name__) |
| 153 | + |
| 154 | + |
| 155 | +@app.route("/") |
| 156 | +def hello(): |
| 157 | + return Response("Hi from your Flask app running in your Docker container!") |
| 158 | + |
| 159 | + |
| 160 | +if __name__ == "__main__": |
| 161 | + app.run("0.0.0.0", port=80, debug=True) |
| 162 | +``` |
| 163 | + |
| 164 | +The above 7 lines of code (not counting blank PEP8-compliant lines) in |
| 165 | +[app.py](https://github.com/fullstackpython/blog-code-examples/blob/master/docker-flask-mac/app.py) |
| 166 | +allow our application to return a simple message when run with the |
| 167 | +Flask development server. |
| 168 | + |
| 169 | +We need just one more file to specify our `Flask` dependency. Create |
| 170 | +a `requirements.txt` file within the same directory as `app.py`: |
| 171 | + |
| 172 | +``` |
| 173 | +flask==1.0.2 |
| 174 | +``` |
| 175 | + |
| 176 | +Make sure both the `app.py` and `requirements.txt` file are saved then |
| 177 | +we can give the code a try. |
| 178 | + |
| 179 | + |
| 180 | +## Running the Container |
| 181 | +Now that we have our image in hand along with the Python code in a file |
| 182 | +we can run the image as a container with the `docker run` command. Execute |
| 183 | +the following command, making sure to replace the absolute path for the |
| 184 | +volume to your own directory. |
| 185 | + |
| 186 | +``` |
| 187 | +docker run -p 5000:80 --volume=/Users/matt/devel/py/flaskdocker:/app flaskdock |
| 188 | +``` |
| 189 | + |
| 190 | +If you receive the error |
| 191 | +`python: can't open file 'app.py': [Errno 2] No such file or directory` then |
| 192 | +you likely forgot to chance `/Users/matt/devel/py/flaskdocker` to the |
| 193 | +directory where your project files, especially `app.py`, are located. |
| 194 | + |
| 195 | + |
| 196 | +<img src="/img/180309-flask-docker/flask-app-response.png" width="100%" |
| 197 | + class="shot rnd" alt="Flask app responding to requests from within a Docker container."> |
| 198 | + |
| 199 | +Everything worked when you see a simple text-based HTTP response like what |
| 200 | +is shown above in the screenshot of my Chrome browser. |
| 201 | + |
| 202 | + |
| 203 | +## What's Next? |
| 204 | +We just installed Docker and configured a Flask application to run inside a |
| 205 | +container. That is just the beginning of how you can integrate Docker into |
| 206 | +your workflow. I strongly recommend reading the |
| 207 | +[Django with PostgreSQL quickstart](https://docs.docker.com/compose/django/) |
| 208 | +that will introduce you to Docker Swarm as well as the core Docker container |
| 209 | +service. |
| 210 | + |
| 211 | +Next up take a look at the [Docker](/docker.html) and |
| 212 | +[deployment](/deployment.html) pages for more related tutorials. |
| 213 | + |
| 214 | +Questions? Let me know via a GitHub |
| 215 | +[issue ticket on the Full Stack Python repository](https://github.com/mattmakai/fullstackpython.com/issues), |
| 216 | +on Twitter |
| 217 | +[@fullstackpython](https://twitter.com/fullstackpython) |
| 218 | +or [@mattmakai](https://twitter.com/mattmakai). |
| 219 | + |
| 220 | +Do you see a typo, syntax issue or just something that's confusing in this |
| 221 | +blog post? Fork |
| 222 | +[this page's source on GitHub](https://github.com/mattmakai/fullstackpython.com/blob/master/content/posts/180309-flask-docker-macos.markdown) |
| 223 | +and submit a pull request with a fix or |
| 224 | +[file an issue ticket on GitHub](https://github.com/mattmakai/fullstackpython.com/issues). |
0 commit comments