【k8s學習】在minikube上布署MongoDB和MongoExpress

【本文目標】
在minikube上部署MongoDB和Mongo-express,MongoDB作為內部項目(internal service),Mongo-express會連接到Mongo服務上,Mongo-express會對外暴露。

注:本文用到的yaml配置文件有大神在git上已經上傳了,可以直接使用,github地址:https://github.com/Einsteinish/mongo-mongoexpress-minikube

【前置文章】

【運行環(huán)境 】

  • MacOS
  • minikube version: v1.25.2
  • hyperkit: 0.20200908
    (--vm-driver可以是docker或hyperkit,在啟動minikube以及部署mongo db上都沒有問題,這里用hyperkit的主要原因是docker在MacOS系統(tǒng)上minikube對外暴露服務有點問題。詳見第3.5章節(jié)。)

1. 架構

用到的Component:

  • 2個Deployment / Pod
  • 2個Service
  • 1個ConfigMap
  • 1個Secret
架構:
架構

可以看到:

  • 2個Deployment / Pod:即MongoDB和Mongo-express
  • 2個Service:internal service(MongoDB)和external service(Mongo-express),外部用戶可以用Node的IP+external Service的Port訪問到Mongo-express,進而連接到internal service中的MongoDB。
  • 1個ConfigMap,用來配置MongoDB的地址:DB Url,供Mongo-express的Deployment.yaml當作環(huán)境變量讀取。
  • 1個Secret,用來配置MongoDB的用戶名(DB User)和密碼(DB Pwd),供Mongo-express的Deployment.yaml當作環(huán)境變量讀取。
運行環(huán)境

運行在minikube上,并且集群中沒有部署項目:


image.png

2. MongoDB部署

2.1 MongoDB docker hub

首先我們想要運行的是MongoDB最新版,docker hub地址:https://hub.docker.com/_/mongo
下拉頁面,可以看到默認的Port是:27017。

image.png

其次是查看環(huán)境變量,可以看到我們需要定義MongoDB的username和password,變量名稱為:MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD

image.png

2.2 定義Secret

我們在定義的時候,不會直接把username和password在mongodb-deployment.yaml中hardcode,因為mongodb-deployment.yaml通常會checkin到Git repository,如果直接寫那么所有人都能看到,這樣不安全。所以我們會使用Kubernetes的Secret組件,這樣用戶名和密碼就存在Kubernetes中,而不是Git repository中。

基于以上原因,我們先定義Secret組件,配置文件叫:mongodb-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
type: Opaque
data:
  mongo-root-username: dXNlcm5hbWU=
  mongo-root-password: cGFzc3dvcmQ=
  • apiVerionkind這兩行聲明是必須的,因為要定義Secret組件,那么kind就是Secret。
  • metadata中的name是Secret運行后的名字,可以自由定義。
  • type是Secret的type,Opaque是最常見的type,base64編碼格式的Secret,用來存儲密碼、秘鑰等。
  • data就是Secret的內容。data需要用base64加密后,再cp到這里。

我們可以用命令先把想要的明文加密成密文后,再放到上述的data中。

image.png

通過mongodb-secret.yaml先創(chuàng)建出Secret組件:

kubectl apply -f mongodb-secret.yaml

可以看到Secret組件創(chuàng)建成功:
image.png
2.3 開始定義mongodb-deployment.yaml文件

在Deployment文件中會引用到2.2中定義的Secret。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mondodb-deployment
  labels:
    app: mongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo
        ports:
        - containerPort: 27017
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-username
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-password

通過配置文件創(chuàng)建deployment:
image.png

可以看到mongo-db的Pod運行起來了:
image.png
2.4 定義MongoDB的internal service:

我們接著上述的Deployment定義,把MongoDB service也放在同一個文件中,用---分割開(上述mongo-deployment.yaml改名為mongodb.yaml):

