March 18th, 2024 × #Docker#DevOps#Web Development
Docker For Developers
An overview of Docker geared towards web developers - what it is, why its useful, how to get started, core concepts, tools, and some pitfalls.
- Docker provides reproducible environments to eliminate "it works on my machine" excuses
- Docker uses OS-level virtualization which is more performant than full virtualization
- Docker helps setup complex architectures like databases without manual install/config
- Start learning Docker by downloading Docker Desktop and going through the official docs and tutorials
- Docker images are base environments ready-to-use for technologies like MySQL, Node, etc
- Dockerfiles define steps to build a Docker image for your own apps and services
- Dockerfiles use simple commands and are easy to create for basic apps
- Images become containers at runtime when you docker run an image
- Use Docker build, run commands to build images and launch containers from CLI
- Docker Compose configures/launches multi-service architectures
- Docker needs lots of compute resources as each service uses resources
Transcript
Scott Tolinski
Welcome to Syntax.
Scott Tolinski
On this Monday, hasty treat. We're gonna be talking about Docker.
Scott Tolinski
I, myself, Scott Tolinski, I don't know that much about Docker. I use it whenever I need to toss something up on my NAS or host something, but I don't work in Node very often.
Scott Tolinski
And when CJ submitted a poll request to the syntax repo to add, Docker support to our repo, I thought to myself, I need to ask CJ a lot of questions about Docker. So that's really what this episode is going to be. I have a whole lot of questions in general, and the concept is going to be from just an average web developer's perspective.
Scott Tolinski
What this stuff JS, why you might use it, why you might want it in your code base, and just a little bit about understanding about Docker if you've never used it before. Again, my name is Scott Tolinski. Wes Bos is out today. So we have sorry. We have my dog barking, but we also have CJ. CJ, how's it going? It's going good. Happy to be on the pod. This is exciting. Yeah.
Scott Tolinski
Yeah. I'm gonna apologize. Right now, my dog in fact, I'm she might make an appearance because the garbage truck's coming by, and I need to give her a hug.
Scott Tolinski
Yeah. She she does well with hugs, but she doesn't do well with garbage trucks.
Scott Tolinski
Speaking of garbage, sometimes your code is garbage, and that's why you need Sentry in your code base. So head on over to century Scott I o, and you can make your code less garbage. For instance, you can, instantly see, like, I'm talking right in a big old table after you add this thing, exactly what's going wrong with your code Bos, how many bugs your code base has. But, like, the big thing for me was, like, performance. I was seeing which pages gave our users the most misery, which was they call it a a user misery Scott. And it's like, alright. This page is being hit by a lot of people, and it's the slowest. Therefore, the misery score is higher. If this page JS, you know, it's a little slow, but not that many people are are hitting it, it prioritizes a little bit lower for you. So that way you're getting the biggest impact.
Scott Tolinski
The 80/20. Right? You're you're able to solve the biggest performance bottlenecks in your application that people are actually hitting. There's there's a 1000000000 features in Sanity. So check it out at century.ioforward/syntax.
Scott Tolinski
Sign up and get 2 months for free. Alright. CJ, first question for you. What is Docker?
Docker provides reproducible environments to eliminate "it works on my machine" excuses
Guest 1
Sure.
Guest 1
So I like to describe it as easily reproducible environments.
Guest 1
And I think someone had the tagline, but it it was something like, like, it works on my machine is no longer an excuse. So the idea that you can you can bundle up some collection of configuration and use it in multiple places, whether it's local, like, in just other developers on your team's environment, or whether it's in production.
Guest 1
And so that's one of, like, the major benefits is you can kind of, like, craft this little environment, and it'll work locally, but then you can use that exact same environment when you're working, like, on your staging server Vercel in production or whatever else. And Docker actually is containerization technology, so it is not a virtual machine.
Guest 1
So virtual machines actually emulate entire bits of hardware. So if you've ever used a hypervisor, like, VMware or, VirtualBox, For any operating system or any machine that you create, it is literally emulating the hard drive, the disk drive, the CPU, the GPU. It's creating virtual versions of all of those, and that is one way of kind of, like, creating a reproducible environment, but there is a lot more overhead because it's having to emulate everything.
Guest 1
But Docker is a containerization technology, so it's also known as operating system level virtualization.
Docker uses OS-level virtualization which is more performant than full virtualization
Guest 1
So instead of having to virtualize and and emulate all of the attached hardware and everything else, every virtualized container actually shares the base operating system kernel, and, it can essentially be a bit more performant and not have to use as much resources because it's not having to emulate and virtualize all of the associated hardware as well.
Scott Tolinski
Nice.
Scott Tolinski
So ESLint interesting that you you get that that point that it's not a virtual machine because Yeah. When I think about Docker, the first thing that comes to my mind is it's a virtual machine. But, apparently, it's Scott. So
Guest 1
Yeah. That's great to know. I would say it's a it's a little white lie. So, like, depending on where you're running it, might not be completely right on this. But because let's say you're running Docker on macOS, if it needs to virtualize, like, a ESLint Linux operating system that needs the Linux kernel, it's possible that Docker Desktop, like, on Mac, actually does spin up a tiny VM.
Guest 1
And then especially, like, on Windows, it does. But if you're in a pure Linux environment, there there are no virtual machines at
Scott Tolinski
all. So it's not inherently
Guest 1
a virtual machine. Yeah. Right. That's cool. Yeah. Cool. Wes Node one thing I will add, just because I know there's a lot of people out there, like, well, you're talking about Docker. You should talk about other things too. So because this is, like, a general idea of containerizations or containerization, there are alternatives. So Docker is kind of just like brand brand name containers, but there's also things like Podman, containerd, builda, LXD.
Guest 1
I haven't used any of these, but I think these things are starting to pop up because people do want alternatives to Docker as well. So I think it's worth mentioning that all of this containerization stuff that we talk about is applicable to other things, not necessarily just Docker and Docker Desktop. Yeah. And Podman has a cool name and a
Scott Tolinski
cute little, like, Doug Trio seal logo. Gotta love that. Yeah. Maybe I'm gonna go Podman just for the logo and vibe.
Scott Tolinski
Okay. So as a developer, right, we're building websites.
Scott Tolinski
And I I know you said, like, it works on my machine isn't a thing. But, like, why would somebody building websites, like, pick Docker to use as opposed to just YOLO ing it on their machine?
Docker helps setup complex architectures like databases without manual install/config
Guest 1
For sure.
Guest 1
For me, I think, like, one of the easiest ways to get started with Docker is not necessarily even containerizing your apps, but just using, like, databases that are in a container. Because if you're building a full stack web app, it typically talks to a database of some kind. And so you can take these pieces of your architecture and kind of, like, operationalize them. So let's say you have a MySQL database, like in the in the case of the Syntax website. That's basically what I did in my pull request. I didn't containerize the SvelteKit app. I just made a little Docker Compose file that says you should spin up a MySQL database, and it should use these environment variables, So that way, it's kind of in sync with the SvelteKit app that's running on the machine.
Guest 1
So before that, the the the documentation that Scott had wrote was basically, like, you should have MySQL running on your machine. Yeah.
Guest 1
And for for some people, that's that's hard to do. Like, I mean, you have to figure out, well, how do you install it and how do you configure it. The nice thing about this Docker Compose file that I added is you literally just say Docker Compose up. That spins up the MySQL database, and you're good to go. Regardless of what operating system you're on or whatever else, you don't have to go through all of those steps to kind of, like, set it up. And so for me, that's kind of, like, the biggest selling point is you have new developers on your team, or you're working on an open source project that other people wanna be able to contribute to. It's so much easier to contribute if you can literally just, like, run run 1 command from the CLI and your entire environment is up and going, versus, like, following a readme of install this, now install this, and configure that. So that's, basically, one of the main benefits here is it's reproducible, and you can use it for a lot of different things, and especially if you have a more complex architecture. So let's say you don't just have a a full stack app and a a database. Let's say you also had, like, a separate front end, a separate back end, a SQL database, a Redis database.
Guest 1
You have the ability to containerize each of those things and then use something like Docker Compose to, like, kinda make them all talk together. And so, yeah, I think that's mainly it. It's, like, it's easier to work with others, and then it's also kind of like it operationalizes the things that are you're manually doing every time you have to start up a specific project.
Scott Tolinski
That actually makes a lot of sense, especially you know, I think the thing that I like the most there is that you directly tied it back to a deficiency in our onboarding process.
Scott Tolinski
Which when I was tasked with making the onboarding process smoother, there were like a number of things. I was like, I don't know. You know, I I, you know, there are challenges that I haven't necessarily had to face with not working with remote code, remote database, even though, like, the level of tutorials code Bos. We always had just we were working on a remote database a 100% of the time, even if it was staging, just because it was easy.
Scott Tolinski
Yeah. But having that that ability makes a ton of sense.
Scott Tolinski
How do you get started learning Docker and applying it to your your work?
Guest 1
Definitely. So, first of all, download Docker Desktop.
Start learning Docker by downloading Docker Desktop and going through the official docs and tutorials
Guest 1
And once you install it, they'll actually have a command you can run for, like, a little hello, world. But my main advice is start with the docs. Like, their docs are immense. Like, everything you could ever wanna do is is really well documented, And they also have an official tutorial. So there's the Deno Docker Node zero one tutorial, and that will walk you through creating containers and just the whole process of, like, using the Docker CLI and Docker Desktop. So, yeah, I highly recommend the official documentation.
Guest 1
And in terms of getting started, I would just, like, you know, learn the basics, and then try to containerize something. So if you have, like, a a Node. Js and Express app, figure out how to turn it into a container.
Guest 1
Basically, like, use some of your existing apps so you're kind of familiar with the process, and then start diving into trying to set it up and get it going with Docker. Yeah. Okay.
Scott Tolinski
So can you maybe, like, tell me a little bit about how does it all work necessarily? Like, you often hear things like there's Docker files. Right? We have containers, which we talked about. Images. Like, what is all this stuff? Sure. So I'll do my best to to describe all this, but we're gonna start at images.
Guest 1
Because that's that's kind of, like, your 1st entry point into it, especially, like, if you spin up a database with Docker, you're pulling, potentially, from an image that has already been created before. So images can be hosted in various places. So Docker Hub is the main one if you're in, like, the Docker ecosystem, but people have and frameworks and tools have created base images that are ready to go. So you can find an official MySQL image. You can find an official Node. Js image or Postgres image or Redis image or PHP image or Laravel. Literally, pick a tech and someone has created a base image. And very often it's, like, the official one from the from, actually, like, the core team and the creator of that tech. And so that base image has an environment ready to go with that specific tech. And so, it's it's all based on Linux. So it's like a base Linux operating system.
Docker images are base environments ready-to-use for technologies like MySQL, Node, etc
Guest 1
But then anything that is required for that thing to run, so, like, various dependencies or whatever else, has already all been installed, and it's kinda just ready to go. So you can pull from those those images and just get them up and going. Like, you actually don't have to write even your own Dockerfile. You can literally, just with a single command line, just pull pull an image and start running it on your computer. So images are kind of like the base of everything, and, Docker Hub is just one place to get images. Like, there is actually this registry specification, so there's a lot of different places that can host images as well.
Guest 1
So you can actually host images on GitHub, and even if you have, like, private repos so this is what some companies will do is, like, if they already are on, like, the GitHub pro plan, you can actually publish your own images to your Git repos as private. So, like, if you have a specific setup that you wanna use in your apps at your company, but you don't wanna share it with the world, you can push that to the the GitHub registry. GitLab also has this. There's a thing called JFrog Artifactory. So this idea of, like, hosting images in places that are that are reusable by others JS, is there, and it's it's not just specific to Docker Hub. Nice. I
Scott Tolinski
I, I feel like I have used Docker Hub on my Synology to grab images for MB or or Jellyfin or those types of things. Right. Believe it or not, there is a Sentry you can self host. I don't know if people know this, but you can self host Sentry. And there is a Sentry from Sentry themselves.
Scott Tolinski
There is a, a an image. I couldn't come up with the word. There's an image there. I got it. Thank you, CJ. I think you're kind of seeing the idea of how this all is put together Node. Because
Guest 1
if this didn't exist and you wanted to get going with Sanity on your local machine, you would literally have to follow the docs. Right? Like, install this dependency, install this, install this. And then, finally, maybe you can get Century running. But Node it's literally just an image you can pull down, and you're you're you're up and going. Cool. So images are the Bos. And, like I said, you kind of feel like your 1st exposure to Docker is maybe pulling from pre created images, but you can also create your your own.
Guest 1
And this is in the form of Dockerfiles. So you start with a Dockerfile that basically describes the environment that you would like to create.
Dockerfiles define steps to build a Docker image for your own apps and services
Guest 1
And this Dockerfile has various layers, and the 1st layer always is a base image. So you're always starting with some base image, and a lot of times you'll start with something known as, like, Alpine Linux. So Alpine Linux is a distribution of Linux that is very minimal. Like, it doesn't have a bunch of extra stuff, so it's, like, super small, so that way your base image can be super small, and and then you can start to install packages and dependencies from that base image.
Guest 1
So, actually, let me pull up an example Dockerfile, and I'm going to describe what's happening in there. In this example Dockerfile that we're looking at, the very first line says from node colon l t s dash alpine. So that's our our base layer. It basically says and and to take a step back, we are describing a Dockerfile that will containerize a Node. Js application. And so at the base layer, there is the Node image. And so they've already done all the the hard work of configuring the Alpine Linux system. They've installed NPM. It's kind of just ready to go, and so that first line gives us a Node. Js system.
Guest 1
The next line installs a tool for running processes in the background. So I have a line here that says run npm install p m two dash g. So this image is going to have p m two, which is a process manager, preinstalled in it so that it can keep track of the Node app that is running.
Guest 1
My next line in there is the working directory, so this is where the code exists. So working directory user source app, that's where the the code will live inside this container.
Guest 1
And then, we copy the package JSON in, do an Npm install, copy the source code in, and then the last line in this file actually says to use p m two runtime to start up that Node. Js application. So this this next idea here is that this 1 file kind of describes the entire all of the steps needed to get a base Node. Js image, to install the dependencies, everything else to kinda just compartmentalize that that process of having a Node. Js application. And so I've described this in a Dockerfile.
Guest 1
What I would do is actually build this Dockerfile into an image. So this Dockerfile then becomes an image, and now that image is is reusable. And a lot of times, you'll actually ship this Dockerfile in your source code. So when other devs come to your code base, they'll actually run a line that builds that image locally using that Dockerfile.
Dockerfiles use simple commands and are easy to create for basic apps
Scott Tolinski
So that file seems pretty easy to reason about to me.
Scott Tolinski
Something the copy stuff is a little weird, you know, the copy package Astra stuff or the copy that that stuff feels like a little weird to me just looking at it. But the rest of it, you can kind of reason about. I'm sure there's, you know, complexity degrees to all this stuff. Do you do you find typically that those are easy to author? Or JS that, like, a big learning curve?
Guest 1
I would say, like, I definitely come from, like, a system administration background. So, like, I've written a lot of Bos scripts and stuff like that. And so from that perspective, like, if you've ever written any kind of Bash script or, like, any kind of, like, run this, then do this, then do this, This is very similar to that, and, their docs kind of describe what all of these things are doing. So, like, copy literally copies files from the directory you're in into the the image that it's building. Yeah. But in my experience, especially for, like, a simple Docker file like this, the the commands are kind of just like run, copy.
Guest 1
That's that's kind of as complex as it gets.
Guest 1
Nice. And then, from there, we have containers. So containers are actually running images.
Guest 1
So we have our Dockerfile.
Images become containers at runtime when you docker run an image
Guest 1
We build that into an image, and then when I actually wanna run this thing, it it is described as a container because it's actually a running a running image. And so the the other way to think about these Dockerfiles is that the layers are, like, cacheable. I I don't wanna get too complex, too quick, but the idea here is that if you if you have a a system that needs to build these Dockerfiles fairly often, you don't wanna have to run the same steps every single time you build that that Docker image.
Guest 1
And so each line in this Dockerfile is actually a cacheable layer. And the 1st time you run it on your machine, it's gonna take a little bit of time.
Guest 1
But the next time you run it, as long as none of the layers above it have changed, it can completely use the cached version of that layer. So, yeah, that that gets into the complexities of it. But for the most part, you got your Dockerfile, describe your your environment, and then what command is needed to actually run that thing.
Scott Tolinski
So if I were to say, like, alright. Add Docker to x, y, and z project.
Scott Tolinski
It's as simple as as writing a Docker file?
Guest 1
Yes. Yeah. And and, I mean, like I said earlier, like, one of the first steps you might try is just bring in a database. And from there, you actually don't even need a Dockerfile. We'll talk about that in a little bit. You can actually just have a Docker Compose file that says, hey. I want a Mongo database or a SQL database. But, yes, if if you have, like, a Node app or a SvelteKit app, and you you wanna turn it into an an image, you're gonna you're gonna author one of these Dockerfiles.
Guest 1
Cool. So, yeah, like like like you said, create the Dockerfile, kinda describe the environment, and then you're you're good to go from there. I I would kinda, like, look at Docker Hub or wherever you're pulling those images from to find what your base image is. In the example of Node, there's, like, the Node LTS Alpine that you typically will pull from. That's the other thing is, in terms of versioning. So LTS is long term support, and so that line describes which image you're pulling from.
Guest 1
You always, always wanna have a version number on there. Like, if you Yeah. If you don't put the version number, it's always gonna grab the latest, and then your images might actually break. Then it might actually turn into a, well, it works on my machine scenario because you didn't lock it down to a specific version. And so I I would also recommend find projects out there that have existing Docker files, Docker Compose files, and learn from them. That's that's basically mostly what I learned from JS I was seeing existing examples of of apps that were using it, and then just kind of, like, started to to piecemeal my own versions of that to get it working with my applications.
Scott Tolinski
Cool. So, like, you have you have the the file. Right? You have either the and and we'll talk a little bit about Docker Compose in a second. But, like, I have this thing in my my repo. How do I say, hey. Go. Hey. Go do the thing.
Scott Tolinski
Sure. So
Use Docker build, run commands to build images and launch containers from CLI
Guest 1
yeah. There's a CLI. So there's a there's a Docker build command. So you'll run Docker build.
Guest 1
I would I would pull up the docs because it's gonna be specific for for, like, every project. But you'll run a Docker build. That will actually create the image, and now that image just lives on your computer.
Guest 1
And then from there, you can do a Docker run, and you specify the name of the image that you just built. And so then it then it'll be up and going. I'm probably gonna get into this a little bit later, like, when we talk about, like, gotchas and stuff like that, but the the idea of, like, containerizing your app, you also have to think about development. Right? So if I'm working in a system where whenever I change the file, I want the server to auto restart or, like, the page to auto refresh.
Guest 1
You have to do some specific things with Docker if you want to get that experience. And so that gets into the idea of, like, volumes and mapping your local computer into the container. And so that is a little bit trickier, and I think it is it is definitely like a a gotcha of a lot of projects. If they just immediately jump into, oh, we're gonna dockerize everything, your your your dev cycles can can start to get much slower because now the the all your files are living in the container, and then so, like, you save them locally, they go to the container, and then there's, like, a round trip. And so, like, your your hot reload and your refresh is a lot slower than it used to be. So if you're going to add this to your project, start with databases, then try to kind of, like, add a volume, get this Hot Hot Reload working.
Guest 1
But if it slows things down, don't use Docker for that part of your app. That's that's my advice there, because too many people just try to go fully gung ho on Docker, and then, like, then your dev experience starts to tank from there. So yeah. And then you never touch it again because you're Exactly. Yeah. And I think that's what has scared a lot of people away from Docker potentially. But yeah. Yeah. What scared me away well, not scared me because I use it to host stuff. But, like, I was running a code server on my
Scott Tolinski
hosting setup, and I was running a code Vercel.
Scott Tolinski
And all I wanted to do JS be like, the code server was saying, you need to find config. Yml to get the password for Node server so that you can sign in. And then so I'm I'm I've ESLint my machine, and I'm like, Wes the hell is this container and where is this config file? Like, Wes? Like, what I had to do is I think I had to then SSH into the container itself. I don't even know what I did. But I I ended up getting into the container environment, and it was in the user directory of the container itself. So that stuff is tough to reason about when you're when you're trying to figure it out.
Guest 1
Yeah. Yeah. And I guess what I would add to that is, typically, you do you would do like a Docker exec, and so you're executing a command inside the the container. And so that's what allows you to get into the container. So if you do a Docker exec of, like, bash, now you have a bash shell, but it's technically running inside the container. That's what I did. Yeah. So a lot of times, you you might need to do that to get in there and configure things, but I I don't really think I even touched on this.
Guest 1
The Docker containers Yarn, ephemeral. So, like, the idea is if you you spin it up Wes when you spin it down, if you haven't mounted any volumes, all of those changes are lost. And that's kind of a good thing because it's like that forces you to make things reproducible in your config.
Guest 1
But you do have to remember that. Like, if you get in there and and and, like, do things via, like, bash and change some stuff around, the moment that container goes down, you're gonna lose those changes.
Guest 1
So you mentioned Docker Compose a little bit ago. What does that how does that relate to everything that we're talking about, and what is that? Yeah. And so, yeah, I touched on it a little bit, but the whole idea is to kind of orchestrate a complex architecture. So an example app I have has a Redis database, a Postgres database, a Svelte front end, and, like, a an API back end. And I want all of those things to be running at the same time, and all of them are pulling from from different base images.
Guest 1
And Docker Compose allows you to kind of, like, orchestrate that stuff locally. So you have a Docker Compose file that describes each of your services. So you would have, like, a DB service that's pulls in your specific base image, defines all of your environment variables, decides which ports to expose, and then you can also have another service in there for your back end application, potentially one for your front end application. And so this is a configuration file that kind of describes all of those services. And then with a single command, you can spin them all up and then bring them all back down. That's awesome. Okay. That that to me is a very good selling point. Yeah.
Docker Compose configures/launches multi-service architectures
Scott Tolinski
Especially given that I'm working with so many of these technologies, as you have mentioned, in that the kind of do it yourself every step of the way kind of way. And it does feel like kind of a a PIA a lot of times.
Scott Tolinski
So you you mentioned some gotchas.
Scott Tolinski
I wanna hear about the gotchas.
Guest 1
For sure. And I'll I'll make these quick. But I think the the main thing is you you do need a lot of CPU and RAM. Like, if you're running all of these services locally, you gotta make sure you have plenty of resources.
Guest 1
I mentioned earlier that idea of, like, live reload and auto refresh. It's it's it's gonna slow things down. It absolutely will. So take that into account and decide whether or not you actually want to containerize that part of your app. And then the other thing is potentially conflicting services. So if you have MySQL installed locally and you try to spin up a MySQL container, you're gonna have to make sure that you expose a different port than the port that's actually running on your machine, And then just in general disk space. So, like, as you start pulling these images, your your hard drive is gonna start to fill up as well. Yeah. Because you need to pull a lot in when you pull in the images. What was I trying to do?
Docker needs lots of compute resources as each service uses resources
Scott Tolinski
If you use the the GitHub actions locally to run GitHub actions, which is all through Docker, it, like, man, it pulled in, like, 60 gigs when I they get that going. I was like, what is going on here? Did did I do something wrong? Is it yeah. Okay. So let's say I'm sold. You Node? I'm at least curious. I'm Docker curious.
Scott Tolinski
What are your favorite resources for picking up or diving in a little bit more? Because I am I'm I'm genuinely interested here.
Guest 1
Yeah. My I would say the docs I like like I said, the the docs are expansive. That kind can kind of be a turn off just because there's so much of them. Mhmm.
Guest 1
So I would start there. But I, personally, I like to learn by example. So I try to pick some existing projects that are out there, look and see how they've set things up, and kinda just copy paste and and go from there. The other cool thing is when you're looking on Docker Hub, all of these various images, a lot of times, will have example Docker Compose files or example Docker files that show you how to use that thing. So even just looking on Docker Hub, you can get a good idea of how to use a specific image. So that's my main thing JS just get in there, get your hands dirty, and, you'll figure it out. Nice. Well, this has been awesome, CJ. I think it, like, cleared up a ton of
Scott Tolinski
big things that I had about Docker. And I and I hope anyone out there has gotten a good good handle on it. Because it is one of those things that people just kinda talk about it. Like, everybody knows and understands it. I've made it this far in my career with being able to even use Docker without truly understanding it. So, I really sincerely appreciate you taking the time to Definitely. Yeah. Answer my dumb guy questions here. So yeah. Of course. Thank you. So that's all for now. Thanks again for CJ. If, you liked seeing CJ and you liked hearing him, head on over to the Syntax YouTube. It's at Syntax FM on YouTube. There's a lot more CJ there. And, Wes will be back next week, and who knows what we'll talk about. But we'll catch you then.