Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Kubernetes extension #1300

Merged
merged 4 commits into from
Mar 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
<aws-lambda-java.version>1.1.0</aws-lambda-java.version>
<kotlin.version>1.3.21</kotlin.version>
<camel.version>3.0.0-M1</camel.version>
<ap4k.version>0.3.1</ap4k.version>
<javax.xml.soap-api.version>1.4.0</javax.xml.soap-api.version>
<maven-artifact-transfer.version>0.10.0</maven-artifact-transfer.version>
<jline.version>2.14.6</jline.version>
Expand Down Expand Up @@ -408,6 +409,11 @@
<artifactId>quarkus-amazon-lambda</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Quarkus test dependencies -->

Expand Down Expand Up @@ -496,6 +502,14 @@
</exclusions>
</dependency>

<!-- ap4k -->
<dependency>
<groupId>io.ap4k</groupId>
<artifactId>kubernetes-annotations</artifactId>
<version>${ap4k.version}</version>
<classifier>noapt</classifier>
</dependency>

<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
Expand Down
15 changes: 15 additions & 0 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,21 @@
<artifactId>quarkus-kotlin-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-spi</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Miscellaneous -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@ public final class ApplicationInfoUtil {
public static final String APPLICATION_INFO_PROPERTIES = "application-info.properties";
public static final String META_INF = "META-INF";

public static final String ARTIFACT_ID_KEY = "artifactId";
public static final String VERSION_KEY = "version";

private ApplicationInfoUtil() {
}

// these properties are used as default values for ApplicationInfoBuildItem
public static void writeApplicationInfoProperties(AppArtifact appArtifact, Path appClassesDir) {
Properties properties = new Properties();
properties.setProperty("artifactId", appArtifact.getArtifactId());
properties.setProperty("version", appArtifact.getVersion());
if (appArtifact != null) {
properties.setProperty("artifactId", appArtifact.getArtifactId());
properties.setProperty("version", appArtifact.getVersion());
}
try {
appClassesDir.resolve(META_INF).toFile().mkdir();
File file = appClassesDir.resolve(META_INF).resolve(APPLICATION_INFO_PROPERTIES).toFile();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

public final class ApplicationInfoBuildItem extends SimpleBuildItem {

public static final String UNSET_VALUE = "<<unset>>";

private final String name;
private final String version;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
public final class FeatureBuildItem extends MultiBuildItem {

public static final String AGROAL = "agroal";
public static final String KUBERNETES = "kubernetes";
public static final String CAMEL_CORE = "camel-core";
public static final String CAMEL_INFINISPAN = "camel-infinispan";
public static final String CAMEL_AWS_S3 = "camel-aws-s3";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.quarkus.deployment.steps;

import static io.quarkus.deployment.ApplicationInfoUtil.APPLICATION_INFO_PROPERTIES;
import static io.quarkus.deployment.ApplicationInfoUtil.ARTIFACT_ID_KEY;
import static io.quarkus.deployment.ApplicationInfoUtil.META_INF;
import static io.quarkus.deployment.ApplicationInfoUtil.VERSION_KEY;
import static io.quarkus.deployment.builditem.ApplicationInfoBuildItem.UNSET_VALUE;

import java.io.File;
import java.io.IOException;
Expand All @@ -20,10 +23,6 @@ public class ApplicationInfoBuildStep {

private static final String PROPERTIES_FILE_TO_READ = META_INF + File.separator + APPLICATION_INFO_PROPERTIES;

private static final String ARTIFACT_ID_KEY = "artifactId";
private static final String VERSION_KEY = "version";
private static final String UNSET_VALUE = "unset";

@BuildStep
public ApplicationInfoBuildItem create(ApplicationConfig applicationConfig) {
final String userConfiguredName = applicationConfig.name;
Expand All @@ -32,8 +31,8 @@ public ApplicationInfoBuildItem create(ApplicationConfig applicationConfig) {
final Properties applicationInfoProperties = getApplicationInfoProperties();

return new ApplicationInfoBuildItem(
useIfNotEmpty(userConfiguredName, applicationInfoProperties.getProperty(ARTIFACT_ID_KEY, UNSET_VALUE)),
useIfNotEmpty(userConfiguredVersion, applicationInfoProperties.getProperty(VERSION_KEY, UNSET_VALUE)));
useIfNotEmpty(userConfiguredName, applicationInfoProperties, ARTIFACT_ID_KEY),
useIfNotEmpty(userConfiguredVersion, applicationInfoProperties, VERSION_KEY));
}

private Properties getApplicationInfoProperties() {
Expand All @@ -60,7 +59,7 @@ private Properties getApplicationInfoProperties() {
}
}

private String useIfNotEmpty(String value, String defaultValue) {
return (value != null) && !value.isEmpty() ? value : defaultValue;
private String useIfNotEmpty(String value, Properties properties, String key) {
return (value != null) && !value.isEmpty() ? value : properties.getProperty(key, UNSET_VALUE);
}
}
125 changes: 125 additions & 0 deletions docs/src/main/asciidoc/ap4k.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
= {project-name} - Deploying an Application to Kubernetes and OpenShift

This guide covers:

* The deployment of the application to Kubernetes
* The deployment of the application to OpenShift (TODO)

== Prerequisites

To complete this guide, you need:

* roughly 15 minutes
* an IDE
* JDK 1.8+ installed with `JAVA_HOME` configured appropriately
* Apache Maven 3.5.3+
* access to a Kubernetes or OpenShift cluster (Minikube and Minishift are both viable options)
* have the following binaries on your PATH: `docker` (for building and pushing images), `kubectl` (for deploying to Kubernetes) and `oc` (for deploying to OpenShift)

== Creating the Maven project

First, we need a new project that contains the kubernetes extension. This can be done using the following command:

[source, subs=attributes+]
----
mvn io.quarkus:quarkus-maven-plugin:${quarkus-version}:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=test \
-DclassName="org.acme.rest.GreetingResource" \
-Dpath="/greeting" \
-Dextensions="kubernetes"
----

== Enable Kubernetes support

{project-name} offers the ability to automatically generate Kubernetes resources based on sane defaults and user supplied configuration. The implementation that takes care
of generating the actual Kubernetes resources is provided by https://github.com/ap4k/ap4k/[ap4k].

When we added the `kubernetes` extension to the command line invocation above, the following dependency was added to the `pom.xml`

[source,xml]
----
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
</dependency>
----

By adding this dependency, we now have the ability to configure the Kubernetes resource generation and application using the usual `application.properties` approach that {project-name} provides.
The configuration items that are available can be found in: `io.quarkus.kubernetes.deployment.KubernetesConfig` class.
Furthermore, the items provided by `io.quarkus.deployment.ApplicationConfig` affect the Kubernetes resources.

By using the following configuration for example:

[source]
----
quarkus.kubernetes.group=yourDockerUsername # this is optional and defaults to your username if not set
quarkus.application.name=test-quarkus-app # this is also optional and defaults to the project name if not set
----

and following the execution of `mvn package` you will notice amongst the other files that are created, two files named
`kubernetes.json` and `kubernetes.yaml` in the `target/wiring-classes/META-INF/kubernetes/` directory.

If you look at either file you will see that it contains both a Kubernetes `Deployment` and a `Service`.

The full source of the `kubernetes.json` file looks something like this:

[source,json]
----
{
"apiVersion" : "v1",
"kind" : "List",
"items" : [ {
"apiVersion" : "apps/v1",
"kind" : "Deployment",
"metadata" : {
"labels" : {
"app" : "test-quarkus-app",
"version" : "1.0-SNAPSHOT",
"group" : "yourDockerUsername"
},
"name" : "test-quarkus-app"
},
"spec" : {
"replicas" : 1,
"selector" : {
"matchLabels" : {
"app" : "test-quarkus-app",
"version" : "1.0-SNAPSHOT",
"group" : "yourDockerUsername"
}
},
"template" : {
"metadata" : {
"labels" : {
"app" : "test-quarkus-app",
"version" : "1.0-SNAPSHOT",
"group" : "yourDockerUsername"
}
},
"spec" : {
"containers" : [ {
"env" : [ {
"name" : "KUBERNETES_NAMESPACE",
"valueFrom" : {
"fieldRef" : {
"fieldPath" : "metadata.namespace"
}
}
} ],
"image" : "yourDockerUsername/test-quarkus-app:1.0-SNAPSHOT",
"imagePullPolicy" : "IfNotPresent",
"name" : "test-quarkus-app"
} ]
}
}
}
} ]
}
----

An important thing to note about the `Deployment` is that is uses `yourDockerUsername/test-quarkus-app:1.0-SNAPSHOT` as the Docker image of the `Pod`.

Also the `Service` is configured to use container port `8080` (which is automatically picked up by the standard Quarkus configuration).

An important thing to keep in mind is that so far, all {project-name} has done is generate the `Kubernetes` resources, it has not applied them. The next section will walk you through how this can be done.
65 changes: 65 additions & 0 deletions extensions/kubernetes/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 Red Hat, Inc.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
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">
<parent>
<artifactId>quarkus-kubernetes-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-kubernetes-deployment</artifactId>
<name>Quarkus - Kubernetes - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-spi</artifactId>
</dependency>
<dependency>
<groupId>io.ap4k</groupId>
<artifactId>kubernetes-annotations</artifactId>
<classifier>noapt</classifier>
<exclusions>
<exclusion>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.quarkus.kubernetes.deployment;

import io.quarkus.runtime.annotations.ConfigGroup;

@ConfigGroup
public class DockerConfig {

/**
* The docker registry to which the images will be pushed
*/
public String registry = "docker.io";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.quarkus.kubernetes.deployment;

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 KubernetesConfig {

/**
* The group of the application.
* This value will be use as:
* - docker image repo
* - labeling resources
*/
@ConfigItem
public String group;

/**
* Configuration that is relevant to docker images
*/
@ConfigItem
public DockerConfig docker;
}
Loading