public static V1Deployment CreateDeployment(string id) { var spec = new V1DeploymentSpec() { Selector = new V1LabelSelector() { MatchLabels = new Dictionary <string, string>() { { "pod-name", $"minecraft-pod-{id}" } } }, Template = new V1PodTemplateSpec() { Metadata = new V1ObjectMeta() { Labels = new Dictionary <string, string>() { { "pod-name", $"minecraft-pod-{id}" } }, }, Spec = new V1PodSpec() { Containers = new List <V1Container>() { new V1Container() { Name = $"minecraft-pod-{id}", Image = "openhack/minecraft-server:2.0", Ports = new List <V1ContainerPort>() { new V1ContainerPort() { ContainerPort = 25565 }, new V1ContainerPort() { ContainerPort = 25575 }, }, Env = new List <V1EnvVar>() { new V1EnvVar() { Name = "EULA", Value = "TRUE" }, } } } }, }, }; var metadata = new V1ObjectMeta() { Name = $"minecraft-deploy-{id}" }; return(new V1Deployment(V1Deployment.KubeApiVersion, V1Deployment.KubeKind, metadata, spec)); }
V1Deployment PrepareDeployment(IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels) { string name = identity.DeploymentName(); var podSpec = this.GetPod(name, identity, module, labels); var selector = new V1LabelSelector(matchLabels: labels); var deploymentSpec = new V1DeploymentSpec(replicas: 1, selector: selector, template: podSpec); var deploymentMeta = new V1ObjectMeta(name: name, labels: labels, annotations: new Dictionary <string, string>()); return(new V1Deployment(metadata: deploymentMeta, spec: deploymentSpec)); }
public static bool ImageEquals(this V1DeploymentSpec self, V1DeploymentSpec other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(self, other)) { return(true); } return(self.Template.ImageEquals(other.Template)); }
/// <summary> /// Creates a new <see cref="V1Deployment"/> for the specified <see cref="Resources.Channel"/> /// </summary> /// <param name="channel">The <see cref="Resources.Channel"/> to deploy</param> /// <returns>A new awaitable <see cref="Task"/></returns> protected virtual async Task CreateChannelDeploymentAsync(Resources.Channel channel) { V1Deployment deployment; try { this.Logger.LogInformation("Creating a new deployment for the channel with name '{resourceName}'...", channel.Name()); V1PodSpec podSpec = new V1PodSpec(); V1Container container = channel.Spec.Container; container.Env.Add(new V1EnvVar("SINK", $"http://gateway.{channel.Namespace()}.svc.cluster.local/events/")); podSpec.Containers = new List <V1Container>() { container }; V1ObjectMeta podMetadata = new V1ObjectMeta(); podMetadata.Annotations = new Dictionary <string, string>() { { "sidecar.istio.io/inject", "true" } }; V1PodTemplateSpec podTemplateSpec = new V1PodTemplateSpec(podMetadata, podSpec); podTemplateSpec.Metadata.Labels = new Dictionary <string, string>() { { "app", channel.Name() }, { "version", "1.0" } }; V1DeploymentSpec deploymentSpec = new V1DeploymentSpec(new V1LabelSelector(), podTemplateSpec); deploymentSpec.Selector.MatchLabels = new Dictionary <string, string>() { { "app", channel.Name() }, { "version", "1.0" } }; V1ObjectMeta deploymentMetadata = new V1ObjectMeta(namespaceProperty: channel.Namespace(), name: channel.Name()); deploymentMetadata.Labels = new Dictionary <string, string>() { { "type", EventingDefaults.Labels.Channel } }; deploymentMetadata.Name = channel.Name(); deploymentMetadata.NamespaceProperty = channel.Namespace(); deployment = new V1Deployment(KubernetesDefaults.ApiVersions.AppsV1, KubernetesDefaults.Kinds.Deployment, deploymentMetadata, deploymentSpec); await this.KubernetesClient.CreateNamespacedDeploymentAsync(deployment, channel.Namespace()); this.Logger.LogInformation("A new deployment for the channel with name '{resourceName}' has been successfully created.", channel.Name()); } catch (HttpOperationException ex) { this.Logger.LogError($"An error occured while creating the deployment for the channel with name '{{resourceName}}': the server responded with a non-success status code '{{statusCode}}'.{Environment.NewLine}Details: {{responseContent}}", channel.Name(), ex.Response.StatusCode, ex.Response.Content); throw; } }
V1Deployment PrepareDeployment(IModuleIdentity identity, KubernetesModule module, IDictionary <string, string> labels) { string name = identity.DeploymentName(); var podSpec = this.GetPod(name, identity, module, labels); var selector = new V1LabelSelector(matchLabels: labels); // Desired status in Deployment should only be Running or Stopped. Assume Running if not Stopped int replicas = (module.DesiredStatus != ModuleStatus.Stopped) ? 1 : 0; var deploymentSpec = new V1DeploymentSpec(replicas: replicas, selector: selector, template: podSpec); var deploymentMeta = new V1ObjectMeta( name: name, labels: labels, annotations: new Dictionary <string, string>(), ownerReferences: module.Owner.ToOwnerReferences()); return(new V1Deployment(metadata: deploymentMeta, spec: deploymentSpec)); }
public V1Deployment Build(HealthCheckResource resource) { var metadata = new V1ObjectMeta { OwnerReferences = new List <V1OwnerReference> { resource.CreateOwnerReference() }, Annotations = new Dictionary <string, string>(), Labels = new Dictionary <string, string> { ["app"] = resource.Spec.Name }, Name = $"{resource.Spec.Name}-deploy", NamespaceProperty = resource.Metadata.NamespaceProperty }; var uiContainer = new V1Container { ImagePullPolicy = resource.Spec.ImagePullPolicy ?? Constants.DEFAULT_PULL_POLICY, Name = Constants.POD_NAME, Image = resource.Spec.Image ?? Constants.IMAGE_NAME, Ports = new List <V1ContainerPort> { new V1ContainerPort(80) }, Env = new List <V1EnvVar> { new V1EnvVar("enable_push_endpoint", "true"), new V1EnvVar("push_endpoint_secret", valueFrom: new V1EnvVarSource(secretKeyRef: new V1SecretKeySelector("key", $"{resource.Spec.Name}-secret"))), new V1EnvVar("Logging__LogLevel__Default", "Debug"), new V1EnvVar("Logging__LogLevel__Microsoft", "Warning"), new V1EnvVar("Logging__LogLevel__System", "Warning"), new V1EnvVar("Logging__LogLevel__HealthChecks", "Information") } }; uiContainer.MapCustomUIPaths(resource, _operatorDiagnostics); var spec = new V1DeploymentSpec { Selector = new V1LabelSelector { MatchLabels = new Dictionary <string, string> { ["app"] = resource.Spec.Name } }, Replicas = 1, Template = new V1PodTemplateSpec { Metadata = new V1ObjectMeta { Labels = new Dictionary <string, string> { ["app"] = resource.Spec.Name }, }, Spec = new V1PodSpec { Containers = new List <V1Container> { uiContainer } } } }; foreach (var annotation in resource.Spec.DeploymentAnnotations) { _logger.LogInformation("Adding annotation {Annotation} to ui deployment with value {AnnotationValue}", annotation.Name, annotation.Value); metadata.Annotations.Add(annotation.Name, annotation.Value); } var specification = spec.Template.Spec; var container = specification.Containers.First(); for (int i = 0; i < resource.Spec.Webhooks.Count; i++) { var webhook = resource.Spec.Webhooks[i]; _logger.LogInformation("Adding webhook configuration for webhook {Webhook}", webhook.Name); container.Env.Add(new V1EnvVar($"HealthChecksUI__Webhooks__{i}__Name", webhook.Name)); container.Env.Add(new V1EnvVar($"HealthChecksUI__Webhooks__{i}__Uri", webhook.Uri)); container.Env.Add(new V1EnvVar($"HealthChecksUI__Webhooks__{i}__Payload", webhook.Payload)); container.Env.Add(new V1EnvVar($"HealthChecksUI__Webhooks__{i}__RestoredPayload", webhook.RestoredPayload)); } if (resource.HasBrandingConfigured()) { const string volumeName = "healthchecks-volume"; if (specification.Volumes == null) { specification.Volumes = new List <V1Volume>(); } if (container.VolumeMounts == null) { container.VolumeMounts = new List <V1VolumeMount>(); } specification.Volumes.Add(new V1Volume(name: volumeName, configMap: new V1ConfigMapVolumeSource(name: $"{resource.Spec.Name}-config"))); container.Env.Add(new V1EnvVar("ui_stylesheet", $"{Constants.STYLES_PATH}/{Constants.STYLE_SHEET_NAME}")); container.VolumeMounts.Add(new V1VolumeMount($"/app/{Constants.STYLES_PATH}", volumeName)); } return(new V1Deployment(metadata: metadata, spec: spec)); }
public V1Deployment Build(HealthCheckResource resource) { var metadata = new V1ObjectMeta { OwnerReferences = new List <V1OwnerReference> { resource.CreateOwnerReference() }, Labels = new Dictionary <string, string> { ["app"] = resource.Spec.Name }, Name = $"{resource.Spec.Name}-deploy", NamespaceProperty = resource.Metadata.NamespaceProperty }; var spec = new V1DeploymentSpec { Selector = new V1LabelSelector { MatchLabels = new Dictionary <string, string> { ["app"] = resource.Spec.Name } }, Replicas = 1, Template = new V1PodTemplateSpec { Metadata = new V1ObjectMeta { Labels = new Dictionary <string, string> { ["app"] = resource.Spec.Name } }, Spec = new V1PodSpec { Containers = new List <V1Container> { new V1Container { ImagePullPolicy = resource.Spec.ImagePullPolicy ?? Constants.DefaultPullPolicy, Name = Constants.PodName, Image = resource.Spec.Image ?? Constants.ImageName, Ports = new List <V1ContainerPort> { new V1ContainerPort(80) }, Env = new List <V1EnvVar> { new V1EnvVar("ui_path", resource.Spec.UiPath ?? Constants.DefaultUIPath), new V1EnvVar("enable_push_endpoint", "true"), new V1EnvVar("push_endpoint_secret", valueFrom: new V1EnvVarSource(secretKeyRef: new V1SecretKeySelector("key", $"{resource.Spec.Name}-secret"))), new V1EnvVar("Logging__LogLevel__Default", "Debug"), new V1EnvVar("Logging__LogLevel__Microsoft", "Warning"), new V1EnvVar("Logging__LogLevel__System", "Warning"), new V1EnvVar("Logging__LogLevel__HealthChecks", "Information") } } } } } }; return(new V1Deployment(metadata: metadata, spec: spec)); }
private async Task ManageDeployments(V1ServiceList currentServices, V1DeploymentList currentDeployments, EdgeDeploymentDefinition <TConfig> customObject) { var desiredModules = ModuleSet.Create(customObject.Spec.ToArray()); var moduleIdentities = await this.moduleIdentityLifecycleManager.GetModuleIdentitiesAsync(desiredModules, this.currentModules); // Pull current configuration from annotations. Dictionary <string, string> currentV1ServicesFromAnnotations = this.GetCurrentServiceConfig(currentServices); // strip out edgeAgent so edgeAgent doesn't update itself. // TODO: remove this filter. var agentDeploymentName = this.DeploymentName(CoreConstants.EdgeAgentModuleName); Dictionary <string, string> currentDeploymentsFromAnnotations = this.GetCurrentDeploymentConfig(currentDeployments) .ToDictionary( pair => pair.Key, pair => pair.Value); var desiredServices = new List <V1Service>(); var desiredDeployments = new List <V1Deployment>(); foreach (KubernetesModule <TConfig> module in customObject.Spec) { var moduleId = moduleIdentities[module.Name]; if (string.Equals(module.Type, "docker")) { // Default labels var labels = new Dictionary <string, string> { [Constants.K8sEdgeModuleLabel] = KubeUtils.SanitizeLabelValue(moduleId.ModuleId), [Constants.K8sEdgeDeviceLabel] = KubeUtils.SanitizeLabelValue(this.deviceId), [Constants.K8sEdgeHubNameLabel] = KubeUtils.SanitizeLabelValue(this.iotHubHostname) }; // Create a Service for every network interface of each module. (label them with hub, device and module id) Option <V1Service> moduleService = this.GetServiceFromModule(labels, module, moduleId); moduleService.ForEach(service => desiredServices.Add(service)); // Create a Pod for each module, and a proxy container. V1PodTemplateSpec v1PodSpec = this.GetPodFromModule(labels, module, moduleId); // if this is the edge agent's deployment then it needs to run under a specific service account if (moduleIdentities[module.Name].ModuleId == CoreConstants.EdgeAgentModuleIdentityName) { v1PodSpec.Spec.ServiceAccountName = this.serviceAccountName; } // Bundle into a deployment string deploymentName = this.DeploymentName(moduleIdentities[module.Name].ModuleId); // Deployment data var deploymentMeta = new V1ObjectMeta(name: deploymentName, labels: labels); var selector = new V1LabelSelector(matchLabels: labels); var deploymentSpec = new V1DeploymentSpec(replicas: 1, selector: selector, template: v1PodSpec); desiredDeployments.Add(new V1Deployment(metadata: deploymentMeta, spec: deploymentSpec)); } else { Events.InvalidModuleType(module); } } // Find current Services/Deployments which need to be removed and updated var servicesRemoved = new List <V1Service>(currentServices.Items); servicesRemoved.RemoveAll(s => desiredServices.Exists(i => string.Equals(i.Metadata.Name, s.Metadata.Name))); var deploymentsRemoved = new List <V1Deployment>(currentDeployments.Items); deploymentsRemoved.RemoveAll( d => { return(desiredDeployments.Exists(i => string.Equals(i.Metadata.Name, d.Metadata.Name))); }); var newServices = new List <V1Service>(); desiredServices.ForEach( s => { string creationString = JsonConvert.SerializeObject(s); if (currentV1ServicesFromAnnotations.ContainsKey(s.Metadata.Name)) { string serviceAnnotation = currentV1ServicesFromAnnotations[s.Metadata.Name]; // If configuration matches, no need to update service if (string.Equals(serviceAnnotation, creationString)) { return; } if (s.Metadata.Annotations == null) { s.Metadata.Annotations = new Dictionary <string, string>(); } s.Metadata.Annotations[Constants.CreationString] = creationString; servicesRemoved.Add(s); newServices.Add(s); Events.UpdateService(s.Metadata.Name); } else { if (s.Metadata.Annotations == null) { s.Metadata.Annotations = new Dictionary <string, string>(); } s.Metadata.Annotations[Constants.CreationString] = creationString; newServices.Add(s); Events.CreateService(s.Metadata.Name); } }); var deploymentsUpdated = new List <V1Deployment>(); var newDeployments = new List <V1Deployment>(); List <V1Deployment> currentDeploymentsList = currentDeployments.Items.ToList(); desiredDeployments.ForEach( d => { if (currentDeploymentsFromAnnotations.ContainsKey(d.Metadata.Name)) { V1Deployment current = currentDeploymentsList.Find(i => string.Equals(i.Metadata.Name, d.Metadata.Name)); string currentFromAnnotation = currentDeploymentsFromAnnotations[d.Metadata.Name]; string creationString = JsonConvert.SerializeObject(d); // If configuration matches, or this is edgeAgent deployment and the images match, // no need to do update deployment if (string.Equals(currentFromAnnotation, creationString) || (string.Equals(d.Metadata.Name, this.DeploymentName(CoreConstants.EdgeAgentModuleName)) && V1DeploymentEx.ImageEquals(current, d))) { return; } d.Metadata.ResourceVersion = current.Metadata.ResourceVersion; if (d.Metadata.Annotations == null) { var annotations = new Dictionary <string, string> { [Constants.CreationString] = creationString }; d.Metadata.Annotations = annotations; } else { d.Metadata.Annotations[Constants.CreationString] = creationString; } deploymentsUpdated.Add(d); Events.UpdateDeployment(d.Metadata.Name); } else { string creationString = JsonConvert.SerializeObject(d); var annotations = new Dictionary <string, string> { [Constants.CreationString] = creationString }; d.Metadata.Annotations = annotations; newDeployments.Add(d); Events.CreateDeployment(d.Metadata.Name); } }); // Remove the old IEnumerable <Task <V1Status> > removeServiceTasks = servicesRemoved.Select( i => { Events.DeletingService(i); return(this.client.DeleteNamespacedServiceAsync(i.Metadata.Name, this.k8sNamespace, new V1DeleteOptions())); }); await Task.WhenAll(removeServiceTasks); IEnumerable <Task <V1Status> > removeDeploymentTasks = deploymentsRemoved.Select( d => { Events.DeletingDeployment(d); return(this.client.DeleteNamespacedDeployment1Async(d.Metadata.Name, this.k8sNamespace, new V1DeleteOptions(propagationPolicy: "Foreground"), propagationPolicy: "Foreground")); }); await Task.WhenAll(removeDeploymentTasks); // Create the new. IEnumerable <Task <V1Service> > createServiceTasks = newServices.Select( s => { Events.CreatingService(s); return(this.client.CreateNamespacedServiceAsync(s, this.k8sNamespace)); }); await Task.WhenAll(createServiceTasks); IEnumerable <Task <V1Deployment> > createDeploymentTasks = newDeployments.Select( deployment => { Events.CreatingDeployment(deployment); return(this.client.CreateNamespacedDeploymentAsync(deployment, this.k8sNamespace)); }); await Task.WhenAll(createDeploymentTasks); // Update the existing - should only do this when different. IEnumerable <Task <V1Deployment> > updateDeploymentTasks = deploymentsUpdated.Select(deployment => this.client.ReplaceNamespacedDeploymentAsync(deployment, deployment.Metadata.Name, this.k8sNamespace)); await Task.WhenAll(updateDeploymentTasks); this.currentModules = desiredModules; }
public V1Deployment Build(HealthCheckResource resource) { var metadata = new V1ObjectMeta { OwnerReferences = new List <V1OwnerReference> { resource.CreateOwnerReference() }, Annotations = new Dictionary <string, string>(), Labels = new Dictionary <string, string> { ["app"] = resource.Spec.Name }, Name = $"{resource.Spec.Name}-deploy", NamespaceProperty = resource.Metadata.NamespaceProperty }; var spec = new V1DeploymentSpec { Selector = new V1LabelSelector { MatchLabels = new Dictionary <string, string> { ["app"] = resource.Spec.Name } }, Replicas = 1, Template = new V1PodTemplateSpec { Metadata = new V1ObjectMeta { Labels = new Dictionary <string, string> { ["app"] = resource.Spec.Name }, }, Spec = new V1PodSpec { Containers = new List <V1Container> { new V1Container { ImagePullPolicy = resource.Spec.ImagePullPolicy ?? Constants.DefaultPullPolicy, Name = Constants.PodName, Image = resource.Spec.Image ?? Constants.ImageName, Ports = new List <V1ContainerPort> { new V1ContainerPort(80) }, Env = new List <V1EnvVar> { new V1EnvVar("ui_path", resource.Spec.UiPath ?? Constants.DefaultUIPath), new V1EnvVar("enable_push_endpoint", "true"), new V1EnvVar("push_endpoint_secret", valueFrom: new V1EnvVarSource(secretKeyRef: new V1SecretKeySelector("key", $"{resource.Spec.Name}-secret"))), new V1EnvVar("Logging__LogLevel__Default", "Debug"), new V1EnvVar("Logging__LogLevel__Microsoft", "Warning"), new V1EnvVar("Logging__LogLevel__System", "Warning"), new V1EnvVar("Logging__LogLevel__HealthChecks", "Information") } } } } } }; foreach (var annotation in resource.Spec.DeploymentAnnotations) { _logger.LogInformation("Adding annotation {Annotation} to ui deployment with value {AnnotationValue}", annotation.Name, annotation.Value); metadata.Annotations.Add(annotation.Name, annotation.Value); } if (resource.HasBrandingConfigured()) { var specification = spec.Template.Spec; var container = specification.Containers.First(); var volumeName = "healthchecks-volume"; if (specification.Volumes == null) { specification.Volumes = new List <V1Volume>(); } if (container.VolumeMounts == null) { container.VolumeMounts = new List <V1VolumeMount>(); } specification.Volumes.Add(new V1Volume(name: volumeName, configMap: new V1ConfigMapVolumeSource(name: $"{resource.Spec.Name}-config"))); container.Env.Add(new V1EnvVar("ui_stylesheet", $"{Constants.StylesPath}/{Constants.StyleSheetName}")); container.VolumeMounts.Add(new V1VolumeMount($"/app/{Constants.StylesPath}", volumeName)); } return(new V1Deployment(metadata: metadata, spec: spec)); }
private static V1Deployment CreateDeploymentDefinition() { Guid podIdentifier = Guid.NewGuid(); var podidentifierstring = podIdentifier.ToString(); string podName = "pod-" + podidentifierstring; string containerPortName = "containerport"; string containerName = "container"; string deploymentName = "poddeployment-" + podIdentifier; V1ObjectMeta deplMetadata = new V1ObjectMeta(); deplMetadata.Name = deploymentName; deplMetadata.Labels = new Dictionary <string, string>(); deplMetadata.Labels.Add("component", "migrationservice"); V1DeploymentSpec deplSpec = new V1DeploymentSpec(); deplSpec.Selector = new V1LabelSelector(); deplSpec.Selector.MatchLabels = new Dictionary <string, string>(); deplSpec.Selector.MatchLabels.Add("app", "bamreplacement"); deplSpec.Replicas = 3; // to be tokenized deplSpec.Strategy = new V1DeploymentStrategy(); deplSpec.Strategy.Type = "RollingUpdate"; deplSpec.Strategy.RollingUpdate = new V1RollingUpdateDeployment(); deplSpec.Strategy.RollingUpdate.MaxSurge = 1; deplSpec.Strategy.RollingUpdate.MaxUnavailable = 0; V1ObjectMeta podMetadata = new V1ObjectMeta(); podMetadata.Name = podName; podMetadata.Labels = new Dictionary <string, string>(); podMetadata.Labels.Add("app", "bamreplacement"); V1ContainerPort port = new V1ContainerPort(); port.Name = containerPortName; port.ContainerPort = 8080; V1EnvVar addr = new V1EnvVar(); addr.Name = "ACTIVITY_PARTITION_NAME"; addr.Value = "bam_EnrichedFPAttributesV2_Instances"; V1Container container = new V1Container(); container.Name = containerName; // container.Image = "abhishekagg24/stableapp:v1"; //container.Image = "nbsbamreplacementmigrationservice:dev"; container.Image = "bamreplacementwebapp:dev"; container.Ports = new List <V1ContainerPort>(); container.Ports.Add(port); container.Env = new List <V1EnvVar>(); container.Env.Add(addr); V1PodSpec podSpec = new V1PodSpec(); podSpec.Containers = new List <V1Container>(); podSpec.Containers.Add(container); deplSpec.Template = new V1PodTemplateSpec(); deplSpec.Template.Metadata = podMetadata; deplSpec.Template.Spec = podSpec; V1Deployment deployment = new V1Deployment(); deployment.ApiVersion = "apps/v1"; deployment.Kind = "Deployment"; deployment.Metadata = deplMetadata; deployment.Spec = deplSpec; return(deployment); }