---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
  - protocol: TCP
    port: 27017
    targetPort: 27017
  • apiVersionkind:最前面的兩行聲明,kind表示定義的組件是Service。
  • metadataname表示Service的名稱,可自行取名。
  • selector:和上述Deployment定義中的Pod聯(lián)系起來。(selector中的和上述template中的metadata中的labels對應)。
  • portsport表示Service的端口,targetPort表示Pod中Container容器的端口,與上述的Deployment中的Pod中的Container的containerPort要一致。
    port和targetPort可以不一致。

通過mongodb.yaml創(chuàng)建Service,可以看到它會先提示Deployment沒有改動,然后再提示Service創(chuàng)建了。


image.png

查看Service,這里的Port指的是上述定義的port(即Service自己對外暴露的端口),不是targetPort:
image.png

查看Pod和Service具體信息,可以看到Service的Endpoint信息,指向的IP是Pod的IP:


image.png
【總結】至此,MongoDB相關的組件都創(chuàng)建好了:
  • 我們先創(chuàng)建了Secret組件,用來存放username和password。
  • 再創(chuàng)建了Deployment,在用戶名和密碼這塊,引用了Secret組件中的key。在Deployment中定義了mongodb的Pod,并且聲明了container容器的Port=27017。
  • 最后在和Deployment定義的同一個配置文件中定義了Service,通過selector來聯(lián)系Deployment中的Pod,通過Ports中的targetPort來聯(lián)系Deployment中的Pod中的Container port。并且同時也通過Ports中的port來暴露自身的端口號,同樣是27017。
    image.png

3. MongoDB-express部署

3.1 MongoDB-express docker hub

MongoDB-express docker hub地址:https://hub.docker.com/_/mongo-express

可以下拉查看基礎信息,默認的port為:
image.png

部署MongoDB-express需要的信息:
image.png
  • MongoDB地址(即internal service):ME_CONFIG_MONGODB_SERVER
  • 用戶名:ME_CONFIG_MONGODB_ADMINUSERNAME
  • 密碼:ME_CONFIG_MONGODB_ADMINPASSWORD
3.2 定義ConfigMap

上述三個變量(MongoDB地址,用戶名和密碼),其中用戶名和密碼我們可以從Secret組件中讀?。ú榭?.2章),剩下來的MongoDB地址,沒有必要加密,但為什么不放在mongodb-express.yaml中是因為,可能MongoDB以后換地址了,那么作為讀取他的mongodb-express項目,不想要重新打包并部署,所以我們使用組件ConfigMap來定義MongoDB地址。

新建配置mongodb-configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongodb-configmap
data:
  database_url: mongodb-service

創(chuàng)建ConfigMap組件:
image.png

查看ConfigMap:
image.png
3.3 定義MongoDB-express Deployment:

新建mongodb-express.yaml文件,用來定義Deployment和Service,首先是Deployment,可以看到定義了Pod中的容器的containerPort為8081,三個變量其中用戶名和密碼從Secret組件中讀?。╲alueFrom定義的是secretKeyRef),而server信息,是從ConfigMap組件中讀?。╲alueFrom定義的是configMapKeyRef。)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-express
  labels:
    app: mongo-express
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo-express
  template:
    metadata:
      labels:
        app: mongo-express
    spec:
      containers:
      - name: mongo-express
        image: mongo-express
        ports:
        - containerPort: 8081
        env:
        - name: ME_CONFIG_MONGODB_ADMINUSERNAME
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-username
        - name: ME_CONFIG_MONGODB_ADMINPASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-password
        - name: ME_CONFIG_MONGODB_SERVER
          valueFrom:
            configMapKeyRef:
              name: mongodb-configmap
              key: database_url

創(chuàng)建Deployment:
image.png

可以看到mongodb-express的Pod運行了:
image.png
3.4 定義MongoDB-express的external service

我們在上述的mongodb-express.yaml中追加Service組件的定義,用---分隔,這里和上述定義mongodb的internal service略有不同的是,我們在mongodb-express中需要定義external service,以便外部的客戶可以通過瀏覽器訪問express dashboard頁面。所以我們在spec中需要額外定義service的type為LoadBalancer,表示給這個service一個外部的IP以便可以接收外部的請求。

