/// <summary> /// Performs common node configuration. /// </summary> /// <param name="controller">The setup controller.</param> /// <param name="clusterManifest">The cluster manifest.</param> public void SetupNode(ISetupController controller, ClusterManifest clusterManifest) { Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller)); Covenant.Requires <ArgumentNullException>(clusterManifest != null, nameof(clusterManifest)); var nodeDefinition = NeonHelper.CastTo <NodeDefinition>(Metadata); var clusterDefinition = Cluster.Definition; var hostingManager = controller.Get <IHostingManager>(KubeSetupProperty.HostingManager); InvokeIdempotent("setup/node", () => { PrepareNode(controller); ConfigureEnvironmentVariables(controller); SetupPackageProxy(controller); UpdateHostname(controller); NodeInitialize(controller); NodeInstallCriO(controller, clusterManifest); NodeInstallIPVS(controller); NodeInstallPodman(controller); NodeInstallKubernetes(controller); SetupKublet(controller); }); }
/// <summary> /// Configures cluster package manager caching. /// </summary> /// <param name="controller">The setup controller.</param> public void SetupPackageProxy(ISetupController controller) { Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller)); var nodeDefinition = NeonHelper.CastTo <NodeDefinition>(Metadata); var clusterDefinition = Cluster.Definition; var hostingManager = controller.Get <IHostingManager>(KubeSetupProperty.HostingManager); InvokeIdempotent("setup/package-caching", () => { controller.LogProgress(this, verb: "configure", message: "apt package proxy"); // Configure the [apt-cacher-ng] pckage proxy service on control-plane nodes. if (NodeDefinition.Role == NodeRole.ControlPlane) { var proxyServiceScript = $@" set -eou pipefail # Enable full failure detection {KubeNodeFolder.Bin}/safe-apt-get update {KubeNodeFolder.Bin}/safe-apt-get install -yq apt-cacher-ng # Configure the cache to pass-thru SSL requests # and then restart. echo ""PassThroughPattern:^.*:443$"" >> /etc/apt-cacher-ng/acng.conf systemctl restart apt-cacher-ng set -eo pipefail # Revert back to partial failure detection # Give the proxy service a chance to start. sleep 5 "; SudoCommand(CommandBundle.FromScript(proxyServiceScript), RunOptions.FaultOnError); } var sbPackageProxies = new StringBuilder(); if (clusterDefinition.PackageProxy != null) { foreach (var proxyEndpoint in clusterDefinition.PackageProxy.Split(' ', StringSplitOptions.RemoveEmptyEntries)) { sbPackageProxies.AppendWithSeparator(proxyEndpoint); } } // Configure the package manager to use the first control-plane as the proxy by default, // failing over to the other control-plane nodes (in order) when necessary. var proxySelectorScript = $@" # Configure APT proxy selection. echo {sbPackageProxies} > {KubeNodeFolder.Config}/package-proxy cat <<EOF > /usr/local/bin/get-package-proxy #!/bin/bash #------------------------------------------------------------------------------ # FILE: get-package-proxy # CONTRIBUTOR: Generated by [neon-cli] during cluster setup. # # This script determine which (if any) configured APT proxy caches are running # and returns its endpoint or ""DIRECT"" if none of the proxies are available and # the distribution's mirror should be accessed directly. This uses the # [{KubeNodeFolder.Config}/package-proxy] file to obtain the list of proxies. # # This is called when the following is specified in the APT configuration, # as we do further below: # # Acquire::http::Proxy-Auto-Detect ""/usr/local/bin/get-package-proxy""; # # See this link for more information: # # https://trent.utfs.org/wiki/Apt-get#Failover_Proxy NEON_PACKAGE_PROXY=$(cat {KubeNodeFolder.Config}/package-proxy) if [ ""\${{NEON_PACKAGE_PROXY}}"" == """" ] ; then echo DIRECT exit 0 fi for proxy in ${{NEON_PACKAGE_PROXY}}; do if nc -w1 -z \${{proxy/:/ }}; then echo http://\${{proxy}}/ exit 0 fi done echo DIRECT exit 0 EOF chmod 775 /usr/local/bin/get-package-proxy cat <<EOF > /etc/apt/apt.conf //----------------------------------------------------------------------------- // FILE: /etc/apt/apt.conf // CONTRIBUTOR: Generated by during neonKUBE cluster setup. // // This file configures APT on the local machine to proxy requests through the // [apt-cacher-ng] instance(s) at the configured. This uses the [/usr/local/bin/get-package-proxy] // script to select a working PROXY if there are more than one, or to go directly to the package // mirror if none of the proxies are available. // // Presumably, this cache is running on the local network which can dramatically // reduce external network traffic to the APT mirrors and improve cluster setup // and update performance. Acquire::http::Proxy-Auto-Detect ""/usr/local/bin/get-package-proxy""; EOF "; SudoCommand(CommandBundle.FromScript(proxySelectorScript), RunOptions.FaultOnError); }); }
/// <summary> /// Configures the global environment variables that describe the configuration /// of the server within the cluster. /// </summary> /// <param name="controller">The setup controller.</param> public void ConfigureEnvironmentVariables(ISetupController controller) { Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller)); controller.LogProgress(this, verb: "configure", message: "environment"); var clusterDefinition = Cluster.Definition; var nodeDefinition = NeonHelper.CastTo <NodeDefinition>(Metadata); // We're going to append the new variables to the existing Linux [/etc/environment] file. var sb = new StringBuilder(); // Append all of the existing environment variables except for those // whose names start with "NEON_" to make the operation idempotent. // // Note that we're going to special case PATH to add any Neon // related directories. using (var currentEnvironmentStream = new MemoryStream()) { Download("/etc/environment", currentEnvironmentStream); currentEnvironmentStream.Position = 0; using (var reader = new StreamReader(currentEnvironmentStream)) { foreach (var line in reader.Lines()) { if (line.StartsWith("PATH=")) { if (!line.Contains(KubeNodeFolder.Bin)) { sb.AppendLine(line + $":/snap/bin:{KubeNodeFolder.Bin}"); } else { sb.AppendLine(line); } } else if (!line.StartsWith("NEON_")) { sb.AppendLine(line); } } } } // Add the global cluster related environment variables. sb.AppendLine($"NEON_CLUSTER={clusterDefinition.Name}"); sb.AppendLine($"NEON_DATACENTER={clusterDefinition.Datacenter.ToLowerInvariant()}"); sb.AppendLine($"NEON_ENVIRONMENT={clusterDefinition.Purpose.ToString().ToLowerInvariant()}"); var sbPackageProxies = new StringBuilder(); if (clusterDefinition.PackageProxy != null) { foreach (var proxyEndpoint in clusterDefinition.PackageProxy.Split(' ', StringSplitOptions.RemoveEmptyEntries)) { sbPackageProxies.AppendWithSeparator(proxyEndpoint); } } sb.AppendLine($"NEON_PACKAGE_PROXY={sbPackageProxies}"); if (clusterDefinition.Hosting != null) { sb.AppendLine($"NEON_HOSTING={clusterDefinition.Hosting.Environment.ToMemberString().ToLowerInvariant()}"); } sb.AppendLine($"NEON_NODE_NAME={Name}"); if (nodeDefinition != null) { sb.AppendLine($"NEON_NODE_ROLE={nodeDefinition.Role}"); sb.AppendLine($"NEON_NODE_IP={nodeDefinition.Address}"); sb.AppendLine($"NEON_NODE_HDD={nodeDefinition.Labels.StorageHDD.ToString().ToLowerInvariant()}"); } sb.AppendLine($"NEON_BIN_FOLDER={KubeNodeFolder.Bin}"); sb.AppendLine($"NEON_CONFIG_FOLDER={KubeNodeFolder.Config}"); sb.AppendLine($"NEON_SETUP_FOLDER={KubeNodeFolder.Setup}"); sb.AppendLine($"NEON_STATE_FOLDER={KubeNodeFolder.State}"); sb.AppendLine($"NEON_RUN_FOLDER={KubeNodeFolder.NeonRun}"); sb.AppendLine($"NEON_TMPFS_FOLDER={KubeNodeFolder.Tmpfs}"); // Kubernetes related variables for control-plane nodes. if (nodeDefinition.IsControlPane) { sb.AppendLine($"KUBECONFIG=/etc/kubernetes/admin.conf"); } // Upload the new environment to the server. UploadText("/etc/environment", sb, tabStop: 4); }