diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d459d50 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +redis-sentinel-proxy diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..369813a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM golang:1.14.3-alpine AS build + +COPY main.go /src/redis-sentinel-proxy/ + +WORKDIR /src/redis-sentinel-proxy/ + +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build . + +FROM alpine:3.4 +MAINTAINER Anubhav Mishra + +# copy binary +COPY --from=build /src/redis-sentinel-proxy/redis-sentinel-proxy /usr/local/bin/redis-sentinel-proxy + +ENTRYPOINT ["/usr/local/bin/redis-sentinel-proxy"] +CMD ["-master", "mymaster"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d50836a --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +IMAGE_NAME := anubhavmishra/redis-sentinel-proxy +.PHONY: test + +.DEFAULT_GOAL := help +help: ## List targets & descriptions + @cat Makefile* | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +deps: + go get . + +run-docker: ## Run dockerized service directly + docker run $(IMAGE_NAME):latest + +push: ## docker push image to registry + docker push $(IMAGE_NAME):latest + +build: ## Build the project + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build . + docker build -t $(IMAGE_NAME):latest . + +run: ## Build and run the project + go build . && ./redis-sentinel-proxy + +clean: + -rm -rf build diff --git a/README.md b/README.md index 842619a..51cf429 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,38 @@ Small command utility that: Usage: `./redis-sentinel-proxy -listen IP:PORT -sentinel :SENTINEL_PORT -master NAME` + +## Usage + +Edit `kubernetes/redis-sentinel-proxy-deployment.yaml`: + +```bash +vim kubernetes/redis-sentinel-proxy-deployment.yaml +... + args: + - "-master" + - "primary" + - "-sentinel" + - "redis-sentinel.$(NAMESPACE):26379" # change this to the sentinel address +``` + +Create `redis-sentinel-proxy-deployment` that uses `redis-sentinel-proxy`: + +```bash +kubectl apply -f kubernetes/redis-sentinel-proxy-deployment.yaml +deployment "redis-sentinel-proxy" configured +``` + +Check if deployment is running: + +```bash +kubectl get pods +redis-sentinel-proxy-2064359825-s4n0k 1/1 Running 0 1d +``` + +Expose `redis-sentinel-proxy-deployment`: + +```bash +kubectl apply -f kubernetes/redis-sentinel-proxy-service.yaml +``` + diff --git a/kubernetes/redis-sentinel-proxy-deployment.yaml b/kubernetes/redis-sentinel-proxy-deployment.yaml new file mode 100644 index 0000000..76906d7 --- /dev/null +++ b/kubernetes/redis-sentinel-proxy-deployment.yaml @@ -0,0 +1,27 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: redis-sentinel-proxy + namespace: redis +spec: + replicas: 1 + template: + metadata: + labels: + app: redis-sentinel-proxy + spec: + containers: + - name: redis-sentinel-proxy + image: anubhavmishra/redis-sentinel-proxy:latest + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "-master" + - "primary" + - "-sentinel" + - "redis-sentinel.$(NAMESPACE):26379" + ports: + - containerPort: 9999 \ No newline at end of file diff --git a/kubernetes/redis-sentinel-proxy-service.yaml b/kubernetes/redis-sentinel-proxy-service.yaml new file mode 100644 index 0000000..a22b590 --- /dev/null +++ b/kubernetes/redis-sentinel-proxy-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis-sentinel-proxy + namespace: redis + labels: + app: redis-sentinel-proxy +spec: + type: NodePort + ports: + - port: 9999 + name: redis-sentinel-proxy + selector: + app: redis-sentinel-proxy \ No newline at end of file diff --git a/main.go b/main.go index c36f96b..35d85f3 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,8 @@ var ( localAddr = flag.String("listen", ":9999", "local address") sentinelAddr = flag.String("sentinel", ":26379", "remote address") masterName = flag.String("master", "", "name of the master redis node") + password = flag.String("password", "", "password (if any) to authenticate") + debug = flag.Bool("debug", false, "sets debug mode") ) func main() { @@ -54,7 +56,7 @@ func main() { func master() { var err error for { - masterAddr, err = getMasterAddr(saddr, *masterName) + masterAddr, err = getMasterAddr(saddr, *masterName, *password) if err != nil { log.Println(err) } @@ -78,7 +80,7 @@ func proxy(local io.ReadWriteCloser, remoteAddr *net.TCPAddr) { go pipe(remote, local) } -func getMasterAddr(sentinelAddress *net.TCPAddr, masterName string) (*net.TCPAddr, error) { +func getMasterAddr(sentinelAddress *net.TCPAddr, masterName string, password string) (*net.TCPAddr, error) { conn, err := net.DialTCP("tcp", nil, sentinelAddress) if err != nil { return nil, err @@ -86,6 +88,22 @@ func getMasterAddr(sentinelAddress *net.TCPAddr, masterName string) (*net.TCPAdd defer conn.Close() + if len(password) > 0 { + conn.Write([]byte(fmt.Sprintf("AUTH %s\n", password))) + if *debug { + fmt.Println("> AUTH ", password) + } + authResp := make([]byte, 256) + _, err = conn.Read(authResp) + + if *debug { + fmt.Println("< ", string(authResp)) + } + } + + if *debug { + fmt.Println("> sentinel get-master-addr-by-name ", masterName) + } conn.Write([]byte(fmt.Sprintf("sentinel get-master-addr-by-name %s\n", masterName))) b := make([]byte, 256) @@ -95,9 +113,12 @@ func getMasterAddr(sentinelAddress *net.TCPAddr, masterName string) (*net.TCPAdd } parts := strings.Split(string(b), "\r\n") + if *debug { + fmt.Println("< ", string(b)) + } if len(parts) < 5 { - err = errors.New("Couldn't get master address from sentinel") + err = errors.New(fmt.Sprintf("Couldn't get master address from sentinel: %s", string(b))) return nil, err }