commit
9a56001d63
|
@ -5,7 +5,7 @@ When first started, etcd stores its configuration into the data directory. This
|
|||
|
||||
If a member’s data directory is ever lost or corrupted, the user should remove the etcd member from the cluster via the [members API][0]. (The member can then be re-added to the cluster with an empty data directory, again using the [members API][0], and it will recover state).
|
||||
|
||||
An etcd member restarted with previously used command line arguments but a new data directory is considered a different member. And it can potentially corrupt the cluster. If you are spinning up multiple clusters for testing it is recommended that you specify a unique cluster-name for the different clusters. This can protect you from cluster corruption in case of the misconfiguration metioned above.
|
||||
An etcd member restarted with previously used command line arguments but a new data directory is considered a different member. And it can potentially corrupt the cluster. If you are spinning up multiple clusters for testing it is recommended that you specify a unique initial-cluster-token for the different clusters. This can protect you from cluster corruption in case of the misconfiguration metioned above.
|
||||
|
||||
The data directory has two sub-directories in it:
|
||||
|
||||
|
|
|
@ -25,16 +25,19 @@ ETCD_INITIAL_CLUSTER_STATE=new
|
|||
-initial-cluster-state new
|
||||
```
|
||||
|
||||
If you are spinning up multiple clusters (or creating and destroying a single cluster) with same configuration for testing purpose, it is highly recommended that you specify a unique `initial-cluster-token` for the different clusters.
|
||||
By doing this, etcd can generate unique cluster IDs and member IDs for the clusters even if they otherwise have the exact same configuration. This can protect you from cross-cluster-interaction, which might corrupt your clusters.
|
||||
|
||||
On each machine you would start etcd with these flags:
|
||||
|
||||
```
|
||||
$ etcd -name infra0 -initial-advertise-peer-urls https://10.0.1.10:2379 \
|
||||
$ etcd -name infra0 -initial-advertise-peer-urls https://10.0.1.10:2379 initial-cluster-token etcd-cluster-1\
|
||||
-initial-cluster infra0=http://10.0.1.10:2379,infra1=http://10.0.1.11:2379,infra2=http://10.0.1.12:2379 \
|
||||
-initial-cluster-state new
|
||||
$ etcd -name infra1 -initial-advertise-peer-urls https://10.0.1.11:2379 \
|
||||
$ etcd -name infra1 -initial-advertise-peer-urls https://10.0.1.11:2379 initial-cluster-token etcd-cluster-1\
|
||||
-initial-cluster infra0=http://10.0.1.10:2379,infra1=http://10.0.1.11:2379,infra2=http://10.0.1.12:2379 \
|
||||
-initial-cluster-state new
|
||||
$ etcd -name infra2 -initial-advertise-peer-urls https://10.0.1.12:2379 \
|
||||
$ etcd -name infra2 -initial-advertise-peer-urls https://10.0.1.12:2379 initial-cluster-token etcd-cluster-1\
|
||||
-initial-cluster infra0=http://10.0.1.10:2379,infra1=http://10.0.1.11:2379,infra2=http://10.0.1.12:2379 \
|
||||
-initial-cluster-state new
|
||||
```
|
||||
|
|
6
Procfile
6
Procfile
|
@ -1,5 +1,5 @@
|
|||
# Use goreman to run `go get github.com/mattn/goreman`
|
||||
etcd1: bin/etcd -name node1 -listen-client-urls http://127.0.0.1:4001 -advertise-client-urls http://127.0.0.1:4001 -listen-peer-urls http://127.0.0.1:7001 -initial-advertise-peer-urls http://127.0.0.1:7001 -initial-cluster 'node1=http://localhost:7001,node2=http://localhost:7002,node3=http://localhost:7003' -initial-cluster-state new
|
||||
etcd2: bin/etcd -name node2 -listen-client-urls http://127.0.0.1:4002 -advertise-client-urls http://127.0.0.1:4002 -listen-peer-urls http://127.0.0.1:7002 -initial-advertise-peer-urls http://127.0.0.1:7002 -initial-cluster 'node1=http://localhost:7001,node2=http://localhost:7002,node3=http://localhost:7003' -initial-cluster-state new
|
||||
etcd3: bin/etcd -name node3 -listen-client-urls http://127.0.0.1:4003 -advertise-client-urls http://127.0.0.1:4003 -listen-peer-urls http://127.0.0.1:7003 -initial-advertise-peer-urls http://127.0.0.1:7003 -initial-cluster 'node1=http://localhost:7001,node2=http://localhost:7002,node3=http://localhost:7003' -initial-cluster-state new
|
||||
etcd1: bin/etcd -name node1 -listen-client-urls http://127.0.0.1:4001 -advertise-client-urls http://127.0.0.1:4001 -listen-peer-urls http://127.0.0.1:7001 -initial-advertise-peer-urls http://127.0.0.1:7001 -initial-cluster-token etcd-cluster-1 -initial-cluster 'node1=http://localhost:7001,node2=http://localhost:7002,node3=http://localhost:7003' -initial-cluster-state new
|
||||
etcd2: bin/etcd -name node2 -listen-client-urls http://127.0.0.1:4002 -advertise-client-urls http://127.0.0.1:4002 -listen-peer-urls http://127.0.0.1:7002 -initial-advertise-peer-urls http://127.0.0.1:7002 -initial-cluster-token etcd-cluster-1 -initial-cluster 'node1=http://localhost:7001,node2=http://localhost:7002,node3=http://localhost:7003' -initial-cluster-state new
|
||||
etcd3: bin/etcd -name node3 -listen-client-urls http://127.0.0.1:4003 -advertise-client-urls http://127.0.0.1:4003 -listen-peer-urls http://127.0.0.1:7003 -initial-advertise-peer-urls http://127.0.0.1:7003 -initial-cluster-token etcd-cluster-1 -initial-cluster 'node1=http://localhost:7001,node2=http://localhost:7002,node3=http://localhost:7003' -initial-cluster-state new
|
||||
proxy: bin/etcd -proxy=on -bind-addr 127.0.0.1:8080 -initial-cluster 'node1=http://localhost:7001,node2=http://localhost:7002,node3=http://localhost:7003'
|
||||
|
|
|
@ -48,9 +48,9 @@ var (
|
|||
snapCount = fs.Uint64("snapshot-count", etcdserver.DefaultSnapCount, "Number of committed transactions to trigger a snapshot")
|
||||
printVersion = fs.Bool("version", false, "Print the version and exit")
|
||||
|
||||
initialCluster = fs.String("initial-cluster", "default=http://localhost:2380,default=http://localhost:7001", "Initial cluster configuration for bootstrapping")
|
||||
initialClusterName = fs.String("initial-cluster-name", "etcd", "Initial name for the etcd cluster during bootstrap")
|
||||
clusterState = new(etcdserver.ClusterState)
|
||||
initialCluster = fs.String("initial-cluster", "default=http://localhost:2380,default=http://localhost:7001", "Initial cluster configuration for bootstrapping")
|
||||
initialClusterToken = fs.String("initial-cluster-token", "etcd-cluster", "Initial cluster token for the etcd cluster during bootstrap")
|
||||
clusterState = new(etcdserver.ClusterState)
|
||||
|
||||
corsInfo = &cors.CORSInfo{}
|
||||
proxyFlag = new(flags.Proxy)
|
||||
|
@ -306,7 +306,7 @@ func setupCluster() (*etcdserver.Cluster, error) {
|
|||
default:
|
||||
// We're statically configured, and cluster has appropriately been set.
|
||||
// Try to configure by indexing the static cluster by name.
|
||||
cls, err = etcdserver.NewClusterFromString(*initialClusterName, *initialCluster)
|
||||
cls, err = etcdserver.NewClusterFromString(*initialClusterToken, *initialCluster)
|
||||
}
|
||||
return cls, err
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ import (
|
|||
|
||||
func TestGenClusterString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
urls []string
|
||||
wstr string
|
||||
token string
|
||||
urls []string
|
||||
wstr string
|
||||
}{
|
||||
{
|
||||
"default", []string{"http://127.0.0.1:4001"},
|
||||
|
@ -42,7 +42,7 @@ func TestGenClusterString(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected new urls error: %v", err)
|
||||
}
|
||||
str := genClusterString(tt.name, urls)
|
||||
str := genClusterString(tt.token, urls)
|
||||
if str != tt.wstr {
|
||||
t.Errorf("#%d: cluster = %s, want %s", i, str, tt.wstr)
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ type ClusterInfo interface {
|
|||
// Cluster is a list of Members that belong to the same raft cluster
|
||||
type Cluster struct {
|
||||
id uint64
|
||||
name string
|
||||
token string
|
||||
members map[uint64]*Member
|
||||
// removed contains the ids of removed members in the cluster.
|
||||
// removed id cannot be reused.
|
||||
|
@ -58,11 +58,11 @@ type Cluster struct {
|
|||
store store.Store
|
||||
}
|
||||
|
||||
// NewClusterFromString returns Cluster through given clusterName and parsing
|
||||
// NewClusterFromString returns Cluster through given cluster token and parsing
|
||||
// members from a sets of names to IPs discovery formatted like:
|
||||
// mach0=http://1.1.1.1,mach0=http://2.2.2.2,mach1=http://3.3.3.3,mach2=http://4.4.4.4
|
||||
func NewClusterFromString(name string, cluster string) (*Cluster, error) {
|
||||
c := newCluster(name)
|
||||
func NewClusterFromString(token string, cluster string) (*Cluster, error) {
|
||||
c := newCluster(token)
|
||||
|
||||
v, err := url.ParseQuery(strings.Replace(cluster, ",", "&", -1))
|
||||
if err != nil {
|
||||
|
@ -76,7 +76,7 @@ func NewClusterFromString(name string, cluster string) (*Cluster, error) {
|
|||
if err := purls.Set(strings.Join(urls, ",")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := NewMember(name, types.URLs(*purls), c.name, nil)
|
||||
m := NewMember(name, types.URLs(*purls), c.token, nil)
|
||||
if _, ok := c.members[m.ID]; ok {
|
||||
return nil, fmt.Errorf("Member exists with identical ID %v", m)
|
||||
}
|
||||
|
@ -86,8 +86,8 @@ func NewClusterFromString(name string, cluster string) (*Cluster, error) {
|
|||
return c, nil
|
||||
}
|
||||
|
||||
func NewClusterFromStore(name string, st store.Store) *Cluster {
|
||||
c := newCluster(name)
|
||||
func NewClusterFromStore(token string, st store.Store) *Cluster {
|
||||
c := newCluster(token)
|
||||
c.store = st
|
||||
|
||||
e, err := c.store.Get(storeMembersPrefix, true, true)
|
||||
|
@ -119,8 +119,8 @@ func NewClusterFromStore(name string, st store.Store) *Cluster {
|
|||
return c
|
||||
}
|
||||
|
||||
func NewClusterFromMembers(name string, id uint64, membs []*Member) *Cluster {
|
||||
c := newCluster(name)
|
||||
func NewClusterFromMembers(token string, id uint64, membs []*Member) *Cluster {
|
||||
c := newCluster(token)
|
||||
c.id = id
|
||||
for _, m := range membs {
|
||||
c.members[m.ID] = m
|
||||
|
@ -128,9 +128,9 @@ func NewClusterFromMembers(name string, id uint64, membs []*Member) *Cluster {
|
|||
return c
|
||||
}
|
||||
|
||||
func newCluster(name string) *Cluster {
|
||||
func newCluster(token string) *Cluster {
|
||||
return &Cluster{
|
||||
name: name,
|
||||
token: token,
|
||||
members: make(map[uint64]*Member),
|
||||
removed: make(map[uint64]bool),
|
||||
}
|
||||
|
|
|
@ -43,8 +43,8 @@ func TestClusterFromString(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("#%d: unexpected new error: %v", i, err)
|
||||
}
|
||||
if c.name != "abc" {
|
||||
t.Errorf("#%d: name = %v, want abc", i, c.name)
|
||||
if c.token != "abc" {
|
||||
t.Errorf("#%d: token = %v, want abc", i, c.token)
|
||||
}
|
||||
wc := newTestCluster(tt.mems)
|
||||
if !reflect.DeepEqual(c.members, wc.members) {
|
||||
|
@ -99,8 +99,8 @@ func TestClusterFromStore(t *testing.T) {
|
|||
hc.AddMember(&m)
|
||||
}
|
||||
c := NewClusterFromStore("abc", st)
|
||||
if c.name != "abc" {
|
||||
t.Errorf("#%d: name = %v, want %v", i, c.name, "abc")
|
||||
if c.token != "abc" {
|
||||
t.Errorf("#%d: token = %v, want %v", i, c.token, "abc")
|
||||
}
|
||||
wc := newTestCluster(tt.mems)
|
||||
if !reflect.DeepEqual(c.members, wc.members) {
|
||||
|
|
|
@ -212,7 +212,7 @@ func NewServer(cfg *ServerConfig) *EtcdServer {
|
|||
if err != nil {
|
||||
log.Fatalf("etcdserver: %v", err)
|
||||
}
|
||||
if cfg.Cluster, err = NewClusterFromString(cfg.Cluster.name, s); err != nil {
|
||||
if cfg.Cluster, err = NewClusterFromString(cfg.Cluster.token, s); err != nil {
|
||||
log.Fatalf("etcdserver: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ func NewServer(cfg *ServerConfig) *EtcdServer {
|
|||
st.Recovery(snapshot.Data)
|
||||
index = snapshot.Index
|
||||
}
|
||||
cfg.Cluster = NewClusterFromStore(cfg.Cluster.name, st)
|
||||
cfg.Cluster = NewClusterFromStore(cfg.Cluster.token, st)
|
||||
id, n, w = restartNode(cfg, index, snapshot)
|
||||
default:
|
||||
log.Fatalf("etcdserver: unsupported bootstrap config")
|
||||
|
|
Loading…
Reference in New Issue