 I'm a developer advocate at Google. I tweet at Thagamizer RB, and all the code that I'm going to show in this talk is on GitHub. I'm Thagamizer on GitHub, and it's in my examples repository in the RailsConf 15 folder. And since I'm showing you code, I have to say that all the code in this talk is copyright Google and licensed under Apache V2. So first things first, I'm not an expert at ops. I'm actually not an expert at anything. I tend toward more drack of all trades, master of none. But I've spent some time racking servers, and I've had bloody knuckles to prove it. And I've built things that look like this, but my skills have not gotten to the level of this yet. And when I try to do something that's all professional ops fancy, I end up building things that look a little bit like this. And why is that? Because I'm fundamentally lazy. I'm passionate about some things, solving problems, building sites, algorithms. But I'm lazy about deployment and operations and maintenance, and I find a lot of that stuff to be fiddly and not a lot of fun. And I'm here to tell you right now that that's okay for most people. And what do I mean specifically by lazy? I mean doing the minimum that you absolutely have to to have something be successful and stable. I want to make systems that are lazy so that they'll make, I can be lazy so that they'll maintain themselves. And one way I've found to do that is with containers. So what the heck's a container? So according to several sources, a container is a way for multiple applications to securely share hardware with a minimum footprint. And frequently this means less of a footprint than using virtual machines. To me, containers can also be an environment package. It's a way of wrapping up your operating system, your build dependencies, any libraries you need, possibly your application code, all into a nice little bundle. Or wrapping up your application with its execution environment. And this takes me back to the old days when I was making little applications that I was giving to my friends on floppy disks and I had to make sure I included all the DLLs that they needed to run them. So how do you use containers? Well, I use Docker. There are lots of container frameworks. There's lots of ways to do containers. Wikipedia will give you a list and a nice little chart of all of them. But I like Docker because there's a great community and ecosystem that go along with the container format. And many common web frameworks, including Rails, while we're why we're all here today, have containers that are freely available on Docker Hub, which is like RubyGems for Docker containers, container images. So Docker sounds awesome. How do you use it? So I'm going to do a quick demo using a basic Rails app. And by basic Rails app, I mean very, very basic. Built solely with the scaffold. This is me. And this is a to-do list app. Standard Rails stuff. You know, it's got a title. Very, very long title. This is me telekinetically typing. Got some notes. You have a due date. And then there's a completion integer where you can put in the percent complete. And I'm sure that most of you guys in the audience could rip something that looked a lot like this up in a couple of minutes, but let's actually walk through all the steps. So to make this application, Rails need to do. And there's a lot of tutorials out there for using Docker and Rails, but almost all of them stop here. They don't actually have any sort of models. And a Rails app without models is kind of boring. So let's make a simple model for a task, has a title, some notes, a due date, and a completion parameter, which is just an integer. And to make it a little more exciting, I'm going to use Postgres as my production database, but I'm going to use SQLite in Dev and Test. This is probably familiar to a lot of you. It's something that you've done multiple times before. And if you're going to use Postgres as your production database, you need to change the default Rails gem file. Here's the gem file I ended up with, which shouldn't be incomprehensible. But in red right now are the two pieces I had to change, and you still can't see them, so let's zoom in a bit. So create a new group for production, put the PG gem in it. And then I need to move SQLite, which is in the default, is in all groups in the default gem file, into the development of production group. So that's great. And since I changed my database setup, I also need to change my database YAML file. And those are the lines I need to change. Set the adapter to Postgres for production, and then I'm going to set my username, password, and host from some environment variables that Docker sets for me, and I will come back to this, I promise. So now I need Dockerfile, and Dockerfile is just the list of things that need to happen to set up your environment. And I'm lazy, so I'm going to write a minimal Dockerfile, and I can do a Dockerfile for this application in three lines, really, just three. The first line is telling me what image I want to start from. All Docker images, most Docker images, are built from other images. So the Rails image is built from a Ruby image. The Ruby image is built from an operating system image, and turtles all the way down. I'm using the Rails image because it's really close to exactly what I want, and therefore I don't have to know anything about ops or how to install packages on an Ubuntu machine or anything like that if I don't want to. And then I'm also going to specify that my RailsMF is production, because this isn't in the Rails image that I pulled. And then the CMD, this command line, is the entry point for my application. This is what happens once my container is built and my app needs to start up. And you'll see that I'm calling a shell script here. So let's see what's in that shell script, my init.sh shell script. And it's, again, three very simple lines. I'm doing an export of secret key base because Rails 4, bundle exec, dbcreate, and then I'm starting up Rails server. Yes, I'm using the default server. You could use Unicorn. You could use something else, lazy. But there's nothing really complicated going on here. I hacked all this stuff together one night at a hack night and not very long at all. So now let's build it. We need to build up our image with Docker. And an image, I've used that word a couple of times, is just a template for a container. Docker build, thagomizer slash to do. The dot on the end means use a Docker file in this directory. And this builds it. So let's see what that looks like. So that's done. And that went really, really fast. And I'm going to hand wave this a bit, but one of the reasons it went really fast is the Docker caches all the intermediate steps in creating the image. So if I only change, and each of those steps is a layer, and if I only change something at the very end in those last layers, I can use the cached versions of all the ones before that. Which means I don't have to repeat all of the steps, like pulling down packages from your package, from your distro's package management system, or building gems from scratch if they have C extensions. I can skip all that if I'm not changing any of that stuff. And that means it builds really quickly. So now it's built. Let's run it. I'm going to run through these commands. I don't know what people's experience with Docker is in the audience, but I'm assuming that you have as about as much as I had three months ago, which is this much. So Docker run. First we're going to do the database component, because we need the database up and running before we start the web. So this command creates a new container named DB, and it uses the Postgres image to do that. These two lines are setting some environment variables for that Postgres container. And these set the password and username for the Postgres database. And all of this is documented in lovely detail on the GitHub page for the Postgres image. I'm following the instructions. It's lovely, especially if you're lazy like me. And then this dash D means we're going to run it demonized. So I'm not going to get the standard out. I'm going to let it run in the background and do its thing. And I'm not going to interact with the container in any way. And now I'm going to start the web server up. Again, we're going to run a container named web. We're using the Thagamizer to do image that I just showed how it built. Again, we're going to run it demonized. This line is mapping ports. That's what the P stands for. And what I'm doing here is I'm mapping port 3000 on my container to 3000 on the host machine. In that case, this case, it could be local host on a Linux box on my Mac. It's a Linux VM. And then this line is magic and lovely. So the link makes it so that my containers can talk to each other. And in this case, I am linking the DB container that I just made to the container I'm starting up now, the web container. And I'm linking it with the alias PG for Postgres. And what link does is it creates a secure tunnel between my web container and my database container. And it also puts a bunch of handy environment variables in my web container so that I can connect to the database container. And that Postgres username, Postgres password, and Postgres host address, all of that that was in the database.yaml file, those are created because I used this link flag on my Docker startup. So let's watch it. That's the database starting up. That's the web starting up. They're up. There's lots of ways to set up virtual machines for testing out your app. This is really, really fast. I'm going to grab the IP, throw it in a browser, be indecisive about which profile I want to use in Chrome, go to port 3000, the tasks collection. There it is, that's my app running. And in case it wasn't obvious, I got all of this stuff set up in less than 20 lines of code beyond the standard Rails boilerplate that Rails Nu gives you. That's about five lines of code to change the gem file, about five lines of code in the database.yaml, three lines in the Docker file, and three lines in init. That's it. I don't know any ways that I can set up a Rails app to run on a boon two that are quite this easy. And there's a couple shell commands, but it still all comes in under 20 lines of code. So why would you use something like Docker? Why would you use containers? Some pros. For me, the biggest one is consistency. I hate hearing, but it works on my machine. I started my career in QA. I've heard that so many times. And I don't care if it works on your machine. I care if it works in production. And if you're using containers, your staging environment and your production environment are the same. They are the same image. They are the same OS with the same libraries, all the same versions, you don't have to worry about messing up your gem file slightly and getting the wrong one minor version off in a way that messes up your app. The next talk, the one after mine, is going to talk about how you can also use Docker in development and possibly have exactly the same OSes and libraries and stuff in development, so there's none of this. But it works on my machine stuff. It either works or it does. Everyone has the same experience. Speed, containers start up really, really quickly. There was a video that came out from the Kubernetes team last week, two weeks ago, about them racing a Kubernetes cluster versus making a latte. It ended up being a neck and neck tie. We're talking minutes. And I've worked on apps where we had Chef Build and Chef's very cool, but rebuilding all of our VMs from scratch took upwards of 15 minutes because of all the stuff we were having to build from source. And being able to start up a container very, very quickly is nice, especially when you want to do things like auto-scaling. And the caching makes it fast if you're only changing the last layers. Flexibility, if you've got a microservices setup or we're in the distributed computing track, containers let you change how the different processes sit on different hardware. So you have a VM. You can say in development you want all the stuff to run on the same VM. In test, you want it to be split up in one way. In your staging environment, you want one of every machine on a separate VM. And then in production, you want five web servers and two database backends. And all of that can be set up pretty easily with a variety of container management tools. Portability, I talked to folks about why they do or do not use the cloud or why they roll their own or why they have their own hardware. And everyone's like, I need flexibility. I need to be able to move back and forward. And containers are great because you can run them on Linux, you can run them on a Mac, you can run them on Windows, you can run them on your personal machine, you can run them on data center hardware that your company owns, you can run them on a cloud provider. Most cloud providers support containers right now. You're never locked into specific hardware. You can move it anywhere, and it'll behave the same. And then repeatability, last year about this time was particularly bad if you had a DevOps as part of one of your hats you were wearing. You're patching rail security bugs. You're patching open SSL security bugs. And I was on a team that was doing DevOps at the time. And we had our client was a little bit nervous about us making OS level changes. Making changes to the OS libraries. Because we pushed code a couple of times a week. And that was all automated. And we had that down. But every time we had to do something lower level than that, we didn't have a process for that. And the nice thing about using containers is the process for, if you set it up this way, containers are flexible, you can make it so the process for updating your code is the exact same process for updating your OS is the exact same process for updating the C libraries you have. And so it's only one process, everyone knows it, and there's much less likely that you're going to mess it up. So there might be some cons. The biggest one is Yagney. You aren't going to need it. For some apps, and I'm not going to say this is most apps, but if you're doing a small proof of concept thing or your personal blog, maybe you don't need containers. Maybe the overhead of setting that up is too much for you, and you'd rather just use a platform as a service provider. That's fine. This is a very cool tool for people who can get benefit out of it, but I'm never going to say that any one tool is perfect for every application. And the other thing is that while containers have been around for a long time, I work at Google, and Google's been running all of their internal stuff on containers for years. Docker is still only a few years old, and some people are reticent about adopting stuff that's on the first half of the adoption curve. I am not one of those people. Y'all are at Ruby RailsConf. I assume y'all aren't those people. But if you work for some of those people who are a little bit reticent, you might have a harder sell on using a technology that's still new. But I think it's really cool. Otherwise I wouldn't be doing this talk. So I've showed you some pretty cool stuff about running these containers on my Mac, but I don't think any of you actually run through production site off of MacBook Air. If you do, I have a dinosaur for you. We should come chat afterwards. So how do you manage containers in a cloud environment? How do you manage containers in a data center environment when you want multiple versions of something or you want five front end web servers? And I'm going to talk about Kubernetes. There's lots of ways of managing containers. This is the one that I happen to know. And it's a Google project for managing clusters of containers. Basically, the idea is that you build up a list of your desired state in the format that Kubernetes understands, and then you start up Kubernetes on a group of VMs or bare metal machines and say, make it look like my desired state. And I want to point out specifically that Kubernetes is open source. There are more contributors outside Google than inside Google at this point. And all this is on GitHub. Very, very visible what's going on. So Kubernetes has a giant pile of vocabulary. I'm going to hit it up. I'm going to talk about it specifically up front because I'm going to use it and I'm going to forget what I have and have not defined. Master, this is the machine that manages everything. Masters have a set of minions. Usually, there's several of them. They're running on different VMs. The underlying base unit is a pod, and this is the smallest deployable unit. You can think of it as part of an application that intrinsically works together, not independently. And I asked some folks who work on Kubernetes, I'm like, so if you have a web application, is the web application plus the DB a pod or is the web app a pod and the database is a pod? And the answer is, it depends. I'm going with web app and the database are going to be separate pods because I want to scale the two pieces independently. For the demo, I'm only going to have one database, but I'm going to have two front end web servers. But if you want to put them together, you can do that too. So a service is an abstraction for a logical set of pods, which is a lot of very fancy words to basically mean a named load balancer. And if I have multiple pods, I have a service that takes care of splitting the work up between them. Services are also how different pods talk to each other, like we had links so that the database could talk to the web container on my local machine. We build services so that my database pods can talk to my web pods in the Kubernetes cluster. And then we have a replication controller. And this is responsible for ensuring that the correct number of pods are running at all times. When you set up a replication controller, you say, this is my desired state. I'd like two replicas. And the replication controller is responsible for saying, are there two replicas? Yes. If one of those machines fails, it starts up another. If you somehow end up with extras, it'll shut one down. I want to also put some notes. This is currently in beta. The API may change. But people are using it. So warning, but it's still awesome. And one of the things I want to be very explicit about is that Kubernetes gives you options. This is open source. You can run this on your own hardware. You can run this on a cloud provider's VMs. Google Cloud Platform supports it. But there are others who are working with Kubernetes. There are other companies that work with Kubernetes. And this technology does not lock you into a specific provider. So that was a bunch of words. And I like giving technical talks with lots of code. So let's look at some code. This is a hand-wavy example of a Kubernetes configuration file. And this is not a specific one. But the basic format's similar for a lot of them. So you have an ID. You have a kind, which could be things like pod or service or replication controller. The API version, desired state. And that desired state is where you set up, this is what I want Kubernetes to maintain for me. And that has maybe a set of containers or something else. And then there's some labels. And these are just used so that you can gather together things that are related and refer to groups more easily. So for this example, let's do the database first. So I'm going to have one database pod. And there's a bunch of ellipses on here where I pulled out a lot of extra braces because JSON on slides doesn't work so hot. But this is the pod configuration file for the database. And I'm specifically showing that it has a set of containers. And that's an array with one unit in it. The container is named DB. It uses the Postgres image. I can pass in my environment variables just like I did to Docker run. And then I can also do some ports. And I'm saying that I want to map my container port 5.432 to the host port 5.432, standard Postgres port. And if I want other pods to be able to talk to this pod, I need to set up a service. And here's the service definition. IDDB, kind service. And again, I want the service port 5.432 to be mapped to a container port 5.432. And then the selector says what pods should be in this service. So any pod that's named database will be in this service. Really simple stuff. So now I've got my database set up. Let's do the web. I'm going to have a replication controller because I want two replicas. Again, pulled out a bunch of friends and curly braces and such. And this is actually a lot of stuff. So let's look at it in two pieces. The top part is the desired state for my replication controller. I want two replicas. The replicas that count toward this are the ones that are named web. And then I give a template for the replication controller to create pods. And that's what that template looks like. I've got a single container named web using the image thagamizer to do prod. And I'm passing in some environment variables. And I'm doing some port mapping. If I want to be able to access this replica set of pods with a replication controller, I need to have a service. Here's the service definition. I've got a selector saying anything that's named web is in this service. And I'm doing some port mapping again, specifically putting it on port 3000. So this is all great, but I haven't showed you anything running. So you can run all this. And the Google Kubernetes environment is Google Container Engine. It's in public alpha. And I'm going to show you how to get it running. So this is just something you run at the command line. The first three things, G Cloud Alpha Container is using the Google Cloud Platform command line interface. And I'm saying that I want alpha feature set, because this is alpha. And I want the container engine subset. Cube CTL, it's the Kubernetes command line interface. And I'm going to say create from file that dash f, the dbpod.json. That's that dbpod file I showed you. And it's going to make that. And then I can say, hey, Kubernetes, give me the list of pods. And I get back a list of pods in their state. And you can see that this one's running. You can see what image it is and what note it's been assigned to currently. Great, that's up. So now I can do the service. Again, create dash f, create from file for the DV service. And I can say, Cube CTL, give me the services. And it gives me a list of the services and what ports they've exposed. Great, now let's create the web controller. Again, create from a file. And I can get the replication controllers and see that I have this web controller, the image that it's being used, and how many replicas there are. And then I can go get the pods. And I can see the list of pods that's been started up and what their state is. And now I need to create my web service. And you'll notice that everything is create dash f. I'm just creating all of these from the standard configuration files. There's really not a lot that's complicated here. The first half of the line looks a little scary, but it's the same every single time. So I create my web service. I start it up, and you can see that it's at port 3000. And then I'm going to do something crazy. I'm going to have Kubernetes resize my web replication controller. And I'm going to say I want five replicas now. Wait a couple seconds to a minute. And I have five running pods now. All I had to do was say how many I wanted it to happen. Because Kubernetes' job is to say, what state do you want the cluster in? And I say, this is the state I want. Kubernetes is like, I will figure out how to make that happen. It pulls down images as it needs to. It creates new containers as it needs to. It divides them among the number of nodes. And you'll see that I've only got three hosts listed because the cluster I created only had three VMs in it. I didn't need to provision new VMs to have additional workers running. So at Mountain West RubyConf, Star Horan gave a great talk. And in his talk, he had a slide that said the lies I've told during this talk. So I would like to think that I haven't lied to you, but there are some large sections of this that I have hand-waved vigorously. And I'm going to call them out right now so that you guys don't have to ask questions about them when I open up the Florida questions. The first one is disk. I didn't show you how to set up the database to hit a persistent disk. So if you restart that database container right now, all your data goes away. You can do that. There's tutorials on how to do it. I also didn't show you how to set a shared disk between multiple web clients. There are tutorials on how to do that, too. This is a 101-level talk. That is not a 101-level concept. Security. I'm not going to say that what I showed you is good for production-level security. Your app has unique security concerns. Please do a security audit. Replication. I didn't show you how to set up a cluster of database machines that replicate across themselves. There are lots of tutorials for this. One of the standard Google Cloud tutorials uses Redis and has Redis Master and Redis Workers that shows how to do something like that. And I kind of talked about this, but Docker runs on Linux machines only. To run it on a Mac, you need a tool called Boot to Docker that uses a virtual box to make a little Linux machine, a little Linux slice where you can run your Docker containers. And it does it well, so I forget the fact that I'm not actually using Docker natively. There's tools for Windows that are the same. You can also just run this on Ubuntu. When I'm at work, I've got an Ubuntu desktop underneath my desk, a big tower, and I do most of my work as a station to that machine. And size. So one of the things I've found talking to folks who do containers and work with Docker a lot is that they're concerned about VM image size. And the images that I chose, the standard Rails image, is huge. If you care about size, you can make your own by taking out the pieces you don't need. For example, I believe the standard Rails image has both Postgres database client libraries and MySQL client libraries. I was only using Postgres, so if I built my own, I could choose not to include the MySQL ones and save some space. But make the trade-off of your time versus how big an image is, and figure out where your laziness actually lies on that. I was going for minimal effort here, which is why I chose those images. So as I said, this is a 101 level talk. A lot of you in the audience have been nodding along, which means I probably didn't show you anything new. But if you want to learn more, first place to start is Shipping RubyOps with Docker by Brian Helmkamp at red.rubyconf 18 months ago, a year ago. This is an awesome hour-long talk on exactly this topic, includes live code demos, because he is more daring than I. I don't do live code demos at a conference because you never know about the Wi-Fi. If you're gonna get into this, I recommend watching this talk first because it will help you internalize the vocabulary. One of the things I struggled with learning this stuff from preparing this talk was that I would pull in a bunch of information and think I understood it and then get stuck. And I would unstick myself three days later once all the pieces kind of sorted themselves out in my head. And I had the answer the whole time, but so much new vocabulary and so much dense documentation was making it hard for me to help myself. And once I watched this talk, I kind of got a big picture sense of how things were and things made more sense. If you wanna find out about Container Engine, cloud.google.com slash container engine slash docs, there are two demos. There's a simple hello world type demo and then there's a guestbook demo and I use the guestbook demo extensively when preparing this talk. If you wanna learn about Kubernetes, that's the Kubernetes website. And if you wanna talk to people who work on Container Engine and on Kubernetes on FreeNode, go to the Google Container's room. The devs actively monitor this. No, really, they actively monitor this. You can talk to the people who are working on this and ask them very technical questions and they will help you find answers. Google Cloud encourages folks to hit up stack overflow, make sure that it helps a lot if your question is tagged so that the appropriate people who are monitoring those tags can answer your question for you. If you run into trouble, let me know and I will make sure someone answers your question. And now time for the sales pitch part. I work on Google Cloud Platform. We have storage, we have VMs, we have App Engine, we have logging and monitoring tools. We have data analysis tools that are awesome and I gave a talk about them at Mountain West RubyConf. Data centers all over the world, internet endpoints all over the world, all the stuff you'd expect for a cloud provider. And at least some of you probably didn't know that you could get a VM from Google before I said these words. And I wanna point this out because this is the really cool part for me. As I've been to a data center and our cloud customers, their code runs on the same racks and the same physical hardware as YouTube as search. I can't tell in the data center what's running on any machine so any work we do to improve the infrastructure for things like YouTube and search benefits our cloud customers as well. We have a free trial because you have a free trial. It does ask for a credit card but you will not be billed unless you okay billing. The credit card is there for fraud protection and a bunch of other legal reasons. And if you have any trouble getting the free trial or you've used your free trial and wanna try something else, come chat with me. I have ways around that but I encourage you to use the free trial because that gives you $200 in credit for 60 days and that's better than I can give you easily at this conference. So thank you. I wanna thank the conference organizers for having me here and for organizing this giant conference. I wanna thank my coworkers who reviewed these slides for me even though they're on the West Coast and so I was sending them slides at inopportune time zone times. When I gave conference talks, I have plastic dinosaurs. Someone told me this looks like just a random bag of stuff. There's actually a bunch of plastic dinosaurs in here that I give away to people who ask questions or come chat with me. I also have stickers up on the podium, right below the podium up here. Lots and lots and lots of stickers. Come get stickers from me. And we've got about 10 minutes left so I'm gonna open the floor to questions.