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=<path_to_repo>. Removes some of the hard-coded
host names and stuff that came with the old version.
This commit is contained in:
Dave Syer
2015-08-11 09:30:02 +01:00
parent 818ad6e3e8
commit e81ed1eace
10 changed files with 96 additions and 72 deletions

View File

@@ -13,7 +13,7 @@ mvn -s .settings.xml package
cd .. 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 *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 ## 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=<host.ip> springcloud/stream-module-launcher docker run -p 8080:8080 -e MODULES=org.springframework.cloud.stream.module:time-source:1.0.0.BUILD-SNAPSHOT -e SPRING_REDIS_HOST=<host.ip> springcloud/stream-module-launcher

View File

@@ -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

View File

@@ -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 .

View File

@@ -20,16 +20,19 @@
<aether.version>1.0.2.v20150114</aether.version> <aether.version>1.0.2.v20150114</aether.version>
<maven.version>3.1.0</maven.version> <maven.version>3.1.0</maven.version>
<wiremock.version>1.57</wiremock.version> <wiremock.version>1.57</wiremock.version>
<docker.image.prefix>springcloud</docker.image.prefix>
<docker.image.name>stream-module-launcher</docker.image.name>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-core</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@@ -68,12 +71,6 @@
<dependency> <dependency>
<groupId>org.springframework.integration</groupId> <groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-test</artifactId> <artifactId>spring-integration-test</artifactId>
<version>${spring-integration.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -137,6 +134,22 @@
<classifier>exec</classifier> <classifier>exec</classifier>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.2.3</version>
<configuration>
<imageName>${docker.image.prefix}/${docker.image.name}</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}-exec.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@@ -1,5 +1,5 @@
FROM java:8 FROM java:8
VOLUME /tmp 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' RUN bash -c 'touch /module-launcher.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/module-launcher.jar"] ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/module-launcher.jar"]

View File

@@ -18,11 +18,7 @@ package org.springframework.boot.loader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.springframework.boot.loader.archive.Archive; import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.util.AsciiBytes; import org.springframework.boot.loader.util.AsciiBytes;
@@ -30,8 +26,8 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
/** /**
* A (possibly temporary) alternative to {@link JarLauncher} that provides a * A (possibly temporary) alternative to {@link JarLauncher} that provides a public
* public {@link #launch(String[])} method. * {@link #launch(String[])} method.
* *
* @author Mark Fisher * @author Mark Fisher
* @author Marius Bogoevici * @author Marius Bogoevici
@@ -60,14 +56,19 @@ public class ModuleJarLauncher extends ExecutableArchiveLauncher {
} }
@Override @Override
protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception { protected void launch(String[] args, String mainClass, ClassLoader classLoader)
try { throws Exception {
// disable JVM-wide registration of TomcatURLStreamHandlerFactory if (ClassUtils.isPresent(
Class<?> streamHandlerFactoryClass = ClassUtils.forName("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory", classLoader); "org.apache.catalina.webresources.TomcatURLStreamHandlerFactory",
Method disable = ReflectionUtils.findMethod(streamHandlerFactoryClass, "disable"); classLoader)) {
ReflectionUtils.invokeMethod(disable, null); // Ensure the method is invoked on a class that is loaded by the provided
} catch (ClassNotFoundException e) { // class loader (not the current context class loader):
// ignore Method method = ReflectionUtils
.findMethod(
classLoader
.loadClass("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory"),
"disable");
ReflectionUtils.invokeMethod(method, null);
} }
super.launch(args, mainClass, classLoader); super.launch(args, mainClass, classLoader);
} }

View File

@@ -16,33 +16,23 @@
package org.springframework.cloud.stream.module.launcher; 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.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; 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 * Bootstrap for launching one or more modules, provided via the "modules" system property
* launch. * 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 * @author Marius Bogoevici
*/ */
@SpringBootApplication @SpringBootApplication
@ComponentScan(basePackageClasses = ModuleLauncherApplication.class)
public class ModuleLauncherApplication { public class ModuleLauncherApplication {
private static final Log log = LogFactory.getLog(ModuleLauncherApplication.class);
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
try { SpringApplication.run(ModuleLauncherApplication.class, args);
SpringApplication.run(ModuleLauncherApplication.class, args);
}
catch (Exception e) {
log.error("Failed to launch module ", e);
}
} }
} }

