IT 铁人赛 k8s 入门30天 -- day8 Demo Project: MongoDB and MongoExpress

前言

本篇是采用一个 MongoDB 结合 MongoExpress 应用当作范例

来实际操作布署 app 到 k8s 的案例

MongoDB 是一个以文件为基底储存类型的资料库

MongoExpress 是一个网页版本用来管理 MongoDB 的後台管理系统

预计布署结构

MongoDB 在布署上, 不希望被外部存取

因此, 会使用 Internal Service 类型

并且需要被其他再同一个 Cluster 内的 Service 透过 DB Url 的方式存取

所以会使用 ConfigMap 来设定 DB Url

并且会用 Secrets 来放置验证用的资料库使用者帐密

MongoExpress 在布署上, 会透过网页让权限的使用者操作

属於 External Service 类型

而在 Deployment 会去存取 建制 MongoDB 所设定的 ConfigMap 与 Secrets

预计布署结构如下:

预计 Request flow 如下图:

mongodb 部份

基础 mongodb-deployment.yaml 撰写如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb-deployment
  labels:
    app: mongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo

注意的是 这边是用 template 的方式来设定 Pod 内部 Container 的运行蓝图

template:
  metadata:
  labels:
    app: mongodb
  spec:
    containers:
    - name: mongodb
      image: mongo

然而, 这样写没有写入用来验证的 root user 跟 root password

从 dockerhub mongo image repository 内容

说明在 environment 代入 MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD 就会设定好上面两个选项

在这个范例, 笔者先建立 Secret 然後在 Deployment 使用 Reference 方式去引用

建立 mongo-secret.yaml 如下:

apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
type: Opaque
data:
  mongo-root-username: dXNlcm5hbWU=
  mongo-root-password: cGFzc3dvcmQ=

注意的是, 这边的 Opaque 是用来储存 key value 对应的资料形式

mongo-root-username, mongo-root-password 是分别用 username, password 做 base64 编码做出来的字串

可以用以下方式产生

echo -n 'username' | base64

重要的是, 由於需要在 mongodb-deployment.yaml 中使用 mongo-secret.yaml 的值

mongo-secret.yaml 必须先发布才能发布 mongodb-deployment.yaml

发布 mongo-secret.yaml

kubectl apply -f mongo-secret.yaml

而新的 mongodb-deployment.yaml 更新如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb-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

发布 mongodb-deployment.yaml

kubectl apply -f mongodb-deployment.yaml

设定 Service 给 mongodb pod

在这个范例中, 笔者把 Service 跟 Deployment 利用以下的语法写在同一个档案

--- 是yaml中用来分隔多个 doucment 的语法

所以更新後的结构会如下:

... Deployment 设定 
---
... Service 设定

只看 mongodb-deployment.yaml Service的部份如下

apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

关键的部份:
1 selector 要跟 Deployment 设定 Pod 的部份一致, 才有办法关联 Service 到对应的 Pod

2 targetPort: 是指 Container 的 Port 也就是前面 template 设定的 containerPort

3 port: 这边是开发给其他 Service 沟通的 Port

4 预设的 Type 是 ClusterIP 也就是 Internal Service 外部无法直接透过 IP 存取

发布 mongodb-deployment.yaml

kubectl apply -f mongodb-deployment.yaml

验证 Service 有应用到 Pod 上面

验证 kubectl describe 部份的 EndPoint IP 与 kubectl get pod -o wide 部份的 IP 是相同

mongo-express 部份

基础 mongo-express-deployment.yaml 如下

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

从 dockerhub mongo-express 官方 image 内容

代表需要设定3个环境变数给 mongo-express 运行

ME_CONFIG_MONGODB_ADMINUSERNAME, ME_CONFIG_MONGODB_ADMINPASSWORD, ME_CONFIG_MONGODB_SERVER

前面两个用来做 credential, 第3个变数用来指定连结的资料库位址

而在之前的 mongo-secret.yaml 中, 设定的mongo-root-username, mongo-root-password 刚好就是这两个

所以只需要在设定好一个 ConfigMap 来储存 ME_CONFIG_MONGODB_SERVER 即可

设定 mongodb-configmap.yaml 如下:

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

关键的部份, 这里的 database_url 是使用之前发布的 mongodb-service 这个 Service 名称来当 url
发布 mongodb-configmap.yaml

kubectl apply -f mongodb-configmap.yaml

更新 mongo-express-deployment.yaml 如下:

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

发布 mongo-express-deployment.yaml

kubectl apply -f mongo-express-deployment.yaml

设定 External Service

同样的这样也会设定 Service 在 Deployment 同一个档案使用分隔线的方式来撰写

所以更新後的结构会如下:

... Deployment 设定 
---
... Service 设定

只看 Service 的部份如下:

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

关键的部份:

1 因为是 External Service 要设定 type 是 LoadBalancer

2 因为是 External Service 要额外设定 nodePort 范围是 30000~32767

kubectl apply -f mongo-express-deployment.yaml

注意的是 在 type 是 LoadBalancer 的部份 EXTERNAL_IP 显示 pending 代表还没拿到实体外部 IP

而 minikube 这边比较特别, 需要使用以下指令才能拿到 EXTERNAL_IP

minikube service $service_name

以本篇范例来说就是以下指令:

minikube service mongo-express-service

然後就可以用浏览器打开对应的 URL 做操作, 如下:


<<:  【Day11】- 递回Recursion

>>:  【Day 07】开始谈论主程序啦!!!

IF EXISTS (SELECT * FROM table where 1=2)

--哇.这是什麽资料库,我怎麽没这个语法. drop table if exists delme c...

Day 9 整理重复烦人的程序码!

该文章同步发布於:我的部落格 昨天我们实作了把 example 给拆开,并且让整个测试更具备逻辑。...

Unity自主学习(十八):认识Unity介面(9)

昨天看完了"Transform"栏位之後,接下来"属性检视区"...

18 在 Phoenix 1.6 安装 tailwindcss

这一篇可能满好用的 安装 Tailwind 这边建议稍微看一次 Tailwind 官网的安装说明 会...

Vue Slot 的插槽基本用法

脑子就像手机充电一样,充太饱也不会让手机变快,充不够就後继无力。 今天要介绍的是据说及将会在 Vu...