Introduction
This part covers setting up your Rails app on GKE + your database with Google Cloud SQL.
In the next parts we’ll cover more topics like:
- DNS
- HTTPS
- Redis
- Sidekiq and background jobs
- Google Cloud Storage
Google Kubernetes Engine
https://cloud.google.com/kubernetes-engine
Google Kubernetes Engine (GKE) provides a managed environment for deploying, managing, and scaling your containerized applications using Google infrastructure.
The GKE environment consists of multiple machines (specifically, Compute Engine instances) grouped together to form a cluster.
GKE main features list:
-
Run Kubernetes on a platform built by the largest engineering contributor to K8s
-
Start quickly with single-click clusters and scale up to 15000 nodes
-
Leverage a high-availability control plane including multi-zonal and regional clusters
-
Eliminate operational overhead with industry-first four-way auto scaling
-
Secure by default, including vulnerability scanning of container images and data encryption
Setup Google Cloud SQL
What is Google Cloud SQL?
Fully managed relational database service for MySQL, PostgreSQL, and SQL Server.
-
Reduce maintenance cost with fully managed relational databases in the cloud
-
Ensure business continuity with reliable and secure services backed by 24/7 SRE team
-
Automate database provisioning, storage capacity management, and other time-consuming tasks
-
Database observability made easy for developers with Cloud SQL Insights
-
Easy integration with existing apps and Google Cloud services like GKE and BigQuery
Go to the Cloud SQL section in your GCP console.
Create database - mysql/postgresql:
~ ❯❯❯ gcloud beta sql instances create mydbinstance \
--database-version POSTGRES_9_6 \
--cpu=1 --memory=3840MiB --region=northamerica-northeast1-a
Create user:
~ ❯❯❯ gcloud sql users set-password postgres \
--instance=mydbinstance \
--password=my-password
!IMPORTANT!
You’ll need to run special proxy for database connections, check deployment file.
Set PROJECT_ID
Let’s setup variable with your GCP project ID.
We’ll use it later in our configuration setup.
~ ❯❯❯ PROJECT_ID=project_id
~ ❯❯❯ gcloud auth login your_account_name
~ ❯❯❯ gcloud config set project $PROJECT_ID
Cluster
What is Kubernetes cluster?
https://www.redhat.com/en/topics/containers/what-is-a-kubernetes-cluster
We can create a cluster via the command line with the following:
~ ❯❯❯ gcloud container clusters create rails \
--enable-cloud-logging \
--enable-cloud-monitoring \
--machine-type n1-standard-1 \
--num-nodes 1
When the cluster creation is complete, we’ll now need to give the cluster credentials to kubectl to begin deploying containers.
~ ❯❯❯ gcloud container clusters get-credentials rails
Using service account and set access
Let’s set access rights and create key file as described in manual:
https://cloud.google.com/sql/docs/mysql/connect-kubernetes-engine
Working with secrets
Let’s create secrets (you can use this template to create all secrets described in deployment.yml)
~ ❯❯❯ export DBPASSWORD="YOUR_SUPER_PASSWORD"
~ ❯❯❯ kubectl create secret generic cloudsql-db-credentials --from-literal=username=default --from-literal=password=${DBPASSWORD}
App deployment config
Let’s take a look to our Dockerfile (depends on your app):
FROM ruby:2.6.2
RUN apt-get update && apt-get install -y build-essential git
RUN apt-get install -y libpq-dev
RUN apt-get install -y nodejs
RUN mkdir -p /app
WORKDIR /app
ENV LANG C.UTF-8
COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install --jobs 20 --retry 5
COPY . $APP_ROOT
ENV RAILS_LOG_TO_STDOUT=true
ENV RAILS_ENV production
RUN chmod +x /app/entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]
Entrypoint.sh file example.
#!/bin/bash
cd /app
RAILS_ENV=production bundle exec rake db:create
RAILS_ENV=production bundle exec rake db:migrate
RAILS_ENV=production bundle exec rake db:seed
bundle exec rails s -e production
Deployments
Let’s create our first deployment.
Read more: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp
name: myapp
spec:
replicas: 2
minReadySeconds: 5
selector:
matchLabels:
app: myapp
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: myapp
spec:
containers:
- env:
- name: SECRET_KEY_BASE
valueFrom:
secretKeyRef:
key: secret-key-base
name: rails
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: cloudsql-db-credentials
- name: DB_USER
valueFrom:
secretKeyRef:
key: username
name: cloudsql-db-credentials
- name: RAILS_ENV
value: production
- name: RACK_ENV
value: production
image: gcr.io/YOUR_APP/myapp:latest
imagePullPolicy: Always
name: rails
ports:
- containerPort: 3000
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
- command:
- /cloud_sql_proxy
- -instances=YOUR_APP_DB:northamerica-northeast1:myappdb=tcp:5432
- -credential_file=/secrets/cloudsql/credentials.json
image: gcr.io/cloudsql-docker/gce-proxy:1.16
imagePullPolicy: IfNotPresent
name: cloudsql-proxy
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /secrets/cloudsql
name: cloudsql-instance-credentials
readOnly: true
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: cloudsql-instance-credentials
secret:
defaultMode: 420
secretName: cloudsql-instance-credentials
Service
Services description: https://kubernetes.io/docs/concepts/services-networking/service/
apiVersion: v1
kind: Service
metadata:
name: rails
labels:
app: rails
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 3000
protocol: TCP
selector:
app: myapp
Let’s deploy!
Our last step - let’s run our deployments for app and service:
Let’s commit and push changes, and run make script:
~ ❯❯❯ make build push
Let’s process our main deployment:
~ ❯❯❯ kubectl apply -f k8s/deployment.yml
Let’s deploy our service and provide public acccess to the service:
~ ❯❯❯ kubectl apply -f k8s/service.yml
That’s it! Run/deploy/test and stay tuned.