git.iko.soy/typeable/nixpkgs
on master help sign in
Merge pull request #137429 from illustris/spark3

Spark: init module

commit4ec195a9c1d17fcaf0d646644053b04dbd8f4080 authorAaron Andersen <aaron@fosslib.net> dateSat 18 Sep 2021, 07:28 (5 years ago) parent9ec36de13839b0
8 files changed+316−46
nixos/doc/manual/from_md/release-notes/rl-2111.section.xml+13 nixos/doc/manual/release-notes/rl-2111.section.md+4 nixos/modules/module-list.nix+1 nixos/modules/services/cluster/spark/default.nix+162 nixos/tests/spark/default.nix+28 nixos/tests/spark/spark_sample.py+40 pkgs/applications/networking/cluster/spark/default.nix+64−45 pkgs/top-level/all-packages.nix+4−1
nixos/doc/manual/from_md/release-notes/rl-2111.section.xml+13
@@ -37,6 +37,13 @@
3737 PostgreSQL now defaults to major version 13.
3838 </para>
3939 </listitem>
40+ <listitem>
41+ <para>
42+ spark now defaults to spark 3, updated from 2. A
43+ <link xlink:href="https://spark.apache.org/docs/latest/core-migration-guide.html#upgrading-from-core-24-to-30">migration
44+ guide</link> is available.
45+ </para>
46+ </listitem>
4047 <listitem>
4148 <para>
4249 Activation scripts can now opt int to be run when running
@@ -250,6 +257,12 @@
250257 entry</link>.
251258 </para>
252259 </listitem>
260+ <listitem>
261+ <para>
262+ <link xlink:href="https://spark.apache.org/">spark</link>, a
263+ unified analytics engine for large-scale data processing.
264+ </para>
265+ </listitem>
253266 </itemizedlist>
254267 </section>
255268 <section xml:id="sec-release-21.11-incompatibilities">
nixos/doc/manual/release-notes/rl-2111.section.md+4
@@ -14,6 +14,8 @@ In addition to numerous new and upgraded packages, this release has the followin
1414
1515- PostgreSQL now defaults to major version 13.
1616
17+- spark now defaults to spark 3, updated from 2. A [migration guide](https://spark.apache.org/docs/latest/core-migration-guide.html#upgrading-from-core-24-to-30) is available.
18+
1719- Activation scripts can now opt int to be run when running `nixos-rebuild dry-activate` and detect the dry activation by reading `$NIXOS_ACTION`.
1820 This allows activation scripts to output what they would change if the activation was really run.
1921 The users/modules activation script supports this and outputs some of is actions.
@@ -78,6 +80,8 @@ subsonic-compatible api. Available as [navidrome](#opt-services.navidrome.enable
7880 or sends them to a downstream service for further analysis.
7981 Documented in [its manual entry](#module-services-parsedmarc).
8082
83+- [spark](https://spark.apache.org/), a unified analytics engine for large-scale data processing.
84+
8185## Backward Incompatibilities {#sec-release-21.11-incompatibilities}
8286
8387
nixos/modules/module-list.nix+1
@@ -297,6 +297,7 @@
297297 ./services/cluster/kubernetes/pki.nix
298298 ./services/cluster/kubernetes/proxy.nix
299299 ./services/cluster/kubernetes/scheduler.nix
300+ ./services/cluster/spark/default.nix
300301 ./services/computing/boinc/client.nix
301302 ./services/computing/foldingathome/client.nix
302303 ./services/computing/slurm/slurm.nix
nixos/modules/services/cluster/spark/default.nixnew file+162
@@ -0,0 +1,162 @@
1+{config, pkgs, lib, ...}:
2+let
3+ cfg = config.services.spark;
4+in
5+with lib;
6+{
7+ options = {
8+ services.spark = {
9+ master = {
10+ enable = mkEnableOption "Spark master service";
11+ bind = mkOption {
12+ type = types.str;
13+ description = "Address the spark master binds to.";
14+ default = "127.0.0.1";
15+ example = "0.0.0.0";
16+ };
17+ restartIfChanged = mkOption {
18+ type = types.bool;
19+ description = ''
20+ Automatically restart master service on config change.
21+ This can be set to false to defer restarts on clusters running critical applications.
22+ Please consider the security implications of inadvertently running an older version,
23+ and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
24+ '';
25+ default = true;
26+ };
27+ extraEnvironment = mkOption {
28+ type = types.attrsOf types.str;
29+ description = "Extra environment variables to pass to spark master. See spark-standalone documentation.";
30+ default = {};
31+ example = {
32+ SPARK_MASTER_WEBUI_PORT = 8181;
33+ SPARK_MASTER_OPTS = "-Dspark.deploy.defaultCores=5";
34+ };
35+ };
36+ };
37+ worker = {
38+ enable = mkEnableOption "Spark worker service";
39+ workDir = mkOption {
40+ type = types.path;
41+ description = "Spark worker work dir.";
42+ default = "/var/lib/spark";
43+ };
44+ master = mkOption {
45+ type = types.str;
46+ description = "Address of the spark master.";
47+ default = "127.0.0.1:7077";
48+ };
49+ restartIfChanged = mkOption {
50+ type = types.bool;
51+ description = ''
52+ Automatically restart worker service on config change.
53+ This can be set to false to defer restarts on clusters running critical applications.
54+ Please consider the security implications of inadvertently running an older version,
55+ and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
56+ '';
57+ default = true;
58+ };
59+ extraEnvironment = mkOption {
60+ type = types.attrsOf types.str;
61+ description = "Extra environment variables to pass to spark worker.";
62+ default = {};
63+ example = {
64+ SPARK_WORKER_CORES = 5;
65+ SPARK_WORKER_MEMORY = "2g";
66+ };
67+ };
68+ };
69+ confDir = mkOption {
70+ type = types.path;
71+ description = "Spark configuration directory. Spark will use the configuration files (spark-defaults.conf, spark-env.sh, log4j.properties, etc) from this directory.";
72+ default = "${cfg.package}/lib/${cfg.package.untarDir}/conf";
73+ defaultText = literalExample "\${cfg.package}/lib/\${cfg.package.untarDir}/conf";
74+ };
75+ logDir = mkOption {
76+ type = types.path;
77+ description = "Spark log directory.";
78+ default = "/var/log/spark";
79+ };
80+ package = mkOption {
81+ type = types.package;
82+ description = "Spark package.";
83+ default = pkgs.spark;
84+ defaultText = "pkgs.spark";
85+ example = literalExample ''pkgs.spark.overrideAttrs (super: rec {
86+ pname = "spark";
87+ version = "2.4.4";
88+
89+ src = pkgs.fetchzip {
90+ url = "mirror://apache/spark/"''${pname}-''${version}/''${pname}-''${version}-bin-without-hadoop.tgz";
91+ sha256 = "1a9w5k0207fysgpxx6db3a00fs5hdc2ncx99x4ccy2s0v5ndc66g";
92+ };
93+ })'';
94+ };
95+ };
96+ };
97+ config = lib.mkIf (cfg.worker.enable || cfg.master.enable) {
98+ environment.systemPackages = [ cfg.package ];
99+ systemd = {
100+ services = {
101+ spark-master = lib.mkIf cfg.master.enable {
102+ path = with pkgs; [ procps openssh nettools ];
103+ description = "spark master service.";
104+ after = [ "network.target" ];
105+ wantedBy = [ "multi-user.target" ];
106+ restartIfChanged = cfg.master.restartIfChanged;
107+ environment = cfg.master.extraEnvironment // {
108+ SPARK_MASTER_HOST = cfg.master.bind;
109+ SPARK_CONF_DIR = cfg.confDir;
110+ SPARK_LOG_DIR = cfg.logDir;
111+ };
112+ serviceConfig = {
113+ Type = "forking";
114+ User = "spark";
115+ Group = "spark";
116+ WorkingDirectory = "${cfg.package}/lib/${cfg.package.untarDir}";
117+ ExecStart = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/start-master.sh";
118+ ExecStop = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/stop-master.sh";
119+ TimeoutSec = 300;
120+ StartLimitBurst=10;
121+ Restart = "always";
122+ };
123+ };
124+ spark-worker = lib.mkIf cfg.worker.enable {
125+ path = with pkgs; [ procps openssh nettools rsync ];
126+ description = "spark master service.";
127+ after = [ "network.target" ];
128+ wantedBy = [ "multi-user.target" ];
129+ restartIfChanged = cfg.worker.restartIfChanged;
130+ environment = cfg.worker.extraEnvironment // {
131+ SPARK_MASTER = cfg.worker.master;
132+ SPARK_CONF_DIR = cfg.confDir;
133+ SPARK_LOG_DIR = cfg.logDir;
134+ SPARK_WORKER_DIR = cfg.worker.workDir;
135+ };
136+ serviceConfig = {
137+ Type = "forking";
138+ User = "spark";
139+ WorkingDirectory = "${cfg.package}/lib/${cfg.package.untarDir}";
140+ ExecStart = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/start-worker.sh spark://${cfg.worker.master}";
141+ ExecStop = "${cfg.package}/lib/${cfg.package.untarDir}/sbin/stop-worker.sh";
142+ TimeoutSec = 300;
143+ StartLimitBurst=10;
144+ Restart = "always";
145+ };
146+ };
147+ };
148+ tmpfiles.rules = [
149+ "d '${cfg.worker.workDir}' - spark spark - -"
150+ "d '${cfg.logDir}' - spark spark - -"
151+ ];
152+ };
153+ users = {
154+ users.spark = {
155+ description = "spark user.";
156+ group = "spark";
157+ isSystemUser = true;
158+ };
159+ groups.spark = { };
160+ };
161+ };
162+}
nixos/tests/spark/default.nixnew file+28
@@ -0,0 +1,28 @@
1+import ../make-test-python.nix ({...}: {
2+ name = "spark";
3+
4+ nodes = {
5+ worker = { nodes, pkgs, ... }: {
6+ virtualisation.memorySize = 1024;
7+ services.spark.worker = {
8+ enable = true;
9+ master = "master:7077";
10+ };
11+ };
12+ master = { config, pkgs, ... }: {
13+ services.spark.master = {
14+ enable = true;
15+ bind = "0.0.0.0";
16+ };
17+ networking.firewall.allowedTCPPorts = [ 22 7077 8080 ];
18+ };
19+ };
20+
21+ testScript = ''
22+ master.wait_for_unit("spark-master.service")
23+ worker.wait_for_unit("spark-worker.service")
24+ worker.copy_from_host( "${./spark_sample.py}", "/spark_sample.py" )
25+ assert "<title>Spark Master at spark://" in worker.succeed("curl -sSfkL http://master:8080/")
26+ worker.succeed("spark-submit --master spark://master:7077 --executor-memory 512m --executor-cores 1 /spark_sample.py")
27+ '';
28+})
nixos/tests/spark/spark_sample.pynew file+40
@@ -0,0 +1,40 @@
1+from pyspark.sql import Row, SparkSession
2+from pyspark.sql import functions as F
3+from pyspark.sql.functions import udf
4+from pyspark.sql.types import *
5+from pyspark.sql.functions import explode
6+
7+def explode_col(weight):
8+ return int(weight//10) * [10.0] + ([] if weight%10==0 else [weight%10])
9+
10+spark = SparkSession.builder.getOrCreate()
11+
12+dataSchema = [
13+ StructField("feature_1", FloatType()),
14+ StructField("feature_2", FloatType()),
15+ StructField("bias_weight", FloatType())
16+]
17+
18+data = [
19+ Row(0.1, 0.2, 10.32),
20+ Row(0.32, 1.43, 12.8),
21+ Row(1.28, 1.12, 0.23)
22+]
23+
24+df = spark.createDataFrame(spark.sparkContext.parallelize(data), StructType(dataSchema))
25+
26+normalizing_constant = 100
27+sum_bias_weight = df.select(F.sum('bias_weight')).collect()[0][0]
28+normalizing_factor = normalizing_constant / sum_bias_weight
29+df = df.withColumn('normalized_bias_weight', df.bias_weight * normalizing_factor)
30+df = df.drop('bias_weight')
31+df = df.withColumnRenamed('normalized_bias_weight', 'bias_weight')
32+
33+my_udf = udf(lambda x: explode_col(x), ArrayType(FloatType()))
34+df1 = df.withColumn('explode_val', my_udf(df.bias_weight))
35+df1 = df1.withColumn("explode_val_1", explode(df1.explode_val)).drop("explode_val")
36+df1 = df1.drop('bias_weight').withColumnRenamed('explode_val_1', 'bias_weight')
37+
38+df1.show()
39+
40+assert(df1.count() == 12)
pkgs/applications/networking/cluster/spark/default.nix+64−45
@@ -1,56 +1,75 @@
1−{ lib, stdenv, fetchzip, makeWrapper, jre, pythonPackages, coreutils, hadoop
1+{ lib, stdenv, fetchzip, makeWrapper, jdk8, python3Packages, extraPythonPackages ? [], coreutils, hadoop
22, RSupport? true, R
33}:
44
55with lib;
66
7−stdenv.mkDerivation rec {
7+let
8+ spark = { pname, version, src }:
9+ stdenv.mkDerivation rec {
10+ inherit pname version src;
11+ nativeBuildInputs = [ makeWrapper ];
12+ buildInputs = [ jdk8 python3Packages.python ]
13+ ++ extraPythonPackages
14+ ++ optional RSupport R;
815
9− pname = "spark";
10− version = "2.4.4";
16+ untarDir = "${pname}-${version}";
17+ installPhase = ''
18+ mkdir -p $out/{lib/${untarDir}/conf,bin,/share/java}
19+ mv * $out/lib/${untarDir}
1120
12− src = fetchzip {
13− url = "mirror://apache/spark/${pname}-${version}/${pname}-${version}-bin-without-hadoop.tgz";
14− sha256 = "1a9w5k0207fysgpxx6db3a00fs5hdc2ncx99x4ccy2s0v5ndc66g";
21+ cp $out/lib/${untarDir}/conf/log4j.properties{.template,}
22+
23+ cat > $out/lib/${untarDir}/conf/spark-env.sh <<- EOF
24+ export JAVA_HOME="${jdk8}"
25+ export SPARK_HOME="$out/lib/${untarDir}"
26+ export SPARK_DIST_CLASSPATH=$(${hadoop}/bin/hadoop classpath)
27+ export PYSPARK_PYTHON="${python3Packages.python}/bin/${python3Packages.python.executable}"
28+ export PYTHONPATH="\$PYTHONPATH:$PYTHONPATH"
29+ ${optionalString RSupport ''
30+ export SPARKR_R_SHELL="${R}/bin/R"
31+ export PATH="\$PATH:${R}/bin"''}
32+ EOF
33+
34+ for n in $(find $out/lib/${untarDir}/bin -type f ! -name "*.*"); do
35+ makeWrapper "$n" "$out/bin/$(basename $n)"
36+ substituteInPlace "$n" --replace dirname ${coreutils.out}/bin/dirname
37+ done
38+ for n in $(find $out/lib/${untarDir}/sbin -type f); do
39+ # Spark deprecated scripts with "slave" in the name.
40+ # This line adds forward compatibility with the nixos spark module for
41+ # older versions of spark that don't have the new "worker" scripts.
42+ ln -s "$n" $(echo "$n" | sed -r 's/slave(s?).sh$/worker\1.sh/g') || true
43+ done
44+ ln -s $out/lib/${untarDir}/lib/spark-assembly-*.jar $out/share/java
45+ '';
46+
47+ meta = {
48+ description = "Apache Spark is a fast and general engine for large-scale data processing";
49+ homepage = "http://spark.apache.org";
50+ license = lib.licenses.asl20;
51+ platforms = lib.platforms.all;
52+ maintainers = with maintainers; [ thoughtpolice offline kamilchm illustris ];
53+ repositories.git = "git://git.apache.org/spark.git";
54+ };
55+ };
56+in {
57+ spark3 = spark rec {
58+ pname = "spark";
59+ version = "3.1.2";
60+
61+ src = fetchzip {
62+ url = "mirror://apache/spark/${pname}-${version}/${pname}-${version}-bin-without-hadoop.tgz";
63+ sha256 = "1bgh2y6jm7wqy6yc40rx68xkki31i3jiri2yixb1bm0i9pvsj9yf";
64+ };
1565 };
66+ spark2 = spark rec {
67+ pname = "spark";
68+ version = "2.4.8";
1669
17− nativeBuildInputs = [ makeWrapper ];
18− buildInputs = [ jre pythonPackages.python pythonPackages.numpy ]
19− ++ optional RSupport R;
20−
21− untarDir = "${pname}-${version}-bin-without-hadoop";
22− installPhase = ''
23− mkdir -p $out/{lib/${untarDir}/conf,bin,/share/java}
24− mv * $out/lib/${untarDir}
25−
26− sed -e 's/INFO, console/WARN, console/' < \
27− $out/lib/${untarDir}/conf/log4j.properties.template > \
28− $out/lib/${untarDir}/conf/log4j.properties
29−
30− cat > $out/lib/${untarDir}/conf/spark-env.sh <<- EOF
31− export JAVA_HOME="${jre}"
32− export SPARK_HOME="$out/lib/${untarDir}"
33− export SPARK_DIST_CLASSPATH=$(${hadoop}/bin/hadoop classpath)
34− export PYSPARK_PYTHON="${pythonPackages.python}/bin/${pythonPackages.python.executable}"
35− export PYTHONPATH="\$PYTHONPATH:$PYTHONPATH"
36− ${optionalString RSupport
37− ''export SPARKR_R_SHELL="${R}/bin/R"
38− export PATH=$PATH:"${R}/bin/R"''}
39− EOF
40−
41− for n in $(find $out/lib/${untarDir}/bin -type f ! -name "*.*"); do
42− makeWrapper "$n" "$out/bin/$(basename $n)"
43− substituteInPlace "$n" --replace dirname ${coreutils.out}/bin/dirname
44− done
45− ln -s $out/lib/${untarDir}/lib/spark-assembly-*.jar $out/share/java
46− '';
47−
48− meta = {
49− description = "Apache Spark is a fast and general engine for large-scale data processing";
50− homepage = "http://spark.apache.org";
51− license = lib.licenses.asl20;
52− platforms = lib.platforms.all;
53− maintainers = with maintainers; [ thoughtpolice offline kamilchm ];
54− repositories.git = "git://git.apache.org/spark.git";
70+ src = fetchzip {
71+ url = "mirror://apache/spark/${pname}-${version}/${pname}-${version}-bin-without-hadoop.tgz";
72+ sha256 = "1mkyq0gz9fiav25vr0dba5ivp0wh0mh7kswwnx8pvsmb6wbwyfxv";
73+ };
5574 };
5675}
pkgs/top-level/all-packages.nix+4−1
@@ -13146,7 +13146,10 @@ with pkgs;
1314613146
1314713147 self = pkgsi686Linux.callPackage ../development/interpreters/self { };
1314813148
13149− spark = callPackage ../applications/networking/cluster/spark { };
13149+ inherit (callPackages ../applications/networking/cluster/spark { hadoop = hadoop_3_1; })
13150+ spark3
13151+ spark2;
13152+ spark = spark3;
1315013153
1315113154 sparkleshare = callPackage ../applications/version-management/sparkleshare { };
1315213155