[BAEL-7049] Kubernetes Operator (#15469)
* [BAEL-7049] Article Code * [BAEL-7049] Fix README --------- Co-authored-by: Philippe Sevestre <psevestre@gmail.com>
This commit is contained in:
parent
d317cbf552
commit
d27a274136
41
kubernetes-modules/k8s-operator/.gitignore
vendored
Normal file
41
kubernetes-modules/k8s-operator/.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#Maven
|
||||||
|
target/
|
||||||
|
pom.xml.tag
|
||||||
|
pom.xml.releaseBackup
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
release.properties
|
||||||
|
.flattened-pom.xml
|
||||||
|
|
||||||
|
# Eclipse
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.settings/
|
||||||
|
bin/
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
.idea
|
||||||
|
*.ipr
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# NetBeans
|
||||||
|
nb-configuration.xml
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
# OSX
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Vim
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# patch
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
|
||||||
|
# Local environment
|
||||||
|
.env
|
||||||
|
|
4
kubernetes-modules/k8s-operator/README.md
Normal file
4
kubernetes-modules/k8s-operator/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Dependency-Track operator
|
||||||
|
|
||||||
|
This sample demonstrates how to create a simple operator using the Java Operator Framework. In our case, the operator will facilitate
|
||||||
|
the deployment of a Dependency-Track instance on a cluster.
|
88
kubernetes-modules/k8s-operator/k8s/deptrack-controller.yaml
Normal file
88
kubernetes-modules/k8s-operator/k8s/deptrack-controller.yaml
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: deptrack-operator
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: deptrack-operator
|
||||||
|
namespace: deptrack-operator
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deptrack-operator
|
||||||
|
namespace: deptrack-operator
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: deptrack-operator
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: deptrack-operator
|
||||||
|
spec:
|
||||||
|
serviceAccountName: deptrack-operator
|
||||||
|
containers:
|
||||||
|
- name: operator
|
||||||
|
image: deptrack-operator
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /actuator/health/readiness
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /actuator/health/liveness
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: deptrack-operator-admin
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: deptrack-operator
|
||||||
|
namespace: deptrack-operator
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: deptrack-operator
|
||||||
|
apiGroup: ""
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: deptrack-operator
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- deployments
|
||||||
|
- services
|
||||||
|
- ingresses
|
||||||
|
- configmaps
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- '*'
|
||||||
|
- apiGroups:
|
||||||
|
- "apiextensions.k8s.io"
|
||||||
|
resources:
|
||||||
|
- customresourcedefinitions
|
||||||
|
verbs:
|
||||||
|
- '*'
|
||||||
|
- apiGroups:
|
||||||
|
- "com.baeldung"
|
||||||
|
resources:
|
||||||
|
- deptrackresources
|
||||||
|
- deptrackresources/status
|
||||||
|
verbs:
|
||||||
|
- '*'
|
12
kubernetes-modules/k8s-operator/k8s/test-resource.yaml
Normal file
12
kubernetes-modules/k8s-operator/k8s/test-resource.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: com.baeldung/v1
|
||||||
|
kind: DeptrackResource
|
||||||
|
metadata:
|
||||||
|
namespace: test
|
||||||
|
name: deptrack1
|
||||||
|
labels:
|
||||||
|
project: tutorials
|
||||||
|
annotations:
|
||||||
|
author: Philippe Sevestre
|
||||||
|
|
||||||
|
spec:
|
||||||
|
ingressHostname: deptrack.172.31.42.16.nip.io
|
111
kubernetes-modules/k8s-operator/pom.xml
Normal file
111
kubernetes-modules/k8s-operator/pom.xml
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-3</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>./../../parent-boot-3</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>k8s-operator</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
<name>k8s-operator</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<josdk.version>4.6.0</josdk.version>
|
||||||
|
<fabric8-client.version>6.9.2</fabric8-client.version>
|
||||||
|
<bouncycastle.version>1.77</bouncycastle.version>
|
||||||
|
<slf4j.version>2.0.9</slf4j.version>
|
||||||
|
<operator-framework-spring-boot.version>5.4.0</operator-framework-spring-boot.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.javaoperatorsdk</groupId>
|
||||||
|
<artifactId>operator-framework-spring-boot-starter</artifactId>
|
||||||
|
<version>${operator-framework-spring-boot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.javaoperatorsdk</groupId>
|
||||||
|
<artifactId>operator-framework-spring-boot-starter-test</artifactId>
|
||||||
|
<version>${operator-framework-spring-boot.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.fabric8</groupId>
|
||||||
|
<artifactId>crd-generator-apt</artifactId>
|
||||||
|
<version>${fabric8-client.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk18on</artifactId>
|
||||||
|
<version>${bouncycastle.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk18on</artifactId>
|
||||||
|
<version>${bouncycastle.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.awaitility</groupId>
|
||||||
|
<artifactId>awaitility</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<image>
|
||||||
|
<name>deptrack-operator</name>
|
||||||
|
</image>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.baeldung.operators.deptrack;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(Application.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Application.class,args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.baeldung.operators.deptrack.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class OperatorConfiguration {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.baeldung.operators.deptrack.controller.deptrack;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.baeldung.operators.deptrack.resources.deptrack.DeptrackApiServerDeploymentResource;
|
||||||
|
import com.baeldung.operators.deptrack.resources.deptrack.DeptrackApiServerServiceResource;
|
||||||
|
import com.baeldung.operators.deptrack.resources.deptrack.DeptrackFrontendDeploymentResource;
|
||||||
|
import com.baeldung.operators.deptrack.resources.deptrack.DeptrackFrontendServiceResource;
|
||||||
|
import com.baeldung.operators.deptrack.resources.deptrack.DeptrackIngressResource;
|
||||||
|
import com.baeldung.operators.deptrack.resources.deptrack.DeptrackResource;
|
||||||
|
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.Context;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@ControllerConfiguration(dependents = {
|
||||||
|
@Dependent(name = DeptrackApiServerDeploymentResource.COMPONENT, type = DeptrackApiServerDeploymentResource.class),
|
||||||
|
@Dependent(name = DeptrackFrontendDeploymentResource.COMPONENT, type = DeptrackFrontendDeploymentResource.class),
|
||||||
|
@Dependent(name = DeptrackApiServerServiceResource.COMPONENT, type = DeptrackApiServerServiceResource.class),
|
||||||
|
@Dependent(name = DeptrackFrontendServiceResource.COMPONENT, type = DeptrackFrontendServiceResource.class),
|
||||||
|
@Dependent(type = DeptrackIngressResource.class )
|
||||||
|
})
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Component
|
||||||
|
public class DeptrackOperatorReconciler implements Reconciler<DeptrackResource> {
|
||||||
|
|
||||||
|
private final ApplicationContext ctx;
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void onPostConstruct() {
|
||||||
|
log.info("Reconciler created");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpdateControl<DeptrackResource> reconcile(DeptrackResource resource, Context<DeptrackResource> context) throws Exception {
|
||||||
|
return UpdateControl.noUpdate();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources;
|
||||||
|
|
||||||
|
public interface Constants {
|
||||||
|
|
||||||
|
String OPERATOR_NAME = "dependency-track-demo-operator";
|
||||||
|
String DEFAULT_API_SERVER_IMAGE = "dependencytrack/apiserver";
|
||||||
|
String DEFAULT_FRONTEND_IMAGE = "dependencytrack/frontend";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.baeldung.operators.deptrack.resources.Constants;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.ManagedFieldsEntry;
|
||||||
|
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
|
||||||
|
import io.fabric8.kubernetes.client.CustomResource;
|
||||||
|
|
||||||
|
public final class BuilderHelper {
|
||||||
|
private static ObjectMapper om;
|
||||||
|
static {
|
||||||
|
om = new ObjectMapper(new YAMLFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BuilderHelper(){}
|
||||||
|
|
||||||
|
public static <T extends CustomResource<?,?>> ObjectMetaBuilder fromPrimary(T primary, String component) {
|
||||||
|
return new ObjectMetaBuilder()
|
||||||
|
.withNamespace(primary.getMetadata().getNamespace())
|
||||||
|
.withManagedFields((List<ManagedFieldsEntry>)null)
|
||||||
|
.addToLabels("component", component)
|
||||||
|
.addToLabels("name", primary.getMetadata().getName())
|
||||||
|
.withName(primary.getMetadata().getName() + "-" + component)
|
||||||
|
.addToLabels("ManagedBy", Constants.OPERATOR_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T loadTemplate(Class<T> clazz, String resource) {
|
||||||
|
|
||||||
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||||
|
if ( cl == null ) {
|
||||||
|
cl = BuilderHelper.class.getClassLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream is = cl.getResourceAsStream(resource)){
|
||||||
|
return loadTemplate(clazz, is);
|
||||||
|
}
|
||||||
|
catch(IOException ioe) {
|
||||||
|
throw new RuntimeException("Unable to load classpath resource '" + resource + "': " + ioe.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T loadTemplate(Class<T> clazz, InputStream is) throws IOException{
|
||||||
|
return om.readValue(is, clazz);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import static com.baeldung.operators.deptrack.resources.deptrack.BuilderHelper.fromPrimary;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.baeldung.operators.deptrack.resources.Constants;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.LabelSelector;
|
||||||
|
import io.fabric8.kubernetes.api.model.LabelSelectorBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodSpec;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodSpecBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.DeploymentSpec;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.Context;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.ResourceIDMatcherDiscriminator;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
|
||||||
|
import io.javaoperatorsdk.operator.processing.event.ResourceID;
|
||||||
|
|
||||||
|
@KubernetesDependent( resourceDiscriminator = DeptrackApiServerDeploymentResource.Discriminator.class)
|
||||||
|
public class DeptrackApiServerDeploymentResource extends CRUDKubernetesDependentResource<Deployment, DeptrackResource> {
|
||||||
|
|
||||||
|
public static final String COMPONENT = "api-server";
|
||||||
|
|
||||||
|
private Deployment template;
|
||||||
|
public DeptrackApiServerDeploymentResource() {
|
||||||
|
super(Deployment.class);
|
||||||
|
this.template = BuilderHelper.loadTemplate(Deployment.class, "templates/api-server-deployment.yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Deployment desired(DeptrackResource primary, Context<DeptrackResource> context) {
|
||||||
|
|
||||||
|
ObjectMeta meta = fromPrimary(primary,COMPONENT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return new DeploymentBuilder(template)
|
||||||
|
.withMetadata(meta)
|
||||||
|
.withSpec(buildSpec(primary, meta))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeploymentSpec buildSpec(DeptrackResource primary, ObjectMeta primaryMeta) {
|
||||||
|
|
||||||
|
return new DeploymentSpecBuilder()
|
||||||
|
.withSelector(buildSelector(primaryMeta.getLabels()))
|
||||||
|
.withReplicas(1) // Dependenty track does not support multiple pods (yet)
|
||||||
|
.withTemplate(buildPodTemplate(primary,primaryMeta))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LabelSelector buildSelector(Map<String, String> labels) {
|
||||||
|
return new LabelSelectorBuilder()
|
||||||
|
.addToMatchLabels(labels)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PodTemplateSpec buildPodTemplate(DeptrackResource primary, ObjectMeta primaryMeta) {
|
||||||
|
|
||||||
|
return new PodTemplateSpecBuilder()
|
||||||
|
.withMetadata(primaryMeta)
|
||||||
|
.withSpec(buildPodSpec(primary))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PodSpec buildPodSpec(DeptrackResource primary) {
|
||||||
|
|
||||||
|
// Check for version override
|
||||||
|
String imageVersion = StringUtils.hasText(primary.getSpec().getApiServerVersion())?
|
||||||
|
":" + primary.getSpec().getApiServerVersion().trim():"";
|
||||||
|
|
||||||
|
// Check for image override
|
||||||
|
String imageName = StringUtils.hasText(primary.getSpec().getApiServerImage())?
|
||||||
|
primary.getSpec().getApiServerImage().trim(): Constants.DEFAULT_API_SERVER_IMAGE;
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
return new PodSpecBuilder(template.getSpec().getTemplate().getSpec())
|
||||||
|
.editContainer(0) // Assumes we have a single container
|
||||||
|
.withImage(imageName + imageVersion)
|
||||||
|
.and()
|
||||||
|
.build();
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class Discriminator extends ResourceIDMatcherDiscriminator<Deployment,DeptrackResource> {
|
||||||
|
public Discriminator() {
|
||||||
|
super(COMPONENT, (p) -> new ResourceID(p.getMetadata()
|
||||||
|
.getName() + "-" + COMPONENT, p.getMetadata()
|
||||||
|
.getNamespace()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import static com.baeldung.operators.deptrack.resources.deptrack.BuilderHelper.fromPrimary;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||||
|
import io.fabric8.kubernetes.api.model.Service;
|
||||||
|
import io.fabric8.kubernetes.api.model.ServiceBuilder;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.Context;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.ResourceIDMatcherDiscriminator;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
|
||||||
|
import io.javaoperatorsdk.operator.processing.event.ResourceID;
|
||||||
|
|
||||||
|
@KubernetesDependent(resourceDiscriminator = DeptrackApiServerServiceResource.Discriminator.class)
|
||||||
|
public class DeptrackApiServerServiceResource extends CRUDKubernetesDependentResource<Service, DeptrackResource> {
|
||||||
|
|
||||||
|
public static final String COMPONENT = "api-server-service";
|
||||||
|
|
||||||
|
private Service template;
|
||||||
|
public DeptrackApiServerServiceResource() {
|
||||||
|
super(Service.class);
|
||||||
|
this.template = BuilderHelper.loadTemplate(Service.class, "templates/api-server-service.yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Service desired(DeptrackResource primary, Context<DeptrackResource> context) {
|
||||||
|
|
||||||
|
ObjectMeta meta = fromPrimary(primary,COMPONENT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Map<String, String> selector = new HashMap<>(meta.getLabels());
|
||||||
|
selector.put("component", DeptrackApiServerDeploymentResource.COMPONENT);
|
||||||
|
|
||||||
|
return new ServiceBuilder(template)
|
||||||
|
.withMetadata(meta)
|
||||||
|
.editSpec()
|
||||||
|
.withSelector(selector)
|
||||||
|
.endSpec()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class Discriminator extends ResourceIDMatcherDiscriminator<Service,DeptrackResource> {
|
||||||
|
public Discriminator() {
|
||||||
|
super(COMPONENT, (p) -> new ResourceID(p.getMetadata().getName() + "-" + COMPONENT,p.getMetadata().getNamespace()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import static com.baeldung.operators.deptrack.resources.deptrack.BuilderHelper.fromPrimary;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.baeldung.operators.deptrack.resources.Constants;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.LabelSelector;
|
||||||
|
import io.fabric8.kubernetes.api.model.LabelSelectorBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodSpec;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodSpecBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
|
||||||
|
import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.DeploymentSpec;
|
||||||
|
import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.Context;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.ResourceIDMatcherDiscriminator;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
|
||||||
|
import io.javaoperatorsdk.operator.processing.event.ResourceID;
|
||||||
|
|
||||||
|
@KubernetesDependent(resourceDiscriminator = DeptrackFrontendDeploymentResource.Discriminator.class)
|
||||||
|
public class DeptrackFrontendDeploymentResource extends CRUDKubernetesDependentResource<Deployment, DeptrackResource> {
|
||||||
|
public static final String COMPONENT = "frontend";
|
||||||
|
private Deployment template;
|
||||||
|
|
||||||
|
public DeptrackFrontendDeploymentResource() {
|
||||||
|
super(Deployment.class);
|
||||||
|
this.template = BuilderHelper.loadTemplate(Deployment.class, "templates/frontend-deployment.yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Deployment desired(DeptrackResource primary, Context<DeptrackResource> context) {
|
||||||
|
|
||||||
|
ObjectMeta meta = fromPrimary(primary,COMPONENT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return new DeploymentBuilder(template).withMetadata(meta)
|
||||||
|
.withSpec(buildSpec(primary, meta))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeploymentSpec buildSpec(DeptrackResource primary, ObjectMeta primaryMeta) {
|
||||||
|
|
||||||
|
return new DeploymentSpecBuilder().withSelector(buildSelector(primaryMeta.getLabels()))
|
||||||
|
.withReplicas(1) // Dependency track does not support multiple pods (yet)
|
||||||
|
.withTemplate(buildPodTemplate(primary, primaryMeta))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LabelSelector buildSelector(Map<String, String> labels) {
|
||||||
|
return new LabelSelectorBuilder().addToMatchLabels(labels)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PodTemplateSpec buildPodTemplate(DeptrackResource primary, ObjectMeta primaryMeta) {
|
||||||
|
|
||||||
|
return new PodTemplateSpecBuilder().withMetadata(primaryMeta)
|
||||||
|
.withSpec(buildPodSpec(primary))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PodSpec buildPodSpec(DeptrackResource primary) {
|
||||||
|
|
||||||
|
// Check for version override
|
||||||
|
String imageVersion = StringUtils.hasText(primary.getSpec()
|
||||||
|
.getFrontendVersion()) ? ":" + primary.getSpec()
|
||||||
|
.getFrontendVersion()
|
||||||
|
.trim() : "";
|
||||||
|
|
||||||
|
// Check for image override
|
||||||
|
String imageName = StringUtils.hasText(primary.getSpec()
|
||||||
|
.getFrontendImage()) ? primary.getSpec()
|
||||||
|
.getFrontendImage()
|
||||||
|
.trim() : Constants.DEFAULT_FRONTEND_IMAGE;
|
||||||
|
|
||||||
|
return new PodSpecBuilder(template.getSpec().getTemplate().getSpec())
|
||||||
|
.editContainer(0)
|
||||||
|
.withImage(imageName + imageVersion)
|
||||||
|
.editFirstEnv()
|
||||||
|
.withName("API_BASE_URL")
|
||||||
|
.withValue("https://" + primary.getSpec().getIngressHostname())
|
||||||
|
.endEnv()
|
||||||
|
.and()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Discriminator extends ResourceIDMatcherDiscriminator<Deployment,DeptrackResource> {
|
||||||
|
public Discriminator() {
|
||||||
|
super(COMPONENT, (p) -> new ResourceID(p.getMetadata()
|
||||||
|
.getName() + "-" + COMPONENT, p.getMetadata()
|
||||||
|
.getNamespace()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import static com.baeldung.operators.deptrack.resources.deptrack.BuilderHelper.fromPrimary;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||||
|
import io.fabric8.kubernetes.api.model.Service;
|
||||||
|
import io.fabric8.kubernetes.api.model.ServiceBuilder;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.Context;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.ResourceIDMatcherDiscriminator;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
|
||||||
|
import io.javaoperatorsdk.operator.processing.event.ResourceID;
|
||||||
|
|
||||||
|
@KubernetesDependent(resourceDiscriminator = DeptrackFrontendServiceResource.Discriminator.class)
|
||||||
|
public class DeptrackFrontendServiceResource extends CRUDKubernetesDependentResource<Service, DeptrackResource> {
|
||||||
|
|
||||||
|
public static final String COMPONENT = "frontend-service";
|
||||||
|
|
||||||
|
private Service template;
|
||||||
|
public DeptrackFrontendServiceResource() {
|
||||||
|
super(Service.class);
|
||||||
|
this.template = BuilderHelper.loadTemplate(Service.class, "templates/frontend-service.yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Service desired(DeptrackResource primary, Context<DeptrackResource> context) {
|
||||||
|
|
||||||
|
ObjectMeta meta = fromPrimary(primary,COMPONENT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Map<String, String> selector = new HashMap<>(meta.getLabels());
|
||||||
|
selector.put("component", DeptrackFrontendDeploymentResource.COMPONENT);
|
||||||
|
|
||||||
|
return new ServiceBuilder(template)
|
||||||
|
.withMetadata(meta)
|
||||||
|
.editSpec()
|
||||||
|
.withSelector(selector)
|
||||||
|
.endSpec()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static class Discriminator implements ResourceDiscriminator<Service,DeptrackResource> {
|
||||||
|
// @Override
|
||||||
|
// public Optional<Service> distinguish(Class<Service> resource, DeptrackResource primary, Context<DeptrackResource> context) {
|
||||||
|
// var ies = context.eventSourceRetriever().getResourceEventSourceFor(Service.class,COMPONENT);
|
||||||
|
// return ies.getSecondaryResource(primary);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
static class Discriminator extends ResourceIDMatcherDiscriminator<Service,DeptrackResource> {
|
||||||
|
public Discriminator() {
|
||||||
|
super(COMPONENT, (p) -> new ResourceID(p.getMetadata().getName() + "-" + COMPONENT,p.getMetadata().getNamespace()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import static com.baeldung.operators.deptrack.resources.deptrack.BuilderHelper.fromPrimary;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||||
|
import io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressRuleValue;
|
||||||
|
import io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressRuleValueBuilder;
|
||||||
|
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||||
|
import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder;
|
||||||
|
import io.javaoperatorsdk.operator.api.reconciler.Context;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
|
||||||
|
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
|
||||||
|
|
||||||
|
@KubernetesDependent
|
||||||
|
public class DeptrackIngressResource extends CRUDKubernetesDependentResource<Ingress,DeptrackResource> {
|
||||||
|
|
||||||
|
private static final String COMPONENT = "ingress";
|
||||||
|
private final Ingress template;
|
||||||
|
|
||||||
|
public DeptrackIngressResource() {
|
||||||
|
super(Ingress.class);
|
||||||
|
this.template = BuilderHelper.loadTemplate(Ingress.class, "templates/ingress.yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Ingress desired(DeptrackResource primary, Context<DeptrackResource> context) {
|
||||||
|
|
||||||
|
ObjectMeta meta = fromPrimary(primary,COMPONENT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return new IngressBuilder(template)
|
||||||
|
.withMetadata(meta)
|
||||||
|
.editSpec()
|
||||||
|
.editDefaultBackend()
|
||||||
|
.editOrNewService()
|
||||||
|
.withName(primary.getFrontendServiceName())
|
||||||
|
.endService()
|
||||||
|
.endDefaultBackend()
|
||||||
|
.editFirstRule()
|
||||||
|
.withHost(primary.getSpec().getIngressHostname())
|
||||||
|
.withHttp(buildHttpRule(primary))
|
||||||
|
.endRule()
|
||||||
|
.endSpec()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private HTTPIngressRuleValue buildHttpRule(DeptrackResource primary) {
|
||||||
|
|
||||||
|
return new HTTPIngressRuleValueBuilder()
|
||||||
|
// Backend route
|
||||||
|
.addNewPath()
|
||||||
|
.withPath("/api")
|
||||||
|
.withPathType("Prefix")
|
||||||
|
.withNewBackend()
|
||||||
|
.withNewService()
|
||||||
|
.withName(primary.getApiServerServiceName())
|
||||||
|
.withNewPort()
|
||||||
|
.withName("http")
|
||||||
|
.endPort()
|
||||||
|
.endService()
|
||||||
|
.endBackend()
|
||||||
|
.endPath()
|
||||||
|
// Frontend route
|
||||||
|
.addNewPath()
|
||||||
|
.withPath("/")
|
||||||
|
.withPathType("Prefix")
|
||||||
|
.withNewBackend()
|
||||||
|
.withNewService()
|
||||||
|
.withName(primary.getFrontendServiceName())
|
||||||
|
.withNewPort()
|
||||||
|
.withName("http")
|
||||||
|
.endPort()
|
||||||
|
.endService()
|
||||||
|
.endBackend()
|
||||||
|
.endPath()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.api.model.Namespaced;
|
||||||
|
import io.fabric8.kubernetes.client.CustomResource;
|
||||||
|
import io.fabric8.kubernetes.model.annotation.Group;
|
||||||
|
import io.fabric8.kubernetes.model.annotation.Version;
|
||||||
|
|
||||||
|
@Group("com.baeldung")
|
||||||
|
@Version("v1")
|
||||||
|
public class DeptrackResource extends CustomResource<DeptrackSpec, DeptrackStatus> implements Namespaced {
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public String getFrontendServiceName() {
|
||||||
|
return this.getMetadata().getName() + "-" + DeptrackFrontendServiceResource.COMPONENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public String getApiServerServiceName() {
|
||||||
|
return this.getMetadata().getName() + "-" + DeptrackApiServerServiceResource.COMPONENT;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DeptrackSpec {
|
||||||
|
|
||||||
|
// Images
|
||||||
|
private String apiServerImage = "dependencytrack/apiserver";
|
||||||
|
private String apiServerVersion = "";
|
||||||
|
|
||||||
|
private String frontendImage = "dependencytrack/frontend";
|
||||||
|
private String frontendVersion = "";
|
||||||
|
|
||||||
|
// PVC settings: NOT IMPLEMENTED
|
||||||
|
private String pvcClass = ""; // Use default storage class
|
||||||
|
private String pvcSize = "10Gi";
|
||||||
|
|
||||||
|
|
||||||
|
// Database settings: NOT IMPLEMENTED
|
||||||
|
private String dbUrl;
|
||||||
|
private String dbDriver = "org.postgresql.Driver";
|
||||||
|
private String dbSecret;
|
||||||
|
|
||||||
|
|
||||||
|
// Ingress settings
|
||||||
|
private String ingressHostname;
|
||||||
|
private Map<String,String> ingressAnnotations;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.baeldung.operators.deptrack.resources.deptrack;
|
||||||
|
|
||||||
|
import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus;
|
||||||
|
|
||||||
|
public class DeptrackStatus extends ObservedGenerationAwareStatus {
|
||||||
|
}
|
13
kubernetes-modules/k8s-operator/src/main/logback.xml
Normal file
13
kubernetes-modules/k8s-operator/src/main/logback.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
@ -0,0 +1 @@
|
|||||||
|
management.endpoint.health.probes.enabled=true
|
@ -0,0 +1,53 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deptrack-api
|
||||||
|
namespace: deptrack
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: api-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: api-server
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: main
|
||||||
|
image: dependencytrack/apiserver:4.10.1
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
name: http
|
||||||
|
protocol: TCP
|
||||||
|
readinessProbe:
|
||||||
|
failureThreshold: 3
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 2
|
||||||
|
livenessProbe:
|
||||||
|
failureThreshold: 3
|
||||||
|
httpGet:
|
||||||
|
path: /api/version
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 2
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: 8Gi
|
||||||
|
requests:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 2Gi
|
||||||
|
restartPolicy: Always
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: deptrack-frontend
|
||||||
|
namespace: deptrack
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 8Gi
|
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: api-server-service
|
||||||
|
name: deptrack-api-server
|
||||||
|
namespace: deptrack
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8080
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 8080
|
||||||
|
selector:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: api-server
|
||||||
|
sessionAffinity: None
|
||||||
|
type: ClusterIP
|
@ -0,0 +1,46 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deptrack-frontend
|
||||||
|
namespace: deptrack
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: frontend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: main
|
||||||
|
env:
|
||||||
|
- name: API_BASE_URL
|
||||||
|
value: https://example.com
|
||||||
|
image: dependencytrack/frontend
|
||||||
|
imagePullPolicy: Always
|
||||||
|
livenessProbe:
|
||||||
|
failureThreshold: 3
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 1
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
name: http
|
||||||
|
protocol: TCP
|
||||||
|
readinessProbe:
|
||||||
|
failureThreshold: 3
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 1
|
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: frontend-service
|
||||||
|
name: deptrack-frontend
|
||||||
|
namespace: deptrack
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8080
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 8080
|
||||||
|
selector:
|
||||||
|
ManagedBy: deptrack-operator
|
||||||
|
component: frontend
|
||||||
|
sessionAffinity: None
|
||||||
|
type: ClusterIP
|
@ -0,0 +1,33 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
labels:
|
||||||
|
ManagedBy: terraform
|
||||||
|
component: ingress
|
||||||
|
name: deptrack-ingress
|
||||||
|
namespace: deptrack
|
||||||
|
spec:
|
||||||
|
defaultBackend:
|
||||||
|
service:
|
||||||
|
name: deptrack-frontend
|
||||||
|
port:
|
||||||
|
name: http
|
||||||
|
rules:
|
||||||
|
- host: example.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- backend:
|
||||||
|
service:
|
||||||
|
name: deptrack-api-server
|
||||||
|
port:
|
||||||
|
name: http
|
||||||
|
path: /api
|
||||||
|
pathType: Prefix
|
||||||
|
- backend:
|
||||||
|
service:
|
||||||
|
name: deptrack-frontend
|
||||||
|
port:
|
||||||
|
name: http
|
||||||
|
path: /
|
||||||
|
pathType: Prefix
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.baeldung.operators.deptrack;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||||
|
import io.javaoperatorsdk.operator.springboot.starter.test.EnableMockOperator;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@EnableMockOperator(crdPaths = "classpath:META-INF/fabric8/deptrackresources.com.baeldung-v1.yml")
|
||||||
|
class ApplicationUnitTest {
|
||||||
|
@Autowired
|
||||||
|
KubernetesClient client;
|
||||||
|
@Test
|
||||||
|
void whenContextLoaded_thenCrdRegistered() {
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
client
|
||||||
|
.apiextensions()
|
||||||
|
.v1()
|
||||||
|
.customResourceDefinitions()
|
||||||
|
.withName("deptrackresources.com.baeldung")
|
||||||
|
.get())
|
||||||
|
.isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
<module>k8s-admission-controller</module>
|
<module>k8s-admission-controller</module>
|
||||||
<module>kubernetes-spring</module>
|
<module>kubernetes-spring</module>
|
||||||
<module>k8s-java-heap-dump</module>
|
<module>k8s-java-heap-dump</module>
|
||||||
|
<module>k8s-operator</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user