Modern Python Projects Transcripts
Chapter: Deployment
Lecture: Let's write a Dockerfile

Login or purchase this course to watch this video and the rest of the course contents.
0:00 Docker uses a configuration file called Docker File.
0:04 Inside of it, you have to define all the steps to create your image.
0:08 So let's create this file and let me copy paste some code,
0:15 Let's see what we have here.
0:17 First, we have to define what image we want to start with.
0:21 You could start with a completely empty image and then install everything yourself.
0:25 But that's too complicated. On the other hand,
0:27 since we are using fast API,
0:30 you could search for an image that is more appropriate to fast API.
0:34 If you go to the documentation,
0:35 you will see a section deploy of Docker and here you can see that there is
0:39 an oficial image that will include Uvicorn-
0:43 gunicorn-fastapi,
0:45 which is pretty much what we want to have.
0:47 But maybe you're not using fast API
0:51 So instead I want to show you how to start with,
0:53 like a generic basic image. That's why I decided to use a python image.
0:59 It's built on top of the DB ambassador,
1:02 and it has the python installed inside, in general when you're building a python project using
1:08 the oficial python image is a good idea.
1:11 So first we define the image we want to start with.
1:14 Then we copy just the requirements files inside of it.
1:18 That's because we want to leverage docker caching.
1:21 Each instruction that you define here creates an intermediate container,
1:25 and if nothing changes, then this container is being reused by Docker caching.
1:31 So if the requirements.txt file remains unchanged,
1:36 Docker is going to. Reuse the cache container that contains all the installed packages.
1:42 Installing python dependencies will usually take a couple of seconds,
1:45 or maybe even a couple of minutes,
1:47 so it's a really good idea to leverage cache in here.
1:50 Next to create a new user called app.
1:52 This step is completely optional, but it's a good practice from the security point of
1:57 view, by default. If you don't define a different user,
2:01 Docker will run your container as the root user.
2:04 If by any chance your container gets hacked and,
2:07 someone can ssh to it. If they have the root user,
2:11 they will also be able to compromise other containers in the same network and in general
2:16 do bad things. If you are the new user and you run docker containers
2:22 This user, you really limit what potential hacker can do with your Docker container
2:26 So once we have this appuser,
2:29 we tell Docker that now the working directory is the home directory of this appuser,
2:35 That way, when we copy something,
2:37 we don't have to add the full path,
2:39 /home/app /whatever.
2:42 And then finally, we tell Docker to use this app user from now on.
2:47 So when we run the entry point command at the end,
2:49 we will be doing this with the APP user.
2:52 Next we expose port 80. This step is actually optional because we'll have to anyway
2:57 expose some ports when we run Docer,
3:00 run Command. But it's a good idea to list which ports your Docker image is
3:06 going to expose. So people who will be using this image can immediately see that
3:10 And then finally, we copy the rest of the code inside the container.
3:14 At this point, usually the caching will stop working.
3:17 So whenever you change, something in one of the files, inside this chapter and you run
3:24 Docker build again, we will use the cache containers all the way up to the
3:28 step and then from now on Docker will be rebuilding the containers again.
3:34 And the final instruction in our Docker file is the entry point where we specified that
3:40 we want to run the gunicorn Command with three workers.
3:44 We want to use the Uvicorn worker type.
3:47 We want to bind the 000 ip with the Port 80 and then we want
3:52 to run the main.py file.
3:54 With the app function from it, in the next lesson will build this image.