Ana içeriğe geç

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

PaketAçıklama
consulNode.js için tam özellikli Consul istemcisi
node-fetch / dahili fetchConsul 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.