Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support configuring script pod resource requirements #977

Merged
merged 3 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions source/Octopus.Tentacle/Kubernetes/KubernetesConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public static class KubernetesConfig
.Select(str => str.Trim())
.WhereNotNullOrWhiteSpace()
.ToArray() ?? Array.Empty<string>();

public static readonly string PodResourceJsonVariableName = $"{EnvVarPrefix}__PODRESOURCEJSON";
public static string? PodResourceJson => Environment.GetEnvironmentVariable(PodResourceJsonVariableName);

public static string MetricsEnableVariableName => $"{EnvVarPrefix}__ENABLEMETRICSCAPTURE";
public static bool MetricsIsEnabled
Expand Down
47 changes: 35 additions & 12 deletions source/Octopus.Tentacle/Kubernetes/KubernetesScriptPodCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using k8s;
using k8s.Models;
using Newtonsoft.Json;
using Octopus.Diagnostics;
Expand Down Expand Up @@ -43,7 +44,7 @@ public KubernetesScriptPodCreator(
IKubernetesPodContainerResolver containerResolver,
IApplicationInstanceSelector appInstanceSelector,
ISystemLog log,
ITentacleScriptLogProvider scriptLogProvider,
ITentacleScriptLogProvider scriptLogProvider,
IHomeConfiguration homeConfiguration,
KubernetesPhysicalFileSystem kubernetesPhysicalFileSystem)
{
Expand Down Expand Up @@ -159,7 +160,7 @@ static string CreateImagePullSecretName(string feedUrl, string? username)
async Task CreatePod(StartKubernetesScriptCommandV1 command, IScriptWorkspace workspace, string? imagePullSecretName, InMemoryTentacleScriptLog tentacleScriptLog, CancellationToken cancellationToken)
{
var homeDir = homeConfiguration.HomeDirectory ?? throw new InvalidOperationException("Home directory is not set.");

var podName = command.ScriptTicket.ToKubernetesScriptPodName();

LogVerboseToBothLogs($"Creating Kubernetes Pod '{podName}'.", tentacleScriptLog);
Expand Down Expand Up @@ -206,8 +207,8 @@ async Task CreatePod(StartKubernetesScriptCommandV1 command, IScriptWorkspace wo
{
new(matchExpressions: new List<V1NodeSelectorRequirement>
{
new("kubernetes.io/os", "In", new List<string>{"linux"}),
new("kubernetes.io/arch", "In", new List<string>{"arm64","amd64"})
new("kubernetes.io/os", "In", new List<string> { "linux" }),
new("kubernetes.io/arch", "In", new List<string> { "arm64", "amd64" })
})
})))
}
Expand Down Expand Up @@ -256,6 +257,9 @@ void LogVerboseToBothLogs(string message, InMemoryTentacleScriptLog tentacleScri
protected async Task<V1Container> CreateScriptContainer(StartKubernetesScriptCommandV1 command, string podName, string scriptName, string homeDir, string workspacePath, string[]? scriptArguments)
{
var spaceInformation = kubernetesPhysicalFileSystem.GetStorageInformation();

var resourceRequirements = GetScriptPodResourceRequirements();

return new V1Container
{
Name = podName,
Expand All @@ -267,7 +271,7 @@ protected async Task<V1Container> CreateScriptContainer(StartKubernetesScriptCom
Path.Combine(homeDir, workspacePath, scriptName)
}.Concat(scriptArguments ?? Array.Empty<string>())
.ToList(),
VolumeMounts = new List<V1VolumeMount>{new(homeDir, "tentacle-home")},
VolumeMounts = new List<V1VolumeMount> { new(homeDir, "tentacle-home") },
Env = new List<V1EnvVar>
{
new(KubernetesConfig.NamespaceVariableName, KubernetesConfig.Namespace),
Expand All @@ -284,14 +288,33 @@ protected async Task<V1Container> CreateScriptContainer(StartKubernetesScriptCom

//We intentionally exclude setting "TentacleJournal" since it doesn't make sense to keep a Deployment Journal for Kubernetes deployments
},
Resources = new V1ResourceRequirements
Resources = resourceRequirements
};
}

V1ResourceRequirements GetScriptPodResourceRequirements()
{
var json = KubernetesConfig.PodResourceJson;
if (!string.IsNullOrWhiteSpace(json))
{
try
{
//set resource requests to be quite low for now as the scripts tend to run fairly quickly
Requests = new Dictionary<string, ResourceQuantity>
{
["cpu"] = new("25m"),
["memory"] = new("100Mi")
}
return KubernetesJson.Deserialize<V1ResourceRequirements>(json);
}
catch (Exception e)
{
//if we can't parse the JSON, fall back to the defaults below and warn the user
log.WarnFormat(e, $"Failed to deserialize env.{KubernetesConfig.PodResourceJsonVariableName} into valid pod resource requirements. Using default values. Value: {json}");
APErebus marked this conversation as resolved.
Show resolved Hide resolved
}
}

return new V1ResourceRequirements
{
//set resource requests to be quite low for now as the scripts tend to run fairly quickly
Requests = new Dictionary<string, ResourceQuantity>
{
["cpu"] = new("25m"),
["memory"] = new("100Mi")
}
};
}
Expand Down