View File

@@ -19,11 +19,6 @@ package org.springframework.cloud.stream.module.launcher;
import java.io.File; import java.io.File;
import java.util.Collections; 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.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.stream.module.resolver.AetherModuleResolver; import org.springframework.cloud.stream.module.resolver.AetherModuleResolver;
@@ -36,10 +31,11 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration @Configuration
@ConfigurationProperties @ConfigurationProperties
// TODO: use a prefix
public class ModuleLauncherConfiguration { public class ModuleLauncherConfiguration {
public static final String DEFAULT_LOCAL_REPO = public static final String DEFAULT_LOCAL_REPO = System.getProperty("user.home")
System.getProperty("user.home") + File.separator + ".m2" + File.separator + "repository"; + File.separator + ".m2" + File.separator + "repository";
public static final String DEFAULT_REMOTE_REPO = "https://repo.spring.io/libs-snapshot"; public static final String DEFAULT_REMOTE_REPO = "https://repo.spring.io/libs-snapshot";
@@ -61,7 +57,8 @@ public class ModuleLauncherConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(ModuleResolver.class) @ConditionalOnMissingBean(ModuleResolver.class)
public ModuleResolver moduleResolver() { public ModuleResolver moduleResolver() {
return new AetherModuleResolver(localRepository, Collections.singletonMap("remoteRepository", remoteRepository)); return new AetherModuleResolver(this.localRepository, Collections.singletonMap(
"remoteRepository", this.remoteRepository));
} }
@Bean @Bean

View File

@@ -18,8 +18,6 @@ package org.springframework.cloud.stream.module.launcher;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
@@ -34,6 +32,7 @@ import org.springframework.util.StringUtils;
*/ */
@Component @Component
@ConfigurationProperties @ConfigurationProperties
// TODO: use a prefix
public class ModuleLauncherRunner implements ApplicationRunner, InitializingBean { public class ModuleLauncherRunner implements ApplicationRunner, InitializingBean {
private final static Log log = LogFactory.getLog(ModuleLauncherRunner.class); private final static Log log = LogFactory.getLog(ModuleLauncherRunner.class);
@@ -41,24 +40,27 @@ public class ModuleLauncherRunner implements ApplicationRunner, InitializingBean
@Autowired @Autowired
private ModuleLauncher moduleLauncher; private ModuleLauncher moduleLauncher;
private String modules; private String[] modules;
public void setModules(String modules) { public void setModules(String[] modules) {
this.modules = modules; this.modules = modules;
} }
@Override @Override
public void afterPropertiesSet() throws Exception { 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 @Override
public void run(ApplicationArguments applicationArguments) throws Exception { public void run(ApplicationArguments applicationArguments) throws Exception {
String[] launchedModules = modules.split(","); String[] launchedModules = this.modules;
if (log.isInfoEnabled()) { if (log.isInfoEnabled()) {
log.info("Launching: " + modules + " with arguments: " log.info("Launching: "
+ StringUtils.arrayToCommaDelimitedString(applicationArguments.getSourceArgs())); + StringUtils.arrayToCommaDelimitedString(this.modules)
+ " with arguments: "
+ StringUtils.arrayToCommaDelimitedString(applicationArguments
.getSourceArgs()));
} }
moduleLauncher.launch(launchedModules, applicationArguments.getSourceArgs()); this.moduleLauncher.launch(launchedModules, applicationArguments.getSourceArgs());
} }
} }

View File

@@ -0,0 +1,4 @@
redis:
image: redis
ports:
- "6379:6379"