 So now I'm going to introduce myself. Hi, I'm Vita. It's so nice to meet all of you. Like everyone here, I'm also a Rubyist, and I'm from China. I'm not sure if you like Panda or not, but I'm living in the hometown of Panda, which is called Sutran province. This is my bail, and this is my GitHub, my Twitter. So if you have any questions or just want to make a friend, you can reach out of me in those ways. I think some here might be curious about why a Chinese girl would appear on a meetup in Singapore. There is actually a reason for that. I've been to Singapore before, and to be honest, I really love this beautiful country and the kind people that I've met when I was traveling. Since I returned to home, I wondered if I could learn more about Singapore. After I searched up on the internet, I was surprised to find a Ruby SG, and even more surprised that I could have a chance to be a part of it. All right, that's why I'm here, and I think it's time to do our business. So what I'm going to share today is how to docker-wise a Rails application. Okay, so considering that some people may not know much about docker, so I will give a brief introduction to it. First of all, we need to know what is docker. Docker is a tool designed to make it easier to create, deploy, and run applications by using containers. So a container is deployed from a docker image, and it's a part of docker. Container is a standard unit of software, and that packages up the code and all its dependencies. So the application is able to run quickly and reliable from one computing environment to another. In my view, docker is a bit like a virtual machine, but it wants to create a whole virtual operating system. Instead, docker applications are allowed to use the same Linux kernel as the system they are running on. And speaking of why I choose docker, personally one of my favorite things about docker is that docker keeps the development test and production environments consistent. But it also has many advantages such as more efficient use of system resources, faster startup times, easier migration, easier maintenance, and expansion. So here I've broken down the process of dockerizing the Rails application into five steps. First one, we need to have a Rails application. Second, we need to install the docker. The third step, at least, we need to set up a docker file to customize our own image. Step four, we need to set up a docker compose YAML file to customize our containers. And the last step is to execute compose command to create and start the containers. But today time is limited, so I'll assume that we already installed docker and we already have Rails application, so we will just talk about how to set up a docker file and a docker compose file. By the way, the following materials are all from one of my demo projects. The full code and configurations can be found in my give-response directory. I'm sorry. And I have detailed how to dockerize a Rails project from scratch with me. And here is my link. So let's start with docker file. So what is docker file for? Basically docker file is used to customize a docker image. This is a docker file which is used in my previous demo project. Let's look at the first line. As I said before, we need to customize our own image. So when we customize an image, it should base on another image. And the front command is used to specify a base image. So it's a necessary command and must be put on the first line of the docker file. The third line, maintainer command, as the command suggests, it specifies a maintainer of the image. The line five to line seven, both of them use command run, which is to execute our command. The line five is to update installation source for outping linux, and line seven is to install the dependencies. As we can see, the line nine is to create an folder under which we will store the Rails project files. Let's talk about workDIR, which is in line 11. WorkDIR command is used to specify work directory, but why we need to specify work directory? So here is an example. Let's assume that I previously created a folder on my linux called test dockerfile, and then I created a dockerfile in test dockerfile. So now it looks like this. So in this example, you can see that basically I want to create the app folder in an image, then create a folder, create a file called hello.txt in an app folder. And in the end, I want to print out the contents of hello.txt, just like how we do it with show. But after I executed docker build command, now we can see the arrow below step five, which says it can't find the hello.txt in app folder. So it turns out docker image works not like show. When we show, several lines of commands are in the same process. Therefore the memory state, which is modified by the previous command will directly affect the later command. So in the show, we can print out hello.txt successfully following those commands because they are in the one process. But it works really different when we build docker image. When we build a docker image, we can imagine that we are playing a logo. And each docker command in the dockerfile is considered a layer of logos. So the image will be built layer by layer. The front layer is the foundation of the next layer. But if the field of the front layer is completed, then it won't change anymore. And any change on the later layer affects only on its own. So every layer is totally separated from each other, which means every command in the dockerfile does not affect the others. So in this example, the reason for the arrow is because when we is killed, it call hello to hello.txt command. Its working directory is not in the add folder. Since the change directory to add folder command, this command is executed in the previous layer. It doesn't affect this one, this layer. Therefore, we should use workdir command to specify the working directory. And then the working directory on each layer will be changed to the specified one. If the directory we specified does not exist, the workdir command will help you to create the directory. Okay, so let's go back to 13. At line 13 and line 14, I want to copy my local gene file and gene file.log to my target path. At line 15, I set Rails environment variables to production. At line 16 is to install bundler. Line 17 is to check bundle version. At line 18 is to kill the bundle install. Look at line 19. Okay, here I've got something to talk. As you can see, I want to copy all the files under the path where the docker file is located to the add folder. But here's a question. Since I have to copy all the files into my image anyway, so why do I have to put gene file and copy gene file and copy gene file.log separately before the run bundle install? So I put an example here. Let's assume that I just modified an HTML and now I want to review my image if my docker file is like this. So at line 13, I copy all my files to the add folder. And run bundle install is at line 18. So the action of copy all the files is in front of the run bundle install command. Then when I build my image, it will work like this. So here is a list of bundle install. As you can see, docker will execute all the remaining commands from the line where I copied all the files. So the run bundle install command will be executed whether or not the gene file and gene file.log are changed. But according to my original settings, as long as I don't modify gene file and gene file.log, then run bundle install command won't be executed. And when I build my image, it will look like this. So here. And there is not a long list of bundle install. Okay. So let's go back to the last line. And the last line we will execute the commands to create tables. Precompile our assets before pushing code to production and create profile to config directory. But one thing we need to be careful is the CMD command is the start command for the main process of the container. So since the CMD command is used to start the main process, there can only be one CMD command in a docker file unlike the run command, which can be write multiple times. All right. And that's for the docker file part. I'm going to jump to the step four. So set up docker file, docker compose file. What is compose? First of all, we need to know what is compose? Compose is a tool for defining and running multi-container local applications. We use compose YAML file to deploy containers for images, from images. And the second thing we need to know is what's the use of docker compose? In our daily work, our project often requires not only web service but also databases and may also need to use engines for load balancing. So when we dockerize our projects we often meet situations that require multiple containers to work together and compose just fulfills such a need. It allows the user to define a set of associated application containers as a project by setting up a docker compose YAML file. So here, finally, we're going to talk about our docker compose file. Here it is. Let's look at the first line. The version key. The version depends on the docker release. There is a table in the docker documentation that maps a different version with their respective docker releases. The second line, services key. Here is something I need to talk. Docker services are what that makes up our application which will be built as different containers. And services act as the organs of our application. So here we've got three services, app service and DB service and engine service. So, okay. Right now we are going to break out our first container and it's also called app service. Line 4. The build key specifies the path where the docker file is located. The path can be either absolute or relative and compose will use the docker file to automatically build an image and then use it. 9.5.2.9.6. So, we can specify the port in the container to the host or we can just specify the port of the container in this way. But when the host will randomly but if we do so then the host will randomly select a port to expose the port inside the container. So in my docker compose file I mapped the port number and to the host the value. 9.7.3.9.10. Or setting environmental variables. Line 11 depends on depends on key resolves the container dependency and the sequence of start-up seed issues. When way is queued docker compose out it will start services in dependency order as defined the way it depends on. In this example DB will be started before the app service. So, alright let's look at our DB service. This service is for installing our post-grade code and running it as a container. It will pull and already view the image which is version 10.12 of post-grade from docker hub. I also pass the required environment variables in it because time is limited today so I'm not going to talk about how to set up engines with docker compose maybe we can talk about it some other time. Let's jump to our last step. After everything is set up now all we need to do is run docker compose out and run docker compose out. The command docker compose out will create services, start services and associated services related containers based on the settings in docker compose for example file. The hyphen d is a detached mode which will run the containers in the background and then app will be built with all the containers and you can view the containers with docker ps hyphen a and here it is. So first is my engines container and second is my app container and last one is post-grade container and we also can check it on browser but never mind it's just an demo. What if we want to delete and solve and delete the containers if we want to solve and delete containers we just need to run docker compose down so it will delete the containers defined in the docker compose demo file. As you can see first of all docker will stop all the containers defined in the docker compose file then it will remove all the stop containers. All of those are what I want to share today so if you have any questions please feel free to ask me. Anybody got any questions? It was a good session. Thank you. Thank you. I'm so nervous. I'm sorry. No, it's fine. So good. It's my first time to share anything on the internet actually. Actually I have a tie here. So let's say also I'm from China. Oh, nice to meet you. Nice to meet you. How can I stop to share this? There's a stop share button. No, I'm sorry. Which one? Ah, I see. I don't know. You have to stop share before I can share again.