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

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

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
0 Nhận xét