Last year I wrote about using docker-compose to have a test/development environment similar to your production environment (you can check the post here)
My environment kept growing and becoming more complex, and I started using docker swarm to deploy the applications, and after some time I started using kubernetes, I’ve learnt something about kubernetes in the way, and I want to share some of that with you now.
You’ll use everything that docker can offer, but we’ll use another tool to “orchestrate” our applications and services.
In this first post it will not appear to have many advantages, but we’ll see a lot more of that in the next posts.
I’ll assume you have at least a local kubernetes environment working, there are lots of tutorials in the internet… For development testing I’m currently using minikube, but anything here works without problems with any other implementation.
One thing I learned, is that even thou kubernetes like pure docker allows you to run pods/services/deployments/… with command lines, it is really easy to loose yourself and forget all the commands that you used to get to that point, so to prevent that, we’ll always create one yaml file, and apply it to create and change resources, and if we need, we delete a resource and recreate it…
I’ll start showing the command lines, but will followup with the yaml right after it.
For simplicity, I’ll run the same rails sample app from the previous sample but now using kubernetes.
I’ll also start running only the rails app right now for simplicity, we’ll build a more complex environment in the next posts.
A pod in kubernetes is similar to a container in docker, it is a isolated environment where your application will run with the specified image.
Assuming you have a local MYSQL installed, and a local redis installed, and that your local IP is 192.168.0.15 (that is my IP right now) you can run your first pod with this command:
kubectl run rails-sample --image=urubatan/urubatan_rails_docker_sample:1.0.0 --env="DATABASE_HOST=192.168.0.15" --env="DATABASE_USERNAME=root" --env="DATABASE_PASSWORD=password" --port=3000 --replicas=1 -- rails s -b 0.0.0.0 -p 3000
And we can check if everything is running with this other command:
kubectl get all
The output should be something similar to this:
NAME READY STATUS RESTARTS AGE pod/rails-sample-6fff95bd98-hpb5s 1/1 Running 0 26s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.152.183.1443/TCP 13d NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/rails-sample 1/1 1 1 26s NAME DESIRED CURRENT READY AGE replicaset.apps/rails-sample-6fff95bd98 1 1 1 26s
You’ll notice that the command created a deployment, that deployment is backed by a replica set, and the replica set created a pod.
Using YAML it is possible to create a “naked” pod, but that is not a good practice, since if for any reason the pod die, kubernetes will not restart that, but if it is part of a deployment, the pod will be correctly re-spawned.
Deployments also help on upgrades, if we just update the deployment with a new image version, it will start new pods before stopping the old ones, making our app availability a lot better than if you need to stop it before starting a new container.
Now, lets see how to create the same deployment using YAML, and we can use kubernetes to do that, just run the command:
kubectl get deployment.apps/rails-sample -o=yaml
The output should be something similar to this:
apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: "2020-01-02T17:21:26Z" generation: 1 labels: run: rails-sample name: rails-sample namespace: default spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: run: rails-sample strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: creationTimestamp: null labels: run: rails-sample spec: containers: - args: - rails - s - -b - 0.0.0.0 - -p - "3000" env: - name: DATABASE_HOST value: 192.168.0.15 - name: DATABASE_USERNAME value: root - name: DATABASE_PASSWORD value: password image: urubatan/urubatan_rails_docker_sample:1.0.0 imagePullPolicy: IfNotPresent name: rails-sample ports: - containerPort: 3000 protocol: TCP resources: {} dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 status: {}
Your output probably has some more information since I’ve cleaned it up a bit here, the important thing is that saving this yaml to a file, you can then recreate the deployment with a simple kubectl apply -f <filename>
You can scale horizontally (meaning adding more pods to the deployment) in 3 ways:
- You can edit your YAML, changing the number of replicas, then do a kubectl apply -f <filename>
- You can run kubectl edit deployment.apps/rails-sample, change the number of replicas then save the file
- you can also run kubectl scale –replicas=3 deployment.apps/rails-sample
And if you run “kubectl get all” again, you’ll see the number of pods increased.
We are done with our first pod now, but if you came back here in a couple of days, we’ll see how to use a service to expose our service to the world, after that we’ll see how to autoscale our deployments based on cpu and/or memory usage, then some reverse proxy options (since I do not think that exposing your rails app directly to the world is a great idea).
I hope this post helped, and wait for the next ones…
If you have any questions or want some more details, please let me know in the comments.
2 thoughts on “Rails from “zero” to kubernetes – first pod”