Skip to content
This repository was archived by the owner on Jul 30, 2021. It is now read-only.

Commit c6f4556

Browse files
committed
*: add backup file option to recover subcommand
1 parent ca27c9e commit c6f4556

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

cmd/bootkube/recover.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ var (
3636
etcdServers string
3737
etcdPrefix string
3838
kubeConfigPath string
39+
podManifestPath string
40+
etcdBackupFile string
3941
}
4042
)
4143

@@ -46,8 +48,10 @@ func init() {
4648
cmdRecover.Flags().StringVar(&recoverOpts.etcdCertificatePath, "etcd-certificate-path", "", "Path to an existing certificate that will be used for TLS-enabled communication between the apiserver and etcd. Must be used in conjunction with --etcd-ca-path and --etcd-private-key-path, and must have etcd configured to use TLS with matching secrets.")
4749
cmdRecover.Flags().StringVar(&recoverOpts.etcdPrivateKeyPath, "etcd-private-key-path", "", "Path to an existing private key that will be used for TLS-enabled communication between the apiserver and etcd. Must be used in conjunction with --etcd-ca-path and --etcd-certificate-path, and must have etcd configured to use TLS with matching secrets.")
4850
cmdRecover.Flags().StringVar(&recoverOpts.etcdServers, "etcd-servers", "", "List of etcd server URLs including host:port, comma separated.")
51+
cmdRecover.Flags().StringVar(&recoverOpts.etcdBackupFile, "etcd-backup-file", "", "Path to the etcd backup file.")
4952
cmdRecover.Flags().StringVar(&recoverOpts.etcdPrefix, "etcd-prefix", "/registry", "Path prefix to Kubernetes cluster data in etcd.")
5053
cmdRecover.Flags().StringVar(&recoverOpts.kubeConfigPath, "kubeconfig", "", "Path to kubeconfig for communicating with the cluster.")
54+
cmdRecover.Flags().StringVar(&recoverOpts.podManifestPath, "pod-manifest-path", "/etc/kubernetes/manifests", "The location where the kubelet is configured to look for static pod manifests. (Only need to be set when recovering from a etcd backup file)")
5155
}
5256

5357
func runCmdRecover(cmd *cobra.Command, args []string) error {
@@ -66,6 +70,31 @@ func runCmdRecover(cmd *cobra.Command, args []string) error {
6670
return err
6771
}
6872
backend = recovery.NewEtcdBackend(etcdClient, recoverOpts.etcdPrefix)
73+
case recoverOpts.etcdBackupFile != "":
74+
bootkube.UserOutput("Attempting recovery using etcd backup file at %q...\n", recoverOpts.etcdBackupFile)
75+
76+
err := recovery.StartRecoveryEtcdForBackup(recoverOpts.podManifestPath, recoverOpts.etcdBackupFile)
77+
if err != nil {
78+
return err
79+
}
80+
defer func() {
81+
err := recovery.CleanRecoveryEtcd(recoverOpts.podManifestPath)
82+
if err != nil {
83+
bootkube.UserOutput("Failed to cleanup recovery etcd from the podManifestPath %v\n", recoverOpts.podManifestPath)
84+
}
85+
}()
86+
87+
bootkube.UserOutput("Waiting for etcd server to start...\n")
88+
// TODO: better way to detect the startup...
89+
time.Sleep(60 * time.Second)
90+
91+
recoverOpts.etcdServers = "http://localhost:32379"
92+
etcdClient, err := createEtcdClient()
93+
if err != nil {
94+
return err
95+
}
96+
backend = recovery.NewEtcdBackend(etcdClient, recoverOpts.etcdPrefix)
97+
6998
default:
7099
bootkube.UserOutput("Attempting recovery using apiserver at %q...\n", recoverOpts.kubeConfigPath)
71100
backend, err = recovery.NewAPIServerBackend(recoverOpts.kubeConfigPath)

pkg/recovery/etcd.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ package recovery
66
import (
77
"context"
88
"fmt"
9+
"os"
910
"path"
1011
"strings"
1112

13+
"github.com/kubernetes-incubator/bootkube/pkg/asset"
14+
1215
"github.com/coreos/etcd/clientv3"
1316
"k8s.io/apimachinery/pkg/api/meta"
1417
"k8s.io/apimachinery/pkg/runtime"
@@ -96,3 +99,28 @@ func (s *etcdBackend) list(ctx context.Context, key string, listObj runtime.Obje
9699
}
97100
return decodeList(elems, listPtr, s.decoder)
98101
}
102+
103+
const assetPathRecoveryEtcd = "recovery-etcd.yaml"
104+
105+
func StartRecoveryEtcdForBackup(p, backupPath string) error {
106+
d, f := path.Split(backupPath)
107+
108+
config := struct {
109+
Image string
110+
BackupFile string
111+
BackupDir string
112+
}{
113+
// TODO: this already exists in bootkube/cmd.
114+
// do not duplicate this!
115+
Image: "quay.io/coreos/etcd:v3.1.6",
116+
BackupFile: f,
117+
BackupDir: d,
118+
}
119+
120+
as := asset.MustCreateAssetFromTemplate(assetPathRecoveryEtcd, RecoveryEtcdTemplate, config)
121+
return as.WriteFile(p)
122+
}
123+
124+
func CleanRecoveryEtcd(p string) error {
125+
return os.Remove(path.Join(p, assetPathRecoveryEtcd))
126+
}

pkg/recovery/etcd_template.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package recovery
2+
3+
var RecoveryEtcdTemplate = []byte(`apiVersion: v1
4+
kind: Pod
5+
metadata:
6+
name: recovery-etcd
7+
namespace: kube-system
8+
labels:
9+
k8s-app: recovery-etcd
10+
spec:
11+
initContainers:
12+
- name: recovery
13+
image: {{ .Image }}
14+
command:
15+
- /usr/local/bin/etcdctl
16+
- snapshot
17+
- restore
18+
- --data-dir=/var/etcd/recovery
19+
- --name=recovery-etcd
20+
- --initial-cluster=recovery-etcd=http://localhost:32380
21+
- --initial-cluster-token=bootkube-recovery
22+
- --initial-advertise-peer-urls=http://localhost:32380
23+
- --skip-hash-check=true
24+
- /var/etcd-backupdir/{{ .BackupFile }}
25+
env:
26+
- name: ETCDCTL_API
27+
value: "3"
28+
volumeMounts:
29+
- mountPath: /var/etcd
30+
name: etcd
31+
readOnly: false
32+
- mountPath: /var/etcd-backupdir
33+
name: etcdbackup
34+
readOnly: false
35+
containers:
36+
- name: etcd
37+
image: {{ .Image }}
38+
command:
39+
- /usr/local/bin/etcd
40+
- --name=recovery-etcd
41+
- --listen-client-urls=http://0.0.0.0:32379
42+
- --listen-peer-urls=http://0.0.0.0:32380
43+
- --advertise-client-urls=http://localhost:32379
44+
- --data-dir=/var/etcd/recovery
45+
volumeMounts:
46+
- mountPath: /var/etcd
47+
name: etcd
48+
readOnly: false
49+
hostNetwork: true
50+
restartPolicy: Never
51+
volumes:
52+
- name: etcd
53+
emptyDir: {}
54+
- name: etcdbackup
55+
hostPath:
56+
path: {{ .BackupDir }}
57+
`)

0 commit comments

Comments
 (0)