diff --git a/bom/deployment/pom.xml b/bom/deployment/pom.xml index 7d81fe6ee..0c4ccca63 100644 --- a/bom/deployment/pom.xml +++ b/bom/deployment/pom.xml @@ -473,12 +473,22 @@ io.quarkus - quarkus-container-deployment + quarkus-container-image-deployment ${project.version} io.quarkus - quarkus-container-spi + quarkus-container-image-spi + ${project.version} + + + io.quarkus + quarkus-container-image-docker-deployment + ${project.version} + + + io.quarkus + quarkus-container-image-jib-deployment ${project.version} diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml index 0bc3c902a..15de4cc01 100644 --- a/bom/runtime/pom.xml +++ b/bom/runtime/pom.xml @@ -185,6 +185,8 @@ 1.1.1 2.5.2 2.2.0 + 0.13.0 + 1.34.0 @@ -713,7 +715,12 @@ io.quarkus - quarkus-container + quarkus-container-image-docker + ${project.version} + + + io.quarkus + quarkus-container-image-jib ${project.version} @@ -2857,6 +2864,24 @@ quarkus-banner ${project.version} + + + + com.google.cloud.tools + jib-core + ${jib-core.version} + + + commons-logging + commons-logging + + + + + com.google.http-client + google-http-client + ${google-http-client.version} + diff --git a/extensions/container-image/container-image-docker/deployment/pom.xml b/extensions/container-image/container-image-docker/deployment/pom.xml new file mode 100644 index 000000000..a19f8d401 --- /dev/null +++ b/extensions/container-image/container-image-docker/deployment/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + io.quarkus + quarkus-container-image-docker-parent + 999-SNAPSHOT + + + quarkus-container-image-docker-deployment + Quarkus - Container - Image - Docker - Deployment + + + + io.quarkus + quarkus-container-image-docker + + + io.quarkus + quarkus-container-image-deployment + + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + + \ No newline at end of file diff --git a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerBuild.java b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerBuild.java similarity index 84% rename from extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerBuild.java rename to extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerBuild.java index a33ad865d..72eaa49ec 100644 --- a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerBuild.java +++ b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerBuild.java @@ -1,5 +1,5 @@ -package io.quarkus.container.deployment; +package io.quarkus.container.image.docker.deployment; import java.io.BufferedReader; import java.io.File; @@ -11,6 +11,7 @@ import java.util.function.Function; import org.jboss.logging.Logger; +import io.quarkus.container.image.deployment.ContainerImageConfig; import io.quarkus.deployment.util.ExecUtil; public class DockerBuild implements BooleanSupplier { @@ -18,15 +19,15 @@ public class DockerBuild implements BooleanSupplier { private static final Logger LOGGER = Logger.getLogger(DockerBuild.class.getName()); private static boolean daemonFound = false; - private final ContainerConfig containerConfig; + private final ContainerImageConfig containerImageConfig; - DockerBuild(ContainerConfig containerConfig) { - this.containerConfig = containerConfig; + public DockerBuild(ContainerImageConfig containerImageConfig) { + this.containerImageConfig = containerImageConfig; } @Override public boolean getAsBoolean() { - if (containerConfig.build) { + if (containerImageConfig.execution != ContainerImageConfig.Execution.NONE) { //No need to perform the check multiple times. if (daemonFound) { return true; diff --git a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerConfig.java b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerConfig.java similarity index 94% rename from extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerConfig.java rename to extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerConfig.java index b3ae56e0d..d4f177993 100644 --- a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerConfig.java +++ b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerConfig.java @@ -1,4 +1,4 @@ -package io.quarkus.container.deployment; +package io.quarkus.container.image.docker.deployment; import java.util.Optional; diff --git a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerBuildStep.java b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerProcessor.java similarity index 69% rename from extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerBuildStep.java rename to extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerProcessor.java index 6c02bf178..91470e818 100644 --- a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/DockerBuildStep.java +++ b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerProcessor.java @@ -1,5 +1,5 @@ -package io.quarkus.container.deployment; +package io.quarkus.container.image.docker.deployment; import java.io.BufferedReader; import java.io.IOException; @@ -11,20 +11,19 @@ import java.nio.file.Paths; import java.util.AbstractMap; import java.util.Collections; import java.util.Map; -import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; -import javax.inject.Inject; - import org.jboss.logging.Logger; -import io.quarkus.container.deployment.util.ImageUtil; +import io.quarkus.container.image.deployment.ContainerImageConfig; +import io.quarkus.container.image.deployment.util.ImageUtil; +import io.quarkus.container.image.deployment.util.NativeBinaryUtil; import io.quarkus.container.spi.ContainerImageBuildItem; import io.quarkus.container.spi.ContainerImageResultBuildItem; +import io.quarkus.deployment.IsNormal; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.builditem.ApplicationInfoBuildItem; import io.quarkus.deployment.pkg.builditem.ArtifactResultBuildItem; import io.quarkus.deployment.pkg.builditem.JarBuildItem; import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem; @@ -32,51 +31,85 @@ import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; import io.quarkus.deployment.pkg.steps.NativeBuild; import io.quarkus.deployment.util.ExecUtil; -public class DockerBuildStep { +public class DockerProcessor { - private static final Logger log = Logger.getLogger(DockerBuildStep.class); + private static final Logger log = Logger.getLogger(DockerProcessor.class); private static final String DOCKERFILE_JVM = "Dockerfile.jvm"; private static final String DOCKERFILE_NATIVE = "Dockerfile.native"; - @Inject - BuildProducer artifact; - - @BuildStep(onlyIf = DockerBuild.class, onlyIfNot = NativeBuild.class) - public ContainerImageResultBuildItem dockerBuildFromJar(DockerConfig dockerConfig, ApplicationInfoBuildItem app, + @BuildStep(onlyIf = { IsNormal.class, DockerBuild.class }, onlyIfNot = NativeBuild.class) + public void dockerBuildFromJar(DockerConfig dockerConfig, + ContainerImageConfig containerImageConfig, // TODO: use to check whether we need to also push to registry OutputTargetBuildItem out, - ContainerImageBuildItem containerImage, JarBuildItem jar) { + ContainerImageBuildItem containerImage, + BuildProducer artifactResultProducer, + BuildProducer containerImageResultProducer, + // used to ensure that the jar has been built + JarBuildItem jar) { + log.info("Building docker image for jar."); + + String image = containerImage.getImage(); + ImageIdReader reader = new ImageIdReader(); - buildContainerImage(dockerConfig, containerImage, out, reader, false); - artifact.produce(new ArtifactResultBuildItem(null, "jar-container", Collections.emptyMap())); - return new ContainerImageResultBuildItem(reader.getImageId(), ImageUtil.getRepository(containerImage.getImage()), - ImageUtil.getTag(containerImage.getImage())); + createContainerImage(containerImageConfig, dockerConfig, image, out, reader, false); + + artifactResultProducer.produce(new ArtifactResultBuildItem(null, "jar-container", Collections.emptyMap())); + containerImageResultProducer.produce( + new ContainerImageResultBuildItem(reader.getImageId(), ImageUtil.getRepository(image), + ImageUtil.getTag(image))); } - @BuildStep(onlyIf = { DockerBuild.class, NativeBuild.class }) - public ContainerImageResultBuildItem dockerBuildFromNativeImage(DockerConfig dockerConfig, ApplicationInfoBuildItem app, + @BuildStep(onlyIf = { IsNormal.class, DockerBuild.class, NativeBuild.class }) + public void dockerBuildFromNativeImage(DockerConfig dockerConfig, + ContainerImageConfig containerImageConfig, ContainerImageBuildItem containerImage, OutputTargetBuildItem out, - Optional dockerImage, + BuildProducer artifactResultProducer, + BuildProducer containerImageResultProducer, + // used to ensure that the native binary has been built NativeImageBuildItem nativeImage) { + + if (!NativeBinaryUtil.nativeIsLinuxBinary(nativeImage)) { + throw new RuntimeException( + "The native binary produced by the build is not a Linux binary and therefore cannot be used in a Linux container image. Consider adding \"quarkus.native.container-build=true\" to your configuration"); + } + log.info("Building docker image for native image."); + + String image = containerImage.getImage(); + ImageIdReader reader = new ImageIdReader(); - buildContainerImage(dockerConfig, containerImage, out, reader, true); - artifact.produce(new ArtifactResultBuildItem(null, "native-container", Collections.emptyMap())); - return new ContainerImageResultBuildItem(reader.getImageId(), ImageUtil.getRepository(containerImage.getImage()), - ImageUtil.getTag(containerImage.getImage())); + createContainerImage(containerImageConfig, dockerConfig, image, out, reader, true); + artifactResultProducer.produce(new ArtifactResultBuildItem(null, "native-container", Collections.emptyMap())); + containerImageResultProducer + .produce(new ContainerImageResultBuildItem(reader.getImageId(), ImageUtil.getRepository(image), + ImageUtil.getTag(image))); } - private void buildContainerImage(DockerConfig dockerConfig, ContainerImageBuildItem containerImage, + private void createContainerImage(ContainerImageConfig containerImageConfig, DockerConfig dockerConfig, String image, OutputTargetBuildItem out, ImageIdReader reader, boolean forNative) { + DockerfilePaths dockerfilePaths = getDockerfilePaths(dockerConfig, forNative, out); - ExecUtil.exec(out.getOutputDirectory().toFile(), - reader, - "docker", "build", - "-f", - dockerfilePaths.getDockerfilePath().toAbsolutePath().toString(), - "-t", containerImage.getImage(), - dockerfilePaths.getDockerExecutionPath().toAbsolutePath().toString()); + String[] buildArgs = { "build", "-f", dockerfilePaths.getDockerfilePath().toAbsolutePath().toString(), "-t", image, + dockerfilePaths.getDockerExecutionPath().toAbsolutePath().toString() }; + boolean buildSuccessful = ExecUtil.exec(out.getOutputDirectory().toFile(), reader, "docker", buildArgs); + if (!buildSuccessful) { + throw dockerException(buildArgs); + } + + if (containerImageConfig.execution == ContainerImageConfig.Execution.PUSH) { + String[] pushArgs = { "push", image }; + boolean pushSuccessful = ExecUtil.exec("docker", pushArgs); + if (!pushSuccessful) { + throw dockerException(pushArgs); + } + } + } + + private RuntimeException dockerException(String[] dockerArgs) { + return new RuntimeException( + "Execution of 'docker " + String.join(" ", dockerArgs) + "' failed. See docker output for more details"); } private DockerfilePaths getDockerfilePaths(DockerConfig dockerConfig, boolean forNative, diff --git a/extensions/container-image/container-image-docker/pom.xml b/extensions/container-image/container-image-docker/pom.xml new file mode 100644 index 000000000..8c6c6a2ec --- /dev/null +++ b/extensions/container-image/container-image-docker/pom.xml @@ -0,0 +1,20 @@ + + + + quarkus-container-image-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-container-image-docker-parent + Quarkus - Container - Image - Docker - Parent + pom + + deployment + runtime + + + \ No newline at end of file diff --git a/extensions/container-image/container-image-docker/runtime/pom.xml b/extensions/container-image/container-image-docker/runtime/pom.xml new file mode 100644 index 000000000..a33c635ac --- /dev/null +++ b/extensions/container-image/container-image-docker/runtime/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + io.quarkus + quarkus-container-image-docker-parent + 999-SNAPSHOT + + + quarkus-container-image-docker + Quarkus - Container - Image - Docker + Extension for building container images with Docker + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + \ No newline at end of file diff --git a/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 000000000..df9380b2a --- /dev/null +++ b/extensions/container-image/container-image-docker/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,10 @@ +--- +name: "Container Image Docker" +metadata: + keywords: + - "docker" + - "container" + - "image" + categories: + - "cloud" + status: "preview" diff --git a/extensions/container-image/container-image-jib/deployment/pom.xml b/extensions/container-image/container-image-jib/deployment/pom.xml new file mode 100644 index 000000000..7a54d45c9 --- /dev/null +++ b/extensions/container-image/container-image-jib/deployment/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + + io.quarkus + quarkus-container-image-jib-parent + 999-SNAPSHOT + + + quarkus-container-image-jib-deployment + Quarkus - Container - Image - Jib - Deployment + + + + io.quarkus + quarkus-container-image-jib + + + io.quarkus + quarkus-container-image-deployment + + + org.jboss.logging + commons-logging-jboss-logging + + + com.google.cloud.tools + jib-core + + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + + \ No newline at end of file diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuild.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuild.java new file mode 100644 index 000000000..e0bb6128d --- /dev/null +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuild.java @@ -0,0 +1,19 @@ +package io.quarkus.container.image.jib.deployment; + +import java.util.function.BooleanSupplier; + +import io.quarkus.container.image.deployment.ContainerImageConfig; + +public class JibBuild implements BooleanSupplier { + + private final ContainerImageConfig containerImageConfig; + + public JibBuild(ContainerImageConfig containerImageConfig) { + this.containerImageConfig = containerImageConfig; + } + + @Override + public boolean getAsBoolean() { + return containerImageConfig.execution != ContainerImageConfig.Execution.NONE; + } +} diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibConfig.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibConfig.java new file mode 100644 index 000000000..36b08e969 --- /dev/null +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibConfig.java @@ -0,0 +1,63 @@ +package io.quarkus.container.image.jib.deployment; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot(phase = ConfigPhase.BUILD_TIME) +public class JibConfig { + + /** + * The base image to be used when a container image is being produced for the jar build + */ + @ConfigItem(defaultValue = "fabric8/java-alpine-openjdk8-jre") + public String baseJvmImage; + + /** + * The base image to be used when a container image is being produced for the native binary build + */ + @ConfigItem(defaultValue = "registry.access.redhat.com/ubi8/ubi-minimal") + public String baseNativeImage; + + /** + * Additional JVM arguments to pass to the JVM when starting the application + */ + @ConfigItem(defaultValue = "-Dquarkus.http.host=0.0.0.0,-Djava.util.logging.manager=org.jboss.logmanager.LogManager") + public List jvmArguments; + + /** + * Additional arguments to pass when starting the native application + */ + @ConfigItem(defaultValue = "-Dquarkus.http.host=0.0.0.0") + public List nativeArguments; + + /** + * Environment variables to add to the container image + */ + @ConfigItem + public Optional> environmentVariables; + + //TODO: do the following config options belong in ContainerImageConfig ? + + /** + * The username to use to authenticate with the registry + */ + @ConfigItem + public Optional username; + + /** + * The password to use to authenticate with the registry + */ + @ConfigItem + public Optional password; + + /** + * Whether or not insecure registries are allowed + */ + @ConfigItem(defaultValue = "false") + public boolean insecure; +} diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java new file mode 100644 index 000000000..822446c39 --- /dev/null +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java @@ -0,0 +1,220 @@ +package io.quarkus.container.image.jib.deployment; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.jboss.logging.Logger; + +import com.google.cloud.tools.jib.api.AbsoluteUnixPath; +import com.google.cloud.tools.jib.api.Containerizer; +import com.google.cloud.tools.jib.api.DockerDaemonImage; +import com.google.cloud.tools.jib.api.FilePermissions; +import com.google.cloud.tools.jib.api.ImageReference; +import com.google.cloud.tools.jib.api.InvalidImageReferenceException; +import com.google.cloud.tools.jib.api.JavaContainerBuilder; +import com.google.cloud.tools.jib.api.Jib; +import com.google.cloud.tools.jib.api.JibContainer; +import com.google.cloud.tools.jib.api.JibContainerBuilder; +import com.google.cloud.tools.jib.api.LayerConfiguration; +import com.google.cloud.tools.jib.api.LogEvent; +import com.google.cloud.tools.jib.api.RegistryImage; +import com.google.cloud.tools.jib.frontend.CredentialRetrieverFactory; + +import io.quarkus.bootstrap.util.ZipUtils; +import io.quarkus.container.image.deployment.ContainerImageConfig; +import io.quarkus.container.image.deployment.util.NativeBinaryUtil; +import io.quarkus.container.spi.ContainerImageResultBuildItem; +import io.quarkus.deployment.IsNormal; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.ApplicationInfoBuildItem; +import io.quarkus.deployment.builditem.MainClassBuildItem; +import io.quarkus.deployment.pkg.builditem.ArtifactResultBuildItem; +import io.quarkus.deployment.pkg.builditem.JarBuildItem; +import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem; +import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; +import io.quarkus.deployment.pkg.steps.NativeBuild; + +public class JibProcessor { + + private static final Logger log = Logger.getLogger(JibProcessor.class); + + private static final IsClassPredicate IS_CLASS_PREDICATE = new IsClassPredicate(); + private static final String BINARY_NAME_IN_CONTAINER = "application"; + + @BuildStep(onlyIf = { IsNormal.class, JibBuild.class }, onlyIfNot = NativeBuild.class) + public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig jibConfig, + JarBuildItem sourceJarBuildItem, + MainClassBuildItem mainClassBuildItem, + OutputTargetBuildItem outputTargetBuildItem, ApplicationInfoBuildItem applicationInfo, + BuildProducer artifactResultProducer, + BuildProducer containerImageResultProducer) { + + JibContainerBuilder jibContainerBuilder = createContainerBuilderFromJar(jibConfig, + sourceJarBuildItem, + outputTargetBuildItem, + mainClassBuildItem); + JibContainer container = containerize(applicationInfo, containerImageConfig, jibConfig, jibContainerBuilder); + + ImageReference targetImage = container.getTargetImage(); + containerImageResultProducer.produce(new ContainerImageResultBuildItem(container.getImageId().getHash(), + targetImage.getRepository(), targetImage.getTag())); + artifactResultProducer.produce(new ArtifactResultBuildItem(null, "jar-container", Collections.emptyMap())); + } + + @BuildStep(onlyIf = { IsNormal.class, JibBuild.class, NativeBuild.class }) + public void buildFromNative(ContainerImageConfig containerImageConfig, JibConfig jibConfig, + NativeImageBuildItem nativeImageBuildItem, + ApplicationInfoBuildItem applicationInfo, + BuildProducer artifactResultProducer, + BuildProducer containerImageResultProducer) { + + if (!NativeBinaryUtil.nativeIsLinuxBinary(nativeImageBuildItem)) { + throw new RuntimeException( + "The native binary produced by the build is not a Linux binary and therefore cannot be used in a Linux container image. Consider adding \"quarkus.native.container-build=true\" to your configuration"); + } + + JibContainerBuilder jibContainerBuilder = createContainerBuilderFromNative(jibConfig, nativeImageBuildItem); + JibContainer container = containerize(applicationInfo, containerImageConfig, jibConfig, jibContainerBuilder); + + ImageReference targetImage = container.getTargetImage(); + containerImageResultProducer.produce(new ContainerImageResultBuildItem(container.getImageId().getHash(), + targetImage.getRepository(), targetImage.getTag())); + artifactResultProducer.produce(new ArtifactResultBuildItem(null, "native-container", Collections.emptyMap())); + } + + private JibContainer containerize(ApplicationInfoBuildItem applicationInfo, ContainerImageConfig containerImageConfig, + JibConfig jibConfig, + JibContainerBuilder jibContainerBuilder) { + Containerizer containerizer = createContainerizer(containerImageConfig, jibConfig, applicationInfo); + try { + log.info("Starting container image build"); + JibContainer container = jibContainerBuilder.containerize(containerizer); + log.infof("%s container image %s (%s)\n", + containerImageConfig.execution == ContainerImageConfig.Execution.PUSH ? "Pushed" : "Created", + container.getTargetImage(), + container.getDigest()); + return container; + } catch (Exception e) { + throw new RuntimeException("Unable to create container image", e); + } + } + + private Containerizer createContainerizer(ContainerImageConfig containerImageConfig, JibConfig jibConfig, + ApplicationInfoBuildItem applicationInfo) { + Containerizer containerizer; + ImageReference imageReference = getImageReference(containerImageConfig, applicationInfo); + if (containerImageConfig.execution == ContainerImageConfig.Execution.PUSH) { + CredentialRetrieverFactory credentialRetrieverFactory = CredentialRetrieverFactory.forImage(imageReference, + log::info); + RegistryImage registryImage = RegistryImage.named(imageReference); + registryImage.addCredentialRetriever(credentialRetrieverFactory.wellKnownCredentialHelpers()); + registryImage.addCredentialRetriever(credentialRetrieverFactory.dockerConfig()); + if (jibConfig.username.isPresent() && jibConfig.password.isPresent()) { + registryImage.addCredential(jibConfig.username.get(), jibConfig.password.get()); + } + containerizer = Containerizer.to(registryImage); + } else { + containerizer = Containerizer.to(DockerDaemonImage.named(imageReference)); + } + containerizer.setToolName("Quarkus"); + containerizer.addEventHandler(LogEvent.class, (e) -> { + if (!e.getMessage().isEmpty()) { + log.log(toJBossLoggingLevel(e.getLevel()), e.getMessage()); + } + }); + containerizer.setAllowInsecureRegistries(jibConfig.insecure); + return containerizer; + } + + private Logger.Level toJBossLoggingLevel(LogEvent.Level level) { + switch (level) { + case ERROR: + return Logger.Level.ERROR; + case WARN: + return Logger.Level.WARN; + case LIFECYCLE: + return Logger.Level.INFO; + default: + return Logger.Level.DEBUG; + } + } + + private ImageReference getImageReference(ContainerImageConfig containerImageConfig, + ApplicationInfoBuildItem applicationInfo) { + return ImageReference.of(containerImageConfig.registry.orElse(null), + containerImageConfig.group + "/" + containerImageConfig.name.orElse(applicationInfo.getName()), + containerImageConfig.tag.orElse(applicationInfo.getVersion())); + } + + private JibContainerBuilder createContainerBuilderFromJar(JibConfig jibConfig, + JarBuildItem sourceJarBuildItem, + OutputTargetBuildItem outputTargetBuildItem, MainClassBuildItem mainClassBuildItem) { + try { + // not ideal since this has been previously zipped - we would like to just reuse it + Path classesDir = outputTargetBuildItem.getOutputDirectory().resolve("jib"); + ZipUtils.unzip(sourceJarBuildItem.getPath(), classesDir); + JavaContainerBuilder javaContainerBuilder = JavaContainerBuilder + .from(jibConfig.baseJvmImage) + .addResources(classesDir, IS_CLASS_PREDICATE.negate()) + .addClasses(classesDir, IS_CLASS_PREDICATE) + .addJvmFlags(jibConfig.jvmArguments) + .setMainClass(mainClassBuildItem.getClassName()); + if (sourceJarBuildItem.getLibraryDir() != null) { + javaContainerBuilder + .addDependencies( + Files.list(sourceJarBuildItem.getLibraryDir()) + .filter(p -> Files.isRegularFile(p) && p.getFileName().toString().endsWith(".jar")) + .sorted(Comparator.comparing(Path::getFileName)) + .collect(Collectors.toList())); + } + + return javaContainerBuilder.toContainerBuilder() + .setEnvironment(jibConfig.environmentVariables.orElse(Collections.emptyMap())) + .setCreationTime(Instant.now()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } catch (InvalidImageReferenceException e) { + throw new RuntimeException(e); + } + } + + private JibContainerBuilder createContainerBuilderFromNative(JibConfig jibConfig, + NativeImageBuildItem nativeImageBuildItem) { + List entrypoint = new ArrayList<>(jibConfig.nativeArguments.size() + 1); + entrypoint.add("./" + BINARY_NAME_IN_CONTAINER); + entrypoint.addAll(jibConfig.nativeArguments); + try { + AbsoluteUnixPath workDirInContainer = AbsoluteUnixPath.get("/work"); + return Jib.from(jibConfig.baseNativeImage) + .addLayer(LayerConfiguration.builder() + .addEntry(nativeImageBuildItem.getPath(), workDirInContainer.resolve(BINARY_NAME_IN_CONTAINER), + FilePermissions.fromOctalString("775")) + .build()) + .setWorkingDirectory(workDirInContainer) + .setEntrypoint(entrypoint) + .setEnvironment(jibConfig.environmentVariables.orElse(Collections.emptyMap())) + .setCreationTime(Instant.now()); + } catch (InvalidImageReferenceException e) { + throw new RuntimeException(e); + } + } + + // TODO: this predicate is rather simplistic since it results in creating the directory structure in both the resources and classes so it should probably be improved to remove empty directories + private static class IsClassPredicate implements Predicate { + + @Override + public boolean test(Path path) { + return path.getFileName().toString().endsWith(".class"); + } + } +} diff --git a/extensions/container-image/container-image-jib/pom.xml b/extensions/container-image/container-image-jib/pom.xml new file mode 100644 index 000000000..3e4f8906d --- /dev/null +++ b/extensions/container-image/container-image-jib/pom.xml @@ -0,0 +1,20 @@ + + + + quarkus-container-image-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-container-image-jib-parent + Quarkus - Container - Image - Jib - Parent + pom + + deployment + runtime + + + \ No newline at end of file diff --git a/extensions/container/runtime/pom.xml b/extensions/container-image/container-image-jib/runtime/pom.xml similarity index 81% rename from extensions/container/runtime/pom.xml rename to extensions/container-image/container-image-jib/runtime/pom.xml index a234d47cc..1ffa679eb 100644 --- a/extensions/container/runtime/pom.xml +++ b/extensions/container-image/container-image-jib/runtime/pom.xml @@ -6,13 +6,15 @@ io.quarkus - quarkus-container-parent + quarkus-container-image-jib-parent 999-SNAPSHOT - quarkus-container - Quarkus - Container - Runtime - Manage container builds + quarkus-container-image-jib + Quarkus - Container - Image - Jib + Extension for building container images with Jib + + @@ -33,6 +35,4 @@ - - - + \ No newline at end of file diff --git a/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 000000000..ceccd5324 --- /dev/null +++ b/extensions/container-image/container-image-jib/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,10 @@ +--- +name: "Container Image Jib" +metadata: + keywords: + - "jib" + - "container" + - "image" + categories: + - "cloud" + status: "preview" diff --git a/extensions/container/deployment/pom.xml b/extensions/container-image/deployment/pom.xml similarity index 87% rename from extensions/container/deployment/pom.xml rename to extensions/container-image/deployment/pom.xml index 5c9fc344c..3dee07f8b 100644 --- a/extensions/container/deployment/pom.xml +++ b/extensions/container-image/deployment/pom.xml @@ -3,13 +3,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-container-parent + quarkus-container-image-parent io.quarkus 999-SNAPSHOT 4.0.0 - quarkus-container-deployment + quarkus-container-image-deployment Quarkus - Container - Deployment @@ -19,7 +19,7 @@ io.quarkus - quarkus-container-spi + quarkus-container-image-spi diff --git a/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageConfig.java b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageConfig.java new file mode 100644 index 000000000..44b9b7d98 --- /dev/null +++ b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageConfig.java @@ -0,0 +1,54 @@ +package io.quarkus.container.image.deployment; + +import java.util.Optional; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot +public class ContainerImageConfig { + + /** + * The container registry to use + */ + @ConfigItem + public Optional registry; + + /** + * The group the container image will be part of + */ + @ConfigItem(defaultValue = "${user.name}") + public String group; + + /** + * The name of the container image. If not set defaults to the application name + */ + @ConfigItem + public Optional name; + + /** + * The tag of the container image. If not set defaults to the application version + */ + @ConfigItem + public Optional tag; + + /** + * Controls what kind of execution is needed. + *
    + *
  • {@link io.quarkus.container.image.deployment.ContainerImageConfig.Execution#NONE} means that no container image will + * be created
  • + *
  • {@link io.quarkus.container.image.deployment.ContainerImageConfig.Execution#BUILD} will result in a container image + * being created locally
  • + *
  • {@link io.quarkus.container.image.deployment.ContainerImageConfig.Execution#PUSH} will result in a container image + * being pushed to the specified registry
  • + *
+ */ + @ConfigItem(defaultValue = "none") + public Execution execution; + + public enum Execution { + NONE, + BUILD, + PUSH + } +} diff --git a/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerProcessor.java b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerProcessor.java new file mode 100644 index 000000000..300704c27 --- /dev/null +++ b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerProcessor.java @@ -0,0 +1,18 @@ +package io.quarkus.container.image.deployment; + +import io.quarkus.container.image.deployment.util.ImageUtil; +import io.quarkus.container.spi.ContainerImageBuildItem; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.ApplicationInfoBuildItem; + +public class ContainerProcessor { + + @BuildStep + public ContainerImageBuildItem publishNativeImageInfo(ApplicationInfoBuildItem app, + ContainerImageConfig containerImageConfig) { + String image = ImageUtil.getImage(containerImageConfig.registry, containerImageConfig.group, + containerImageConfig.name.orElse(app.getName()), containerImageConfig.tag.orElse(app.getVersion())); + return new ContainerImageBuildItem(image); + } + +} diff --git a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/util/ImageUtil.java b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/util/ImageUtil.java similarity index 96% rename from extensions/container/deployment/src/main/java/io/quarkus/container/deployment/util/ImageUtil.java rename to extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/util/ImageUtil.java index 78d3c5626..147c6155d 100644 --- a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/util/ImageUtil.java +++ b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/util/ImageUtil.java @@ -1,13 +1,16 @@ -package io.quarkus.container.deployment.util; +package io.quarkus.container.image.deployment.util; import java.util.Optional; -public class ImageUtil { +public final class ImageUtil { private static final String SLASH = "/"; private static final String COLN = ":"; + private ImageUtil() { + } + /** * Create an image from the individual parts. * diff --git a/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/util/NativeBinaryUtil.java b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/util/NativeBinaryUtil.java new file mode 100644 index 000000000..a42338d96 --- /dev/null +++ b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/util/NativeBinaryUtil.java @@ -0,0 +1,31 @@ +package io.quarkus.container.image.deployment.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UncheckedIOException; + +import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem; + +public final class NativeBinaryUtil { + + private NativeBinaryUtil() { + } + + /** + * Checks if the file is a linux binary by checking the first bytes of the file against the ELF magic number + */ + public static boolean nativeIsLinuxBinary(NativeImageBuildItem nativeImageBuildItem) { + File file = nativeImageBuildItem.getPath().toFile(); + try (FileInputStream fileInputStream = new FileInputStream(file)) { + byte[] firstBytes = new byte[4]; + int readBytes = fileInputStream.read(firstBytes); + if (readBytes != 4) { + return false; + } + return (firstBytes[0] == 0x7f && firstBytes[1] == 0x45 && firstBytes[2] == 0x4c && firstBytes[3] == 0x46); + } catch (IOException e) { + throw new UncheckedIOException("Unable to determine type of native binary " + nativeImageBuildItem.getPath(), e); + } + } +} diff --git a/extensions/container/pom.xml b/extensions/container-image/pom.xml similarity index 75% rename from extensions/container/pom.xml rename to extensions/container-image/pom.xml index dce9c3896..d42d073be 100644 --- a/extensions/container/pom.xml +++ b/extensions/container-image/pom.xml @@ -10,12 +10,13 @@ 4.0.0 - quarkus-container-parent - Quarkus - Container + quarkus-container-image-parent + Quarkus - Container Image pom deployment - runtime spi + container-image-docker + container-image-jib diff --git a/extensions/container/spi/pom.xml b/extensions/container-image/spi/pom.xml similarity index 80% rename from extensions/container/spi/pom.xml rename to extensions/container-image/spi/pom.xml index 0ccac1010..f92626b5c 100644 --- a/extensions/container/spi/pom.xml +++ b/extensions/container-image/spi/pom.xml @@ -2,14 +2,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-container-parent + quarkus-container-image-parent io.quarkus 999-SNAPSHOT 4.0.0 - quarkus-container-spi - Quarkus - Container - SPI + quarkus-container-image-spi + Quarkus - Container - Image - SPI Extensions that provide Container features should include this module and the corresponding BuildItems diff --git a/extensions/container/spi/src/main/java/io/quarkus/container/spi/ContainerImageBuildItem.java b/extensions/container-image/spi/src/main/java/io/quarkus/container/spi/ContainerImageBuildItem.java similarity index 100% rename from extensions/container/spi/src/main/java/io/quarkus/container/spi/ContainerImageBuildItem.java rename to extensions/container-image/spi/src/main/java/io/quarkus/container/spi/ContainerImageBuildItem.java diff --git a/extensions/container/spi/src/main/java/io/quarkus/container/spi/ContainerImageResultBuildItem.java b/extensions/container-image/spi/src/main/java/io/quarkus/container/spi/ContainerImageResultBuildItem.java similarity index 100% rename from extensions/container/spi/src/main/java/io/quarkus/container/spi/ContainerImageResultBuildItem.java rename to extensions/container-image/spi/src/main/java/io/quarkus/container/spi/ContainerImageResultBuildItem.java diff --git a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/ContainerConfig.java b/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/ContainerConfig.java deleted file mode 100644 index eb340485f..000000000 --- a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/ContainerConfig.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.quarkus.container.deployment; - -import java.util.Optional; - -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.annotations.ConfigRoot; - -@ConfigRoot -public class ContainerConfig { - - /** - * The container registry to use - */ - @ConfigItem - public Optional registry; - - /** - * The group the container image will be part of - */ - @ConfigItem(defaultValue = "${user.name}") - public String group; - - /** - * The name of the container image. If not set defaults to the application name - */ - @ConfigItem - public Optional name; - - /** - * The tag of the container image. If not set defaults to the application version - */ - @ConfigItem - public Optional tag; - /** - * Flag that specifies if container build is enabled - */ - @ConfigItem - public boolean build; - - /** - * Flag that specifies if container deploy is enabled - */ - @ConfigItem - public boolean deploy; -} diff --git a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/ContainerProcessor.java b/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/ContainerProcessor.java deleted file mode 100644 index 6fcb345c8..000000000 --- a/extensions/container/deployment/src/main/java/io/quarkus/container/deployment/ContainerProcessor.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.quarkus.container.deployment; - -import io.quarkus.container.deployment.util.ImageUtil; -import io.quarkus.container.spi.ContainerImageBuildItem; -import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.builditem.ApplicationInfoBuildItem; -import io.quarkus.deployment.pkg.steps.NativeBuild; - -public class ContainerProcessor { - - private ContainerConfig containerConfig; - - @BuildStep(onlyIfNot = NativeBuild.class) - public ContainerImageBuildItem publishImageInfo(ApplicationInfoBuildItem app) { - String image = ImageUtil.getImage(containerConfig.registry, containerConfig.group, - containerConfig.name.orElse(app.getName()), containerConfig.tag.orElse(app.getVersion())); - return new ContainerImageBuildItem(image); - } - - @BuildStep(onlyIf = NativeBuild.class) - public ContainerImageBuildItem publishNativeImageInfo(ApplicationInfoBuildItem app) { - String image = ImageUtil.getImage(containerConfig.registry, containerConfig.group, - containerConfig.name.orElse(app.getName()), containerConfig.tag.orElse(app.getVersion() + "-native")); - return new ContainerImageBuildItem(image); - } - - public ContainerConfig getContainerConfig() { - return this.containerConfig; - } - - public void setContainerConfig(ContainerConfig containerConfig) { - this.containerConfig = containerConfig; - } - -} diff --git a/extensions/container/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/container/runtime/src/main/resources/META-INF/quarkus-extension.yaml deleted file mode 100644 index e159d75dd..000000000 --- a/extensions/container/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: "Docker" -metadata: - keywords: - - "docker" - guide: "https://quarkus.io/guides/docker" - categories: - - "cloud" - status: "stable" diff --git a/extensions/kubernetes-client/spi/pom.xml b/extensions/kubernetes-client/spi/pom.xml index 5e408e285..76c870dd9 100644 --- a/extensions/kubernetes-client/spi/pom.xml +++ b/extensions/kubernetes-client/spi/pom.xml @@ -2,7 +2,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - quarkus-kubernetes-parent + quarkus-kubernetes-client-parent io.quarkus 999-SNAPSHOT diff --git a/extensions/kubernetes/deployment/pom.xml b/extensions/kubernetes/deployment/pom.xml index 68fb40276..34af2d8fc 100644 --- a/extensions/kubernetes/deployment/pom.xml +++ b/extensions/kubernetes/deployment/pom.xml @@ -15,11 +15,11 @@ io.quarkus - quarkus-container-deployment + quarkus-container-image-deployment io.quarkus - quarkus-container-spi + quarkus-container-image-spi io.quarkus diff --git a/extensions/kubernetes/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesDeploy.java b/extensions/kubernetes/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesDeploy.java index ad5ddd2b2..9defdf1a6 100644 --- a/extensions/kubernetes/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesDeploy.java +++ b/extensions/kubernetes/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesDeploy.java @@ -14,8 +14,7 @@ import java.util.function.Function; import org.jboss.logging.Logger; -import io.quarkus.container.deployment.ContainerConfig; -import io.quarkus.container.deployment.DockerBuild.OutputFilter; +import io.quarkus.container.image.deployment.ContainerImageConfig; import io.quarkus.deployment.util.ExecUtil; public class KubernetesDeploy implements BooleanSupplier { @@ -23,16 +22,17 @@ public class KubernetesDeploy implements BooleanSupplier { private final Logger LOGGER = Logger.getLogger(KubernetesDeploy.class); private KubernetesConfig kubernetesConfig; - private ContainerConfig containerConfig; + private ContainerImageConfig containerImageConfig; - KubernetesDeploy(ContainerConfig containerConfig, KubernetesConfig kubernetesConfig) { - this.containerConfig = containerConfig; + KubernetesDeploy(ContainerImageConfig containerImageConfig, KubernetesConfig kubernetesConfig) { + this.containerImageConfig = containerImageConfig; this.kubernetesConfig = kubernetesConfig; } @Override public boolean getAsBoolean() { - if (containerConfig.deploy) { + // TODO: I think this is wrong for s2i + if (containerImageConfig.execution == ContainerImageConfig.Execution.PUSH) { OutputFilter filter = new OutputFilter(); try { if (kubernetesConfig.getDeploymentTarget().contains(DeploymentTarget.OPENSHIFT)) { diff --git a/extensions/pom.xml b/extensions/pom.xml index b3bc0b0d4..3730d72ca 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -130,7 +130,7 @@ scala - container + container-image kubernetes kubernetes-client diff --git a/integration-tests/container/pom.xml b/integration-tests/container-image/pom.xml similarity index 83% rename from integration-tests/container/pom.xml rename to integration-tests/container-image/pom.xml index e272c2aeb..825f2776f 100644 --- a/integration-tests/container/pom.xml +++ b/integration-tests/container-image/pom.xml @@ -7,29 +7,28 @@ quarkus-integration-tests-parent 999-SNAPSHOT - quarkus-integration-test-container - Quarkus - Integration Tests - Container extension + quarkus-integration-test-container-image + Quarkus - Integration Tests - Jib extension + + + + com.google.j2objc + j2objc-annotations + 1.3 + + + io.quarkus quarkus-core-deployment test - - io.quarkus - quarkus-container-deployment - test - io.quarkus quarkus-test-maven test - - io.quarkus - quarkus-container - test - diff --git a/integration-tests/container-image/src/it/container-build-docker/invoker.properties b/integration-tests/container-image/src/it/container-build-docker/invoker.properties new file mode 100644 index 000000000..555032053 --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-docker/invoker.properties @@ -0,0 +1 @@ +invoker.goals=clean package -Dquarkus.container-image.execution=build diff --git a/integration-tests/container-image/src/it/container-build-docker/pom.xml b/integration-tests/container-image/src/it/container-build-docker/pom.xml new file mode 100644 index 000000000..004dfa6d9 --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-docker/pom.xml @@ -0,0 +1,117 @@ + + + 4.0.0 + org.acme + container-build-docker + 0.1-SNAPSHOT + + UTF-8 + 2.22.0 + 1.8 + UTF-8 + 1.8 + + + + + io.quarkus + quarkus-bom + @project.version@ + pom + import + + + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-container-image-docker + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + io.quarkus + quarkus-maven-plugin + @project.version@ + + + + build + + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + + + + + + + + native + + + native + + + + + + io.quarkus + quarkus-maven-plugin + @project.version@ + + + + native-image + + + true + + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + + + + + + + + + + diff --git a/integration-tests/container-image/src/it/container-build-docker/src/main/docker/Dockerfile.jvm b/integration-tests/container-image/src/it/container-build-docker/src/main/docker/Dockerfile.jvm new file mode 100644 index 000000000..fa97e4b11 --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-docker/src/main/docker/Dockerfile.jvm @@ -0,0 +1,22 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the docker image run: +# +# mvn package +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/getting-started-jvm . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/getting-started-jvm +# +### +FROM fabric8/java-alpine-openjdk8-jre +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV AB_ENABLED=jmx_exporter +COPY target/lib/* /deployments/lib/ +COPY target/*-runner.jar /deployments/app.jar +ENTRYPOINT [ "/deployments/run-java.sh" ] \ No newline at end of file diff --git a/integration-tests/container/src/it/container-build/src/main/java/org/acme/Hello.java b/integration-tests/container-image/src/it/container-build-docker/src/main/java/org/acme/Hello.java similarity index 100% rename from integration-tests/container/src/it/container-build/src/main/java/org/acme/Hello.java rename to integration-tests/container-image/src/it/container-build-docker/src/main/java/org/acme/Hello.java diff --git a/integration-tests/container/src/it/container-build/src/main/resources/application.properties b/integration-tests/container-image/src/it/container-build-docker/src/main/resources/application.properties similarity index 100% rename from integration-tests/container/src/it/container-build/src/main/resources/application.properties rename to integration-tests/container-image/src/it/container-build-docker/src/main/resources/application.properties diff --git a/integration-tests/container-image/src/it/container-build-docker/verify.groovy b/integration-tests/container-image/src/it/container-build-docker/verify.groovy new file mode 100644 index 000000000..508f36d8c --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-docker/verify.groovy @@ -0,0 +1,12 @@ +import io.quarkus.deployment.util.ExecUtil + +try { + ExecUtil.exec("docker", "version", "--format", "'{{.Server.Version}}'") +} catch (Exception ignored) { + println "Docker not found" + return +} + +String group = System.getProperty("user.name") +assert ExecUtil.exec("docker", "images", group + "/container-build-docker") +assert ExecUtil.exec("docker", "rmi", group + "/container-build-docker:0.1-SNAPSHOT") \ No newline at end of file diff --git a/integration-tests/container-image/src/it/container-build-jib/invoker.properties b/integration-tests/container-image/src/it/container-build-jib/invoker.properties new file mode 100644 index 000000000..555032053 --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-jib/invoker.properties @@ -0,0 +1 @@ +invoker.goals=clean package -Dquarkus.container-image.execution=build diff --git a/integration-tests/container/src/it/container-build/pom.xml b/integration-tests/container-image/src/it/container-build-jib/pom.xml similarity index 97% rename from integration-tests/container/src/it/container-build/pom.xml rename to integration-tests/container-image/src/it/container-build-jib/pom.xml index ada200183..e4328de64 100644 --- a/integration-tests/container/src/it/container-build/pom.xml +++ b/integration-tests/container-image/src/it/container-build-jib/pom.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 org.acme - container-build + container-build-jib 0.1-SNAPSHOT UTF-8 @@ -30,7 +30,7 @@ io.quarkus - quarkus-container + quarkus-container-image-jib io.quarkus diff --git a/integration-tests/container-image/src/it/container-build-jib/src/main/java/org/acme/Hello.java b/integration-tests/container-image/src/it/container-build-jib/src/main/java/org/acme/Hello.java new file mode 100644 index 000000000..ad80766a1 --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-jib/src/main/java/org/acme/Hello.java @@ -0,0 +1,16 @@ +package org.acme; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/hello") +public class Hello { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "hello"; + } +} \ No newline at end of file diff --git a/integration-tests/container-image/src/it/container-build-jib/src/main/resources/application.properties b/integration-tests/container-image/src/it/container-build-jib/src/main/resources/application.properties new file mode 100644 index 000000000..3c1ac56a1 --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-jib/src/main/resources/application.properties @@ -0,0 +1,2 @@ +# Configuration file +# key = value \ No newline at end of file diff --git a/integration-tests/container-image/src/it/container-build-jib/verify.groovy b/integration-tests/container-image/src/it/container-build-jib/verify.groovy new file mode 100644 index 000000000..bf91d6494 --- /dev/null +++ b/integration-tests/container-image/src/it/container-build-jib/verify.groovy @@ -0,0 +1,12 @@ +import io.quarkus.deployment.util.ExecUtil + +try { + ExecUtil.exec("docker", "version", "--format", "'{{.Server.Version}}'") +} catch (Exception ignored) { + println "Docker not found" + return +} + +String group = System.getProperty("user.name") +assert ExecUtil.exec("docker", "images", group + "/container-build-jib") +assert ExecUtil.exec("docker", "rmi", group + "/container-build-jib:0.1-SNAPSHOT") diff --git a/integration-tests/container/src/it/container-build/invoker.properties b/integration-tests/container/src/it/container-build/invoker.properties deleted file mode 100644 index 16310a86d..000000000 --- a/integration-tests/container/src/it/container-build/invoker.properties +++ /dev/null @@ -1,2 +0,0 @@ -# invoker.goals=clean package -Dquarkus.container.build=true -Dquarkus.package.type=native -invoker.goals=clean package -Dquarkus.container.build=true diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 5f3314150..4d253bbab 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -1,5 +1,3 @@ - - amazon-lambda-http amazon-lambda-http-resteasy kogito - container + kogito-maven + container-image optaplanner-jackson kubernetes kubernetes-client