ติดตั้ง TICK Stack ใน IoT Workshop
Branch:
workshop/dev-07-tick-setupPhase: Development (7/9) Repo: kangana1024/iot-workshop
ถ้าเรามองว่า sensor คือคนที่เก็บข้อมูล แล้วถามว่า — ข้อมูลพวกนั้นไปอยู่ที่ไหน? ใครดูแล? ใครเตือนเมื่อมีปัญหา?
คำตอบคือ TICK Stack ครับ มันคือทีมงานเบื้องหลังที่ทำให้ระบบ IoT เราฉลาดขึ้นทันที วันนี้เราจะติดตั้งมันครบ 4 ตัว พร้อม config ที่ใช้งานได้จริง มาลุยกันเลย! (ง •̀_•́)ง
น้องๆ จะได้อะไรจาก workshop นี้
- เข้าใจว่า TICK Stack คืออะไร และ ทำไม ถึงต้องใช้กับ IoT
- ติดตั้ง TICK Stack ครบด้วย Docker Compose
- ตั้งค่า InfluxDB: database, retention policies, continuous queries
- ตั้งค่า Telegraf agent เชื่อม InfluxDB
- เปิด Chronograf dashboard และเชื่อมต่อ Kapacitor
- รัน + ทดสอบ connectivity ทั้งระบบ
ก่อนอื่น — ทำไมต้อง TICK Stack?
ลองนึกภาพว่าอาคารมีเซ็นเซอร์วัดอุณหภูมิ 500 ตัว ส่งข้อมูลทุก 5 วินาที
ถ้าเราเก็บลง MySQL แบบปกติ… ตารางจะพองขึ้น หลายล้านแถวต่อวัน query ช้า index พัง ชีวิตพัง
Time-series database อย่าง InfluxDB ถูกออกแบบมาเพื่อเรื่องนี้โดยเฉพาะ — มันรู้ว่าข้อมูลมี “เวลา” เป็นแกนหลัก เก็บได้เร็ว query ได้เร็ว และลบข้อมูลเก่าอัตโนมัติได้
แล้ว T, C, K ที่เหลือล่ะ? ก็คือทีมที่ต้องทำงานร่วมกัน:
| ตัวอักษร | Component | เปรียบเหมือน |
|---|---|---|
| Telegraf | Agent เก็บ metrics | พนักงานไปรษณีย์ที่เก็บข้อมูลส่งให้ทุก 10 วินาที |
| InfluxDB | Time-series database | คลังเก็บของที่ฉลาดพอจะรู้ว่าของเก่าควรทิ้งเมื่อไหร่ |
| Chronograf | Web UI / Dashboard | หน้าจอ monitor ที่ห้องควบคุม |
| Kapacitor | Alerting & Processing | ยามที่คอยเฝ้าและกดออดแจ้งเตือนเมื่อเจออะไรผิดปกติ |
ภาพรวม Architecture
ก่อนลงมือ เราต้องรู้ว่าข้อมูลไหลยังไง:
ง่ายมาก — ข้อมูลไหลจากซ้ายไปขวา Telegraf คือตัวกลางที่รับจาก MQTT แล้วยัดเข้า InfluxDB ส่วน Chronograf และ Kapacitor นั่งรอดูอยู่ฝั่งขวา
Step 1: โครงสร้าง Directory
# ใน repository iot-workshop
mkdir -p deployments/{influxdb,telegraf,chronograf,kapacitor}
mkdir -p deployments/influxdb/{data,config}
mkdir -p deployments/telegraf/conf.d
mkdir -p deployments/kapacitor/{scripts,data}
โครงสร้างสุดท้ายจะหน้าตาแบบนี้:
deployments/
├── docker-compose.tick.yml
├── influxdb/
│ ├── data/ # persistent data volume
│ └── config/
│ └── influxdb.conf
├── telegraf/
│ ├── telegraf.conf
│ └── conf.d/
│ └── mqtt.conf
├── chronograf/
│ └── data/ # persistent data volume
└── kapacitor/
├── kapacitor.conf
├── data/ # persistent data volume
└── scripts/ # TICKscript alerts
Step 2: Docker Compose สำหรับ TICK Stack
ทำไม ถึงใช้ Docker Compose? เพราะเราต้องการให้ทุก container อยู่ใน network เดียวกัน (iot-net) คุยกันได้ด้วย hostname โดยไม่ต้องใช้ IP — เหมือนคนในบ้านเดียวกันตะโกนหาได้เลยโดยไม่ต้องรู้หมายเลขห้อง
สร้างไฟล์ deployments/docker-compose.tick.yml:
version: '3.8'
networks:
iot-net:
external: true
name: iot-workshop_iot-net
volumes:
influxdb-data:
driver: local
influxdb-config:
driver: local
chronograf-data:
driver: local
kapacitor-data:
driver: local
services:
# ─────────────────────────────────────────
# InfluxDB - Time Series Database
# ─────────────────────────────────────────
influxdb:
image: influxdb:1.8.10
container_name: iot-influxdb
restart: unless-stopped
ports:
- "8086:8086" # HTTP API
- "8088:8088" # RPC for backup/restore
environment:
INFLUXDB_DB: iot_data
INFLUXDB_ADMIN_USER: admin
INFLUXDB_ADMIN_PASSWORD: ${INFLUXDB_ADMIN_PASSWORD:-admin123}
INFLUXDB_USER: telegraf
INFLUXDB_USER_PASSWORD: ${INFLUXDB_USER_PASSWORD:-telegraf123}
INFLUXDB_READ_USER: grafana
INFLUXDB_READ_USER_PASSWORD: ${INFLUXDB_READ_USER_PASSWORD:-grafana123}
INFLUXDB_HTTP_AUTH_ENABLED: "true"
INFLUXDB_DATA_ENGINE: tsm1
INFLUXDB_REPORTING_DISABLED: "true"
INFLUXDB_HTTP_FLUX_ENABLED: "false"
volumes:
- influxdb-data:/var/lib/influxdb
- ./influxdb/config/influxdb.conf:/etc/influxdb/influxdb.conf:ro
networks:
- iot-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8086/ping"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
# ─────────────────────────────────────────
# Telegraf - Metrics Collection Agent
# ─────────────────────────────────────────
telegraf:
image: telegraf:1.29
container_name: iot-telegraf
restart: unless-stopped
depends_on:
influxdb:
condition: service_healthy
environment:
INFLUXDB_URL: http://influxdb:8086
INFLUXDB_USER: telegraf
INFLUXDB_PASSWORD: ${INFLUXDB_USER_PASSWORD:-telegraf123}
MQTT_BROKER: tcp://mosquitto:1883
MQTT_USERNAME: ${MQTT_USERNAME:-iot_client}
MQTT_PASSWORD: ${MQTT_PASSWORD:-mqtt123}
volumes:
- ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
- ./telegraf/conf.d:/etc/telegraf/telegraf.d:ro
networks:
- iot-net
# ─────────────────────────────────────────
# Chronograf - Web UI & Dashboard
# ─────────────────────────────────────────
chronograf:
image: chronograf:1.10
container_name: iot-chronograf
restart: unless-stopped
ports:
- "8888:8888"
depends_on:
influxdb:
condition: service_healthy
environment:
INFLUXDB_URL: http://influxdb:8086
INFLUXDB_USERNAME: admin
INFLUXDB_PASSWORD: ${INFLUXDB_ADMIN_PASSWORD:-admin123}
KAPACITOR_URL: http://kapacitor:9092
TOKEN_SECRET: ${CHRONOGRAF_TOKEN_SECRET:-supersecrettoken}
GENERIC_NAME: "IoT Workshop"
volumes:
- chronograf-data:/var/lib/chronograf
networks:
- iot-net
# ─────────────────────────────────────────
# Kapacitor - Alerting & Processing
# ─────────────────────────────────────────
kapacitor:
image: kapacitor:1.7
container_name: iot-kapacitor
restart: unless-stopped
ports:
- "9092:9092"
depends_on:
influxdb:
condition: service_healthy
environment:
KAPACITOR_INFLUXDB_0_URLS_0: http://influxdb:8086
KAPACITOR_INFLUXDB_0_USERNAME: admin
KAPACITOR_INFLUXDB_0_PASSWORD: ${INFLUXDB_ADMIN_PASSWORD:-admin123}
KAPACITOR_HOSTNAME: kapacitor
volumes:
- ./kapacitor/kapacitor.conf:/etc/kapacitor/kapacitor.conf:ro
- kapacitor-data:/var/lib/kapacitor
networks:
- iot-net
สังเกตว่า Telegraf และ Chronograf มี depends_on: influxdb: condition: service_healthy — นั่นคือมันจะรอจนกว่า InfluxDB healthcheck ผ่านก่อนค่อยเริ่ม ไม่งั้น connect ไม่ติดตั้งแต่แรก (ˊ•͈ ꇴ •͈ˋ)
Step 3: InfluxDB Configuration
ทำไม ต้องมี config file แยก? เพราะ environment variable ตั้งได้แค่ basic settings ส่วน performance tuning (cache size, compaction, timeout) ต้องใช้ config file ถึงจะครบ
สร้างไฟล์ deployments/influxdb/config/influxdb.conf:
[meta]
dir = "/var/lib/influxdb/meta"
retention-autocreate = true
logging-enabled = true
[data]
dir = "/var/lib/influxdb/data"
engine = "tsm1"
wal-dir = "/var/lib/influxdb/wal"
# ปรับ cache size ตาม RAM ที่มี
cache-max-memory-size = "1g"
cache-snapshot-memory-size = "25m"
cache-snapshot-write-cold-duration = "10m"
# Compaction settings
compact-full-write-cold-duration = "4h"
max-concurrent-compactions = 0 # 0 = auto detect CPUs
# TSM settings
max-series-per-database = 1000000
max-values-per-tag = 100000
[http]
enabled = true
bind-address = ":8086"
auth-enabled = true
log-enabled = true
write-tracing = false
pprof-enabled = false
https-enabled = false
# Increase timeouts for heavy queries
read-timeout = "10s"
max-row-limit = 10000
max-connection-limit = 0
[logging]
format = "logfmt"
level = "info"
suppress-logo = false
[subscriber]
enabled = true
http-timeout = "30s"
insecure-skip-verify = false
ca-certs = ""
write-concurrency = 40
write-buffer-size = 1000
[continuous_queries]
enabled = true
log-enabled = true
query-stats-enabled = false
run-interval = "1s"
Step 4: ตั้งค่า Database และ Retention Policies
นี่คือส่วนที่สำคัญมากครับ เราจะคุยเรื่อง ทำไม ก่อนเลย
ทำไมต้องมี Retention Policy?
ลองนึกภาพ hard disk เป็นตู้เก็บเอกสาร ถ้าเก็บทุกอย่างไว้ตลอดกาล ตู้เต็มแน่นอน
Retention Policy คือ “นโยบายทำลายเอกสาร” — raw data อยู่แค่ 30 วัน (เอาไว้ดู detail) แต่ข้อมูลสรุปรายชั่วโมงอยู่ได้ 1 ปี และสรุปรายวันอยู่ได้ถึง 5 ปี
Raw (30 วัน) → Hourly aggregate (1 ปี) → Daily aggregate (5 ปี)
[ละเอียดมาก] [พอประมาณ] [ภาพรวม]
ทำไมต้องมี Continuous Query?
เพราะเราไม่อยากนั่งสรุปข้อมูลเองทุกชั่วโมง Continuous Query คือ scheduled task ที่ InfluxDB รันให้อัตโนมัติ — มันจะรวบข้อมูล raw ทุกชั่วโมงแล้วเขียนสรุปไว้ใน retention policy ที่นานกว่า
เชื่อมต่อและตั้งค่า:
# เชื่อมต่อ InfluxDB CLI
docker exec -it iot-influxdb influx -username admin -password admin123
# หรือใช้ curl
curl -X POST http://localhost:8086/query \
-u admin:admin123 \
--data-urlencode "q=SHOW DATABASES"
สร้าง Database และ Retention Policies
-- สร้าง database สำหรับข้อมูล IoT
CREATE DATABASE iot_data;
-- สร้าง database สำหรับ telemetry ระยะสั้น (raw data)
CREATE DATABASE iot_raw WITH DURATION 7d REPLICATION 1 NAME "raw_7d";
-- เปลี่ยนไปใช้ iot_data database
USE iot_data;
-- ─────────────────────────────────────
-- Retention Policies
-- ─────────────────────────────────────
-- 1. Raw data: เก็บ 30 วัน (ค่า default)
CREATE RETENTION POLICY "raw_30d"
ON "iot_data"
DURATION 30d
REPLICATION 1
DEFAULT;
-- 2. Hourly aggregates: เก็บ 1 ปี
CREATE RETENTION POLICY "hourly_1y"
ON "iot_data"
DURATION 365d
REPLICATION 1;
-- 3. Daily aggregates: เก็บ 5 ปี
CREATE RETENTION POLICY "daily_5y"
ON "iot_data"
DURATION 1825d
REPLICATION 1;
-- ตรวจสอบ retention policies
SHOW RETENTION POLICIES ON iot_data;
Continuous Queries สำหรับ Data Downsampling
-- ─────────────────────────────────────
-- Continuous Query: Hourly Aggregation
-- ─────────────────────────────────────
-- อุณหภูมิ: สรุปรายชั่วโมง
CREATE CONTINUOUS QUERY "cq_temperature_hourly"
ON "iot_data"
BEGIN
SELECT
MEAN(value) AS mean_value,
MAX(value) AS max_value,
MIN(value) AS min_value,
STDDEV(value) AS stddev_value,
COUNT(value) AS sample_count
INTO "iot_data"."hourly_1y"."sensor_data"
FROM "iot_data"."raw_30d"."sensor_data"
WHERE "measurement_type" = 'temperature'
GROUP BY time(1h), "device_id", "location", "building"
END;
-- Humidity: สรุปรายชั่วโมง
CREATE CONTINUOUS QUERY "cq_humidity_hourly"
ON "iot_data"
BEGIN
SELECT
MEAN(value) AS mean_value,
MAX(value) AS max_value,
MIN(value) AS min_value,
COUNT(value) AS sample_count
INTO "iot_data"."hourly_1y"."sensor_data"
FROM "iot_data"."raw_30d"."sensor_data"
WHERE "measurement_type" = 'humidity'
GROUP BY time(1h), "device_id", "location", "building"
END;
-- ─────────────────────────────────────
-- Continuous Query: Daily Aggregation
-- ─────────────────────────────────────
CREATE CONTINUOUS QUERY "cq_sensor_daily"
ON "iot_data"
RESAMPLE EVERY 1h FOR 2h
BEGIN
SELECT
MEAN(mean_value) AS mean_value,
MAX(max_value) AS max_value,
MIN(min_value) AS min_value,
SUM(sample_count) AS sample_count
INTO "iot_data"."daily_5y"."sensor_data"
FROM "iot_data"."hourly_1y"."sensor_data"
GROUP BY time(1d), "device_id", "location", "building", "measurement_type"
END;
-- ─────────────────────────────────────
-- Device Status Aggregation
-- ─────────────────────────────────────
CREATE CONTINUOUS QUERY "cq_device_uptime_hourly"
ON "iot_data"
BEGIN
SELECT
COUNT(status) AS total_reports,
SUM(IF(status = 1, 1, 0)) AS online_count
INTO "iot_data"."hourly_1y"."device_status_summary"
FROM "iot_data"."raw_30d"."device_status"
GROUP BY time(1h), "device_id", "location"
END;
-- ตรวจสอบ continuous queries
SHOW CONTINUOUS QUERIES;
ทดสอบ Write และ Query ข้อมูล
# Write ข้อมูล test
curl -X POST "http://localhost:8086/write?db=iot_data&precision=s" \
-u telegraf:telegraf123 \
--data-binary 'sensor_data,device_id=device_001,location=floor_1,building=A,measurement_type=temperature value=25.3 1711411200'
# Query ข้อมูล
curl -G "http://localhost:8086/query" \
-u admin:admin123 \
--data-urlencode "db=iot_data" \
--data-urlencode "q=SELECT * FROM sensor_data WHERE time > now() - 1h LIMIT 10"
Step 5: Telegraf Basic Configuration
ทำไม Telegraf ถึงต้องมี config เยอะขนาดนี้? เพราะมันเป็นตัว collect แบบ pluggable — เราบอกมันว่า “รับข้อมูลจากไหน (inputs) แล้วส่งไปไหน (outputs)” ในไฟล์เดียว เปลี่ยน pipeline แค่แก้ config ไม่ต้องแก้ code
สร้างไฟล์ deployments/telegraf/telegraf.conf:
# ─────────────────────────────────────────────────────
# Telegraf Configuration - IoT Workshop
# ─────────────────────────────────────────────────────
[global_tags]
environment = "production"
project = "iot-workshop"
[agent]
interval = "10s"
round_interval = true
metric_batch_size = 1000
metric_buffer_limit = 10000
collection_jitter = "0s"
flush_interval = "10s"
flush_jitter = "0s"
precision = "0s"
hostname = "telegraf-agent"
omit_hostname = false
debug = false
quiet = false
logfile = ""
# ─────────────────────────────────────────────────────
# OUTPUT: InfluxDB
# ─────────────────────────────────────────────────────
[[outputs.influxdb]]
urls = ["$INFLUXDB_URL"]
database = "iot_data"
retention_policy = "raw_30d"
username = "$INFLUXDB_USER"
password = "$INFLUXDB_PASSWORD"
timeout = "10s"
write_consistency = "any"
# Connection pool
content_encoding = "gzip"
# ─────────────────────────────────────────────────────
# INPUT: Internal Telegraf Metrics (self-monitoring)
# ─────────────────────────────────────────────────────
[[inputs.internal]]
collect_memstats = true
# ─────────────────────────────────────────────────────
# INPUT: CPU & Memory (agent host)
# ─────────────────────────────────────────────────────
[[inputs.cpu]]
percpu = false
totalcpu = true
collect_cpu_time = false
report_active = false
[[inputs.mem]]
# no config needed
Step 6: Chronograf Dashboard Setup
Chronograf คือ “ห้องควบคุม” ของเรา เปิดขึ้นมาแล้วเห็นกราฟสวยงาม แต่ก่อนจะสวย ต้องตั้งค่าก่อน
เปิด Chronograf UI
- เปิด browser ไปที่
http://localhost:8888 - สร้าง account ครั้งแรก (กำหนด username/password)
- เชื่อมต่อ InfluxDB
เชื่อมต่อ InfluxDB ผ่าน Chronograf
ที่หน้า Configuration > Add Data Source:
Connection URL: http://influxdb:8086
Connection Name: IoT Workshop InfluxDB
Username: admin
Password: admin123
Default Retention Policy: raw_30d
สร้าง Dashboard สำหรับ IoT
ที่หน้า Dashboards > Create Dashboard:
Dashboard: IoT Sensor Overview
Cell 1 - Temperature (Line Chart):
Query:
SELECT MEAN("value") AS "temperature"
FROM "iot_data"."raw_30d"."sensor_data"
WHERE "measurement_type" = 'temperature'
AND time > now() - 1h
GROUP BY time(1m), "device_id"
Visualization: Line Chart
Y-axis: Temperature (°C)
Cell 2 - Humidity (Gauge):
SELECT LAST("value") AS "humidity"
FROM "iot_data"."raw_30d"."sensor_data"
WHERE "measurement_type" = 'humidity'
AND time > now() - 5m
GROUP BY "device_id"
Cell 3 - Device Status (Table):
SELECT LAST("status") AS "status",
LAST("battery_level") AS "battery"
FROM "iot_data"."raw_30d"."device_status"
WHERE time > now() - 5m
GROUP BY "device_id", "location"
Step 7: Kapacitor Connection และ Configuration
ทำไม ต้องมี Kapacitor แยก? ก็เพราะ Chronograf ทำได้แค่ “ดู” แต่ Kapacitor ทำได้ “ตัดสินใจ” — มันนั่งอ่าน stream ข้อมูลตลอดเวลา พอเจออุณหภูมิเกิน 35°C ก็ยิง Slack alert ออกมาเลย โดยไม่ต้องรอให้คนมาดูหน้าจอ
เหมือนเปรียบ Chronograf = แพทย์ที่ดูผล Kapacitor = เครื่อง monitor ที่ส่งสัญญาณเตือนเองเมื่อ vital sign ผิดปกติ
Kapacitor Configuration
สร้างไฟล์ deployments/kapacitor/kapacitor.conf:
# ─────────────────────────────────────────────────────
# Kapacitor Configuration - IoT Workshop
# ─────────────────────────────────────────────────────
hostname = "kapacitor"
data_dir = "/var/lib/kapacitor"
skip-config-overrides = false
default-retention-policy = ""
[http]
bind-address = ":9092"
auth-enabled = false
log-enabled = true
write-tracing = false
pprof-enabled = false
https-enabled = false
[logging]
file = "STDOUT"
level = "INFO"
# ─────────────────────────────────────────────────────
# InfluxDB Connection
# ─────────────────────────────────────────────────────
[[influxdb]]
enabled = true
name = "default"
default = true
urls = ["http://influxdb:8086"]
username = "admin"
password = "${INFLUXDB_ADMIN_PASSWORD}"
timeout = 0
insecure-skip-verify = false
startup-timeout = "5m"
disable-subscriptions = false
subscription-protocol = "http"
subscription-mode = "cluster"
kapacitor-hostname = ""
http-port = 0
udp-bind = ""
udp-buffer = 1000
udp-read-buffer = 0
[influxdb.subscriptions]
# Subscribe to all measurements in iot_data
iot_data = ["raw_30d"]
[influxdb.excluded-subscriptions]
_internal = ["monitor"]
# ─────────────────────────────────────────────────────
# Alert Handlers
# ─────────────────────────────────────────────────────
# Slack Notifications
[slack]
enabled = true
default = true
workspace = "iot-workshop"
url = "${SLACK_WEBHOOK_URL}"
channel = "#iot-alerts"
username = "Kapacitor"
icon-emoji = ":bell:"
global = false
state-changes-only = false
# SMTP Email
[smtp]
enabled = true
host = "${SMTP_HOST}"
port = 587
username = "${SMTP_USER}"
password = "${SMTP_PASSWORD}"
from = "[email protected]"
to = ["[email protected]"]
no-verify = false
global = false
state-changes-only = false
# HTTP (Webhook to Go API)
[httppost]
[[httppost.endpoint]]
name = "go-api"
url = "http://backend:8080/api/v1/alerts/webhook"
headers = {Content-Type = "application/json", X-Alert-Source = "kapacitor"}
history-size = 100
เชื่อมต่อ Kapacitor กับ Chronograf
ที่หน้า Chronograf > Configuration > Add Kapacitor Connection:
Kapacitor URL: http://kapacitor:9092
Name: IoT Workshop Kapacitor
Username: (leave empty)
Password: (leave empty)
Step 8: Network และ การรันระบบ
ตรวจสอบว่า IoT Network มีอยู่แล้ว
# ตรวจสอบ network
docker network ls | grep iot
# ถ้ายังไม่มี สร้างใหม่
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--ip-range 172.20.240.0/20 \
iot-workshop_iot-net
รัน TICK Stack
cd deployments
# สร้าง .env file
cat > .env << 'EOF'
INFLUXDB_ADMIN_PASSWORD=admin123_secure
INFLUXDB_USER_PASSWORD=telegraf123_secure
INFLUXDB_READ_USER_PASSWORD=grafana123_secure
MQTT_USERNAME=iot_client
MQTT_PASSWORD=mqtt_secure_pass
CHRONOGRAF_TOKEN_SECRET=your_random_secret_here
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
SMTP_HOST=smtp.example.com
[email protected]
SMTP_PASSWORD=smtp_password
EOF
# รัน TICK stack
docker compose -f docker-compose.tick.yml up -d
# ตรวจสอบสถานะ
docker compose -f docker-compose.tick.yml ps
# ดู logs
docker compose -f docker-compose.tick.yml logs -f influxdb
docker compose -f docker-compose.tick.yml logs -f telegraf
ทดสอบ Connectivity
ถ้า TICK Stack ขึ้นมาครบแล้ว ลองยิง ping ดูทีละตัว:
[InfluxDB :8086] --> ping? --> HTTP 204 ✓
[Kapacitor :9092] --> ping? --> {"version":"..."} ✓
[Chronograf :8888] --> ping? --> HTML page ✓
# ทดสอบ InfluxDB
curl -u admin:admin123 http://localhost:8086/ping
# ควรได้ HTTP 204
# ทดสอบ Kapacitor
curl http://localhost:9092/kapacitor/v1/ping
# ควรได้ {"version":"..."}
# ทดสอบ Chronograf
curl http://localhost:8888
# ควรได้ HTML page
# ทดสอบ Write ข้อมูลไปยัง InfluxDB
curl -X POST "http://localhost:8086/write?db=iot_data" \
-u telegraf:telegraf123 \
--data-binary 'sensor_data,device_id=test001,measurement_type=temperature value=26.5'
echo "Write successful"
# ทดสอบ Query
curl -G "http://localhost:8086/query" \
-u admin:admin123 \
--data-urlencode "db=iot_data" \
--data-urlencode "q=SELECT * FROM sensor_data WHERE time > now() - 1m"
Step 9: Makefile Commands
เพิ่ม targets ใน Makefile หลัก เพื่อให้ทีมใช้งานง่ายขึ้น ไม่ต้องจำ docker compose command ยาวๆ:
# TICK Stack commands
tick-up:
@echo "Starting TICK Stack..."
cd deployments && docker compose -f docker-compose.tick.yml up -d
@echo "✓ TICK Stack started"
tick-down:
@echo "Stopping TICK Stack..."
cd deployments && docker compose -f docker-compose.tick.yml down
@echo "✓ TICK Stack stopped"
tick-logs:
cd deployments && docker compose -f docker-compose.tick.yml logs -f
tick-status:
cd deployments && docker compose -f docker-compose.tick.yml ps
influx-cli:
docker exec -it iot-influxdb influx -username admin -password $(INFLUXDB_ADMIN_PASSWORD)
tick-reset:
@echo "WARNING: This will delete all InfluxDB data!"
@read -p "Continue? [y/N] " confirm && [ "$$confirm" = "y" ]
cd deployments && docker compose -f docker-compose.tick.yml down -v
@echo "✓ TICK Stack data cleared"
สรุปสิ่งที่ทำใน Workshop นี้
___________________________
| TICK Stack is ready! |
| T - Telegraf [OK] |
| I - InfluxDB [OK] |
| C - Chronograf [OK] |
| K - Kapacitor [OK] |
|___________________________|
\(^o^)/
น้องๆ ทำอะไรไปบ้างในตอนนี้:
| สิ่งที่ทำ | รายละเอียด |
|---|---|
| Docker Compose | deploy ครบ TICK stack บน iot-net |
| InfluxDB | database, retention policies (raw/hourly/daily), continuous queries |
| Telegraf | agent config พร้อม InfluxDB output |
| Chronograf | เชื่อมต่อ InfluxDB + Kapacitor, สร้าง dashboard template |
| Kapacitor | config พร้อม webhook/Slack/email handlers |
| Network | ทุก container อยู่ใน iot-workshop_iot-net เดียวกัน |
สิ่งที่เราสร้างวันนี้คือ “กระดูกสันหลัง” ของระบบ IoT ทั้งหมด ข้อมูลจะไหลจาก sensor ผ่าน MQTT → Telegraf → InfluxDB แล้ว Chronograf กับ Kapacitor ก็นั่งรอดูอยู่
ขั้นตอนต่อไป
ตอนหน้าเราจะไปตั้งค่า Telegraf Pipeline ให้ดึงข้อมูลจาก MQTT แล้วประมวลผลก่อนยัดเข้า InfluxDB — นั่นคือส่วนที่ทำให้ระบบ “ฉลาด” จริงๆ อย่าพลาดนะครับ! (ง •̀_•́)ง