Spark/Gradle -- 在 build.gradle 中获取 IP 地址以用于启动 master 和 workers

Spark/Gradle -- Getting IP Address in build.gradle to use for starting master and workers

我基本了解 build.gradle 构建脚本的各个移动部分,但无法将它们全部组合在一起。

在 Apache Spark 独立模式下,只是试图从 build.gradle 在同一个盒子上启动主节点和工作节点。 (稍后将通过使用 $SPARK_HOME/sbin/start-slaves 的调用扩展 masterIP 的正确参数。)

问题:如何将我的 IP 地址分配给 Groovy/build.gradle 中的变量,以便将其传递给 Exec 任务中的命令?我们希望在几台不同的开发机器上 运行。

我们有一个(我认为相当标准的)/etc/hosts 配置,其中 FQDN 和主机名分配给 127.0.1.1。驱动程序解决了这个问题,但是用主机名启动主从不是一个选项,我需要 ip 地址。

我正在尝试:

task getMasterIP (type: Exec){
    // declare script scope variable using no def or
    executable "hostname"
    args += "-I"

    // need results of hostname call assigned to script scope variable
    sparkMasterIP = <resultsOfHostnameCall>
}

// added this because startSlave stops if Master is already running
task startSlaveOnly(dependsOn:'getMasterIP', type: Exec){
    executable "/usr/local/spark/sbin/start-slave.sh"
    args += "spark://$sparkMasterIP:7077"
    doLast {
        println "enslaved"
    }
}

// now make startSlave call startSlaveOnly after the initial startMaster
task startSlave(dependsOn:'startMaster', type: Exec) {
    finalizedBy 'startSlaveOnly'
}

当我尝试 something like suggested in the docs for Exec for Groovy calls 时:

task getMasterIP (type: Exec){
    // declare script scope variable using no def or
    sparkMasterIP = executable "hostname"
    args += "-I"
}

我收到无法识别可执行文件的警告。


“关于我的想法的更多背景知识”部分,不是主要问题。

谷歌搜索 "build.gradle script scope variables" 并查看前两个结果,in the basic docs I only see one type of variable and ext properties to be used

16.4. Declaring variables -- There are two kinds of variables that can be declared in a build script: local variables and extra properties.

但是在这个 other Gradle doc Appendix B. Potential Traps 中,我看到除了 ext 属性之外的两种变量范围:

For Gradle users it is important to understand how Groovy deals with script variables. Groovy has two types of script variables. One with a local scope and one with a script-wide scope.

使用此示例:

String localScope1 = 'localScope1'
def localScope2 = 'localScope2'
scriptScope = 'scriptScope'

我假设我应该使用没有 "def" 或类型声明的脚本范围变量。完全接受完全不同的方法,谢谢。

要获取本地 IP:

//return all v4 addresses 
def getLocalIPv4() {
    def ip4s = []
    NetworkInterface.getNetworkInterfaces()
            .findAll { it.isUp() && !it.isLoopback() && !it.isVirtual() }
            .each {
        it.getInetAddresses()
                .findAll { !it.isLoopbackAddress() && it instanceof Inet4Address }
                .each { ip4s << it }
    }
    return ip4s
}

//optionally, return all ipv6 addresses
def getLocalIPv6() {
    def ip6s = []
    NetworkInterface.getNetworkInterfaces()
            .findAll { it.isUp() && !it.isLoopback() && !it.isVirtual() }
            .each {
        it.getInetAddresses()
                .findAll { !it.isLoopbackAddress() && it instanceof Inet6Address }
                .each { ip6s << it }
    }
    return ip6s
}



task printIP()<<{
    println getLocalIPv4()
    println getLocalIPv6()
}

上面的两个函数return分别是ipv4或者ipv6地址列表。您可能会注意到我正在跳过所有本地主机、未启动的接口、所有环回和虚拟接口。如果你想使用第一个ipv4地址,你可以在其他地方使用它:

getLocalIPv4()[0]

或者您的情况:

args += "spark:/"+ getLocalIPv4()[0] + ":7077"

I found this post that appears to be a more straightforward way 这样做但它仅限于 Linux 平台,主机名 -I 在 Windows 中不起作用,也许不是所有 Linux 发行版?

  • 正在获取主机名
  • 将其赋值给变量
  • 在 build.gradle 中使用 任务

这是我构建的任务结果,接受的答案更好更通用,这只是为了另一种看待它的方式

task getMasterIP{
        doLast {
            new ByteArrayOutputStream().withStream { os ->
                def result = exec {
                    executable = 'hostname'
                    args += '-I'
                }
                ext.ipAddress = os.toString()
            }
        }
}

RaGe 的回答在查看所有平台上的所有接口方面做得更好