สร้าง API Gateway และระบบ Monitoring Microservice ด้วย Kong, Prometheus และ Grafana แบบง่ายๆ

ภาพจาก https://www.express-gateway.io/eg-vs-amazon-aws-api-gateway/

บทความโดย ผศ.ดร.ณัฐโชติ พรหมฤทธิ์
ภาควิชาคอมพิวเตอร์
คณะวิทยาศาสตร์
มหาวิทยาลัยศิลปากร

บทความนี้เราจะสร้าง API Gateway และระบบ Monitoring งานทะเบียนนักศึกษาซึ่งถูกพัฒนาแบบ Microservice Architecture

สำหรับผู้อ่านใหม่ที่ต้องการจะ Implement ตาม สามารถอ่านบทความ 2 บทความก่อนหน้านี้ ได้แก่

Kong API Gateway

API Gateway เป็นจุดศูนย์รวมของการควบคุมการเข้าถึง Internal API ที่เราเปิด Public ให้ผู้ใช้ภายนอกเรียกใช้งาน ทำให้เราสามารถทำงานต่าง ๆ อย่างเช่น การทำ Authentication เพื่อยืนยันตัวตนก่อนเข้าใช้ Service การทำ Rate Limiting เพื่อควบคุม Traffic ได้ว่าใน 1 วินาที/นาที/ชั่วโมง/วัน จะมี Request ได้กี่ครั้ง หรือการทำ Monitoring Service ร่วมกับ Prometheus เป็นต้น

ภาพจาก https://medium.com/@_oleksii_/how-to-connect-your-servers-to-prometheus-server-ec2fed5c48dd

Kong เป็น API Gateway แบบ Open source ตัวหนึ่งที่ได้รับความนิยม โดยเฉพาะการนำมาใช้กับ Software แบบ Microservice Architecture

โดยเราสามารถตั้งค่า Kong ใน 4 ส่วนหลักๆ ได้แก่

Service คือ Service ปลายทางที่ต้องการให้ Kong ส่งต่อ Request ไปหา
Route คือ Path ที่  Client เรียกมาหา Kong โดยที่ Route จะต้องผูกกับ Service
Consumer คือ ผู้ที่จะเรียกใช้ Kong
Plugin คือ ตัวที่ทำให้ Kong สามารถทำ Authentication, Rate Limiting หรือ Monitoring Service ฯลฯ ได้

ซึ่ง Kong กำหนด Default Port ในการรับ-ส่งข้อมูลไว้ดังนี้

8000 สำหรับ HTTP Request ที่จะถูกส่งต่อไปยัง Service ตามที่กำหนด
8443 สำหรับ HTTPS Request ที่จะถูกส่งต่อไปยัง Service ตามที่กำหนด
8001 สำหรับการตั้งค่า Kong ผ่าน HTTP Request
8444 สำหรับการตั้งค่า Kong ผ่าน HTTPS Request

Kong เองนั้นสามารถตั้งค่าผ่านทาง Port 8001 หรือ  8444 ด้วยการเรียกใช้ RESTful Administration API โดยตรง แต่เพื่อความสะดวก เราจะตั้งค่าผ่าน Kong Admin GUI ที่ชื่อว่า Konga ผ่าน URL ด้านล่าง

https://konga.labxx.cpsudevops.com

และกำหนด URL สำหรับ HTTPS Request ที่จะถูกส่งต่อไปยัง Register Gateway Service คือ

https://service.labxx.cpsudevops.com/register/

นอกจากนี้เราจะ Config PostgreSQL เป็น Database สำหรับ Kong และ Konga รวมทั้ง Config Node-exporter สำหรับดึงค่าต่างๆ จากตัว Hardware เช่น CPU, Memory และ HDD ฯลฯ เพื่อส่งข้อมูลไปยัง Prometheus

DB-Engines Ranking from https://db-engines.com/en/ranking

