 Okay, hi. So, I think I'm just going to... So, right. So, hi, my name is Sora Suno. I'm actually a software engineer at the Ministry of Education. So, today I'm going to be talking about Docker and Ruby development. So, let me share a bit about what ESTL, what MOE is. So, basically, we are the Experimental Systems Technology Lab within the Ministry of Education. So, we are a unit that started up about one and a half years ago. And then, basically, we tried to solve engineering problems within the Ministry that for a long time, a lot of software development has been moved out to other vendors to solve. And it's very hard for the external vendors to actually understand the challenges that our teachers and the Ministry has in general. So, we are a unit that set up within MOE to try to tackle these challenges. So, at MOE, we have been using Docker for about a year. And we have some experience with running it. So, some of the use cases which we use Docker for is the production and staging environment for our attendance and health application. So, there is an application that allows teachers to mark attendance and check the health of the students when they are in a school setting. We also run tests and security checks in our CI. So, because we are a Ministry set up, we are unable to put our code elsewhere in the cloud. So, we don't have the advantage of using Travis and some of these other tools to run automated tests or security scans for us. So, we do a lot of these things in-house. So, part of the problem is that if you have a CI engine running, they probably depend on the version of the Ruby installed on the machine and we want to get away with that. So, basically, we put all our tests in containers and we run the tests in containers. They still be isolated from the other... So, the dependencies of the application doesn't matter. In Cosmology, we are using... So, Cosmology is this LMS where students can submit code and learn programming. It's being currently used in the NUS. So, we use Docker as well to run the code engine. So, the whatever code... Some of the students have the right finding codes to try to hack the system. So, if you run a code in the Docker container, it will be separated and isolated from the environment that you're running the code from. So, evaluating it as a setup to let students log in at their own instances. So, let me share with you some of the problems that we have currently in development and deployment. So, part of the problem is sharing of computational resources. So, we have a lot of machines that are very powerful and our applications are unable to saturate the full capacity of these machines. So, one way around this is to let multiple applications run on the same physical hardware. From that, rise the question of how do we ensure proper application isolation. So, when you have multiple applications running on the same physical host, how do we ensure that these applications do not interfere with each other? And the next point is how do you manage these dependencies between these applications? For instance, if you have a Ruby application that is running Rails and you have a Ruby application like Sinatra, they may have different dependencies and you want to manage them separately and ensure that they don't interfere with each other. The next problem that we face is the issue of deployment integrity or basically solving the... This thing works on my machine, it works in QA, it works in staging layout, how come deployment doesn't work? So, there are a lot of tools that try to solve this particular problem like Ansible Puppet where they try to actually let you set up a virtual machine and then they will install all the dependencies that will install all the different libraries. But how do we actually manage this at scale and do it safely is a challenge. So, imagine if you have a cluster of 100 machines and you want to deploy an update on these 100 machines, at any point of time when something fails, you are unable to tell that that particular thing has failed on one of the machines in your cluster. It's very difficult to do rollback. That's the second point, which is how to ensure that the dependencies of the application are deployed properly and safely. And the next point is how do you actually quickly scale up if necessary? It's like, if you have Puppet Ansible, fine. You can say that I was just going to create a new VM and then I run the Puppet script or the Ansible Playbook and you will launch a new, you'll set a VR properly. But the challenge is that downloading all the dependencies will take time and that's something we want to resolve. So, I believe that Docker can help solve these two problems. So, I'm going to describe to you what Docker is and then how we actually use it in our current setup. So, before we talk about Docker, we have to understand what exactly are containers. So, basically, if you have been around reading Hacker News or you're reading the new sources out there, you realize that containers are like the new bus word now. Everybody's talking about containers. Everybody's talking about Docker and how to actually containerize your setup. So, in general, the idea is that containers are lightweight virtual machines. What they do is they provide isolation at the kernel or the operating system layer. They actually help isolate the processes associated with the application they are trying to run in its own user space, with its own networking stack and so on and so forth. And it's definitely not a new technology. It has been around since 2005. OpenVC has been around. So, if you have been using the low-end boxes, most of the providers there are using OpenVC, which actually is just a container. It's not even a full-fetched virtual machines. This diagram shows how the container relationship is with together with the host operating system. The kernel is shared among all the different containers, as well as the host operating system. And the kernel provides guarantees that the processes will not break out. You can contrast this with virtual machines. So, for a virtual machine setup, you have a virtualizer at the base, from which you will host your own operating system. And each of the operating systems have their own kernel, have their own user libraries. The next way you can do isolation is through application-based isolation. So, for things like if you have done PHP before, you will know that for a long time, the Apache site's available way is the right way to do isolation. So, you have an application that can run part of the Apache as a different site. For the rubies in this room, you have RBEMV, which will help you manage the dependencies of your different Ruby applications. So, on your host machine, you will deploy a RBEMV setup, and then you will say that this app will take this... In this folder, you will run a certain Ruby, real version, and you will run in certain gems. And Python, you have virtual AMP, which basically do the same thing. What they're trying to achieve is application-level isolation of the process that you're trying to run. So, what is Docker? Docker is an opinionated approach to managing applications using containers. What they provide for you is a set of tools to run, to build and run Docker images and Docker containers. So, I'll elaborate on how exactly they are an opinionated approach. So, they are like containers, but they have certain rules and restrictions associated with these images and containers. So, what is a Docker container? It's actually run from Docker images. So, the biggest challenge in understanding this Docker setup and how it differs from traditional virtual machine is that Docker advocates having one application run within one container. So, if you have a typical virtual machine setup, what you will do is you will spin up a VM and you will say, okay, I'm going to install Rails. I'm going to install nginx in it. I'm going to install a database in it and they're going to link up together and then I'm going to launch my app. But what Docker says is no. You put your LB, you put your nginx in one container, you put your app in one container and you put your DB in a separate container. What this then allows you to do is it allows you to scale horizontally for your application. So, if you use Rails, you know that the application... Rails is single-treaded. Ruby, the MRI is single-treaded. So, if you want to handle more processes, the only way is to actually launch multiple parallel machines and having this particular setup allows you to spin up more containers at any time. Contrast this with a traditional setup where you have a full set of machine there. It's very hard to actually duplicate this machine and have it scale because you have redundancy in your database and your load balancer, which is what you don't want. So, what are Docker images? So, Docker images basically are the file system of the container. How they do... Basically, they are built from Dockerfile and they promote... It uses a layered file system which allows for sharing an extension. So, basically, you can have a root image called the Ubuntu image, for instance, and then you add your Ruby dependencies on top of it, which will be in a layer and then you can add your application dependency on top of that. And how do you actually manage these dependencies is through the use of Dockerfile, which specifies instructions on how to actually run this. Later, I will show you some examples of the Dockerfiles they will use in our setup. So, now I will show you a bit on how the container is run. So, this is a prime number generator. So, for the rubies in room, I think this is no surprise. It will take a couple of seconds to understand what it does. Basically, it iterates through till forever trying to determine all the prime numbers. Obviously, it's not very optimized, but I just write this code to show we will be dockerizing this application, this mini application. So, what you then do is you have a Dockerfile. So, what it says is from ruby 2.3.0-lpine. So, the base image from which this new image will be built from will be from the ruby image, which is tagged with 2.3.0. The next instruction is then to copy this prime.rb file, which we created into the file system of the image. And then, we will run the command ruby prime.rb. To build the image, we will run docker-build-t-primes and dot, which stands for the current folder. And to run the container, we will do docker-run-primes, and then you will just run. So, I'm going to show this. Okay, so over here, we have the prime.rb file. So, this is the exact same file that we have seen earlier. And then in the build script, we have this. So, we will try to run the build. So, what I can see is that it's running each of these instructions and it's building this image called primes. And if we do, you can see that this image has been created like 10 seconds ago. Now, to run the image, we will just run the run command. And you see that basically it's just spinning out a bunch of primes. So, what I would like to illustrate to you is that the difference between a virtual machine and a container is that in a virtual machine setup, you will not be able to see this running process in your host, in your top, in your process manager because it's isolated away from the host operating system. But over here, if I run htop, you can actually see that the biggest process here is this will be prime.rb. So, all it does is it isolates the whole entire program in a kernel level and not at the whole virtualized level. It's not running as part of a virtual machine, but running as part of the host operating systems. Okay, I'm going to kill this. So, now I'll share with some of the tools that we use in our setup. So, there's this tool called Docker Compose. So, now you would think that after you set up, you know we can run one container like what's the big deal? You need to have an Nginx server. You need to have a database server that runs on your app. So, what a Docker Compose file does is it basically defines the containers that you want to deploy using your application. So, you have an app container and you have an Nginx container and you have a database container. So, after you have this file, all you need to do is run Docker Compose up and then you will then go to each of these definitions and launch the containers associated with that particular dependency that you need. And Docker's form is how Docker tends to do large-scale deployment. So, the idea is that you have one Docker's form host node which connects to a lot of different Docker servers and when you schedule a container to run on the Docker form, the form will then allocate the containers to the other different places. So, a lot of the tools set up are actually together. So, you can use Compose with form and when you try to up the container, it will then deploy onto the various machines, different machines. It depends on how you're going to set them up. Okay, so that was a bit dry. So, now we'll share a bit of how we actually do the deployment setup within the MOE. So, when our developers push a code on a merge to master, basically what our CI will do is it will then run the different aspect tests and different security scans on the application. After which, once the build is successful, we will push the master image of the app into our Docker registry. From then, we will then pull the master image into our staging server and you will then launch it. So, this is a typical workflow we do this. So, if you're interested, after this, you can come and talk and we will discuss more about how we actually do this setup. So, some of the lessons that we have learned when we do this Docker setup is that we will... Every line in the Dockerfile that you see earlier is actually cached. So, let's see. So, this is one of the typical Dockerfiles in our system. So, every line of this command is actually being run and every time it will be cached. What happens is that the... Every line in the Dockerfile will be executed and every time it will be cached. But, if you have a command like AppGetInstall or AbundantInstall, which will take a very long time, it will take a very long time to actually execute them. So, what we plan to do, what we have done is that we have abstracted a common part of the different images. So, instead of having this App1 does a AppGetInstall, we will build an Analyzer for the dependencies and have that do the AppGetInstall instead. Then the application will then be powered on top of it. So, we don't do the redundant stuff twice. The other issue is that because every container should only run one process, which is the application process, you don't want to install SSH into your containers. But, you still need a way to actually enter your container. So, what you do is you run this command instead Dockerexact, container name bash, and you will run a bash setup for the container without actually polluting your container images. Also, if you have been looking around, you will see a lot of people talking about development and production parity. So, in our opinion, it doesn't work. You cannot have your development environment be identical to your production environment. Simply because in your development environment, the things that you care about is debugging tools. It's easy to read, easy to look at stack traces. And these are the stuff that you do not want to have in your production images. So, this idea of development, production parity, it just doesn't fly. In production environment, you also want your SSH pipeline to compress down your JavaScript and your CSS. So, you can't do debugging if your development does that thing anyway. So, debugging tool should not be present in production image. So, what you should instead strive for is to have staging and production parity. It means you have some confidence that in your staging environment, everything works well. And once that's transported to your production environment, you're pretty much guaranteed that your application will run the same way. That is what we should strive for. And some of the issue that we face is tooling problems. So, if you run OSX, you're going to have a hard time because you have to launch a new virtual machine. So, the issue about containers is that for Linux containers, you can only run them on Linux host machines because they share, they make, they share the same kernel code as the host operating system. So, if your machine, if you're on Mac, you definitely cannot run Docker natively yet. So, in order to use Docker in Mac, you have to install this idea of Docker machine, which actually does help you create a VM instance from which you can run your Docker commands on. But that is extremely, extremely painful from our experience. Container debugging is also not easy because your, the whole idea of having your production image is to have it be very thin and very skinny. So, things like Veeam, things like Nano, they are not present in the production image. So, when something goes wrong, you can't even edit a file to see what's happening. So, that is something which is very hard and you have to resort to doing some cat stuff to actually get it to work but it's very difficult. And, next is the whole ecosystem of the, the whole Docker ecosystem. So, because they're moving so quickly, every release takes place every two months. So, things are breaking all the time. Resources are being outdated all the time. So, we do a search for like how to make, how to do Docker deployment. You will receive different information at different time because as new features can be implemented, the best practices has changed. I think this is something that if you're a Rubyist, you will feel that as well because like, there's just too much, there's just changes happening all the time and Docker happens that and for Docker, it's happening at even faster pace. There are also some politics with other cloud vendors and big players. So, if you're keeping up, it's not as bad as a Node.js style of fragmentation is happening right now but there are some politics because different vendors, they are trying to do their own big cloud solution and they probably view Docker as a threat. So, they are trying to implement their own things as well and Docker Swarm itself is untested. So, if you want to do a larger-scale setup, it's better to stick to more proven solutions like Messospheres or Kubernetes. But the really, really, really nice thing about Docker is that your application or dependencies are fully isolated from each other. So, what it means is that it is a general R-B-E-N-V or virtual M for all the applications that can take off and they help you and they help provide standard ways to manage your Docker application. So, let me end this thing with this problem that we were doing the other day. So, have you guys heard of this game called Factorial? It's a crazy additive game where you build factories and automation stuff. So, me and my friends were playing it and we were like, hey, won't it be a good idea to launch a dedicated server for this game? So, what we did is we go to the Factorial website and then there's this at the bottom here there's this dedicated and headless server and it says, well, if you use Linux you need to do you need to download this you need to check your dependencies you need to create a new user and you need to start a server in this particular way and you're like, ain't nobody got time for that, right? I just don't have my own damn server to run to play a game and so on. So, if you do a Google search for Factorial Docker you see that the first result is someone who has already created a Docker image of the server. So, what you need to do is basically take this command and then you you run it with a slight modification. Shit. So, you take this address this port number and then this thing you just go play and you go multiplayer connect to game you put the local host with the IP and then you run a game. So, that's all it takes for you to run a dedicated server. So, if you need to demo if you need to try out any application that's been Dockerized all it takes is to run a command I mean sometimes you have to play around with the flags and the settings a bit but generally you have a good indication of how the application would behave and run before putting a lot of effort to try to get it to scale. So, that's our experience with Docker so far. So, if you have any question and if you're curious about how this setup you can talk after this. Thank you.