INFRA-803 Rebuild Docker image tasks (#6804)

This commit is contained in:
Walter Oggioni 2020-11-20 11:21:53 +01:00 committed by GitHub
parent 02018b75e9
commit 734d35b719
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 546 additions and 73 deletions

View File

@ -127,6 +127,7 @@ buildscript {
ext.commons_io_version = '2.6'
ext.controlsfx_version = '8.40.15'
ext.detekt_version = constants.getProperty('detektVersion')
ext.docker_java_version = constants.getProperty("dockerJavaVersion")
if (JavaVersion.current().isJava8()) {
ext.fontawesomefx_commons_version = '8.15'
ext.fontawesomefx_fontawesome_version = '4.7.0-5'

11
buildSrc/build.gradle Normal file
View File

@ -0,0 +1,11 @@
Properties constants = new Properties()
file("$rootDir/../constants.properties").withInputStream { constants.load(it) }
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.github.docker-java', name: 'docker-java', version: constants.dockerJavaVersion
compile group: 'com.github.docker-java', name: 'docker-java-transport-httpclient5', version: constants.dockerJavaVersion
}

View File

@ -0,0 +1,251 @@
package net.corda.build.docker
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.ObjectWriter
import com.fasterxml.jackson.databind.SerializationFeature
import com.github.dockerjava.api.DockerClient
import com.github.dockerjava.api.async.ResultCallback
import com.github.dockerjava.api.command.BuildImageResultCallback
import com.github.dockerjava.api.model.BuildResponseItem
import com.github.dockerjava.api.model.Identifier
import com.github.dockerjava.api.model.PushResponseItem
import com.github.dockerjava.api.model.Repository
import com.github.dockerjava.api.model.ResponseItem
import com.github.dockerjava.core.DefaultDockerClientConfig
import com.github.dockerjava.core.DockerClientBuilder
import com.github.dockerjava.core.DockerClientConfig
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient
import com.github.dockerjava.transport.DockerHttpClient
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.logging.Logger
import java.util.function.Consumer
import java.util.stream.Collectors
import java.util.stream.Stream
class ObjectInputStreamWithCustomClassLoader extends ObjectInputStream {
private ClassLoader classLoader
ObjectInputStreamWithCustomClassLoader(InputStream ins, ClassLoader classLoader) {
super(ins)
this.classLoader = classLoader
}
protected Class<?> resolveClass(ObjectStreamClass desc) {
return Class.forName(desc.getName(), false, classLoader)
}
}
class DockerError extends GradleException {
Integer code
String msg
@Override
String toString() {
return "Docker error${" " + code ?: ""}: $msg"
}
}
@CompileStatic
class DockerImage implements Serializable {
String id
File baseDir
Object dockerFile
String destination
Set<Identifier> tags = new HashSet<>()
private void writeObject(ObjectOutputStream oos) {
oos.writeObject(id)
oos.writeObject(baseDir)
oos.writeObject(dockerFile)
oos.writeObject(destination)
oos.writeInt(tags.size())
for(Identifier identifier in tags) {
oos.writeObject(identifier.repository)
oos.writeObject(identifier.tag.orElse(null))
}
}
private void readObject(ObjectInputStream ois) {
id = ois.readObject() as String
baseDir = ois.readObject() as File
dockerFile = ois.readObject()
destination = ois.readObject()
int len = ois.readInt()
Set<Identifier> identifiers = new HashSet<>()
for(int i in 0..<len) {
Repository repository = ois.readObject() as Repository
String tag = ois.readObject()
identifiers.add(new Identifier(repository, tag))
}
tags = Collections.unmodifiableSet(identifiers)
}
}
@PackageScope
class BuildDockerImageCallback extends BuildImageResultCallback {
private static final ObjectMapper objectMapper = new ObjectMapper()
private static final ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter()
.with(SerializationFeature.INDENT_OUTPUT)
private final Logger logger
BuildDockerImageCallback(Logger logger) {
this.logger = logger
}
@Override
void onNext(BuildResponseItem buildResponseItem) {
super.onNext(buildResponseItem)
if (buildResponseItem.errorIndicated) {
ResponseItem.ErrorDetail errorDetail = buildResponseItem.errorDetail
throw new DockerError(code : errorDetail.code, msg: errorDetail.message)
} else if(buildResponseItem.stream) {
String stream = buildResponseItem.stream
int sz = stream.size()
String msg
if (sz > 1) {
msg = stream.substring(0, sz - 1)
} else {
msg = null
}
if(msg) {
logger.info(buildResponseItem.stream.substring(0))
}
}
}
}
class DockerUtils {
@CompileStatic
static DockerClient fromConfig(DockerClientConfig cfg) {
DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
.dockerHost(cfg.dockerHost)
.sslConfig(cfg.SSLConfig)
.build()
return DockerClientBuilder.getInstance(cfg)
.withDockerHttpClient(httpClient)
.build()
}
@CompileStatic
static identifier2string(Identifier identifier) {
return identifier.repository.name + identifier.tag.map { ":" + it}.orElse("")
}
@CompileStatic
static DefaultDockerClientConfig.Builder dockerClientConfigBuilder() {
def builder = DefaultDockerClientConfig.createDefaultConfigBuilder()
if(System.getProperty('os.name')?.startsWith('Windows')) {
builder.withDockerHost("npipe:////./pipe/docker_engine")
}
return builder
}
@CompileStatic
static def buildImage(Project project, DockerClient dockerClient, DockerImage img) {
BuildDockerImageCallback callback = new BuildDockerImageCallback(project.logger)
File dockerFile
switch(img.dockerFile) {
case String:
def candidate = new File(img.dockerFile as String)
if(candidate.isAbsolute()) {
dockerFile = candidate
} else {
dockerFile = new File(img.baseDir, img.dockerFile as String)
}
break
case File:
dockerFile = img.dockerFile as File
break
case null:
dockerFile = new File(img.baseDir, "Dockerfile")
break
default:
throw new IllegalArgumentException("Unsupported object type for 'dockerFile': ${img.dockerFile.getClass().name}")
}
project.logger.info("Building image from ${img.baseDir.absolutePath} using Dockerfile: ${dockerFile}")
dockerClient.buildImageCmd(dockerFile)
.withTags(img.tags.collect { Identifier identifier ->
identifier.repository.name + identifier.tag.map { ':' + it}.orElse('')
}.toSet())
.exec(callback)
img.id = callback.awaitImageId()
}
@CompileStatic
static def buildImages(Project project, Iterable<DockerImage> images) {
DockerClientConfig cfg = dockerClientConfigBuilder().build()
DockerClient dockerClient = fromConfig(cfg)
images.each { buildImage(project, dockerClient, it) }
}
@CompileStatic
static def pushImages(Project project, Stream<DockerImage> imageStream) {
def logger = project.logger
Map<String, List<DockerImage>> destinationMap = imageStream.collect(
Collectors.<DockerImage, String>groupingBy{ DockerImage img -> img.destination ?: "" })
for(def entry in destinationMap.entrySet()) {
def destination = entry.key
List<DockerImage> images = entry.value
def configBuilder = dockerClientConfigBuilder()
System.getenv('DOCKER_USERNAME')?.with {
configBuilder.withRegistryUsername(it)
}
System.getenv('DOCKER_PASSWORD')?.with {
configBuilder.withRegistryPassword(it)
}
if(destination) {
configBuilder.withRegistryUrl(destination)
}
DockerClientConfig cfg = configBuilder.build()
DockerClient dockerClient = fromConfig(cfg)
logger.info("Ready to push to push to ${cfg.registryUrl}")
images.forEach(new Consumer<DockerImage>() {
@Override
void accept(DockerImage img) {
pushImage(project, dockerClient, img)
}
})
}
}
@CompileStatic
static def pushImage(Project project, DockerClient dockerClient, DockerImage image) {
def logger = project.logger
image.tags.each { identifier ->
ResultCallback<PushResponseItem> callback = new ResultCallback.Adapter<PushResponseItem>() {
@Override
void onNext(PushResponseItem item) {
if (item.errorIndicated) {
throw new DockerError(msg: item.errorDetail.message)
} else if (item.status == 'Preparing') {
logger.info("Preparing ${item.id}")
} else if (item.status == 'Waiting') {
logger.info("Waiting for ${item.id}")
} else if (item.status == 'Pushing') {
if (item.progressDetail) {
ResponseItem.ProgressDetail progressDetail = item.progressDetail
logger.debug("Pushing ${item.id}, progress ${progressDetail.current}/${progressDetail.total}")
}
} else if (item.status == 'Pushed') {
logger.info("Pushed ${item.id}")
}
}
}
dockerClient.pushImageCmd(identifier).exec(callback)
callback.awaitCompletion()
logger.info("Pushed ${identifier2string(identifier)}")
}
}
}

View File

@ -18,6 +18,7 @@ quasarVersion=0.7.13_r3
# Quasar version to use with Java 11:
quasarVersion11=0.8.1_r3
jdkClassifier11=jdk11
dockerJavaVersion=3.2.5
proguardVersion=6.1.1
bouncycastleVersion=1.66
classgraphVersion=4.8.90
@ -35,4 +36,3 @@ openSourceBranch=https://github.com/corda/corda/blob/release/os/4.4
openSourceSamplesBranch=https://github.com/corda/samples/blob/release-V4
jolokiaAgentVersion=1.6.1
detektVersion=1.0.1

37
docker/README.md Normal file
View File

@ -0,0 +1,37 @@
# Building docker images
There are 3 Gradle tasks dedicated to this:
- `buildDockerFolder` will simply create the build folder with all the dockerfiles and the required
artifacts (like the `corda.jar`, `config-exporter.jar`).
This is an internal task and doesn't need to be explicitly invoked.
- `buildDockerImage` will build a docker image a publish it in the local docker cache
- `pushDockerImage` will build a docker image and push it to a remote docker registry.
It is possible to override the docker registry URL for all images using the `--registry-url`
command-line parameter, otherwise each image will be pushed to its own preconfigured docker registry
as specified in the `net.corda.build.docker.DockerImage.destination` field.
The latter field is currently left as `null` for all image variants, which means they are pushed to
[docker hub](https://hub.docker.com).
All 3 tasks use the command-line parameter `--image` to specify which image variant will be built
(it can be used multiple times to build multiple images).
To get a list of all supported variants simply launch with a random string:
```
gradlew docker:buildDockerImage --image NON_EXISTENT_IMAGE_VARIANT
```
results in
```
> Cannot convert string value 'NON_EXISTENT_IMAGE_VARIANT' to an enum value of type 'ImageVariant' (valid case insensitive values: UBUNTU_ZULU, UBUNTU_ZULU_11, AL_CORRETTO, OFFICIAL)
```
If no image variant is specified, all available image variants will be built.
The default repository for all images is `corda/corda` and you will need official R3 credentials
for Artifactory to push there. [Ross Nicoll](ross.nicoll@r3.com) (or other Artifactory administrators) can assist with this if needed,
otherwise you can override the repository name using the `docker.image.repository` Gradle property.
e.g.
```
gradlew docker:pushDockerImage -Pdocker.image.repository=MyOwnRepository/test --image OFFICIAL --registry-url registry.hub.docker.com
```

View File

@ -1,14 +1,20 @@
evaluationDependsOn(":node:capsule")
import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
import com.bmuschko.gradle.docker.tasks.image.DockerPushImage
import com.github.dockerjava.api.model.Identifier
import net.corda.build.docker.DockerImage
import net.corda.build.docker.DockerUtils
import net.corda.build.docker.ObjectInputStreamWithCustomClassLoader
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.stream.Collectors
import java.util.stream.Stream
apply plugin: 'kotlin'
apply plugin: 'application'
apply plugin: 'com.bmuschko.docker-remote-api'
// We need to set mainClassName before applying the shadow plugin.
mainClassName = 'net.corda.core.ConfigExporterMain'
@ -26,77 +32,239 @@ shadowJar {
exclude '**/Log4j2Plugins.dat'
}
docker{
registryCredentials {
url = System.env.DOCKER_URL ?: "hub.docker.com"
username = System.env.DOCKER_USERNAME
password = System.env.DOCKER_PASSWORD
enum ImageVariant {
UBUNTU_ZULU("zulu", "Dockerfile", "1.8"),
UBUNTU_ZULU_11("zulu", "Dockerfile11", "11"),
AL_CORRETTO("corretto", "DockerfileAL", "1.8"),
OFFICIAL(UBUNTU_ZULU)
String knownAs
String dockerFile
String javaVersion
String versionString(String baseTag, String version) {
return "${baseTag}-${knownAs}" +
(knownAs.isEmpty() ? "" : "-") +
"java${javaVersion}-" + version
}
ImageVariant(ImageVariant other) {
this.knownAs = other.knownAs
this.dockerFile = other.dockerFile
this.javaVersion = other.javaVersion
}
ImageVariant(String knownAs, String dockerFile, String javaVersion) {
this.knownAs = knownAs
this.dockerFile = dockerFile
this.javaVersion = javaVersion
}
static final String getRepository(Project project) {
return project.properties.getOrDefault("docker.image.repository", "corda/corda")
}
static private final String runTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
def getName(Project project) {
return versionString(getRepository(project), project.version.toString().toLowerCase())
}
Set<Identifier> buildTags(Project project) {
final String suffix = project.version.toString().toLowerCase().contains("snapshot") ? runTime : "RELEASE"
return [suffix, "latest"].stream().map {
toAppend -> "${getName(project)}:${toAppend}".toString()
}.map(Identifier.&fromCompoundString).collect(Collectors.toSet())
}
static Set<ImageVariant> toBeBuilt = Arrays.stream(values()).collect(Collectors.toSet())
}
class BuildDockerFolderTask extends DefaultTask {
@Option(option = "image", description = "Docker image variants that will be built")
void setVariants(List<ImageVariant> variants) {
ImageVariant.toBeBuilt = new HashSet<>(variants)
}
@OptionValues("image")
Collection<ImageVariant> allVariants() {
return EnumSet.allOf(ImageVariant.class)
}
@Input
Iterable<ImageVariant> variantsToBuild() {
return ImageVariant.toBeBuilt
}
@InputFiles
FileCollection getDockerBuildFiles() {
return project.fileTree("${project.projectDir}/src/docker/build")
}
@InputFiles
FileCollection getShellScripts() {
return project.fileTree("${project.projectDir}/src/bash")
}
@Lazy
private File cordaJar = project.findProject(":node:capsule").tasks.buildCordaJAR.outputs.files.singleFile
@Lazy
private File configExporter = project.tasks.shadowJar.outputs.files.singleFile
@Lazy
private File dbMigrator = project.findProject(":tools:dbmigration").tasks.shadowJar.outputs.files.singleFile
@InputFiles
private FileCollection getRequiredArtifacts() {
FileCollection res = project.tasks.shadowJar.outputs.files
def capsuleProject = project.findProject(":node:capsule")
def capsuleTaksOutput = capsuleProject.tasks.buildCordaJAR.outputs.files
res += capsuleTaksOutput
return res
}
@OutputFiles
FileCollection getDockerFiles() {
return project.objects.fileCollection().from(ImageVariant.toBeBuilt.stream().map {
new File(dockerBuildDir, it.dockerFile)
}.collect(Collectors.toList()))
}
@OutputDirectory
final File dockerBuildDir = project.file("${project.buildDir}/docker/build")
@TaskAction
def run() {
for(ImageVariant imageVariant : ImageVariant.toBeBuilt) {
def sourceFile = project.projectDir.toPath().resolve("src/docker/${imageVariant.dockerFile}")
def destinationFile = dockerBuildDir.toPath().resolve(imageVariant.dockerFile)
Files.copy(sourceFile, destinationFile, StandardCopyOption.REPLACE_EXISTING)
}
Files.copy(cordaJar.toPath(), dockerBuildDir.toPath().resolve("corda.jar"), StandardCopyOption.REPLACE_EXISTING)
Files.copy(configExporter.toPath(), dockerBuildDir.toPath().resolve("config-exporter.jar"), StandardCopyOption.REPLACE_EXISTING)
["src/bash/run-corda.sh",
"src/config/starting-node.conf",
"src/bash/generate-config.sh"].forEach {
def source = project.file(it).toPath()
Files.copy(source, dockerBuildDir.toPath().resolve(source.fileName), StandardCopyOption.REPLACE_EXISTING)
}
}
}
final dockerTempDir = file("$buildDir/docker-temp")
task buildDockerFolder(type: Copy) {
into dockerTempDir
from "src/bash/run-corda.sh"
from(project(':node:capsule').tasks.buildCordaJAR) {
rename 'corda-(.*)', 'corda.jar'
class BuildDockerImageTask extends DefaultTask {
@Option(option = "image", description = "Docker image variants that will be built")
void setVariants(List<ImageVariant> variants) {
ImageVariant.toBeBuilt = new HashSet<>(variants)
}
from(shadowJar) {
rename 'config-exporter-(.*).jar', 'config-exporter.jar'
@OptionValues("image")
Collection<ImageVariant> allVariants() {
return EnumSet.allOf(ImageVariant.class)
}
final File dockerBuildDir = project.file("${project.buildDir}/docker/build")
@OutputDirectory
final File dockerBuiltImageDir = project.file("${project.buildDir}/docker/images")
@Input
String getRepository() {
return ImageVariant.getRepository(project)
}
@InputFiles
FileCollection dockerFiles
private Map<ImageVariant, DockerImage> images
@OutputFiles
FileCollection getImageFiles() {
return project.objects.fileCollection().from(ImageVariant.toBeBuilt.stream().map { imageVariant ->
dockerBuiltImageDir.toPath().resolve(imageVariant.toString()).toFile()
}.collect(Collectors.toList()))
}
void from(BuildDockerFolderTask buildDockerFolderTask) {
dockerFiles = buildDockerFolderTask.outputs.files
}
@Override
Task configure(Closure closure) {
return super.configure(closure)
}
@TaskAction
def run() {
this.@images = ImageVariant.toBeBuilt.stream().map { imageVariant ->
new Tuple2<>(imageVariant, new DockerImage(
baseDir: dockerBuildDir,
dockerFile: imageVariant.dockerFile,
tags: imageVariant.buildTags(project)))
}.collect(Collectors.toMap({it.first}, {it.second}))
DockerUtils.buildImages(project, this.@images.values())
images.entrySet().forEach { entry ->
ImageVariant imageVariant = entry.key
def destinationFile = dockerBuiltImageDir.toPath().resolve(imageVariant.toString())
new ObjectOutputStream(Files.newOutputStream(destinationFile)).withStream {
it.writeObject(entry.value)
}
}
}
from "src/config/starting-node.conf"
from "src/bash/generate-config.sh"
from "src/docker/DockerfileAL"
from "src/docker/Dockerfile"
from "src/docker/Dockerfile11"
}
final String runTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
final String suffix = project.version.toString().toLowerCase().contains("snapshot") ? runTime : "RELEASE"
final zuluBuildTags = ["corda/corda-zulu-java${JavaVersion.current()}-${project.version.toString().toLowerCase()}:${suffix}", "corda/corda-zulu-java${JavaVersion.current()}-${project.version.toString().toLowerCase()}:latest"]
final correttoBuildTags = ["corda/corda-corretto-java${JavaVersion.current()}-${project.version.toString().toLowerCase()}:${suffix}", "corda/corda-corretto-java${JavaVersion.current()}-${project.version.toString().toLowerCase()}:latest"]
class PushDockerImage extends DefaultTask {
@Option(option = "image", description = "Docker image variants that will be built")
void setVariants(List<ImageVariant> variants) {
ImageVariant.toBeBuilt = new HashSet<>(variants)
}
task buildOfficialZuluDockerImage(type: DockerBuildImage, dependsOn: [buildDockerFolder]) {
inputDir = dockerTempDir
tags = zuluBuildTags
dockerFile = new File(dockerTempDir, "Dockerfile")
@OptionValues("image")
Collection<ImageVariant> allVariants() {
return EnumSet.allOf(ImageVariant.class)
}
private static String registryURL
@Option(option = "registry-url", description = "Docker image registry where images will be pushed, defaults to DockerHub")
void setRegistryURL(String registryURL) {
PushDockerImage.registryURL = registryURL
}
@InputFiles
FileCollection imageFiles
def from(BuildDockerImageTask buildDockerImageTask) {
imageFiles = buildDockerImageTask.outputs.files
}
@TaskAction
def run() {
def classLoader = DockerImage.class.classLoader
Stream<DockerImage> imageStream = imageFiles.files.stream().filter{
it.isFile()
}.map {
new ObjectInputStreamWithCustomClassLoader(Files.newInputStream(it.toPath()), classLoader).withStream {
DockerImage image = it.readObject()
if(PushDockerImage.registryURL) {
image.destination = PushDockerImage.registryURL
}
image
}
}
DockerUtils.pushImages(project, imageStream)
}
}
task buildOfficialZuluJDK11DockerImage(type: DockerBuildImage, dependsOn: [buildDockerFolder]) {
inputDir = dockerTempDir
tags = zuluBuildTags
dockerFile = new File(dockerTempDir, "Dockerfile11")
def buildDockerFolderTask = tasks.register("buildDockerFolder", BuildDockerFolderTask)
def buildDockerImageTask = tasks.register("buildDockerImage", BuildDockerImageTask) {
from(buildDockerFolderTask.get())
}
task buildOfficialCorrettoDockerImage(type: DockerBuildImage, dependsOn: [buildDockerFolder]) {
inputDir = dockerTempDir
tags = correttoBuildTags
dockerFile = new File(dockerTempDir, "DockerfileAL")
}
task pushZuluTimeStampedTag('type': DockerPushImage, dependsOn: [buildOfficialZuluDockerImage]){
imageName = zuluBuildTags[0]
}
task pushZuluLatestTag('type': DockerPushImage, dependsOn: [buildOfficialZuluDockerImage]){
imageName = zuluBuildTags[1]
}
task pushZulu11TimeStampedTag('type': DockerPushImage, dependsOn: [buildOfficialZuluJDK11DockerImage]){
imageName = zuluBuildTags[0]
}
task pushZulu11LatestTag('type': DockerPushImage, dependsOn: [buildOfficialZuluJDK11DockerImage]){
imageName = zuluBuildTags[1]
}
task pushCorrettoTimeStampedTag('type': DockerPushImage, dependsOn: [buildOfficialCorrettoDockerImage]){
imageName = correttoBuildTags[0]
}
task pushCorrettoLatestTag('type': DockerPushImage, dependsOn: [buildOfficialCorrettoDockerImage]){
imageName = correttoBuildTags[1]
}
task pushOfficialImages(dependsOn: [pushZuluTimeStampedTag, pushZuluLatestTag, pushCorrettoTimeStampedTag, pushCorrettoLatestTag])
tasks.register("pushDockerImage", PushDockerImage) {
from(buildDockerImageTask.get())
}

View File

@ -41,7 +41,7 @@ configurations {
dependencies {
compile "com.microsoft.azure:azure:1.22.0"
compile "com.github.docker-java:docker-java:3.0.6"
compile "com.github.docker-java:docker-java:$docker_java_version"
testCompile "org.jetbrains.kotlin:kotlin-test"
testCompile "org.jetbrains.kotlin:kotlin-test-junit"

View File

@ -45,14 +45,16 @@ class DockerInstantiator(private val volume: LocalVolume,
val ports = (portsToOpen + Constants.NODE_RPC_ADMIN_PORT).map { ExposedPort.tcp(it) }
.map { PortBinding(null, it) }
.let { Ports(*it.toTypedArray()) }
val hostConfig = HostConfig()
.withBinds(Bind(volume.getPath(), nodeInfosVolume))
.withPortBindings(ports)
.withPublishAllPorts(true)
.withNetworkMode(networkId)
val createCmd = localClient.createContainerCmd(imageId)
.withName(instanceName)
.withVolumes(nodeInfosVolume)
.withBinds(Bind(volume.getPath(), nodeInfosVolume))
.withPortBindings(ports)
.withHostConfig(hostConfig)
.withExposedPorts(ports.bindings.map { it.key })
.withPublishAllPorts(true)
.withNetworkMode(networkId)
.withEnv(convertedEnv).exec()
localClient.startContainerCmd(createCmd.id).exec()

View File

@ -16,7 +16,10 @@ object DockerUtils {
fun createLocalDockerClient(): DockerClient {
return if (SystemUtils.IS_OS_WINDOWS) {
DockerClientBuilder.getInstance("tcp://127.0.0.1:2375").build()
val cfg = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost("tcp://127.0.0.1:2375")
.build()
DockerClientBuilder.getInstance(cfg).build()
} else {
DockerClientBuilder.getInstance().build()
}

View File

@ -1,8 +1,8 @@
package net.corda.networkbuilder.nodes
import com.github.dockerjava.api.model.BuildResponseItem
import com.github.dockerjava.core.async.ResultCallbackTemplate
import com.github.dockerjava.core.command.BuildImageResultCallback
import com.github.dockerjava.api.async.ResultCallbackTemplate
import com.github.dockerjava.api.command.BuildImageResultCallback
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigValueFactory