From 645210810513a18b71906f91b34b2bd104e2e3ef Mon Sep 17 00:00:00 2001 From: Eddie Wassef Date: Sat, 24 Jan 2026 22:38:01 -0600 Subject: [PATCH] Add Zot registry support and enhance reverse proxy Replaces Docker registry with Zot, updating container image and port constants, and adds Zot config file and persistent images directory. Updates DockerHubClient to mount config and images for registry. Adds nginx config regeneration with WebSocket support to reverse proxy client and command. Updates .gitignore and project file for new assets. --- .claude/settings.local.json | 8 ++++ .gitignore | 2 + cli/src/Vdk/Commands/UpdateClustersCommand.cs | 19 ++++++++- cli/src/Vdk/ConfigMounts/zot-config.json | 27 ++++++++++++ cli/src/Vdk/Constants/Containers.cs | 6 +-- cli/src/Vdk/Services/DockerHubClient.cs | 21 +++++++++- cli/src/Vdk/Services/IReverseProxyClient.cs | 6 +++ cli/src/Vdk/Services/ReverseProxyClient.cs | 42 +++++++++++++++++++ cli/src/Vdk/Vdk.csproj | 7 ++++ cli/src/Vdk/vega.conf | 42 +++++++++++++++++++ 10 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 cli/src/Vdk/ConfigMounts/zot-config.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..03d39c0 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(docker stop:*)", + "Bash(docker rm:*)" + ] + } +} diff --git a/.gitignore b/.gitignore index 1841901..955cdc1 100644 --- a/.gitignore +++ b/.gitignore @@ -487,3 +487,5 @@ $RECYCLE.BIN/ # Intellij *.iml +*.db +/cli/src/Vdk/images diff --git a/cli/src/Vdk/Commands/UpdateClustersCommand.cs b/cli/src/Vdk/Commands/UpdateClustersCommand.cs index 0516016..c9a10af 100644 --- a/cli/src/Vdk/Commands/UpdateClustersCommand.cs +++ b/cli/src/Vdk/Commands/UpdateClustersCommand.cs @@ -13,18 +13,21 @@ public class UpdateClustersCommand : Command private readonly IKindClient _kind; private readonly IFileSystem _fileSystem; private readonly Func _clientFunc; + private readonly IReverseProxyClient _reverseProxy; public UpdateClustersCommand( IConsole console, IKindClient kind, IFileSystem fileSystem, - Func clientFunc) + Func clientFunc, + IReverseProxyClient reverseProxy) : base("clusters", "Update cluster configurations (certificates, etc.)") { _console = console; _kind = kind; _fileSystem = fileSystem; _clientFunc = clientFunc; + _reverseProxy = reverseProxy; var verboseOption = new Option("--verbose") { Description = "Enable verbose output for debugging" }; verboseOption.Aliases.Add("-v"); @@ -72,6 +75,20 @@ public async Task InvokeAsync(bool verbose = false) } _console.WriteLine("Cluster certificate update complete."); + + // Regenerate nginx configuration for all clusters (adds WebSocket support, etc.) + _console.WriteLine(); + if (_reverseProxy.Exists()) + { + _reverseProxy.RegenerateConfigs(); + } + else + { + if (verbose) + { + _console.WriteLine("[DEBUG] Reverse proxy not running, skipping nginx config regeneration."); + } + } } private async Task UpdateClusterCertificates(string clusterName, byte[] localCert, byte[] localKey, bool verbose) diff --git a/cli/src/Vdk/ConfigMounts/zot-config.json b/cli/src/Vdk/ConfigMounts/zot-config.json new file mode 100644 index 0000000..69ad82a --- /dev/null +++ b/cli/src/Vdk/ConfigMounts/zot-config.json @@ -0,0 +1,27 @@ +{ + "distSpecVersion": "1.1.0", + "storage": { + "rootDirectory": "/var/lib/registry", + "gc": true, + "gcDelay": "1h", + "gcInterval": "24h" + }, + "http": { + "address": "0.0.0.0", + "port": "5000" + }, + "log": { + "level": "info" + }, + "extensions": { + "ui": { + "enable": true + }, + "search": { + "enable": true, + "cve": { + "updateInterval": "24h" + } + } + } +} diff --git a/cli/src/Vdk/Constants/Containers.cs b/cli/src/Vdk/Constants/Containers.cs index 2dba5eb..c75b251 100644 --- a/cli/src/Vdk/Constants/Containers.cs +++ b/cli/src/Vdk/Constants/Containers.cs @@ -3,11 +3,11 @@ namespace Vdk.Constants; public static class Containers { public const string RegistryName = "vega-registry"; - public const string RegistryImage = "registry:2"; + public const string RegistryImage = "ghcr.io/project-zot/zot-linux-amd64:v2.1.0"; public const int RegistryContainerPort = 5000; - public const int RegistryHostPort = 50000; + public const int RegistryHostPort = 5000; public const string ProxyName = "vega-proxy"; - public const string ProxyImage = "nginx:latest"; + public const string ProxyImage = "nginx:1.27"; public const string CloudProviderKindName = "cloud-provider-kind"; public const string CloudProviderKindImage = "registry.k8s.io/cloud-provider-kind/cloud-controller-manager:v0.6.0"; } \ No newline at end of file diff --git a/cli/src/Vdk/Services/DockerHubClient.cs b/cli/src/Vdk/Services/DockerHubClient.cs index 2f536de..d7703ee 100644 --- a/cli/src/Vdk/Services/DockerHubClient.cs +++ b/cli/src/Vdk/Services/DockerHubClient.cs @@ -8,13 +8,30 @@ public class DockerHubClient(IDockerEngine docker, IConsole console) : IHubClien public void CreateRegistry() { if (ExistRegistry()) return; - console.WriteLine("Creating Vega VDK Registry"); + console.WriteLine("Creating Vega VDK Registry (Zot)"); console.WriteLine(" - This may take a few minutes..."); + + // Mount the config file and images directory for persistence + var configFile = new FileInfo(Path.Combine("ConfigMounts", "zot-config.json")); + var imagesDir = new DirectoryInfo("images"); + + // Ensure images directory exists + if (!imagesDir.Exists) + { + imagesDir.Create(); + } + + var volumes = new[] + { + new FileMapping { Source = configFile.FullName, Destination = "/etc/zot/config.json" }, + new FileMapping { Source = imagesDir.FullName, Destination = "/var/lib/registry" } + }; + docker.Run(Containers.RegistryImage, Containers.RegistryName, [PortMapping.DefaultRegistryPortMapping], null, - null, + volumes, null); } diff --git a/cli/src/Vdk/Services/IReverseProxyClient.cs b/cli/src/Vdk/Services/IReverseProxyClient.cs index 414860f..af1e4b5 100644 --- a/cli/src/Vdk/Services/IReverseProxyClient.cs +++ b/cli/src/Vdk/Services/IReverseProxyClient.cs @@ -13,4 +13,10 @@ public interface IReverseProxyClient void List(); bool Exists(); + + /// + /// Regenerates the nginx configuration for all VDK clusters. + /// Useful for applying config changes (like WebSocket support) to existing clusters. + /// + void RegenerateConfigs(); } \ No newline at end of file diff --git a/cli/src/Vdk/Services/ReverseProxyClient.cs b/cli/src/Vdk/Services/ReverseProxyClient.cs index baa8e2b..22d7629 100644 --- a/cli/src/Vdk/Services/ReverseProxyClient.cs +++ b/cli/src/Vdk/Services/ReverseProxyClient.cs @@ -175,6 +175,11 @@ private void PatchNginxConfig(string clusterName, int targetPortHttps) writer.WriteLine(" proxy_set_header X-Real-IP $remote_addr;"); writer.WriteLine(" proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;"); writer.WriteLine(" proxy_set_header X-Forwarded-Proto $scheme;"); + writer.WriteLine(); + writer.WriteLine(" # Support WebSocket protocol upgrades"); + writer.WriteLine(" proxy_http_version 1.1;"); + writer.WriteLine(" proxy_set_header Upgrade $http_upgrade;"); + writer.WriteLine(" proxy_set_header Connection \"upgrade\";"); writer.WriteLine(" }"); writer.WriteLine("}"); writer.WriteLine($"##### END {clusterName}"); @@ -415,6 +420,43 @@ public void List() throw new NotImplementedException(); } + public void RegenerateConfigs() + { + var conf = new FileInfo(NginxConf); + if (!conf.Exists) + { + _console.WriteWarning("Nginx configuration file does not exist. Run 'vega create proxy' first."); + return; + } + + _console.WriteLine("Regenerating nginx configuration for all VDK clusters..."); + + // Reinitialize the conf file with the hub server block + conf.Delete(); + InitConfFile(conf); + + // Iterate through all VDK clusters and add their server blocks + var clusters = _kind.ListClusters(); + var vdkClusters = clusters.Where(c => c.isVdk && c.master != null && c.master.HttpsHostPort.HasValue).ToList(); + + if (vdkClusters.Count == 0) + { + _console.WriteLine("No VDK clusters found to configure."); + ReloadConfigs(); + return; + } + + foreach (var cluster in vdkClusters) + { + _console.WriteLine($" Adding cluster '{cluster.name}' to nginx configuration"); + PatchNginxConfig(cluster.name, cluster.master!.HttpsHostPort!.Value); + } + + _console.WriteLine($"Regenerated configuration for {vdkClusters.Count} cluster(s)."); + ReloadConfigs(); + _console.WriteLine("Nginx configuration reloaded."); + } + private static int GetEnvironmentVariableAsInt(string variableName, int defaultValue = 0) { string strValue = Environment.GetEnvironmentVariable(variableName); diff --git a/cli/src/Vdk/Vdk.csproj b/cli/src/Vdk/Vdk.csproj index c451c7d..eda4e36 100644 --- a/cli/src/Vdk/Vdk.csproj +++ b/cli/src/Vdk/Vdk.csproj @@ -40,6 +40,13 @@ PreserveNewest + + PreserveNewest + + + + + diff --git a/cli/src/Vdk/vega.conf b/cli/src/Vdk/vega.conf index e69de29..ea4640c 100644 --- a/cli/src/Vdk/vega.conf +++ b/cli/src/Vdk/vega.conf @@ -0,0 +1,42 @@ + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name hub.dev-k8s.cloud; + ssl_certificate /etc/certs/fullchain.pem; + ssl_certificate_key /etc/certs/privkey.pem; + location / { + client_max_body_size 0; + proxy_pass http://host.docker.internal:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + + +##### START idp +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name idp.dev-k8s.cloud; + ssl_certificate /etc/certs/fullchain.pem; + ssl_certificate_key /etc/certs/privkey.pem; + location / { + proxy_pass https://host.docker.internal:40237; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Support WebSocket protocol upgrades + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} +##### END idp +