注:內部的internal service沒有定義type,不定義type的時候,默認為ClusterIP,也是load balanced,即如果有兩個mongodb的Pod,我們訪問mongo-service,那么也會做負載均衡跳到兩個Pod中的一個。

所以type定義為LoadBlancer是在負載均衡的基礎上再做了暴露Service IP的作用。

另外,除了Service自身的端口port,以及需要轉發(fā)的Pod中的container的端口targetPort外,我們還需要定義第三種端口,即nodePort,這個端口表示的意思是給外部IP地址訪問時用的端口,一般來說范圍在30000~32767之間。在例子中,我們定義為30000:

---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-express-service
spec:
  selector:
    app: mongodb-express
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081
      nodePort: 30000

創(chuàng)建Service:
image.png

查看Service:

  • mongodb的internal service類型為ClusterIP,它會分配內部IP(cluster-ip,集群內IP,即內部IP)給這個Service。并且如果是internal service,port這一列顯示的就是它的端口
  • mongo-express-service的external service類型則為LoadBalancer,同樣的也會分配內部IP,除此之外,還會分配外部IP(external-ip,即Node本身的IP)給這個Service。如果是真實的kubernetes集群,這里也會顯示IP格式的地址,因為我跑在minkube上,所以有一點不一樣,顯示的是<pending>(表示還沒有外部IP,在minikube上需要額外配)。并且如果是LoadBalancer類型的Service,port這里會有兩個端口,前者是Service的端口,即cluster-ip的端口,后者是外部端口,即external-ip的端口。
    image.png

如上述所說,在minikube的external-ip中,顯示的是<pending>,表示還沒有分配外部IP,所以我們需要手動分配:
這個命令表示給service mongo-express-service分配一個public的IP地址,這個是minikube only的,所以你看到的是minikube的命令,而不是kubectl:

minikube service mongo-express-service

3.5 MacOS,vm-driver=docker,對外暴露有點問題

我的系統(tǒng)是MacOS,然后minikube選擇的虛擬driver是docker,在service expose的過程中出現了一些問題,發(fā)現命令停在了以下狀態(tài)并且無法正確expose:
image.png

網上看了一圈說是MacOS上的minikube用docker作虛擬driver的時候,network會有點問題,參考:https://github.com/kubernetes/minikube/issues/11193,解決辦法是可以安裝https://github.com/yuzhaopeng/minikube-mac-network,中文文檔有:https://zhuanlan.zhihu.com/p/446915171,(這個解決辦法我沒有試過)。

**但我覺得太麻煩了,直接改個虛擬driver,用hyperkit代替docker。

3.6 安裝新的vm-driver:hyperkit

hyperkit是輕量級虛擬化工具包。先安裝hyperkit:**

brew install hyperkit

安裝完畢:
image.png

啟動minikube,這次使用的是vm-driver=hyperkit,而不是docker:

minikube start --vm-driver=hyperkit

3.7 使用hyperkit作為vm-driver后,再次啟動,并對外暴露服務

啟動好了之后,再重新kubectl apply -f <filename>上面的文件,本文用到的文件有大神在git上已經上傳了,可以直接使用,git地址:https://github.com/Einsteinish/mongo-mongoexpress-minikube

在組件(secret, configmap, deployment, pod, replicaset, service)都創(chuàng)建好了之后,再次使用minikube的命令進行對外暴露:

minikube service mongo-express-service --url

返回:http://192.168.64.4:30000

使用minikube service命令查看所有的服務:

minikube service list

image.png

使用瀏覽器打開:
image.png

4. 測試

在mongo-express UI頁面上新增一個database:
image.png

這個請求:首先會跳到Mongo Express External Service --> 然后再轉發(fā)到Mongo Express Pod上 --> 再通過Pod上的url轉到Mongo DB Internal Serivce --> 再轉發(fā)到Mongo DB Pod


參考:
https://www.youtube.com/watch?v=X48VuDVv0do
https://www.bogotobogo.com/DevOps/Docker/Docker_Kubernetes_MongoDB_MongoExpress.php
https://github.com/Einsteinish/mongo-mongoexpress-minikube

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容