Consul
The Hashicorp team is the same team that developed Vagrant. Consul is a service software offering service discovery, health detection, K/V storage support for distributed high availability multi-data centers. Similar to ZooKeeper but with a few more features. For details, see Consul and ZooKeeper.
fabio
Fabio is a fast, simple, zero-configuration load balancing router developed by ebay’s team using Golang that enables Consul’s deployed applications to quickly support HTTP (S). Because Consul supports service registration and health checks, Fabio is able to deliver load with zero configuration, and upgrade deployment has never been easier. Fabio can deliver 15,000 requests per second, according to the project. With these two components it is very easy to do service discovery with automatic load balancing, “artifact in hand, world I have!” ^ _ ^
Characteristics of service discovery
Hosts and ports must be filled in the configuration file to invoke services between services, which is difficult to maintain and deploy and expand in a distributed environment. At this point, consider registering the host and port and other information with the registry when the service starts up so that other services can find it. It is even easier to “address” the DNS after registration. For example, Zookeepr can do this job well, but there is another drawback: how to ensure that the service is available after the health check service is registered in the registry? At this point, you need to write your own logic to automatically go offline from the registry when the service becomes unavailable. Consul can then easily resolve the issue.
The working principle of
Consul provides a health check mechanism for HTTP services (Consul also supports other types such as TCP). Provide a health check address (URL) and a frequency timeout so consul will periodically request when the status code is 200 that the service is healthy and otherwise faulty. Fabio’s job is easy now that services registered with Consul can maintain their own health status! Is directly from the consul registry in health service according to the service registration time tags configuration automatically created their own routing table, and then automatically when an HTTP request to come over to do load balancing simple flow chart is as follows:
= = = = = = service registry = = = = = = = = = = = = = = = = = = A service < -- -- -- -- -- - > -- -- -- -- > consul cluster healthy in A cluster = A/unhealthy health examination = = = = = = = = = = = = = = = = = = = = = = = ^ | add/move A way out by the table | = = = = = = = = fabio cluster = = = = = = = = | | A service If found successful routing or return error V HTTP requestsCopy the code
Demo
Here we start writing a demo service to experience consul+ Fabio while using Docker + K8s to arrange expansion. Consul + Fabio supports docker consul + Fabio is used as an example. Docker pull Magiconair/Fabio Docker pull Consul Can be developed in cluster mode or dev mode. Here you can refer to the Docker compose configuration for standalone deployment Consul cluster I compiled:
version: '2' services: consul_server_1: image: "consul:latest" container_name: "consul_server_1" environment: CONSUL_LOCAL_CONFIG: '{"leave_on_terminate": true}' networks: app_net: ipv4_address: 172.17.0.3 command: "Agent-server-bind = 172.17.0.3-client = 172.17.0.3-retry-join =172.17.0.2" : image: "consul:latest" container_name: "consul_server_2" ports: - "8600:8600" - "8500:8500" networks: app_net: ipv4_address: 172.17.0.4 command: "agent-server-bind = 172.17.0.4-client = 172.17.0.4-retry -join= 172.17.0.3-ui" image: "consul:latest" container_name: "consul_server_3" environment: CONSUL_LOCAL_CONFIG: '{"leave_on_terminate": True}' networks: app_net: ipv4_address: 172.17.0.5 Command: "Agent-server-bind = 172.17.0.5-client = 172.17.0.5-retry-join = 172.17.0.4-bootstrap-expect =3" Networks: app_net: Driver: bridge ipam: config: -subnet: 172.17.0.0/24Copy the code
You can also follow the documentation on docker Hub to deploy and access the next Consul UI after successful startup.
fabio: image: "magiconair/fabio" ports:
- "9998:9998"
- "9999:9999" volumes:
- ./fabio.properties:/etc/fabio/fabio.propertiesCopy the code
Fabio. Properties specifies consul’s address port on Consul and its own statistics, etc. In this case, you can write a simple configuration
Registry. Consul. Register. Addr = 172.16.0.21:9998 registry. Consul. Addr = 172.16.0.21:8500 metrics. Target = stdoutCopy the code
route add <svc> <src> <dst> weight <w> tags "<t1>,<t2>,..."
- Add route for service svc from src to dst and assign weight and tags
route add <svc> <src> <dst> weight <w>
- Add route for service svc from src to dst and assign weightCopy the code
For details, please move. Run a demo after the installation is complete. The official provides a simple implementation:
package main import ( "flag" "fmt" "log" "net" "net/http" "os" "os/signal" "path/filepath" "strconv" "strings" "github.com/magiconair/fabio-example/_third_party/github.com/hashicorp/consul/api" ) func main() { var addr, name, Prefix String flag.stringVar (&addr, "addr", "127.0.0.1:5000", "host:port of the service") flag.stringvar (&name, "name", filepath.Base(os.Args[0]), "name of the service") flag.StringVar(&prefix, "prefix", "", "comma-sep list of host/path prefixes to register") flag.Parse() if prefix == "" { flag.Usage() os.Exit(1) } // register prefixes prefixes := strings.Split(prefix, ",") for _, p := range prefixes { http.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Serving %s from %s on %s\n", r.RequestURI, name, addr) }) } // start http server go func() { log.Printf("Listening on %s serving %s", addr, prefix) if err := http.ListenAndServe(addr, nil); err ! = nil { log.Fatal(err) } }() // register consul health check endpoint http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "OK") }) // build urlprefix-host/path tag list // e.g. urlprefix-/foo, urlprefix-/bar, ... var tags []string for _, p := range prefixes { tags = append(tags, "urlprefix-"+p) } // get host and port as string/int host, portstr, err := net.SplitHostPort(addr) if err ! = nil { log.Fatal(err) } port, err := strconv.Atoi(portstr) if err ! = nil { log.Fatal(err) } // register service with health check serviceID := name + "-" + addr service := &api.AgentServiceRegistration{ ID: serviceID, Name: name, Port: port, Address: host, Tags: tags, Check: &api.AgentServiceCheck{ HTTP: "http://" + addr + "/health", Interval: "1s", Timeout: "1s", }, } client, err := api.NewClient(api.DefaultConfig()) if err ! = nil { log.Fatal(err) } if err := client.Agent().ServiceRegister(service); err ! = nil { log.Fatal(err) } log.Printf("Registered service %q in consul with tags %q", name, strings.Join(tags, ",")) // run until we get a signal quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, os.Kill) <-quit // deregister service if err := client.Agent().ServiceDeregister(serviceID); err ! = nil { log.Fatal(err) } log.Printf("Deregistered service %q in consul", name) }Copy the code
The application is unregistered on launch and registers the health check address /health on exit, and is unregistered on exit. When registering with Consul there is a tag that allows fabio to automatically associate route mappings with the service based on this parameter. Run first
CONSUL_HTTP_ADDR = 172.16.0.21:8500 / fabio - example - addr = 172.16.0.17:9876 - prefix=a.com/Copy the code
Consul has received the registered FABIO route and added it.
# Service Host Path Dest Weight 1 fabio-example a.com/http://172.16.0.17:9876/ 100%Copy the code
~ curl-iv-h 'Host: a.com' 172.16.0.21:9999/ * Trying 172.16.0.21... * Connected to 172.16.0.21 (172.16.0.21) port 9999 (#0) > GET/HTTP/1.1 > Host: a.com > user-agent: Curl /7.43.0 > < HTTP/1.1 200 OK HTTP/1.1 200 OK < content-length: 49 content-length: 49 < content-type: text/plain; charset=utf-8 Content-Type: text/plain; charset=utf-8 < Date: Fri, 22 Jul 2016 01:01:28 GMT Date: Fri, 22 Jul 2016 01:01:28 GMT < Serving/from fabio-example on 172.16.0.17:9876 * Connection #0 to host 172.16.0.21 left intactCopy the code
Expand capacity with Kubernetes
For example, IP ports need to be dynamically retrieved from the container, and the tags prefix need to be configured when the service starts. Please refer to the fabio documentation. Spring-cloud-consul is a service that can be used quickly with just one line of code and a few lines of configuration: Add the @enableDiscoveryClient annotation to the Application class. application.yml
Spring: Cloud: Consul: Discovery: healthCheckPath: ${management. ContextPath}/health # healthCheckInterval: Urlprefix-api.xxxx.com/ #Copy the code
Ps: Spring health detection can be implemented quickly using spring-boot-starter-actuator. Then k8S can expand capacity if it needs to expand capacity, because if the method of service discovery is not adopted during k8S expansion, HTTP requests may be forwarded to the container that has been started, but the service is not available (for example, the Java process is started, but initialization may take several minutes…). . Feel the expansion by 10
$ kubectl scale --replicas=10 rc api
$ kubectl get pods
[root@172-16-0-17 fabio-example]# kubectl get pods
NAME READY STATUS RESTARTS AGE
api-6xytx 1/1 Running 0 11s
api-9e5838075aae036e2dc971984855e379-ac30s 1/1 Running 0 14h
api-dfmtv 1/1 Running 0 11s
api-eo01h 1/1 Running 0 11s
api-hn1kv 1/1 Running 0 11s
api-iyqmg 1/1 Running 0 11s
api-k32ud 1/1 Running 0 11s
api-q10a7 1/1 Running 0 11s
api-re7e1 1/1 Running 0 11s
api-tm2pk 1/1 Running 0 11sCopy the code
Expand to 10 in 10 seconds and check consul and Fabio
# Service Host Path Dest Weight 1 API api.com/http://172.31.9.3:8080/ 10% 2 API api.com/http://172.31.9.2:8080/ 10% 3 API api.com/http://172.31.82.6:8080/ 10% 4 API API.com/http://172.31.82.4:8080/ 10% 5 API api.com / http://172.31.28.3:8080/ 10% 6 API api.com/http://172.31.28.2:8080/ 10% 7 API api.com/http://172.31.23.7:8080/ 10% 8 API Api.com/http://172.31.23.2:8080/ 10% 9 API Api.com/http://172.31.12.6:8080/ 10% 10 API api.com / http://172.31.12.4:8080/ 10%Copy the code
Fabio can also update the routing table immediately when it shrinks to one. Fabio + Consul enables deployment and expansion in a distributed environment. Consul also provides all other components to perform similar functions, such as Consul -template.
This article is adapted from Nuggets -Consul + Fabio for automatic service discovery and load balancing