โดยเราจะ Config Kong, Konga, Prometheus และ Node-exporter ผ่าน Docker-compose ตามขั้นตอนต่อไปนี้

  • Remote Login ไปยัง Cloud Server โดยใช้ ssh
ssh nc-user@labxx.cpsudevops.com
  • สร้าง Project ชื่อ kong_dock ซึ่งภายใน Folder จะประกอบด้วยไฟล์ docker-compose.yml และ prometheus.yml
.
|__ docker-compose.yml
|__ prometheus.yml
  • แก้ไขไฟล์ docker-compose.yml ตามตัวอย่างด้านล่าง
version: '2'

services:
  kong:
    image: kong:2.0.2-alpine
    container_name: kong
    depends_on:
      - kong_db
      - kong_migration
      
    expose:
      - "8001"
      - "8444"
      - "8000"
      - "8443"
    restart: always
    environment:
      KONG_DATABASE:         postgres
      KONG_PG_HOST:          kong_db
      KONG_PG_PORT:          5432
      KONG_PG_DATABASE:      kong
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG:  /dev/stderr
      KONG_ADMIN_ERROR_LOG:  /dev/stderr
      KONG_PROXY_LISTEN:     0.0.0.0:8000, 0.0.0.0:8443 ssl
      KONG_ADMIN_LISTEN:     0.0.0.0:8001, 0.0.0.0:8444 ssl
      KONG_PLUGINS:          basic-auth, key-auth, rate-limiting, prometheus, proxy-cache, oauth2

      VIRTUAL_HOST: service.labxx.cpsudevops.com
      VIRTUAL_PORT: 8000
      LETSENCRYPT_HOST: service.labxx.cpsudevops.com

    networks: 
    - webproxy
    - default
    
  kong_db:
    image: postgres:9.6
    container_name: kong_db
    volumes:
      - kong_datastore:/var/lib/postgresql/data
    restart: always
    environment:
      POSTGRES_DB: kong
      POSTGRES_USER: kong
      POSTGRES_HOST_AUTH_METHOD: trust
  
  kong_migration:
    image: kong:latest
    container_name: kong_migration
    command: "kong migrations bootstrap"
    restart: on-failure
    environment:
      KONG_PG_HOST: kong_db
    depends_on:
      - kong_db
      
  konga:
    container_name: konga
    image: pantsel/konga
    restart: always

    environment:
      DB_ADAPTER: postgres
      DB_HOST: konga_db
      DB_USER: konga 
      DB_DATABASE: konga
      NODE_ENV: development

      VIRTUAL_HOST: konga.labxx.cpsudevops.com
      VIRTUAL_PORT: 1337
      LETSENCRYPT_HOST: konga.labxx.cpsudevops.com

    expose:
    - "1337"

    networks: 
      - webproxy
      - default
  
  konga_db:
    image: postgres:9.6
    container_name: konga_db
    volumes:
      - konga_database:/var/lib/postgresql/data
    restart: always
    environment:
      POSTGRES_DB: konga
      POSTGRES_USER: konga
      POSTGRES_HOST_AUTH_METHOD: trust 

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/promtheus
    command:
     - '--config.file=/etc/prometheus/prometheus.yml'
    expose:
      - "9090"
    restart: always

  node_exporter:
    image: prom/node-exporter:latest
    container_name: node_exporter
    expose:
      - "9100"
    restart: always

volumes:
  kong_datastore:
  konga_database:
  prometheus_data:
  
networks:
  webproxy:
    external:
      name: webproxy
  default:
    external:
      name: kong_network
  • แก้ไขไฟล์ prometheus.yml
global: 
  external_labels: 
    monitor: devops_monitor
  scrape_interval: 5s
scrape_configs: 
  - job_name: prometheus
    static_configs: 
      - targets: 
        - "localhost:9090"
        
  - job_name: node_exporter
    static_configs:
      - targets:
        - "node_exporter:9100"
        
  - job_name: kong
    static_configs:
      - targets:
        - "kong:8001"
  • สร้าง Bridge network โดยตั้งชื่อเป็น kong_network
