You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2015/01/18 19:28:06 UTC

[1/2] karaf-cellar git commit: Improve jclouds service registration

Repository: karaf-cellar
Updated Branches:
  refs/heads/master 7a598b285 -> 7ec918a08


Improve jclouds service registration


Project: http://git-wip-us.apache.org/repos/asf/karaf-cellar/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf-cellar/commit/a27f5149
Tree: http://git-wip-us.apache.org/repos/asf/karaf-cellar/tree/a27f5149
Diff: http://git-wip-us.apache.org/repos/asf/karaf-cellar/diff/a27f5149

Branch: refs/heads/master
Commit: a27f5149974f68844ea69f8a2a32d35e4d980cb2
Parents: 7a598b2
Author: Jean-Baptiste Onofré <jb...@apache.org>
Authored: Sun Jan 18 19:27:18 2015 +0100
Committer: Jean-Baptiste Onofré <jb...@apache.org>
Committed: Sun Jan 18 19:27:18 2015 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/karaf/cellar/cloud/Activator.java  | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/a27f5149/cloud/src/main/java/org/apache/karaf/cellar/cloud/Activator.java
----------------------------------------------------------------------
diff --git a/cloud/src/main/java/org/apache/karaf/cellar/cloud/Activator.java b/cloud/src/main/java/org/apache/karaf/cellar/cloud/Activator.java
index 8c020cb..b8f253a 100644
--- a/cloud/src/main/java/org/apache/karaf/cellar/cloud/Activator.java
+++ b/cloud/src/main/java/org/apache/karaf/cellar/cloud/Activator.java
@@ -16,6 +16,7 @@ package org.apache.karaf.cellar.cloud;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ManagedServiceFactory;
 
 import java.util.Hashtable;
@@ -25,17 +26,21 @@ import java.util.Hashtable;
  */
 public class Activator implements BundleActivator {
 
+    private ServiceRegistration serviceRegistration;
+
     @Override
     public void start(BundleContext context) throws Exception {
         Hashtable<String, Object> properties = new Hashtable<String, Object>();
         properties.put(Constants.SERVICE_PID, "org.apache.karaf.cellar.cloud");
         BlobStoreDiscoveryServiceFactory blobStoreDiscoveryServiceFactory = new BlobStoreDiscoveryServiceFactory(context);
-        context.registerService(ManagedServiceFactory.class.getName(), blobStoreDiscoveryServiceFactory, properties);
+        serviceRegistration = context.registerService(ManagedServiceFactory.class.getName(), blobStoreDiscoveryServiceFactory, properties);
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        // nothing to do
+        if (serviceRegistration != null) {
+            serviceRegistration.unregister();
+        }
     }
 
 }
\ No newline at end of file


[2/2] karaf-cellar git commit: [KARAF-3447] Add kubernetes discovery service

Posted by jb...@apache.org.
[KARAF-3447] Add kubernetes discovery service


Project: http://git-wip-us.apache.org/repos/asf/karaf-cellar/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf-cellar/commit/7ec918a0
Tree: http://git-wip-us.apache.org/repos/asf/karaf-cellar/tree/7ec918a0
Diff: http://git-wip-us.apache.org/repos/asf/karaf-cellar/diff/7ec918a0

Branch: refs/heads/master
Commit: 7ec918a08faa3c40be9a5236c96aa26c23a6be9e
Parents: a27f514
Author: Jean-Baptiste Onofré <jb...@apache.org>
Authored: Sun Jan 18 19:27:34 2015 +0100
Committer: Jean-Baptiste Onofré <jb...@apache.org>
Committed: Sun Jan 18 19:27:34 2015 +0100

----------------------------------------------------------------------
 assembly/pom.xml                                |   5 +
 assembly/src/main/resources/features.xml        |  10 ++
 assembly/src/main/resources/kubernetes.cfg      |   5 +
 kubernetes/NOTICE                               |  39 ++++++
 kubernetes/pom.xml                              |  88 +++++++++++++
 .../karaf/cellar/kubernetes/Activator.java      |  43 ++++++
 .../kubernetes/KubernetesDiscoveryService.java  | 130 +++++++++++++++++++
 .../KubernetesDiscoveryServiceFactory.java      | 102 +++++++++++++++
 manual/src/main/webapp/user-guide/cloud.conf    |  67 +++++++++-
 manual/src/main/webapp/user-guide/index.conf    |   2 +-
 pom.xml                                         |   9 ++
 11 files changed, 493 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/assembly/pom.xml
