mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 18:28:27 +00:00
Merge pull request #3640 from akhilmhdh/feat/redis-sentinel-support
Feat/redis sentinel support
This commit is contained in:
@@ -15,8 +15,8 @@ import { mockSmtpServer } from "./mocks/smtp";
|
|||||||
import { initDbConnection } from "@app/db";
|
import { initDbConnection } from "@app/db";
|
||||||
import { queueServiceFactory } from "@app/queue";
|
import { queueServiceFactory } from "@app/queue";
|
||||||
import { keyStoreFactory } from "@app/keystore/keystore";
|
import { keyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { Redis } from "ioredis";
|
|
||||||
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
||||||
|
import { buildRedisFromConfig } from "@app/lib/config/redis";
|
||||||
|
|
||||||
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
||||||
export default {
|
export default {
|
||||||
@@ -30,7 +30,7 @@ export default {
|
|||||||
dbRootCert: envConfig.DB_ROOT_CERT
|
dbRootCert: envConfig.DB_ROOT_CERT
|
||||||
});
|
});
|
||||||
|
|
||||||
const redis = new Redis(envConfig.REDIS_URL);
|
const redis = buildRedisFromConfig(envConfig);
|
||||||
await redis.flushdb("SYNC");
|
await redis.flushdb("SYNC");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -55,8 +55,8 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const smtp = mockSmtpServer();
|
const smtp = mockSmtpServer();
|
||||||
const queue = queueServiceFactory(envConfig.REDIS_URL, { dbConnectionUrl: envConfig.DB_CONNECTION_URI });
|
const queue = queueServiceFactory(envConfig, { dbConnectionUrl: envConfig.DB_CONNECTION_URI });
|
||||||
const keyStore = keyStoreFactory(envConfig.REDIS_URL);
|
const keyStore = keyStoreFactory(envConfig);
|
||||||
|
|
||||||
const hsmModule = initializeHsmModule(envConfig);
|
const hsmModule = initializeHsmModule(envConfig);
|
||||||
hsmModule.initialize();
|
hsmModule.initialize();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Redis } from "ioredis";
|
import { buildRedisFromConfig, TRedisConfigKeys } from "@app/lib/config/redis";
|
||||||
|
|
||||||
import { pgAdvisoryLockHashText } from "@app/lib/crypto/hashtext";
|
import { pgAdvisoryLockHashText } from "@app/lib/crypto/hashtext";
|
||||||
import { applyJitter } from "@app/lib/dates";
|
import { applyJitter } from "@app/lib/dates";
|
||||||
import { delay as delayMs } from "@app/lib/delay";
|
import { delay as delayMs } from "@app/lib/delay";
|
||||||
@@ -68,8 +67,8 @@ type TWaitTillReady = {
|
|||||||
jitter?: number;
|
jitter?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const keyStoreFactory = (redisUrl: string) => {
|
export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys) => {
|
||||||
const redis = new Redis(redisUrl);
|
const redis = buildRedisFromConfig(redisConfigKeys);
|
||||||
const redisLock = new Redlock([redis], { retryCount: 2, retryDelay: 200 });
|
const redisLock = new Redlock([redis], { retryCount: 2, retryDelay: 200 });
|
||||||
|
|
||||||
const setItem = async (key: string, value: string | number | Buffer, prefix?: string) =>
|
const setItem = async (key: string, value: string | number | Buffer, prefix?: string) =>
|
||||||
|
|||||||
@@ -30,7 +30,19 @@ const envSchema = z
|
|||||||
.enum(["true", "false"])
|
.enum(["true", "false"])
|
||||||
.default("false")
|
.default("false")
|
||||||
.transform((el) => el === "true"),
|
.transform((el) => el === "true"),
|
||||||
REDIS_URL: zpStr(z.string()),
|
REDIS_URL: zpStr(z.string().optional()),
|
||||||
|
REDIS_SENTINEL_HOSTS: zpStr(
|
||||||
|
z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Comma-separated list of Sentinel host:port pairs. Eg: 192.168.65.254:26379,192.168.65.254:26380")
|
||||||
|
),
|
||||||
|
REDIS_SENTINEL_MASTER_NAME: zpStr(
|
||||||
|
z.string().optional().default("mymaster").describe("The name of the Redis master set monitored by Sentinel")
|
||||||
|
),
|
||||||
|
REDIS_SENTINEL_ENABLE_TLS: zodStrBool.optional().describe("Whether to use TLS/SSL for Redis Sentinel connection"),
|
||||||
|
REDIS_SENTINEL_USERNAME: zpStr(z.string().optional().describe("Authentication username for Redis Sentinel")),
|
||||||
|
REDIS_SENTINEL_PASSWORD: zpStr(z.string().optional().describe("Authentication password for Redis Sentinel")),
|
||||||
HOST: zpStr(z.string().default("localhost")),
|
HOST: zpStr(z.string().default("localhost")),
|
||||||
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database connection string")).default(
|
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database connection string")).default(
|
||||||
`postgresql://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`
|
`postgresql://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`
|
||||||
@@ -259,26 +271,34 @@ const envSchema = z
|
|||||||
(data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY),
|
(data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY),
|
||||||
"Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined."
|
"Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined."
|
||||||
)
|
)
|
||||||
|
.refine(
|
||||||
|
(data) => Boolean(data.REDIS_URL) || Boolean(data.REDIS_SENTINEL_HOSTS),
|
||||||
|
"Either REDIS_URL or REDIS_SENTINEL_HOSTS must be defined."
|
||||||
|
)
|
||||||
.transform((data) => ({
|
.transform((data) => ({
|
||||||
...data,
|
...data,
|
||||||
|
|
||||||
DB_READ_REPLICAS: data.DB_READ_REPLICAS
|
DB_READ_REPLICAS: data.DB_READ_REPLICAS
|
||||||
? databaseReadReplicaSchema.parse(JSON.parse(data.DB_READ_REPLICAS))
|
? databaseReadReplicaSchema.parse(JSON.parse(data.DB_READ_REPLICAS))
|
||||||
: undefined,
|
: undefined,
|
||||||
isCloud: Boolean(data.LICENSE_SERVER_KEY),
|
isCloud: Boolean(data.LICENSE_SERVER_KEY),
|
||||||
isSmtpConfigured: Boolean(data.SMTP_HOST),
|
isSmtpConfigured: Boolean(data.SMTP_HOST),
|
||||||
isRedisConfigured: Boolean(data.REDIS_URL),
|
isRedisConfigured: Boolean(data.REDIS_URL || data.REDIS_SENTINEL_HOSTS),
|
||||||
isDevelopmentMode: data.NODE_ENV === "development",
|
isDevelopmentMode: data.NODE_ENV === "development",
|
||||||
isRotationDevelopmentMode: data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE,
|
isRotationDevelopmentMode: data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE,
|
||||||
isProductionMode: data.NODE_ENV === "production" || IS_PACKAGED,
|
isProductionMode: data.NODE_ENV === "production" || IS_PACKAGED,
|
||||||
|
isRedisSentinelMode: Boolean(data.REDIS_SENTINEL_HOSTS),
|
||||||
|
REDIS_SENTINEL_HOSTS: data.REDIS_SENTINEL_HOSTS?.trim()
|
||||||
|
?.split(",")
|
||||||
|
.map((el) => {
|
||||||
|
const [host, port] = el.trim().split(":");
|
||||||
|
return { host: host.trim(), port: Number(port.trim()) };
|
||||||
|
}),
|
||||||
isSecretScanningConfigured:
|
isSecretScanningConfigured:
|
||||||
Boolean(data.SECRET_SCANNING_GIT_APP_ID) &&
|
Boolean(data.SECRET_SCANNING_GIT_APP_ID) &&
|
||||||
Boolean(data.SECRET_SCANNING_PRIVATE_KEY) &&
|
Boolean(data.SECRET_SCANNING_PRIVATE_KEY) &&
|
||||||
Boolean(data.SECRET_SCANNING_WEBHOOK_SECRET),
|
Boolean(data.SECRET_SCANNING_WEBHOOK_SECRET),
|
||||||
isHsmConfigured:
|
isHsmConfigured:
|
||||||
Boolean(data.HSM_LIB_PATH) && Boolean(data.HSM_PIN) && Boolean(data.HSM_KEY_LABEL) && data.HSM_SLOT !== undefined,
|
Boolean(data.HSM_LIB_PATH) && Boolean(data.HSM_PIN) && Boolean(data.HSM_KEY_LABEL) && data.HSM_SLOT !== undefined,
|
||||||
|
|
||||||
samlDefaultOrgSlug: data.DEFAULT_SAML_ORG_SLUG,
|
samlDefaultOrgSlug: data.DEFAULT_SAML_ORG_SLUG,
|
||||||
SECRET_SCANNING_ORG_WHITELIST: data.SECRET_SCANNING_ORG_WHITELIST?.split(",")
|
SECRET_SCANNING_ORG_WHITELIST: data.SECRET_SCANNING_ORG_WHITELIST?.split(",")
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { Redis } from "ioredis";
|
||||||
|
|
||||||
|
export type TRedisConfigKeys = Partial<{
|
||||||
|
REDIS_URL: string;
|
||||||
|
REDIS_SENTINEL_HOSTS: { host: string; port: number }[];
|
||||||
|
REDIS_SENTINEL_MASTER_NAME: string;
|
||||||
|
REDIS_SENTINEL_ENABLE_TLS: boolean;
|
||||||
|
REDIS_SENTINEL_USERNAME: string;
|
||||||
|
REDIS_SENTINEL_PASSWORD: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export const buildRedisFromConfig = (cfg: TRedisConfigKeys) => {
|
||||||
|
if (cfg.REDIS_URL) return new Redis(cfg.REDIS_URL, { maxRetriesPerRequest: null });
|
||||||
|
|
||||||
|
return new Redis({
|
||||||
|
// refine at tope will catch this case
|
||||||
|
sentinels: cfg.REDIS_SENTINEL_HOSTS!,
|
||||||
|
name: cfg.REDIS_SENTINEL_MASTER_NAME!,
|
||||||
|
maxRetriesPerRequest: null,
|
||||||
|
sentinelUsername: cfg.REDIS_SENTINEL_USERNAME,
|
||||||
|
sentinelPassword: cfg.REDIS_SENTINEL_PASSWORD,
|
||||||
|
enableTLSForSentinelMode: cfg.REDIS_SENTINEL_ENABLE_TLS
|
||||||
|
});
|
||||||
|
};
|
||||||
+4
-4
@@ -1,7 +1,6 @@
|
|||||||
import "./lib/telemetry/instrumentation";
|
import "./lib/telemetry/instrumentation";
|
||||||
|
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { Redis } from "ioredis";
|
|
||||||
|
|
||||||
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
||||||
|
|
||||||
@@ -9,6 +8,7 @@ import { runMigrations } from "./auto-start-migrations";
|
|||||||
import { initAuditLogDbConnection, initDbConnection } from "./db";
|
import { initAuditLogDbConnection, initDbConnection } from "./db";
|
||||||
import { keyStoreFactory } from "./keystore/keystore";
|
import { keyStoreFactory } from "./keystore/keystore";
|
||||||
import { formatSmtpConfig, initEnvConfig } from "./lib/config/env";
|
import { formatSmtpConfig, initEnvConfig } from "./lib/config/env";
|
||||||
|
import { buildRedisFromConfig } from "./lib/config/redis";
|
||||||
import { removeTemporaryBaseDirectory } from "./lib/files";
|
import { removeTemporaryBaseDirectory } from "./lib/files";
|
||||||
import { initLogger } from "./lib/logger";
|
import { initLogger } from "./lib/logger";
|
||||||
import { queueServiceFactory } from "./queue";
|
import { queueServiceFactory } from "./queue";
|
||||||
@@ -44,15 +44,15 @@ const run = async () => {
|
|||||||
|
|
||||||
const smtp = smtpServiceFactory(formatSmtpConfig());
|
const smtp = smtpServiceFactory(formatSmtpConfig());
|
||||||
|
|
||||||
const queue = queueServiceFactory(envConfig.REDIS_URL, {
|
const queue = queueServiceFactory(envConfig, {
|
||||||
dbConnectionUrl: envConfig.DB_CONNECTION_URI,
|
dbConnectionUrl: envConfig.DB_CONNECTION_URI,
|
||||||
dbRootCert: envConfig.DB_ROOT_CERT
|
dbRootCert: envConfig.DB_ROOT_CERT
|
||||||
});
|
});
|
||||||
|
|
||||||
await queue.initialize();
|
await queue.initialize();
|
||||||
|
|
||||||
const keyStore = keyStoreFactory(envConfig.REDIS_URL);
|
const keyStore = keyStoreFactory(envConfig);
|
||||||
const redis = new Redis(envConfig.REDIS_URL);
|
const redis = buildRedisFromConfig(envConfig);
|
||||||
|
|
||||||
const hsmModule = initializeHsmModule(envConfig);
|
const hsmModule = initializeHsmModule(envConfig);
|
||||||
hsmModule.initialize();
|
hsmModule.initialize();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Job, JobsOptions, Queue, QueueOptions, RepeatOptions, Worker, WorkerListener } from "bullmq";
|
import { Job, JobsOptions, Queue, QueueOptions, RepeatOptions, Worker, WorkerListener } from "bullmq";
|
||||||
import Redis from "ioredis";
|
|
||||||
import PgBoss, { WorkOptions } from "pg-boss";
|
import PgBoss, { WorkOptions } from "pg-boss";
|
||||||
|
|
||||||
import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
|
import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
|
||||||
@@ -13,6 +12,7 @@ import {
|
|||||||
TScanPushEventPayload
|
TScanPushEventPayload
|
||||||
} from "@app/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-queue-types";
|
} from "@app/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-queue-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { buildRedisFromConfig, TRedisConfigKeys } from "@app/lib/config/redis";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
|
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
|
||||||
import {
|
import {
|
||||||
@@ -265,10 +265,10 @@ export type TQueueJobTypes = {
|
|||||||
|
|
||||||
export type TQueueServiceFactory = ReturnType<typeof queueServiceFactory>;
|
export type TQueueServiceFactory = ReturnType<typeof queueServiceFactory>;
|
||||||
export const queueServiceFactory = (
|
export const queueServiceFactory = (
|
||||||
redisUrl: string,
|
redisCfg: TRedisConfigKeys,
|
||||||
{ dbConnectionUrl, dbRootCert }: { dbConnectionUrl: string; dbRootCert?: string }
|
{ dbConnectionUrl, dbRootCert }: { dbConnectionUrl: string; dbRootCert?: string }
|
||||||
) => {
|
) => {
|
||||||
const connection = new Redis(redisUrl, { maxRetriesPerRequest: null });
|
const connection = buildRedisFromConfig(redisCfg);
|
||||||
const queueContainer = {} as Record<
|
const queueContainer = {} as Record<
|
||||||
QueueName,
|
QueueName,
|
||||||
Queue<TQueueJobTypes[QueueName]["payload"], void, TQueueJobTypes[QueueName]["name"]>
|
Queue<TQueueJobTypes[QueueName]["payload"], void, TQueueJobTypes[QueueName]["name"]>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import { Redis } from "ioredis";
|
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
import { createTransport } from "nodemailer";
|
import { createTransport } from "nodemailer";
|
||||||
|
|
||||||
import { formatSmtpConfig, getConfig } from "@app/lib/config/env";
|
import { formatSmtpConfig, getConfig } from "@app/lib/config/env";
|
||||||
|
import { buildRedisFromConfig } from "@app/lib/config/redis";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
||||||
|
|
||||||
@@ -65,12 +65,15 @@ export const bootstrapCheck = async ({ db }: BootstrapOpt) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log("Testing redis connection");
|
console.log("Testing redis connection");
|
||||||
const redis = new Redis(appCfg.REDIS_URL);
|
const redis = buildRedisFromConfig(appCfg);
|
||||||
const redisPing = await redis?.ping();
|
const redisPing = await redis?.ping();
|
||||||
if (!redisPing) {
|
if (!redisPing) {
|
||||||
console.error("Redis - Failed to connect");
|
console.error("Redis - Failed to connect");
|
||||||
} else {
|
} else {
|
||||||
console.error("Redis successfully connected");
|
console.log("Redis successfully connected");
|
||||||
|
if (appCfg.isRedisSentinelMode) {
|
||||||
|
console.log("Redis Sentinel Mode");
|
||||||
|
}
|
||||||
redis.disconnect();
|
redis.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import type { RateLimitOptions, RateLimitPluginOptions } from "@fastify/rate-limit";
|
import type { RateLimitOptions, RateLimitPluginOptions } from "@fastify/rate-limit";
|
||||||
import { Redis } from "ioredis";
|
|
||||||
|
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { buildRedisFromConfig } from "@app/lib/config/redis";
|
||||||
import { RateLimitError } from "@app/lib/errors";
|
import { RateLimitError } from "@app/lib/errors";
|
||||||
|
|
||||||
export const globalRateLimiterCfg = (): RateLimitPluginOptions => {
|
export const globalRateLimiterCfg = (): RateLimitPluginOptions => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const redis = appCfg.isRedisConfigured
|
const redis = appCfg.isRedisConfigured ? buildRedisFromConfig(appCfg) : null;
|
||||||
? new Redis(appCfg.REDIS_URL, { connectTimeout: 500, maxRetriesPerRequest: 1 })
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
errorResponseBuilder: (_, context) => {
|
errorResponseBuilder: (_, context) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: "Configurations"
|
title: "Environment Variables"
|
||||||
description: "Read how to configure environment variables for self-hosted Infisical."
|
description: "Read how to configure environment variables for self-hosted Infisical."
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -34,12 +34,14 @@ Used to configure platform-specific security and operational settings
|
|||||||
|
|
||||||
By default, Infisical binds to `localhost`, which restricts access to connections from the same machine.
|
By default, Infisical binds to `localhost`, which restricts access to connections from the same machine.
|
||||||
|
|
||||||
To make the application accessible externally (e.g., for self-hosted deployments), set this to `0.0.0.0`, which tells the server to listen on all network interfaces.
|
To make the application accessible externally (e.g., for self-hosted deployments), set this to `0.0.0.0`, which tells the server to listen on all network interfaces.
|
||||||
|
|
||||||
|
Example values:
|
||||||
|
|
||||||
|
- `localhost` (default, same as `127.0.0.1`)
|
||||||
|
- `0.0.0.0` (all interfaces, accessible externally)
|
||||||
|
- `192.168.1.100` (specific interface IP)
|
||||||
|
|
||||||
Example values:
|
|
||||||
- `localhost` (default, same as `127.0.0.1`)
|
|
||||||
- `0.0.0.0` (all interfaces, accessible externally)
|
|
||||||
- `192.168.1.100` (specific interface IP)
|
|
||||||
</ParamField>
|
</ParamField>
|
||||||
|
|
||||||
<ParamField query="TELEMETRY_ENABLED" type="string" default="true" optional>
|
<ParamField query="TELEMETRY_ENABLED" type="string" default="true" optional>
|
||||||
@@ -86,8 +88,9 @@ The platform utilizes Postgres to persist all of its data and Redis for caching
|
|||||||
### PostgreSQL
|
### PostgreSQL
|
||||||
|
|
||||||
<Info>
|
<Info>
|
||||||
Please note that the database user you create must be granted all privileges on the Infisical database.
|
Please note that the database user you create must be granted all privileges
|
||||||
This includes the ability to create new schemas, create, update, delete, modify tables and indexes, etc.
|
on the Infisical database. This includes the ability to create new schemas,
|
||||||
|
create, update, delete, modify tables and indexes, etc.
|
||||||
</Info>
|
</Info>
|
||||||
|
|
||||||
<ParamField query="DB_CONNECTION_URI" type="string" default="" required>
|
<ParamField query="DB_CONNECTION_URI" type="string" default="" required>
|
||||||
@@ -119,10 +122,42 @@ DB_READ_REPLICAS=[{"DB_CONNECTION_URI":""}]
|
|||||||
</ParamField>
|
</ParamField>
|
||||||
|
|
||||||
### Redis
|
### Redis
|
||||||
|
Redis is used for caching and background tasks. You can use either a standalone Redis instance or a Redis Sentinel setup.
|
||||||
|
|
||||||
<ParamField query="REDIS_URL" type="string" default="none" required>
|
<Tabs>
|
||||||
Redis connection string.
|
<Tab title="Redis standalone">
|
||||||
</ParamField>
|
<ParamField query="REDIS_URL" type="string" default="none" required>
|
||||||
|
Redis connection string.
|
||||||
|
</ParamField>
|
||||||
|
</Tab>
|
||||||
|
<Tab title="Redis Sentinel">
|
||||||
|
<ParamField
|
||||||
|
query="REDIS_SENTINEL_HOSTS"
|
||||||
|
type="string"
|
||||||
|
default="none"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
Comma-separated list of Sentinel host:port pairs. ```
|
||||||
|
192.168.65.254:26379,192.168.65.254:26380 ```
|
||||||
|
</ParamField>
|
||||||
|
<ParamField
|
||||||
|
query="REDIS_SENTINEL_MASTER_NAME"
|
||||||
|
type="string"
|
||||||
|
default="mymaster"
|
||||||
|
>
|
||||||
|
The name of the Redis master set monitored by Sentinel
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="REDIS_SENTINEL_ENABLE_TLS" type="bool" default="false">
|
||||||
|
Whether to use TLS/SSL for Redis Sentinel connection
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="REDIS_SENTINEL_USERNAME" type="string" default="none">
|
||||||
|
Authentication username for Redis Sentinel
|
||||||
|
</ParamField>
|
||||||
|
<ParamField query="REDIS_SENTINEL_PASSWORD" type="string" default="none">
|
||||||
|
Authentication password for Redis Sentinel
|
||||||
|
</ParamField>
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
## Email Service
|
## Email Service
|
||||||
|
|
||||||
@@ -640,13 +675,27 @@ To help you sync secrets from Infisical to services such as Github and Gitlab, I
|
|||||||
The App ID of your GitHub App.
|
The App ID of your GitHub App.
|
||||||
</ParamField>
|
</ParamField>
|
||||||
|
|
||||||
<ParamField query="SECRET_SCANNING_GIT_APP_SLUG" type="string" default="none" optional>
|
{" "}
|
||||||
The slug of your GitHub App.
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
<ParamField query="SECRET_SCANNING_PRIVATE_KEY" type="string" default="none" optional>
|
<ParamField
|
||||||
A private key for your GitHub App.
|
query="SECRET_SCANNING_GIT_APP_SLUG"
|
||||||
</ParamField>
|
type="string"
|
||||||
|
default="none"
|
||||||
|
optional
|
||||||
|
>
|
||||||
|
The slug of your GitHub App.
|
||||||
|
</ParamField>
|
||||||
|
|
||||||
|
{" "}
|
||||||
|
|
||||||
|
<ParamField
|
||||||
|
query="SECRET_SCANNING_PRIVATE_KEY"
|
||||||
|
type="string"
|
||||||
|
default="none"
|
||||||
|
optional
|
||||||
|
>
|
||||||
|
A private key for your GitHub App.
|
||||||
|
</ParamField>
|
||||||
|
|
||||||
<ParamField query="SECRET_SCANNING_WEBHOOK_SECRET" type="string" default="none" optional>
|
<ParamField query="SECRET_SCANNING_WEBHOOK_SECRET" type="string" default="none" optional>
|
||||||
The webhook secret of your GitHub App.
|
The webhook secret of your GitHub App.
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
HOST_IP=
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
## Sink for Redis Sentinel
|
||||||
|
|
||||||
|
1. Create a `.env` from `.env.example`
|
||||||
|
2. The HOST_IP value must be your host ip, so that redis inside the containers can connect to it and switch over as needed.
|
||||||
|
|
||||||
|
To test Sentinel is working correctly
|
||||||
|
|
||||||
|
1. Run
|
||||||
|
|
||||||
|
```
|
||||||
|
docker exec -it sentinel-2 redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose -f docker-compose.sentinel.yml stop redis-master
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Again running step 1 should show the other replica port.
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
redis-master:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: redis-master
|
||||||
|
hostname: redis-master
|
||||||
|
ports:
|
||||||
|
- "6380:6379"
|
||||||
|
volumes:
|
||||||
|
- ./data/master:/data
|
||||||
|
command:
|
||||||
|
[
|
||||||
|
"redis-server",
|
||||||
|
"--appendonly",
|
||||||
|
"yes",
|
||||||
|
"--repl-diskless-load",
|
||||||
|
"on-empty-db",
|
||||||
|
"--replica-announce-ip",
|
||||||
|
"${HOST_IP}",
|
||||||
|
"--replica-announce-port",
|
||||||
|
"6380",
|
||||||
|
"--protected-mode",
|
||||||
|
"no",
|
||||||
|
]
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
ipv4_address: 172.21.0.3
|
||||||
|
|
||||||
|
redis-slave-1:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: redis-slave-1
|
||||||
|
hostname: redis-slave-1
|
||||||
|
depends_on:
|
||||||
|
- redis-master
|
||||||
|
ports:
|
||||||
|
- "6381:6379"
|
||||||
|
volumes:
|
||||||
|
- ./data/slave1:/data
|
||||||
|
command:
|
||||||
|
[
|
||||||
|
"redis-server",
|
||||||
|
"--appendonly",
|
||||||
|
"yes",
|
||||||
|
"--replicaof",
|
||||||
|
"redis-master",
|
||||||
|
"6379",
|
||||||
|
"--repl-diskless-load",
|
||||||
|
"on-empty-db",
|
||||||
|
"--replica-announce-ip",
|
||||||
|
"${HOST_IP}",
|
||||||
|
"--replica-announce-port",
|
||||||
|
"6381",
|
||||||
|
"--protected-mode",
|
||||||
|
"no",
|
||||||
|
]
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
ipv4_address: 172.21.0.4
|
||||||
|
|
||||||
|
redis-slave-2:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: redis-slave-2
|
||||||
|
hostname: redis-slave-2
|
||||||
|
depends_on:
|
||||||
|
- redis-master
|
||||||
|
ports:
|
||||||
|
- "6382:6379"
|
||||||
|
volumes:
|
||||||
|
- ./data/slave2:/data
|
||||||
|
command:
|
||||||
|
[
|
||||||
|
"redis-server",
|
||||||
|
"--appendonly",
|
||||||
|
"yes",
|
||||||
|
"--replicaof",
|
||||||
|
"redis-master",
|
||||||
|
"6379",
|
||||||
|
"--repl-diskless-load",
|
||||||
|
"on-empty-db",
|
||||||
|
"--replica-announce-ip",
|
||||||
|
"${HOST_IP}",
|
||||||
|
"--replica-announce-port",
|
||||||
|
"6382",
|
||||||
|
"--protected-mode",
|
||||||
|
"no",
|
||||||
|
]
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
ipv4_address: 172.21.0.5
|
||||||
|
|
||||||
|
sentinel-1:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: sentinel-1
|
||||||
|
hostname: sentinel-1
|
||||||
|
depends_on:
|
||||||
|
- redis-master
|
||||||
|
ports:
|
||||||
|
- "26379:26379"
|
||||||
|
command: >
|
||||||
|
sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf &&
|
||||||
|
echo "sentinel monitor mymaster ${HOST_IP} 6380 2" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf &&
|
||||||
|
redis-sentinel /etc/sentinel.conf'
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
ipv4_address: 172.21.0.6
|
||||||
|
|
||||||
|
sentinel-2:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: sentinel-2
|
||||||
|
hostname: sentinel-2
|
||||||
|
depends_on:
|
||||||
|
- redis-master
|
||||||
|
ports:
|
||||||
|
- "26380:26379"
|
||||||
|
command: >
|
||||||
|
sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf &&
|
||||||
|
echo "sentinel monitor mymaster ${HOST_IP} 6380 2" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf &&
|
||||||
|
redis-sentinel /etc/sentinel.conf'
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
ipv4_address: 172.21.0.7
|
||||||
|
|
||||||
|
sentinel-3:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: sentinel-3
|
||||||
|
hostname: sentinel-3
|
||||||
|
depends_on:
|
||||||
|
- redis-master
|
||||||
|
ports:
|
||||||
|
- "26381:26379"
|
||||||
|
command: >
|
||||||
|
sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf &&
|
||||||
|
echo "sentinel monitor mymaster ${HOST_IP} 6380 2" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf &&
|
||||||
|
echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf &&
|
||||||
|
redis-sentinel /etc/sentinel.conf'
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
ipv4_address: 172.21.0.8
|
||||||
|
|
||||||
|
redisinsight:
|
||||||
|
image: redis/redisinsight:latest
|
||||||
|
container_name: redisinsight
|
||||||
|
ports:
|
||||||
|
- "5540:5540"
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
ipv4_address: 172.21.0.9
|
||||||
|
|
||||||
|
networks:
|
||||||
|
redis-net:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 172.21.0.0/16
|
||||||
Reference in New Issue
Block a user