Deploying Rails apps to the cloud used to be a real headache, but these days it’s actually pretty smooth sailing. I’ve been working with Rails and cloud platforms for years now, and let me tell you - Kubernetes has been a game-changer.
Let’s start with the basics. You’ll want to containerize your Rails app using Docker first. Here’s a simple Dockerfile to get you started:
FROM ruby:3.0
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
CMD ["rails", "server", "-b", "0.0.0.0"]
This sets up a Ruby environment, installs your gems, and starts the Rails server. Easy peasy.
Next up, you’ll need to create some Kubernetes manifests. Here’s a basic deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-rails-app
spec:
replicas: 3
selector:
matchLabels:
app: my-rails-app
template:
metadata:
labels:
app: my-rails-app
spec:
containers:
- name: my-rails-app
image: your-docker-image:tag
ports:
- containerPort: 3000
This will create three replicas of your app, which is great for high availability. You’ll also need a service to expose your app:
apiVersion: v1
kind: Service
metadata:
name: my-rails-app-service
spec:
selector:
app: my-rails-app
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
Now, let’s talk about actually getting this deployed. If you’re using AWS, you’ll want to set up EKS (Elastic Kubernetes Service). It’s pretty straightforward - you can use the AWS CLI or the web console to create a cluster.
Once your cluster is up and running, you’ll need to configure kubectl to talk to it. AWS makes this easy:
aws eks get-token --cluster-name your-cluster-name | kubectl apply -f -
Then you can deploy your app:
kubectl apply -f your-deployment.yaml
kubectl apply -f your-service.yaml
Google Cloud’s GKE (Google Kubernetes Engine) is similarly easy to work with. You can create a cluster with just a few clicks in the Google Cloud Console, or use the gcloud CLI:
gcloud container clusters create your-cluster-name
Then authenticate kubectl:
gcloud container clusters get-credentials your-cluster-name
And deploy your app just like with AWS.
Now, here’s where things get interesting. You’ve got your app running, but what about your database? In my experience, it’s usually best to use a managed database service rather than trying to run your own DB in Kubernetes. Both AWS and Google Cloud offer great managed PostgreSQL services.
For AWS, you’d use RDS. Here’s a quick example of how to set that up with Terraform:
resource "aws_db_instance" "default" {
engine = "postgres"
engine_version = "13.4"
instance_class = "db.t3.micro"
name = "mydb"
username = "foo"
password = "foobarbaz"
}
For Google Cloud, you’d use Cloud SQL. Again, here’s a Terraform example:
resource "google_sql_database_instance" "main" {
name = "main-instance"
database_version = "POSTGRES_13"
region = "us-central1"
settings {
tier = "db-f1-micro"
}
}
Once you’ve got your database set up, you’ll need to configure your Rails app to use it. This is where environment variables come in handy. You can set these in your Kubernetes deployment:
spec:
containers:
- name: my-rails-app
image: your-docker-image:tag
env:
- name: DATABASE_URL
value: postgres://username:password@host:5432/database
Now, let’s talk about some advanced topics. One thing you’ll definitely want to set up is automatic deployments. I’m a big fan of GitLab CI/CD for this. Here’s a sample .gitlab-ci.yml file:
stages:
- build
- deploy
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
deploy:
stage: deploy
image: google/cloud-sdk
script:
- echo $GCP_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
- gcloud container clusters get-credentials your-cluster-name --zone your-zone --project your-project
- kubectl set image deployment/my-rails-app my-rails-app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
This will automatically build and deploy your app whenever you push to your main branch. Pretty cool, right?
Another important consideration is logging and monitoring. Both AWS and Google Cloud offer great solutions for this. On AWS, you’d use CloudWatch, while on Google Cloud you’d use Cloud Logging and Cloud Monitoring.
You can set up logging for your Rails app using the lograge gem. Here’s how to configure it:
# config/initializers/lograge.rb
Rails.application.configure do
config.lograge.enabled = true
config.lograge.formatter = Lograge::Formatters::Json.new
end
This will output your logs in JSON format, which is much easier for log aggregation tools to parse.
For monitoring, you might want to use a tool like Prometheus. You can add Prometheus metrics to your Rails app using the prometheus-client gem:
require 'prometheus/client'
prometheus = Prometheus::Client.registry
http_requests_total = Prometheus::Client::Counter.new(:http_requests_total, 'A counter of HTTP requests made')
prometheus.register(http_requests_total)
class ApplicationController < ActionController::Base
before_action :record_request_metrics
def record_request_metrics
http_requests_total.increment(labels: { path: request.path, method: request.method })
end
end
Then you can set up Prometheus in your Kubernetes cluster to scrape these metrics.
Now, let’s talk about scaling. Kubernetes makes horizontal scaling super easy. You can manually scale your deployment with a simple command:
kubectl scale deployment my-rails-app --replicas=5
But it’s even cooler to set up autoscaling. Here’s how you’d do that:
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: my-rails-app-autoscaler
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-rails-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50
This will automatically scale your app based on CPU usage. Pretty nifty!
One last thing I want to touch on is secrets management. You definitely don’t want to be storing sensitive information like database passwords in your code or Docker images. Kubernetes has a built-in Secrets API that’s great for this:
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
database-password: base64encodedpassword
Then you can use this in your deployment:
spec:
containers:
- name: my-rails-app
image: your-docker-image:tag
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: database-password
And there you have it! That’s a pretty comprehensive overview of deploying Rails apps to AWS and Google Cloud with Kubernetes. It might seem like a lot, but once you get the hang of it, it’s actually pretty straightforward. And the benefits in terms of scalability and ease of management are huge.
I’ve been using this setup for a while now, and it’s made my life so much easier. No more worrying about individual servers or manual deployments. Everything is automated, scalable, and robust. It’s really changed the way I think about web development.
Of course, there’s always more to learn. The cloud landscape is constantly evolving, with new tools and best practices emerging all the time. But that’s what makes it exciting, right? There’s always something new to discover and play with.
So go forth and deploy! And remember, if you run into any issues, the Rails and Kubernetes communities are incredibly helpful. Don’t be afraid to ask for help. Happy coding!