From e81ed1eacefefa42e8187c47ff2aa1bfa6583338 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 11 Aug 2015 09:30:02 +0100 Subject: [PATCH] Align dockerization process with spring.io guides (And with existing Spring Cloud projects.) Uses a maven plugin to build the image. It can be pushed manually, or else using -Ddocker.image.prefix=. Removes some of the hard-coded host names and stuff that came with the old version. --- spring-cloud-stream-module-launcher/README.md | 15 +++++++-- .../docker-compose.yml | 19 ++++++++++++ .../dockerize.sh | 13 -------- spring-cloud-stream-module-launcher/pom.xml | 31 +++++++++++++------ .../{ => src/main/docker}/Dockerfile | 2 +- .../boot/loader/ModuleJarLauncher.java | 29 ++++++++--------- .../launcher/ModuleLauncherApplication.java | 22 ++++--------- .../launcher/ModuleLauncherConfiguration.java | 13 +++----- .../module/launcher/ModuleLauncherRunner.java | 20 ++++++------ .../docker-compose.yml | 4 +++ 10 files changed, 96 insertions(+), 72 deletions(-) create mode 100644 spring-cloud-stream-module-launcher/docker-compose.yml delete mode 100755 spring-cloud-stream-module-launcher/dockerize.sh rename spring-cloud-stream-module-launcher/{ => src/main/docker}/Dockerfile (61%) create mode 100644 spring-cloud-stream-samples/docker-compose.yml diff --git a/spring-cloud-stream-module-launcher/README.md b/spring-cloud-stream-module-launcher/README.md index 24bac773b..701fd991d 100644 --- a/spring-cloud-stream-module-launcher/README.md +++ b/spring-cloud-stream-module-launcher/README.md @@ -13,7 +13,7 @@ mvn -s .settings.xml package cd .. ```` -2: start redis locally via `redis-server` (optionally start `redis-cli` and use the `MONITOR` command to watch activity) +2: start redis locally via `redis-server` or `docker-compose` (there's a `docker-compose.yml` in `spring-cloud-stream-samples`). Optionally start `redis-cli` and use the `MONITOR` command to watch activity. *NOTE:* redis.conf (on OSX it is found here: /usr/local/etc/redis.conf) may need to be updated to set the binding to an address other than 127.0.0.1 else the docker instances will fail to connect. For example: bind 0.0.0.0 @@ -38,7 +38,18 @@ The time messages will be emitted every 5 seconds. The console for the log modul ## Running with Docker -Run each module as a Docker process by passing environment variables for the module name as well as the host machine's IP address for the redis connection to be established within the container: +The easiest way to get a demo working is to use `docker-compose` (from this directory): + +``` +$ mvn package docker:build +$ docker-compose up +... +logsink_1 | 2015-08-11 08:25:49.909 INFO 1 --- [hannel-adapter1] o.s.cloud.stream.module.log.LogSink : Received: 2015-08-11 08:25:49 +logsink_1 | 2015-08-11 08:25:54.909 INFO 1 --- [hannel-adapter1] o.s.cloud.stream.module.log.Log +... +``` + +You can also run each module individually as a Docker process by passing environment variables for the module name as well as the host machine's IP address for the redis connection to be established within the container: ```` docker run -p 8080:8080 -e MODULES=org.springframework.cloud.stream.module:time-source:1.0.0.BUILD-SNAPSHOT -e SPRING_REDIS_HOST= springcloud/stream-module-launcher diff --git a/spring-cloud-stream-module-launcher/docker-compose.yml b/spring-cloud-stream-module-launcher/docker-compose.yml new file mode 100644 index 000000000..bf14d474d --- /dev/null +++ b/spring-cloud-stream-module-launcher/docker-compose.yml @@ -0,0 +1,19 @@ +redis: + image: redis + +timesource: + image: springcloud/stream-module-launcher + links: + - redis + environment: + SPRING_REDIS_HOST: redis + MODULES: org.springframework.cloud.stream.module:time-source:1.0.0.BUILD-SNAPSHOT + +logsink: + image: springcloud/stream-module-launcher + links: + - redis + environment: + SPRING_REDIS_HOST: redis + MODULES: org.springframework.cloud.stream.module:log-sink:1.0.0.BUILD-SNAPSHOT + \ No newline at end of file diff --git a/spring-cloud-stream-module-launcher/dockerize.sh b/spring-cloud-stream-module-launcher/dockerize.sh deleted file mode 100755 index eeda75c4a..000000000 --- a/spring-cloud-stream-module-launcher/dockerize.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -if [ ! -f "Dockerfile" ]; then - echo "Dockerfile not found" - exit 1 -fi - -if [ ! -f "target/spring-cloud-stream-module-launcher-1.0.0.BUILD-SNAPSHOT-exec.jar" ]; then - echo "JAR not available; run mvn package first" - exit 1 -fi - -docker build -t 192.168.59.103:5000/module-launcher . diff --git a/spring-cloud-stream-module-launcher/pom.xml b/spring-cloud-stream-module-launcher/pom.xml index cc2258252..fca9dcc7b 100644 --- a/spring-cloud-stream-module-launcher/pom.xml +++ b/spring-cloud-stream-module-launcher/pom.xml @@ -20,16 +20,19 @@ 1.0.2.v20150114 3.1.0 1.57 + springcloud + stream-module-launcher - org.springframework - spring-core + org.springframework.boot + spring-boot-starter-actuator org.springframework.boot - spring-boot-starter-actuator + spring-boot-configuration-processor + true org.springframework.boot @@ -68,12 +71,6 @@ org.springframework.integration spring-integration-test - ${spring-integration.version} - test - - - ch.qos.logback - logback-classic test @@ -137,6 +134,22 @@ exec + + com.spotify + docker-maven-plugin + 0.2.3 + + ${docker.image.prefix}/${docker.image.name} + src/main/docker + + + / + ${project.build.directory} + ${project.build.finalName}-exec.jar + + + + diff --git a/spring-cloud-stream-module-launcher/Dockerfile b/spring-cloud-stream-module-launcher/src/main/docker/Dockerfile similarity index 61% rename from spring-cloud-stream-module-launcher/Dockerfile rename to spring-cloud-stream-module-launcher/src/main/docker/Dockerfile index aac2fce74..fb1f8f97e 100644 --- a/spring-cloud-stream-module-launcher/Dockerfile +++ b/spring-cloud-stream-module-launcher/src/main/docker/Dockerfile @@ -1,5 +1,5 @@ FROM java:8 VOLUME /tmp -ADD target/spring-cloud-stream-module-launcher-1.0.0.BUILD-SNAPSHOT-exec.jar module-launcher.jar +ADD *-exec.jar module-launcher.jar RUN bash -c 'touch /module-launcher.jar' ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/module-launcher.jar"] diff --git a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/boot/loader/ModuleJarLauncher.java b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/boot/loader/ModuleJarLauncher.java index b3ae1f658..6970b5dc9 100644 --- a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/boot/loader/ModuleJarLauncher.java +++ b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/boot/loader/ModuleJarLauncher.java @@ -18,11 +18,7 @@ package org.springframework.boot.loader; import java.lang.reflect.Method; import java.net.URL; -import java.net.URLClassLoader; -import java.util.Collections; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import org.springframework.boot.loader.archive.Archive; import org.springframework.boot.loader.util.AsciiBytes; @@ -30,8 +26,8 @@ import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; /** - * A (possibly temporary) alternative to {@link JarLauncher} that provides a - * public {@link #launch(String[])} method. + * A (possibly temporary) alternative to {@link JarLauncher} that provides a public + * {@link #launch(String[])} method. * * @author Mark Fisher * @author Marius Bogoevici @@ -60,14 +56,19 @@ public class ModuleJarLauncher extends ExecutableArchiveLauncher { } @Override - protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception { - try { - // disable JVM-wide registration of TomcatURLStreamHandlerFactory - Class streamHandlerFactoryClass = ClassUtils.forName("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory", classLoader); - Method disable = ReflectionUtils.findMethod(streamHandlerFactoryClass, "disable"); - ReflectionUtils.invokeMethod(disable, null); - } catch (ClassNotFoundException e) { - // ignore + protected void launch(String[] args, String mainClass, ClassLoader classLoader) + throws Exception { + if (ClassUtils.isPresent( + "org.apache.catalina.webresources.TomcatURLStreamHandlerFactory", + classLoader)) { + // Ensure the method is invoked on a class that is loaded by the provided + // class loader (not the current context class loader): + Method method = ReflectionUtils + .findMethod( + classLoader + .loadClass("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory"), + "disable"); + ReflectionUtils.invokeMethod(method, null); } super.launch(args, mainClass, classLoader); } diff --git a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherApplication.java b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherApplication.java index 19450b92c..0634e41e7 100644 --- a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherApplication.java +++ b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherApplication.java @@ -16,33 +16,23 @@ package org.springframework.cloud.stream.module.launcher; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; /** - * Bootstrap for launching one or more modules, provided via the "modules" system property or "MODULES" environment variable as a comma-delimited list, with the arguments provided at - * launch. + * Bootstrap for launching one or more modules, provided via the "modules" system property + * or "MODULES" environment variable as a comma-delimited list, with the arguments + * provided at launch. * - * @see ModuleLauncher#launch(String[], String[]) for module and argument structure and format + * @see ModuleLauncher#launch(String[], String[]) for module and argument structure and + * format * * @author Marius Bogoevici */ @SpringBootApplication -@ComponentScan(basePackageClasses = ModuleLauncherApplication.class) public class ModuleLauncherApplication { - private static final Log log = LogFactory.getLog(ModuleLauncherApplication.class); - public static void main(String[] args) throws Exception { - try { - SpringApplication.run(ModuleLauncherApplication.class, args); - } - catch (Exception e) { - log.error("Failed to launch module ", e); - } + SpringApplication.run(ModuleLauncherApplication.class, args); } } diff --git a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherConfiguration.java b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherConfiguration.java index 828cf2c91..63c99b29f 100644 --- a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherConfiguration.java +++ b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherConfiguration.java @@ -19,11 +19,6 @@ package org.springframework.cloud.stream.module.launcher; import java.io.File; import java.util.Collections; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.ApplicationRunner; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.stream.module.resolver.AetherModuleResolver; @@ -36,10 +31,11 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @ConfigurationProperties +// TODO: use a prefix public class ModuleLauncherConfiguration { - public static final String DEFAULT_LOCAL_REPO = - System.getProperty("user.home") + File.separator + ".m2" + File.separator + "repository"; + public static final String DEFAULT_LOCAL_REPO = System.getProperty("user.home") + + File.separator + ".m2" + File.separator + "repository"; public static final String DEFAULT_REMOTE_REPO = "https://repo.spring.io/libs-snapshot"; @@ -61,7 +57,8 @@ public class ModuleLauncherConfiguration { @Bean @ConditionalOnMissingBean(ModuleResolver.class) public ModuleResolver moduleResolver() { - return new AetherModuleResolver(localRepository, Collections.singletonMap("remoteRepository", remoteRepository)); + return new AetherModuleResolver(this.localRepository, Collections.singletonMap( + "remoteRepository", this.remoteRepository)); } @Bean diff --git a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherRunner.java b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherRunner.java index a18d8c560..7ed9152ae 100644 --- a/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherRunner.java +++ b/spring-cloud-stream-module-launcher/src/main/java/org/springframework/cloud/stream/module/launcher/ModuleLauncherRunner.java @@ -18,8 +18,6 @@ package org.springframework.cloud.stream.module.launcher; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; @@ -34,6 +32,7 @@ import org.springframework.util.StringUtils; */ @Component @ConfigurationProperties +// TODO: use a prefix public class ModuleLauncherRunner implements ApplicationRunner, InitializingBean { private final static Log log = LogFactory.getLog(ModuleLauncherRunner.class); @@ -41,24 +40,27 @@ public class ModuleLauncherRunner implements ApplicationRunner, InitializingBean @Autowired private ModuleLauncher moduleLauncher; - private String modules; + private String[] modules; - public void setModules(String modules) { + public void setModules(String[] modules) { this.modules = modules; } @Override public void afterPropertiesSet() throws Exception { - Assert.hasText(modules, "A list of modules must be specified"); + Assert.notEmpty(this.modules, "A list of modules must be specified"); } @Override public void run(ApplicationArguments applicationArguments) throws Exception { - String[] launchedModules = modules.split(","); + String[] launchedModules = this.modules; if (log.isInfoEnabled()) { - log.info("Launching: " + modules + " with arguments: " - + StringUtils.arrayToCommaDelimitedString(applicationArguments.getSourceArgs())); + log.info("Launching: " + + StringUtils.arrayToCommaDelimitedString(this.modules) + + " with arguments: " + + StringUtils.arrayToCommaDelimitedString(applicationArguments + .getSourceArgs())); } - moduleLauncher.launch(launchedModules, applicationArguments.getSourceArgs()); + this.moduleLauncher.launch(launchedModules, applicationArguments.getSourceArgs()); } } diff --git a/spring-cloud-stream-samples/docker-compose.yml b/spring-cloud-stream-samples/docker-compose.yml new file mode 100644 index 000000000..e5a62d0ef --- /dev/null +++ b/spring-cloud-stream-samples/docker-compose.yml @@ -0,0 +1,4 @@ +redis: + image: redis + ports: + - "6379:6379"