Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make PipeCD control plane support plugin-arched piped #5252

Open
17 of 51 tasks
ffjlabo opened this issue Oct 4, 2024 · 17 comments
Open
17 of 51 tasks

Make PipeCD control plane support plugin-arched piped #5252

ffjlabo opened this issue Oct 4, 2024 · 17 comments
Labels

Comments

@ffjlabo
Copy link
Member

ffjlabo commented Oct 4, 2024

What would you like to be added:

This issue tracks the progress for deprecating Platform Provider and Kind toward piped plugin architecture in pipedv1.

The purpose is to manage application kind and platform providers on the PipeCD plugin side in the future.

Considering the impact on users, pay attention to the following points:

  • In Pipedv1, platform providers, kind remain on the data and do not create logic with them. Use the value you define instead.
  • minify the migration for users.

current update process

  1. Update data for the pipedv1
  • Add the label kind based on the current Application Kind to the Application.
  • Add deployTarget based on the current Application Platform Provider to the Application.
  1. update to pipedv1 (users can use existing application at the time)

Details (under planning)

For Platform Provider

Instead of Platform Provider, we plan to introduce the config for the plugin and define deployTargets.

piped config

apiVersion: pipecd.dev/v1beta1
kind: Piped
spec:
...
  plugin:
    - name: k8s_plugin
      port: 8081
      deployTargets:
        - name: dev
          labels: 
            env: dev
          config: # depends on plugins
            masterURL: http://cluster-dev
            kubeConfigPath: ./kubeconfig-dev
type PipedDeployTarget struct {
	Name   string                     `json:"name"`
	Labels map[string]string          `json:"labels,omitempty"`
	Config json.RawMessage            `json:"config"`
}

We also plan to deploy the app to multiple targets at once in a multicluster feature for k8s.
So, we define DeployTargets as an array in Application and Deployment.

Application

message Application {
    reserved 3;
    ...
    // TODO: Add validation for this field.
    string platform_provider = 15;
    // 
    repeated string deploy_targets = 16;
    ...
}

Deployment

message Deployment {
    reserved 4;
    ...
    // The name of platform provider where to deploy this application.
    // This must be one of the provider names registered in the piped.
    string platform_provider = 11;
    
    repeated string deploy_targets = 12;
}

For the backward compatibility

Before updating the piped, users should migrate the current data on DB.

Former idea

During the migration, there might be both platform providers and deploy targets in the piped config.
So we need to convert the platform providers to deploy targets internally.

Refer the Platform Provider or Deploy Target

  • If the ApplicationKind is Application, just use DeployTarget
  • If the ApplicationKind is old one, convert PlatformProvider to DeployTarget
func (s *PipedSpec) FindDeployTarget(name string, t model.ApplicationKind) (*PipedDeployTarget, bool) {
	// First, check the application is supported by the plugin architecture. It means that the kind is set to "Application".
	// If not, the deploy target is the platform provider.
	// For backward compatibility, the deploy target is the platform provider.
	if t != model.ApplicationKind_APPLICATION {
		p, found := s.FindPlatformProvider(name, t)
		if !found {
			return &PipedDeployTarget{}, false
		}
		return &PipedDeployTarget{
				Name:   p.Name,
				Labels: p.Labels,
				Config: p.Config,
			}, true
	}

	// If the application is supported by the plugin architecture, the deploy target is the deploy target.
	for _, dt := range s.DeployTargets {
		if dt.Name == name {
			return dt, true
		}
	}

	return &PipedDeployTarget{}, false
}

For Kind

Instead of Kind, we plan to introduce the label to represent the application kind.

apiVersion: pipecd.dev/v1beta1
kind: Application
metadata:
  labels:
    kind: KUBERNETES # <- like this
spec:
  name: myApp

For the builtin plugins, we define 5 labels as string.

  • KUBERNETES
  • ECS
  • LAMBDA
  • CLOUDRUN
  • TERRAFORM

For the backward compatibility

Before updating the piped, users should migrate the current data on DB.

Former idea

We need to support both before and after creating plugin architecture for now.
So, I propose the way to decide the application kind like this.

  • Define APPLICATION as ApplicationKind
  • Add new method to decide the actual kind for Application and Deployment.
enum ApplicationKind {
    KUBERNETES = 0;
    TERRAFORM = 1;
    LAMBDA = 3;
    CLOUDRUN = 4;
    ECS = 5;
    APPLICATION = 6; <- new! 
}
func (a * Application) GetKind() string {
	// First, check the application is supported by the plugin architecture. It means that the kind is set to "Application".
	// If so, return the kind from the labels.
	if a.Kind == ApplicationKind_Application {
		return a.Labels["kind"]
	}

	// For backward compatibility, return the kind as string
	return a.Kind.String()
}
func (d *Deployment) GetKind() string {
	// First, check the application is supported by the plugin architecture. It means that the kind is set to "Application".
	// If so, return the kind from the labels.
	if d.Kind == ApplicationKind_Application {
		return d.Labels["kind"]
	}

	// For backward compatibility, return the kind as string
	return d.Kind.String()
}

TODO

