Skip to content

Commit d79cafa

Browse files
committed
✨ (Section 4) Add short hands-on section on running Flask on Docker
1 parent 8a6ccc8 commit d79cafa

File tree

11 files changed

+485
-2
lines changed

11 files changed

+485
-2
lines changed

docs/docs-upcoming/04_docker_intro/01_project_overview/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/docs-upcoming/04_docker_intro/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# What is a Docker container?
2+
3+
I'm sure you have heard of the term "Virtual Machine". A Virtual Machine is an emulation of an Operating System.
4+
5+
This means that you can run a Windows Virtual Machine on a computer running Mac OS. When you do that, you can have the Windows Operating System running inside an app in your Mac.
6+
7+
When you run a Virtual Machine, you can configure what hardware it has access to (e.g. 50% of the host's RAM, 2 CPU cores, etc).
8+
9+
Docker containers are a bit different because they don't emulate an Operating System. They use the Operating System kernel of your computer, and run as a process within the host.
10+
11+
Containers have their own storage and networking, but because they don't have to emulate the operating system and everything that entails, they are much more lightweight and efficient. Another benefit of containers is that their start-up time is very fast.
12+
13+
Naturally, there's pros and cons to both. For example, you can't run a Windows Docker container if you are using Mac OS in your machine. You'd have to run a Windows Virtual Machine, and then run Docker containers in that, which isn't very efficient!
14+
15+
:::caution
16+
Because Docker containers use your OS kernel, you can run Linux images in a Mac OS container.
17+
18+
However, new Mac computers use a different CPU architecture (ARM), and this can pose problems in some cases. More on this later on!
19+
:::
20+
21+
## What does a Docker container run?
22+
23+
If you want to run your Flask app in a Docker container, you need to get (or create) a Docker image that has all the dependencies your Flask app uses:
24+
25+
- Python
26+
- Dependencies from `requirements.txt`
27+
- Possibly nginx or gunicorn (more on this when we talk about deployment)
28+
29+
Let's take a look at Docker images in the next lecture.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# What is a Docker image?
2+
3+
A Docker image is a snapshot of source code, libraries, dependencies, tools, and everything else (except the Operating System kernel!) that a container needs to run.
4+
5+
There are many pre-built images that you can use. For example, some come with Ubuntu (a Linux distribution). Others come with Ubuntu and Python already installed. You can also make your own images that already have Flask installed (as well as other dependencies your app needs).
6+
7+
Creating a Docker image is straightforward (when you know how!). I'll guide you through how to do this in the next lecture, but bear with me for a second:
8+
9+
```dockerfile
10+
FROM python:3.10
11+
WORKDIR /app
12+
COPY ./requirements.txt requirements.txt
13+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
14+
COPY . .
15+
CMD ["gunicorn", "--bind", "0.0.0.0:80", "main:app"]
16+
```
17+
18+
This is a `Dockerfile`, a definition of how to create a Docker image. Once you have this file, you can ask Docker to create the Docker image. Then, after creating the Docker image, you can ask Docker to run it as a container.
19+
20+
In this `Dockerfile` you can see the first line: `FROM python:3.10`. This tells Docker to first download the `python:3.10` image (an image someone else already created), and once that image is created, run the following commands.
21+
22+
The following commands are specific to our use case, and do things like install requirements, copy our source code into the image, and tell Docker what command to run when we start a container from this image.
23+
24+
This separation between images and containers is interesting because once the image is created you can ship it across the internet and:
25+
26+
- Share it with other developers.
27+
- Deploy it to servers.
28+
29+
Plus once you've downloaded the image (which can take a while), starting a container from it is almost instant since there's very little work to do.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# How to run a Docker container
2+
3+
## Install Docker Desktop
4+
5+
Docker Desktop is an application to help you manage your images and containers. Download it and install it here: [https://www.docker.com/products/docker-desktop/](https://www.docker.com/products/docker-desktop/).
6+
7+
## Create your Docker image
8+
9+
Next, download the REST API code from Section 3. You can download it here: LINK.
10+
11+
If you want to use the code you wrote while following the videos, that's fine! Just make sure it works by running the Flask app locally and testing it with Insomnia REST Client or Postman.
12+
13+
### Write the `Dockerfile`
14+
15+
In your project folder (i.e. the same folder as `app.py`), we're going to write the Dockerfile.
16+
17+
To do this, make a file called `Dockerfile`.
18+
19+
:::caution
20+
Make sure the file is called `Dockerfile`, and not `Dockerfile.txt` or anything like that!
21+
:::
22+
23+
Inside the `Dockerfile` we're going to write this:
24+
25+
```dockerfile
26+
FROM python:3.10
27+
WORKDIR /app
28+
RUN pip install flask
29+
COPY . .
30+
CMD ["flask", "run", "--host", "0.0.0.0"]
31+
```
32+
33+
Here's a quick breakdown of what each line does:
34+
35+
1. `FROM python:3.10` uses the `python:3.10` image as a base.
36+
2. `WORKDIR /app` does it so everything we do in the Docker image will happen in the image's `/app` directory.
37+
3. `RUN pip install flask` runs a command in the image. Here the command is `pip install flask`, which is what we need to run our app.
38+
4. `COPY . .` is a bit cryptic! It copies everything in the current folder (so `app.py`) into the image's current folder (so `/app`).
39+
5. `CMD ["flask", "run", "--host", "0.0.0.0"]` tells the image what command to run when you start a container. Here the command is `flask run --host=0.0.0.0`.
40+
41+
:::tip
42+
We need `--host=0.0.0.0` to make Docker be able to do port forwarding, as otherwise the Flask app will only be accessible within the container, but not outside the container.
43+
:::
44+
45+
Now we need to create the Docker image.
46+
47+
We do this with the `docker build` command in the terminal.
48+
49+
:::caution
50+
Make sure to restart your terminal after installing Docker Desktop, so that you have access to the `docker` program in your terminal.
51+
:::
52+
53+
Open a terminal (in VSCode that's CMD+J or CTRL+J), and run this command:
54+
55+
```
56+
docker build -t rest-apis-flask-python .
57+
```
58+
59+
The `-t rest-apis-flask-python` flag is optional, but tags the image, giving it a name. It can be handy for later! The final `.` at the end of the command is not a mistake; it tells the command _what_ to build. The `.` means "the current directory".
60+
61+
This command can take a while to run as it needs to download the `python:3.10` image first. You should see quite a lot of output while the command runs.
62+
63+
When the command is finished, you should see this (among other things):
64+
65+
```
66+
=> [2/4] WORKDIR /app 0.4s
67+
=> [3/4] RUN pip install flask 2.9s
68+
=> [4/4] COPY . . 0.0s
69+
=> exporting to image 0.1s
70+
=> => exporting layers 0.1s
71+
=> => writing image sha256:d9a68a03f868e74bca48567dfc9a0b702d1618941a71b77de12ff14e908ba155 0.0s
72+
=> => naming to docker.io/library/rest-apis-first-rest-api 0.0s
73+
```
74+
75+
And now your image is built! You should be able to see it in the "Images" section of your Docker Desktop app.
76+
77+
## Run the Docker container
78+
79+
When we start a Docker container from this image, it will run the `flask run` command. Remember that by default, `flask run` starts a Flask app using port 5000.
80+
81+
But the container's ports are not accessible from outside the container by default. We need to tell Docker that when we access a certain port in our computer, those requests and responses should be forwarded to a certain port in our container.
82+
83+
So we'll run the container, but we must remember to a port (e.g. 5000) in our computer to port 5000 in the container
84+
85+
To do so, run this command:
86+
87+
```
88+
docker run -d -p 5000:5000 rest-apis-flask-python
89+
```
90+
91+
We're passing a few things to `docker run`:
92+
93+
1. `-d` runs the container in the background, so that you can close the terminal and the container keeps running.
94+
2. `-p 5000:5000` maps port 5000 in your computer to port 5000 in the container.
95+
3. `rest-apis-flask-python` is the image tag that you want to run.
96+
97+
You should see something like this as your output:
98+
99+
```
100+
9f3c564ac64a1723069dda0e80becb70d3697d4bfcbcb626cd5add0c65df173f
101+
```
102+
103+
That's the ID of the container. If you're not using Docker Desktop, you need this ID in order to stop the container later (with `docker rm 9f3c564`, that's the first few characters of the ID).
104+
105+
And now, if everything has worked, you should be able to access the Flask app _just as if it was running without Docker_!
106+
107+
:::caution Did something not work?
108+
A common error can happen when the port that you tried to forward isn't available (e.g. because something else is already running):
109+
110+
```
111+
docker: Error response from daemon: driver failed programming external connectivity on endpoint bold_goldwasser (ff58b1755c1d1d0fd6b1dd4f59ab3b903b0e68f320624c4a2495672a735039d5): Bind for 0.0.0.0:5000 failed: port is already allocated.
112+
```
113+
114+
You have two options: either figure out what is running on port 5000 and shut it down before trying again, or you can change the port that you want to use in your computer:
115+
116+
```
117+
docker run -dp 5001:5000 rest-apis-flask-python
118+
```
119+
:::
120+
121+
Try making requests using the URL `127.0.0.1:5000` with Insomnia REST Client or Postman, and you should see it working well!
122+
123+
![Insomnia REST Client successfully made a request to the API running in Docker](assets/running-app-docker.png)
2.01 MB
Loading

0 commit comments

Comments
 (0)