⚗️ Installing kubectl inside container

This commit is contained in:
Andreas Dinauer 2025-06-07 11:22:52 +02:00
parent b40ba6c8ee
commit dc633ead9d
4 changed files with 50 additions and 17 deletions

View File

@ -78,20 +78,36 @@
# accessed directly. (example: "foo.example.com,bar.example.com") # accessed directly. (example: "foo.example.com,bar.example.com")
# #
### ###
FROM registry.access.redhat.com/ubi9/openjdk-21:1.21 FROM eclipse-temurin:21-jdk
ENV LANGUAGE='en_US:en' ENV LANGUAGE='en_US:en'
WORKDIR /root
RUN apt-get update && \
apt-get install -y apt-transport-https ca-certificates curl gnupg && \
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg && \
chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg && \
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | tee /etc/apt/sources.list.d/kubernetes.list && \
chmod 644 /etc/apt/sources.list.d/kubernetes.list && \
apt-get update && \
apt-get install -y kubectl
RUN useradd -m quarkus
WORKDIR /etc/build
# We make four distinct layers so if there are application changes the library layers can be re-used # We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ COPY target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/ COPY target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/ COPY target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ COPY target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080 EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" USER quarkus
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] CMD ["java","-jar","/deployments/quarkus-run.jar"]

View File

@ -12,6 +12,8 @@ import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces; import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@ -24,6 +26,8 @@ import java.util.List;
@Authenticated @Authenticated
public class NodeResource public class NodeResource
{ {
private static final Logger LOG = LoggerFactory.getLogger(NodeResource.class);
@Inject @Inject
ClientProvider clientProvider; ClientProvider clientProvider;
@ -34,6 +38,7 @@ public class NodeResource
List<NodeStats> result = new ArrayList<>(); List<NodeStats> result = new ArrayList<>();
List<String> stats = getTopNodes(); List<String> stats = getTopNodes();
for(String nodeName : stats) for(String nodeName : stats)
{ {
String[] parts = nodeName.split("\\s+"); String[] parts = nodeName.split("\\s+");
@ -53,7 +58,9 @@ public class NodeResource
private List<String> getTopNodes() throws IOException, InterruptedException private List<String> getTopNodes() throws IOException, InterruptedException
{ {
ProcessBuilder pb = new ProcessBuilder(List.of("kubectl", "top", "nodes", "--no-headers")); List<String> commands = List.of("kubectl", String.format("--kubeconfig=%s", clientProvider.pathToKubeconfig()), "top", "nodes", "--no-headers");
LOG.info("Executing command: {}", String.join(" ", commands));
ProcessBuilder pb = new ProcessBuilder(commands);
Process p = pb.start(); Process p = pb.start();
List<String> text = new ArrayList<>(); List<String> text = new ArrayList<>();
@ -65,9 +72,14 @@ public class NodeResource
text.add(line); text.add(line);
} }
} }
p.waitFor(); int exitCode = p.waitFor();
if(exitCode == 0)
{
LOG.info("Found {} nodes", text.size());
return text; return text;
} }
throw new RuntimeException("Failed to retrieve top nodes.");
}
public record NodeStats(Node node, Integer absoluteCpuUsage, Integer relativeCpuUsage, Integer totalCpu, Integer absoluteMemory, Integer relativeMemory, Integer totalMemory) public record NodeStats(Node node, Integer absoluteCpuUsage, Integer relativeCpuUsage, Integer totalCpu, Integer absoluteMemory, Integer relativeMemory, Integer totalMemory)
{ {

View File

@ -1,29 +1,32 @@
package dev.dinauer.utils; package dev.dinauer.utils;
import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.kubernetes.client.extension.ExtensionAdapter;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.client.vertx.VertxHttpClientBuilder;
import io.fabric8.kubernetes.client.vertx.VertxHttpClientFactory; import io.fabric8.kubernetes.client.vertx.VertxHttpClientFactory;
import io.vertx.mutiny.core.Vertx; import io.vertx.mutiny.core.Vertx;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.config.inject.ConfigProperty;
import java.io.File; import java.io.File;
@ApplicationScoped @ApplicationScoped
public class ClientProvider public class ClientProvider
{ {
@ConfigProperty(name = "dev.dinauer.kobooboo.kubeconfigs.dir")
String configFilePath;
@Inject @Inject
Vertx vertx; Vertx vertx;
public KubernetesClient getClient() public KubernetesClient getClient()
{ {
String configFilePath = ConfigProvider.getConfig().getValue("dev.dinauer.kobooboo.kubeconfigs.dir", String.class);
return new KubernetesClientBuilder().withConfig(Config.fromKubeconfig(new File(configFilePath))).withHttpClientFactory(new VertxHttpClientFactory(vertx.getDelegate())).build(); return new KubernetesClientBuilder().withConfig(Config.fromKubeconfig(new File(configFilePath))).withHttpClientFactory(new VertxHttpClientFactory(vertx.getDelegate())).build();
} }
public String pathToKubeconfig()
{
return configFilePath;
}
} }

View File

@ -3,6 +3,7 @@ package dev.dinauer.utils;
import dev.dinauer.login.User; import dev.dinauer.login.User;
import dev.dinauer.login.UserRepo; import dev.dinauer.login.UserRepo;
import io.quarkus.elytron.security.common.BcryptUtil; import io.quarkus.elytron.security.common.BcryptUtil;
import io.quarkus.runtime.Startup;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
@ -10,6 +11,7 @@ import jakarta.inject.Inject;
import java.io.IOException; import java.io.IOException;
import java.util.Set; import java.util.Set;
@Startup
@ApplicationScoped @ApplicationScoped
public class StartupService public class StartupService
{ {