----------------------------------------------------------------------
diff --git a/assembly/pom.xml b/assembly/pom.xml
index 5b3d8b2..9c1b517 100644
--- a/assembly/pom.xml
+++ b/assembly/pom.xml
@@ -95,6 +95,11 @@
                                     <type>xml</type>
                                     <classifier>hazelcast</classifier>
                                 </artifact>
+                                <artifact>
+                                    <file>target/classes/kubernetes.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>kubernetes</classifier>
+                                </artifact>
                             </artifacts>
                         </configuration>
                     </execution>

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/assembly/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/features.xml b/assembly/src/main/resources/features.xml
index ddefc52..f66c05f 100644
--- a/assembly/src/main/resources/features.xml
+++ b/assembly/src/main/resources/features.xml
@@ -16,6 +16,7 @@
 <features name="karaf-cellar-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
 
     <repository>mvn:org.apache.jclouds.karaf/jclouds-karaf/${jclouds.version}/xml/features</repository>
+    <repository>mvn:io.fabric8/karaf-features/${fabric8.version}/xml/features</repository>
     
     <feature name="cellar-core" description="Karaf clustering core" version="${project.version}" resolver="(obr)">
         <configfile finalname="/etc/org.apache.karaf.cellar.groups.cfg">
@@ -97,6 +98,15 @@
         <bundle>mvn:org.apache.karaf.cellar/org.apache.karaf.cellar.cloud/${project.version}</bundle>
     </feature>
 
