go.etcd.io/etcd@v3.3.27+incompatible/Documentation/upgrades/upgrade_3_3.md (about) 1 --- 2 title: Upgrade etcd from 3.2 to 3.3 3 --- 4 5 In the general case, upgrading from etcd 3.2 to 3.3 can be a zero-downtime, rolling upgrade: 6 - one by one, stop the etcd v3.2 processes and replace them with etcd v3.3 processes 7 - after running all v3.3 processes, new features in v3.3 are available to the cluster 8 9 Before [starting an upgrade](#upgrade-procedure), read through the rest of this guide to prepare. 10 11 ### Upgrade checklists 12 13 **NOTE:** When [migrating from v2 with no v3 data](https://github.com/etcd-io/etcd/issues/9480), etcd server v3.2+ panics when etcd restores from existing snapshots but no v3 `ETCD_DATA_DIR/member/snap/db` file. This happens when the server had migrated from v2 with no previous v3 data. This also prevents accidental v3 data loss (e.g. `db` file might have been moved). etcd requires that post v3 migration can only happen with v3 data. Do not upgrade to newer v3 versions until v3.0 server contains v3 data. 14 15 Highlighted breaking changes in 3.3. 16 17 #### Changed value type of `etcd --auto-compaction-retention` flag to `string` 18 19 Changed `--auto-compaction-retention` flag to [accept string values](https://github.com/etcd-io/etcd/pull/8563) with [finer granularity](https://github.com/etcd-io/etcd/issues/8503). Now that `--auto-compaction-retention` accepts string values, etcd configuration YAML file `auto-compaction-retention` field must be changed to `string` type. Previously, `--config-file etcd.config.yaml` can have `auto-compaction-retention: 24` field, now must be `auto-compaction-retention: "24"` or `auto-compaction-retention: "24h"`. If configured as `--auto-compaction-mode periodic --auto-compaction-retention "24h"`, the time duration value for `--auto-compaction-retention` flag must be valid for [`time.ParseDuration`](https://golang.org/pkg/time/#ParseDuration) function in Go. 20 21 ```diff 22 # etcd.config.yaml 23 +auto-compaction-mode: periodic 24 -auto-compaction-retention: 24 25 +auto-compaction-retention: "24" 26 +# Or 27 +auto-compaction-retention: "24h" 28 ``` 29 30 #### Changed `etcdserver.EtcdServer.ServerConfig` to `*etcdserver.EtcdServer.ServerConfig` 31 32 `etcdserver.EtcdServer` has changed the type of its member field `*etcdserver.ServerConfig` to `etcdserver.ServerConfig`. And `etcdserver.NewServer` now takes `etcdserver.ServerConfig`, instead of `*etcdserver.ServerConfig`. 33 34 Before and after (e.g. [k8s.io/kubernetes/test/e2e_node/services/etcd.go](https://github.com/kubernetes/kubernetes/blob/release-1.8/test/e2e_node/services/etcd.go#L50-L55)) 35 36 ```diff 37 import "github.com/coreos/etcd/etcdserver" 38 39 type EtcdServer struct { 40 *etcdserver.EtcdServer 41 - config *etcdserver.ServerConfig 42 + config etcdserver.ServerConfig 43 } 44 45 func NewEtcd(dataDir string) *EtcdServer { 46 - config := &etcdserver.ServerConfig{ 47 + config := etcdserver.ServerConfig{ 48 DataDir: dataDir, 49 ... 50 } 51 return &EtcdServer{config: config} 52 } 53 54 func (e *EtcdServer) Start() error { 55 var err error 56 e.EtcdServer, err = etcdserver.NewServer(e.config) 57 ... 58 ``` 59 60 #### Added `embed.Config.LogOutput` struct 61 62 **Note that this field has been renamed to `embed.Config.LogOutputs` in `[]string` type in v3.4. Please see [v3.4 upgrade guide](https://github.com/etcd-io/etcd/blob/master/Documentation/upgrades/upgrade_3_4.md) for more details.** 63 64 Field `LogOutput` is added to `embed.Config`: 65 66 ```diff 67 package embed 68 69 type Config struct { 70 Debug bool `json:"debug"` 71 LogPkgLevels string `json:"log-package-levels"` 72 + LogOutput string `json:"log-output"` 73 ... 74 ``` 75 76 Before gRPC server warnings were logged in etcdserver. 77 78 ``` 79 WARNING: 2017/11/02 11:35:51 grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: Error while dialing dial tcp: operation was canceled"; Reconnecting to {localhost:2379 <nil>} 80 WARNING: 2017/11/02 11:35:51 grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: Error while dialing dial tcp: operation was canceled"; Reconnecting to {localhost:2379 <nil>} 81 ``` 82 83 From v3.3, gRPC server logs are disabled by default. 84 85 **Note that `embed.Config.SetupLogging` method has been deprecated in v3.4. Please see [v3.4 upgrade guide](https://github.com/etcd-io/etcd/blob/master/Documentation/upgrades/upgrade_3_4.md) for more details.** 86 87 ```go 88 import "github.com/coreos/etcd/embed" 89 90 cfg := &embed.Config{Debug: false} 91 cfg.SetupLogging() 92 ``` 93 94 Set `embed.Config.Debug` field to `true` to enable gRPC server logs. 95 96 #### Changed `/health` endpoint response 97 98 Previously, `[endpoint]:[client-port]/health` returned manually marshaled JSON value. 3.3 now defines [`etcdhttp.Health`](https://godoc.org/github.com/coreos/etcd/etcdserver/api/etcdhttp#Health) struct. 99 100 Note that in v3.3.0-rc.0, v3.3.0-rc.1, and v3.3.0-rc.2, `etcdhttp.Health` has boolean type `"health"` and `"errors"` fields. For backward compatibilities, we reverted `"health"` field to `string` type and removed `"errors"` field. Further health information will be provided in separate APIs. 101 102 ```bash 103 $ curl http://localhost:2379/health 104 {"health":"true"} 105 ``` 106 107 #### Changed gRPC gateway HTTP endpoints (replaced `/v3alpha` with `/v3beta`) 108 109 Before 110 111 ```bash 112 curl -L http://localhost:2379/v3alpha/kv/put \ 113 -X POST -d '{"key": "Zm9v", "value": "YmFy"}' 114 ``` 115 116 After 117 118 ```bash 119 curl -L http://localhost:2379/v3beta/kv/put \ 120 -X POST -d '{"key": "Zm9v", "value": "YmFy"}' 121 ``` 122 123 Requests to `/v3alpha` endpoints will redirect to `/v3beta`, and `/v3alpha` will be removed in 3.4 release. 124 125 #### Changed maximum request size limits 126 127 3.3 now allows custom request size limits for both server and **client side**. In previous versions(v3.2.10, v3.2.11), client response size was limited to only 4 MiB. 128 129 Server-side request limits can be configured with `--max-request-bytes` flag: 130 131 ```bash 132 # limits request size to 1.5 KiB 133 etcd --max-request-bytes 1536 134 135 # client writes exceeding 1.5 KiB will be rejected 136 etcdctl put foo [LARGE VALUE...] 137 # etcdserver: request is too large 138 ``` 139 140 Or configure `embed.Config.MaxRequestBytes` field: 141 142 ```go 143 import "github.com/coreos/etcd/embed" 144 import "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes" 145 146 // limit requests to 5 MiB 147 cfg := embed.NewConfig() 148 cfg.MaxRequestBytes = 5 * 1024 * 1024 149 150 // client writes exceeding 5 MiB will be rejected 151 _, err := cli.Put(ctx, "foo", [LARGE VALUE...]) 152 err == rpctypes.ErrRequestTooLarge 153 ``` 154 155 **If not specified, server-side limit defaults to 1.5 MiB**. 156 157 Client-side request limits must be configured based on server-side limits. 158 159 ```bash 160 # limits request size to 1 MiB 161 etcd --max-request-bytes 1048576 162 ``` 163 164 ```go 165 import "github.com/coreos/etcd/clientv3" 166 167 cli, _ := clientv3.New(clientv3.Config{ 168 Endpoints: []string{"127.0.0.1:2379"}, 169 MaxCallSendMsgSize: 2 * 1024 * 1024, 170 MaxCallRecvMsgSize: 3 * 1024 * 1024, 171 }) 172 173 174 // client writes exceeding "--max-request-bytes" will be rejected from etcd server 175 _, err := cli.Put(ctx, "foo", strings.Repeat("a", 1*1024*1024+5)) 176 err == rpctypes.ErrRequestTooLarge 177 178 179 // client writes exceeding "MaxCallSendMsgSize" will be rejected from client-side 180 _, err = cli.Put(ctx, "foo", strings.Repeat("a", 5*1024*1024)) 181 err.Error() == "rpc error: code = ResourceExhausted desc = grpc: trying to send message larger than max (5242890 vs. 2097152)" 182 183 184 // some writes under limits 185 for i := range []int{0,1,2,3,4} { 186 _, err = cli.Put(ctx, fmt.Sprintf("foo%d", i), strings.Repeat("a", 1*1024*1024-500)) 187 if err != nil { 188 panic(err) 189 } 190 } 191 // client reads exceeding "MaxCallRecvMsgSize" will be rejected from client-side 192 _, err = cli.Get(ctx, "foo", clientv3.WithPrefix()) 193 err.Error() == "rpc error: code = ResourceExhausted desc = grpc: received message larger than max (5240509 vs. 3145728)" 194 ``` 195 196 **If not specified, client-side send limit defaults to 2 MiB (1.5 MiB + gRPC overhead bytes) and receive limit to `math.MaxInt32`**. Please see [clientv3 godoc](https://godoc.org/github.com/coreos/etcd/clientv3#Config) for more detail. 197 198 #### Changed raw gRPC client wrapper function signatures 199 200 3.3 changes the function signatures of `clientv3` gRPC client wrapper. This change was needed to support [custom `grpc.CallOption` on message size limits](https://github.com/etcd-io/etcd/pull/9047). 201 202 Before and after 203 204 ```diff 205 -func NewKVFromKVClient(remote pb.KVClient) KV { 206 +func NewKVFromKVClient(remote pb.KVClient, c *Client) KV { 207 208 -func NewClusterFromClusterClient(remote pb.ClusterClient) Cluster { 209 +func NewClusterFromClusterClient(remote pb.ClusterClient, c *Client) Cluster { 210 211 -func NewLeaseFromLeaseClient(remote pb.LeaseClient, keepAliveTimeout time.Duration) Lease { 212 +func NewLeaseFromLeaseClient(remote pb.LeaseClient, c *Client, keepAliveTimeout time.Duration) Lease { 213 214 -func NewMaintenanceFromMaintenanceClient(remote pb.MaintenanceClient) Maintenance { 215 +func NewMaintenanceFromMaintenanceClient(remote pb.MaintenanceClient, c *Client) Maintenance { 216 217 -func NewWatchFromWatchClient(wc pb.WatchClient) Watcher { 218 +func NewWatchFromWatchClient(wc pb.WatchClient, c *Client) Watcher { 219 ``` 220 221 #### Changed clientv3 `Snapshot` API error type 222 223 Previously, clientv3 `Snapshot` API returned raw [`grpc/*status.statusError`] type error. v3.3 now translates those errors to corresponding public error types, to be consistent with other APIs. 224 225 Before 226 227 ```go 228 import "context" 229 230 // reading snapshot with canceled context should error out 231 ctx, cancel := context.WithCancel(context.Background()) 232 rc, _ := cli.Snapshot(ctx) 233 cancel() 234 _, err := io.Copy(f, rc) 235 err.Error() == "rpc error: code = Canceled desc = context canceled" 236 237 // reading snapshot with deadline exceeded should error out 238 ctx, cancel = context.WithTimeout(context.Background(), time.Second) 239 defer cancel() 240 rc, _ = cli.Snapshot(ctx) 241 time.Sleep(2 * time.Second) 242 _, err = io.Copy(f, rc) 243 err.Error() == "rpc error: code = DeadlineExceeded desc = context deadline exceeded" 244 ``` 245 246 After 247 248 ```go 249 import "context" 250 251 // reading snapshot with canceled context should error out 252 ctx, cancel := context.WithCancel(context.Background()) 253 rc, _ := cli.Snapshot(ctx) 254 cancel() 255 _, err := io.Copy(f, rc) 256 err == context.Canceled 257 258 // reading snapshot with deadline exceeded should error out 259 ctx, cancel = context.WithTimeout(context.Background(), time.Second) 260 defer cancel() 261 rc, _ = cli.Snapshot(ctx) 262 time.Sleep(2 * time.Second) 263 _, err = io.Copy(f, rc) 264 err == context.DeadlineExceeded 265 ``` 266 267 #### Changed `etcdctl lease timetolive` command output 268 269 Previously, `lease timetolive LEASE_ID` command on expired lease prints `-1s` for remaining seconds. 3.3 now outputs clearer messages. 270 271 Before 272 273 274 ```bash 275 lease 2d8257079fa1bc0c granted with TTL(0s), remaining(-1s) 276 ``` 277 278 After 279 280 ```bash 281 lease 2d8257079fa1bc0c already expired 282 ``` 283 284 #### Changed `golang.org/x/net/context` imports 285 286 `clientv3` has deprecated `golang.org/x/net/context`. If a project vendors `golang.org/x/net/context` in other code (e.g. etcd generated protocol buffer code) and imports `github.com/coreos/etcd/clientv3`, it requires Go 1.9+ to compile. 287 288 Before 289 290 ```go 291 import "golang.org/x/net/context" 292 cli.Put(context.Background(), "f", "v") 293 ``` 294 295 After 296 297 ```go 298 import "context" 299 cli.Put(context.Background(), "f", "v") 300 ``` 301 302 #### Changed gRPC dependency 303 304 3.3 now requires [grpc/grpc-go](https://github.com/grpc/grpc-go/releases) `v1.7.5`. 305 306 ##### Deprecated `grpclog.Logger` 307 308 `grpclog.Logger` has been deprecated in favor of [`grpclog.LoggerV2`](https://github.com/grpc/grpc-go/blob/master/grpclog/loggerv2.go). `clientv3.Logger` is now `grpclog.LoggerV2`. 309 310 Before 311 312 ```go 313 import "github.com/coreos/etcd/clientv3" 314 clientv3.SetLogger(log.New(os.Stderr, "grpc: ", 0)) 315 ``` 316 317 After 318 319 ```go 320 import "github.com/coreos/etcd/clientv3" 321 import "google.golang.org/grpc/grpclog" 322 clientv3.SetLogger(grpclog.NewLoggerV2(os.Stderr, os.Stderr, os.Stderr)) 323 324 // log.New above cannot be used (not implement grpclog.LoggerV2 interface) 325 ``` 326 327 ##### Deprecated `grpc.ErrClientConnTimeout` 328 329 Previously, `grpc.ErrClientConnTimeout` error is returned on client dial time-outs. 3.3 instead returns `context.DeadlineExceeded` (see [#8504](https://github.com/etcd-io/etcd/issues/8504)). 330 331 Before 332 333 ```go 334 // expect dial time-out on ipv4 blackhole 335 _, err := clientv3.New(clientv3.Config{ 336 Endpoints: []string{"http://254.0.0.1:12345"}, 337 DialTimeout: 2 * time.Second 338 }) 339 if err == grpc.ErrClientConnTimeout { 340 // handle errors 341 } 342 ``` 343 344 After 345 346 ```go 347 _, err := clientv3.New(clientv3.Config{ 348 Endpoints: []string{"http://254.0.0.1:12345"}, 349 DialTimeout: 2 * time.Second 350 }) 351 if err == context.DeadlineExceeded { 352 // handle errors 353 } 354 ``` 355 356 #### Changed official container registry 357 358 etcd now uses [`gcr.io/etcd-development/etcd`](https://gcr.io/etcd-development/etcd) as a primary container registry, and [`quay.io/coreos/etcd`](https://quay.io/coreos/etcd) as secondary. 359 360 Before 361 362 ```bash 363 docker pull quay.io/coreos/etcd:v3.2.5 364 ``` 365 366 After 367 368 ```bash 369 docker pull gcr.io/etcd-development/etcd:v3.3.0 370 ``` 371 372 ### Upgrades to >= v3.3.14 373 374 [v3.3.14](https://github.com/etcd-io/etcd/releases/tag/v3.3.14) had to include some features from 3.4, while trying to minimize the difference between client balancer implementation. This release fixes ["kube-apiserver 1.13.x refuses to work when first etcd-server is not available" (kubernetes#72102)](https://github.com/kubernetes/kubernetes/issues/72102). 375 376 `grpc.ErrClientConnClosing` has been [deprecated in gRPC >= 1.10](https://github.com/grpc/grpc-go/pull/1854). 377 378 ```diff 379 import ( 380 + "go.etcd.io/etcd/clientv3" 381 382 "google.golang.org/grpc" 383 + "google.golang.org/grpc/codes" 384 + "google.golang.org/grpc/status" 385 ) 386 387 _, err := kvc.Get(ctx, "a") 388 -if err == grpc.ErrClientConnClosing { 389 +if clientv3.IsConnCanceled(err) { 390 391 // or 392 +s, ok := status.FromError(err) 393 +if ok { 394 + if s.Code() == codes.Canceled 395 ``` 396 397 [The new client balancer](https://github.com/etcd-io/etcd/blob/master/Documentation/learning/design-client.md) uses an asynchronous resolver to pass endpoints to the gRPC dial function. As a result, [v3.3.14](https://github.com/etcd-io/etcd/releases/tag/v3.3.14) or later requires `grpc.WithBlock` dial option to wait until the underlying connection is up. 398 399 ```diff 400 import ( 401 "time" 402 "go.etcd.io/etcd/clientv3" 403 + "google.golang.org/grpc" 404 ) 405 406 +// "grpc.WithBlock()" to block until the underlying connection is up 407 ccfg := clientv3.Config{ 408 Endpoints: []string{"localhost:2379"}, 409 DialTimeout: time.Second, 410 + DialOptions: []grpc.DialOption{grpc.WithBlock()}, 411 DialKeepAliveTime: time.Second, 412 DialKeepAliveTimeout: 500 * time.Millisecond, 413 } 414 ``` 415 416 Please see [CHANGELOG](https://github.com/etcd-io/etcd/blob/master/CHANGELOG-3.3.md) for a full list of changes. 417 418 ### Server upgrade checklists 419 420 #### Upgrade requirements 421 422 To upgrade an existing etcd deployment to 3.3, the running cluster must be 3.2 or greater. If it's before 3.2, please [upgrade to 3.2](upgrade_3_2.md) before upgrading to 3.3. 423 424 Also, to ensure a smooth rolling upgrade, the running cluster must be healthy. Check the health of the cluster by using the `etcdctl endpoint health` command before proceeding. 425 426 #### Preparation 427 428 Before upgrading etcd, always test the services relying on etcd in a staging environment before deploying the upgrade to the production environment. 429 430 Before beginning, [backup the etcd data](../op-guide/maintenance.md#snapshot-backup). Should something go wrong with the upgrade, it is possible to use this backup to [downgrade](#downgrade) back to existing etcd version. Please note that the `snapshot` command only backs up the v3 data. For v2 data, see [backing up v2 datastore](../v2/admin_guide.md#backing-up-the-datastore). 431 432 #### Mixed versions 433 434 While upgrading, an etcd cluster supports mixed versions of etcd members, and operates with the protocol of the lowest common version. The cluster is only considered upgraded once all of its members are upgraded to version 3.3. Internally, etcd members negotiate with each other to determine the overall cluster version, which controls the reported version and the supported features. 435 436 #### Limitations 437 438 Note: If the cluster only has v3 data and no v2 data, it is not subject to this limitation. 439 440 If the cluster is serving a v2 data set larger than 50MB, each newly upgraded member may take up to two minutes to catch up with the existing cluster. Check the size of a recent snapshot to estimate the total data size. In other words, it is safest to wait for 2 minutes between upgrading each member. 441 442 For a much larger total data size, 100MB or more , this one-time process might take even more time. Administrators of very large etcd clusters of this magnitude can feel free to contact the [etcd team][etcd-contact] before upgrading, and we'll be happy to provide advice on the procedure. 443 444 #### Downgrade 445 446 If all members have been upgraded to v3.3, the cluster will be upgraded to v3.3, and downgrade from this completed state is **not possible**. If any single member is still v3.2, however, the cluster and its operations remains "v3.2", and it is possible from this mixed cluster state to return to using a v3.2 etcd binary on all members. 447 448 Please [backup the data directory](../op-guide/maintenance.md#snapshot-backup) of all etcd members to make downgrading the cluster possible even after it has been completely upgraded. 449 450 ### Upgrade procedure 451 452 This example shows how to upgrade a 3-member v3.2 ectd cluster running on a local machine. 453 454 #### 1. Check upgrade requirements 455 456 Is the cluster healthy and running v3.2.x? 457 458 ``` 459 $ ETCDCTL_API=3 etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379 460 localhost:2379 is healthy: successfully committed proposal: took = 6.600684ms 461 localhost:22379 is healthy: successfully committed proposal: took = 8.540064ms 462 localhost:32379 is healthy: successfully committed proposal: took = 8.763432ms 463 464 $ curl http://localhost:2379/version 465 {"etcdserver":"3.2.7","etcdcluster":"3.2.0"} 466 ``` 467 468 #### 2. Stop the existing etcd process 469 470 When each etcd process is stopped, expected errors will be logged by other cluster members. This is normal since a cluster member connection has been (temporarily) broken: 471 472 ``` 473 14:13:31.491746 I | raft: c89feb932daef420 [term 3] received MsgTimeoutNow from 6d4f535bae3ab960 and starts an election to get leadership. 474 14:13:31.491769 I | raft: c89feb932daef420 became candidate at term 4 475 14:13:31.491788 I | raft: c89feb932daef420 received MsgVoteResp from c89feb932daef420 at term 4 476 14:13:31.491797 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 6d4f535bae3ab960 at term 4 477 14:13:31.491805 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 9eda174c7df8a033 at term 4 478 14:13:31.491815 I | raft: raft.node: c89feb932daef420 lost leader 6d4f535bae3ab960 at term 4 479 14:13:31.524084 I | raft: c89feb932daef420 received MsgVoteResp from 6d4f535bae3ab960 at term 4 480 14:13:31.524108 I | raft: c89feb932daef420 [quorum:2] has received 2 MsgVoteResp votes and 0 vote rejections 481 14:13:31.524123 I | raft: c89feb932daef420 became leader at term 4 482 14:13:31.524136 I | raft: raft.node: c89feb932daef420 elected leader c89feb932daef420 at term 4 483 14:13:31.592650 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream MsgApp v2 reader) 484 14:13:31.592825 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message reader) 485 14:13:31.693275 E | rafthttp: failed to dial 6d4f535bae3ab960 on stream Message (dial tcp [::1]:2380: getsockopt: connection refused) 486 14:13:31.693289 I | rafthttp: peer 6d4f535bae3ab960 became inactive 487 14:13:31.936678 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message writer) 488 ``` 489 490 It's a good idea at this point to [backup the etcd data](../op-guide/maintenance.md#snapshot-backup) to provide a downgrade path should any problems occur: 491 492 ``` 493 $ etcdctl snapshot save backup.db 494 ``` 495 496 #### 3. Drop-in etcd v3.3 binary and start the new etcd process 497 498 The new v3.3 etcd will publish its information to the cluster: 499 500 ``` 501 14:14:25.363225 I | etcdserver: published {Name:s1 ClientURLs:[http://localhost:2379]} to cluster a9ededbffcb1b1f1 502 ``` 503 504 Verify that each member, and then the entire cluster, becomes healthy with the new v3.3 etcd binary: 505 506 ``` 507 $ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379 508 localhost:22379 is healthy: successfully committed proposal: took = 5.540129ms 509 localhost:32379 is healthy: successfully committed proposal: took = 7.321771ms 510 localhost:2379 is healthy: successfully committed proposal: took = 10.629901ms 511 ``` 512 513 Upgraded members will log warnings like the following until the entire cluster is upgraded. This is expected and will cease after all etcd cluster members are upgraded to v3.3: 514 515 ``` 516 14:15:17.071804 W | etcdserver: member c89feb932daef420 has a higher version 3.3.0 517 14:15:21.073110 W | etcdserver: the local etcd version 3.2.7 is not up-to-date 518 14:15:21.073142 W | etcdserver: member 6d4f535bae3ab960 has a higher version 3.3.0 519 14:15:21.073157 W | etcdserver: the local etcd version 3.2.7 is not up-to-date 520 14:15:21.073164 W | etcdserver: member c89feb932daef420 has a higher version 3.3.0 521 ``` 522 523 #### 4. Repeat step 2 to step 3 for all other members 524 525 #### 5. Finish 526 527 When all members are upgraded, the cluster will report upgrading to 3.3 successfully: 528 529 ``` 530 14:15:54.536901 N | etcdserver/membership: updated the cluster version from 3.2 to 3.3 531 14:15:54.537035 I | etcdserver/api: enabled capabilities for version 3.3 532 ``` 533 534 ``` 535 $ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379 536 localhost:2379 is healthy: successfully committed proposal: took = 2.312897ms 537 localhost:22379 is healthy: successfully committed proposal: took = 2.553476ms 538 localhost:32379 is healthy: successfully committed proposal: took = 2.517902ms 539 ``` 540 541 [etcd-contact]: https://groups.google.com/forum/#!forum/etcd-dev