docker network create kong_network
  • รัน Container ด้วย docker-compose และกลับไปที่ Terminal โดยใช้ parameter -d
docker-compose up -d
  • ดู Container ของ kong_dock ที่กำลังรันทั้งหมด ตามที่ docker-compose.yml ดูแล ด้วย Command line
docker-compose ps
  • ดู Container ของ kong_dock ที่กำลังรันทั้งหมด ด้วย Portainer
  • Config Kong ผ่าน Konga จาก URL https://konga.labxx.cpsudevops.com
  • กรอกข้อมูลเพื่อสร้าง Admin Account แล้วกด Create Admin
  • Login
  • Connect ไปยัง Kong โดยกำหนดค่า Kong Admin URL เป็น http://kong:8001 แล้วกด CREATE CONNECTION
  • สร้าง Service โดยกดที่เมนู SERVICES แล้วกด ADD NEW SERVICE
  • ใส่ชื่อ Service, Protocol, Host (Private IP Address บน Cloud Server), Port และ Path แล้วกด SUBMIT SERVICE
  • สร้าง Route โดยกดที่ RegisterGateway แล้วกดที่แถบ Routes
  • กด ADD ROUTE ใส่ชื่อ Route Name ใส่ข้อมูล Paths, Methods และ Protocols โดยกด Enter ทุกครั้ง แล้วกด SUBMIT ROUTE
  • ลองกดส่ง Request ใน Postman ไปยัง https://service.labxx.cpsudevops.com/register/ แบบ JSON
{
  "firstname": "Nuttachot",
  "lastname": "Promrit",
  "email": "promrit_n@silpakorn.edu"
}
  • ดู Email ใน Inbox

หมายเหตุ เพื่อไม่ให้ Client สามารถส่ง Request ด้วยการ Bypass Kong ไปยัง Internal Service โดยตรง จะต้องมีการปิด Port 7001 บน Firewall เมื่อมีการรัน Service บน Production Server

Authentication

Authentication คือการยืนยันตัวตนเมื่อเข้าใช้งาน เราจะตั้งค่า Kong ให้ทำ Authentication แบบ Basic Authen และ API Key กับ Request ที่เข้ามาจากภายนอก ก่อนส่งต่อไปหา Register Gateway Service โดยมีขั้นตอนดังนี้

  • สร้าง Consumer โดยกดเมนู CONSUMERS กด CREATE CONSUMER ใส่ username เป็น devops กด SUBMIT CONSUMER แล้วกด Tab Credentials
  • เลือกเมนู BASIC กด CREATE CREDENTIALS ใส่ข้อมูล username และ password แล้วกด SUBMIT
  • เลือกเมนู  API KEYS กด CREATE API KEY ปล่อย key เป็นค่าว่างไว้ เพื่อให้ Kong สร้าง key ที่ปลอดภัยให้โดยอัตโนมัติ แล้วกด SUBMIT
  • เราจะทำ Authen กับ ROUTE โดยการกดที่เมนู ROUTES กด registerRoute แล้วเลือก Plugins
  • กด ADD PLUGIN เลือก Basic Auth ปล่อย consumer ไว้ Kong จะเลือกจาก consumer ที่เราตั้งไว้ แล้วกด ADD PLUGIN อีกครั้ง
  • เลือก Key Auth ปล่อย consumer ไว้ ใส่ key names กด Enter แล้วกด ADD PLUGIN
  • Disabled key-auth เพื่อทดลองกดส่ง Request ใน Postman ไปยัง https://service.labxx.cpsudevops.com/register/ เพื่อให้ Kong ทำ Authen แบบ basic-auth
  • Enabled key-auth และ Disabled basic-auth เพื่อทดลองกดส่ง Request ใน Postman

Rate Limiting

