#100DaysOfWeb in Python Transcripts
Chapter: Days 97-100: Docker and Docker Compose
Lecture: Docker image for our Python services
0:00 It's time to move over and get our Python-backed services running in another container. Now, you know what? It's going to be a lot like this one.
0:10 Same, this is all the same. We're not going to use Nginx, so we're not doing that little bit. But from here on is going to be the same.
0:21 Let me duplicate that for a minute and then we'll go back and fix this to make it a little bit better. So we'll create a Dockerfile here
0:29 and we can go ahead and add those little utilities I like. Like I said, if you want, take 'em out, it's no problem.
0:34 But we're not doing any of that stuff. What we're going to do is we're going to copy a movie_svc like so to /app. That should be good.
0:44 I'm going to also go and create a virtual environment. Do you have to do this in a Docker container?
0:50 No. It's kind of completely dedicated to just this app. But for example, like, this uses Python also is going to mess with the global environment.
1:00 So what I'd like to do is have something a little bit more isolated. So I'm going to come over here and I'm going to try
1:07 to put my copy as late as possible 'cause those files are going to change as I work on my app. All this other stuff can cache much, much more often.
1:15 So what we're going to do is we're going to create a virtual environment. Now, we're also going to need a few other things up here at the beginning.
1:23 We're going to need some Python tools like we need Python-pip and Python-dev and build-essentials, so we're going to add that in here.
1:31 And then we're going to run a command which is going to be Python -m venv /venv. So it's going to create a virtual environment
1:43 right in the root of our system. Now remember, when you create virtual environments they get out of date immediately, right?
1:52 They for some reason come with an out-of-date pip. Like, this step doesn't bother to upgrade it even if it's somewhere else on the system.
2:00 So the next thing we want to do is we're going to make sure our virtual environment has the latest pip. So we'll just say this in /venv
2:07 normally you would say source or we need to run the full path and that works out better for Docker. So /venv/bin/pip install -U pip setuptools
2:22 Let's go and see how this runs. So we're over here in our services and we're going to run Docker build this directory
2:33 see what we get. See how a bunch of this was already cached? Great, here's our Python-dev and pip and all that that we're installing on the system.
2:52 Oh, I forgot, we're going to need do Python3, okay? So we need to make sure that we have this installed but Python, I guess, means Python 2.
3:03 Try again. There we go, that's much better. That's cool, we're only 10 versions out of date on pip. But not anymore, okay.
3:18 So our virtual environment is all set up. What else do we have to do in order to run our app? Well, what did I do when I ran it over here?
3:25 I went it down here and I said pip install -r requirements da-da-da, right? Same thing on a server. So we're going to go here after we do this.
3:33 We're going to run, well, let me put it down here and then I'll do another little example. So we're going to run that, and where's their requirements?
3:48 It's going to be /app/, so we have a movie service and that's just going to be right there. So requirements.txt.
3:58 That should be good, let's give it another try. Here go our requirements. It looks like it found the file.
4:09 Okay, super, that's all set up and it looks like we have our app running. I guess we could go and log in and just see if we can get it to work.
4:18 So let's go over here and say I'm going to do the -t. Remember before, we said that. We're going to do services like so. I'm going to build it.
4:29 I'm going to give it a name, knowing say docker run. For now we'll do -it. Services latest and bash.
4:39 Great, so what is the command we would like to run? We would like to run venv/bin/Python and we're going to run /app/app.py.
4:51 Now, this in some situations may work. It's not going to work now 'cause we need to change something really minor about how everything works.
5:01 Let's see what happens. Oh, it runs here but you'll see it won't run, oh, later. So it looks like everything's listening on our port.
5:10 And I'll show you one more tweak we got to make. You want to say docker run. So we could try to do this and see what we get.
5:22 And it's off and running. How 'about that? Okay, well, if it's happy, I'm happy. Let's see what we get if we go to this.
5:27 Well, can we go to that port? No. Because, of course, we haven't opened the port. So when I come over here, say -p 7007 goes to and from port 7007.
5:42 Let's try it one more time. It's running. Let's see what happens if we go to this URL. It was reset. Now, I want to show you this error.
5:56 I left this in on purpose. It's a little annoying but debugging these things is very challenging. So let's go back here to.
6:06 Well, it looks like it works. It says it's serving, right? Let's go back here and run this. And then we'll run our command that we ask it to run.
6:16 And I'll put an & on the back so that we can still interact with it. And we could do, hit local host on port 7000 and it's not working.
6:27 So here's the error that I was actually expecting us to get earlier. But notice it's not even listed. This is not a server 500.
6:33 This is no connection. What's going on? Let's look a little more carefully up here. When we look at the message, it's running on local host.
6:47 That maybe usually sounds like, oh, it just it's running here, it's fine. But that means it's only listening on the local loop back.
6:56 In order for us to get Responder to actually work we have to come over here and say an address equals, by the way, just pet peeve
7:08 of mine, what you type in there I have no idea. How do I know it's address? I had to go dig through the source code
7:15 several layers down to find out the keyword argument is address. It never has to be this way. You can always use default values
7:23 in keyword arguments, but they're explicit. Anyway, let me type address. It's going to be the string, either a full address or everything.
7:32 So now, notice our application has changed. Our Docker file has not changed. But we need to get a new Docker container
7:41 based on our new code. How do we do that? We're going to build like this. And you'll notice those files have changed.
7:50 And notice it copies those over and then it reruns the installer for the requirements. So one little trick that we can do is we know
8:01 that we're based on Responder. There may be other things that we're also based on but Responder is a pretty good bet.
8:08 You know, like, if you're doing Flask you can just say Flask. If you're doing Django, Django, whatever. So we can just say Responder right here
8:15 and then we can rerun the rest of the requirements 'cause most of the stuff that's slow comes from Responder. Why is this valuable?
8:22 This output, this calculation, this work, will be cached. So if we make little minor changes to our code we won't have to redo this every time.
8:35 So let's do that again. One more time, Docker build, just going to go through installing it one more time because we're now doing that new layer.
8:49 Of course that takes a while. But let's see what happens if we change our code again. So suppose I make a super important change
8:57 like that and we re-run our build. Watch this, done. Yep, everything's all finished. So this is a nice way to let your rebuild
9:06 happen much more quickly. It's your call whether or not you want to kind of hack it a little bit like that
9:10 but I like to do this. I think it's running now. Let's try this again. There we go. We're going to run it, we're going to expose that port.
9:20 It's running, and now notice, listening in on 0000. Now there's a server error, okay? That's progress. It doesn't sound like progress, but it is.
9:32 And what is the server error? It's that it can't find the template file that it's trying to work with 'cause its working directory is broken.
9:38 So we have one final change that we need to make over here. Let's go over here and we're going to I guess I'll do it after. Sure, we'll do it after.
9:49 We can say working dir is /app. So when our subsequent commands run either here or these ones here like this command right there
10:03 that's running, when that runs it'll be running from the perspective of that working directory. In fact, we could even write it like this if we want.
10:12 So let's do a Docker build one more time. Now we have our working directory applied. Let's try this one more time.
10:23 Server error, is it going to go away? Course it does, course it does because it's beautiful. So here we have our full Python app running right here.
10:32 If we go back we can get movies by IMDB number we can get the genres, and so on. So we have the movie service working
10:40 and if we were to re-run the container we would also have this working. Notice it's now going to talk to our local
10:48 notice MCL right here, little API calls. Okay, great, so it looks like we have our Python app running as well.