├── Dockerfile ├── README.md ├── confd ├── conf.d │ └── twemproxy.toml └── templates │ └── twemproxy.tmpl ├── run.sh └── supervisord.conf /Dockerfile: -------------------------------------------------------------------------------- 1 | # expected values in etcd 2 | # - `/services/twemproxy/listen` : the host_ip:port the proxy will listen on 3 | # - `/services/twemproxy/servers/` : enumeration of the redis servers for 01-N servers, in the format of host_ip:port 4 | # example: 5 | # etcdctl set /services/twemproxy/listen 10.10.100.1:6000 6 | # etcdctl set /services/redis/01 10.10.100.11:6001 7 | # etcdctl set /services/redis/02 10.10.100.12:6002 8 | 9 | FROM jgoodall/ubuntu-confd 10 | 11 | MAINTAINER "John Goodall " 12 | 13 | ENV DEBIAN_FRONTEND noninteractive 14 | 15 | # Install basics 16 | RUN apt-get update 17 | RUN apt-get -qy install libtool make automake 18 | 19 | # Install twemproxy 20 | RUN curl -qL https://twemproxy.googlecode.com/files/nutcracker-0.3.0.tar.gz | tar xzf - 21 | RUN cd nutcracker-0.3.0 && ./configure --enable-debug=log && make && mv src/nutcracker /twemproxy 22 | RUN cd / && rm -rf nutcracker-0.3.0 23 | 24 | # Set up run script 25 | ADD run.sh /run.sh 26 | RUN chmod 755 /run.sh 27 | 28 | # Copy confd files 29 | ADD confd/conf.d/twemproxy.toml /etc/confd/conf.d/twemproxy.toml 30 | ADD confd/templates/twemproxy.tmpl /etc/confd/templates/twemproxy.tmpl 31 | 32 | # Copy supervisord files 33 | ADD supervisord.conf /etc/supervisor/supervisord.conf 34 | 35 | EXPOSE 6000 6222 36 | 37 | CMD ["/run.sh"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | docker-twemproxy 2 | ================ 3 | 4 | Docker image of [twemproxy](https://github.com/twitter/twemproxy) proxy server in front of [redis](http://redis.io/) instances. 5 | 6 | ## Overview 7 | 8 | The container reads the redis server information from [etcd](https://github.com/coreos/etcd). The twemproxy container will use [confd](https://github.com/kelseyhightower/confd) to watch the `/services/redis` path. It exposes port 6000, so map that when you do `docker run`. 9 | 10 | When you start your redis containers, put their connection information into `etcd` in the `/services/redis/`: 11 | 12 | etcdctl set /services/redis/01 10.10.100.11:6001 13 | etcdctl set /services/redis/02 10.10.100.12:6002 14 | 15 | You also need to set the port that you want twemproxy to run on: 16 | 17 | etcdctl set /services/twemproxy/port 6000 18 | 19 | Finally, define the `etcd` peer `confd` should use as an [environment variable](https://docs.docker.com/reference/run/#env-environment-variables) using `-e ETCD_HOST=:` when you do the `docker run` to start the container. 20 | 21 | ## Usage 22 | 23 | You may want to customize the twemproxy configuration in `confd/templates/twemproxy.tmpl` - particularly the `hash_tag` option. 24 | 25 | # start some redis containers 26 | docker run --name=redis-A --rm -p 6101:6379 dockerfile/redis 27 | docker run --name=redis-B --rm -p 6102:6379 dockerfile/redis 28 | # publish the redis host:ip information into etcd 29 | etcdctl set /services/redis/A 127.0.0.1:6101 30 | etcdctl set /services/redis/B 127.0.0.1:6102 31 | # define the desired twemproxy and stats port 32 | TWEMPROXY_PORT=6100 33 | TWEMPROXY_STATS_PORT=6100 34 | # set the twemproxy port in etcd 35 | etcdctl set /services/twemproxy/port ${TWEMPROXY_PORT} 36 | # use the port you set above when you start the container 37 | docker run --name=twemproxy --rm -p ${TWEMPROXY_PORT}:6000 -p ${TWEMPROXY_STATS_PORT}:6001 -e ETCD_HOST=127.0.0.1:4001 jgoodall/twemproxy 38 | # publish the twemproxy host info if desired 39 | etcdctl set /services/twemproxy/host 127.0.0.1 40 | # connect using a redis client 41 | redis-cli -h `etcdctl get /services/twemproxy/host` -p `etcdctl get /services/twemproxy/port` 42 | # get stats on cluster (use `docker ps` to get ``) 43 | curl :$TWEMPROXY_STATS_PORT 44 | -------------------------------------------------------------------------------- /confd/conf.d/twemproxy.toml: -------------------------------------------------------------------------------- 1 | [template] 2 | src = "twemproxy.tmpl" 3 | dest = "/twemproxy.yaml" 4 | keys = [ 5 | "/services/twemproxy/port", 6 | "/services/redis", 7 | ] 8 | reload_cmd = "/usr/bin/supervisorctl twemproxy restart" 9 | check_cmd = "/twemproxy -t -c {{ .src }}" -------------------------------------------------------------------------------- /confd/templates/twemproxy.tmpl: -------------------------------------------------------------------------------- 1 | situ: 2 | listen: 0.0.0.0:{{ .services_twemproxy_port }} 3 | hash: fnv1a_64 4 | hash_tag: "P:" 5 | distribution: ketama 6 | auto_eject_hosts: false 7 | timeout: 1000 8 | redis: true 9 | servers: 10 | {{ range $server := .services_redis }} - {{$server.Value}}:1 11 | {{ end }} -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Run docker run with -e ETCD_HOST=: 4 | if [ -n "${ETCD_HOST:+x}" ]; then 5 | mv /etc/supervisor/supervisord.conf /tmp/supervisord.conf 6 | sed -e "/confd -node/s/127.0.0.1:4001/${ETCD_HOST}/" /tmp/supervisord.conf > /etc/supervisor/supervisord.conf 7 | fi 8 | 9 | # for debugging 10 | cat /etc/supervisor/supervisord.conf 11 | 12 | /usr/bin/supervisord -c /etc/supervisor/supervisord.conf -------------------------------------------------------------------------------- /supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon = true 3 | 4 | [program:confd] 5 | command=/confd -node="http://127.0.0.1:4001" -verbose=true -debug=true 6 | priority=10 7 | numprocs=1 8 | autostart=true 9 | autorestart=true 10 | stdout_events_enabled=true 11 | stderr_events_enabled=true 12 | 13 | [program:twemproxy] 14 | command=/twemproxy -c /twemproxy.yaml -v 7 -s 6222 15 | numprocs=1 16 | autostart=true 17 | autorestart=true 18 | stdout_events_enabled=true 19 | stderr_events_enabled=true 20 | 21 | [eventlistener:stdout] 22 | command = supervisor_stdout 23 | buffer_size = 100 24 | events = PROCESS_LOG 25 | result_handler = supervisor_stdout:event_handler 26 | --------------------------------------------------------------------------------