Node.js Entegrasyonu
Consul Guardian, Node.js uygulamanızın yanında sidecar olarak çalışır. Uygulamanız consul npm paketi veya HTTP çağrıları ile Consul KV'den konfigürasyon okur. Guardian aynı anahtarları bağımsız olarak izler, her değişikliği Git'e commit eder ve herhangi bir anahtarı önceki değerine geri yüklemenizi sağlar.
Uygulama kodunuzda hiçbir değişiklik gerekmez.
Node.js uygulamaları Consul'dan nasıl okur
| Paket | Açıklama |
|---|---|
| consul | Node.js için tam özellikli Consul istemcisi |
node-fetch / dahili fetch | Consul API'ye doğrudan HTTP çağrıları |
Örnek: consul npm paketi
npm install consul
const Consul = require("consul");
const consul = new Consul({ host: "consul", port: 8500 });
async function getConfig(key) {
const result = await consul.kv.get(key);
return result ? result.Value : null;
}
async function loadConfig() {
return {
dbHost: await getConfig("config/myapp/db_host"),
dbPort: parseInt(await getConfig("config/myapp/db_port"), 10),
cacheEnabled: (await getConfig("config/myapp/cache_enabled")) === "true",
maxRetries: parseInt(await getConfig("config/myapp/max_retries"), 10) || 3,
};
}
Örnek: Express uygulaması
const express = require("express");
const Consul = require("consul");
const app = express();
const consul = new Consul({ host: "consul", port: 8500 });
let config = {};
async function refreshConfig() {
const keys = [
"config/myapp/db_host",
"config/myapp/db_port",
"config/myapp/api_timeout",
];
for (const key of keys) {
const result = await consul.kv.get(key);
if (result) {
const shortKey = key.split("/").pop();
config[shortKey] = result.Value;
}
}
}
// Başlangıçta config yükle, her 30 saniyede yenile
refreshConfig();
setInterval(refreshConfig, 30000);
app.get("/health", (req, res) => {
res.json({ status: "ok", config });
});
app.listen(3000);
Örnek: NestJS ile Consul
// config.service.ts
import { Injectable, OnModuleInit } from "@nestjs/common";
import * as Consul from "consul";
@Injectable()
export class ConfigService implements OnModuleInit {
private consul: Consul.Consul;
private cache: Record<string, string> = {};
constructor() {
this.consul = new Consul({ host: "consul", port: 8500 });
}
async onModuleInit() {
await this.loadAll();
}
async loadAll() {
const keys = await this.consul.kv.keys("config/myapp/");
for (const key of keys) {
const result = await this.consul.kv.get(key);
if (result) {
this.cache[key] = result.Value;
}
}
}
get(key: string): string | undefined {
return this.cache[`config/myapp/${key}`];
}
}
Guardian ekleme
Docker Compose
version: "3.8"
services:
consul:
image: hashicorp/consul:1.17
ports:
- "8500:8500"
command: agent -dev -client=0.0.0.0
myapp:
build: .
ports:
- "3000:3000"
environment:
- CONSUL_HOST=consul
- CONSUL_PORT=8500
depends_on:
- consul
guardian:
image: ghcr.io/consul-guardian/consul-guardian:latest
environment:
- CONSUL_GUARDIAN_CONSUL_ADDRESS=http://consul:8500
- CONSUL_GUARDIAN_WATCH_PREFIXES=config/,feature-flags/
- CONSUL_GUARDIAN_GIT_REPO_PATH=/data/repo
volumes:
- guardian-data:/data
depends_on:
- consul
volumes:
guardian-data:
PM2 + Consul senaryosu
Production'da PM2 ile Node.js çalıştırıyor ve Consul'dan config okuyorsanız, Guardian aynı altyapıya kolayca eklenir:
version: "3.8"
services:
consul:
image: hashicorp/consul:1.17
command: agent -dev -client=0.0.0.0
myapp:
build: .
command: pm2-runtime ecosystem.config.js
environment:
- CONSUL_HOST=consul
depends_on:
- consul
guardian:
image: ghcr.io/consul-guardian/consul-guardian:latest
environment:
- CONSUL_GUARDIAN_CONSUL_ADDRESS=http://consul:8500
- CONSUL_GUARDIAN_WATCH_PREFIXES=config/,feature-flags/
- CONSUL_GUARDIAN_GIT_REPO_PATH=/data/repo
volumes:
- guardian-data:/data
depends_on:
- consul
volumes:
guardian-data:
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myregistry/myapp:latest
ports:
- containerPort: 3000
env:
- name: CONSUL_HOST
value: "consul.consul.svc.cluster.local"
- name: CONSUL_PORT
value: "8500"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: consul-guardian
spec:
replicas: 1
selector:
matchLabels:
app: consul-guardian
template:
metadata:
labels:
app: consul-guardian
spec:
containers:
- name: guardian
image: ghcr.io/consul-guardian/consul-guardian:latest
env:
- name: CONSUL_GUARDIAN_CONSUL_ADDRESS
value: "http://consul.consul.svc.cluster.local:8500"
- name: CONSUL_GUARDIAN_WATCH_PREFIXES
value: "config/,feature-flags/"
- name: CONSUL_GUARDIAN_GIT_REPO_PATH
value: "/data/repo"
volumeMounts:
- name: guardian-data
mountPath: /data
volumes:
- name: guardian-data
persistentVolumeClaim:
claimName: guardian-pvc
Geri yükleme senaryosu
Bir deploy scripti yanlışlıkla config/myapp/api_timeout değerini "5000" yerine "5" olarak yazar (5 saniye yerine 5 milisaniye). Tüm dış API çağrıları zaman aşımına uğramaya başlar.
1. Ne olduğunu bulun
consul-guardian log --key config/myapp/api_timeout
# 2024-03-15T13:22:00Z bad1234 config/myapp/api_timeout modified
# 2024-03-01T10:00:00Z good567 config/myapp/api_timeout modified
2. Geri yükleyin
consul-guardian restore --key config/myapp/api_timeout --commit good567
3. Doğrulayın
consul kv get config/myapp/api_timeout
# 5000 ← doğru değer geri yüklendi
Uygulamanız periyodik olarak config yeniliyorsa (yukarıdaki Express örneğinde olduğu gibi), düzeltmeyi otomatik olarak alır. Sadece başlangıçta config okuyorsa, process'i yeniden başlatın veya sinyal gönderin.
Kod değişikliği gerekmez
Guardian, package.json dosyanıza bağımlılık eklemez, Express veya NestJS'de middleware gerektirmez ve Consul okumalarınızı proxy'lemez. Consul KV'yi bağımsız olarak izleyen ayrı bir süreçtir.