├── .gitignore ├── README.md ├── cassandra ├── Dockerfile ├── cassandra-clusternode.sh ├── cassandra_repo_key └── expect ├── coreos-vagrant ├── .gitattributes ├── .gitignore ├── CONTRIBUTING.md ├── DCO ├── LICENSE ├── MAINTAINERS ├── NOTICE ├── README.md ├── Vagrantfile ├── config.rb └── user-data ├── coreos_install ├── coreos_show_discovery ├── coreos_update ├── devel-node ├── Dockerfile ├── cassandra_repo_key ├── kafka_cassandra_topology │ ├── cassandra_writer │ │ ├── __init__.py │ │ └── bolt.py │ ├── pyleus_topology.yaml │ ├── requirements.txt │ ├── single_python_consumer.py │ └── single_python_producer.py ├── python-cassandra-driver_2.1.4-1_amd64.deb ├── python-kafka-python_0.9.3-1_all.deb └── start-shell.sh ├── fleet ├── cassandra@.service ├── kafka@.service ├── storm-nimbus.service ├── storm-supervisor@.service ├── storm-ui.service └── zookeeper@.service ├── kafka ├── Dockerfile └── start-kafka.sh ├── storm-nimbus └── Dockerfile ├── storm-supervisor └── Dockerfile ├── storm-ui └── Dockerfile ├── storm ├── Dockerfile ├── cluster.xml ├── config-supervisord.sh ├── start-supervisor.sh └── storm.yaml └── zookeeper ├── Dockerfile └── start.sh /.gitignore: -------------------------------------------------------------------------------- 1 | coreos.inc 2 | hosts 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##CoreOS instances 2 | 3 | Install Vagrant (>= 1.6) and VirtualBox, then run 4 | 5 | ``` 6 | git clone https://github.com/endocode/CoreOS-Kafka-Storm-Cassandra-cluster-demo 7 | cd CoreOS-Kafka-Storm-Cassandra-cluster-demo/coreos-vagrant 8 | vagrant up 9 | ``` 10 | 11 | Vagrant will create three CoreOS VMs with the following IPs: 172.17.8.101, 172.17.8.102, 172.17.8.103 12 | 13 | Then login to your first Vagrant instance and submit fleet units: 14 | ``` 15 | vagrant ssh core-01 16 | fleetctl submit /tmp/fleet/* 17 | ``` 18 | 19 | ##Run Zookeeper cluster 20 | 21 | ``` 22 | fleetctl start zookeeper@{1..3}.service 23 | ``` 24 | 25 | ##Run Kafka cluster 26 | 27 | ``` 28 | fleetctl start kafka@{1..3}.service 29 | ``` 30 | 31 | ##Run Cassandra luster 32 | 33 | ``` 34 | fleetctl start cassandra@{1..3}.service 35 | ``` 36 | 37 | ##Run Storm cluster 38 | 39 | ``` 40 | fleetctl start storm-nimbus.service 41 | # storm-ui (not required) will listen on http://172.17.8.101:8080 42 | fleetctl start storm-ui.service 43 | fleetctl start storm-supervisor@{1..3}.service 44 | ``` 45 | 46 | ##Run development container inside CoreOS VM (storm, kafka, maven, scala, python, zookeeper, cassandra, etc) 47 | 48 | ```docker run --rm -ti -v /home/core/devel:/root/devel -e BROKER_LIST=`fleetctl list-machines -no-legend=true -fields=ip | sed 's/$/:9092/' | tr '\n' ','` -e NIMBUS_HOST=`etcdctl get /storm-nimbus` -e ZK=`fleetctl list-machines -no-legend=true -fields=ip | tr '\n' ','` endocode/devel-node:0.9.2 start-shell.sh bash``` 49 | 50 | ###Test Kafka cluster 51 | 52 | Run these commands in devel-node container to test your Kafka cluster. 53 | 54 | Create topic 55 | 56 | ```$KAFKA_HOME/bin/kafka-topics.sh --create --topic test --partitions 3 --zookeeper $ZK --replication-factor 2``` 57 | 58 | Show topic info 59 | 60 | ```$KAFKA_HOME/bin/kafka-topics.sh --describe --topic test --zookeeper $ZK``` 61 | 62 | Send some data to topic 63 | 64 | ```$KAFKA_HOME/bin/kafka-console-producer.sh --topic test --broker-list="$BROKER_LIST"``` 65 | 66 | Get some data from topic 67 | 68 | ```$KAFKA_HOME/bin/kafka-console-consumer.sh --zookeeper $ZK --topic test --from-beginning``` 69 | 70 | Remove topic (valid only with KAFKA_DELETE_TOPIC_ENABLE=true environment) 71 | 72 | ```$KAFKA_HOME/bin/kafka-topics.sh --zookeeper $ZK --delete --topic test``` 73 | 74 | ###Cassandra 75 | 76 | ####Show Cassandra cluster status 77 | 78 | ```nodetool -h172.17.8.101 status``` 79 | 80 | ####Cassandra cluster CLI 81 | 82 | 83 | ```cqlsh 172.17.8.101``` 84 | 85 | ####Cassandra queries 86 | 87 | You can view and manage your Cassandra table's content with the following queries: 88 | 89 | ``` 90 | SELECT * FROM testkeyspace.meter_data; 91 | #Delete content from table 92 | TRUNCATE testkeyspace.meter_data; 93 | SELECT COUNT(*) FROM testkeyspace.meter_data LIMIT 1000000; 94 | ``` 95 | 96 | ####Storm topology 97 | 98 | We will use Pyleus (http://yelp.github.io/pyleus/) framework to manage Storm topologies in pure python. Unfortunately current Pyleus version (0.2.4) doesn't support latest Storm 0.9.3 (https://github.com/Yelp/pyleus/issues/86). That is why we use Storm 0.9.2 in this example. 99 | endocode/devel-node:0.9.2 Docker container contains sample kafka-storm-cassandra Storm topology. Follow these steps to build and submit Storm topology into Storm cluster: 100 | 101 | ``` 102 | docker run --rm -ti -v /home/core/devel:/root/devel -e BROKER_LIST=`fleetctl list-machines -no-legend=true -fields=ip | sed 's/$/:9092/' | tr '\n' ','` -e NIMBUS_HOST=`etcdctl get /storm-nimbus` -e ZK=`fleetctl list-machines -no-legend=true -fields=ip | tr '\n' ','` endocode/devel-node:0.9.2 start-shell.sh bash 103 | # Create Kafka topic 104 | $KAFKA_HOME/bin/kafka-topics.sh --create --topic topic --partitions 3 --zookeeper $ZK --replication-factor 2 105 | # Create Cassandra keyspace and table 106 | echo "CREATE KEYSPACE testkeyspace WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 2 };" | cqlsh 172.17.8.101 107 | echo "CREATE TABLE IF NOT EXISTS testkeyspace.meter_data ( id uuid, Timestamp timestamp, P_1 float, P_2 float, P_3 float, Q_1 float, Q_2 float, Q_3 float, HARM list, PRIMARY KEY (id, Timestamp) );" | cqlsh 172.17.8.101 108 | cd ~/kafka_cassandra_topology 109 | pyleus build 110 | pyleus submit -n $NIMBUS_HOST kafka-cassandra.jar 111 | #Run Kafka random data producer 112 | ./single_python_producer.py 113 | ``` 114 | 115 | It will run kafka-cassandra topology in Storm cluster and Kafka producer. All this data will be stored in Cassandra cluster using Storm topology. You can monitor Cassandra table in CQL shell in another endocode/devel-node:0.9.2 container: 116 | 117 | ``` 118 | cqlsh 172.17.8.101 119 | Connected to cluster at 172.17.8.101:9160. 120 | [cqlsh 4.1.1 | Cassandra 2.0.12 | CQL spec 3.1.1 | Thrift protocol 19.39.0] 121 | Use HELP for help. 122 | cqlsh> SELECT COUNT(*) FROM testkeyspace.meter_data LIMIT 1000000; 123 | 124 | count 125 | ------- 126 | 1175 127 | 128 | (1 rows) 129 | 130 | cqlsh> 131 | ``` 132 | -------------------------------------------------------------------------------- /cassandra/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:trusty 2 | # based on Spotify's dockerfile - https://github.com/spotify/docker-cassandra/blob/master/cassandra-base/Dockerfile 3 | MAINTAINER Anton Khramov 4 | 5 | RUN /bin/echo -e "deb http://archive.ubuntu.com/ubuntu/ trusty multiverse\ndeb http://archive.ubuntu.com/ubuntu/ trusty-updates multiverse\ndeb http://security.ubuntu.com/ubuntu trusty-security multiverse" | tee -a /etc/apt/sources.list 6 | RUN apt-get update && apt-get dist-upgrade -y 7 | RUN apt-get install -y expect java-package 8 | RUN curl -j -L -H 'Cookie: oraclelicense=accept-securebackup-cookie' https://edelivery.oracle.com/otn-pub/java/jdk/7u79-b15/jre-7u79-linux-x64.tar.gz -o /tmp/jre-7u79-linux-x64.tar.gz 9 | ADD expect /tmp/expect 10 | RUN /tmp/expect 11 | 12 | ADD cassandra_repo_key /tmp/cassandra_repo_key 13 | RUN apt-key add /tmp/cassandra_repo_key 14 | RUN echo "deb http://debian.datastax.com/community stable main" | tee -a /etc/apt/sources.list.d/cassandra.sources.list 15 | RUN apt-get update 16 | RUN dpkg -i /tmp/oracle-java7-jre_7u79_amd64.deb || apt-get install -fy 17 | 18 | # Workaround for https://github.com/docker/docker/issues/6345 19 | RUN ln -s -f /bin/true /usr/bin/chfn 20 | 21 | # Install Cassandra 2.0.14 22 | RUN apt-get install -y cassandra=2.0.14 dsc20=2.0.14-1 23 | 24 | # cleanup image 25 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 26 | 27 | ENV CASSANDRA_CONFIG /etc/cassandra 28 | 29 | # Necessary since cassandra is trying to override the system limitations 30 | # See https://groups.google.com/forum/#!msg/docker-dev/8TM_jLGpRKU/dewIQhcs7oAJ 31 | RUN rm -f /etc/security/limits.d/cassandra.conf 32 | 33 | #JMX port 34 | EXPOSE 7199 35 | #storage_port 36 | EXPOSE 7000 37 | #ssl_storage_port (prev 7001 conflicts with etcd) 38 | EXPOSE 7002 39 | #rpc_port 40 | EXPOSE 9160 41 | #native_transport_port 42 | EXPOSE 9042 43 | #Hadoop Job Tracker client port 44 | #EXPOSE 8012 45 | #OpsCenter agent port 46 | #EXPOSE 61621 47 | 48 | # Place cluster-node startup-config script 49 | ADD cassandra-clusternode.sh /usr/local/bin/cassandra-clusternode 50 | 51 | # Fix to solve "JNA not found. Native methods will be disabled." 52 | RUN ln -s /usr/share/java/jna-*.jar /usr/share/cassandra/lib/ 53 | 54 | RUN mkdir -p /var/lib/cassandra/data /var/lib/cassandra/commitlog /var/lib/cassandra/saved_caches 55 | 56 | # Start Cassandra 57 | ENTRYPOINT ["cassandra-clusternode"] 58 | -------------------------------------------------------------------------------- /cassandra/cassandra-clusternode.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Get running container's IP 4 | IP=`hostname --ip-address | cut -f 1 -d ' '` 5 | if [ $# == 2 ]; then SEEDS="$2,$IP"; 6 | else SEEDS="$IP"; fi 7 | 8 | # Setup cluster name 9 | if [ -z "$CASSANDRA_CLUSTERNAME" ]; then 10 | echo "No cluster name specified, preserving default one" 11 | else 12 | sed -i -e "s/^cluster_name:.*/cluster_name: \"$CASSANDRA_CLUSTERNAME\"/" $CASSANDRA_CONFIG/cassandra.yaml 13 | fi 14 | 15 | # Dunno why zeroes here 16 | sed -i -e "s/^rpc_address.*/rpc_address: \"$IP\"/" $CASSANDRA_CONFIG/cassandra.yaml 17 | 18 | # Listen on IP:port of the container 19 | sed -i -e "s/^listen_address.*/listen_address: \"$IP\"/" $CASSANDRA_CONFIG/cassandra.yaml 20 | 21 | # Configure Cassandra seeds 22 | if [ -z "$CASSANDRA_SEEDS" ]; then 23 | echo "No seeds specified, being my own seed..." 24 | CASSANDRA_SEEDS=$SEEDS 25 | fi 26 | sed -i -e "s/- seeds: \"127.0.0.1\"/- seeds: \"$CASSANDRA_SEEDS\"/" $CASSANDRA_CONFIG/cassandra.yaml 27 | 28 | if [ -n "$BROADCAST_ADDR" ]; then 29 | sed -i -e "s/# broadcast_address: 1.2.3.4/broadcast_address: \"$BROADCAST_ADDR\"/g" $CASSANDRA_CONFIG/cassandra.yaml 30 | fi 31 | 32 | if [ -n "$CASSANDRA_SSL_STORAGE_PORT" ]; then 33 | sed -i -e "s/ssl_storage_port: .*/ssl_storage_port: $CASSANDRA_SSL_STORAGE_PORT/g" $CASSANDRA_CONFIG/cassandra.yaml 34 | fi 35 | 36 | if [ -n "$CASSANDRA_LOCAL_JMX" ]; then 37 | sed -i -e "s/\(^LOCAL_JMX=\).*/\1$CASSANDRA_LOCAL_JMX/g" $CASSANDRA_CONFIG/cassandra-env.sh 38 | PASSWORD=`openssl rand -base64 6` 39 | echo -e "\e[92mJMX credentials:\e[0m\n\e[92mUsername:\e[0m cassandra\n\e[92mPassword:\e[0m $PASSWORD" 40 | echo -e "monitorRole QED\ncontrolRole R&D\ncassandra $PASSWORD" > /etc/cassandra/jmxremote.password 41 | echo "cassandra readwrite" >> /usr/lib/jvm/jre-7-oracle-x64/lib/management/jmxremote.access 42 | chown cassandra:cassandra /etc/cassandra/jmxremote.password 43 | chmod 400 /etc/cassandra/jmxremote.password 44 | fi 45 | 46 | ## With virtual nodes disabled, we need to manually specify the token 47 | #if [ -z "$CASSANDRA_TOKEN" ]; then 48 | # echo "Missing initial token for Cassandra" 49 | # exit -1 50 | #fi 51 | # 52 | #echo "JVM_OPTS=\"\$JVM_OPTS -Dcassandra.initial_token=$CASSANDRA_TOKEN\"" >> $CASSANDRA_CONFIG/cassandra-env.sh 53 | 54 | # Most likely not needed 55 | echo "JVM_OPTS=\"\$JVM_OPTS -Djava.rmi.server.hostname=$IP\"" >> $CASSANDRA_CONFIG/cassandra-env.sh 56 | 57 | echo "Starting Cassandra on $IP..." 58 | 59 | cassandra -f 60 | -------------------------------------------------------------------------------- /cassandra/cassandra_repo_key: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: GnuPG v1.4.10 (GNU/Linux) 3 | 4 | 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 47 | RPmGJpOrBPU= 48 | =JGkB 49 | -----END PGP PUBLIC KEY BLOCK----- 50 | -------------------------------------------------------------------------------- /cassandra/expect: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect 2 | set timeout 600 3 | spawn /usr/bin/sudo -Hu nobody /bin/bash -c "cd /tmp && /usr/bin/make-jpkg jre-7u79-linux-x64.tar.gz" 4 | expect "Is this correct \\\[Y/n\\\]: " 5 | send "y\r" 6 | expect "Press \\\[Return\\\] to continue: " 7 | send "\r" 8 | expect "The Debian package has been created in the current directory." 9 | -------------------------------------------------------------------------------- /coreos-vagrant/.gitattributes: -------------------------------------------------------------------------------- 1 | # Detect text files automatically 2 | * text=auto 3 | 4 | # Force Unix-style line endings on these files 5 | user-data* text eol=lf 6 | -------------------------------------------------------------------------------- /coreos-vagrant/.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant/ 2 | log/ 3 | -------------------------------------------------------------------------------- /coreos-vagrant/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via 4 | GitHub pull requests. This document outlines some of the conventions on 5 | development workflow, commit message formatting, contact points and other 6 | resources to make it easier to get your contribution accepted. 7 | 8 | # Certificate of Origin 9 | 10 | By contributing to this project you agree to the Developer Certificate of 11 | Origin (DCO). This document was created by the Linux Kernel community and is a 12 | simple statement that you, as a contributor, have the legal right to make the 13 | contribution. See the [DCO](DCO) file for details. 14 | 15 | # Email and Chat 16 | 17 | The project currently uses the general CoreOS email list and IRC channel: 18 | - Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev) 19 | - IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org 20 | 21 | Please avoid emailing maintainers found in the MAINTAINERS file directly. They 22 | are very busy and read the mailing lists. 23 | 24 | ## Getting Started 25 | 26 | - Fork the repository on GitHub 27 | - Read the [README](README.md) for build and test instructions 28 | - Play with the project, submit bugs, submit patches! 29 | 30 | ## Contribution Flow 31 | 32 | This is a rough outline of what a contributor's workflow looks like: 33 | 34 | - Create a topic branch from where you want to base your work (usually master). 35 | - Make commits of logical units. 36 | - Make sure your commit messages are in the proper format (see below). 37 | - Push your changes to a topic branch in your fork of the repository. 38 | - Make sure the tests pass, and add any new tests as appropriate. 39 | - Submit a pull request to the original repository. 40 | 41 | Thanks for your contributions! 42 | 43 | ### Format of the Commit Message 44 | 45 | We follow a rough convention for commit messages that is designed to answer two 46 | questions: what changed and why. The subject line should feature the what and 47 | the body of the commit should describe the why. 48 | 49 | ``` 50 | scripts: add the test-cluster command 51 | 52 | this uses tmux to setup a test cluster that you can easily kill and 53 | start for debugging. 54 | 55 | Fixes #38 56 | ``` 57 | 58 | The format can be described more formally as follows: 59 | 60 | ``` 61 | : 62 | 63 | 64 | 65 |