• EggJS 云原生应用硬核实战(Kubernetes+Traefik+Helm+Prometheus+Grafana),提供 Demo


    介绍

    这是一个关于 Egg.js 应用上云☁️的示例,笔者所在的大前端团队的已应用于生产。

    CI/CD & DevOps & GitOps & HPA 等这里暂不做讨论,因为每一个点篇幅都很长。

    我这里的实验条件

    示例项目

    可直接做实验(文章写的再好,不如提供一个上云示例)

    GitHub: k8s-eggjs->点我

    GitHub: k8s-eggjs

    GitHub: k8s-eggjs

    这个示例,简单的提供了两个接口:

    /api/posts

    curl -X POST http://localhost:7001/api/posts --data '{"title":"post1", "content": "post1 content"}' --header 'Content-Type:application/json; charset=UTF-8'
    

    api/topics

    curl -X POST http://localhost:7001/api/topics --data '{"title":"topic1", "content": "topic1 content"}' --header 'Content-Type:application/json; charset=UTF-8'
    

    笔者也把这个项目部署到了

    上云实战

    (示例已提供,可直接做实验)

    Scripts

    package.json 这里简单调整为:

     "start": "egg-scripts start --workers=1 --title=egg-server-k8s-eggjs-promethues",
    

    最好是单进程启动,应用容器的编排完全交给 kubernetes。

    Egg 关于 K8S 部署的相关 issues

    Docker Image 准备

    文件位于 docker/Dockerfile.prod

    FROM node:15-alpine
    
    RUN ln -sf /usr/share/zoneinfo/Asia/ShangHai /etc/localtime
    RUN echo "Asia/Shanghai" > /etc/timezone
    
    COPY package.json /app/dependencies/package.json
    COPY yarn.lock /app/dependencies/yarn.lock
    RUN cd /app/dependencies 
        && yarn install --frozen-lockfile --registry=https://registry.npm.taobao.org 
        && yarn cache clean 
        && mkdir /app/egg 
        && ln -s /app/dependencies/node_modules /app/egg/node_modules
    
    COPY ./ /app/egg/
    
    WORKDIR /app/egg
    EXPOSE 7001
    
    CMD npm run start
    

    构建Image

    docker build -f docker/Dockerfile.prod -t k8s-eggjs-promethues:1.0.0 .  --no-cache
    

    打个 tag,笔者试验镜像是放在阿里云的(公司有自己的私有仓库)

    docker tag k8s-eggjs-promethues:1.0.0 registry.cn-shenzhen.aliyuncs.com/hacker-linner/k8s-eggjs-promethues:1.0.0
    

    推送到阿里云

    docker push registry.cn-shenzhen.aliyuncs.com/hacker-linner/k8s-eggjs-promethues:1.0.0
    

    Helm Chart(k8s-helm-charts)

    (示例项目已提供,可直接做实验)

    生成部署 Chart

    mkdir k8s-helm-charts && cd k8s-helm-charts
    helm create k8seggjs
    

    我们复制一份 k8seggjs/values.yaml 到外层与 k8seggjs 文件夹同级(k8s-helm-charts/values.yaml)。

    k8s-helm-charts/values.yaml做如下修改:

    replicaCount: 3 # 部署副本我用3个实例做负载均衡,保证服务可用
    
    image:
      repository: registry.cn-shenzhen.aliyuncs.com/hacker-linner/k8s-eggjs-promethues # 镜像变为刚上传
      pullPolicy: Always # 镜像拉取策略可直接用默认`IfNotPresent`
    
    # apiPort,metricsPort 默认模板没有,
    # 这里我对 template 里面的 ingress.yaml service.yaml deployment.yaml 文件做了相应改动
    service:
      type: ClusterIP
      apiPort: 7001 # 这个 API 服务的端口
      metricsPort: 7777 # 这个是 prometheus 所需的 metrics 端口
    
    # Ingress Controller,根据你的环境决定,我这里用的是 traefik
    ingress:
      enabled: true
      annotations:
        ingress.kubernetes.io/ssl-redirect: "true"
        ingress.kubernetes.io/proxy-body-size: "0"
        kubernetes.io/ingress.class: "traefik"
        traefik.ingress.kubernetes.io/router.tls: "true"
        traefik.ingress.kubernetes.io/router.entrypoints: websecure
      hosts:
        - host: k8seggjs.hacker-linner.com
          paths:
            - /
      tls:
        - secretName: hacker-linner-cert-tls
          hosts:
          
    # 做资源限制,防止内存泄漏,交给 K8S 杀掉然后重启,保证服务可用
    resources:
      limits:
        cpu: 100m
        memory: 128Mi
      requests:
        cpu: 100m
        memory: 128Mi
    

    创建部署 Namespace

    kubectl create ns k8seggjs
    

    使用 Helm 部署

    helm install k8seggjs ./k8seggjs -f values.yaml -n k8seggjs
    
    # 卸载:helm uninstall k8seggjs -n k8seggjs
    

    ServiceMonitor(k8s-prometheus)

    RBAC 设置

    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleList
    items:
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: prometheus-k8s-k8seggjs
        namespace: k8seggjs
      rules:
      - apiGroups:
        - ""
        resources:
        - services
        - endpoints
        - pods
        verbs:
        - get
        - list
        - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBindingList
    items:
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: prometheus-k8s-k8seggjs
        namespace: k8seggjs
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: prometheus-k8s-k8seggjs
      subjects:
      - kind: ServiceAccount
        name: prometheus-k8s
        namespace: monitoring
    

    指标 Service 设置

    apiVersion: v1
    kind: Service
    metadata:
      namespace: k8seggjs
      name: k8seggjs-metrics
      labels:
        k8s-app: k8seggjs-metrics
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/scheme: http
        prometheus.io/path: /metrics
        prometheus.io/port: "7777"
    spec:
      selector:
        app.kubernetes.io/name: k8seggjs
      ports:
      - name: k8seggjs-metrics
        port: 7777
        targetPort: 7777
        protocol: TCP
    

    ServiceMonitor 设置

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      name: k8seggjs
      namespace: monitoring
    spec:
      endpoints:
      - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
        interval: 5s
        port: k8seggjs-metrics
      jobLabel: k8s-app
      namespaceSelector:
        matchNames:
        - k8seggjs
      selector:
        matchLabels:
          k8s-app: k8seggjs-metrics
    

    应用

    kubectl apply -f ServiceMonitor.yaml
    

    egg-exporter & egg-prometheus

    egg-exporter,Egg.js 的 Prometheus 指标收集插件,附带 Grafana 看板。

    egg-prometheus,Prometheus plugin for Egg.js。

    示例项目的指标收集就是用的这个。

    Grafana (k8s-grafana)

    dashboard-metrics.json,完整的面板 json。来自于egg-exporter。笔者这里做了 metrics 前缀的调整。

    config.exporter = {
      scrapePort: 7777,
      scrapePath: '/metrics',
      prefix: 'k8seggjs_',
      defaultLabels: { stage: process.env.NODE_ENV },
    };
    

    我们导入 json 文件进行 Grafana 面板创建

    修改面板 Variables

    $stage

    • Query: k8seggjs_nodejs_version_info{worker="app"}
    • Regex: /.*stage="([^"]*).*/

    $appname

    • Query: k8seggjs_nodejs_version_info{worker="app"}
    • Regex: /.*app="([^"]*).*/

    $node

    • Query: k8seggjs_nodejs_version_info{worker="app"}
    • Regex: /.*instance="([^"]*).*/

    最终效果

    Refs

    互相交流学习

    我的微信:

  • 相关阅读:
    15.Numpy之点乘、算术运算、切片、遍历和下标取值
    13.python-列表排序
    [Js-c++]c++中的指针、引用和数组名
    [Hadoop]Windows下用eclipse远程连接hdfs报错Connection denied解决方案
    [Java-JVM]Centos7编译openjdk7
    [Js-Java SE]Java中的Native关键字与JNI
    [Js-C++]C++中赋值表达式的结果
    [Js-C++].h文件与#include详解
    [Js-C++]C++中*&(指针引用)和*(指针)的区别
    [Js-Python]解决pip安装安装源速度慢的问题
  • 原文地址:https://www.cnblogs.com/hacker-linner/p/14073662.html
Copyright © 2020-2023  润新知