├── LICENSE ├── Makefile ├── README.md ├── client.sh ├── install ├── Dockerfile.template ├── bin │ ├── install-cassandra │ ├── pipework │ ├── run-command │ └── start-cassandra ├── common.sh └── etc │ ├── cassandra.hosts │ ├── dnsmasq.conf │ └── resolv.conf ├── list-images.sh ├── start-cluster.sh └── stop-cluster.sh /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: help 3 | 4 | help: 5 | @echo 'To build a Docker image, run "make image VERSION=1.2.x"' 6 | 7 | check-version: 8 | ifndef VERSION 9 | @echo "Error: VERSION is undefined." 10 | @make --no-print-directory help 11 | @exit 1 12 | endif 13 | 14 | image: check-version 15 | sed -r -e "s/VERSION/$(VERSION)/g" install/Dockerfile.template > install/Dockerfile 16 | sudo docker build -t cassandra:$(VERSION) install/ 17 | rm -f install/Dockerfile 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Docker setup for Apache Cassandra 2 | ================================= 3 | 4 | This repository contains a set of scripts and configuration files to run a Cassandra cluster 5 | from [Docker](https://www.docker.io/) containers. The current version of this repository is 6 | configured to create a Cassandra 1.2 or 2.0 image and cluster. 7 | 8 | Example: 9 | 10 | ![Sample session](https://i.imgur.com/pS8twa3.gif) 11 | 12 | Cassandra nodes are created with their own IP address and configured hostname: 13 | 14 | $ ./start-cluster.sh 2.0.3 3 15 | Starting node 1 16 | Starting node 2 17 | Starting node 3 18 | 19 | $ ./client.sh 2.0.3 nodetool -h cass1 status 20 | Datacenter: datacenter1 21 | ======================= 22 | Status=Up/Down 23 | |/ State=Normal/Leaving/Joining/Moving 24 | -- Address Load Tokens Owns Host ID Rack 25 | UN 192.168.100.3 40.84 KB 256 34.9% 9d4a223f-e80e-4b50-b379-0705b1c8971d rack1 26 | UN 192.168.100.1 38.93 KB 256 33.7% 5128dcb0-14d0-4d17-9b53-acc8f9a0844b rack1 27 | UN 192.168.100.2 30.92 KB 256 31.4% 8e6faaba-601f-4812-a33b-05ceaecf1159 rack1 28 | 29 | Note that the nodes might take about 30 seconds to show up as they join the Cassandra ring. 30 | 31 | The shell scripts all assume that you have `sudo` privilege. 32 | 33 | Getting started 34 | --------------- 35 | 36 | ### 1. Check out this repository 37 | 38 | $ git clone https://github.com/nicolasff/docker-cassandra.git 39 | $ cd docker-cassandra 40 | 41 | ### 2. Install pipework 42 | 43 | Make sure that the bundled script `pipework` is in your path. You can install it with: 44 | 45 | $ sudo cp install/bin/pipework /usr/bin/ 46 | 47 | The latest version is on GitHub at https://github.com/jpetazzo/pipework. 48 | 49 | ### 3. Create a Docker image for Cassandra 50 | 51 | To create a Cassandra 2.0.3 image and tag it, run: 52 | 53 | $ make image VERSION=2.0.3 54 | 55 | You should then see it appear in your list of Docker images: 56 | 57 | $ sudo docker images 58 | REPOSITORY TAG ID CREATED SIZE 59 | cassandra 2.0.3 b9ba84a33bb5 About a minute ago 12.29 kB (virtual 404.7 MB) 60 | 61 | $ ./list-images.sh 62 | 2.0.3 63 | 64 | ### 4. Start a cluster 65 | 66 | Run `./start-cluster.sh 2.0.3 3` to create a cluster of 3 nodes running Cassandra 2.0.3. They are given an IP address and name each, from `cass1` (`192.168.100.1`) to `cass3` (`192.168.100.3`). 67 | 68 | Run `sudo docker ps` to list your Cassandra nodes: 69 | 70 | $ sudo docker ps 71 | ID IMAGE COMMAND CREATED STATUS PORTS 72 | 99d67692f535 cassandra:2.0.3 /usr/bin/start-cassa 10 minutes ago Up 10 minutes 49332->9160 73 | fe7e2b13cb9e cassandra:2.0.3 /usr/bin/start-cassa 10 minutes ago Up 10 minutes 49331->9160 74 | f21da380b00c cassandra:2.0.3 /usr/bin/start-cassa 10 minutes ago Up 10 minutes 49330->9160 75 | 76 | ### 5. Connect to your cluster 77 | 78 | Cassandra nodes expose port 9160 for Thrift. Use `sudo docker port 9160` or `sudo docker ps` to find the local port it is mapped to. 79 | 80 | `client.sh` creates a docker container with access to the Cassandra cluster network (`192.168.100.0/24`). The first client is given the name `cass254` 81 | with IP `192.168.100.254`, the next one `cass253`, etc. Names are reused when client containers are stopped. 82 | 83 | `client.sh` runs any command that is passed to it, e.g. `nodetool`, `cassandra-cli`, `cqlsh`... You can also open a shell with `./client.sh 2.0.3 bash`. 84 | 85 | ### 6. Terminate your cluster 86 | 87 | $ ./stop-cluster.sh 2.0.3 88 | Killing and removing containers 99d67692f535 fe7e2b13cb9e f21da380b00c 89 | 90 | $ sudo docker ps 91 | ID IMAGE COMMAND CREATED STATUS PORTS 92 | 93 | Licensing and contributions 94 | --------------------------- 95 | 96 | This set of scripts and configuration files is released under the [Apache 2.0 License](https://github.com/nicolasff/docker-cassandra/blob/master/LICENSE). 97 | `pipework` is Copyright 2013 [Jérôme Petazzoni](https://github.com/jpetazzo) and distributed under the Apache 2.0 license. 98 | 99 | Contributions and suggestions welcome [on GitHub](https://github.com/nicolasff/docker-cassandra/issues) or [on Twitter](https://twitter.com/yowgi). 100 | -------------------------------------------------------------------------------- /client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source install/common.sh 4 | 5 | if [[ $# -lt 2 ]]; then 6 | echo "Usage: $0 VERSION CMD [ARGS...]" 7 | echo "Creates a container that is connected to the Cassandra cluster, and run a command there" 8 | exit 1 9 | fi 10 | 11 | BRIDGE=br1 12 | VERSION=$1 13 | 14 | test_image $VERSION 15 | 16 | # We want to start the client containers from cass254, with decreasing IDs 17 | id=254 18 | while true; do 19 | hostname="cass$id" 20 | ip=192.168.100.$id 21 | available=1 22 | 23 | # echo "Checking if hostname $hostname is available..." 24 | 25 | cids=$(sudo docker ps | grep -w run-command | awk '{print $1}') 26 | for client_cid in $cids; do 27 | client_hostname=$(sudo docker inspect $client_cid | grep -w Hostname | sed -E -e 's/.*(cass[0-9]+).*/\1/g') 28 | # echo "Checking hostname of container $client_cid: $client_hostname" 29 | if [[ "$hostname" == "$client_hostname" ]]; then 30 | available=0 31 | fi 32 | done 33 | 34 | if [[ $id == 100 ]]; then 35 | echo "Could not find a hostname for this client" 36 | exit 1 37 | fi 38 | 39 | if [[ $available == 1 ]]; then 40 | break 41 | else 42 | id=$(($id-1)) 43 | fi 44 | done 45 | 46 | # start container 47 | shift # remove version number 48 | cid=$(sudo docker run -i -d --dns 127.0.0.1 -h $hostname -t cassandra:$VERSION /usr/bin/run-command $@) 49 | 50 | # Add network interface 51 | sleep 0.5 52 | sudo pipework $BRIDGE $cid $ip/24 53 | 54 | sudo docker attach $cid 55 | 56 | # Destroy container after use 57 | sudo docker kill $cid > /dev/null 58 | sudo docker rm $cid > /dev/null 59 | -------------------------------------------------------------------------------- /install/Dockerfile.template: -------------------------------------------------------------------------------- 1 | FROM ubuntu:precise 2 | MAINTAINER Nicolas Favre-Felix 3 | 4 | # Install dependencies 5 | RUN apt-get -y update 6 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes software-properties-common python-software-properties 7 | RUN add-apt-repository -y ppa:webupd8team/java 8 | RUN apt-get -y update 9 | RUN /bin/echo debconf shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections 10 | RUN DEBIAN_FRONTEND=noninteractive apt-get -y install oracle-java7-installer oracle-java7-set-default 11 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y wget dnsmasq-base python2.7 vim less iputils-ping 12 | 13 | # Install Cassandra 14 | ADD bin/install-cassandra /usr/bin/install-cassandra 15 | RUN install-cassandra VERSION 16 | 17 | # Install start scripts and hosts file 18 | ADD bin/pipework /usr/bin/ 19 | ADD bin/start-cassandra /usr/bin/ 20 | ADD bin/run-command /usr/bin/ 21 | 22 | # Configure host names 23 | ADD etc/cassandra.hosts /etc/dnsmasq.d/0hosts 24 | ADD etc/dnsmasq.conf /etc/dnsmasq.conf 25 | ADD etc/resolv.conf /etc/resolv.dnsmasq.conf 26 | 27 | EXPOSE 9160 9042 28 | -------------------------------------------------------------------------------- /install/bin/install-cassandra: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION=$1 4 | 5 | # Download and extract 6 | wget http://archive.apache.org/dist/cassandra/$VERSION/apache-cassandra-$VERSION-bin.tar.gz 7 | tar -xvzf apache-cassandra-$VERSION-bin.tar.gz 8 | rm -f apache-cassandra-$VERSION-bin.tar.gz 9 | mv apache-cassandra-$VERSION /root/ 10 | ln -sf /root/apache-cassandra-$VERSION /root/apache-cassandra 11 | 12 | # Configure 13 | CONFIG=/root/apache-cassandra/conf/cassandra.yaml 14 | ENV=/root/apache-cassandra/conf/cassandra-env.sh 15 | sed -i -e "s/^# num_tokens.*/num_tokens: 256/" $CONFIG 16 | sed -i -e "s/^listen_address.*/listen_address: /" $CONFIG 17 | sed -i -e "s/^rpc_address.*/rpc_address: 0.0.0.0/" $CONFIG 18 | sed -i -e 's/seeds: "127.0.0.1"/seeds: "cass1"/g' $CONFIG 19 | sed -i -e "s/Xss180k/Xss300k/g" $ENV 20 | -------------------------------------------------------------------------------- /install/bin/pipework: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | case "$1" in 5 | --wait) 6 | while ! grep -q ^up$ /sys/class/net/eth1/operstate 2>/dev/null 7 | do sleep 1 8 | done 9 | exit 0 10 | ;; 11 | esac 12 | 13 | IFNAME=$1 14 | GUESTNAME=$2 15 | IPADDR=$3 16 | MACADDR=$4 17 | 18 | [ "$IPADDR" ] || { 19 | echo "Syntax:" 20 | echo "pipework / [macaddr]" 21 | echo "pipework dhcp [macaddr]" 22 | echo "pipework --wait" 23 | exit 1 24 | } 25 | 26 | # First step: determine type of first argument (bridge, physical interface...) 27 | if [ -d /sys/class/net/$IFNAME ] 28 | then 29 | if [ -d /sys/class/net/$IFNAME/bridge ] 30 | then IFTYPE=bridge 31 | else IFTYPE=phys 32 | fi 33 | else 34 | case "$IFNAME" in 35 | br*) 36 | IFTYPE=bridge 37 | ;; 38 | *) 39 | echo "I do not know how to setup interface $IFNAME." 40 | exit 1 41 | ;; 42 | esac 43 | fi 44 | 45 | # Second step: find the guest (for now, we only support LXC containers) 46 | while read dev mnt fstype options dump fsck 47 | do 48 | [ "$fstype" != "cgroup" ] && continue 49 | echo $options | grep -qw devices || continue 50 | CGROUPMNT=$mnt 51 | done < /proc/mounts 52 | 53 | [ "$CGROUPMNT" ] || { 54 | echo "Could not locate cgroup mount point." 55 | exit 1 56 | } 57 | 58 | N=$(find "$CGROUPMNT" -name "$GUESTNAME*" | wc -l) 59 | case "$N" in 60 | 0) 61 | echo "Could not find any container matching $GUESTNAME." 62 | exit 1 63 | ;; 64 | 1) 65 | true 66 | ;; 67 | *) 68 | echo "Found more than one container matching $GUESTNAME." 69 | exit 1 70 | ;; 71 | esac 72 | 73 | if [ "$IPADDR" = "dhcp" ] 74 | then 75 | # We use udhcpc to obtain the DHCP lease, make sure it's installed. 76 | which udhcpc >/dev/null || { 77 | echo "You asked for DHCP; please install udhcpc first." 78 | exit 1 79 | } 80 | else 81 | # Check if a subnet mask was provided. 82 | echo $IPADDR | grep -q / || { 83 | echo "The IP address should include a netmask." 84 | echo "Maybe you meant $IPADDR/24 ?" 85 | exit 1 86 | } 87 | fi 88 | 89 | NSPID=$(head -n 1 $(find "$CGROUPMNT" -name "$GUESTNAME*" | head -n 1)/tasks) 90 | [ "$NSPID" ] || { 91 | echo "Could not find a process inside container $GUESTNAME." 92 | exit 1 93 | } 94 | mkdir -p /var/run/netns 95 | rm -f /var/run/netns/$NSPID 96 | ln -s /proc/$NSPID/ns/net /var/run/netns/$NSPID 97 | 98 | 99 | # Check if we need to create a bridge. 100 | [ $IFTYPE = bridge ] && [ ! -d /sys/class/net/$IFNAME ] && { 101 | ip link add $IFNAME type bridge 102 | ip link set $IFNAME up 103 | } 104 | 105 | # If it's a bridge, we need to create a veth pair 106 | [ $IFTYPE = bridge ] && { 107 | LOCAL_IFNAME=vethl$NSPID 108 | GUEST_IFNAME=vethg$NSPID 109 | ip link add name $LOCAL_IFNAME type veth peer name $GUEST_IFNAME 110 | ip link set $LOCAL_IFNAME master $IFNAME 111 | ip link set $LOCAL_IFNAME up 112 | } 113 | 114 | # If it's a physical interface, create a macvlan subinterface 115 | [ $IFTYPE = phys ] && { 116 | GUEST_IFNAME=macvlan$NSPID 117 | ip link add link $IFNAME dev $GUEST_IFNAME type macvlan mode bridge 118 | ip link set $IFNAME up 119 | } 120 | 121 | ip link set $GUEST_IFNAME netns $NSPID 122 | ip netns exec $NSPID ip link set $GUEST_IFNAME name eth1 123 | [ "$MACADDR" ] && ip netns exec $NSPID ip link set eth1 address $MACADDR 124 | if [ "$IPADDR" = "dhcp" ] 125 | then 126 | ip netns exec $NSPID udhcpc -qi eth1 127 | else 128 | ip netns exec $NSPID ip addr add $IPADDR dev eth1 129 | ip netns exec $NSPID ip link set eth1 up 130 | fi 131 | -------------------------------------------------------------------------------- /install/bin/run-command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pipework --wait 4 | dnsmasq 5 | 6 | export PATH=$PATH:/root/apache-cassandra/bin 7 | $@ 8 | -------------------------------------------------------------------------------- /install/bin/start-cassandra: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pipework --wait 4 | dnsmasq 5 | 6 | IP=$(grep -w $(hostname) /etc/dnsmasq.d/0hosts | cut -f 3 -d / | sed -e 's/"//g') 7 | CONFIG=/root/apache-cassandra/conf/cassandra.yaml 8 | ENV=/root/apache-cassandra/conf/cassandra-env.sh 9 | 10 | # Change the listen address so that we can communicate with other nodes 11 | sed -i -e "s/^listen_address.*/listen_address: $IP/" $CONFIG 12 | sed -i -e "s/^rpc_address.*/rpc_address: 0.0.0.0/" $CONFIG 13 | 14 | # wait 10 seconds instead of 30 15 | export JVM_OPTS="-Dcassandra.ring_delay_ms=10000" 16 | 17 | # Fix JMX settings 18 | sed -i -e 's/# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname="/JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname='$IP'"/g' $ENV 19 | 20 | # Fix seeds list for the seed node 21 | if [[ $(hostname) -eq "cass1" ]]; then 22 | sed -i -e 's/seeds: "cass1"/seeds: "192.168.100.1"/g' $CONFIG 23 | fi 24 | 25 | /root/apache-cassandra/bin/cassandra -f 26 | -------------------------------------------------------------------------------- /install/common.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | # test that an image exists 4 | function test_image() { 5 | version=$1 6 | image=cassandra:$version 7 | sudo docker history $image > /dev/null 2> /dev/null 8 | if [[ $? != 0 ]]; then 9 | echo "Could not find Docker image $image, use 'make image VERSION=$version' to build it" 10 | exit 1 11 | fi 12 | } 13 | 14 | # Argc test + usage help 15 | function check_usage() { 16 | argc=$1 17 | expected=$2 18 | usage=$3 19 | 20 | if [[ $argc -ne $expected ]]; then 21 | echo -e $usage 22 | exit 1 23 | fi 24 | } 25 | -------------------------------------------------------------------------------- /install/etc/cassandra.hosts: -------------------------------------------------------------------------------- 1 | address="/cass1/192.168.100.1" 2 | address="/cass2/192.168.100.2" 3 | address="/cass3/192.168.100.3" 4 | address="/cass4/192.168.100.4" 5 | address="/cass5/192.168.100.5" 6 | address="/cass6/192.168.100.6" 7 | address="/cass7/192.168.100.7" 8 | address="/cass8/192.168.100.8" 9 | address="/cass9/192.168.100.9" 10 | address="/cass10/192.168.100.10" 11 | address="/cass11/192.168.100.11" 12 | address="/cass12/192.168.100.12" 13 | address="/cass13/192.168.100.13" 14 | address="/cass14/192.168.100.14" 15 | address="/cass15/192.168.100.15" 16 | address="/cass16/192.168.100.16" 17 | address="/cass17/192.168.100.17" 18 | address="/cass18/192.168.100.18" 19 | address="/cass19/192.168.100.19" 20 | address="/cass20/192.168.100.20" 21 | address="/cass21/192.168.100.21" 22 | address="/cass22/192.168.100.22" 23 | address="/cass23/192.168.100.23" 24 | address="/cass24/192.168.100.24" 25 | address="/cass25/192.168.100.25" 26 | address="/cass26/192.168.100.26" 27 | address="/cass27/192.168.100.27" 28 | address="/cass28/192.168.100.28" 29 | address="/cass29/192.168.100.29" 30 | address="/cass30/192.168.100.30" 31 | address="/cass31/192.168.100.31" 32 | address="/cass32/192.168.100.32" 33 | address="/cass33/192.168.100.33" 34 | address="/cass34/192.168.100.34" 35 | address="/cass35/192.168.100.35" 36 | address="/cass36/192.168.100.36" 37 | address="/cass37/192.168.100.37" 38 | address="/cass38/192.168.100.38" 39 | address="/cass39/192.168.100.39" 40 | address="/cass40/192.168.100.40" 41 | address="/cass41/192.168.100.41" 42 | address="/cass42/192.168.100.42" 43 | address="/cass43/192.168.100.43" 44 | address="/cass44/192.168.100.44" 45 | address="/cass45/192.168.100.45" 46 | address="/cass46/192.168.100.46" 47 | address="/cass47/192.168.100.47" 48 | address="/cass48/192.168.100.48" 49 | address="/cass49/192.168.100.49" 50 | address="/cass50/192.168.100.50" 51 | address="/cass51/192.168.100.51" 52 | address="/cass52/192.168.100.52" 53 | address="/cass53/192.168.100.53" 54 | address="/cass54/192.168.100.54" 55 | address="/cass55/192.168.100.55" 56 | address="/cass56/192.168.100.56" 57 | address="/cass57/192.168.100.57" 58 | address="/cass58/192.168.100.58" 59 | address="/cass59/192.168.100.59" 60 | address="/cass60/192.168.100.60" 61 | address="/cass61/192.168.100.61" 62 | address="/cass62/192.168.100.62" 63 | address="/cass63/192.168.100.63" 64 | address="/cass64/192.168.100.64" 65 | address="/cass65/192.168.100.65" 66 | address="/cass66/192.168.100.66" 67 | address="/cass67/192.168.100.67" 68 | address="/cass68/192.168.100.68" 69 | address="/cass69/192.168.100.69" 70 | address="/cass70/192.168.100.70" 71 | address="/cass71/192.168.100.71" 72 | address="/cass72/192.168.100.72" 73 | address="/cass73/192.168.100.73" 74 | address="/cass74/192.168.100.74" 75 | address="/cass75/192.168.100.75" 76 | address="/cass76/192.168.100.76" 77 | address="/cass77/192.168.100.77" 78 | address="/cass78/192.168.100.78" 79 | address="/cass79/192.168.100.79" 80 | address="/cass80/192.168.100.80" 81 | address="/cass81/192.168.100.81" 82 | address="/cass82/192.168.100.82" 83 | address="/cass83/192.168.100.83" 84 | address="/cass84/192.168.100.84" 85 | address="/cass85/192.168.100.85" 86 | address="/cass86/192.168.100.86" 87 | address="/cass87/192.168.100.87" 88 | address="/cass88/192.168.100.88" 89 | address="/cass89/192.168.100.89" 90 | address="/cass90/192.168.100.90" 91 | address="/cass91/192.168.100.91" 92 | address="/cass92/192.168.100.92" 93 | address="/cass93/192.168.100.93" 94 | address="/cass94/192.168.100.94" 95 | address="/cass95/192.168.100.95" 96 | address="/cass96/192.168.100.96" 97 | address="/cass97/192.168.100.97" 98 | address="/cass98/192.168.100.98" 99 | address="/cass99/192.168.100.99" 100 | address="/cass100/192.168.100.100" 101 | address="/cass101/192.168.100.101" 102 | address="/cass102/192.168.100.102" 103 | address="/cass103/192.168.100.103" 104 | address="/cass104/192.168.100.104" 105 | address="/cass105/192.168.100.105" 106 | address="/cass106/192.168.100.106" 107 | address="/cass107/192.168.100.107" 108 | address="/cass108/192.168.100.108" 109 | address="/cass109/192.168.100.109" 110 | address="/cass110/192.168.100.110" 111 | address="/cass111/192.168.100.111" 112 | address="/cass112/192.168.100.112" 113 | address="/cass113/192.168.100.113" 114 | address="/cass114/192.168.100.114" 115 | address="/cass115/192.168.100.115" 116 | address="/cass116/192.168.100.116" 117 | address="/cass117/192.168.100.117" 118 | address="/cass118/192.168.100.118" 119 | address="/cass119/192.168.100.119" 120 | address="/cass120/192.168.100.120" 121 | address="/cass121/192.168.100.121" 122 | address="/cass122/192.168.100.122" 123 | address="/cass123/192.168.100.123" 124 | address="/cass124/192.168.100.124" 125 | address="/cass125/192.168.100.125" 126 | address="/cass126/192.168.100.126" 127 | address="/cass127/192.168.100.127" 128 | address="/cass128/192.168.100.128" 129 | address="/cass129/192.168.100.129" 130 | address="/cass130/192.168.100.130" 131 | address="/cass131/192.168.100.131" 132 | address="/cass132/192.168.100.132" 133 | address="/cass133/192.168.100.133" 134 | address="/cass134/192.168.100.134" 135 | address="/cass135/192.168.100.135" 136 | address="/cass136/192.168.100.136" 137 | address="/cass137/192.168.100.137" 138 | address="/cass138/192.168.100.138" 139 | address="/cass139/192.168.100.139" 140 | address="/cass140/192.168.100.140" 141 | address="/cass141/192.168.100.141" 142 | address="/cass142/192.168.100.142" 143 | address="/cass143/192.168.100.143" 144 | address="/cass144/192.168.100.144" 145 | address="/cass145/192.168.100.145" 146 | address="/cass146/192.168.100.146" 147 | address="/cass147/192.168.100.147" 148 | address="/cass148/192.168.100.148" 149 | address="/cass149/192.168.100.149" 150 | address="/cass150/192.168.100.150" 151 | address="/cass151/192.168.100.151" 152 | address="/cass152/192.168.100.152" 153 | address="/cass153/192.168.100.153" 154 | address="/cass154/192.168.100.154" 155 | address="/cass155/192.168.100.155" 156 | address="/cass156/192.168.100.156" 157 | address="/cass157/192.168.100.157" 158 | address="/cass158/192.168.100.158" 159 | address="/cass159/192.168.100.159" 160 | address="/cass160/192.168.100.160" 161 | address="/cass161/192.168.100.161" 162 | address="/cass162/192.168.100.162" 163 | address="/cass163/192.168.100.163" 164 | address="/cass164/192.168.100.164" 165 | address="/cass165/192.168.100.165" 166 | address="/cass166/192.168.100.166" 167 | address="/cass167/192.168.100.167" 168 | address="/cass168/192.168.100.168" 169 | address="/cass169/192.168.100.169" 170 | address="/cass170/192.168.100.170" 171 | address="/cass171/192.168.100.171" 172 | address="/cass172/192.168.100.172" 173 | address="/cass173/192.168.100.173" 174 | address="/cass174/192.168.100.174" 175 | address="/cass175/192.168.100.175" 176 | address="/cass176/192.168.100.176" 177 | address="/cass177/192.168.100.177" 178 | address="/cass178/192.168.100.178" 179 | address="/cass179/192.168.100.179" 180 | address="/cass180/192.168.100.180" 181 | address="/cass181/192.168.100.181" 182 | address="/cass182/192.168.100.182" 183 | address="/cass183/192.168.100.183" 184 | address="/cass184/192.168.100.184" 185 | address="/cass185/192.168.100.185" 186 | address="/cass186/192.168.100.186" 187 | address="/cass187/192.168.100.187" 188 | address="/cass188/192.168.100.188" 189 | address="/cass189/192.168.100.189" 190 | address="/cass190/192.168.100.190" 191 | address="/cass191/192.168.100.191" 192 | address="/cass192/192.168.100.192" 193 | address="/cass193/192.168.100.193" 194 | address="/cass194/192.168.100.194" 195 | address="/cass195/192.168.100.195" 196 | address="/cass196/192.168.100.196" 197 | address="/cass197/192.168.100.197" 198 | address="/cass198/192.168.100.198" 199 | address="/cass199/192.168.100.199" 200 | address="/cass200/192.168.100.200" 201 | address="/cass201/192.168.100.201" 202 | address="/cass202/192.168.100.202" 203 | address="/cass203/192.168.100.203" 204 | address="/cass204/192.168.100.204" 205 | address="/cass205/192.168.100.205" 206 | address="/cass206/192.168.100.206" 207 | address="/cass207/192.168.100.207" 208 | address="/cass208/192.168.100.208" 209 | address="/cass209/192.168.100.209" 210 | address="/cass210/192.168.100.210" 211 | address="/cass211/192.168.100.211" 212 | address="/cass212/192.168.100.212" 213 | address="/cass213/192.168.100.213" 214 | address="/cass214/192.168.100.214" 215 | address="/cass215/192.168.100.215" 216 | address="/cass216/192.168.100.216" 217 | address="/cass217/192.168.100.217" 218 | address="/cass218/192.168.100.218" 219 | address="/cass219/192.168.100.219" 220 | address="/cass220/192.168.100.220" 221 | address="/cass221/192.168.100.221" 222 | address="/cass222/192.168.100.222" 223 | address="/cass223/192.168.100.223" 224 | address="/cass224/192.168.100.224" 225 | address="/cass225/192.168.100.225" 226 | address="/cass226/192.168.100.226" 227 | address="/cass227/192.168.100.227" 228 | address="/cass228/192.168.100.228" 229 | address="/cass229/192.168.100.229" 230 | address="/cass230/192.168.100.230" 231 | address="/cass231/192.168.100.231" 232 | address="/cass232/192.168.100.232" 233 | address="/cass233/192.168.100.233" 234 | address="/cass234/192.168.100.234" 235 | address="/cass235/192.168.100.235" 236 | address="/cass236/192.168.100.236" 237 | address="/cass237/192.168.100.237" 238 | address="/cass238/192.168.100.238" 239 | address="/cass239/192.168.100.239" 240 | address="/cass240/192.168.100.240" 241 | address="/cass241/192.168.100.241" 242 | address="/cass242/192.168.100.242" 243 | address="/cass243/192.168.100.243" 244 | address="/cass244/192.168.100.244" 245 | address="/cass245/192.168.100.245" 246 | address="/cass246/192.168.100.246" 247 | address="/cass247/192.168.100.247" 248 | address="/cass248/192.168.100.248" 249 | address="/cass249/192.168.100.249" 250 | address="/cass250/192.168.100.250" 251 | address="/cass251/192.168.100.251" 252 | address="/cass252/192.168.100.252" 253 | address="/cass253/192.168.100.253" 254 | address="/cass254/192.168.100.254" 255 | -------------------------------------------------------------------------------- /install/etc/dnsmasq.conf: -------------------------------------------------------------------------------- 1 | user=root 2 | listen-address=127.0.0.1 3 | resolv-file=/etc/resolv.dnsmasq.conf 4 | conf-dir=/etc/dnsmasq.d 5 | -------------------------------------------------------------------------------- /install/etc/resolv.conf: -------------------------------------------------------------------------------- 1 | nameserver 8.8.8.8 2 | nameserver 8.8.4.4 3 | -------------------------------------------------------------------------------- /list-images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo docker images | grep -w '^cassandra' | awk '{print $2}' | sort | uniq 4 | -------------------------------------------------------------------------------- /start-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source install/common.sh 4 | 5 | check_usage $# 2 "Usage: $0 " 6 | 7 | VERSION=$1 8 | NODES=$2 9 | BRIDGE=br1 10 | 11 | test_image $VERSION 12 | 13 | for id in $(seq 1 $NODES); do 14 | 15 | echo "Starting node $id" 16 | hostname="cass$id" 17 | ip=192.168.100.$id 18 | 19 | # start container 20 | if [[ $id == 1 ]]; then 21 | ports="-p 9160:9160 -p 9042:9042" 22 | else 23 | ports="" 24 | fi 25 | cid=$(sudo docker run -d --dns 127.0.0.1 -h $hostname $ports -t cassandra:$VERSION /usr/bin/start-cassandra) 26 | 27 | # Add network interface 28 | sleep 1 29 | sudo pipework $BRIDGE $cid $ip/24 30 | 31 | done 32 | -------------------------------------------------------------------------------- /stop-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source install/common.sh 4 | 5 | check_usage $# 1 "Usage: $0 " 6 | 7 | VERSION=$1 8 | IMAGE=cassandra:$VERSION 9 | 10 | test_image $VERSION 11 | 12 | if sudo docker ps | grep $IMAGE >/dev/null; then 13 | cids=$(sudo docker ps | grep $IMAGE | awk '{ print $1 }') 14 | echo $cids | xargs echo "Killing and removing containers" 15 | sudo docker kill $cids > /dev/null 16 | sudo docker rm $cids > /dev/null 17 | fi 18 | --------------------------------------------------------------------------------