RubyConf 2021

Workshop: A Gentle Introduction to Docker for Rubyists

Workshop: A Gentle Introduction to Docker for Rubyists

by Jason Swett

In the video titled "Workshop: A Gentle Introduction to Docker for Rubyists," speaker Jason Swett provides an accessible workshop on Docker, particularly tailored for Ruby developers. His aim is to demystify Docker by explaining its core concepts and offering a hands-on learning experience.

Key points discussed include:

- Introduction to Docker: Jason shares his personal journey of learning Docker, expressing the confusion many face with the official documentation. He emphasizes his goal of simplifying the concepts during the workshop.

- Workshop Format: The session is designed to be interactive with exercises. Participants are encouraged to work in pairs and ask questions at any time. Jason also highlights the importance of pacing to ensure understanding.

- Docker Basics: The initial focus is on understanding what Docker is, its two main use cases—development and production environments, and definitions of essential terms such as images, containers, Dockerfiles, and volumes.

- Hands-on Exercises: Jason leads participants through exercises, starting with a "Docker Hello World" example using a Lisp container. This exercise illustrates how Docker allows running applications without installing dependencies on the host machine.

- Dockerizing a Sinatra Application: The workshop progresses to dockerizing a simple Sinatra web application. Jason demonstrates creating Dockerfiles, installing dependencies, and exposing ports, reinforcing how Docker can simplify the development process.

- Discussion of Docker Tools: Jason touches on Docker Compose and Docker Hub as tools that facilitate managing Docker applications and images.

- Final Thoughts: The goal of the workshop is to leave attendees with a better understanding of Docker's benefits for Ruby development and the ease it brings to setting up environments.

Overall, Jason's friendly and engaging approach, along with exercises that illustrate practical use cases, aims to build confidence in using Docker for Ruby applications. The key takeaway is that Docker provides a powerful way to create isolated environments, manage dependencies, and ultimately enhance productivity for developers.

