mirror of
https://github.com/vmware-tanzu/velero.git
synced 2025-12-23 06:15:21 +00:00
Add option for privileged fs-backup pod
Signed-off-by: Scott Seago <sseago@redhat.com>
This commit is contained in:
1
changelogs/unreleased/9300-sseago
Normal file
1
changelogs/unreleased/9300-sseago
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Add option for privileged fs-backup pod
|
||||||
@@ -308,6 +308,8 @@ func (s *nodeAgentServer) run() {
|
|||||||
s.logger.Infof("Using customized backupPVC config %v", backupPVCConfig)
|
s.logger.Infof("Using customized backupPVC config %v", backupPVCConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
privilegedFsBackup := s.dataPathConfigs != nil && s.dataPathConfigs.PrivilegedFsBackup
|
||||||
|
|
||||||
podResources := corev1api.ResourceRequirements{}
|
podResources := corev1api.ResourceRequirements{}
|
||||||
if s.dataPathConfigs != nil && s.dataPathConfigs.PodResources != nil {
|
if s.dataPathConfigs != nil && s.dataPathConfigs.PodResources != nil {
|
||||||
if res, err := kube.ParseResourceRequirements(s.dataPathConfigs.PodResources.CPURequest, s.dataPathConfigs.PodResources.MemoryRequest, s.dataPathConfigs.PodResources.CPULimit, s.dataPathConfigs.PodResources.MemoryLimit); err != nil {
|
if res, err := kube.ParseResourceRequirements(s.dataPathConfigs.PodResources.CPURequest, s.dataPathConfigs.PodResources.MemoryRequest, s.dataPathConfigs.PodResources.CPULimit, s.dataPathConfigs.PodResources.MemoryLimit); err != nil {
|
||||||
@@ -327,12 +329,12 @@ func (s *nodeAgentServer) run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pvbReconciler := controller.NewPodVolumeBackupReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.metrics, s.logger, dataMovePriorityClass)
|
pvbReconciler := controller.NewPodVolumeBackupReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.metrics, s.logger, dataMovePriorityClass, privilegedFsBackup)
|
||||||
if err := pvbReconciler.SetupWithManager(s.mgr); err != nil {
|
if err := pvbReconciler.SetupWithManager(s.mgr); err != nil {
|
||||||
s.logger.Fatal(err, "unable to create controller", "controller", constant.ControllerPodVolumeBackup)
|
s.logger.Fatal(err, "unable to create controller", "controller", constant.ControllerPodVolumeBackup)
|
||||||
}
|
}
|
||||||
|
|
||||||
pvrReconciler := controller.NewPodVolumeRestoreReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.logger, dataMovePriorityClass)
|
pvrReconciler := controller.NewPodVolumeRestoreReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.logger, dataMovePriorityClass, privilegedFsBackup)
|
||||||
if err := pvrReconciler.SetupWithManager(s.mgr); err != nil {
|
if err := pvrReconciler.SetupWithManager(s.mgr); err != nil {
|
||||||
s.logger.WithError(err).Fatal("Unable to create the pod volume restore controller")
|
s.logger.WithError(err).Fatal("Unable to create the pod volume restore controller")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const (
|
|||||||
// NewPodVolumeBackupReconciler creates the PodVolumeBackupReconciler instance
|
// NewPodVolumeBackupReconciler creates the PodVolumeBackupReconciler instance
|
||||||
func NewPodVolumeBackupReconciler(client client.Client, mgr manager.Manager, kubeClient kubernetes.Interface, dataPathMgr *datapath.Manager,
|
func NewPodVolumeBackupReconciler(client client.Client, mgr manager.Manager, kubeClient kubernetes.Interface, dataPathMgr *datapath.Manager,
|
||||||
counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, podResources corev1api.ResourceRequirements,
|
counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, podResources corev1api.ResourceRequirements,
|
||||||
metrics *metrics.ServerMetrics, logger logrus.FieldLogger, dataMovePriorityClass string) *PodVolumeBackupReconciler {
|
metrics *metrics.ServerMetrics, logger logrus.FieldLogger, dataMovePriorityClass string, privileged bool) *PodVolumeBackupReconciler {
|
||||||
return &PodVolumeBackupReconciler{
|
return &PodVolumeBackupReconciler{
|
||||||
client: client,
|
client: client,
|
||||||
mgr: mgr,
|
mgr: mgr,
|
||||||
@@ -77,6 +77,7 @@ func NewPodVolumeBackupReconciler(client client.Client, mgr manager.Manager, kub
|
|||||||
exposer: exposer.NewPodVolumeExposer(kubeClient, logger),
|
exposer: exposer.NewPodVolumeExposer(kubeClient, logger),
|
||||||
cancelledPVB: make(map[string]time.Time),
|
cancelledPVB: make(map[string]time.Time),
|
||||||
dataMovePriorityClass: dataMovePriorityClass,
|
dataMovePriorityClass: dataMovePriorityClass,
|
||||||
|
privileged: privileged,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +98,7 @@ type PodVolumeBackupReconciler struct {
|
|||||||
resourceTimeout time.Duration
|
resourceTimeout time.Duration
|
||||||
cancelledPVB map[string]time.Time
|
cancelledPVB map[string]time.Time
|
||||||
dataMovePriorityClass string
|
dataMovePriorityClass string
|
||||||
|
privileged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:rbac:groups=velero.io,resources=podvolumebackups,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=velero.io,resources=podvolumebackups,verbs=get;list;watch;create;update;patch;delete
|
||||||
@@ -837,6 +839,7 @@ func (r *PodVolumeBackupReconciler) setupExposeParam(pvb *velerov1api.PodVolumeB
|
|||||||
Resources: r.podResources,
|
Resources: r.podResources,
|
||||||
// Priority class name for the data mover pod, retrieved from node-agent-configmap
|
// Priority class name for the data mover pod, retrieved from node-agent-configmap
|
||||||
PriorityClassName: r.dataMovePriorityClass,
|
PriorityClassName: r.dataMovePriorityClass,
|
||||||
|
Privileged: r.privileged,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ func initPVBReconcilerWithError(needError ...error) (*PodVolumeBackupReconciler,
|
|||||||
corev1api.ResourceRequirements{},
|
corev1api.ResourceRequirements{},
|
||||||
metrics.NewServerMetrics(),
|
metrics.NewServerMetrics(),
|
||||||
velerotest.NewLogger(),
|
velerotest.NewLogger(),
|
||||||
"", // dataMovePriorityClass
|
"", // dataMovePriorityClass
|
||||||
|
false, // privileged
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ import (
|
|||||||
|
|
||||||
func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, kubeClient kubernetes.Interface, dataPathMgr *datapath.Manager,
|
func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, kubeClient kubernetes.Interface, dataPathMgr *datapath.Manager,
|
||||||
counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, podResources corev1api.ResourceRequirements,
|
counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, podResources corev1api.ResourceRequirements,
|
||||||
logger logrus.FieldLogger, dataMovePriorityClass string) *PodVolumeRestoreReconciler {
|
logger logrus.FieldLogger, dataMovePriorityClass string, privileged bool) *PodVolumeRestoreReconciler {
|
||||||
return &PodVolumeRestoreReconciler{
|
return &PodVolumeRestoreReconciler{
|
||||||
client: client,
|
client: client,
|
||||||
mgr: mgr,
|
mgr: mgr,
|
||||||
@@ -72,6 +72,7 @@ func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, ku
|
|||||||
exposer: exposer.NewPodVolumeExposer(kubeClient, logger),
|
exposer: exposer.NewPodVolumeExposer(kubeClient, logger),
|
||||||
cancelledPVR: make(map[string]time.Time),
|
cancelledPVR: make(map[string]time.Time),
|
||||||
dataMovePriorityClass: dataMovePriorityClass,
|
dataMovePriorityClass: dataMovePriorityClass,
|
||||||
|
privileged: privileged,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ type PodVolumeRestoreReconciler struct {
|
|||||||
resourceTimeout time.Duration
|
resourceTimeout time.Duration
|
||||||
cancelledPVR map[string]time.Time
|
cancelledPVR map[string]time.Time
|
||||||
dataMovePriorityClass string
|
dataMovePriorityClass string
|
||||||
|
privileged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:rbac:groups=velero.io,resources=podvolumerestores,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=velero.io,resources=podvolumerestores,verbs=get;list;watch;create;update;patch;delete
|
||||||
@@ -896,6 +898,7 @@ func (r *PodVolumeRestoreReconciler) setupExposeParam(pvr *velerov1api.PodVolume
|
|||||||
Resources: r.podResources,
|
Resources: r.podResources,
|
||||||
// Priority class name for the data mover pod, retrieved from node-agent-configmap
|
// Priority class name for the data mover pod, retrieved from node-agent-configmap
|
||||||
PriorityClassName: r.dataMovePriorityClass,
|
PriorityClassName: r.dataMovePriorityClass,
|
||||||
|
Privileged: r.privileged,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -617,7 +617,7 @@ func initPodVolumeRestoreReconcilerWithError(objects []runtime.Object, cliObj []
|
|||||||
|
|
||||||
dataPathMgr := datapath.NewManager(1)
|
dataPathMgr := datapath.NewManager(1)
|
||||||
|
|
||||||
return NewPodVolumeRestoreReconciler(fakeClient, nil, fakeKubeClient, dataPathMgr, nil, "test-node", time.Minute*5, time.Minute, corev1api.ResourceRequirements{}, velerotest.NewLogger(), ""), nil
|
return NewPodVolumeRestoreReconciler(fakeClient, nil, fakeKubeClient, dataPathMgr, nil, "test-node", time.Minute*5, time.Minute, corev1api.ResourceRequirements{}, velerotest.NewLogger(), "", false), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPodVolumeRestoreReconcile(t *testing.T) {
|
func TestPodVolumeRestoreReconcile(t *testing.T) {
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ type PodVolumeExposeParam struct {
|
|||||||
|
|
||||||
// PriorityClassName is the priority class name for the data mover pod
|
// PriorityClassName is the priority class name for the data mover pod
|
||||||
PriorityClassName string
|
PriorityClassName string
|
||||||
|
|
||||||
|
// Privileged indicates whether to create the pod with a privileged container
|
||||||
|
Privileged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodVolumeExposer is the interfaces for a pod volume exposer
|
// PodVolumeExposer is the interfaces for a pod volume exposer
|
||||||
@@ -153,7 +156,7 @@ func (e *podVolumeExposer) Expose(ctx context.Context, ownerObject corev1api.Obj
|
|||||||
|
|
||||||
curLog.WithField("path", path).Infof("Host path is retrieved for pod %s, volume %s", param.ClientPodName, param.ClientPodVolume)
|
curLog.WithField("path", path).Infof("Host path is retrieved for pod %s, volume %s", param.ClientPodName, param.ClientPodVolume)
|
||||||
|
|
||||||
hostingPod, err := e.createHostingPod(ctx, ownerObject, param.Type, path.ByPath, param.OperationTimeout, param.HostingPodLabels, param.HostingPodAnnotations, param.HostingPodTolerations, pod.Spec.NodeName, param.Resources, nodeOS, param.PriorityClassName)
|
hostingPod, err := e.createHostingPod(ctx, ownerObject, param.Type, path.ByPath, param.OperationTimeout, param.HostingPodLabels, param.HostingPodAnnotations, param.HostingPodTolerations, pod.Spec.NodeName, param.Resources, nodeOS, param.PriorityClassName, param.Privileged)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error to create hosting pod")
|
return errors.Wrapf(err, "error to create hosting pod")
|
||||||
}
|
}
|
||||||
@@ -269,7 +272,7 @@ func (e *podVolumeExposer) CleanUp(ctx context.Context, ownerObject corev1api.Ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject corev1api.ObjectReference, exposeType string, hostPath string,
|
func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject corev1api.ObjectReference, exposeType string, hostPath string,
|
||||||
operationTimeout time.Duration, label map[string]string, annotation map[string]string, toleration []corev1api.Toleration, selectedNode string, resources corev1api.ResourceRequirements, nodeOS string, priorityClassName string) (*corev1api.Pod, error) {
|
operationTimeout time.Duration, label map[string]string, annotation map[string]string, toleration []corev1api.Toleration, selectedNode string, resources corev1api.ResourceRequirements, nodeOS string, priorityClassName string, privileged bool) (*corev1api.Pod, error) {
|
||||||
hostingPodName := ownerObject.Name
|
hostingPodName := ownerObject.Name
|
||||||
|
|
||||||
containerName := string(ownerObject.UID)
|
containerName := string(ownerObject.UID)
|
||||||
@@ -327,6 +330,7 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor
|
|||||||
args = append(args, podInfo.logLevelArgs...)
|
args = append(args, podInfo.logLevelArgs...)
|
||||||
|
|
||||||
var securityCtx *corev1api.PodSecurityContext
|
var securityCtx *corev1api.PodSecurityContext
|
||||||
|
var containerSecurityCtx *corev1api.SecurityContext
|
||||||
nodeSelector := map[string]string{}
|
nodeSelector := map[string]string{}
|
||||||
podOS := corev1api.PodOS{}
|
podOS := corev1api.PodOS{}
|
||||||
if nodeOS == kube.NodeOSWindows {
|
if nodeOS == kube.NodeOSWindows {
|
||||||
@@ -359,6 +363,9 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor
|
|||||||
securityCtx = &corev1api.PodSecurityContext{
|
securityCtx = &corev1api.PodSecurityContext{
|
||||||
RunAsUser: &userID,
|
RunAsUser: &userID,
|
||||||
}
|
}
|
||||||
|
containerSecurityCtx = &corev1api.SecurityContext{
|
||||||
|
Privileged: &privileged,
|
||||||
|
}
|
||||||
|
|
||||||
nodeSelector[kube.NodeOSLabel] = kube.NodeOSLinux
|
nodeSelector[kube.NodeOSLabel] = kube.NodeOSLinux
|
||||||
podOS.Name = kube.NodeOSLinux
|
podOS.Name = kube.NodeOSLinux
|
||||||
@@ -394,6 +401,7 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor
|
|||||||
Env: podInfo.env,
|
Env: podInfo.env,
|
||||||
EnvFrom: podInfo.envFrom,
|
EnvFrom: podInfo.envFrom,
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
|
SecurityContext: containerSecurityCtx,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PriorityClassName: priorityClassName,
|
PriorityClassName: priorityClassName,
|
||||||
|
|||||||
@@ -190,6 +190,29 @@ func TestPodVolumeExpose(t *testing.T) {
|
|||||||
return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil
|
return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "succeed with privileged pod",
|
||||||
|
ownerBackup: backup,
|
||||||
|
exposeParam: PodVolumeExposeParam{
|
||||||
|
ClientNamespace: "fake-ns",
|
||||||
|
ClientPodName: "fake-client-pod",
|
||||||
|
ClientPodVolume: "fake-client-volume",
|
||||||
|
Privileged: true,
|
||||||
|
},
|
||||||
|
kubeClientObj: []runtime.Object{
|
||||||
|
podWithNode,
|
||||||
|
node,
|
||||||
|
daemonSet,
|
||||||
|
},
|
||||||
|
funcGetPodVolumeHostPath: func(context.Context, *corev1api.Pod, string, kubernetes.Interface, filesystem.Interface, logrus.FieldLogger) (datapath.AccessPoint, error) {
|
||||||
|
return datapath.AccessPoint{
|
||||||
|
ByPath: "/host_pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
funcExtractPodVolumeHostPath: func(context.Context, string, kubernetes.Interface, string, string) (string, error) {
|
||||||
|
return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|||||||
@@ -84,4 +84,7 @@ type NodeAgentConfigs struct {
|
|||||||
|
|
||||||
// PriorityClassName is the priority class name for data mover pods created by the node agent
|
// PriorityClassName is the priority class name for data mover pods created by the node agent
|
||||||
PriorityClassName string `json:"priorityClassName,omitempty"`
|
PriorityClassName string `json:"priorityClassName,omitempty"`
|
||||||
|
|
||||||
|
// PrivilegedFsBackup determines whether to create fs-backup pods as privileged pods
|
||||||
|
PrivilegedFsBackup bool `json:"privilegedFsBackup,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ By default, `velero install` does not install Velero's [File System Backup][3].
|
|||||||
|
|
||||||
If you've already run `velero install` without the `--use-node-agent` flag, you can run the same command again, including the `--use-node-agent` flag, to add the file system backup to your existing install.
|
If you've already run `velero install` without the `--use-node-agent` flag, you can run the same command again, including the `--use-node-agent` flag, to add the file system backup to your existing install.
|
||||||
|
|
||||||
|
Note that for some use cases (including installation on OpenShift clusters) the fs-backup pods must run in a Privileged security context. This is configured through the node-agent configmap (see below) by setting `privilegedFsBackup` to `true` in the configmap.
|
||||||
|
|
||||||
## CSI Snapshot Data Movement
|
## CSI Snapshot Data Movement
|
||||||
|
|
||||||
Velero node-agent is required by [CSI Snapshot Data Movement][12] when Velero built-in data mover is used. By default, `velero install` does not install Velero's node-agent. To enable it, specify the `--use-node-agent` flag.
|
Velero node-agent is required by [CSI Snapshot Data Movement][12] when Velero built-in data mover is used. By default, `velero install` does not install Velero's node-agent. To enable it, specify the `--use-node-agent` flag.
|
||||||
|
|||||||
Reference in New Issue
Block a user