In this tutorial, we’re going to dig deeper into the deployment of a highly available and scalable RoR application. But first, let’s make a quick overview about the RESTful architecture with whom we’re gonna implement our app.
RESTful architectures carry some architectural constraints that were inherited from various networked distributed architectural styles. Client and server in RESTful architectures are orthogonal, meaning there is a clear separation of concerns and functions between them. User logic is moved completely to the client side and server components are kept simple to improve scalability. This separation also allows the two components to be developed and evolve independently, so long as they respect the communication protocols and defined interfaces. In a RESTful architecture, each request is treated independently. This means the architecture of the server is stateless and requests cannot take advantage of any stored context and must carry all the necessary information to be understood and processed. Each response also needs to be labeled as cacheable or noncacheable. If a response is cacheable, the client can store and reuse the data for network efficiency (i.e., cache the data to reduce round-trips).
Ruby on Rails is a Model-View-Controller (MVC) framework. MVC is a software architectural pattern that divides a given application into three interconnected logic blocks. In the three blocks, the internal representation of some information or object (the model) is separated from the way the user interacts with this information (the controller) and the way this information is presented to the user (the view).
Start by setting up the files needed to build the app. The app will run inside a Docker container containing its dependencies. Defining dependencies is done using a file called
Dockerfile. To begin with, the Dockerfile consists of:
That’ll put your application code inside an image that builds a container with Ruby, Bundler and all your dependencies inside it.
Next, open the editor and create a Gemfile and Gemfile.lock. Keep the lock file empty and specify the rails version in the Gemfile. (ex: 5 or 6)
Next, provide an entrypoint script to fix a Rails-specific issue that prevents the server from restarting when a certain
server.pid file pre-exists. This script will be executed every time the container gets started.
entrypoint.sh consists of:
Now you should be able to implement a docker-compose file. This file describes the services that comprise your app (a database and a web app), how to get each one’s Docker image (the database just runs on a pre-made PostgreSQL image, and the web app is built from the current directory), and the configuration needed to link them together and expose the web app’s port.
Next, you’ll need to build the project and generate the rails app skeleton as specified within the Gemfile:
Now that you’ve got a new Gemfile, you need to build the image again. (This, and changes to the
Gemfile or the Dockerfile, should be the only times you’ll need to rebuild using the build command.)
The app is now running but you’ll need to configure the database. By default, Rails expects a database to be running on
localhost - so you need to point it at the
db container instead. You also need to change the database and username to align with the defaults set by the
Finally, create the database:
Now, we’re done with docker and docker compose. The next step will be orchestrating and making our application auto-scalable.
The portability and reproducibility of a containerized process mean we have an opportunity to move and scale our containerized applications across clouds and datacenters. Containers effectively guarantee that those applications run the same way anywhere, allowing us to quickly and easily take advantage of all these environments.
All containers in Kubernetes are scheduled as pods, which are groups of co-located containers that share some resources. Furthermore, in a realistic application we almost never create individual pods; instead, most of our workloads are scheduled as deployments, which are scalable groups of pods maintained automatically by Kubernetes.
In this Kubernetes YAML file, we have two objects, separated by the
Deployment, describing a scalable group of identical pods. In this case, you’ll get just one
replica, or copy of your pod, and that pod (which is described under the
template:key) has just one container in it, based off of your
apppwebimage from the previous step in this tutorial.
NodePortservice, which will route traffic from port 30001 on your host to port 8080 inside the pods it routes to, allowing you to reach your bulletin board from the network.
Also, notice that while Kubernetes YAML can appear long and complicated at first, it almost always follows the same pattern:
apiVersion, which indicates the Kubernetes API that parses this object
kindindicating what sort of object this is
metadataapplying things like names to your objects
specspecifying all the parameters and configurations of your object.
Now, let’s deploy the application:
Kubernetes: Scaling and Auto-scaling
Now let’s scale the application by replicating the database and the server each three times:
Check the pods, if running:
To make the application more lucid, we can activate auto-scaling. The parameter that we’ll choose will be the CPU usage.
Congratulation! you’ve created a scalable RoR application that is highly available.
Distributed storage: (amazon S3)
The first thing we need to do is to create a Bucket in S3. Then add user policy to grant access to files. Make sure to give the user the necessary permissions to have read/write access to the S3 Bucket. Next, update
config/storage.yml Finally, add aws-sdk-s3 gem to your Gemfile and install the dependency.
Let’s build our app!
Our app will be, mainly, a blog where the user can authenticate and perform CRUD operation on article model. (for styling I do recommend bulma: it’s a nice css library and opensource)
Step 1: Create a Rails app within the container
Step 2: Generate the post model
Step 3: Generate controllers
Step 4: Configure routes
Step 5: Migrate the data
Step 6: Integrate the devise gem to handle authentication
For more information about the implementation, please consult my GitHub repository. I’ve pushed the whole application.
This is a highly available RoR application that uses docker and kubernetes. - louazz/Kubernetes_and_rails
Thank you for your attention!