เราสามารถควบคุม Traffic ได้ว่าใน 1 วินาที/นาที/ชั่วโมง/วัน จะมี Request ได้กี่ครั้ง ด้วยการทำ Rate Limiting Plugin โดยมีขั้นตอนดังนี้

  • ทำ Rate Limiting กับ ROUTE โดยการกดที่เมนู ROUTES กด registerRoute แล้วเลือก Plugins
  • กด ADD PLUGIN เลือกเมนู Traffic Control กด ADD PLUGIN ที่ Rate Limiting กำหนดให้ส่ง Request ได้ 5,000 ครั้ง ต่อชั่วโมง แล้วกด ADD PLUGIN
  • ทดลองกดส่ง Request ใน Postman จะเห็นว่า X-RateLimit-Remaining-Hour เหลือ 4999 และเมื่อกดส่งอีกครั้ง X-RateLimit-Remaining-Hour จะเหลือ 4998

Prometheus + Grafana

เราจะใช้ Prometheus จัดเก็บข้อมูลต่างๆ ของ Cloud Server และ Service ในแบบ Time Series และใช้ Grafana สำหรับดึงข้อมูลมาแสดงบน Real Time Dashboard

ก่อนอื่นเราจะ Add plugin ใน Kong เพื่อ Monitor Consumer แล้วติดตั้ง Grafana Container ตามขั้นตอนดังต่อไปนี้

  • เลือกเมนู CONSUMERS กดที่ devops แล้วเลือก Tab Plugins
  • กด  ADD NEW PLUGIN เลือกเมนู Analytics & Monitoring กด ADD PLUGIN ที่ Prometheus แล้วกด ADD PLUGIN อีกครั้ง
  • สร้าง Project ชื่อ grafana_dock ภายใน Folder มีไฟล์ docker-compose.yml
.
|__ docker-compose.yml
  • แก้ไข docker-compose.yml เพื่อติดตั้ง Grafana Container ตามตัวอย่างด้านล่าง
version: '2'

services:
  grafana:
    image: grafana/grafana
    restart: always
    expose:
      - "3000"
    external_links:
      - prometheus
    environment:
      GF_INSTALL_PLUGINS: grafana-clock-panel, grafana-simple-json-datasource
      VIRTUAL_HOST: grafana.lab20.cpsudevops.com
      VIRTUAL_PORT: 3000
      LETSENCRYPT_HOST: grafana.lab20.cpsudevops.com 
    networks: 
      - webproxy
      - default
      
networks:
  webproxy:
    external:
      name: webproxy
  default:
    external:
      name: kong_network
  • รัน Container ด้วย docker-compose และกลับไปที่ Terminal โดยใช้ parameter -d
docker-compose up -d
  • ดู Container ของ kong_dock ที่กำลังรันทั้งหมด ตามที่ docker-compose.yml ดูแล ด้วย Command line
docker-compose ps
  • Login เข้า Grafana จาก URL https://grafana.labxx.cpsudevops.com โดย username คือ admin และ password คือ admin แล้วเปลี่ยน Password ใหม่
  • กด Add data source เลือก Prometheus
  • ใส่ URL http://prometheus:9090 เพื่อ Connect ไปยัง Prometheus Container แล้วกด Save & Test
  • เลือกเมนู + เพื่อ Import Dashboard
  • ใส่ ID ของ Dashboard ที่เราจะติดตั้ง เลือก Prometheus Data Source เป็น Prometheus แล้วกด Import
Node Exporter Dashboard

โดยเราสามารถค้นหา Dashboard ได้จาก https://grafana.com/grafana/dashboards

สำหรับ Dashboard ID ของ Kong APIs Monitoring แบบ Official  คือ 7424 ครับ

Kong APIs Monitoring Dashboard 
ขอขอบคุณ Nipa.Cloud ที่ให้การสนับสนุน Environment ในการเรียนการสอน
รายวิชา Dev-Ops and Cloud Engineering 101