diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd-no-dns/httpd-no-dns.json b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd-no-dns/httpd-no-dns.json
new file mode 100644
index 00000000000..6b35538d4e5
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd-no-dns/httpd-no-dns.json
@@ -0,0 +1,62 @@
+{
+ "name": "httpd-service-no-dns",
+ "lifetime": "3600",
+ "components": [
+ {
+ "name": "httpd",
+ "number_of_containers": 2,
+ "artifact": {
+ "id": "centos/httpd-24-centos7:latest",
+ "type": "DOCKER"
+ },
+ "launch_command": "/usr/bin/run-httpd",
+ "resource": {
+ "cpus": 1,
+ "memory": "1024"
+ },
+ "readiness_check": {
+ "type": "HTTP",
+ "props": {
+ "url": "http://${THIS_HOST}:8080"
+ }
+ },
+ "configuration": {
+ "files": [
+ {
+ "type": "ENV",
+ "dest_file": "/var/www/html/index.html",
+ "props": {
+ "content": "
Hello from ${COMPONENT_INSTANCE_NAME}!"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "httpd-proxy",
+ "number_of_containers": 1,
+ "dependencies": [ "httpd" ],
+ "artifact": {
+ "id": "centos/httpd-24-centos7:latest",
+ "type": "DOCKER"
+ },
+ "launch_command": "/usr/bin/run-httpd",
+ "resource": {
+ "cpus": 1,
+ "memory": "1024"
+ },
+ "configuration": {
+ "files": [
+ {
+ "type": "TEMPLATE",
+ "dest_file": "/etc/httpd/conf.d/httpd-proxy.conf",
+ "src_file": "httpd-proxy-no-dns.conf"
+ }
+ ]
+ }
+ }
+ ],
+ "quicklinks": {
+ "Apache HTTP Server": "http://httpd-proxy-0.${SERVICE_NAME}.${USER}.${DOMAIN}:8080"
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd-no-dns/httpd-proxy-no-dns.conf b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd-no-dns/httpd-proxy-no-dns.conf
new file mode 100644
index 00000000000..9894e64d508
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd-no-dns/httpd-proxy-no-dns.conf
@@ -0,0 +1,24 @@
+#
+# 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.
+
+
+ BalancerMember http://${HTTPD-0_IP}:8080
+ BalancerMember http://${HTTPD-1_IP}:8080
+ ProxySet lbmethod=bytraffic
+
+
+ProxyPass "/" "balancer://test/"
+ProxyPassReverse "/" "balancer://test/"
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd/httpd-proxy.conf b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd/httpd-proxy.conf
new file mode 100644
index 00000000000..e8651a5c6cd
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd/httpd-proxy.conf
@@ -0,0 +1,24 @@
+#
+# 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.
+
+
+ BalancerMember http://httpd-0.${SERVICE_NAME}.${USER}.${DOMAIN}:8080
+ BalancerMember http://httpd-1.${SERVICE_NAME}.${USER}.${DOMAIN}:8080
+ ProxySet lbmethod=bytraffic
+
+
+ProxyPass "/" "balancer://test/"
+ProxyPassReverse "/" "balancer://test/"
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd/httpd.json b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd/httpd.json
new file mode 100644
index 00000000000..e63376dcf86
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/httpd/httpd.json
@@ -0,0 +1,55 @@
+{
+ "name": "httpd-service",
+ "lifetime": "3600",
+ "components": [
+ {
+ "name": "httpd",
+ "number_of_containers": 2,
+ "artifact": {
+ "id": "centos/httpd-24-centos7:latest",
+ "type": "DOCKER"
+ },
+ "launch_command": "/usr/bin/run-httpd",
+ "resource": {
+ "cpus": 1,
+ "memory": "1024"
+ },
+ "configuration": {
+ "files": [
+ {
+ "type": "ENV",
+ "dest_file": "/var/www/html/index.html",
+ "props": {
+ "content": "Hello from ${COMPONENT_INSTANCE_NAME}!"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "httpd-proxy",
+ "number_of_containers": 1,
+ "artifact": {
+ "id": "centos/httpd-24-centos7:latest",
+ "type": "DOCKER"
+ },
+ "launch_command": "/usr/bin/run-httpd",
+ "resource": {
+ "cpus": 1,
+ "memory": "1024"
+ },
+ "configuration": {
+ "files": [
+ {
+ "type": "TEMPLATE",
+ "dest_file": "/etc/httpd/conf.d/httpd-proxy.conf",
+ "src_file": "httpd-proxy.conf"
+ }
+ ]
+ }
+ }
+ ],
+ "quicklinks": {
+ "Apache HTTP Server": "http://httpd-proxy-0.${SERVICE_NAME}.${USER}.${DOMAIN}:8080"
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/api/ServiceApiConstants.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/api/ServiceApiConstants.java
index 0bfb2208c51..a85191c2cd5 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/api/ServiceApiConstants.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/api/ServiceApiConstants.java
@@ -52,6 +52,11 @@ public interface ServiceApiConstants {
String CONTAINER_ID = $("CONTAINER_ID");
+ // Templates for component instance host/IP
+ String COMPONENT_HOST = $("%s_HOST");
+
+ String COMPONENT_IP = $("%s_IP");
+
// Constants for default cluster ZK
String CLUSTER_ZK_QUORUM = $("CLUSTER_ZK_QUORUM");
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/component/Component.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/component/Component.java
index cb7131e6f9b..cbaf47280d0 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/component/Component.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/component/Component.java
@@ -47,8 +47,10 @@ import org.slf4j.LoggerFactory;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -58,6 +60,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static org.apache.hadoop.yarn.api.records.ContainerExitStatus.*;
+import static org.apache.hadoop.yarn.service.api.ServiceApiConstants.*;
import static org.apache.hadoop.yarn.service.component.ComponentEventType.*;
import static org.apache.hadoop.yarn.service.component.instance.ComponentInstanceEventType.START;
import static org.apache.hadoop.yarn.service.component.instance.ComponentInstanceEventType.STOP;
@@ -386,6 +389,34 @@ public class Component implements EventHandler {
return true;
}
+ public Map getDependencyHostIpTokens() {
+ Map tokens = new HashMap<>();
+ List dependencies = componentSpec.getDependencies();
+ if (SliderUtils.isEmpty(dependencies)) {
+ return tokens;
+ }
+ for (String dependency : dependencies) {
+ Collection instances = scheduler.getAllComponents()
+ .get(dependency).getAllComponentInstances().values();
+ for (ComponentInstance instance : instances) {
+ if (instance.getContainerStatus() == null) {
+ continue;
+ }
+ if (SliderUtils.isEmpty(instance.getContainerStatus().getIPs()) ||
+ SliderUtils.isUnset(instance.getContainerStatus().getHost())) {
+ continue;
+ }
+ String ip = instance.getContainerStatus().getIPs().get(0);
+ String host = instance.getContainerStatus().getHost();
+ tokens.put(String.format(COMPONENT_IP,
+ instance.getCompInstanceName().toUpperCase()), ip);
+ tokens.put(String.format(COMPONENT_HOST,
+ instance.getCompInstanceName().toUpperCase()), host);
+ }
+ }
+ return tokens;
+ }
+
private void incRunningContainers() {
componentMetrics.containersRunning.incr();
scheduler.getServiceMetrics().containersRunning.incr();
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/ProviderUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/ProviderUtils.java
index ec0c2ca00d2..93abd736045 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/ProviderUtils.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/ProviderUtils.java
@@ -397,6 +397,7 @@ public class ProviderUtils implements YarnServiceConstants {
tokens.put(CONTAINER_ID, instance.getContainer().getId().toString());
tokens.put(COMPONENT_ID,
String.valueOf(instance.getCompInstanceId().getId()));
+ tokens.putAll(instance.getComponent().getDependencyHostIpTokens());
return tokens;
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java
index 9ffc9db8671..51139bec143 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java
@@ -1550,6 +1550,10 @@ public class RegistryDNS extends AbstractService implements DNSOperations,
private final RegistryCommand removeRecordCommand = new RegistryCommand() {
@Override
public void exec(Zone zone, Record record) throws IOException {
+ if (zone == null) {
+ LOG.error("Unable to remove record because zone is null: {}", record);
+ return;
+ }
zone.removeRecord(record);
LOG.info("Removed {}", record);
if (isDNSSECEnabled()) {
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Examples.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Examples.md
new file mode 100644
index 00000000000..db6d5530737
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Examples.md
@@ -0,0 +1,159 @@
+
+
+# YARN Service Examples
+
+This document describes some example service definitions (`Yarnfile`).
+
+
+
+## Apache web server - httpd (with registry DNS)
+Below is the `Yarnfile` for a service called `httpd-service` with two `httpd` instances.
+There is also an httpd proxy instance (httpd-proxy-0) that proxies between the other two httpd instances (httpd-0 and httpd-1).
+
+Note this example requires registry DNS.
+```
+{
+ "name": "httpd-service",
+ "lifetime": "3600",
+ "components": [
+ {
+ "name": "httpd",
+ "number_of_containers": 2,
+ "artifact": {
+ "id": "centos/httpd-24-centos7:latest",
+ "type": "DOCKER"
+ },
+ "launch_command": "/usr/bin/run-httpd",
+ "resource": {
+ "cpus": 1,
+ "memory": "1024"
+ },
+ "configuration": {
+ "files": [
+ {
+ "type": "ENV",
+ "dest_file": "/var/www/html/index.html",
+ "props": {
+ "content": "Hello from ${COMPONENT_INSTANCE_NAME}!"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "httpd-proxy",
+ "number_of_containers": 1,
+ "artifact": {
+ "id": "centos/httpd-24-centos7:latest",
+ "type": "DOCKER"
+ },
+ "launch_command": "/usr/bin/run-httpd",
+ "resource": {
+ "cpus": 1,
+ "memory": "1024"
+ },
+ "configuration": {
+ "files": [
+ {
+ "type": "TEMPLATE",
+ "dest_file": "/etc/httpd/conf.d/httpd-proxy.conf",
+ "src_file": "httpd-proxy.conf"
+ }
+ ]
+ }
+ }
+ ],
+ "quicklinks": {
+ "Apache HTTP Server": "http://httpd-proxy-0.${SERVICE_NAME}.${USER}.${DOMAIN}:8080"
+ }
+}
+```
+This `Yarnfile` is already included in the Hadoop distribution, along with the required configuration template `httpd-proxy.conf`.
+First upload the configuration template file to HDFS:
+```
+hdfs dfs -copyFromLocal ${HADOOP_YARN_HOME}/share/hadoop/yarn/yarn-service-examples/httpd/httpd-proxy.conf .
+```
+
+The proxy configuration template looks like the following and will configure the httpd-proxy-0 container to balance between the httpd-0 and httpd-1 containers evenly:
+```
+
+ BalancerMember http://httpd-0.${SERVICE_NAME}.${USER}.${DOMAIN}:8080
+ BalancerMember http://httpd-1.${SERVICE_NAME}.${USER}.${DOMAIN}:8080
+ ProxySet lbmethod=bytraffic
+
+
+ProxyPass "/" "balancer://test/"
+ProxyPassReverse "/" "balancer://test/"
+```
+
+Then run the service with the command:
+```
+yarn service create [service-name] --example httpd
+```
+where `service-name` is optional. If omitted, it uses the name defined in the `Yarnfile`.
+
+Once the service is running, navigate to `http://httpd-proxy-0.${SERVICE_NAME}.${USER}.${DOMAIN}:8080` to see the root page.
+The pages should alternately show "Hello from httpd-0!" or "Hello from httpd-1!"
+
+The individual httpd URLs can also be visited, `http://httpd-0.${SERVICE_NAME}.${USER}.${DOMAIN}:8080` and `http://httpd-1.${SERVICE_NAME}.${USER}.${DOMAIN}:8080`.
+
+If unsure of your hostnames, visit the apiserver REST endpoint `http://:9191/ws/v1/services/httpd-service`.
+
+## Apache web server - httpd (without registry DNS)
+
+A similar IP-based example is provided for environments that do not have registry DNS set up.
+The service name for this example is `httpd-service-no-dns`.
+There are a couple of additions to the `Yarnfile` for the `httpd-service` described above.
+A readiness check is added for the `httpd` component:
+```
+ "readiness_check": {
+ "type": "HTTP",
+ "props": {
+ "url": "http://${THIS_HOST}:8080"
+ }
+ },
+```
+and `httpd` is added as a dependency for the `httpd-proxy` component:
+```
+ "dependencies": [ "httpd" ],
+```
+
+This means that the httpd-proxy-0 instance will not be started until after an HTTP probe has succeeded for the httpd-0 and httpd-1 containers.
+This is necessary so that the IPs of the containers can be used in the configuration of httpd-proxy-0.
+The proxy configuration is similar to that of the previous example, with the BalancerMember lines changed as follows:
+```
+ BalancerMember http://${HTTPD-0_IP}:8080
+ BalancerMember http://${HTTPD-1_IP}:8080
+```
+
+Note that IP and HOST variables such as `${HTTPD-0_IP}` and `${HTTPD-0_HOST}` should only be used by a component that has a dependency on the named component (`httpd` in this case) AND should only be used when the named component specifies a readiness check.
+Here, `httpd-proxy` has a dependency on `httpd` and `httpd` has an HTTP readiness check.
+Without the dependency and readiness check, the httpd-proxy-0 container would be started in parallel with the httpd-0 and http-1 containers, and the IPs and hosts would not be assigned yet for httpd-0 and httpd-1.
+
+Other variables can be used by any component.
+
+Before creating the service, upload the proxy configuration to HDFS:
+```
+hdfs dfs -copyFromLocal ${HADOOP_YARN_HOME}/share/hadoop/yarn/yarn-service-examples/httpd-no-dns/httpd-proxy-no-dns.conf .
+```
+
+Then run the service with the command:
+```
+yarn service create [service-name] --example httpd-no-dns
+```
+where `service-name` is optional. If omitted, it uses the name defined in the `Yarnfile`.
+
+Look up your IPs at the apiserver REST endpoint `http://:9191/ws/v1/services/httpd-service`.
+Then visit port 8080 for each IP to view the pages.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Overview.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Overview.md
index 3dd4d8ceb31..407fbc00760 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Overview.md
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Overview.md
@@ -52,7 +52,8 @@ The benefits of combining these workloads are two-fold:
* [Concepts](Concepts.md): Describes the internals of the framework and some features in YARN core to support running services on YARN.
* [Service REST API](YarnServiceAPI.md): The API doc for deploying/managing services on YARN.
-* [Service Discovery](ServiceDiscovery.md): Deep dives into the YARN DNS internals
+* [Service Discovery](ServiceDiscovery.md): Deep dives into the YARN DNS internals.
+* [Examples](Examples.md): List some example service definitions (`Yarnfile`).