00:00:10.480 All right, it looks like we might have roughly everybody here, so I'm going to go ahead and get started.
00:00:17.920 Welcome to A Gentle Introduction to Docker for Rubyists.
00:00:29.840 I've started learning Docker a little recently, and by recently, I mean a year or two ago. I just began teaching Docker to myself.
00:00:40.399 My experience with the official Docker documentation and the general information available online is that it was really hard for me to understand.
00:00:46.480 Does anybody else have that experience looking at the Docker docs? Yeah, it seems pretty common.
00:00:56.960 I found it really tough; it took me a long time to make heads or tails of anything with Docker. Sometimes when I would talk to others who were already proficient, they acted like it was easy.
00:01:10.400 That was really frustrating to me—it's like, am I dumb or something? Why is it so easy for them but super hard for me?
00:01:21.360 So, what I'm going to do today is go really slow and start at the beginning—what is Docker, the foundational concepts, and why do people use Docker?
00:01:36.159 My hope is that I can do a better job of explaining some things today than the official Docker documentation does and most of the material online.
00:01:49.040 Now, as for the format: One thing I want to say is that in the past, I've facilitated workshops like this for corporate clients. I would fly to their office, and there would be a team of 10 to 30 people.
00:02:06.560 This is a much larger group than I am used to, so we'll see how it goes. I think it'll go fine, but it is definitely different.
00:02:20.080 For those people watching the video later, I have low hopes that this will translate well. Apologies to those watching at home; it surely will not be the same, but we will do our best.
00:02:32.000 The way I'm going to conduct this workshop is highly interactive and exercise-based. I'll do an exercise myself and then turn it over to you to do the same exercise.
00:02:42.240 During the time you're doing the exercises, I'll come around the room to check on everybody periodically and ask, 'Am I going too fast, too slow, or just right?' Please help me remember to do those check-ins. Sometimes I forget, but they are really important.
00:03:01.360 Working in pairs or groups is strongly encouraged, so if you'd like to buddy up with the person next to you and work on one computer, I think that's great.
00:03:14.560 In the workshops I've done where participants pair up, everything goes much better. The process of verbalizing things with your partner—like saying, 'I didn't understand this step,' and then discussing it together—helps a lot, especially with a group this size where I can't provide individual attention.
00:03:35.360 Questions are encouraged. If you have a question, feel free to interrupt me, or you can raise your hand, and I'll call on you.
00:03:54.240 Here's the overview of what we're going to do today. By the way, it's not super important for me that we get through all of this.
00:04:01.680 What I don't want to do is rush through everything just to get through it because you're not going to retain anything if we do it that way.
00:04:20.080 So, we're going to go at an appropriate speed. If we finish everything, great; if we only get a third of the way through, that's fine.
00:04:30.000 The important thing is that we go slow enough for you to understand and retain some of what you learn.
00:04:39.360 With that in mind, we're going to talk first about what Docker is. We'll discuss the two use cases for Docker, concepts and terminology, do a Docker Hello World, dockerize a Sinatra application, and then add Docker Compose to the Sinatra app.
00:04:48.960 If you're not familiar with Docker Compose, we'll go over what that is, and then we'll add a PostgreSQL database to our application.
00:05:09.520 A little bit about me: I'm the host of the Code with Jason podcast. By chance, are there any listeners in the room? I'm just curious, and it looks like there are at least a couple.
00:05:21.920 I wrote a small eBook called 'Docker for Beginners' that came out recently, which was a product of putting together this workshop, and I've also written a book called 'The Complete Guide to Rails Testing.' I blog at codewithjason.com.
00:05:39.680 Now, what is Docker? Does anyone feel like they could explain what Docker is?
00:05:47.200 Do I have a volunteer to give me their version of what they think Docker is?
00:05:53.760 A small virtual machine. Okay, that's probably the most common answer. You could say it's somewhat like a VM; it's not exactly a VM, but it's similar.
00:06:08.080 However, I think that's kind of the wrong answer because it's the right answer but answers the wrong question. When people ask, 'What is Docker?' they're not really asking mechanically how it works.
00:06:25.040 So I believe a better way to answer the question is to talk about why people use it. What are the benefits of Docker?
00:06:33.760 Does anyone have an idea of why people use Docker? I'm going to ask lots of questions throughout the workshop.
00:06:41.360 Quick dependency setup?
00:06:45.760 Any other use cases for Docker?
00:06:54.880 Managing different versions of the same software? Okay.
00:07:02.560 Here's what I came to understand regarding the use cases for Docker. It took me a lot of studying to arrive at this, and for some reason, they don't just tell you in the beginning; there are two use cases.
00:07:11.759 One is to make it easier to install and run your development environment's dependencies.
00:07:21.840 I'll say that again because it's a little bit of a mouthful: Docker makes it easier to install and run your development environment dependencies.
00:07:29.040 We'll go a little deeper into what that means shortly, but that's one use case—the development environment.
00:07:39.680 The other use case is for a production environment. Similar idea: it makes it easier to install and run your production environment's dependencies.
00:07:47.360 The mechanics of the production environment are a little different than the development environment.
00:07:56.000 There’s some overlap, but they are two kind of distinct use cases. Today, we are focusing on the development environment use case.
00:08:03.520 We are going to completely ignore the production environment use case. The reason for ignoring that is, first of all, there's already a lot we are going to cover.
00:08:10.560 We simply can't cover that much in this session. Also, between the two, the development environment stuff is easier to work with and understand.
00:08:17.680 All right, so we're going to get into the exercises shortly, but just a bit more context before we get to those.
00:08:31.760 Does anyone know in Docker terminology what a host machine refers to? I see someone nodding. What does the host machine mean?
00:08:46.560 Yeah, the host is the machine that the container is running on. If I'm running Docker on my computer, the host machine is my actual laptop.
00:08:54.080 Now, images and containers are big concepts. This will take a little time to explain, but here's my attempt.
00:09:00.800 One of the use cases for Docker is to make it easy to install and run your development environment's dependencies. Where do containers come into this picture?
00:09:10.480 If I have an application and I've Dockerized my database, I've only Dockerized my database—why would I do that? It helps me with one dependency.
00:09:21.760 I don't have to manually install PostgreSQL or whatever database management system I need. I can have my Docker config file, and PostgreSQL will be running.
00:09:31.440 That happens through a container. I will have a PostgreSQL container running on my computer.
00:09:43.600 This allows me to avoid having PostgreSQL installed on the host machine. Instead, I just have PostgreSQL in the container. When I connect to the database, I'll specify like we would with anything else: the IP address, username, and password.
00:09:58.320 Instead of pointing at my actual host machine's localhost, we point the database connection config at the container.
00:10:04.640 PostgreSQL is running inside that container. We'll come back to containers.
00:10:12.320 I don't expect many of these concepts to sink in on the first pass. It will take revisiting these topics several times. Just like it took me, I had to read definitions over and over before they finally clicked.
00:10:25.920 These definitions have intertwined dependencies. You have to hear one term, then another, and bounce around a little before you can understand them all together.
00:10:39.040 Let's think again about that PostgreSQL container where I have PostgreSQL running. It's like a computer inside my computer that's running PostgreSQL. The way I get there is I have a PostgreSQL image.
00:10:52.000 The image is like the blueprint, and the container is like the house. The image has the instructions: 'Here's how you make a PostgreSQL container.' You don't actually run the image, you just have the image on your computer.
00:11:04.960 When you want to run that thing, what you get is a container. So again, the image is like the blueprint, and the container is like the house.
00:11:19.200 These concepts will be easier to grasp once we get into the exercises.
00:11:27.679 A Dockerfile is a script with instructions for building a container. You define how to create an image from it.
00:11:36.800 For example, if you wanted to make a custom PostgreSQL image, you would have lines in your Dockerfile that say something like 'apt-get install postgresql.' That's where the Dockerfile comes into the picture.
00:11:50.480 Lastly, let's talk about volumes. Containers are ephemeral; you start and stop containers, create and delete them—they don't last forever.
00:12:02.400 This creates a problem when it comes to storage. Returning to the PostgreSQL example: your PostgreSQL database needs a place to store its data.
00:12:12.960 If you just keep that data in the container, when you stop or delete that container, you lose the data. Therefore, we can't do it that way.
00:12:26.080 The solution is to store data on the host machine. We'll see the details later, but the idea is simple: we link the PostgreSQL container back to a specified location on the host machine.
00:12:40.640 We configure the container to say, 'Hey, don't store this data inside the container; instead, store it on the host machine.'
00:12:54.480 Would you agree that this has been a lot to digest so far?
00:13:01.440 Okay, would it be beneficial to skip ahead and get started with the exercises?
00:13:08.040 The first exercise will be a Docker Hello World. I’m glad that apparently like two people have Lisp installed on their computer.
00:13:19.760 I picked Lisp because I assumed most people wouldn’t have it installed.
00:13:26.720 Here's what I want to convey: to me, the magical thing about Docker is that you can run services without actually having them installed.
00:13:31.760 Right now, we're going to get a Lisp image, run it, and get a Lisp container. We'll write some Lisp inside that container, and when we're done, we can delete everything without any evidence left behind.
00:13:46.720 That’s pretty neat because, to give another example, I have a WordPress site because my blog is on WordPress, but I loathe WordPress. I don’t want to install PHP and MySQL.
00:14:00.720 Instead, I've Dockerized my WordPress website, so when I want to work on it, I just spin up the container. I don't have to have PHP or MySQL installed on my actual laptop.
00:14:11.840 The other benefit here is that when a new programmer starts at your organization, it usually takes way less time to set up the development environment.
00:14:23.760 So, let's do a little exercise. How long has it taken someone in this room to get your development environment set up? Raise your hand if it has taken at least an hour.
00:14:36.960 We've got hands everywhere. How long did it take, for example?
00:14:42.080 At least four hours? At least a day? Isn't that right?
00:14:46.000 Almost everybody still has their hand raised. How about at least two days? A week?
00:14:52.000 I'm surprised that many people still have their hands raised for over a day or two.
00:15:02.720 Imagine if instead that can be reduced to just 10 minutes, and not just 10 minutes, but a really easy ten minutes.
00:15:14.480 The magic of Docker is that it can dramatically simplify this process, and I aim to convey some of that magic to you.
00:15:27.200 So, I'll do this on my computer, then turn it over to you to do it on yours. First, we're going to add a Dockerfile.
00:15:34.800 At the root of the project, we create this Dockerfile. I'll explain what all three lines mean.
00:15:49.280 A Dockerfile is the instructions for creating an image. The first line, 'FROM ubuntu:20.04,' states the base image.
00:16:02.160 The next line indicates what to run in the image. We can use 'RUN apt update and apt install -y sbcl.' This means to install Lisp.
00:16:12.000 Now, the '-y' flag means 'don't prompt me'; we want the initial installations to occur automatically.
00:16:29.200 The default working directory is going to be '/user/src,' so we would need that to know where to find our files.
00:16:39.680 Next, let's check for the images we currently have on our computer.
00:16:50.000 I'll see what images do I have, and let's ensure we don't have a conflict.
00:17:02.000 I'll run docker image ls and look for one related to hello.
00:17:10.400 Now, let's build this image. The command is 'docker build -t hello .' This specifies the current directory, where the Dockerfile is located.
00:17:21.600 Let's see what it does. Now we are installing Lisp using the instructions from the Dockerfile.
00:17:31.600 While we wait, does anyone have any questions? If so, feel free to ask!
00:17:49.680 Oh, I see a hand! Can you repeat that? Someone asked about the images—are they themselves based on a base image?
00:18:00.480 Correct! You can consider images as being built on top of one another.
00:18:10.240 Now, the build has finished, so let's run it.
00:18:13.680 Let's use the command: 'docker run hello.' This will run our container.
00:18:20.960 Again, this is a bit more complex since we need to map the ports, so we have to do port mapping.
00:18:28.280 Now let's go to the browser and check if it works. I'm heading to 127.0.0.1:4567 to see if there's a response.
00:18:39.280 Oh, it works! We've successfully run a Lisp application without installing it on our computer.
00:18:52.960 Now I'll exit the container and delete the image using 'docker rmi -f hello.' So there you have it.
00:19:03.680 What I want you to take from this is that you can run software without having it natively installed on your machine.
00:19:12.720 It’s an efficient way to manage dependencies. Would anyone like to try the exercise now?
00:19:21.760 If you didn’t follow along in real time, let’s take some time to catch up.
00:19:30.000 Can the people starting the exercise now raise their hands so I can assist?
00:19:37.600 Okay. Since we have less time left, I think I'll summarize and provide some additional explanations.
00:19:47.680 I had planned for a second exercise, but due to time, we might not cover it.
00:19:56.000 What I’ll do now is take your questions and review some of the terms we went over or additional terms I skipped.
00:20:11.680 Let’s take a brief break and regroup.
00:20:20.720 The time remaining is likely insufficient for a full exercise.
00:20:26.800 I’ll begin with dockerizing a Sinatra application.
00:20:36.960 If you'd like to follow along, feel free to do so asynchronously.
00:20:44.640 Let's start by creating a directory for our Sinatra app.
00:20:52.720 We will call it hello.rb.
00:20:59.760 It's a simple setup that maps paths to methods.
00:21:09.040 We need our gem file to install the Sinatra gem.
00:21:16.680 And finally, we need a rack-up file for our Sinatra application.
00:21:24.000 Next, I’ll do the undockerized version of the app to show the structure.
00:21:36.480 So I’ll do a bundle install first to install Sinatra.
00:21:42.960 Let’s run it: ruby hello.rb. It should be listening on 127.0.0.1 port 4567.
00:21:49.680 Let’s check it in the browser. It works!
00:21:57.840 Now we're going to create a Dockerfile for this application.
00:22:04.560 The first line indicates the base image, while the second line sets our working directory.
00:22:12.200 Next, we’ll copy files into the specified directory.
00:22:18.560 Line five is crucial because we’ll run 'bundle install' to install necessary dependencies.
00:22:29.440 We need to expose port 4567 and define the command that will run the Sinatra application.
00:22:39.680 After we finish building the image for the Sinatra app, let’s check for any naming conflicts.
00:22:49.520 I’ll keep this simple; let’s run docker image ls and see what we have.
00:22:58.960 Now, let's build the Docker image. We'll call it 'sinatra_app' or something similar to avoid conflicts.
00:23:07.760 It may take a moment, and we will see the progress reported.
00:23:18.760 We can install Sinatra using Docker!
00:23:28.960 As we finish building, I would love to hear any questions or thoughts about this process.
00:23:40.000 Shall we try running the application in Docker once we finish building?
00:23:52.160 Like before, we would map the ports from the container to the host.
00:24:00.480 After running that command, we should see the Sinatra app available.
00:24:10.320 Seems to be working! Given that we can see it accessible in our browser.
00:24:26.640 Now that we tested our app, it’s time to summarize.
00:24:35.760 Overall, I hope you feel more comfortable working with Docker!
00:24:49.400 Feel free to reach out during the rest of the conference if you have any further questions!
00:25:00.480 Thank you all for being here today!