# Apache storm on kubernetes
## 1. Build docker image of apache storm version 1.1.1
### create following two files
#### - Dockerfile
```
FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y default-jre wget unzip python
RUN echo "JAVA_HOME=\"/usr/lib/jvm/java-8-openjdk-amd64\"" >> /etc/environment
ENV JAVA_HOME "/usr/lib/jvm/java-8-openjdk-amd64"
ENV STORM_VERSION 1.1.1
ENV STORM_HOME /opt/apache-storm-${STORM_VERSION}
RUN echo ${STORM_VERSION}
RUN wget -q -O - http://apache.stu.edu.tw/storm/apache-storm-${STORM_VERSION}/apache-storm-${STORM_VERSION}.tar.gz | tar -xzf - -C /opt
RUN ln -s $STORM_HOME/bin/storm /usr/bin/storm
VOLUME /mnt/storm
ADD start_storm.sh /usr/bin/start_storm.sh
RUN chmod +x /usr/bin/start_storm.sh
ENTRYPOINT ["/usr/bin/start_storm.sh"]
```
#### - start_storm.sh
```
#!/bin/bash
storm_version="1.1.1"
storm_conf_path="/opt/apache-storm-${storm_version}/conf/storm.yaml"
# check environment
# -------------------------------------------------------------------
echo "[ environment ]"
kernel_ver=`uname -r`
release=`cat /etc/lsb-release`
echo "KERNEL_VERSION=${kernel_ver}"
echo "LSB_RELEASE=${release}"
echo "JAVA_HOME=${JAVA_HOME}"
echo "JAVA VERSION="; java --version
echo "STORM_VERSION=${STORM_VERSION}"
echo "STORM_HOME=${STORM_HOME}"
echo
# config storm.yaml
# -------------------------------------------------------------------
echo "[ storm.yaml ]"
if [[ -n ${STORM_ZOOKEEPER} ]]; then
echo "STORM_ZOOKEEPER=${STORM_ZOOKEEPER}"
echo "storm.zookeeper.servers:" > ${storm_conf_path}
zm_list=($(echo ${STORM_ZOOKEEPER}))
for zm in ${zm_list[@]}; do
echo " - \"${zm}\"" >> ${storm_conf_path}
done
fi
if [[ -n ${STORM_NIMBUS} ]]; then
echo "STORM_NIMBUS=${STORM_NIMBUS}"
nb_list=($(echo ${STORM_NIMBUS}))
nb_seed_str=""
for nb in ${nb_list[@]}; do
nb="\"${nb}\""
if [[ "${#nb_seed_str}" -ne "0" ]]; then
nb=", ${nb}"
fi
nb_seed_str="${nb_seed_str}${nb}"
done
echo "nimbus.seeds: [${nb_seed_str}]" >> ${storm_conf_path}
fi
if [[ -n ${STORM_DRPC} ]]; then
echo "STORM_DRPC=${STORM_DRPC}"
echo "drpc.servers:" > ${storm_conf_path}
drpc_list=($(echo ${STORM_DRPC}))
for drpc in ${drpc_list[@]}; do
echo " - \"${drpc}\"" >> ${storm_conf_path}
done
fi
if [[ -n ${STORM_SUPERVISOR_SLOTS_PORTS} ]]; then
echo "STORM_SUPERVISOR_SLOTS_PORTS=${STORM_SUPERVISOR_SLOTS_PORTS}"
echo "supervisor.slots.ports:" >> ${storm_conf_path}
port_list=($(echo ${STORM_SUPERVISOR_SLOTS_PORTS}))
for port in ${port_list[@]}; do
echo " - ${port}" >> ${storm_conf_path}
done
fi
if [[ -n ${STORM_LOCAL_DIR} ]]; then
echo "STORM_LOCAL_DIR=${STORM_LOCAL_DIR}"
echo "storm.local.dir: \"${STORM_LOCAL_DIR}\"" >> ${storm_conf_path}
fi
echo "${storm_conf_path}"; cat ${storm_conf_path}; echo
# run storm roles
# -------------------------------------------------------------------
if [[ -n ${STORM_ROLE} ]]; then
echo "[ run storm ]"
if [[ "${STORM_ROLE}" == "nimbus" ]]; then
echo "- run nimbus"
/usr/bin/storm nimbus
elif [[ "${STORM_ROLE}" == "supervisor" ]]; then
echo "- run supervisor"
/usr/bin/storm supervisor
elif [[ "${STORM_ROLE}" == "ui" ]]; then
echo "- run ui"
/usr/bin/storm ui
elif [[ "${STORM_ROLE}" == "drpc" ]]; then
echo "- run drpc"
/usr/bin/storm drpc
fi
echo; echo
fi
```
### build docker image
"*docker build --rm -t <dockerhub username>/<image name>:<image tag> .*" to build image
### upload the image to dockerhub
"*docker login*" to login your dockerhub account
"*docker push <dockerhub username>/<image name>:<image tag>*" to upload your image to dockerhub
## 2. Write YAML file to run apache storm on kubernetes
### Environment Variable in YAML:
* STORM_ZOOKEEPER
zookeeper IP address, separate with space if multiple IP supplied.
* STORM_NIMBUS
nimbus hostname, separate with space if multiple name supplied.
* STORM_SUPERVISOR_SLOTS_PORTS
port number opend on supervisor node, separate with space if multiple port number supplied.
* STORM_ROLE
role or storm command to run storm. you might specify "nimbus", "supervisor", "ui", or "drpc".
* STORM_LOCAL_DIR
directory path where jar file kept. ex. "/mnt/storm"
> For nimbus node, you have to specified hostname in YAML file. This hostname has to be in the STORM_NIMBUS of Environment Variables.
### Yaml Example
#### nimbus-1.yaml
```
apiVersion: v1
kind: Service
metadata:
name: nimbus-1
labels:
app: nimbus-1
spec:
ports:
- port: 6627
targetPort: 6627
nodePort: 30011
type: NodePort
selector:
app: nimbus-1
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nimbus-1
spec:
replicas: 1
template:
metadata:
labels:
app: nimbus-1
spec:
hostname: nimbus-1
containers:
- name: nimbus-1
image: thisistom/storm_base_1.1.1:v1.0
env:
- name: STORM_ZOOKEEPER
value: "172.22.132.10"
- name: STORM_NIMBUS
value: "nimbus-1 nimbus-2"
- name: STORM_SUPERVISOR_SLOTS_PORTS
value: "6700 6701 6702 6703"
- name: STORM_ROLE
value: "nimbus"
- name: STORM_LOCAL_DIR
value: "/mnt/storm"
ports:
- containerPort: 6627
securityContext:
privileged: true
```
#### nimbus-2.yaml
```
apiVersion: v1
kind: Service
metadata:
name: nimbus-2
labels:
app: nimbus-2
spec:
ports:
- port: 6627
targetPort: 6627
nodePort: 30012
type: NodePort
selector:
app: nimbus-2
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nimbus-2
spec:
replicas: 1
template:
metadata:
labels:
app: nimbus-2
spec:
hostname: nimbus-2
containers:
- name: nimbus-2
image: thisistom/storm_base_1.1.1:v1.0
env:
- name: STORM_ZOOKEEPER
value: "172.22.132.10"
- name: STORM_NIMBUS
value: "nimbus-1 nimbus-2"
- name: STORM_SUPERVISOR_SLOTS_PORTS
value: "6700 6701 6702 6703"
- name: STORM_ROLE
value: "nimbus"
- name: STORM_LOCAL_DIR
value: "/mnt/storm"
ports:
- containerPort: 6627
securityContext:
privileged: true
```
#### supervisor.yaml
```
apiVersion: v1
kind: Service
metadata:
name: supervisor
labels:
app: supervisor
spec:
ports:
- port: 6700
name: slot6700
nodePort: 30030
- port: 6701
name: slot6701
nodePort: 30031
- port: 6702
name: slot6702
nodePort: 30032
- port: 6703
name: slot6703
nodePort: 30033
type: NodePort
selector:
app: supervisor
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: supervisor
spec:
replicas: 3
template:
metadata:
labels:
app: supervisor
spec:
containers:
- name: supervisor
image: thisistom/storm_base_1.1.1:v1.0
env:
- name: STORM_ZOOKEEPER
value: "172.22.132.10"
- name: STORM_NIMBUS
value: "nimbus-1 nimbus-2"
- name: STORM_SUPERVISOR_SLOTS_PORTS
value: "6700 6701 6702 6703"
- name: STORM_ROLE
value: "supervisor"
- name: STORM_LOCAL_DIR
value: "/mnt/storm"
ports:
- containerPort: 6700
name: slot6700
- containerPort: 6701
name: slot6701
- containerPort: 6702
name: slot6702
- containerPort: 6703
name: slot6703
securityContext:
privileged: true
```
#### ui.yaml
```
apiVersion: v1
kind: Service
metadata:
name: ui
labels:
app: ui
spec:
ports:
- port: 8080
targetPort: 8080
nodePort: 30021
type: NodePort
selector:
app: ui
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ui
spec:
replicas: 1
template:
metadata:
labels:
app: ui
spec:
containers:
- name: ui
image: thisistom/storm_base_1.1.1:v1.0
env:
- name: STORM_ZOOKEEPER
value: "172.22.132.10"
- name: STORM_NIMBUS
value: "nimbus-1 nimbus-2"
- name: STORM_SUPERVISOR_SLOTS_PORTS
value: "6700 6701 6702 6703"
- name: STORM_ROLE
value: "ui"
- name: STORM_LOCAL_DIR
value: "/mnt/storm"
ports:
- containerPort: 8080
securityContext:
privileged: true
```
### run storm on kubernetes


> Above YAML example will create 2 nimbus, 3 supervisor and 1 ui and use NodePort mode to expose service.
#### Open storm ui *http://<kubernete node ip>:<service port>*

## 3. Run storm-starter example
> need to install default-jdk, git, maven, ruby, python in order to build storm-starter
###
#### get apache storm-starter and build


#### package jar file


#### upload the jar to nimbus then submit topology

> You might install openssh-client in nimbus to scp jar file to nimbus and run below storm command to submit topology
>*storm jar ./storm-starter-1.1.1.jar org.apache.storm.starter.RollingTopWords production-topology remote*
#### UI: Topology "production-topology" submitted

#### UI: Stats, Spouts and Bolts

#### UI: Topology Visuallization