+    <feature name="cellar-kubernetes" description="Cellar kubernetes support in clusters" version="${project.version}" resolver="(obr)">
+        <configfile finalname="/etc/org.apache.karaf.cellar.kubernetes.cfg">
+            mvn:org.apache.karaf.cellar/apache-karaf-cellar/${project.version}/cfg/kubernetes
+        </configfile>
+        <feature version="${project.version}">cellar-core</feature>
+        <feature>fabric8-kubernetes-api</feature>
+        <bundle>mvn:org.apache.karaf.cellar/org.apache.karaf.cellar.kubernetes/${project.version}</bundle>
+    </feature>
+
     <feature name="cellar-webconsole" description="Cellar plugin for Karaf WebConsole" version="${project.version}" resolver="(obr)">
         <feature version="${project.version}">cellar</feature>
         <feature>webconsole</feature>

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/assembly/src/main/resources/kubernetes.cfg
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/kubernetes.cfg b/assembly/src/main/resources/kubernetes.cfg
new file mode 100644
index 0000000..9e83ff8
--- /dev/null
+++ b/assembly/src/main/resources/kubernetes.cfg
@@ -0,0 +1,5 @@
+#
+# Label selector used to idenfity Cellar nodes in Kubernetes cluster
+#
+pod.label.key = name
+pod.label.value = cellar
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/kubernetes/NOTICE
----------------------------------------------------------------------
diff --git a/kubernetes/NOTICE b/kubernetes/NOTICE
new file mode 100644
index 0000000..addb35c
--- /dev/null
+++ b/kubernetes/NOTICE
@@ -0,0 +1,39 @@
+Apache Karaf Cellar
+Copyright 2011-2014 The Apache Software Foundation
+
+I. Used Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Hazelcast (http://www.hazelcast.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JClouds (http://www.jclouds.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+II. License Summary
+- Apache License 2.0
+- MIT License

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/kubernetes/pom.xml
----------------------------------------------------------------------
diff --git a/kubernetes/pom.xml b/kubernetes/pom.xml
new file mode 100644
index 0000000..aa78931
--- /dev/null
+++ b/kubernetes/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf</groupId>
+        <artifactId>cellar</artifactId>
+        <version>3.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.karaf.cellar</groupId>
+    <artifactId>org.apache.karaf.cellar.kubernetes</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Cellar :: Kubernetes</name>
+
+    <dependencies>
+
+        <!-- Internal Dependencies -->
+        <dependency>
+            <groupId>org.apache.karaf.cellar</groupId>
+            <artifactId>org.apache.karaf.cellar.core</artifactId>
+        </dependency>
+
+        <!-- Fabric8 Kubernetes API Dependencies -->
+        <dependency>
+            <groupId>io.fabric8</groupId>
+            <artifactId>kubernetes-api</artifactId>
+        </dependency>
+
+        <!-- OSGi -->
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.cellar.kubernetes.*;version="${project.version}"
+                        </Export-Package>
+                        <Import-Package>
+                            io.fabric8.kubernetes.api;version="${fabric8.version}",
+                            org.apache.karaf.cellar.core*;version="${project.version}",
+                            org.osgi*,
+                            org.slf4j;version="[1.6,2)";resolution:=optional
+                        </Import-Package>
+                        <DynamicImport-Package>javax.*,org.w3c.*,org.xml.*,io.fabric8.*,*</DynamicImport-Package>
+                        <Bundle-Activator>org.apache.karaf.cellar.kubernetes.Activator</Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/Activator.java
----------------------------------------------------------------------
diff --git a/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/Activator.java b/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/Activator.java
new file mode 100644
index 0000000..7769668
--- /dev/null
+++ b/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/Activator.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+package org.apache.karaf.cellar.kubernetes;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+import java.util.Hashtable;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration serviceRegistration;
+
+    @Override
+    public void start(BundleContext bundleContext) throws Exception {
+        Hashtable<String, Object> properties = new Hashtable<String, Object>();
+        properties.put(Constants.SERVICE_PID, "org.apache.karaf.cellar.kubernetes");
+        KubernetesDiscoveryServiceFactory kubernetesDiscoveryServiceFactory = new KubernetesDiscoveryServiceFactory(bundleContext);
+        serviceRegistration = bundleContext.registerService(ManagedServiceFactory.class.getName(), kubernetesDiscoveryServiceFactory, properties);
+    }
+
+    public void stop(BundleContext bundleContext) throws Exception {
+        if (serviceRegistration != null) {
+            serviceRegistration.unregister();
+            serviceRegistration = null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryService.java
----------------------------------------------------------------------
diff --git a/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryService.java b/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryService.java
new file mode 100644
index 0000000..40216d8
--- /dev/null
+++ b/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryService.java
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+package org.apache.karaf.cellar.kubernetes;
+
+import io.fabric8.kubernetes.api.KubernetesClient;
+import io.fabric8.kubernetes.api.KubernetesFactory;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.PodList;
+import org.apache.karaf.cellar.core.discovery.DiscoveryService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Discovery service that uses the Kubernetes API to discover Cellar nodes.
+ */
+public class KubernetesDiscoveryService implements DiscoveryService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(KubernetesDiscoveryService.class);
+
+    private String kubernetesHost;
+    private String kubernetesPort;
+    private String kubernetesPodLabelKey;
+    private String kubernetesPodLabelValue;
+
+    private KubernetesClient kubernetesClient;
+
+    public KubernetesDiscoveryService() {
+        LOGGER.debug("CELLAR KUBERNETES: create discovery service");
+    }
+
+    public void init() {
+        try {
+            String kubernetesUrl = "http://" + kubernetesHost + ":" + kubernetesPort;
+            LOGGER.debug("CELLAR KUBERNETES: query API at {} ...", kubernetesUrl);
+            kubernetesClient = new KubernetesClient(new KubernetesFactory(kubernetesUrl));
+            LOGGER.debug("CELLAR KUBERNETES: discovery service initalized");
+        } catch (Exception e) {
+            LOGGER.error("CELLAR KUBERNETES: can't init discovery service", e);
+        }
+    }
+
+    public void destroy() {
+        LOGGER.debug("CELLAR KUBERNETES: destroy discovery service");
+    }
+
+    public void update(Map<String, Object> properties) {
+        LOGGER.debug("CELLAR KUBERNETES: update properties");
+    }
+
+    @Override
+    public Set<String> discoverMembers() {
+        LOGGER.debug("CELLAR KUBERNETES: query pods with labeled with [{}={}]", kubernetesPodLabelKey, kubernetesPodLabelValue);
+        Set<String> members = new HashSet<String>();
+        try {
+            PodList podList = kubernetesClient.getPods();
+            for (Pod pod : podList.getItems()) {
+                String value = pod.getLabels().get(kubernetesPodLabelKey);
+                if (value != null && !value.isEmpty()) {
+                    members.add(pod.getCurrentState().getPodIP());
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.error("CELLAR KUBERNETES: can't get pods", e);
+        }
+        return members;
+    }
+
+    @Override
+    public void signIn() {
+        // nothing to do for Kubernetes
+    }
+
+    @Override
+    public void refresh() {
+        // nothing to do for Kubernetes
+    }
+
+    @Override
+    public void signOut() {
+        // nothing to do for Kubernetes
+    }
+
+    public String getKubernetesHost() {
+        return kubernetesHost;
+    }
+
+    public void setKubernetesHost(String kubernetesHost) {
+        this.kubernetesHost = kubernetesHost;
+    }
+
+    public String getKubernetesPort() {
+        return kubernetesPort;
+    }
+
+    public void setKubernetesPort(String kubernetesPort) {
+        this.kubernetesPort = kubernetesPort;
+    }
+
+    public String getKubernetesPodLabelKey() {
+        return kubernetesPodLabelKey;
+    }
+
+    public void setKubernetesPodLabelKey(String kubernetesPodLabelKey) {
+        this.kubernetesPodLabelKey = kubernetesPodLabelKey;
+    }
+
+    public String getKubernetesPodLabelValue() {
+        return kubernetesPodLabelValue;
+    }
+
+    public void setKubernetesPodLabelValue(String kubernetesPodLabelValue) {
+        this.kubernetesPodLabelValue = kubernetesPodLabelValue;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryServiceFactory.java
----------------------------------------------------------------------
diff --git a/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryServiceFactory.java b/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryServiceFactory.java
new file mode 100644
index 0000000..054948b
--- /dev/null
+++ b/kubernetes/src/main/java/org/apache/karaf/cellar/kubernetes/KubernetesDiscoveryServiceFactory.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+package org.apache.karaf.cellar.kubernetes;
+
+import org.apache.karaf.cellar.core.discovery.DiscoveryService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A factory for Kubernetes discovery services.
+ */
+public class KubernetesDiscoveryServiceFactory implements ManagedServiceFactory {
+
+    private static String getEnvOrDefault(String var, String def) {
+        final String val = System.getenv(var);
+        return val == null ? def : val;
+    }
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(KubernetesDiscoveryServiceFactory.class);
+
+    private static final String KUBERNETES_POD_LABEL_KEY = "pod.label.key";
+    private static final String KUBERNETES_POD_LABEL_VALUE = "pod.label.value";
+
+    private final Map<String, ServiceRegistration> registrations = new ConcurrentHashMap<String, ServiceRegistration>();
+
+    private final BundleContext bundleContext;
+
+    public KubernetesDiscoveryServiceFactory(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public String getName() {
+        return "CELLAR KUBERNETES: discovery service factory";
+    }
+
+    @Override
+    public void updated(String pid, Dictionary properties) throws ConfigurationException {
+        ServiceRegistration newServiceRegistration = null;
+        try {
+            if (properties != null) {
+                Properties serviceProperties = new Properties();
+                for (Map.Entry entry : serviceProperties.entrySet()) {
+                    Object key = entry.getKey();
+                    Object value = entry.getValue();
+                    serviceProperties.put(key, value);
+                }
+
+                KubernetesDiscoveryService kubernetesDiscoveryService = new KubernetesDiscoveryService();
+
+                String kubernetesHost = getEnvOrDefault("KUBERNETES_RO_SERVICE_HOST", "localhost");
+                String kubernetesPort = getEnvOrDefault("KUBERNETES_RO_SERVICE_PORT", "8080");
+                String kubernetesPodLabelKey = (String) properties.get(KUBERNETES_POD_LABEL_KEY);
+                String kubernetesPodLabelValue = (String) properties.get(KUBERNETES_POD_LABEL_VALUE);
+
+                kubernetesDiscoveryService.setKubernetesHost(kubernetesHost);
+                kubernetesDiscoveryService.setKubernetesPort(kubernetesPort);
+                kubernetesDiscoveryService.setKubernetesPodLabelKey(kubernetesPodLabelKey);
+                kubernetesDiscoveryService.setKubernetesPodLabelValue(kubernetesPodLabelValue);
+                kubernetesDiscoveryService.init();
+
+                newServiceRegistration = bundleContext.registerService(DiscoveryService.class.getName(), kubernetesDiscoveryService, (Dictionary) serviceProperties);
+            }
+        } finally {
+            ServiceRegistration oldServiceRegistration = (newServiceRegistration == null) ? registrations.remove(pid) : registrations.put(pid, newServiceRegistration);
+            if (oldServiceRegistration != null) {
+                LOGGER.debug("CELLAR KUBERNETES: unregister discovery service {}", pid);
+                oldServiceRegistration.unregister();
+            }
+        }
+    }
+
+    @Override
+    public void deleted(String pid) {
+        LOGGER.debug("CELLAR KUBERNETES: delete discovery service {}", pid);
+        ServiceRegistration oldServiceRegistration = registrations.remove(pid);
+        if (oldServiceRegistration != null) {
+            oldServiceRegistration.unregister();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/manual/src/main/webapp/user-guide/cloud.conf
----------------------------------------------------------------------
diff --git a/manual/src/main/webapp/user-guide/cloud.conf b/manual/src/main/webapp/user-guide/cloud.conf
index 95539ac..67a2ca6 100644
--- a/manual/src/main/webapp/user-guide/cloud.conf
+++ b/manual/src/main/webapp/user-guide/cloud.conf
@@ -1,17 +1,23 @@
-h1. Cellar cloud discovery
+h1. Discovery Services
+
+The Discovery Services allow you to use third party libraries to discover the nodes member of the Cellar cluster.
+
+h2. jClouds
+
+Cellar relies on Hazelcast (http://www.hazelcast.com) in order to discover cluster nodes. This can happen either by using unicast, multicast  or specifying the ip address of each node.
+See the [Core Configuration|hazelcast] section for details.
 
-Cellar relies on Hazelcast (http://www.hazelcast.com) in order to discover cluster nodes. This can happen either by using multicast or by unicast (specifying the ip address of each node).
 Unfortunately multicast is not allowed in most IaaS providers and the alternative of specifying all IP addresses creates maintenance difficulties, especially since in most cases the addresses are not known in advance.
 
-Cellar solves this problem using a cloud discovery service powered by jclouds (http://www.jclouds.org).
+Cellar solves this problem using a cloud discovery service powered by jclouds (http://jclouds.apache.org).
 
-h2. Cloud discovery service
+h3. Cloud discovery service
 
 Most cloud providers provide cloud storage among other services. Cellar uses the cloud storage via jclouds, in order to determine the IP addresses of each node so that Hazelcast can find them.
 
 This approach is also called blackboard and refers to the process where each node registers itself in a common storage are so that other nodes know its existence.
 
-h2. Installing Cellar cloud discovery service
+h3. Installing Cellar cloud discovery service
 
 To install the cloud discovery service simply install the appropriate jclouds provider and then install cellar-cloud feature.
 Amazon S3 is being used here for this example, but the below applies to any provider supported by jclouds.
@@ -30,4 +36,53 @@ credential=<the credential/password of the blobstore account)
 container=<the name of the bucket>
 validity=<the amount of time an entry is considered valid, after that time the entry is removed>
 
-After creating the file the service will check for new nodes. If new nodes are found the Hazelcast instance configuration will be updated and the instance restarted.
\ No newline at end of file
+After creating the file the service will check for new nodes. If new nodes are found the Hazelcast instance configuration will be updated and the instance restarted.
+
+h2. Kubernetes & docker.io
+
+[Kubernetes|http://kubernetes.io] is an open source orchestration system for docker.io containers.
+It handles scheduling onto nodes in a compute cluster and actively manages workloads to ensure that their state matches
+the users declared intentions.
+Using the concepts of "labels", "pods", "replicationControllers" and "services", it groups the containers which make up
+an application into logical units for easy management and discovery.
+Following the aforementioned concept will most likely change how you package and provision your Karaf based applications.
+For instance, you will eventually have to provide a Docker image with a pre-configured Karaf, KAR files in deployment
+folder, etc. so that your Kubernetes container may bootstrap everything on boot.
+
+The Cellar Kubernetes discovery service is a great complement to the Karaf docker.io feature (allowing you to easily
+create and manage docker.io images in and for Karaf).
+
+h3. Kubernetes discovery service
+
+In order to determine the IP address of each node, so that Hazelcast can connect to them, the Kubernetes discovery service queries
+the Kubernetes API for containers labeled with the _pod.label.key_ and _pod.label.key_ specified in _etc/org.apache.karaf.cellar.kubernetes.cfg_.
+So, you *must be sure* to label your containers (pods) accordingly.
+*NOTE*: Since environment variables are injected into all Kubernetes containers, they can access said API at:
+
+{code}
+http://$KUBERNETES_RO_SERVICE_HOST:$KUBERNETES_RO_SERVICE_PORT
+{code}
+
+After a Cellar node starts up, Kubernetes discovery service will configure Hazelcast with currently running Cellar nodes.
+Since Hazelcast follows a peer-to-peer all-shared topology, whenever nodes come up and down, the cluster will remain up-to-date.
+
+h3. Installing Kubernetes discovery service
+
+To install the Kubernetes discovery service, simply install cellar-kubernetes feature.
+
+{code}
+karaf@root()> feature:install cellar-kubernetes
+{code}
+
+Once the feature is installed, a new configuration file for the Kubernetes discovery service will live in etc/org.apache.karaf.cellar.kubernetes.cfg with the following contents:
+
+{code}
+#
+# Label selector used to idenfity Cellar nodes in Kubernetes cluster
+#
+pod.label.key = name
+pod.label.value = cellar
+{code}
+
+In case you change the file, the discovery service will check again for new nodes. If new nodes are found, Hazelcast configuration will be
+updated and the instance restarted.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/manual/src/main/webapp/user-guide/index.conf
----------------------------------------------------------------------
diff --git a/manual/src/main/webapp/user-guide/index.conf b/manual/src/main/webapp/user-guide/index.conf
index c31b553..e568b51 100644
--- a/manual/src/main/webapp/user-guide/index.conf
+++ b/manual/src/main/webapp/user-guide/index.conf
@@ -9,4 +9,4 @@ h1. Karaf Cellar User Guide
 * [OBR in Karaf Cellar|/user-guide/obr]
 * [OSGi Event broadcast with Karaf Cellar|/user-guide/event]
 * [DOSGi and Transport|/user-guide/transport]
-* [Cellar Cloud Discovery|/user-guide/cloud]
+* [Discovery Services|/user-guide/cloud]

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/7ec918a0/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 8aaf2f9..5cd9a60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
 
     <properties>
         <easymock.version>3.2</easymock.version>
+        <fabric8.version>2.0.20</fabric8.version>
         <felix.bundlerepository.version>2.0.2</felix.bundlerepository.version>
         <felix.utils.version>1.6.0</felix.utils.version>
         <felix.webconsole.version>4.2.2</felix.webconsole.version>
@@ -61,6 +62,7 @@
         <module>hazelcast</module>
         <module>utils</module>
         <module>cloud</module>
+        <module>kubernetes</module>
         <module>webconsole</module>
         <module>assembly</module>
         <module>samples</module>
@@ -287,6 +289,13 @@
                 <version>${joda-time.version}</version>
             </dependency>
 
+            <!-- Kubernetes -->
+            <dependency>
+                <groupId>io.fabric8</groupId>
+                <artifactId>kubernetes-api</artifactId>
+                <version>${fabric8.version}</version>
+            </dependency>
+
             <!-- Testing -->
             <dependency>
                 <groupId>junit</groupId>