mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 02:03:20 -04:00 
			
		
		
		
	* Support multiple k8s api servers specification and load balance among api servers This fix adds supports for multiple k8s api servers specification, load balance among api servers. When two or more api servers are specified in kubernetes block (endpoint ...), a proxy is created locally (with randomly generately port). The coredns will points to the generated proxy so that load balancing could be achieved. Signed-off-by: Yong Tang <yong.tang.github@outlook.com> * Setup initial healthcheck at the beginning Signed-off-by: Yong Tang <yong.tang.github@outlook.com> * Update README.md for kubernetes middleware and remove whitespaces. Signed-off-by: Yong Tang <yong.tang.github@outlook.com> * Use middleware/pkg/healthcheck in middleware/kubernetes for api proxy Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
		
			
				
	
	
		
			77 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			77 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package kubernetes
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"log"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 
 | |
| 	"github.com/coredns/coredns/middleware/pkg/healthcheck"
 | |
| )
 | |
| 
 | |
| type proxyHandler struct {
 | |
| 	healthcheck.HealthCheck
 | |
| }
 | |
| 
 | |
| type apiProxy struct {
 | |
| 	http.Server
 | |
| 	listener net.Listener
 | |
| 	handler  proxyHandler
 | |
| }
 | |
| 
 | |
| func (p *proxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | |
| 	upstream := p.Select()
 | |
| 	network := "tcp"
 | |
| 	if upstream.Network != "" {
 | |
| 		network = upstream.Network
 | |
| 	}
 | |
| 	address := upstream.Name
 | |
| 	d, err := net.Dial(network, address)
 | |
| 	if err != nil {
 | |
| 		log.Printf("[ERROR] Unable to establish connection to upstream %s://%s: %s", network, address, err)
 | |
| 		http.Error(w, fmt.Sprintf("Unable to establish connection to upstream %s://%s: %s", network, address, err), 500)
 | |
| 		return
 | |
| 	}
 | |
| 	hj, ok := w.(http.Hijacker)
 | |
| 	if !ok {
 | |
| 		log.Printf("[ERROR] Unable to establish connection: no hijacker")
 | |
| 		http.Error(w, "Unable to establish connection: no hijacker", 500)
 | |
| 		return
 | |
| 	}
 | |
| 	nc, _, err := hj.Hijack()
 | |
| 	if err != nil {
 | |
| 		log.Printf("[ERROR] Unable to hijack connection: %s", err)
 | |
| 		http.Error(w, fmt.Sprintf("Unable to hijack connection: %s", err), 500)
 | |
| 		return
 | |
| 	}
 | |
| 	defer nc.Close()
 | |
| 	defer d.Close()
 | |
| 
 | |
| 	err = r.Write(d)
 | |
| 	if err != nil {
 | |
| 		log.Printf("[ERROR] Unable to copy connection to upstream %s://%s: %s", network, address, err)
 | |
| 		http.Error(w, fmt.Sprintf("Unable to copy connection to upstream %s://%s: %s", network, address, err), 500)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	errChan := make(chan error, 2)
 | |
| 	cp := func(dst io.Writer, src io.Reader) {
 | |
| 		_, err := io.Copy(dst, src)
 | |
| 		errChan <- err
 | |
| 	}
 | |
| 	go cp(d, nc)
 | |
| 	go cp(nc, d)
 | |
| 	<-errChan
 | |
| }
 | |
| 
 | |
| func (p *apiProxy) Run() {
 | |
| 	p.handler.Start()
 | |
| 	p.Serve(p.listener)
 | |
| }
 | |
| 
 | |
| func (p *apiProxy) Stop() {
 | |
| 	p.handler.Stop()
 | |
| 	p.Close()
 | |
| }
 |