You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dm...@apache.org on 2017/02/14 01:33:37 UTC
ignite git commit: IGNITE-4159: Kubernetes IP finder.
Repository: ignite
Updated Branches:
refs/heads/master 3ef7a0e03 -> 37c0a2202
IGNITE-4159: Kubernetes IP finder.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/37c0a220
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/37c0a220
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/37c0a220
Branch: refs/heads/master
Commit: 37c0a220284527a38b181561865e8a57cfb1549b
Parents: 3ef7a0e
Author: Denis Magda <dm...@gridgain.com>
Authored: Mon Feb 13 17:33:32 2017 -0800
Committer: Denis Magda <dm...@gridgain.com>
Committed: Mon Feb 13 17:33:32 2017 -0800
----------------------------------------------------------------------
modules/kubernetes/DEVNOTES.txt | 63 ++++
modules/kubernetes/README.txt | 33 ++
modules/kubernetes/config/Dockerfile | 45 +++
modules/kubernetes/config/example-kube.xml | 44 +++
.../kubernetes/config/ignite-deployment.yaml | 26 ++
modules/kubernetes/config/ignite-service.yaml | 14 +
modules/kubernetes/config/run.sh | 50 +++
modules/kubernetes/licenses/apache-2.0.txt | 202 ++++++++++++
modules/kubernetes/pom.xml | 93 ++++++
.../TcpDiscoveryKubernetesIpFinder.java | 315 +++++++++++++++++++
.../tcp/ipfinder/kubernetes/package-info.java | 22 ++
.../TcpDiscoveryKubernetesIpFinderSelfTest.java | 93 ++++++
.../tcp/ipfinder/kubernetes/package-info.java | 22 ++
.../testsuites/IgniteKubernetesTestSuite.java | 41 +++
pom.xml | 1 +
15 files changed, 1064 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/DEVNOTES.txt
----------------------------------------------------------------------
diff --git a/modules/kubernetes/DEVNOTES.txt b/modules/kubernetes/DEVNOTES.txt
new file mode 100644
index 0000000..b2a8173
--- /dev/null
+++ b/modules/kubernetes/DEVNOTES.txt
@@ -0,0 +1,63 @@
+Building and testing Kubernetes module
+=========================================
+
+The instructions provide a guidance on how to build and test Ignite Kubernetes IP finder in Kubernetes environment.
+
+To test the IP finder you have to build the whole Apache Ignite project, package the binary as a Docker image and
+feed the image to your kubernetes environment.
+
+Building Apache Ignite
+=========================
+
+Use the command below to assemble an Apache Ignite binary:
+ mvn clean package -Prelease -Dignite.edition=fabric-lgpl -DskipTests
+
+Note, if you alter the build instruction somehow make sure to update the files under 'config' folder if needed.
+
+Installing Docker and Minikube
+==============================
+
+Install Docker and Minikube for testing purpose in your development environment.
+
+Once this is done, make sure that Minikube sees Docker images registered locally:
+ eval $(minikube docker-env)
+
+Start Minikube:
+ minikube start --vm-driver=xhyve
+
+Assembling Apache Ignite Docker Image
+=====================================
+
+Create a folder for all the files to be placed in the Docker image and copy the following there:
+ - Apache Ignite binary in a zip form built at the step above.
+ - Dockerfile from `ignite-kubernetes/config/Dockerfile`.
+ - Ignite configuration with enabled Kubernetes IP finder from `ignite-kubernetes/config/example-kube.xml`.
+ - The executable file that will start an Ignite node process from `ignite-kubernetes/config/run.sh`
+
+Go to the folder and execute a command below to prepare the image:
+ docker build -t ignite-kube:v1 .
+
+Creating containerized Ignite pods and Ignite lookup service
+============================================================
+
+Start the Kubernetes service that is used for IP addresses lookup. Use `ignite-kubernetes/config/ignite-service.yaml`:
+ kubectl create -f {path_to}/ignite-service.yaml
+
+Create and deploy Ignite pods using `ignite-kubernetes/config/ignite-deployment.yaml` configuration:
+ kubectl create -f {path_to}/ignite-deployment.yaml
+
+Make sure that the pods were deployed and running properly:
+ kubectl get pod
+ kubectl logs {pod name}
+
+Increase or decrease number of Ignite pods checking that Kubernetes IP finder works as expected:
+ kubectl scale --replicas=4 -f {path_to}/ignite-deployment.yaml
+
+Docker Image Redeployment
+=========================
+
+If you need to redeploy the docker image after it gets updated and you prefer not to change the image version then
+delete a current Kubernetes Ignite deployment (don't delete the service):
+ kubectl delete deployment ignite-cluster
+
+After that you are free to build and deploy an updated docker image using the same commands as listed above.
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/README.txt
----------------------------------------------------------------------
diff --git a/modules/kubernetes/README.txt b/modules/kubernetes/README.txt
new file mode 100644
index 0000000..a9a5a09
--- /dev/null
+++ b/modules/kubernetes/README.txt
@@ -0,0 +1,33 @@
+Apache Ignite Kubernetes Module
+------------------------
+
+Apache Ignite Kubernetes module provides a TCP Discovery IP Finder that uses a dedicated Kubernetes service
+for IP addresses lookup of Apache Ignite pods containerized by Kubernetes.
+
+To enable Kubernetes module when starting a standalone node, move 'optional/ignite-kubernetes' folder to
+'libs' folder before running 'ignite.{sh|bat}' script. The content of the module folder will
+be added to classpath in this case.
+
+Importing Kubernetes Module In Maven Project
+-------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add Kubernetes module
+dependency like this (replace '${ignite.version}' with actual Ignite version you are
+interested in):
+
+<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">
+ ...
+ <dependencies>
+ ...
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-kubernetes</artifactId>
+ <version>${ignite.version}</version>
+ </dependency>
+ ...
+ </dependencies>
+ ...
+</project>
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/config/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/kubernetes/config/Dockerfile b/modules/kubernetes/config/Dockerfile
new file mode 100644
index 0000000..4e08ce8
--- /dev/null
+++ b/modules/kubernetes/config/Dockerfile
@@ -0,0 +1,45 @@
+# Use Java 8 image as default one.
+FROM java:8
+
+# Set Apache Ignite version.
+ENV IGNITE_VERSION 2.0.0-SNAPSHOT
+
+# Set IGNITE_HOME variable.
+ENV IGNITE_HOME /opt/ignite/apache-ignite-fabric-lgpl-${IGNITE_VERSION}-bin
+
+# Setting a path to an Apache Ignite configuration file. Used by run.sh script below.
+ENV CONFIG_URI ${IGNITE_HOME}/config/example-kube.xml
+
+# Make sure kubernetes lib is copied to 'libs' folder.
+ENV OPTION_LIBS ignite-kubernetes
+
+# Disabling quiet mode.
+ENV IGNITE_QUIET=false
+
+# Install or update needed tools.
+RUN apt-get update && apt-get install -y --no-install-recommends unzip
+
+# Creating and setting a working directory for following commands.
+WORKDIR /opt/ignite
+
+# Copying local Apache Ignite build to the docker image.
+COPY ./apache-ignite-fabric-lgpl-${IGNITE_VERSION}-bin.zip apache-ignite-fabric-lgpl-${IGNITE_VERSION}-bin.zip
+
+# Unpacking the build.
+RUN unzip apache-ignite-fabric-lgpl-${IGNITE_VERSION}-bin.zip
+RUN rm apache-ignite-fabric-lgpl-${IGNITE_VERSION}-bin.zip
+
+# Copying the executable file and setting permissions.
+COPY ./run.sh $IGNITE_HOME/
+RUN chmod +x $IGNITE_HOME/run.sh
+
+# Copying the configuration.
+COPY ./example-kube.xml $IGNITE_HOME/config
+
+# Starting an Apache Ignite node.
+CMD $IGNITE_HOME/run.sh
+
+# Exposing the ports.
+EXPOSE 11211 47100 47500 49112
+
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/config/example-kube.xml
----------------------------------------------------------------------
diff --git a/modules/kubernetes/config/example-kube.xml b/modules/kubernetes/config/example-kube.xml
new file mode 100644
index 0000000..bc04463
--- /dev/null
+++ b/modules/kubernetes/config/example-kube.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+
+<!--
+ Configuration example with Kubernetes IP finder enabled.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+
+ <!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
+ <property name="discoverySpi">
+ <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+ <property name="ipFinder">
+ <!--
+ Enables Kubernetes IP finder with default settings.
+ -->
+ <bean
+ class="org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes.TcpDiscoveryKubernetesIpFinder"/>
+ </property>
+ </bean>
+ </property>
+ </bean>
+</beans>
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/config/ignite-deployment.yaml
----------------------------------------------------------------------
diff --git a/modules/kubernetes/config/ignite-deployment.yaml b/modules/kubernetes/config/ignite-deployment.yaml
new file mode 100644
index 0000000..ed5c102
--- /dev/null
+++ b/modules/kubernetes/config/ignite-deployment.yaml
@@ -0,0 +1,26 @@
+# An example of a Kubernetes configuration for Ignite pods deployment.
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ # Custom Ignite cluster's name.
+ name: ignite-cluster
+spec:
+ # Number of nodes to be started by Kubernetes initially.
+ replicas: 2
+ template:
+ metadata:
+ labels:
+ # Must be equal to Ignite's Kubernetes service name.
+ app: ignite
+ spec:
+ containers:
+ # Custom Ignite node's pod name.
+ - name: ignite-node
+ # Custom Ignite Docker image name.
+ image: ignite-kube:v1
+ ports:
+ # Ports to open.
+ - containerPort: 11211 # REST port number.
+ - containerPort: 47100 # communication SPI port number.
+ - containerPort: 47500 # discovery SPI port number.
+ - containerPort: 49112 # JMX port number.
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/config/ignite-service.yaml
----------------------------------------------------------------------
diff --git a/modules/kubernetes/config/ignite-service.yaml b/modules/kubernetes/config/ignite-service.yaml
new file mode 100644
index 0000000..07b7516
--- /dev/null
+++ b/modules/kubernetes/config/ignite-service.yaml
@@ -0,0 +1,14 @@
+# An example of a Kubernetes configuration for Ignite lookup service deployment.
+apiVersion: v1
+kind: Service
+metadata:
+ # Name of Ignite Service used by Kubernetes IP finder for IP addresses lookup.
+ # The name must be equal to TcpDiscoveryKubernetesIpFinder.setServiceName parameter.
+ name: ignite
+spec:
+ clusterIP: None
+ ports:
+ - port: 9042 # some custom port (optional).
+ selector:
+ # Must be equal to the label set for Ignite pods.
+ app: ignite
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/config/run.sh
----------------------------------------------------------------------
diff --git a/modules/kubernetes/config/run.sh b/modules/kubernetes/config/run.sh
new file mode 100644
index 0000000..dbf2871
--- /dev/null
+++ b/modules/kubernetes/config/run.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+if [ ! -z "$OPTION_LIBS" ]; then
+ IFS=, LIBS_LIST=("$OPTION_LIBS")
+
+ for lib in ${LIBS_LIST[@]}; do
+ cp -r $IGNITE_HOME/libs/optional/"$lib"/* \
+ $IGNITE_HOME/libs/
+ done
+fi
+
+if [ ! -z "$EXTERNAL_LIBS" ]; then
+ IFS=, LIBS_LIST=("$EXTERNAL_LIBS")
+
+ for lib in ${LIBS_LIST[@]}; do
+ echo $lib >> temp
+ done
+
+ wget -i temp -P $IGNITE_HOME/libs
+
+ rm temp
+fi
+
+QUIET=""
+
+if [ "$IGNITE_QUIET" = "false" ]; then
+ QUIET="-v"
+fi
+
+if [ -z $CONFIG_URI ]; then
+ $IGNITE_HOME/bin/ignite.sh $QUIET
+else
+ $IGNITE_HOME/bin/ignite.sh $QUIET $CONFIG_URI
+fi
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/licenses/apache-2.0.txt
----------------------------------------------------------------------
diff --git a/modules/kubernetes/licenses/apache-2.0.txt b/modules/kubernetes/licenses/apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/kubernetes/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/pom.xml
----------------------------------------------------------------------
diff --git a/modules/kubernetes/pom.xml b/modules/kubernetes/pom.xml
new file mode 100644
index 0000000..5d4e5f0
--- /dev/null
+++ b/modules/kubernetes/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+
+<!--
+ POM file.
+-->
+<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">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-parent</artifactId>
+ <version>1</version>
+ <relativePath>../../parent</relativePath>
+ </parent>
+
+ <artifactId>ignite-kubernetes</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <url>http://ignite.apache.org</url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-core</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinder.java
----------------------------------------------------------------------
diff --git a/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinder.java b/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinder.java
new file mode 100644
index 0000000..a5bd24f
--- /dev/null
+++ b/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinder.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes;
+
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.resources.LoggerResource;
+import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinderAdapter;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.ObjectMapper;
+
+/**
+ * IP finder for automatic lookup of Ignite nodes running in Kubernetes environment. All Ignite nodes have to deployed
+ * as Kubernetes pods in order to be discovered. An application that uses Ignite client nodes as a gateway to the
+ * cluster is required to be containerized as well. Applications and Ignite nodes running outside of Kubernetes will
+ * not be able to reach the containerized counterparts.
+ * <p>
+ * The implementation is based on a dedicated Kubernetes service that has to be created and should be deployed prior
+ * Ignite nodes startup. The service will maintain a list of all endpoints (internal IP addresses) of all containerized
+ * Ignite pods running so far. The name of the service must be equal to {@link #setServiceName(String)} which is
+ * `ignite` by default.
+ * <p>
+ * As for Ignite pods, it's recommended to label them in such a way that the service will use the label in its selector
+ * configuration excluding endpoints of irrelevant Kubernetes pods running in parallel.
+ * <p>
+ * The IP finder, in its turn, will call this service to retrieve Ignite pods IP addresses. The port will be
+ * either the one that is set with {@link TcpDiscoverySpi#setLocalPort(int)} or {@link TcpDiscoverySpi#DFLT_PORT}.
+ * Make sure that all Ignite pods occupy a similar discovery port, otherwise they will not be able to discover each
+ * other using this IP finder.
+ * <h2 class="header">Optional configuration</h2>
+ * <ul>
+ * <li>The Kubernetes service name for IP addresses lookup (see {@link #setServiceName(String)})</li>
+ * <li>The Kubernetes service namespace for IP addresses lookup (see {@link #setNamespace(String)}</li>
+ * <li>The host name of the Kubernetes API server (see {@link #setMasterUrl(String)})</li>
+ * <li>Path to the service token (see {@link #setAccountToken(String)}</li>
+ * </ul>
+ * <p>
+ * Both {@link #registerAddresses(Collection)} and {@link #unregisterAddresses(Collection)} have no effect.
+ * <p>
+ * Note, this IP finder is only workable when it used in Kubernetes environment.
+ * Choose another implementation of {@link org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder} for local
+ * or home network tests.
+ */
+public class TcpDiscoveryKubernetesIpFinder extends TcpDiscoveryIpFinderAdapter {
+ /** Grid logger. */
+ @LoggerResource
+ private IgniteLogger log;
+
+ /** Init routine guard. */
+ private final AtomicBoolean initGuard = new AtomicBoolean();
+
+ /** Init routine latch. */
+ private final CountDownLatch initLatch = new CountDownLatch(1);
+
+ /** Trust manager. */
+ private TrustManager[] trustAll = new TrustManager[] {
+ new X509TrustManager() {
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
+ public X509Certificate[] getAcceptedIssuers() { return null; }
+ }
+ };
+
+ /** Host verifier. */
+ private HostnameVerifier trustAllHosts = new HostnameVerifier() {
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ };
+
+ /** Ignite's Kubernetes Service name. */
+ private String serviceName = "ignite";
+
+ /** Ignite Pod setNamespace name. */
+ private String namespace = "default";
+
+ /** Kubernetes API server URL in a string form. */
+ private String master = "https://kubernetes.default.svc.cluster.local:443";
+
+ /** Account token location. */
+ private String accountToken = "/var/run/secrets/kubernetes.io/serviceaccount/token";
+
+ /** Kubernetes API server URL. */
+ private URL url;
+
+ /** SSL context */
+ private SSLContext ctx;
+
+ /**
+ * Creates an instance of Kubernetes IP finder.
+ */
+ public TcpDiscoveryKubernetesIpFinder() {
+ setShared(true);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<InetSocketAddress> getRegisteredAddresses() throws IgniteSpiException {
+ init();
+
+ Collection<InetSocketAddress> addrs = new ArrayList<>();
+
+ try {
+ System.out.println("Getting Apache Ignite endpoints from: " + url);
+
+ HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
+
+ conn.setHostnameVerifier(trustAllHosts);
+
+ conn.setSSLSocketFactory(ctx.getSocketFactory());
+ conn.addRequestProperty("Authorization", "Bearer " + serviceAccountToken(accountToken));
+
+ // Sending the request and processing a response.
+ ObjectMapper mapper = new ObjectMapper();
+
+ Endpoints endpoints = mapper.readValue(conn.getInputStream(), Endpoints.class);
+
+ if (endpoints != null) {
+ if (endpoints.subsets != null && !endpoints.subsets.isEmpty()) {
+ for (Subset subset : endpoints.subsets) {
+
+ if (subset.addresses != null && !subset.addresses.isEmpty()) {
+ for (Address address : subset.addresses) {
+ addrs.add(new InetSocketAddress(address.ip, 0));
+
+ System.out.println("Added an address to the list: " + address.ip);
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (Exception e) {
+ throw new IgniteSpiException("Failed to retrieve Ignite pods IP addresses.", e);
+ }
+
+ return addrs;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void registerAddresses(Collection<InetSocketAddress> addrs) throws IgniteSpiException {
+ // No-op
+ }
+
+ /** {@inheritDoc} */
+ @Override public void unregisterAddresses(Collection<InetSocketAddress> addrs) throws IgniteSpiException {
+ // No-op
+ }
+
+ /**
+ * Sets the name of Kubernetes service for Ignite pods' IP addresses lookup. The name of the service must be equal
+ * to the name set in service's Kubernetes configuration. If this parameter is not changed then the name of the
+ * service has to be set to 'ignite' in the corresponding Kubernetes configuration.
+ *
+ * @param service Kubernetes service name for IP addresses lookup. If it's not set then 'ignite' is used by default.
+ */
+ public void setServiceName(String service) {
+ this.serviceName = service;
+ }
+
+ /**
+ * Sets the namespace the Kubernetes service belongs to. By default, it's supposed that the service is running under
+ * Kubernetes `default` namespace.
+ *
+ * @param namespace The Kubernetes service namespace for IP addresses lookup.
+ */
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ /**
+ * Sets the host name of the Kubernetes API server. By default the following host name is used:
+ * 'https://kubernetes.default.svc.cluster.local:443'.
+ *
+ * @param master The host name of the Kubernetes API server.
+ */
+ public void setMasterUrl(String master) {
+ this.master = master;
+ }
+
+ /**
+ * Specifies the path to the service token file. By default the following account token is used:
+ * '/var/run/secrets/kubernetes.io/serviceaccount/token'.
+ *
+ * @param accountToken The path to the service token file.
+ */
+ public void setAccountToken(String accountToken) {
+ this.accountToken = accountToken;
+ }
+
+ /**
+ * Kubernetes IP finder initialization.
+ *
+ * @throws IgniteSpiException In case of error.
+ */
+ private void init() throws IgniteSpiException {
+ if (initGuard.compareAndSet(false, true)) {
+
+ if (serviceName == null || serviceName.isEmpty() ||
+ namespace == null || namespace.isEmpty() ||
+ master == null || master.isEmpty() ||
+ accountToken == null || accountToken.isEmpty()) {
+ throw new IgniteSpiException(
+ "One or more configuration parameters are invalid [setServiceName=" +
+ serviceName + ", setNamespace=" + namespace + ", setMasterUrl=" +
+ master + ", setAccountToken=" + accountToken + "]");
+ }
+
+ try {
+ // Preparing the URL and SSL context to be used for connection purposes.
+ String path = String.format("/api/v1/namespaces/%s/endpoints/%s", namespace, serviceName);
+
+ url = new URL(master + path);
+
+ ctx = SSLContext.getInstance("SSL");
+
+ ctx.init(null, trustAll, new SecureRandom());
+ }
+ catch (Exception e) {
+ throw new IgniteSpiException("Failed to connect to Ignite's Kubernetes Service.", e);
+ }
+ finally {
+ initLatch.countDown();
+ }
+ }
+ else {
+ try {
+ U.await(initLatch);
+ }
+ catch (IgniteInterruptedCheckedException e) {
+ throw new IgniteSpiException("Thread has been interrupted.", e);
+ }
+
+ if (url == null || ctx == null)
+ throw new IgniteSpiException("IP finder has not been initialized properly.");
+ }
+ }
+
+ /**
+ * Reads content of the service account token file.
+ *
+ * @param file The path to the service account token.
+ * @return Service account token.
+ */
+ private String serviceAccountToken(String file) {
+ try {
+ return new String(Files.readAllBytes(Paths.get(file)));
+ } catch (IOException e) {
+ throw new IgniteSpiException("Failed to load services account token [setAccountToken= " + file + "]", e);
+ }
+ }
+
+ /**
+ * Object used by Jackson for processing of Kubernetes lookup service's response.
+ */
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ private static class Address {
+ /** */
+ public String ip;
+ }
+
+ /**
+ * Object used by Jackson for processing of Kubernetes lookup service's response.
+ */
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ private static class Subset {
+ /** */
+ public List<Address> addresses;
+ }
+
+ /**
+ * Object used by Jackson for processing of Kubernetes lookup service's response.
+ */
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ private static class Endpoints {
+ /** */
+ public List<Subset> subsets;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java
----------------------------------------------------------------------
diff --git a/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java b/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java
new file mode 100644
index 0000000..a572cb2
--- /dev/null
+++ b/modules/kubernetes/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/**
+ * <!-- Package description. -->
+ * Contains Kubernetes IP finder implementation.
+ */
+package org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinderSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinderSelfTest.java b/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinderSelfTest.java
new file mode 100644
index 0000000..fd3e2a3
--- /dev/null
+++ b/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/TcpDiscoveryKubernetesIpFinderSelfTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes;
+
+import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinderAbstractSelfTest;
+
+/**
+ * TcpDiscoveryKubernetesIpFinder test.
+ */
+public class TcpDiscoveryKubernetesIpFinderSelfTest extends
+ TcpDiscoveryIpFinderAbstractSelfTest<TcpDiscoveryKubernetesIpFinder> {
+ /**
+ * Constructor.
+ *
+ * @throws Exception If any error occurs.
+ */
+ public TcpDiscoveryKubernetesIpFinderSelfTest() throws Exception {
+ // No-op.
+ }
+
+ @Override protected void beforeTest() throws Exception {
+ // No-op.
+ }
+
+ /* {@inheritDoc} */
+ @Override protected TcpDiscoveryKubernetesIpFinder ipFinder() throws Exception {
+ // No-op.
+ return null;
+ }
+
+ /* {@inheritDoc} */
+ @Override public void testIpFinder() throws Exception {
+ TcpDiscoveryKubernetesIpFinder ipFinder = new TcpDiscoveryKubernetesIpFinder();
+
+ ipFinder.setAccountToken(null);
+
+ try {
+ ipFinder.getRegisteredAddresses();
+ }
+ catch (IgniteSpiException e) {
+ assertTrue(e.getMessage().startsWith("One or more configuration parameters are invalid"));
+ }
+
+ ipFinder = new TcpDiscoveryKubernetesIpFinder();
+
+ ipFinder.setMasterUrl(null);
+
+ try {
+ ipFinder.getRegisteredAddresses();
+ }
+ catch (IgniteSpiException e) {
+ assertTrue(e.getMessage().startsWith("One or more configuration parameters are invalid"));
+ }
+
+ ipFinder = new TcpDiscoveryKubernetesIpFinder();
+
+ ipFinder.setNamespace(null);
+
+ try {
+ ipFinder.getRegisteredAddresses();
+ }
+ catch (IgniteSpiException e) {
+ assertTrue(e.getMessage().startsWith("One or more configuration parameters are invalid"));
+ }
+
+ ipFinder = new TcpDiscoveryKubernetesIpFinder();
+
+ ipFinder.setServiceName("");
+
+ try {
+ ipFinder.getRegisteredAddresses();
+ }
+ catch (IgniteSpiException e) {
+ assertTrue(e.getMessage().startsWith("One or more configuration parameters are invalid"));
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java
----------------------------------------------------------------------
diff --git a/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java b/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java
new file mode 100644
index 0000000..83ab56f
--- /dev/null
+++ b/modules/kubernetes/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/kubernetes/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/**
+ * <!-- Package description. -->
+ * Contains Kubernetes IP finder internal tests.
+ */
+package org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/modules/kubernetes/src/test/java/org/apache/ignite/testsuites/IgniteKubernetesTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/kubernetes/src/test/java/org/apache/ignite/testsuites/IgniteKubernetesTestSuite.java b/modules/kubernetes/src/test/java/org/apache/ignite/testsuites/IgniteKubernetesTestSuite.java
new file mode 100644
index 0000000..540657e
--- /dev/null
+++ b/modules/kubernetes/src/test/java/org/apache/ignite/testsuites/IgniteKubernetesTestSuite.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.testsuites;
+
+
+import junit.framework.TestSuite;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes.TcpDiscoveryKubernetesIpFinderSelfTest;
+import org.apache.ignite.testframework.IgniteTestSuite;
+
+/**
+ * Ignite Kubernetes integration test.
+ */
+public class IgniteKubernetesTestSuite extends TestSuite {
+ /**
+ * @return Test suite.
+ * @throws Exception Thrown in case of the failure.
+ */
+ public static TestSuite suite() throws Exception {
+ TestSuite suite = new IgniteTestSuite("Kubernetes Integration Test Suite");
+
+ // Cloud Nodes IP finder.
+ suite.addTestSuite(TcpDiscoveryKubernetesIpFinderSelfTest.class);
+
+ return suite;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/37c0a220/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index ea76053..238361b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,6 +88,7 @@
<module>modules/web/ignite-websphere-test</module>
<module>modules/cassandra</module>
<module>modules/flink</module>
+ <module>modules/kubernetes</module>
</modules>
<profiles>