Skip to content

Commit

Permalink
Merge pull request #232 from acekingke/backupForNFS
Browse files Browse the repository at this point in the history
*: support backup/restore with  NFS #148
  • Loading branch information
andyli029 authored Apr 18, 2022
2 parents 3159e89 + 8b9b76e commit 21e0621
Show file tree
Hide file tree
Showing 28 changed files with 407 additions and 31 deletions.
7 changes: 6 additions & 1 deletion api/v1alpha1/backup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ type BackupSpec struct {
Image string `json:"image"`

// HostName represents the host for which to take backup
HostName string `json:"hostname"`
// If is empty, is use leader HostName
HostName string `json:"hostname,omitempty"`

// Represents the name of backup to NFS
// +optional
BackupToNFS string `json:"BackupToNFS,omitempty"`

// ClusterName represents the cluster name to backup
ClusterName string `json:"clustname"`
Expand Down
4 changes: 4 additions & 0 deletions api/v1alpha1/mysqlcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ type MysqlClusterSpec struct {
// Represents the name of the cluster restore from backup path
// +optional
RestoreFrom string `json:"restoreFrom,omitempty"`

// Represents NFS ip address where cluster restore from.
// +optional
RestoreFromNFS string `json:"restoreFromNFS,omitempty"`
}

// MysqlOpts defines the options of MySQL container.
Expand Down
10 changes: 7 additions & 3 deletions backup/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ func (b *Backup) GetNameForJob() string {
return fmt.Sprintf("%s-backup", b.Name)
}

// Create the backup Domain Name.
func (b *Backup) GetBackupURL(cluster_name string, hostname string) string {
return fmt.Sprintf("%s.%s-mysql.%s:%v", hostname, cluster_name, b.Namespace, utils.XBackupPort)
// Create the backup Domain Name or leader DNS.
func (b *Backup) GetBackupURL(clusterName string, hostName string) string {
if len(hostName) != 0 {
return fmt.Sprintf("%s.%s-mysql.%s:%v", hostName, clusterName, b.Namespace, utils.XBackupPort)
} else {
return fmt.Sprintf("%s-leader.%s:%v", clusterName, b.Namespace, utils.XBackupPort)
}
}
40 changes: 37 additions & 3 deletions backup/syncer/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,43 @@ func (s *jobSyncer) ensurePodSpec(in corev1.PodSpec) corev1.PodSpec {
sctName := fmt.Sprintf("%s-secret", s.backup.Spec.ClusterName)
in.Containers[0].Name = utils.ContainerBackupName
in.Containers[0].Image = fmt.Sprintf("%s%s", mysqlcluster.GetPrefixFromEnv(), s.backup.Spec.Image)
in.Containers[0].Args = []string{
"request_a_backup",
s.backup.GetBackupURL(s.backup.Spec.ClusterName, s.backup.Spec.HostName),

if len(s.backup.Spec.BackupToNFS) != 0 {
// add volumn about pvc
in.Volumes = []corev1.Volume{
{
Name: utils.XtrabackupPV,
VolumeSource: corev1.VolumeSource{
NFS: &corev1.NFSVolumeSource{
Server: s.backup.Spec.BackupToNFS,
Path: "/",
},
},
},
}
//"rm -rf /backup/*;curl --user sys_backups:sys_backups sample-mysql-0.sample-mysql.default:8082/download|xbstream -x -C /backup"
in.Containers[0].Command = []string{
"/bin/bash", "-c", "--",
}
var backupToDir string = utils.BuildBackupName(s.backup.Spec.ClusterName)
in.Containers[0].Args = []string{
fmt.Sprintf("mkdir -p /backup/%s;"+
"curl --user $BACKUP_USER:$BACKUP_PASSWORD %s/download|xbstream -x -C /backup/%s; exit ${PIPESTATUS[0]}",
backupToDir,
s.backup.GetBackupURL(s.backup.Spec.ClusterName, s.backup.Spec.HostName), backupToDir),
}
in.Containers[0].VolumeMounts = []corev1.VolumeMount{
{
Name: utils.XtrabackupPV,
MountPath: utils.XtrabckupLocal,
},
}
} else {
// in.Containers[0].ImagePullPolicy = s.opt.ImagePullPolicy
in.Containers[0].Args = []string{
"request_a_backup",
s.backup.GetBackupURL(s.backup.Spec.ClusterName, s.backup.Spec.HostName),
}
}
var optTrue bool = true
in.Containers[0].Env = []corev1.EnvVar{
Expand Down
5 changes: 4 additions & 1 deletion charts/mysql-operator/crds/mysql.radondb.com_backups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ spec:
spec:
description: BackupSpec defines the desired state of Backup
properties:
BackupToNFS:
description: Represents the name of backup to NFS
type: string
clustname:
description: ClusterName represents the cluster name to backup
type: string
Expand All @@ -46,14 +49,14 @@ spec:
type: integer
hostname:
description: HostName represents the host for which to take backup
If is empty, is use leader HostName
type: string
image:
default: radondb/mysql57-sidecar:v2.2.0
description: To specify the image that will be used for sidecar container.
type: string
required:
- clustname
- hostname
type: object
status:
description: BackupStatus defines the observed state of Backup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,9 @@ spec:
description: Represents the name of the cluster restore from backup
path
type: string
restoreFromNFS:
description: Represents NFS ip address where cluster restore from.
type: string
xenonOpts:
default:
admitDefeatHearbeatCount: 5
Expand Down
5 changes: 4 additions & 1 deletion config/crd/bases/mysql.radondb.com_backups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ spec:
spec:
description: BackupSpec defines the desired state of Backup
properties:
BackupToNFS:
description: Represents the name of backup to NFS
type: string
clustname:
description: ClusterName represents the cluster name to backup
type: string
Expand All @@ -46,14 +49,14 @@ spec:
type: integer
hostname:
description: HostName represents the host for which to take backup
If is empty, is use leader HostName
type: string
image:
default: radondb/mysql57-sidecar:v2.2.0
description: To specify the image that will be used for sidecar container.
type: string
required:
- clustname
- hostname
type: object
status:
description: BackupStatus defines the observed state of Backup
Expand Down
3 changes: 3 additions & 0 deletions config/crd/bases/mysql.radondb.com_mysqlclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,9 @@ spec:
description: Represents the name of the cluster restore from backup
path
type: string
restoreFromNFS:
description: Represents NFS ip address where cluster restore from.
type: string
xenonOpts:
default:
admitDefeatHearbeatCount: 5
Expand Down
2 changes: 1 addition & 1 deletion config/samples/backup_secret.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
kind: Secret
apiVersion: v1
apiVersion: mysql.radondb.com/v1alpha1
metadata:
name: sample-backup-secret
namespace: default
Expand Down
2 changes: 2 additions & 0 deletions config/samples/mysql_v1alpha1_backup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ metadata:
spec:
# Add fields here
image: radondb/mysql-sidecar:latest
# hostname if empty, use the leader as hostname
hostname: sample-mysql-0
clustname: sample
# BackupToNFS: "IP of NFS server"
4 changes: 4 additions & 0 deletions config/samples/mysql_v1alpha1_mysqlcluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ spec:
# backupSecretName:

# if you want create mysqlcluster from S3, uncomment and fill the directory in S3 bucket below:
# such as restoreFrom: "backup_202241423817"
# restoreFrom:

# Restore from NFS, uncomment below and set the ip of NFS server
# such as restoreFromNFS: "10.233.55.172"
# restoreFromNFS:
mysqlOpts:
rootPassword: "RadonDB@123"
rootHost: localhost
Expand Down
32 changes: 32 additions & 0 deletions config/samples/nfs_rc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: nfs-server
spec:
replicas: 1
selector:
role: nfs-server
template:
metadata:
labels:
role: nfs-server
spec:
containers:
- name: nfs-server
image: gcr.azk8s.cn/google_containers/volume-nfs:0.8
ports:
- name: nfs
containerPort: 2049
- name: mountd
containerPort: 20048
- name: rpcbind
containerPort: 111
securityContext:
privileged: true
volumeMounts:
- mountPath: /exports
name: nfs-export-fast
volumes:
- name: nfs-export-fast
persistentVolumeClaim:
claimName: backup-pv-claim
14 changes: 14 additions & 0 deletions config/samples/nfs_server.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
kind: Service
apiVersion: v1
metadata:
name: nfs-server
spec:
ports:
- name: nfs
port: 2049
- name: mountd
port: 20048
- name: rpcbind
port: 111
selector:
role: nfs-server
11 changes: 11 additions & 0 deletions config/samples/pv-claim.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: backup-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 30Gi
33 changes: 33 additions & 0 deletions config/samples/pv-volume.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
name: manual
provisioner: kubernetes.io/no-provisioner
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
---

apiVersion: v1
kind: PersistentVolume
metadata:
name: backup-pv-volume
labels:
type: local
spec:
storageClassName: manual
# you can set affinity ,for example:
# nodeAffinity:
# required:
# nodeSelectorTerms:
# - matchExpressions:
# - key: kubernetes.io/hostname
# operator: In
# values:
# - node2
capacity:
storage: 40Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/backup"
64 changes: 64 additions & 0 deletions docs/deploy_backup_restore_nfs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# mysql-operator

## Quickstart for NFS backup
### Create NFS server
First create your PVC, such as "neosan1",
Or use local storage pvc, see `config/sample/pv-claim.yaml`
and `pv-volume.yaml` for more details.
Then create NFS server, such as "nfs-server",
```yaml
fill it to `config/samples/nfs_rc.yaml `
```yaml
...
volumes:
- name: nfs-export-fast
persistentVolumeClaim:
claimName: neosan1 // or backup-pv-claim
```
```shell
# create the nfs pod
kubectl apply -f config/samples/nfs_rc.yaml
# create the nfs service
kubectl apply -f config/samples/nfs_server.yaml
```
if create the nfs server successful, get the then:

## config `mysql_v1alpha1_backup.yaml ` and backup
Add field in `mysql_v1alpha1_backup.yaml ` as follow:
```yaml
BackupToNFS: "IP of NFS server"
```
use command as follow to backup
```shell
kubectl apply -f config/samples/mysql_v1alpha1_backup.yaml
```
> Notice: backup cr and mysqlcluster cr must be in the same namespace.
## Restore cluster from exist NFS backup
first, configure the `mysql_v1alpha1_cluster.yaml`, uncomment the `restoreFromNFS` field:
```yaml
....
restoreFrom: "sample_202196152239"
restoreFromNFS : 10.96.253.82
```
`sample_202196152239` is the nfs server backup path, change it to yours.
the `10.96.253.82` is the NFS server ip, change it to yours.

> Notice: you can find the `sample_202196152239` in the nfs_server pod, at `/exports` path
or find it in node `/mnt/backup` path if you use the local pesistent volume with `sample/pv-volume.yaml`.

use command as follow to create cluster from NFS server backup copy:

## build your own image
such as :
```
docker build -f Dockerfile.sidecar -t acekingke/sidecar:0.1 . && docker push acekingke/sidecar:0.1
docker build -t acekingke/controller:0.1 . && docker push acekingke/controller:0.1
```
you can replace acekingke/sidecar:0.1 with your own tag

## deploy your own manager
```shell
make manifests
make install
make deploy IMG=acekingke/controller:0.1 KUSTOMIZE=~/radondb-mysql-kubernetes/bin/kustomize
```
Loading

0 comments on commit 21e0621

Please sign in to comment.