├── .gitignore ├── Dockerfile ├── Dockerfile.influxdb ├── Makefile ├── README.md ├── config.toml ├── integration ├── data_test_client.go ├── influxdb_test.go └── test_data.json └── run_influxdb /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | pid 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM google/golang:1.3.1 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | #install docker and go build tools 6 | RUN echo 'deb http://http.debian.net/debian wheezy-backports main' >> /etc/apt/sources.list \ 7 | && apt-get update \ 8 | && apt-get install -y -t wheezy-backports linux-image-amd64 \ 9 | mercurial bzr protobuf-compiler flex bison libgflags-dev libsnappy-dev\ 10 | valgrind g++ make autoconf libtool libz-dev libbz2-dev zlib1g-dev curl \ 11 | rpm build-essential git wget gawk \ 12 | && curl -sSL https://get.docker.io/ | sh 13 | 14 | #checkout InfluxDB version 0.8.6 15 | RUN mkdir -p $GOPATH/src/github.com/influxdb && \ 16 | cd $GOPATH/src/github.com/influxdb && \ 17 | git clone https://github.com/influxdb/influxdb.git && \ 18 | cd influxdb && git checkout tags/v0.8.6 19 | 20 | WORKDIR $GOPATH/src/github.com/influxdb/influxdb 21 | 22 | #configure and build binary as a static binary 23 | ENV GO_BUILD_OPTIONS --ldflags '-s -extldflags "-static"' 24 | RUN ./configure 25 | RUN make build_binary 26 | 27 | ADD config.toml $GOPATH/src/github.com/influxdb/influxdb/config.toml 28 | ADD run_influxdb $GOPATH/src/github.com/influxdb/influxdb/run_influxdb 29 | ADD Dockerfile.influxdb $GOPATH/src/github.com/influxdb/influxdb/Dockerfile 30 | 31 | CMD docker build -t influxdb-min $GOPATH/src/github.com/influxdb/influxdb 32 | -------------------------------------------------------------------------------- /Dockerfile.influxdb: -------------------------------------------------------------------------------- 1 | FROM busybox 2 | 3 | ADD influxdb /usr/bin/influxdb 4 | ADD run_influxdb /usr/bin/run_influxdb 5 | ADD config.toml /etc/influxdb/config.toml 6 | 7 | EXPOSE 8083 8086 8090 8099 8 | 9 | CMD ["/usr/bin/run_influxdb"] 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build deploy destroy shell test 2 | 3 | PORT_MAPPINGS := -p 8083:8083 -p 8086:8086 -p 8084:8084 -p 8090:8090 -p 8099:8099 4 | 5 | default: build 6 | build: 7 | docker build -t influxdb-build . 8 | docker run -rm -v /var/run/docker.sock:/var/run/docker.sock influxdb-build 9 | deploy: 10 | docker run -d $(PORT_MAPPINGS) influxdb-min > pid 11 | destroy: 12 | docker rm -f $(shell cat pid) && rm pid 13 | shell: 14 | docker run --rm $(PORT_MAPPINGS) -t -i influxdb-min /bin/ash 15 | test: 16 | go test ./integration 17 | release: 18 | docker tag influxdb-min allen13/influxdb-min 19 | docker push allen13/influxdb-min 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ####DockerHub repo 2 | docker pull allen13/influxdb-min 3 | ####Minimum docker image from busybox for influxdb 4 | * Total size: 18.02 MB 5 | 6 | * See [Create The Smallest Possible Docker Container](http://blog.xebia.com/2014/07/04/create-the-smallest-possible-docker-container/) 7 | * Influxdb docker image referenced from: [tutum-docker-influxdb](https://github.com/tutumcloud/tutum-docker-influxdb) 8 | 9 | It builds two images, first influxdb-build, and then influxdb-min by running influxdb-build. 10 | 11 | You should see some outputs similar to: 12 | 13 | ... 14 | Successfully built c2a85185ca6f 15 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 16 | influxdb-min latest c0f1eba0f177 7 minutes ago 18.02 MB 17 | influxdb-build latest 65fe5c5e641b 7 minutes ago 1.526 GB 18 | 19 | 20 | 21 | ####Runtime configuration templating through environment variables 22 | Currently supported variables: 23 | 24 | docker run -d \ 25 | -e SEED="master:8090" \ 26 | -e REPLICATION_FACTOR="2" \ 27 | -e HOSTNAME="localhost" \ 28 | influxdb-min 29 | 30 | Add more substitutions to run_influxdb as needed. 31 | 32 | ####Interacting with the image locally 33 | Use the Makefile for convienient local interactions: 34 | - **make or make build** - build image 35 | - **make deploy** - detached image deploy 36 | - **make test** - test deployed image 37 | - **make destroy** - destroy deployed image 38 | - **make shell** - go interactive with the ash shell 39 | -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | # Welcome to the InfluxDB configuration file. 2 | 3 | # If hostname (on the OS) doesn't return a name that can be resolved by the other 4 | # systems in the cluster, you'll have to set the hostname to an IP or something 5 | # that can be resolved here. 6 | # hostname = "" 7 | 8 | bind-address = "0.0.0.0" 9 | 10 | # Once every 24 hours InfluxDB will report anonymous data to m.influxdb.com 11 | # The data includes raft name (random 8 bytes), os, arch and version 12 | # We don't track ip addresses of servers reporting. This is only used 13 | # to track the number of instances running and the versions which 14 | # is very helpful for us. 15 | # Change this option to true to disable reporting. 16 | reporting-disabled = false 17 | 18 | [logging] 19 | # logging level can be one of "debug", "info", "warn" or "error" 20 | level = "info" 21 | file = "/data/influxdb/influxdb.log" # stdout to log to standard out 22 | 23 | # Configure the admin server 24 | [admin] 25 | port = 8083 # binding is disabled if the port isn't set 26 | assets = "./admin" 27 | 28 | # Configure the http api 29 | [api] 30 | port = 8086 # binding is disabled if the port isn't set 31 | # ssl-port = 8084 # Ssl support is enabled if you set a port and cert 32 | # ssl-cert = /path/to/cert.pem 33 | 34 | # connections will timeout after this amount of time. Ensures that clients that misbehave 35 | # and keep alive connections they don't use won't end up connection a million times. 36 | # However, if a request is taking longer than this to complete, could be a problem. 37 | read-timeout = "5s" 38 | 39 | [input_plugins] 40 | 41 | # Configure the graphite api 42 | [input_plugins.graphite] 43 | enabled = false 44 | # port = 2003 45 | # database = "" # store graphite data in this database 46 | 47 | # Raft configuration 48 | [raft] 49 | # The raft port should be open between all servers in a cluster. 50 | # However, this port shouldn't be accessible from the internet. 51 | 52 | port = 8090 53 | 54 | # Where the raft logs are stored. The user running InfluxDB will need read/write access. 55 | dir = "/data/influxdb/development/raft" 56 | 57 | # election-timeout = "1s" 58 | 59 | [storage] 60 | dir = "/data/influxdb/development/db" 61 | # How many requests to potentially buffer in memory. If the buffer gets filled then writes 62 | # will still be logged and once the local storage has caught up (or compacted) the writes 63 | # will be replayed from the WAL 64 | write-buffer-size = 10000 65 | 66 | [cluster] 67 | # A comma separated list of servers to seed 68 | # this server. this is only relevant when the 69 | # server is joining a new cluster. Otherwise 70 | # the server will use the list of known servers 71 | # prior to shutting down. Any server can be pointed to 72 | # as a seed. It will find the Raft leader automatically. 73 | 74 | # Here's an example. Note that the port on the host is the same as the raft port. 75 | # seed-servers = ["hosta:8090","hostb:8090"] 76 | 77 | # Replication happens over a TCP connection with a Protobuf protocol. 78 | # This port should be reachable between all servers in a cluster. 79 | # However, this port shouldn't be accessible from the internet. 80 | 81 | protobuf_port = 8099 82 | protobuf_timeout = "2s" # the write timeout on the protobuf conn any duration parseable by time.ParseDuration 83 | protobuf_heartbeat = "200ms" # the heartbeat interval between the servers. must be parseable by time.ParseDuration 84 | protobuf_min_backoff = "1s" # the minimum backoff after a failed heartbeat attempt 85 | protobuf_max_backoff = "10s" # the maxmimum backoff after a failed heartbeat attempt 86 | 87 | # How many write requests to potentially buffer in memory per server. If the buffer gets filled then writes 88 | # will still be logged and once the server has caught up (or come back online) the writes 89 | # will be replayed from the WAL 90 | write-buffer-size = 10000 91 | 92 | # the maximum number of responses to buffer from remote nodes, if the 93 | # expected number of responses exceed this number then querying will 94 | # happen sequentially and the buffer size will be limited to this 95 | # number 96 | max-response-buffer-size = 100000 97 | 98 | # When queries get distributed out to shards, they go in parallel. This means that results can get buffered 99 | # in memory since results will come in any order, but have to be processed in the correct time order. 100 | # Setting this higher will give better performance, but you'll need more memory. Setting this to 1 will ensure 101 | # that you don't need to buffer in memory, but you won't get the best performance. 102 | concurrent-shard-query-limit = 10 103 | 104 | [leveldb] 105 | 106 | # Maximum mmap open files, this will affect the virtual memory used by 107 | # the process 108 | max-open-files = 40 109 | 110 | # LRU cache size, LRU is used by leveldb to store contents of the 111 | # uncompressed sstables. You can use `m` or `g` prefix for megabytes 112 | # and gigabytes, respectively. 113 | lru-cache-size = "200m" 114 | 115 | # The default setting on this is 0, which means unlimited. Set this to something if you want to 116 | # limit the max number of open files. max-open-files is per shard so this * that will be max. 117 | max-open-shards = 0 118 | 119 | # The default setting is 100. This option tells how many points will be fetched from LevelDb before 120 | # they get flushed into backend. 121 | point-batch-size = 100 122 | 123 | # These options specify how data is sharded across the cluster. There are two 124 | # shard configurations that have the same knobs: short term and long term. 125 | # Any series that begins with a capital letter like Exceptions will be written 126 | # into the long term storage. Any series beginning with a lower case letter 127 | # like exceptions will be written into short term. The idea being that you 128 | # can write high precision data into short term and drop it after a couple 129 | # of days. Meanwhile, continuous queries can run downsampling on the short term 130 | # data and write into the long term area. 131 | [sharding] 132 | # how many servers in the cluster should have a copy of each shard. 133 | # this will give you high availability and scalability on queries 134 | replication-factor = 1 135 | 136 | [sharding.short-term] 137 | # each shard will have this period of time. Note that it's best to have 138 | # group by time() intervals on all queries be < than this setting. If they are 139 | # then the aggregate is calculated locally. Otherwise, all that data gets sent 140 | # over the network when doing a query. 141 | duration = "7d" 142 | 143 | # split will determine how many shards to split each duration into. For example, 144 | # if we created a shard for 2014-02-10 and split was set to 2. Then two shards 145 | # would be created that have the data for 2014-02-10. By default, data will 146 | # be split into those two shards deterministically by hashing the (database, serise) 147 | # tuple. That means that data for a given series will be written to a single shard 148 | # making querying efficient. That can be overridden with the next option. 149 | split = 1 150 | 151 | # You can override the split behavior to have the data for series that match a 152 | # given regex be randomly distributed across the shards for a given interval. 153 | # You can use this if you have a hot spot for a given time series writing more 154 | # data than a single server can handle. Most people won't have to resort to this 155 | # option. Also note that using this option means that queries will have to send 156 | # all data over the network so they won't be as efficient. 157 | # split-random = "/^hf.*/" 158 | 159 | [sharding.long-term] 160 | duration = "30d" 161 | split = 1 162 | # split-random = "/^Hf.*/" 163 | 164 | [wal] 165 | 166 | dir = "/data/influxdb/development/wal" 167 | flush-after = 1000 # the number of writes after which wal will be flushed, 0 for flushing on every write 168 | bookmark-after = 1000 # the number of writes after which a bookmark will be created 169 | 170 | # the number of writes after which an index entry is created pointing 171 | # to the offset of the first request, default to 1k 172 | index-after = 1000 173 | 174 | # the number of requests per one log file, if new requests came in a 175 | # new log file will be created 176 | requests-per-logfile = 10000 177 | -------------------------------------------------------------------------------- /integration/data_test_client.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "net/http" 7 | "time" 8 | influxdb "github.com/influxdb/influxdb/client" 9 | . "gopkg.in/check.v1" 10 | ) 11 | 12 | type DataTestClient struct { 13 | db string 14 | } 15 | 16 | func (self *DataTestClient) CreateDatabase(db string, c *C) { 17 | client, err := influxdb.NewClient(&influxdb.ClientConfig{}) 18 | c.Assert(err, IsNil) 19 | c.Assert(client.CreateDatabase(db), IsNil) 20 | } 21 | 22 | func (self *DataTestClient) SetDB(db string) { 23 | self.db = db 24 | } 25 | 26 | func (self *DataTestClient) WriteData(series []*influxdb.Series, c *C, timePrecision ...influxdb.TimePrecision) { 27 | client, err := influxdb.NewClient(&influxdb.ClientConfig{ 28 | Database: self.db, 29 | HttpClient: &http.Client{ 30 | Timeout: 60 * time.Second, 31 | }, 32 | }) 33 | c.Assert(err, IsNil) 34 | if len(timePrecision) == 0 { 35 | c.Assert(client.WriteSeries(series), IsNil) 36 | } else { 37 | c.Assert(client.WriteSeriesWithTimePrecision(series, timePrecision[0]), IsNil) 38 | } 39 | } 40 | 41 | func (self *DataTestClient) WriteJsonData(seriesString string, c *C, timePrecision ...influxdb.TimePrecision) { 42 | series := []*influxdb.Series{} 43 | decoder := json.NewDecoder(bytes.NewBufferString(seriesString)) 44 | decoder.UseNumber() 45 | err := decoder.Decode(&series) 46 | c.Assert(err, IsNil) 47 | self.WriteData(series, c, timePrecision...) 48 | } 49 | 50 | func (self *DataTestClient) RunQuery(query string, c *C, timePrecision ...influxdb.TimePrecision) []*influxdb.Series { 51 | client, err := influxdb.NewClient(&influxdb.ClientConfig{Database: self.db}) 52 | c.Assert(err, IsNil) 53 | series, err := client.Query(query, timePrecision...) 54 | c.Assert(err, IsNil) 55 | return series 56 | } 57 | 58 | func (self *DataTestClient) RunQueryWithNumbers(query string, c *C, timePrecision ...influxdb.TimePrecision) []*influxdb.Series { 59 | client, err := influxdb.NewClient(&influxdb.ClientConfig{Database: self.db}) 60 | c.Assert(err, IsNil) 61 | series, err := client.QueryWithNumbers(query, timePrecision...) 62 | c.Assert(err, IsNil) 63 | return series 64 | } 65 | 66 | func (self *DataTestClient) RunInvalidQuery(query string, c *C, timePrecision ...influxdb.TimePrecision) []*influxdb.Series { 67 | client, err := influxdb.NewClient(&influxdb.ClientConfig{Database: self.db}) 68 | c.Assert(err, IsNil) 69 | _, err = client.Query(query, timePrecision...) 70 | c.Assert(err, NotNil) 71 | return nil 72 | } 73 | 74 | func (self *DataTestClient) DeleteDatabase(db string, c *C) { 75 | client, err := influxdb.NewClient(&influxdb.ClientConfig{}) 76 | c.Assert(err, IsNil) 77 | c.Assert(client.DeleteDatabase(db), IsNil) 78 | } 79 | type ApiSeries interface { 80 | GetName() string 81 | GetColumns() []string 82 | GetPoints() [][]interface{} 83 | } 84 | func ToMap(series ApiSeries) []map[string]interface{} { 85 | seriesPoints := series.GetPoints() 86 | points := make([]map[string]interface{}, 0, len(seriesPoints)) 87 | for _, p := range seriesPoints { 88 | point := map[string]interface{}{} 89 | for idx, column := range series.GetColumns() { 90 | point[column] = p[idx] 91 | } 92 | points = append(points, point) 93 | } 94 | return points 95 | } 96 | -------------------------------------------------------------------------------- /integration/influxdb_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "testing" 5 | "net/http" 6 | "io/ioutil" 7 | "github.com/bradfitz/iter" 8 | . "gopkg.in/check.v1" 9 | ) 10 | func Test(t *testing.T) { TestingT(t) } 11 | 12 | type DataTestSuite struct { 13 | client *DataTestClient 14 | dbname string 15 | } 16 | 17 | var _ = Suite(&DataTestSuite{}) 18 | 19 | func (self *DataTestSuite) SetUpSuite(c *C) { 20 | self.dbname = "testdb" 21 | http.DefaultTransport.(*http.Transport).CloseIdleConnections() 22 | } 23 | 24 | func (self *DataTestSuite) SetUpTest(c *C) { 25 | self.client = &DataTestClient{} 26 | self.client.CreateDatabase(self.dbname, c) 27 | self.client.SetDB(self.dbname) 28 | } 29 | 30 | func (self *DataTestSuite) TearDownTest(c *C) { 31 | self.client.DeleteDatabase(self.dbname, c) 32 | self.client = nil 33 | } 34 | 35 | func loadInstanceMetricTemplate(c *C) string{ 36 | data, err := ioutil.ReadFile("test_data.json") 37 | c.Assert(err,IsNil) 38 | return string(data) 39 | } 40 | 41 | func (self *DataTestSuite) TestWriteItems(c *C) { 42 | data := loadInstanceMetricTemplate(c) 43 | entries := 10 44 | for _ = range iter.N(entries){ 45 | self.client.WriteJsonData(data, c) 46 | } 47 | result := self.client.RunQuery("select count(trackingObjectId) from instance_metrics", c) 48 | maps := ToMap(result[0]) 49 | c.Assert(maps[0]["count"], Equals, float64(entries)) 50 | } 51 | -------------------------------------------------------------------------------- /integration/test_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "instance_metrics", 4 | "columns": [ 5 | "trackingObjectId", 6 | "cpu0", 7 | "cpu1", 8 | "cpu2", 9 | "cpu3", 10 | "cpu4", 11 | "cpu5", 12 | "cpu6", 13 | "cpu7", 14 | "cpu8", 15 | "cpu9", 16 | "cpu10", 17 | "cpu11", 18 | "cpu12", 19 | "cpu13", 20 | "cpu14", 21 | "cpu15", 22 | "vbd_xvdb_write", 23 | "vbd_xvdb_read", 24 | "vbd_xvda_write", 25 | "vbd_xvda_read", 26 | "vbd_xvdc_write", 27 | "vbd_xvdc_read", 28 | "vbd_xvdd_write", 29 | "vbd_xvdd_read", 30 | "memory", 31 | "public_in", 32 | "public_out", 33 | "private_in", 34 | "private_out", 35 | "memory_internal_free", 36 | "memory_usage" 37 | ], 38 | "points": [ 39 | [ 1, 87.280266, 19.74551, 17.898554, 41.58789, 49.124672, 14.738017, 6.2651515, 84.44474, 72.30867, 64.2923, 46.528107, 33.20553, 80.86744, 82.33386, 75.422905, 42.261715, 95656032, 297410498, 906254121, 686616193, 200624334, 799981580, 85821045, 288228070, 2147483648, 84635587, 1, 77778281, 56218055, 1431024020, 716459628] 40 | ] 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /run_influxdb: -------------------------------------------------------------------------------- 1 | #!/bin/ash 2 | 3 | CONFIG_FILE="/etc/influxdb/config.toml" 4 | 5 | #Dynamically change the value of 'max-open-shards' to what 'ulimit -n' returns 6 | sed -i "s/^max-open-shards.*/max-open-shards = $(ulimit -n)/g" ${CONFIG_FILE} 7 | 8 | #Configure InfluxDB Cluster 9 | if [ -n "${HOSTNAME}" ]; then 10 | if [ "${HOSTNAME}" == "auto" ]; then 11 | #set hostname with IPv4 eth0 12 | HOSTIPNAME=$(ip a show dev eth0 | grep inet | grep eth0 | sed -e 's/^.*inet.//g' -e 's/\/.*$//g') 13 | sed -i "s/^# hostname.*$/hostname = \"${HOSTIPNAME}\"/g" ${CONFIG_FILE} 14 | else 15 | sed -i "s/^# hostname.*$/hostname = \"${HOSTNAME}\"/g" ${CONFIG_FILE} 16 | fi 17 | fi 18 | 19 | if [ -n "${SEED}" ]; then 20 | sed -i "s/^# seed-servers.*$/seed-servers = [\"${SEED}\"]/g" ${CONFIG_FILE} 21 | fi 22 | 23 | if [ -n "${REPLICATION_FACTOR}" ]; then 24 | sed -i "s/replication-factor = 1/replication-factor = ${REPLICATION_FACTOR}/g" ${CONFIG_FILE} 25 | fi 26 | 27 | echo "=> Starting InfluxDB ..." 28 | 29 | exec /usr/bin/influxdb -config=/etc/influxdb/config.toml 30 | --------------------------------------------------------------------------------