Giaosucan's blog - Chia sẻ kiến thức theo cách bá đạo

Ticker

20/recent/ticker-posts

Frequency Tribe Part 2 - Infra deployment

Tiếp tục bài 1, bài này đi sâu hơn về infrastructure và deployment của FrequencyTribe

Kiến trúc Kubernetes | ./blogd

Như đã trình bày trong architect ở bài trước, frequencyTribe bao gồm tập hợp các app bao gồm api backend, join, secure và admin app, database. Ban đầu các app này được deploy trên các server droplet của Digital Ocean. Tuy nhiên cách deploy không giải quyết được 1 số yêu cầu sau

Hệ thống cần đảm bảo High Avaiblity và Autoscaling. Nếu số lượng request tăng cao hay giảm đi, phải tự động scale up or scale down

Tự động launch ra server mới khi server cũ gặp vấn đề

FrequencyTribe có nhiều client, mỗi khi có client mới, phải build up một infa mới cho từng client. Đây là kiến trúc single tenant. Mỗi khách hàng có infrastructure riêng biệt, database riêng biệt

Single vs multi-tenant SAAS | Hacker Noon

Ngoài ra, mỗi app instance deploy lên cho từng khách hàng sẽ có những thông tin khác nhau ví dụ như domain name, các thông tin hiển thị trên GUI cũng khác nhau. Ví dụ chatbot deploy cho khách hàng A sẽ display message "Hello A" còn deploy cho khách hàng B sẽ display message "Hello B".

Cuối cùng, hệ thống được chuyển đổi sang K8S

Database sử dụng RDS của DO có khả năng replicas. App Telegram Bot sử dụng datase MySQL. Đây là một nhược điểm vì tồn tại 2 loại RDS trong hệ thống (Nguyên nhân team Bot và team App đã không thống nhất về solution từ đầu) dẫn tới cần phải thực hiện migrate từ MySQL sang PostgresSQL

Việc deploy lên K8S vẫn được thực hiện theo cách truyền thống.

Application được build thành docker image rồi deploy lên k8s pod, là sử dụng ingress controller, và ELB

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: __DOMAIN__-api
  namespace: __DOMAIN__
  labels:
    lab: __DOMAIN__-api
spec:
  replicas: 1
  selector:
    matchLabels:
      lab: __DOMAIN__-api
  template:
    metadata:
      labels:
        lab: __DOMAIN__-api
    spec:
      imagePullSecrets:
        - name: tribers
      volumes:
        - name: app-config
          configMap:
            name: app-config
      containers:
        - name: __DOMAIN__-api
          image: tribers/common-api:__TAG__
          imagePullPolicy: Always
          volumeMounts:
            - mountPath: /app/.env
              name: app-config
              subPath: .env
          ports:
            - containerPort: 80
-----
kind: Service
metadata:
  name: __DOMAIN__-api
  namespace: __DOMAIN__
  labels:
    lab: __DOMAIN__-api
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    lab: __DOMAIN__-api

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
  name: __DOMAIN__-api
  namespace: __DOMAIN__
spec:
  tls:
    - hosts:
      - api.__DOMAIN_URL__
      secretName: api-tls
  rules:
    - host:  api.__DOMAIN_URL__
      http:
        paths:
          - backend:
              serviceName: __DOMAIN__-api
              servicePort: 80

Mỗi khi có khách hàng mới, sẽ tạo ra một namespace riêng cho client đó, replace DOMAIN bằng domain của khách hàng rồi deploy

Các thông tin về configuration trong code được lưu trong file .env ví dụ DB config, URL, KEY sẽ được lưu trong k8S configmap và mount vào k8s pod

Ví dụ một khách hàng là tribers sẽ được deploy một single tenant với infra như ở dưới

giaosucan@giaosucan:~/Freelancer$ kubectl get pods -n tribers
NAME                              READY   STATUS    RESTARTS   AGE
rabbitmq-b755f69c5-lkhz8          1/1     Running   0          29d
redis-fd794cd65-6vsv2             1/1     Running   0          29d
tribers-admin-69f455d856-v5chk    1/1     Running   0          5d8h
tribers-api-78c79c689b-zghtn      1/1     Running   0          4d21h
tribers-bot-57c565c974-hrdzx      1/1     Running   0          13d
tribers-celery-56d9bcb879-r4tgt   1/1     Running   0          4d21h
tribers-join-6fc6656758-k2466     1/1     Running   0          2d17h
tribers-secure-7c84fb9cdb-7bj2j   1/1     Running   0          5d8h

giaosucan@giaosucan:~/Freelancer$ kubectl get configmap -n tribers
NAME               DATA   AGE
app-config         1      28d

Việc deploy này được thực hiện tự động bằng Jenkins jobs

Còn về việc configuration cho từng khách hàng, một api được implement và deploy riêng biệt chuyên để thực hiện việc này

giaosucan@giaosucan:~/Freelancer$ kubectl get pods -n config-staging
NAME                          READY   STATUS    RESTARTS   AGE
api-config-65969699d4-m9pzp   1/1     Running   0          7d18h

Chức năng chính của api này là lưu những thông tin configuration mà admin tạo ra lưu vào DB.

Ví dụ dưới là một sample thông tin configuration

Thông tin này được nhập bới admin và lưu trong db. Khi thực hiện deploy vd khách hàng A, API config được gọi từ Jenkins để get thông tin config dưới dạng file json. Và code sẽ read những thông tin này để hiện thị specific cho khách hàng A

Như vậy, chỉ cần dùng 1 code base duy nhất để deploy cho nhiều khách hàng khác nhau. Dựa vào thông tin configuration để display info specific cho từng khách hàng

Đăng nhận xét

0 Nhận xét