【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

【前置文章】

  • 【k8s学习】Kubernetes学习——核心组件和架构
  • 【k8s学习】minikube、kubectl、yaml配置文件的介绍

【运行环境 】

  • 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上,所以有一点不一样,显示的是(表示还没有外部IP,在minikube上需要额外配)。并且如果是LoadBalancer类型的Service,port这里会有两个端口,前者是Service的端口,即cluster-ip的端口,后者是外部端口,即external-ip的端口。
    image.png

如上述所说,在minikube的external-ip中,显示的是,表示还没有分配外部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 上面的文件,本文用到的文件有大神在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和MongoExpress)