From b60d9a11fa762f30b3b3a184156c290ea7c13ae3 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Mon, 22 Jun 2020 11:50:32 +0100 Subject: [PATCH] Example with Kubernetes ConfigMap. --- .../filesystem-config-source.adoc | 4 +- .../configmap/.kubernetes/configmap-app.yml | 57 +++++++++ examples/configmap/README.adoc | 76 ++++++++++++ examples/configmap/pom.xml | 110 ++++++++++++++++++ .../examples/configmap/ConfigMapApp.java | 44 +++++++ .../ConfigMapConfigSourceFactory.java | 27 +++++ .../io.smallrye.config.ConfigSourceFactory | 1 + examples/pom.xml | 1 + .../source/file/FileSystemConfigSource.java | 8 +- 9 files changed, 324 insertions(+), 4 deletions(-) create mode 100644 examples/configmap/.kubernetes/configmap-app.yml create mode 100644 examples/configmap/README.adoc create mode 100644 examples/configmap/pom.xml create mode 100644 examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapApp.java create mode 100644 examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapConfigSourceFactory.java create mode 100644 examples/configmap/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceFactory diff --git a/doc/modules/ROOT/pages/config-sources/filesystem-config-source.adoc b/doc/modules/ROOT/pages/config-sources/filesystem-config-source.adoc index aa4539f2a..16d0596b1 100644 --- a/doc/modules/ROOT/pages/config-sources/filesystem-config-source.adoc +++ b/doc/modules/ROOT/pages/config-sources/filesystem-config-source.adoc @@ -35,14 +35,14 @@ The same mapping rules as defined for environment variables are applied, so the To use the FileSystem Config Source, add the following to your Maven `pom.xml`: -[source,xml,subs="verbatim,attributes"] +https://xxx[[source,xml,subs="verbatim,attributes"] ---- io.smallrye.config smallrye-config-source-file-system {version} ----- +----] This Config Source is not automatically registered. This means that you also need to provide your own `ConfigSourceProvider` implementation and registration via `ServiceLoader` to use this Config Source like documented in diff --git a/examples/configmap/.kubernetes/configmap-app.yml b/examples/configmap/.kubernetes/configmap-app.yml new file mode 100644 index 000000000..9f496f3ee --- /dev/null +++ b/examples/configmap/.kubernetes/configmap-app.yml @@ -0,0 +1,57 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: configmap-app +spec: + type: "LoadBalancer" + ports: + - name: "http" + port: 8080 + targetPort: 8080 + selector: + app: configmap-app +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: configmap-app + labels: + app: configmap-app +spec: + replicas: 1 + selector: + matchLabels: + app: configmap-app + template: + metadata: + labels: + app: configmap-app + spec: + containers: + - name: configmap-app + image: docker-registry:5000/smallrye-config-examples/configmap-app + imagePullPolicy: Always + ports: + - containerPort: 8080 + env: + - name: CONFIG_MAP_DIR_SOURCE + value: "/usr/local/apps/config" + volumeMounts: + - name: configmap-app + mountPath: /usr/local/apps/config + volumes: + - name: configmap-app + configMap: + name: configmap-app + restartPolicy: Always +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: configmap-app + labels: + app: configmap-app +data: + smallrye.config.example.configmap.foo: something + smallrye.config.example.configmap.bar: something-else diff --git a/examples/configmap/README.adoc b/examples/configmap/README.adoc new file mode 100644 index 000000000..aa26b9eee --- /dev/null +++ b/examples/configmap/README.adoc @@ -0,0 +1,76 @@ += Kubernetes ConfigMap ConfigSource Example + +In this example, the `FileSystemConfigSource` is used to access a Kubernetes ConfigMap configuration. + +== Setup + +Since the `FileSystemConfigSource` is implemented in a separate `SmallRyeConfig` module, it requires an additional +dependency in the project that wants to read configuration from Kubernetes ConfigMap. + +[source,xml,subs="verbatim,attributes"] +---- + + io.smallrye.config + smallrye-config-source-file-system + {version} + +---- + +== Implementation + +The `FileSystemConfigSource` needs to be registed with the application. The recommended way is to use a +`ConfigSourceFactory` via the standard ServiceLoader mechanism. The factory gives the option to configure the +`FileSystemConfigSource` with higher priority ConfigSources. + +[source,java] +---- +public class ConfigMapConfigSourceFactory implements ConfigSourceFactory { + @Override + public ConfigSource getSource(final ConfigSourceContext context) { + final ConfigValue value = context.getValue("CONFIG_MAP_DIR_SOURCE"); + if (value == null || value.getValue() == null) { + throw new IllegalArgumentException("CONFIG_MAP_DIR_SOURCE not defined"); + } + + return new FileSystemConfigSource(value.getValue()); + } + + @Override + public OptionalInt getPriority() { + return OptionalInt.of(200); + } +} +---- + +In this case, the volume path to read the Kubernetes ConfigMap comes from an environment variable configuration. + +== Run + +The example starts a simple http server with a single endpoint im `/configMap`. To deploy the example in a Kubernetes +cluster requires the following steps. + +Set up a local Docker Registry first to store the generated Docker images: + +[source,bash] +---- +docker run -d -p 5000:5000 --restart=always --name docker-registry registry:2 +---- + +Set up a host in '/etc/hosts' pointing `127.0.0.1` to `docker-registry`. + +Build the example with: + +[source,bash] +---- +mvn package docker:build docker:push +---- + +Deploy to Kubernetes with: + +[source,bash] +---- +kubectl apply -f .kubernetes +---- + +Call tbe endpoint `curl http://localhost:8080/configMap`. This should list all the configurations set in the Kubernets +Config Map. The Kubernetes and ConfigMap configuration can be found in `.kubernetes/configmap-app.yml`. diff --git a/examples/configmap/pom.xml b/examples/configmap/pom.xml new file mode 100644 index 000000000..c71ac1d63 --- /dev/null +++ b/examples/configmap/pom.xml @@ -0,0 +1,110 @@ + + + 4.0.0 + + io.smallrye + smallrye-parent + 20 + + + io.smallrye.config.examples + configmap + 1.8.2-SNAPSHOT + + SmallRye Config Examples: ConfigMap + + + + jakarta.annotation + jakarta.annotation-api + + + + io.smallrye.config + smallrye-config + ${project.version} + + + + io.smallrye.config + smallrye-config-source-file-system + ${project.version} + + + + + org.junit.jupiter + junit-jupiter + + + + + + + maven-assembly-plugin + 3.3.0 + + ${project.artifactId}-app + false + + + io.smallrye.config.examples.configmap.ConfigMapApp + + + + jar-with-dependencies + + + + + create-jar + package + + single + + + + + + + io.fabric8 + docker-maven-plugin + 0.33.0 + + true + docker-registry:5000 + docker.io + + + smallrye-config-examples/configmap-app + + adoptopenjdk/openjdk11:alpine-slim + + 8080 + + /usr/local/apps + + usr/local/apps + + + + ${project.build.directory}/${project.artifactId}-app.jar + ${project.artifactId}-app.jar + + + + + java -jar ${project.artifactId}-app.jar + + + + 8080:8080 + + + + + + + + + diff --git a/examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapApp.java b/examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapApp.java new file mode 100644 index 000000000..35f422246 --- /dev/null +++ b/examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapApp.java @@ -0,0 +1,44 @@ +package io.smallrye.config.examples.configmap; + +import java.net.InetSocketAddress; +import java.util.Map; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import org.eclipse.microprofile.config.spi.ConfigSource; + +import com.sun.net.httpserver.HttpServer; + +public class ConfigMapApp { + public static void main(String[] args) throws Exception { + Config config = ConfigProvider.getConfig(); + + HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); + server.createContext("/configMap", exchange -> { + boolean responseSent = false; + + final Iterable configSources = config.getConfigSources(); + for (ConfigSource configSource : configSources) { + if (configSource.getName().startsWith("FileSystemConfig")) { + final Map properties = configSource.getProperties(); + final byte[] bytes = properties.toString().getBytes(); + exchange.sendResponseHeaders(200, properties.toString().length()); + exchange.getResponseBody().write(bytes); + exchange.getResponseBody().flush(); + exchange.getResponseBody().close(); + responseSent = true; + break; + } + } + + if (!responseSent) { + exchange.sendResponseHeaders(404, 0); + exchange.getResponseBody().write(new byte[0]); + exchange.getResponseBody().flush(); + exchange.getResponseBody().close(); + } + }); + + server.start(); + } +} diff --git a/examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapConfigSourceFactory.java b/examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapConfigSourceFactory.java new file mode 100644 index 000000000..4c10b5211 --- /dev/null +++ b/examples/configmap/src/main/java/io/smallrye/config/examples/configmap/ConfigMapConfigSourceFactory.java @@ -0,0 +1,27 @@ +package io.smallrye.config.examples.configmap; + +import java.util.OptionalInt; + +import org.eclipse.microprofile.config.spi.ConfigSource; + +import io.smallrye.config.ConfigSourceContext; +import io.smallrye.config.ConfigSourceFactory; +import io.smallrye.config.ConfigValue; +import io.smallrye.config.source.file.FileSystemConfigSource; + +public class ConfigMapConfigSourceFactory implements ConfigSourceFactory { + @Override + public ConfigSource getSource(final ConfigSourceContext context) { + final ConfigValue value = context.getValue("config.map.dir.source"); + if (value == null || value.getValue() == null) { + throw new IllegalArgumentException("CONFIG_MAP_DIR_SOURCE not defined"); + } + + return new FileSystemConfigSource(value.getValue()); + } + + @Override + public OptionalInt getPriority() { + return OptionalInt.of(200); + } +} diff --git a/examples/configmap/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceFactory b/examples/configmap/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceFactory new file mode 100644 index 000000000..bd3b3ba4e --- /dev/null +++ b/examples/configmap/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceFactory @@ -0,0 +1 @@ +io.smallrye.config.examples.configmap.ConfigMapConfigSourceFactory diff --git a/examples/pom.xml b/examples/pom.xml index 211998a71..f1425f7e9 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -32,5 +32,6 @@ interceptors expansion profiles + configmap diff --git a/sources/file-system/src/main/java/io/smallrye/config/source/file/FileSystemConfigSource.java b/sources/file-system/src/main/java/io/smallrye/config/source/file/FileSystemConfigSource.java index 7396aa339..294cd4839 100644 --- a/sources/file-system/src/main/java/io/smallrye/config/source/file/FileSystemConfigSource.java +++ b/sources/file-system/src/main/java/io/smallrye/config/source/file/FileSystemConfigSource.java @@ -60,10 +60,14 @@ public class FileSystemConfigSource extends MapBackedConfigSource { private static final Pattern PATTERN = Pattern.compile("[^a-zA-Z0-9_]"); - FileSystemConfigSource(File dir) { + public FileSystemConfigSource(File dir) { this(dir, DEFAULT_ORDINAL); } + public FileSystemConfigSource(String dir) { + this(new File(dir), DEFAULT_ORDINAL); + } + /** * Construct a new instance * @@ -71,7 +75,7 @@ public class FileSystemConfigSource extends MapBackedConfigSource { * @param ordinal the ordinal value */ public FileSystemConfigSource(File dir, int ordinal) { - super("DirConfigSource[dir=" + dir.getAbsolutePath() + "]", scan(dir), ordinal); + super("FileSystemConfigSource[dir=" + dir.getAbsolutePath() + "]", scan(dir), ordinal); } private static Map scan(File directory) {