00:00:12.519
What's up, MountainWest? Try to wake up after lunch. Who here is using EC2? Who has an EC2 account? This is a way you can participate in this little demo.
00:00:21.119
Basically, I made an AMI, and if you send it a little bit of user data, which I'm going to send right here, but you can also get it from my Twitter account, it's a little idea on Twitter. The thing about it is you have to add a line because Twitter gets rid of the carriage returns. You have to add one or else it won't run as a script. When you send this user data, it's going to do some stuff, and we're going to walk through it. It also looks like this: if you want to start an AMI, if you search for 'little idea' or 'Mountain West Ruby Conference,' you should find it there. There should only be one match for that, and you just send that little bit of user data, and it will build Rails for us.
00:01:08.960
That's what we're going to do, so I'm going to start this from the command line so we'll get logs, and I'll start another one here. Oops! Say again. Hold on, I'm not getting the right window. There we go.
00:01:20.520
Somehow I cut off the bottom of my Firefox when I changed the settings, so let's try this.
00:01:24.760
How can I even close it now? Alright, so let's actually just give it a go. This is the user data we're going to launch. It should come up when the public DNS entry gets up. I'll put that in Twitter too, and then we'll see this one already building.
00:01:32.080
We have some slides to get through in the next twenty-eight minutes, so let's try that. Puppet: Systems Building Systems. Yay!
00:01:35.800
So, what I'm going to talk about today is testing all the time. I'd say something else, but I'm in Salt Lake, so I'm going to try to show respect. Not really; it's going to be different. We'll see what I'm really going to talk about, which is some code. I'm going to talk about tribes. If you've seen me talk before, I love talking about tribes, but we'll get there. I'm going to talk about the dawn of time, clouds, evolution, and opportunity, not necessarily in that order.
00:02:00.080
I'm Andrew Shafer. I have two little sons, I like math, and I work for Reductive Labs. I mostly work on Puppet and puppet-related stuff. So, let's start at the beginning. In the beginning, there was nothing. Before that, there were machines that talked to cards. How do you think Ruby would run on that?
00:02:30.200
Back in the day, there was a period of time when the only people who really ran computers were people who wanted to do computation. So, you have this brief period where the people that run the computers were the only ones that understood them. They were the only ones that programmed them, and there was no real computer science. Essentially, it was mathematicians and physicists building computers, and that lasted for about two minutes before they were separated.
00:03:00.840
Then, the internet became dominated by porn. What are you going to do? So, let's look at the code. This is the code that's running in the background as we speak. It takes about fifteen minutes to build the image; if we did some other things, you could get it down to way less—about four or five minutes.
00:03:09.440
That's what we just put in as the user data. This is Puppet code, which isn't Ruby code but is written in Ruby. We love Ruby! But as an external DSL, I mean, come on. It's Ruby! You can write beautiful API DSLs, it's all good. What the hell's going on here? This can't be happening! But I’m pleased to say, I saw it all over the place when this award was announced for submissions. We submitted to the Fauxka Ruby award, and we won an excellent prize, which is second place basically for the Puppet project.
00:03:38.800
One of the main judges was M. I was pretty proud of that. The first place was a Korean group building a Ruby project to model the climate. I don’t feel bad losing to that project at all. Now we’re back to this thing, right? What is that going to do? Well, let's walk through the Puppet code that actually does all this— the modules that are building this. I pre-loaded them, so when it gets the user data, we’ll talk about clouds a little bit more later.
00:04:10.680
It's going to take the user data, and basically, just run through those modules and build out the site. So, that's the code we're looking at now. This is the definition of that code for the Rails site, and it's going to do a bunch of stuff. Who here works on Rails stuff? Raise your hand. Like, pretty much everyone! Who's configured Rails? How many moving parts does Rails need to run?
00:04:51.600
More than two? Yeah. There are all these things about joy and optimizing for joy. On one hand, you have Ruby, which I think is optimized for developer joy but certainly not for operational joy and keeping machines up. You have all these choices, and you have all these configurations. It can become a real pain. You basically have to go through and set up certain things. You need Ruby, right? You need gems to install Rails easily.
00:05:13.120
You need Apache because we’re going to use Passenger. So, what the cool kids are using, I hear. I don’t know. Then, we’re going to use MySQL, and we’re going to install Rails and do some stuff. So we’re going to walk through all this code real quick, and then we’re going to get back to the story.
00:05:36.440
If you guys saw my Twitter, I put the public URL for the one we just started. It’ll take a little while, then the patch will come up. You’ll see the 'It works!' page, and then after a little while, it’ll build Rails, and we’ll have the base install of a Rails page.
00:06:07.760
So, we’re going to include Ruby here. When you include something, you’re going to look in the module path and find the class. This is basically telling Puppet to install these packages, and in this case, we didn’t provide a provider. So, you can choose different package providers, and we’ll see that in a minute.
00:06:40.920
These are going to use the base install, and this image happens to be Debian. So, that’s essentially going to end up being 'apt install.' If we go look at the logs, they’re being generated right now. It’s going to 'apt install' these Ruby packages like you’d expect.
00:07:08.320
Then we’re going to go back to the gems. This is kind of an interesting topic to me. One of the debates— this project has a lot of attention from sysadmins who have to manage a lot of computers, not necessarily Ruby programmers. What are gems?
00:07:32.600
Right? So you have native packages and source packages on the platforms. But then you get to gems—so when you install Passenger from gems, is that a source package or binary package? We’ll get back to that, but I think this is funny. Ruby Forge is a PHP app.
00:08:00.360
And the other thing is, people have evolved, so there’s all this stuff happening with clouds and REST. It makes it very difficult to automate things. If you look at the convention, there’s no rhyme or reason. There’s some weird key—there’s no way to just say, 'Give me the latest Ruby gems,' or even give me the gems by number. You can’t just match this version. You have to have this magic key to get it.
00:08:30.840
So when you start thinking about automating, these little problems make it difficult to create conventions around them, which can create impedance mismatches that add up over time and increase complexity and expense.
00:09:00.600
What this is going to do is something you've probably all typed before. If you install gems from Ruby or from Ruby Forge, you're going to download it, and it's going to create a command; something I'm going to explain in just a minute. You’ll see this sort of process—get the thing, untar it, run setup, and then I like to have a little link so I can just run 'gem.' So, that creates a condition that's known as idempotent.
00:09:30.760
Who knows what idempotent is? Maybe...Idempotent is when an operation will reach a certain state no matter how many times you perform that operation. If you’re talking about a purely mathematical example of an idempotent operation, if you multiply any number by zero, it doesn’t matter how many times you do it; you’ll always end up with zero.
00:10:03.880
Now we’re back here and we’ve set up these creates commands. Another thing that Puppet does—this is controversial—it builds a graph of resources. So you have to explicitly build those relationships to ensure ordering.
00:10:32.720
After we have gems, we're going to install Apache. The first thing we’re going to do is install the Apache packages from the native package manager. Then we’re going to ensure that the Apache service is running.
00:11:00.560
Now in this case, since we're building it and it's Debian, it doesn't really matter because when you install Apache, it's going to start it, but if you were to run this over time, how most people set their Puppet up is they run it on some synchronization cycle. Then it's going to restart processes that aren’t running.
00:11:36.040
It ensures everything is running, and you can also set things to notify that process, which we’ll see in a minute. Here, I’m going to get rid of the default site. If you built a server, especially on Debian, it starts with the default site. This is something I think is much more manageable in most cases than a lot of other distributions.
00:12:00.920
Now we’re going to look at the Apache site. This is another defined resource; it’s going to set up a case statement. This code is pretty easy to understand, and it’s almost all data. We pass in whatever value if it’s supposed to be present, then it’s going to enable the site, and this is setting up idempotent, so it’s not going to run it if it’s already enabled.
00:12:40.600
Then it’s going to notify that service. So, what that means is if a site gets enabled, you have to reload Apache. That’s what these notifies are going to set up, and then I wanted to get rid of it so I got rid of it. We keep going and we’re going to install Passenger.
00:13:10.320
Passenger is another good one because you’ll get to this line. This is going to set up some files for it, and we’re going to look at installing Passenger here.
00:13:36.040
This is a defined resource, and these are pretty standard. It’s going to set up a file that’s going to be in the mods available, and it’s going to load the configuration file. This down here is to be able to set settings—going back to the tribes idea, right? You have the developers and the sysadmins. If you’re going to maintain a site with sysadmins, no one’s going to rebuild Passenger every time, right?
00:14:42.760
It doesn’t make sense. You’re probably going to have a native repository; you build it once, and you distribute the repository. For one thing, it takes time, and for another thing, you install a gem and it says it can’t build until it has 'make,' and then you have to run something else.
00:15:00.640
But you can’t just run it; you have to hit return twice. Has anyone seen this? So we have to tell it to hit return, and then it’s going to build the module we loaded before. We’re going to keep going now and install MySQL; we put the packages in and blah blah blah.
00:15:20.960
Now we're going to create our databases. You’ve all created databases for your Rails apps, so this is just setting up something to create and drop databases. This will ensure that the Ruby gem for MySQL is installed.
00:15:50.440
Here we have the first use of the provider gem. 'Gem' is saying, 'I don’t want to install with the native package manager; I want to install with gem because I know it’s a gem.' Now we’re down to setting up Rails. Pretty straightforward! I’m just going to pass in a version; this is a default value.
00:16:22.560
I’m going to install it from the gem— 'gem install rails'—boom! Then I’m going to set up all the stuff that we do. You run Rails on some directory; I’m using 'VAR/rails' and the name, but people put it all sorts of places. Seems like a good place for me.
00:16:52.360
Then you have to set up these dependencies; again, it’s going to build it all out. You guys have done this, right? database.yaml, and you have to do sites available, which we’re going to see; that’s the Apache passenger-type stuff.
00:17:23.360
Then we already saw this defined earlier; that’s going to enable and restart when it gets to that point. This is the template it’s going to pass in; right now, it’s very secure. Make sure you note that if you’re a sysadmin.
00:17:49.840
This is the virtual host setup. If you’ve installed Passenger, I’m sure you’ve seen this. If you’re doing Rails, you’ve seen that too. I don’t know what the time is, but I think they should have Rails on some of those URLs, right?
00:18:19.680
So this is in the cloud! What Puppet gives you the ability to do—and there are other projects that try to do this as well—is to make your infrastructure code. You can start to take advantage of all the lessons learned by developers over the years.
00:19:00.240
There are places where they don’t really version scripts either. Now that you have this semantic code that can be updated and tracked in Git, you're leveraging a lot of flexibility.
00:19:37.520
When you start thinking about bringing up infrastructure and servers, it used to be a purchase order and wait weeks or even months for hardware. Now anyone can bring up servers—off the street—20 servers in minutes on EC2, right?
00:20:13.560
How do you do this? Well, the answer is I don’t really know, because the code is declarative, and the tests you’re trying to write usually are too. When you’re writing code and tests, it becomes more of a challenge.
00:20:49.760
With all of this, I’d love to hear anyone’s ideas on how to approach this. The best thing I’ve seen in practice is that you describe what your machine should be using something like RSpec. You run continuous integration against your Puppet code and validate it with RSpec.
00:21:18.480
It’s more about description testing—it’s not unit testing or test-driven. When we start talking about infrastructure, what does test-driven mean anyway, right?
00:21:34.640
Anyone who’s tried to scale serious infrastructure—whether it’s Rails or Java—understands that you go through phase shifts. As you add more users, the infrastructure has to adapt—you need to examine data models and usage patterns.
00:22:00.440
You may have a wall of confusion between developers and sysadmins, and the time saved here could be a lot. Evolution is always happening, right? Puppet has a little bit of everything, and it’s been great for allowing us to adapt.
00:22:51.520
I like the fish best! So this is the thing that's really interesting: anyone can now bring up servers for just ten cents an hour! You can do many experiments on infrastructure and applications; the feedback loop is quicker than ever.
00:23:14.720
You won’t have to think of upfront costs anymore; now you can spin up whatever you want for a minimal cost, and turn it off when you’re done.
00:23:46.920
The opportunities are immense; the biggest companies were often born out of economic downturns. With some resourcefulness, you can climb high, innovate, and generate value—there are limitless possibilities! So, that concludes my Puppet presentation.
00:24:35.920
I’m Andrew, and does anyone have any questions?
00:25:46.640
Based on experience, I think your points on testing are spot on, but execution matters. The system you propose relies on practical application, and often the realities of cross-platform or multi-package environments are challenging. But with more clarity around this, teams can manage their environments more effectively.
00:26:30.240
If a new package is released and a version changes, what’s the best practice for updating? The system you have allows for a centralized Puppet master that will synchronize with clients at set intervals. If you want to change your infrastructure, update your central repository and the changes will propagate to all instances.
00:27:52.160
But this does have some issues—be careful when deploying code to avoid crashing servers. It’s easier to rebuild than to attempt to backtrack complicated issues with packages that may not behave as expected.
00:28:06.240
Any other questions? I think we’re good. MountainWest, let’s go!