mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
INFRA-803 Rebuild Docker image tasks (#6804)
This commit is contained in:
parent
02018b75e9
commit
734d35b719
@ -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
11
buildSrc/build.gradle
Normal 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
|
||||
}
|
@ -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)}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
37
docker/README.md
Normal 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
|
||||
```
|
||||
|
||||
|
@ -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())
|
||||
}
|
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user