Nic Lin's Blog

喜歡在地上滾的工程師

從零搭建,如何讓 Rails 跑在 Kubernetes(k8s)(二)

這篇會將上一篇容器化的 Rails App 放到 k8s 裡面運行。

請參考上一篇 從零搭建,如何讓 Rails 跑在 Kubernetes(k8s)(一)

開發前準備

懶人安裝指令:

brew install kubernetes-cli && brew cask install minikube

輸入 kubectl version 檢查版本

Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.3", GitCommit:"435f92c719f279a3a67808c80521ea17d5715c66", GitTreeState:"clean", BuildDate:"2018-11-27T01:14:37Z", GoVersion:"go1.11.2", Compiler:"gc", Platform:"darwin/amd64"}

如果有出現

Unable to connect to the server: dial tcp 192.168.99.100:8443: i/o timeout

或是

The connection to the server localhost:8080 was refused - did you specify the right host or port?

這邊先暫時不用擔心,因為還沒有啟動 k8s 叢集,可以先忽略訊息。

接下來確認 minikube 的版本

minikube version

# minikube version: v0.30.0

都沒問題就可以輸入 minikube start 啟動 k8s 叢集,這裡需要花一點時間,依照電腦規格及網路速度不同會有不同的等待時間,第一次啟動會比較久一些,請耐心等候 XD

Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Downloading Minikube ISO
 140.01 MB / 140.01 MB [============================================] 100.00% 0s
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.

啟動完後,可以透過 minikube status 指令獲得當前狀態

minikube: Running
cluster: Running
kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100

如果不放心,也可以透過 minikube ssh 連進機器看一下

連進去之後輸入 docker ps,可以看到內部跑大量的 docker container,這就是 k8s 裡面的架構了。

輸入 exit 離開(這時候 k8s 還是正常運行在背景的,不需重新 start)

將上一章節的 Rails app docker image 上傳至 docker hub 雲端

等等建立 container 時要從雲端拉,所以這邊要先上傳。

打包指令

docker build -t niclin/rails-app:v1 .

Push 上去

docker push niclin/rails-app:v1

這邊每個人帳號名稱不一樣,像我的就是 niclin ,要記得替換,如果不知道怎麼操作,可以參考Docker 官方的文件

建立 Database service

先建立 secrets

下方第三條指令的 secret-key-base 是用 rails 的 rake secret 生成

kubectl create secret generic db-user-pass --from-literal=password=mypass

kubectl create secret generic db-user --from-literal=username=postgres

kubectl create secret generic railsapp-secrets --from-literal=secret-key-base=50dae16d7d1403e175ceb2461605b527cf87a5b18479740508395cb3f1947b12b63bad049d7d1545af4dcafa17a329be4d29c18bd63b421515e37b43ea43df64

在專案目錄下新建檔案,路徑為 kube/deployments/db.yaml(這邊要自己創建資料夾)

檔案內容可以直接複製,這邊沒有要修改的部分

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  generation: 1
  labels:
    run: db
  name: db
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      run: db
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: db
    spec:
      containers:
      - env:
        - name: DATABASE_USER
          value: "postgres"
        - name: DATABASE_PASSWORD
          value: "mypass"
        - name: POSTGRES_DB
          value: "rails-app-db"
        - name: PGDATA
          value: "/var/lib/postgresql/data"
        image: postgres
        imagePullPolicy: Always
        name: db
        ports:
        - containerPort: 5432
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

這裡雖然可以直接透過 cli 下指令生成相關 service,不過為了避免看教學看到暈掉,這邊直接用檔案管理進行操作,輸入以下指令即可建立

kubectl create -f kube/deployments/db.yaml

接下來查看 pod 狀態

kubectl get pods

要等 STATUS 變成 Running 才算啟動完成,這邊的指令可以加 -w 參數直接觀察變動。

確定狀態啟動後,我們將 database expose 出去

kubectl expose deployment db

這時候我們可以查看是不是有新建立一個 Database 的 service 呢

kubectl get services

建立 Rails App service

在專案目錄下新建檔案,路徑為 kube/deployments/rails.yaml (這邊要自己創建資料夾)

這邊要注意的是,要把 niclin/rails-app:v1 的 image 來源換成你自己 dokcer hub 上的哦(要拉我的也是可以啦)

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  generation: 1
  labels:
    run: app
  name: app
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      run: app
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: app
    spec:
      containers:
      - command:
        - rails
        - s
        - -p
        - "3000"
        - -b
        - 0.0.0.0
        image: niclin/rails-app:v1
        imagePullPolicy: IfNotPresent
        env:
        - name: DATABASE_URL
          value: "postgres"
        - name: DATABASE_NAME
          value: "rails-app-db"
        - name: DATABASE_PORT
          value: "5432"
        - name: DATABASE_USER
          valueFrom:
            secretKeyRef:
              name: "db-user"
              key: "username"
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: "db-user-pass"
              key: "password"
        - name: SECRET_KEY_BASE
          valueFrom:
            secretKeyRef:
              name: "railsapp-secrets"
              key: "secret-key-base"
        name: app
        ports:
        - containerPort: 3000
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

接著輸入指令創建 service

kubectl create -f kube/deployments/rails.yaml

在跑 rake db:migrate 之前,要先拿到 pod name

kubectl get pods

這邊也要等 STATUS 變成 Running 才能繼續下面的 migrate 哦

kubectl exec -it POD_NAME rails db:migrate

# 舉例: kubectl exec -it app-655469bcc8-x9chm rails db:migrate
# 每個人不一樣喔,要自己看自己的 pod name

將 app expose 出去。

kubectl expose deployment app --type=NodePort

在最後這個步驟,沒什麼好說的了,就是打開瀏覽器來看辛苦的成果了,沒意外會看到你在 minikube 分配到的 IP 跑起的 Rails server 畫面了!

minikube service app

最後,你也可以透過 minikube dashboard 指令來查看詳細內容

後記:刪除 Pod 的方式

參考 Kubernetes pod gets recreated when deleted

To list all deployments

kubectl get deployments --all-namespaces

Then to delete the deployment:

kubectl delete -n NAMESPACE deployment DEPLOYMENT

# 我的範例:kubectl delete -n default deployment app

參考來源

comments powered by Disqus