美文网首页【Kubernetes】
【k8s学习】在minikube上布署MongoDB和Mongo

【k8s学习】在minikube上布署MongoDB和Mongo

作者: 伊丽莎白2015 | 来源:发表于2022-06-20 11:48 被阅读0次

    【本文目标】
    在minikube上部署MongoDB和Mongo-express,MongoDB作为内部项目(internal service),Mongo-express会连接到Mongo服务上,Mongo-express会对外暴露。

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

    【前置文章】

    【运行环境 】

    • MacOS
    • minikube version: v1.25.2
    • hyperkit: 0.20200908
      (--vm-driver可以是docker或hyperkit,在启动minikube以及部署mongo db上都没有问题,这里用hyperkit的主要原因是docker在MacOS系统上minikube对外暴露服务有点问题。详见第3.5章节。)

    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当作环境变量读取。
    • 1个Secret,用来配置MongoDB的用户名(DB User)和密码(DB Pwd),供Mongo-express的Deployment.yaml当作环境变量读取。
    运行环境

    运行在minikube上,并且集群中没有部署项目:


    image.png

    2. MongoDB部署

    2.1 MongoDB docker hub

    首先我们想要运行的是MongoDB最新版,docker hub地址:https://hub.docker.com/_/mongo
    下拉页面,可以看到默认的Port是:27017

    image.png

    其次是查看环境变量,可以看到我们需要定义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先创建出Secret组件:

    kubectl apply -f mongodb-secret.yaml

    可以看到Secret组件创建成功: 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
    
    通过配置文件创建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联系起来。(selector中的和上述template中的metadata中的labels对应)。
    • portsport表示Service的端口,targetPort表示Pod中Container容器的端口,与上述的Deployment中的Pod中的Container的containerPort要一致。
      port和targetPort可以不一致。

    通过mongodb.yaml创建Service,可以看到它会先提示Deployment没有改动,然后再提示Service创建了。


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

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


    image.png
    【总结】至此,MongoDB相关的组件都创建好了:
    • 我们先创建了Secret组件,用来存放username和password。
    • 再创建了Deployment,在用户名和密码这块,引用了Secret组件中的key。在Deployment中定义了mongodb的Pod,并且声明了container容器的Port=27017。
    • 最后在和Deployment定义的同一个配置文件中定义了Service,通过selector来联系Deployment中的Pod,通过Ports中的targetPort来联系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.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
    
    创建ConfigMap组件: image.png 查看ConfigMap: image.png
    3.3 定义MongoDB-express Deployment:

    新建mongodb-express.yaml文件,用来定义Deployment和Service,首先是Deployment,可以看到定义了Pod中的容器的containerPort为8081,三个变量其中用户名和密码从Secret组件中读取(valueFrom定义的是secretKeyRef),而server信息,是从ConfigMap组件中读取(valueFrom定义的是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
    
    创建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,以及需要转发的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
    
    创建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,对外暴露有点问题
    我的系统是MacOS,然后minikube选择的虚拟driver是docker,在service expose的过程中出现了一些问题,发现命令停在了以下状态并且无法正确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)都创建好了之后,再次使用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 --> 然后再转发到Mongo Express Pod上 --> 再通过Pod上的url转到Mongo DB Internal Serivce --> 再转发到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

    相关文章

      网友评论

        本文标题:【k8s学习】在minikube上布署MongoDB和Mongo

        本文链接:https://www.haomeiwen.com/subject/zsurvrtx.html