Merge pull request #2827 from weaveworks/issues/2799-peer-disco
Peer Discovery via cloud service
This commit is contained in:
commit
bc47866880
11 files changed
+293
-15
No files matched your search
@@ -124,3 +124,9 @@
|
||||
[submodule "vendor/github.com/containernetworking/cni"]
|
||||
path = vendor/github.com/containernetworking/cni
|
||||
url = https://github.com/containernetworking/cni
|
||||
[submodule "vendor/golang.org/x/net"]
|
||||
path = vendor/golang.org/x/net
|
||||
url = https://go.googlesource.com/net
|
||||
[submodule "vendor/google.golang.org/grpc"]
|
||||
path = vendor/google.golang.org/grpc
|
||||
url = https://github.com/grpc/grpc-go
|
||||
@@ -198,17 +198,6 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID
|
||||
w.WriteHeader(204)
|
||||
})
|
||||
|
||||
router.Methods("DELETE").Path("/peer").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
alloc.Shutdown()
|
||||
w.WriteHeader(204)
|
||||
})
|
||||
|
||||
router.Methods("DELETE").Path("/peer/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ident := mux.Vars(r)["id"]
|
||||
transferred := alloc.AdminTakeoverRanges(ident)
|
||||
fmt.Fprintf(w, "%d IPs taken over from %s\n", transferred, ident)
|
||||
})
|
||||
|
||||
router.Methods("GET").Path("/ipinfo/tracker").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, tracker)
|
||||
})
|
||||
|
||||
@@ -82,3 +82,25 @@ func findInterface(ifaceName string) (iface *net.Interface, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LocalAddresses() ([]*net.IPNet, error) {
|
||||
links, err := netlink.LinkList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
retval := []*net.IPNet{}
|
||||
for _, link := range links {
|
||||
if _, isBridge := link.(*netlink.Bridge); isBridge || (link.Attrs().Flags&net.FlagLoopback) != 0 {
|
||||
continue
|
||||
}
|
||||
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
retval = append(retval, addr.IPNet)
|
||||
}
|
||||
}
|
||||
return retval, nil
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/weaveworks/weave/ipam"
|
||||
)
|
||||
|
||||
// TODO: move these definitions somewhere more shareable
|
||||
type PeerUpdateRequest struct {
|
||||
Name string `json:"peername"`
|
||||
Nickname string `json:"nickname"` // optional
|
||||
Addresses []string `json:"addresses"` // can be empty
|
||||
}
|
||||
|
||||
type PeerUpdateResponse struct {
|
||||
Addresses []string `json:"addresses"`
|
||||
PeerCount int `json:"peercount"`
|
||||
}
|
||||
|
||||
var httpClient = &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
func do(verb string, discoveryEndpoint, token string, request interface{}, response interface{}) error {
|
||||
body := new(bytes.Buffer)
|
||||
err := json.NewEncoder(body).Encode(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest(verb, discoveryEndpoint+"/peer", body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Scope-Probe token=%s", token))
|
||||
req.Header.Set("X-Weave-Net-Version", version)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
Log.Printf("Calling peer discovery %s with %s", req.URL, request)
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
rbody, _ := ioutil.ReadAll(resp.Body)
|
||||
return errors.New(resp.Status + ": " + string(rbody))
|
||||
}
|
||||
if response == nil {
|
||||
return nil
|
||||
}
|
||||
err = json.NewDecoder(resp.Body).Decode(response)
|
||||
Log.Printf("peer discovery result: (%v) %v", err, response)
|
||||
return err
|
||||
}
|
||||
|
||||
func peerDiscoveryUpdate(discoveryEndpoint, token, peername, nickname string, addresses []string) ([]string, int, error) {
|
||||
request := PeerUpdateRequest{
|
||||
Name: peername,
|
||||
Nickname: nickname,
|
||||
Addresses: addresses,
|
||||
}
|
||||
var updateResponse PeerUpdateResponse
|
||||
err := do("POST", discoveryEndpoint, token, request, &updateResponse)
|
||||
return updateResponse.Addresses, updateResponse.PeerCount, err
|
||||
}
|
||||
|
||||
func peerDiscoveryDelete(discoveryEndpoint, token, peername string) error {
|
||||
request := PeerUpdateRequest{Name: peername}
|
||||
return do("DELETE", discoveryEndpoint, token, request, nil)
|
||||
}
|
||||
|
||||
func HandleHTTPPeer(router *mux.Router, alloc *ipam.Allocator, discoveryEndpoint, token, peername string) {
|
||||
router.Methods("DELETE").Path("/peer").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if discoveryEndpoint != "" {
|
||||
if err := peerDiscoveryDelete(discoveryEndpoint, token, peername); err != nil {
|
||||
Log.Errorf("Error while deleting self from peer discovery: %s", err)
|
||||
}
|
||||
}
|
||||
if alloc != nil {
|
||||
alloc.Shutdown()
|
||||
}
|
||||
w.WriteHeader(204)
|
||||
})
|
||||
|
||||
router.Methods("DELETE").Path("/peer/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ident := mux.Vars(r)["id"]
|
||||
if discoveryEndpoint != "" {
|
||||
// TODO: deal with this being either a peername or a nickname
|
||||
if err := peerDiscoveryDelete(discoveryEndpoint, token, ident); err != nil {
|
||||
Log.Errorf("Error while deleting self from peer discovery: %s", err)
|
||||
}
|
||||
}
|
||||
if alloc != nil {
|
||||
transferred := alloc.AdminTakeoverRanges(ident)
|
||||
fmt.Fprintf(w, "%d IPs taken over from %s\n", transferred, ident)
|
||||
}
|
||||
})
|
||||
}
|
||||
+31
-3
@@ -53,7 +53,7 @@ type dnsConfig struct {
|
||||
func (c *ipamConfig) Enabled() bool {
|
||||
var (
|
||||
hasPeerCount = c.PeerCount > 0
|
||||
hasMode = len(c.Mode) > 0
|
||||
hasMode = c.HasMode()
|
||||
hasRange = c.IPRangeCIDR != ""
|
||||
hasSubnet = c.IPSubnetCIDR != ""
|
||||
)
|
||||
@@ -75,6 +75,10 @@ func (c *ipamConfig) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c ipamConfig) HasMode() bool {
|
||||
return len(c.Mode) > 0
|
||||
}
|
||||
|
||||
func (c *ipamConfig) parseMode() error {
|
||||
modeAndParam := strings.SplitN(c.Mode, "=", 2)
|
||||
|
||||
@@ -143,6 +147,9 @@ func main() {
|
||||
trustedSubnetStr string
|
||||
dbPrefix string
|
||||
isAWSVPC bool
|
||||
discoveryEndpoint string
|
||||
token string
|
||||
advertiseAddress string
|
||||
|
||||
defaultDockerHost = "unix:///var/run/docker.sock"
|
||||
)
|
||||
@@ -184,6 +191,9 @@ func main() {
|
||||
mflag.StringVar(&trustedSubnetStr, []string{"-trusted-subnets"}, "", "comma-separated list of trusted subnets in CIDR notation")
|
||||
mflag.StringVar(&dbPrefix, []string{"-db-prefix"}, "/weavedb/weave", "pathname/prefix of filename to store data")
|
||||
mflag.BoolVar(&isAWSVPC, []string{"-awsvpc"}, false, "use AWS VPC for routing")
|
||||
mflag.StringVar(&discoveryEndpoint, []string{"-peer-discovery-url"}, "https://cloud.weave.works/api/net", "url for peer discovery")
|
||||
mflag.StringVar(&token, []string{"-token"}, "", "token for peer discovery")
|
||||
mflag.StringVar(&advertiseAddress, []string{"-advertise-address"}, "", "address to advertise for peer discovery")
|
||||
|
||||
// crude way of detecting that we probably have been started in a
|
||||
// container, with `weave launch` --> suppress misleading paths in
|
||||
@@ -257,7 +267,24 @@ func main() {
|
||||
router := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlay, db)
|
||||
Log.Println("Our name is", router.Ourself)
|
||||
|
||||
if peers, err = router.InitialPeers(resume, peers); err != nil {
|
||||
if token != "" {
|
||||
var addresses []string
|
||||
if advertiseAddress == "" {
|
||||
localAddrs, err := weavenet.LocalAddresses()
|
||||
checkFatal(err)
|
||||
for _, addr := range localAddrs {
|
||||
addresses = append(addresses, addr.IP.String())
|
||||
}
|
||||
} else {
|
||||
addresses = strings.Split(advertiseAddress, ",")
|
||||
}
|
||||
discoveredPeers, count, err := peerDiscoveryUpdate(discoveryEndpoint, token, name.String(), nickName, addresses)
|
||||
checkFatal(err)
|
||||
if !ipamConfig.HasMode() {
|
||||
ipamConfig.PeerCount = len(peers) + count
|
||||
}
|
||||
peers = append(peers, discoveredPeers...)
|
||||
} else if peers, err = router.InitialPeers(resume, peers); err != nil {
|
||||
Log.Fatal("Unable to get initial peer set: ", err)
|
||||
}
|
||||
|
||||
@@ -352,6 +379,7 @@ func main() {
|
||||
}
|
||||
router.HandleHTTP(muxRouter)
|
||||
HandleHTTP(muxRouter, version, router, allocator, defaultSubnet, ns, dnsserver)
|
||||
HandleHTTPPeer(muxRouter, allocator, discoveryEndpoint, token, name.String())
|
||||
muxRouter.Methods("GET").Path("/metrics").Handler(metricsHandler(router, allocator, ns, dnsserver))
|
||||
http.Handle("/", common.LoggingHTTPHandler(muxRouter))
|
||||
Log.Println("Listening for HTTP control messages on", httpAddr)
|
||||
@@ -376,7 +404,7 @@ func options() map[string]string {
|
||||
mflag.Visit(func(f *mflag.Flag) {
|
||||
value := f.Value.String()
|
||||
name := canonicalName(f)
|
||||
if name == "password" {
|
||||
if name == "password" || name == "token" {
|
||||
value = "<redacted>"
|
||||
}
|
||||
options[name] = value
|
||||
|
||||
@@ -135,5 +135,6 @@ Weave Net supports *any* protocol, and it doesn't have to be over TCP/IP. For ex
|
||||
**See Also**
|
||||
|
||||
* [Installing Weave Net](/site/installing-weave.md)
|
||||
* [Using Weave Cloud to get started with Weave Net](/site/using-weave/weave-cloud.md)
|
||||
* [Using Fastdp With Weave Net](/site/using-weave/fastdp.md)
|
||||
* [Using the Weave Net Docker Network Plugin](/site/plugin.md)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
@@ -0,0 +1,126 @@
|
||||
---
|
||||
title: Using Weave Cloud to get started with Weave Net
|
||||
menu_order: 10
|
||||
---
|
||||
|
||||
Weave Net provides a simple to deploy networking solution for containerized apps. Here, we describe how to manage a Weave container network using a sample application which consists of two simple `netcat` services deployed to containers on two separate hosts.
|
||||
|
||||
This section contains the following topics:
|
||||
|
||||
* [Signing in to Weave Cloud](#signing-in)
|
||||
* [Launching Weave Net](#launching)
|
||||
* [Launching on Additional Hosts](#peer-connections)
|
||||
* [How Peer Discovery Works](#how-it-works)
|
||||
|
||||
### <a name="signing-in"></a>Signing in to Weave Cloud
|
||||
|
||||
Weave Cloud is a fast and simple way to visualize, manage and monitor
|
||||
containers and microservices. In order to use Weave Cloud to set up
|
||||
Weave Net, you must sign up to Weave Cloud and create an "Instance".
|
||||
|
||||
The instance will have a Service Token which is a 32-character string
|
||||
used to uniquely identify it. Get hold of the Service Token for your
|
||||
Instance, as shown below:
|
||||
|
||||

|
||||
|
||||
For the purpose of these instructions we will use a dummy Service
|
||||
Token `dk6hz1acdd58aea6b75migoy4axqasdf`.
|
||||
|
||||
|
||||
### <a name="launching"></a>Launching Weave Net
|
||||
|
||||
Before launching Weave Net and deploying your apps, ensure that Docker
|
||||
is [installed](https://docs.docker.com/engine/installation/) on both
|
||||
hosts.
|
||||
|
||||
On `$HOST1` run:
|
||||
|
||||
host1$ weave launch --token=dk6hz1acdd58aea6b75migoy4axqasdf
|
||||
host1$ eval $(weave env)
|
||||
host1$ docker run --name a1 -ti weaveworks/ubuntu
|
||||
|
||||
Where,
|
||||
|
||||
* The first line runs Weave Net.
|
||||
|
||||
* The second line configures the Weave Net environment, so that containers launched via the Docker command line are automatically attached to the Weave network, and,
|
||||
* The third line runs the [application container](/site/faq.md#own-image) using [a Docker command](https://docs.docker.com/engine/reference/run/).
|
||||
|
||||
> **Note** If the first command results in an error like
|
||||
> ```
|
||||
> Cannot connect to the Docker daemon. Is the docker daemon running on this host?
|
||||
> ```
|
||||
> then you likely need to be 'root' in order to connect to the Docker
|
||||
> daemon. If so, run the above and all subsequent commands in a
|
||||
> *single* root shell:
|
||||
> ```
|
||||
> host1$ sudo -s
|
||||
> host1# weave launch --token=dk6hz1acdd58aea6b75migoy4axqasdf
|
||||
> host1# eval $(weave env)
|
||||
> host1# docker run --name a1 -ti weaveworks/ubuntu
|
||||
> ```
|
||||
> Do *not* prefix individual commands with `sudo`, since some commands
|
||||
> modify environment entries and hence they all need to be executed from
|
||||
> the same shell.
|
||||
|
||||
Weave Net must be launched once per host. The relevant container images will be pulled down from Docker Hub on demand during `weave launch`.
|
||||
|
||||
You can also preload the images by running `weave setup`. Preloaded images are useful for automated deployments, and ensure there are no delays during later operations.
|
||||
|
||||
If you are deploying an application that consists of more than one container to the same host, launch them one after another using `docker run`, as appropriate.
|
||||
|
||||
|
||||
### <a name="peer-connections"></a>Launching on Additional Hosts
|
||||
|
||||
To launch Weave Net on an additional host and create a peer
|
||||
connection, run exactly the same commands as on the first host:
|
||||
|
||||
host2$ weave launch --token=dk6hz1acdd58aea6b75migoy4axqasdf
|
||||
host2$ eval $(weave env)
|
||||
host2$ docker run --name a2 -ti weaveworks/ubuntu
|
||||
|
||||
Because you are using Weave Cloud, the second peer will discover the
|
||||
first and automatically create a connection to it.
|
||||
|
||||
>**Note:** If there is a firewall between `$HOST1` and `$HOST2`, you must permit traffic to flow through TCP 6783 and UDP 6783/6784, which are Weave’s control and data ports.
|
||||
|
||||
Now you can proceed to [test container communications](site/using-weave#testing)
|
||||
|
||||
### <a name="how-it-works"></a>How Peer Discovery Works
|
||||
|
||||
The Weave Cloud back-end maintains a database of all the peers that
|
||||
have registered in each instance. You can create as many instances as
|
||||
you like in the Weave Cloud console: for different projects, or to
|
||||
separate test and production.
|
||||
|
||||
As each peer starts up, it looks for all network instances that
|
||||
another peer might be able to contact it on, and registers those with the back-end.
|
||||
If you want to control which addresses are used, add the `--advertise-address` flag:
|
||||
|
||||
host1$ weave launch --token=dk6hz1acdd58aea6b75migoy4axqasdf --advertise-address=192.0.2.1,198.51.100.4
|
||||
|
||||
When the new peer registers itself, it also fetches a list of all
|
||||
other peers in the instance, and begins to contact them.
|
||||
|
||||
If the peer cannot contact the Weave Cloud back-end it will print an
|
||||
error message in its log and exit. To check the logs run:
|
||||
|
||||
host1$ docker logs weave
|
||||
|
||||
When a Weave Net instance is formed for the first time, the peers must
|
||||
initialize the [IP Allocation Manager](site/ipam.md). This process,
|
||||
and the configuration options available, are unchanged when using
|
||||
Weave Cloud.
|
||||
|
||||
When you shut down a peer for good, use [the `weave reset`
|
||||
command](site/ipam/stop-remove-peers-ipam.md) and it will be removed
|
||||
from the Weave Cloud database so future peers will not attempt to
|
||||
connect to it.
|
||||
|
||||
**See Also**
|
||||
|
||||
* [Installing Weave Net](/site/installing-weave.md)
|
||||
* [Using Weave Net](/site/using-weave.md)
|
||||
* [Using Fastdp With Weave Net](/site/using-weave/fastdp.md)
|
||||
* [Using the Weave Net Docker Network Plugin](/site/plugin.md)
|
||||
+1
-1
Submodule vendor/github.com/weaveworks/common updated: 08ae9c8392...14d8aacf4c.
+1
Submodule vendor/golang.org/x/net added at d379faa25c.
+1
Submodule vendor/google.golang.org/grpc added at 1dab933725.
Reference in new issue
Block a user