Compare commits
10 Commits
f21234790e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 4884b05f35 | |||
| 605d06ba5c | |||
| 07244800f7 | |||
| 85af933847 | |||
| 7859803df5 | |||
| e3f8a84ff5 | |||
| ff895e4193 | |||
| c1a481a269 | |||
| bfe4a1cbae | |||
| a2d6b6f460 |
Generated
+8
-8
@@ -7,32 +7,32 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1714043624,
|
"lastModified": 1752780124,
|
||||||
"narHash": "sha256-Xn2r0Jv95TswvPlvamCC46wwNo8ALjRCMBJbGykdhcM=",
|
"narHash": "sha256-5dn97vIYxn6VozKePOQSDxVCsrl38nDdMJXx86KIJH0=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "86853e31dc1b62c6eeed11c667e8cdd0285d4411",
|
"rev": "c718918222bdb104397762dea67e6b397a7927fe",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"ref": "release-23.11",
|
"ref": "release-25.05",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1713995372,
|
"lastModified": 1752480373,
|
||||||
"narHash": "sha256-fFE3M0vCoiSwCX02z8VF58jXFRj9enYUSTqjyHAjrds=",
|
"narHash": "sha256-JHQbm+OcGp32wAsXTE/FLYGNpb+4GLi5oTvCxwSoBOA=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "dd37924974b9202f8226ed5d74a252a9785aedf8",
|
"rev": "62e0f05ede1da0d54515d4ea8ce9c733f12d9f08",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"ref": "nixos-23.11",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
# Nixpkgs
|
# Nixpkgs
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
# You can access packages and modules from different nixpkgs revs
|
# You can access packages and modules from different nixpkgs revs
|
||||||
# at the same time. Here's an working example:
|
# at the same time. Here's an working example:
|
||||||
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
# Also see the 'unstable-packages' overlay at 'overlays/default.nix'.
|
# Also see the 'unstable-packages' overlay at 'overlays/default.nix'.
|
||||||
|
|
||||||
# Home manager
|
# Home manager
|
||||||
home-manager.url = "github:nix-community/home-manager/release-23.11";
|
home-manager.url = "github:nix-community/home-manager/release-25.05";
|
||||||
home-manager.inputs.nixpkgs.follows = "nixpkgs";
|
home-manager.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,5 @@
|
|||||||
incus = import ./incus.nix;
|
incus = import ./incus.nix;
|
||||||
orbstack = import ./orbstack.nix;
|
orbstack = import ./orbstack.nix;
|
||||||
power-user-defaults = import ./power-user-defaults.nix;
|
power-user-defaults = import ./power-user-defaults.nix;
|
||||||
|
redis-cluster = import ./redis-cluster.nix;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
# Disable sshd
|
# Disable sshd
|
||||||
services.openssh.enable = false;
|
# services.openssh.enable = false; disable for port 22
|
||||||
|
|
||||||
# systemd
|
# systemd
|
||||||
systemd.services."systemd-oomd".serviceConfig.WatchdogSec = 0;
|
systemd.services."systemd-oomd".serviceConfig.WatchdogSec = 0;
|
||||||
|
|||||||
@@ -0,0 +1,531 @@
|
|||||||
|
# Redis Cluster NixOS Configuration Module
|
||||||
|
# Optimized for high throughput and lowest latency
|
||||||
|
# Security disabled for maximum performance
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.redisCluster;
|
||||||
|
|
||||||
|
# Generate Redis instances for cluster
|
||||||
|
generateRedisInstances = masters: replicasPerMaster: basePort:
|
||||||
|
let
|
||||||
|
# Create master instances
|
||||||
|
masterInstances = listToAttrs (map (i: {
|
||||||
|
name = "master-${toString i}";
|
||||||
|
value = {
|
||||||
|
enable = true;
|
||||||
|
port = basePort + i;
|
||||||
|
bind = "0.0.0.0"; # Bind to all interfaces for cluster communication
|
||||||
|
|
||||||
|
# Cluster configuration
|
||||||
|
extraParams = [
|
||||||
|
"--cluster-enabled" "yes"
|
||||||
|
"--cluster-config-file" "nodes-${toString (basePort + i)}.conf"
|
||||||
|
"--cluster-node-timeout" "5000"
|
||||||
|
"--cluster-announce-ip" cfg.announceIp
|
||||||
|
"--cluster-announce-port" (toString (basePort + i))
|
||||||
|
];
|
||||||
|
|
||||||
|
# Performance optimizations
|
||||||
|
save = []; # Disable RDB for maximum performance
|
||||||
|
appendOnly = false; # Disable AOF for maximum performance
|
||||||
|
|
||||||
|
# High-performance settings
|
||||||
|
settings = {
|
||||||
|
# Memory and performance optimizations
|
||||||
|
maxclients = mkForce 65000;
|
||||||
|
timeout = mkForce 0; # Never timeout connections
|
||||||
|
tcp-keepalive = mkForce 60;
|
||||||
|
tcp-backlog = mkForce 511;
|
||||||
|
|
||||||
|
# Disable slow operations for performance
|
||||||
|
slowlog-log-slower-than = mkForce (-1); # Disable slow log
|
||||||
|
|
||||||
|
# Memory optimization
|
||||||
|
maxmemory-policy = mkForce "noeviction"; # Don't evict keys
|
||||||
|
|
||||||
|
# Network optimizations
|
||||||
|
# Note: tcp-nodelay is automatically handled by Redis as a socket option
|
||||||
|
|
||||||
|
# Hash optimizations for speed
|
||||||
|
hash-max-ziplist-entries = mkForce 512;
|
||||||
|
hash-max-ziplist-value = mkForce 64;
|
||||||
|
list-max-ziplist-size = mkForce (-2);
|
||||||
|
set-max-intset-entries = mkForce 512;
|
||||||
|
zset-max-ziplist-entries = mkForce 128;
|
||||||
|
zset-max-ziplist-value = mkForce 64;
|
||||||
|
|
||||||
|
# Cluster optimizations
|
||||||
|
cluster-require-full-coverage = mkForce "no"; # Allow partial cluster operation
|
||||||
|
cluster-allow-reads-when-down = mkForce "yes";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) (range 0 (masters - 1)));
|
||||||
|
|
||||||
|
# Create replica instances
|
||||||
|
replicaInstances = listToAttrs (flatten (map (masterIdx:
|
||||||
|
map (replicaIdx: {
|
||||||
|
name = "replica-${toString masterIdx}-${toString replicaIdx}";
|
||||||
|
value = {
|
||||||
|
enable = true;
|
||||||
|
port = basePort + masters + (masterIdx * replicasPerMaster) + replicaIdx;
|
||||||
|
bind = "0.0.0.0";
|
||||||
|
|
||||||
|
# Cluster configuration
|
||||||
|
extraParams = [
|
||||||
|
"--cluster-enabled" "yes"
|
||||||
|
"--cluster-config-file" "nodes-${toString (basePort + masters + (masterIdx * replicasPerMaster) + replicaIdx)}.conf"
|
||||||
|
"--cluster-node-timeout" "5000"
|
||||||
|
"--cluster-announce-ip" cfg.announceIp
|
||||||
|
"--cluster-announce-port" (toString (basePort + masters + (masterIdx * replicasPerMaster) + replicaIdx))
|
||||||
|
];
|
||||||
|
|
||||||
|
# Performance optimizations (same as masters)
|
||||||
|
save = [];
|
||||||
|
appendOnly = false;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
maxclients = mkForce 65000;
|
||||||
|
timeout = mkForce 0;
|
||||||
|
tcp-keepalive = mkForce 60;
|
||||||
|
tcp-backlog = mkForce 511;
|
||||||
|
slowlog-log-slower-than = mkForce (-1);
|
||||||
|
maxmemory-policy = mkForce "noeviction";
|
||||||
|
# Note: tcp-nodelay is automatically handled by Redis as a socket option
|
||||||
|
hash-max-ziplist-entries = mkForce 512;
|
||||||
|
hash-max-ziplist-value = mkForce 64;
|
||||||
|
list-max-ziplist-size = mkForce (-2);
|
||||||
|
set-max-intset-entries = mkForce 512;
|
||||||
|
zset-max-ziplist-entries = mkForce 128;
|
||||||
|
zset-max-ziplist-value = mkForce 64;
|
||||||
|
cluster-require-full-coverage = mkForce "no";
|
||||||
|
cluster-allow-reads-when-down = mkForce "yes";
|
||||||
|
|
||||||
|
# Replica-specific settings
|
||||||
|
replica-read-only = mkForce "no"; # Allow writes to replicas in cluster mode
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) (range 0 (replicasPerMaster - 1))
|
||||||
|
) (range 0 (masters - 1))));
|
||||||
|
|
||||||
|
in masterInstances // replicaInstances;
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options.services.redisCluster = {
|
||||||
|
enable = mkEnableOption "Redis Cluster";
|
||||||
|
|
||||||
|
masters = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 3;
|
||||||
|
description = "Number of master nodes in the cluster (minimum 3)";
|
||||||
|
};
|
||||||
|
|
||||||
|
replicasPerMaster = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 1;
|
||||||
|
description = "Number of replica nodes per master";
|
||||||
|
};
|
||||||
|
|
||||||
|
basePort = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 7000;
|
||||||
|
description = "Base port number for Redis cluster nodes";
|
||||||
|
};
|
||||||
|
|
||||||
|
announceIp = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "IP address to announce to other cluster nodes";
|
||||||
|
};
|
||||||
|
|
||||||
|
openFirewall = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Open firewall ports for cluster communication";
|
||||||
|
};
|
||||||
|
|
||||||
|
createCluster = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Automatically create and initialize the cluster";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.masters >= 3;
|
||||||
|
message = "Redis cluster requires at least 3 master nodes";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Configure Redis instances
|
||||||
|
services.redis = {
|
||||||
|
# Global Redis optimizations
|
||||||
|
vmOverCommit = true;
|
||||||
|
package = pkgs.redis;
|
||||||
|
|
||||||
|
servers = generateRedisInstances cfg.masters cfg.replicasPerMaster cfg.basePort;
|
||||||
|
};
|
||||||
|
|
||||||
|
# System-wide performance optimizations
|
||||||
|
boot.kernel.sysctl = {
|
||||||
|
# Network optimizations
|
||||||
|
"net.core.somaxconn" = mkForce "65535";
|
||||||
|
"net.core.netdev_max_backlog" = mkForce "5000";
|
||||||
|
"net.ipv4.tcp_max_syn_backlog" = mkForce "65535";
|
||||||
|
"net.ipv4.tcp_fin_timeout" = mkForce "30";
|
||||||
|
"net.ipv4.tcp_keepalive_time" = mkForce "1200";
|
||||||
|
"net.ipv4.tcp_keepalive_intvl" = mkForce "15";
|
||||||
|
"net.ipv4.tcp_keepalive_probes" = mkForce "5";
|
||||||
|
|
||||||
|
# Memory optimizations
|
||||||
|
"vm.swappiness" = mkForce "1";
|
||||||
|
"vm.overcommit_memory" = mkForce "1";
|
||||||
|
"vm.dirty_background_ratio" = mkForce "5";
|
||||||
|
"vm.dirty_ratio" = mkForce "10";
|
||||||
|
|
||||||
|
# File system optimizations
|
||||||
|
"fs.file-max" = mkForce "2097152";
|
||||||
|
};
|
||||||
|
|
||||||
|
# System-wide ulimit settings for Redis
|
||||||
|
security.pam.loginLimits = [
|
||||||
|
{
|
||||||
|
domain = "*";
|
||||||
|
type = "soft";
|
||||||
|
item = "nofile";
|
||||||
|
value = "1048576";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
domain = "*";
|
||||||
|
type = "hard";
|
||||||
|
item = "nofile";
|
||||||
|
value = "1048576";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Service-level optimizations for all Redis instances
|
||||||
|
systemd.services =
|
||||||
|
let
|
||||||
|
redisServices = map (i: "redis-master-${toString i}") (range 0 (cfg.masters - 1)) ++
|
||||||
|
flatten (map (masterIdx:
|
||||||
|
map (replicaIdx: "redis-replica-${toString masterIdx}-${toString replicaIdx}")
|
||||||
|
(range 0 (cfg.replicasPerMaster - 1))
|
||||||
|
) (range 0 (cfg.masters - 1)));
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
# Resource limits - set much higher for Redis cluster
|
||||||
|
LimitNOFILE = "1048576";
|
||||||
|
LimitNPROC = "65535";
|
||||||
|
LimitMEMLOCK = "infinity";
|
||||||
|
|
||||||
|
# CPU and scheduling optimizations
|
||||||
|
Nice = "-10";
|
||||||
|
IOSchedulingClass = "1";
|
||||||
|
IOSchedulingPriority = "4";
|
||||||
|
|
||||||
|
# Memory optimizations
|
||||||
|
OOMScoreAdjust = "-900";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Redis service optimizations
|
||||||
|
redisServiceConfigs = listToAttrs (map (serviceName: {
|
||||||
|
name = serviceName;
|
||||||
|
value = { inherit serviceConfig; };
|
||||||
|
}) redisServices);
|
||||||
|
|
||||||
|
# Cluster initialization service
|
||||||
|
clusterInitService = mkIf cfg.createCluster {
|
||||||
|
redis-cluster-init = {
|
||||||
|
description = "Initialize Redis Cluster";
|
||||||
|
after = map (i: "redis-master-${toString i}.service") (range 0 (cfg.masters - 1));
|
||||||
|
wants = map (i: "redis-master-${toString i}.service") (range 0 (cfg.masters - 1));
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStart = let
|
||||||
|
masterNodes = concatStringsSep " " (map (i:
|
||||||
|
"${cfg.announceIp}:${toString (cfg.basePort + i)}"
|
||||||
|
) (range 0 (cfg.masters - 1)));
|
||||||
|
in "${pkgs.redis}/bin/redis-cli --cluster create ${masterNodes} --cluster-replicas ${toString cfg.replicasPerMaster} --cluster-yes";
|
||||||
|
|
||||||
|
# Wait for Redis instances to be ready
|
||||||
|
ExecStartPre = "${pkgs.bash}/bin/bash -c 'for i in {1..30}; do ${pkgs.redis}/bin/redis-cli -p ${toString cfg.basePort} ping && break || sleep 2; done'";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
in redisServiceConfigs // clusterInitService;
|
||||||
|
|
||||||
|
# Firewall configuration
|
||||||
|
networking.firewall = mkIf cfg.openFirewall {
|
||||||
|
allowedTCPPorts =
|
||||||
|
# Redis cluster ports
|
||||||
|
(map (i: cfg.basePort + i) (range 0 (cfg.masters - 1))) ++
|
||||||
|
# Replica ports
|
||||||
|
(map (i: cfg.basePort + cfg.masters + i) (range 0 (cfg.masters * cfg.replicasPerMaster - 1))) ++
|
||||||
|
# Cluster bus ports (node port + 10000)
|
||||||
|
(map (i: cfg.basePort + i + 10000) (range 0 (cfg.masters - 1))) ++
|
||||||
|
(map (i: cfg.basePort + cfg.masters + i + 10000) (range 0 (cfg.masters * cfg.replicasPerMaster - 1)));
|
||||||
|
};
|
||||||
|
|
||||||
|
# Cluster management utilities
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.redis
|
||||||
|
(pkgs.writeShellScriptBin "redis-cluster-rebuild" ''
|
||||||
|
exec /etc/redis-cluster-rebuild.sh "$@"
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
|
||||||
|
# Create helper scripts
|
||||||
|
environment.etc."redis-cluster-info.sh" = {
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Redis Cluster Information:"
|
||||||
|
echo "========================="
|
||||||
|
echo "Masters: ${toString cfg.masters}"
|
||||||
|
echo "Replicas per master: ${toString cfg.replicasPerMaster}"
|
||||||
|
echo "Base port: ${toString cfg.basePort}"
|
||||||
|
echo "Announce IP: ${cfg.announceIp}"
|
||||||
|
echo ""
|
||||||
|
echo "Master nodes:"
|
||||||
|
${concatStringsSep "\n" (map (i:
|
||||||
|
"echo \" Master ${toString i}: ${cfg.announceIp}:${toString (cfg.basePort + i)}\""
|
||||||
|
) (range 0 (cfg.masters - 1)))}
|
||||||
|
echo ""
|
||||||
|
echo "Cluster status:"
|
||||||
|
${pkgs.redis}/bin/redis-cli -p ${toString cfg.basePort} cluster nodes
|
||||||
|
'';
|
||||||
|
mode = "0755";
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc."redis-cluster-rebuild.sh" = {
|
||||||
|
text = ''
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration from NixOS
|
||||||
|
MASTERS=${toString cfg.masters}
|
||||||
|
REPLICAS_PER_MASTER=${toString cfg.replicasPerMaster}
|
||||||
|
BASE_PORT=${toString cfg.basePort}
|
||||||
|
ANNOUNCE_IP="${cfg.announceIp}"
|
||||||
|
|
||||||
|
echo "Redis Cluster Rebuild Script"
|
||||||
|
echo "============================"
|
||||||
|
echo "Masters: $MASTERS"
|
||||||
|
echo "Replicas per master: $REPLICAS_PER_MASTER"
|
||||||
|
echo "Base port: $BASE_PORT"
|
||||||
|
echo "Announce IP: $ANNOUNCE_IP"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Function to stop all Redis services
|
||||||
|
stop_redis_services() {
|
||||||
|
echo "Stopping Redis services..."
|
||||||
|
|
||||||
|
# Stop cluster init service first
|
||||||
|
systemctl stop redis-cluster-init.service 2>/dev/null || true
|
||||||
|
|
||||||
|
# Stop all master services
|
||||||
|
for i in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
echo " Stopping redis-master-$i..."
|
||||||
|
systemctl stop redis-master-$i.service 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Stop all replica services
|
||||||
|
for master_idx in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
for replica_idx in $(seq 0 $((REPLICAS_PER_MASTER - 1))); do
|
||||||
|
echo " Stopping redis-replica-$master_idx-$replica_idx..."
|
||||||
|
systemctl stop redis-replica-$master_idx-$replica_idx.service 2>/dev/null || true
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "All Redis services stopped."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to clean Redis data directories
|
||||||
|
clean_redis_data() {
|
||||||
|
echo "Cleaning Redis data directories..."
|
||||||
|
|
||||||
|
# Remove main Redis data directory
|
||||||
|
if [ -d "/var/lib/redis" ]; then
|
||||||
|
echo " Removing /var/lib/redis..."
|
||||||
|
rm -rf /var/lib/redis
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove any cluster configuration files from working directories
|
||||||
|
for i in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
local port=$((BASE_PORT + i))
|
||||||
|
rm -f /var/lib/redis*/nodes-$port.conf 2>/dev/null || true
|
||||||
|
rm -f /tmp/nodes-$port.conf 2>/dev/null || true
|
||||||
|
rm -f ./nodes-$port.conf 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove replica cluster config files
|
||||||
|
for master_idx in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
for replica_idx in $(seq 0 $((REPLICAS_PER_MASTER - 1))); do
|
||||||
|
local port=$((BASE_PORT + MASTERS + master_idx * REPLICAS_PER_MASTER + replica_idx))
|
||||||
|
rm -f /var/lib/redis*/nodes-$port.conf 2>/dev/null || true
|
||||||
|
rm -f /tmp/nodes-$port.conf 2>/dev/null || true
|
||||||
|
rm -f ./nodes-$port.conf 2>/dev/null || true
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Redis data directories cleaned."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to start Redis services
|
||||||
|
start_redis_services() {
|
||||||
|
echo "Starting Redis services..."
|
||||||
|
|
||||||
|
# Start all master services
|
||||||
|
for i in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
echo " Starting redis-master-$i..."
|
||||||
|
systemctl start redis-master-$i.service
|
||||||
|
done
|
||||||
|
|
||||||
|
# Start all replica services
|
||||||
|
for master_idx in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
for replica_idx in $(seq 0 $((REPLICAS_PER_MASTER - 1))); do
|
||||||
|
echo " Starting redis-replica-$master_idx-$replica_idx..."
|
||||||
|
systemctl start redis-replica-$master_idx-$replica_idx.service
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "All Redis services started."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to wait for Redis services to be ready
|
||||||
|
wait_for_redis() {
|
||||||
|
echo "Waiting for Redis services to be ready..."
|
||||||
|
|
||||||
|
# Wait for masters
|
||||||
|
for i in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
local port=$((BASE_PORT + i))
|
||||||
|
echo " Waiting for master on port $port..."
|
||||||
|
for attempt in $(seq 1 30); do
|
||||||
|
if ${pkgs.redis}/bin/redis-cli -p $port ping >/dev/null 2>&1; then
|
||||||
|
echo " Master on port $port is ready."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ $attempt -eq 30 ]; then
|
||||||
|
echo " ERROR: Master on port $port failed to start!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# Wait for replicas
|
||||||
|
for master_idx in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
for replica_idx in $(seq 0 $((REPLICAS_PER_MASTER - 1))); do
|
||||||
|
local port=$((BASE_PORT + MASTERS + master_idx * REPLICAS_PER_MASTER + replica_idx))
|
||||||
|
echo " Waiting for replica on port $port..."
|
||||||
|
for attempt in $(seq 1 30); do
|
||||||
|
if ${pkgs.redis}/bin/redis-cli -p $port ping >/dev/null 2>&1; then
|
||||||
|
echo " Replica on port $port is ready."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ $attempt -eq 30 ]; then
|
||||||
|
echo " ERROR: Replica on port $port failed to start!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "All Redis services are ready."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to create the cluster
|
||||||
|
create_cluster() {
|
||||||
|
echo "Creating Redis cluster..."
|
||||||
|
|
||||||
|
# Build master nodes list
|
||||||
|
MASTER_NODES=""
|
||||||
|
for i in $(seq 0 $((MASTERS - 1))); do
|
||||||
|
local port=$((BASE_PORT + i))
|
||||||
|
MASTER_NODES="$MASTER_NODES $ANNOUNCE_IP:$port"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo " Master nodes:$MASTER_NODES"
|
||||||
|
echo " Creating cluster with $REPLICAS_PER_MASTER replicas per master..."
|
||||||
|
|
||||||
|
${pkgs.redis}/bin/redis-cli --cluster create $MASTER_NODES --cluster-replicas $REPLICAS_PER_MASTER --cluster-yes
|
||||||
|
|
||||||
|
echo "Redis cluster created successfully!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show cluster status
|
||||||
|
show_cluster_status() {
|
||||||
|
echo ""
|
||||||
|
echo "Cluster Status:"
|
||||||
|
echo "==============="
|
||||||
|
${pkgs.redis}/bin/redis-cli -p $BASE_PORT cluster nodes
|
||||||
|
echo ""
|
||||||
|
${pkgs.redis}/bin/redis-cli -p $BASE_PORT cluster info
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
case "''${1:-rebuild}" in
|
||||||
|
"stop")
|
||||||
|
stop_redis_services
|
||||||
|
;;
|
||||||
|
"clean")
|
||||||
|
clean_redis_data
|
||||||
|
;;
|
||||||
|
"start")
|
||||||
|
start_redis_services
|
||||||
|
wait_for_redis
|
||||||
|
;;
|
||||||
|
"create")
|
||||||
|
create_cluster
|
||||||
|
show_cluster_status
|
||||||
|
;;
|
||||||
|
"rebuild"|"")
|
||||||
|
echo "Full rebuild process starting..."
|
||||||
|
stop_redis_services
|
||||||
|
sleep 2
|
||||||
|
clean_redis_data
|
||||||
|
start_redis_services
|
||||||
|
wait_for_redis
|
||||||
|
sleep 3
|
||||||
|
create_cluster
|
||||||
|
show_cluster_status
|
||||||
|
echo ""
|
||||||
|
echo "Redis cluster rebuild completed successfully!"
|
||||||
|
;;
|
||||||
|
"status")
|
||||||
|
show_cluster_status
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 [stop|clean|start|create|rebuild|status]"
|
||||||
|
echo ""
|
||||||
|
echo "Commands:"
|
||||||
|
echo " stop - Stop all Redis services"
|
||||||
|
echo " clean - Remove Redis data directories"
|
||||||
|
echo " start - Start all Redis services"
|
||||||
|
echo " create - Create the cluster (services must be running)"
|
||||||
|
echo " rebuild - Full rebuild (stop, clean, start, create) [default]"
|
||||||
|
echo " status - Show cluster status"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
|
mode = "0755";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
+187
-4
@@ -21,7 +21,8 @@
|
|||||||
outputs.nixosModules.important-defaults
|
outputs.nixosModules.important-defaults
|
||||||
outputs.nixosModules.incus
|
outputs.nixosModules.incus
|
||||||
outputs.nixosModules.orbstack
|
outputs.nixosModules.orbstack
|
||||||
outputs.nixosModules.power-user-defaults
|
outputs.nixosModules.redis-cluster
|
||||||
|
# outputs.nixosModules.power-user-defaults
|
||||||
];
|
];
|
||||||
|
|
||||||
nixpkgs = {
|
nixpkgs = {
|
||||||
@@ -71,7 +72,7 @@
|
|||||||
# User configuration
|
# User configuration
|
||||||
users.users.wongdingfeng = {
|
users.users.wongdingfeng = {
|
||||||
uid = 502;
|
uid = 502;
|
||||||
extraGroups = [ "wheel" "orbstack" ];
|
extraGroups = [ "wheel" "orbstack" "audio" "video" ];
|
||||||
|
|
||||||
# simulate isNormalUser, but with an arbitrary UID
|
# simulate isNormalUser, but with an arbitrary UID
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
@@ -80,6 +81,17 @@
|
|||||||
home = "/home/wongdingfeng";
|
home = "/home/wongdingfeng";
|
||||||
homeMode = "700";
|
homeMode = "700";
|
||||||
useDefaultShell = true;
|
useDefaultShell = true;
|
||||||
|
|
||||||
|
# Set a password for RDP login (insecure but required)
|
||||||
|
hashedPassword = "$6$rounds=4096$salt$3xAS2/rKTsVNrHRYnBJcLk9KPIbO7GGr.vCO6xLz2CIhVFZFj9EoylXnJz7sVLJhfJk8hGgJ2U8J1QD2vG7z0."; # password: "password"
|
||||||
|
|
||||||
|
# SSH keys
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
# Add your SSH public keys here
|
||||||
|
# "ssh-rsa AAAAB3NzaC1yc2EAAAA... your-email@example.com"
|
||||||
|
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... your-email@example.com"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICA/3qb5Eg8NSFMHXZqFlWI9TxHZHQtFAjvcDfiTUtbv wongdingfeng@Wong-Ding-Fengs-MacBook-Pro.local-2024-01-23"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
security.sudo.wheelNeedsPassword = false;
|
security.sudo.wheelNeedsPassword = false;
|
||||||
@@ -89,6 +101,177 @@
|
|||||||
|
|
||||||
time.timeZone = "Asia/Singapore";
|
time.timeZone = "Asia/Singapore";
|
||||||
|
|
||||||
# System packages are now handled in power-user-defaults.nix
|
# SSH Server configuration
|
||||||
# environment.systemPackages is defined there with a comprehensive list
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
# Better security defaults
|
||||||
|
PasswordAuthentication = true;
|
||||||
|
PermitRootLogin = "yes";
|
||||||
|
|
||||||
|
# Enable X11 forwarding
|
||||||
|
X11Forwarding = true;
|
||||||
|
X11DisplayOffset = 10;
|
||||||
|
X11UseLocalhost = true;
|
||||||
|
|
||||||
|
# Additional security settings
|
||||||
|
Protocol = 2;
|
||||||
|
MaxAuthTries = 3;
|
||||||
|
ClientAliveInterval = 300;
|
||||||
|
ClientAliveCountMax = 2;
|
||||||
|
|
||||||
|
# Allow only specific users (optional - uncomment if needed)
|
||||||
|
# AllowUsers = [ "wongdingfeng" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Optional: Custom port (uncomment if you want to change from default 22)
|
||||||
|
ports = [ 2222 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Redis Cluster configuration
|
||||||
|
services.redisCluster = {
|
||||||
|
enable = true;
|
||||||
|
masters = 8; # 8 master nodes
|
||||||
|
replicasPerMaster = 1; # 1 replicas each = 16 total instances
|
||||||
|
basePort = 7000; # Masters: 7000-7007, Replicas: 7008-7015
|
||||||
|
announceIp = "0.0.0.0"; # Bind to all interfaces
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# System packages
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
neovim
|
||||||
|
gitAndTools.gitFull
|
||||||
|
tmux
|
||||||
|
htop
|
||||||
|
neofetch
|
||||||
|
ripgrep
|
||||||
|
fd
|
||||||
|
ranger
|
||||||
|
fish
|
||||||
|
|
||||||
|
# Desktop applications
|
||||||
|
firefox
|
||||||
|
chromium
|
||||||
|
gnome-terminal
|
||||||
|
nautilus
|
||||||
|
gedit
|
||||||
|
|
||||||
|
# System utilities
|
||||||
|
xorg.xauth
|
||||||
|
xorg.xhost
|
||||||
|
|
||||||
|
# Development tools
|
||||||
|
vscode
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
];
|
||||||
|
|
||||||
|
# Enable X11 with GNOME desktop environment
|
||||||
|
services.xserver = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# GNOME Desktop Environment
|
||||||
|
displayManager.gdm.enable = true;
|
||||||
|
desktopManager.gnome.enable = true;
|
||||||
|
|
||||||
|
# Keyboard layout
|
||||||
|
xkb = {
|
||||||
|
layout = "us";
|
||||||
|
variant = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable xrdp for remote desktop access
|
||||||
|
services.xrdp = {
|
||||||
|
enable = true;
|
||||||
|
defaultWindowManager = "gnome-session";
|
||||||
|
openFirewall = true;
|
||||||
|
|
||||||
|
# Insecure configuration - allows all connections
|
||||||
|
port = 3389;
|
||||||
|
|
||||||
|
# Additional insecure settings
|
||||||
|
confDir = pkgs.writeTextDir "xrdp.ini" ''
|
||||||
|
[Globals]
|
||||||
|
ini_version=1
|
||||||
|
fork=true
|
||||||
|
port=3389
|
||||||
|
tcp_nodelay=true
|
||||||
|
tcp_keepalive=true
|
||||||
|
security_layer=negotiate
|
||||||
|
crypt_level=low
|
||||||
|
certificate=
|
||||||
|
key_file=
|
||||||
|
ssl_protocols=TLSv1.2, TLSv1.3
|
||||||
|
autorun=
|
||||||
|
allow_channels=true
|
||||||
|
allow_multimon=true
|
||||||
|
bitmap_cache=true
|
||||||
|
bitmap_compression=true
|
||||||
|
hide_log_window=true
|
||||||
|
max_bpp=32
|
||||||
|
new_cursors=true
|
||||||
|
use_fastpath=both
|
||||||
|
require_credentials=false
|
||||||
|
bulk_compression=true
|
||||||
|
|
||||||
|
[Xorg]
|
||||||
|
name=Xorg
|
||||||
|
lib=libxup.so
|
||||||
|
username=ask
|
||||||
|
password=ask
|
||||||
|
ip=127.0.0.1
|
||||||
|
port=-1
|
||||||
|
code=20
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Additional firewall configuration for xrdp
|
||||||
|
networking.firewall = {
|
||||||
|
enable = true;
|
||||||
|
allowedTCPPorts = [ 3389 2222 ]; # xrdp and SSH
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable sound for desktop environment
|
||||||
|
security.rtkit.enable = true;
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa.enable = true;
|
||||||
|
alsa.support32Bit = true;
|
||||||
|
pulse.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Font configuration for X11 applications
|
||||||
|
fonts = {
|
||||||
|
packages = with pkgs; [
|
||||||
|
dejavu_fonts
|
||||||
|
liberation_ttf
|
||||||
|
freetype
|
||||||
|
];
|
||||||
|
fontconfig.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# GNOME services and additional desktop features
|
||||||
|
services.gnome = {
|
||||||
|
gnome-keyring.enable = true;
|
||||||
|
glib-networking.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable location services for GNOME
|
||||||
|
services.geoclue2.enable = true;
|
||||||
|
|
||||||
|
# Enable printing support
|
||||||
|
services.printing.enable = true;
|
||||||
|
|
||||||
|
# Enable USB support
|
||||||
|
services.udisks2.enable = true;
|
||||||
|
|
||||||
|
# Modern systemd features
|
||||||
|
systemd.extraConfig = ''
|
||||||
|
DefaultTimeoutStopSec=10s
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Latest NixOS system state version
|
||||||
|
system.stateVersion = "25.05"; # Use latest stable version
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
# This is just an example, you should generate yours with nixos-generate-config and put it in here.
|
# This is just an example, you should generate yours with nixos-generate-config and put it in here.
|
||||||
{
|
{
|
||||||
boot.loader.systemd-boot.enable = true;
|
|
||||||
|
|
||||||
fileSystems."/" = {
|
|
||||||
device = "/dev/sda1";
|
|
||||||
fsType = "ext4";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Set your system kind (needed for flakes)
|
# Set your system kind (needed for flakes)
|
||||||
nixpkgs.hostPlatform = "aarch64-linux";
|
nixpkgs.hostPlatform = "aarch64-linux";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user