Firstly, I listed the target features to require some modifications.
We need to further investigation to decide the way to fix.

investigation

implementation

Why is this needed:

@ffjlabo ffjlabo added the epic label Oct 4, 2024
@t-kikuc t-kikuc added this to v0.50.0 Oct 4, 2024
@ffjlabo ffjlabo moved this to In Progress in v0.50.0 Oct 4, 2024
@khanhtc1202 khanhtc1202 changed the title Deprecate Platform Provider and Kind Make PipeCD control plane support plugin-arched piped Oct 7, 2024
@ffjlabo
Copy link
Member Author

ffjlabo commented Oct 22, 2024

Platform Provider; Livestatestore

The purpose of the component

  • Livestatestore stores the actual resource state for each app belonging to the platform.
  • Livestatestore is almost all for the platform-specific things such as detector, livestatereporter, and executor.

Modification idea

  • Put it on the plugin side
  • Store the app resource state per deployTarget
  • Introduce an aggregation layer to get multiple resource states by appID across the multiple deployTarget, In case of the multiple deployTarget per app,

@ffjlabo
Copy link
Member Author

ffjlabo commented Oct 23, 2024

Platform Provider; Livestatereporter

The purpose of the component

  • Livestatereporter sends the application state to the Control Plane
  • Currently, There are livestatereporters for each platform provider

Modification idea

  • piped side
    • Every minute, piped does below
      • List apps by plugin name
      • Get the app livestate from the plugin via gRPC call e.g. GetLivestate(app)
      • Send them to the Control Plane
  • plugin side
    • Get the livestates grouped by deployTarget from livestatestore and return to the piped.
  • Control Plane side
    • Receive and store the livestates

Concern

  • There is a different way to update livestate on Control Plane between k8s and other platforms.
  • I think this is mainly for the speed to show it on the UI.
  • It would be nice to add an option like livestateFlushInterval to change them by users.

@ffjlabo
Copy link
Member Author

ffjlabo commented Oct 23, 2024

Platform Provider; Detector

The purpose of the component

  • Detector check and send application sync state to the Control Plane
  • Currently, There are detectors for each platform provider

Modification idea

  • piped side
    • Every minute, piped does below
      • List apps by plugin name
      • Get the application sync states from the plugin via gRPC call e.g. Detect(app)
      • Send them to the Control Plane
  • plugin side
    • Get the liveManifests grouped by deployTarget from livestatestore
    • Calculate the diff between live ones and git ones.
    • Make the app sync state referencing the diff and send it to the Control Plane

Concern

  • There is a different interval to execute the detectors between terraform and other platforms.
  • It would be nice to add an option like detectInterval to change them by users.

@ffjlabo
Copy link
Member Author

ffjlabo commented Oct 29, 2024

Platform Provider; Plan Preview

The purpose of the component

  • Make Plan Preview results ( the diffs, the plan result) for the apps which have some changes

Modification idea

  • piped side
    • List commands for Plan Preview from the Control Plane by commandCheckInterval
    • Every command, list apps managed by the piped using repoID related to the commands
    • Every app, extract the apps that have some diffs
    • Get the PlanPreviewResult from the plugin via gRPC call e.g. BuildPlanPreviewResult(app)
    • Send all results of the apps to the ControlPlane with a command
  • plugin side
    • Get the manifests on the latest commit
    • Get the manifests on the commit used by the latest Deployment
    • Make a PlanPreviewResult using the diffs between the above

Concern

  • It might be good to extract the apps that have some diffs on the plugin side

@ffjlabo
Copy link
Member Author

ffjlabo commented Oct 31, 2024

Platform Provider; Metrics

The metrics deployment_status is affected because it has the label platform_provider.
https://github.com/pipe-cd/pipecd/blob/548a804d344d7c5faa70bcb6bd0889aa2a9269af/pkg/app/piped/controller/controllermetrics/metrics.go#L23C1-L40C2

deployment_status{application_id="xxxxxxxx",application_kind="KUBERNETES",application_name="simple",deployment="xxxxxxx",instance="127.0.0.1:9085",job="pipecd-ops",launcher_version="v0.49.2",pipecd_component="piped",piped="xxxxx",piped_version="v0.49.2",platform_provider="kubernetes",project="test",status="DEPLOYMENT_CANCELLED"}

Modification idea
There are two ideas.

  1. Create new metrics like plugin_deployment_status
  2. Add a new label deployTarget to the deployment_status

Concern

For idea 1.

  • pros
    • Completely create it based on the new data model
  • cons
    • We should observe both of the metrics (e.g. create two views for both on grafana)
    • It is hard to check the deployment status from piped < v1 to pipedv1 because they are different metrics.

For idea 2.

  • pros
    • We can continue to use it.
  • cons
    • We have to modify the query to check both of them like deployment_status{platform_provider="kubernetes"} or deployment_status{deployTarget="kubernetes"}

@ffjlabo
Copy link
Member Author

ffjlabo commented Oct 31, 2024

Kind; appconfigreporter

The purpose of the component

  • Detect and update the app config when it has some changes.
  • Send the changed app info to the Control Plane, then the Control Plane updates the app with it.
  • It has logic for checking the difference between the app info in the current app config and the already registered app.
    • if appInfo.Kind != app.Kind {
      r.logger.Warn("kind in application config has been changed which isn't allowed",
      zap.String("app-id", app.Id),
      zap.String("repo-id", app.GitPath.Repo.Id),
      zap.String("config-file-path", app.GitPath.GetApplicationConfigFilePath()),
      )
      }
    • Especially, compare values in model.ApplicationInfo and corresponding in the model.Application (e.g. Kind, Name...)

Modification idea

  • Compare model.Application.Labels["kind"] instead of model.Application.Kind

Concern

  • Nothing for now

@ffjlabo
Copy link
Member Author

ffjlabo commented Oct 31, 2024

Kind; event watcher

The purpose of the component

  • Event Watcher handles events according to the rule set in the app config.
  • When it loads the app config, it calls config.LoadAplication(repoPath, configRelPath string, appKind model.ApplicationKind)
    appCfg, err := config.LoadApplication(repo.GetPath(), app.GitPath.GetApplicationConfigFilePath(), app.Kind)

Modification Idea

  • Modify config.LoadApplication(repoPath, configRelPath string, appKind model.ApplicationKind) to LoadApplication(repoPath, configRelPath string, appKind string)
  • Use model.Application.Labels["kind"] instead of model.Application.Kind

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 5, 2024

Kind; livestatereporter

The purpose of the component

Modification Idea

  • Add plugin_kind to the model.ApplicationLiveStateSnapshot
  • Use model.Application.Labels["kind"] instead of model.Application.Kind
message ApplicationLiveStateSnapshot {
    reserved 2;
    ...
    ApplicationKind kind = 5 [(validate.rules).enum.defined_only = true];
    ...
    string plugin_kind = 16;
}

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 5, 2024

Kind; detector

The purpose of the component

  • Detector check and send application sync state to the Control Plane
  • Currently, There are detectors for each platform provider
  • It has logic for checking

Modification idea

  • Use model.Application.Labels["kind"] instead of model.Application.Kind

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 5, 2024

Kind; notifier

The purpose of the component

  • Notifier notifies the deployment progress to the slack
  • piped uses kind to show deployment info on the slack message
    {"Kind", strings.ToLower(app.Kind.String()), true},

Modification idea

  • Use model.Application.Labels["kind"] instead of model.Application.Kind

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 5, 2024

Kind; Plan preview

The purpose of the component

Modification idea

  • For 1, the actual logic will be implemented in the plugin side.
  • For 2, we don't need to determine by Kind in plugin architecture. Instead of this, we should determine which plugin.
  • For 3, just use labels["kind"]

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 15, 2024

Kind; trigger

Modification idea

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 19, 2024

Kind; server

The purpose of the component

Modification idea

  • just pass kind to the application same as current one. After pipedv1, we use Application as kind.

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 20, 2024

Kind; Metrics

The purpose of the component
The metrics deployment_status is affected because it has the label application_kind.
https://github.com/pipe-cd/pipecd/blob/548a804d344d7c5faa70bcb6bd0889aa2a9269af/pkg/app/piped/controller/controllermetrics/metrics.go#L23C1-L40C2

deployment_status{application_id="xxxxxxxx",application_kind="KUBERNETES",application_name="simple",deployment="xxxxxxx",instance="127.0.0.1:9085",job="pipecd-ops",launcher_version="v0.49.2",pipecd_component="piped",piped="xxxxx",piped_version="v0.49.2",platform_provider="kubernetes",project="test",status="DEPLOYMENT_CANCELLED"}

Modification idea

  • Use model.Application.Labels["kind"] instead of model.Application.Kind

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 20, 2024

Kind; planner

The purpose of the component

Modification idea

  • Use model.Application.Labels["kind"] instead of model.Application.Kind
  • For 2, We don't need to determine by Kind in plugin architecture. Instead of this, we should determine which plugin is used.
  • For 3, same way as for 1.

@ffjlabo
Copy link
Member Author

ffjlabo commented Nov 20, 2024

Kind; scheduler

The purpose of the component

Modification idea

  • Use model.Application.Labels["kind"] instead of model.Application.Kind
  • For 2. same as for 1
  • For 3. We don't need to determine by Kind in plugin architecture. Instead of this, we should determine which plugin is used.
  • For 4. create HasDeployTargets instead of the HasPlatformprvoders

@khanhtc1202
Copy link
Member

khanhtc1202 commented Nov 21, 2024

PlatformProvider; UI

Purpose

Mostly related to 2 model applications and deployment

Used in

  • API call AddApplication, UpdateApplication
  • For showing in Application, Deployment detail page

The source fetched to used in the drawer is come from the piped configuration

https://github.com/pipe-cd/pipecd/blob/master/web/src/components/application-form/index.tsx#L58-L80

Modification idea

  • Keep it as in the application and deployment model
  • Also, keep the configuration and parser for pipedv0 config the same as it is (no UI affected around that fetch)
  • Make a new Add Application form/suggestion form that doesn't show any platform provider-related information

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Status: In Progress
Development

No branches or pull requests

2 participants