github.com/GoogleContainerTools/skaffold/v2@v2.13.2/docs-v2/design_proposals/new-render-and-deploy.md (about)

     1  # New Skaffold Render and Deploy (v2)
     2  
     3  * Author(s): [Yuwen Ma](https://github.com/yuwenma)
     4  * Design Shepherd: 
     5  	- [Vic Iglesias](https://github.com/viglesiasce)
     6  	- [Tejal Desai](https://github.com/tejal29)
     7  	- [Nick Kubala](https://github.com/nkubala)
     8  
     9  * Last Updated: 2021-05-07
    10  * Status: Approved/ Under implementation
    11  
    12  ## Glossary
    13  
    14  #### DRY configuration 
    15  
    16  Raw application configuration. 
    17  
    18  It means the configuration may use variants or base/overlays (kustomize structured layout) but not extended and can’t be understood by the cluster directly. The raw config is not validated or passed through any validation or other operation checks yet.
    19  
    20  #### WET configuration
    21  
    22  Manipulated application configuration.
    23  
    24  It has been flattened (from the DRY structure) and processed through a series of validation, generation and transformation operations and is a pure kubernetes resource and can be applied to the cluster directly.
    25  
    26  ## Objectives
    27  
    28  `skaffold` v2 is aimed at redesigning the skaffold workflow to decouple these two orthogonal concerns:
    29  
    30  1. Hydration (aka “rendering”) of configuration: [A DRY configuration](#DRY-configuration) is transformed, generated, and validated into [WET configs](#WET-configuration).
    31  
    32  2. Deployment (aka “apply”) of configuration: The WET configuration is applied to the K8S control plane.
    33  
    34  This `skaffold` v2 will use [`kpt`](https://github.com/GoogleContainerTools/kpt), which provides the canonical API(s) and toolchain for configuration packaging, hydration, and deployment, to enable the `skaffold` config generation, transformation and validation in a new *"render"* stage and replace the `skaffold` "deploy" stage with more accurate pruning.
    35  
    36  ## Background
    37  
    38  ### An overview of the skaffold workflow
    39  
    40  `skaffold`, as a centralized tool for application’s local development as well as CI/CD workflow, leverages `kubectl`, `kustomize`, `helm` or/and `kpt` for config management and deployment. The workflow is composed of a series of steps as below.
    41  
    42  ![Basic Workflow](images/basic-workflow.png)
    43  
    44  Users are expected to configure one “deployer” in the skaffold.yaml deploy section. “Deployer” refers to the tools used to manage and deploy the configurations. Currently skaffold supports 4 "deployers": `kpt`, `kustomize`, `helm`, `kubectl`. Below table presents the main commands running in each step when a certain deployer is chosen (trivial flags and options are ignored). 
    45  
    46  ![Deploy Operation](images/deploy-operation.png)
    47  ![Deployers](images/deployer-enabled-ops.png)
    48  
    49  ### Problems
    50  
    51  From the above table and some user feedback (e.g. [3905](https://github.com/GoogleContainerTools/skaffold/issues/3905) [4856](https://github.com/GoogleContainerTools/skaffold/issues/4856) [4356](https://github.com/GoogleContainerTools/skaffold/issues/4356), we can summarize the skaffold deployment issues as below: 
    52  
    53  #### [User facing] Confusing scope of “deployer” 
    54  
    55  From the above table, there’s a misalignment between the "deployer" name and the tool’s actual "deployment" functionality. 
    56  
    57  For instance, `kustomize` "deployer" has no deployment operations (it relies on `kubectl` to deploy), but it is called a "deployer"; The `kustomize` CLI does have config validation functionalities (via `kustomize config`), but the `kustomize` "deployer" has a no-op in the validation stage (Step 3). This "deployer" behavior confuses customers who understand `kustomize` and want to use `kustomize` in `skaffold`. 
    58  
    59  #### [User facing] Unexpected `skaffold` usage compound
    60  
    61  Though `skaffold` allows users to use different "deployers" together in a single workflow, a mixed usage of "deployers" normally means users are seeking workarounds to fill in the gaps due to the differentiation of the deployers’ scope and design principle (`kustomize` does not do in-place file changes and has no real "deploy" feature, `kubectl` deploys without good handling on prune, `helm` is package management tool and is imperative). Mixing the deployers under the hood in the deploy section gives the *wrong* signals that:
    62  
    63  - the deployers should be used as a mix. This will exacerbate each deployer’s known problems and make the skaffold more brittle.  
    64  - `skaffold` should handle the issues caused by the conflicts/misalignment among the "deployers".
    65  
    66  #### Limitations of current kpt deployer
    67  
    68  `skaffold` has [a kpt "deployer"](https://skaffold.dev/docs/references/yaml/#deploy-kpt) which can support basic declarative config validation and hydration.  This kpt deployer (stable version) has been released 2020 Dec, designed and implementated based on kpt version v0.34.0, which version does not have the declarative hydration in Kptfile file (new features in the [kpt v1 release](https://github.com/GoogleContainerTools/kpt/releases)).
    69  
    70  Thus,  the current skaffold kpt "deployer" has the following limitations:
    71  
    72  1. `kpt` deployer defines its own `kpt fn` stdin/stdout pipe to build up a validation pipeline and will not be compatible with `kpt` v1.
    73  Since the `kpt` deployer wraps the `kpt fn` pipeline inside the `skaffold`, failovers may not always be handled properly.  
    74  2. Skaffold deployers has no config resource path DAG detection, which will be properly handled by kpt v1.
    75  3. `kpt` deployer unifies kustomize into the kpt pipeline by switching the kyaml “ResourceList” to k8s resource and switching back after running kustomize build. These extra steps are not declarative native and sacrifices the flexibility of declarative config management (e.g. the order of the hydration in a pipeline is hard-coded).
    76  4. `kpt` deployer adds some additional steps to handle the kpt version incompatibility issues. E.g. both config.kubernetes.io/function and config.k8s.io/function annotations are supported, network flag is required to be configured in both skaffold.yaml and the declarative kpt function file, resources with config.kubernetes.io/local-config annotation is removed from sinkDir resource. 
    77  5. `kpt` deployer does not have a package management solution for skaffold.
    78  
    79  ## Proposal
    80  
    81  To obtain the Objectives and to fix the issues listed in the background, we propose the following design:
    82  
    83  Create a new **rendering** functionality to manage the configuration hydration. This "rendering" splits the hydration functionality from the existing "deployment" step and is configurable via a new "render" section in the `skaffold.yaml`. Both rendering and deployment fully relies on `kpt` as the *backbone*:
    84  
    85  - Leverage the kpt definition to define "transformation" and "validation" operations in `skaffold.yaml`.
    86  - Run each operation declarative in the `kpt` managed container runtime. 
    87  - Support package management through `kpt` package and declarative setters.
    88  - kpt launches together with skaffold as a builtin tool.
    89  - Deprecate the `helm` operation with the `kpt` "helm-inflator" image.
    90  - Deprecate the kustomize operation with the kpt `kustomize` image, and unify the `kpt` and `kustomize` operations into the `kpt` declarative pipeline.
    91  - Strengthen the "deploy" functionality (or step) by removing the existing hydration operation (e.g. kustomize build) and using `kpt` to apply the config to the cluster (e.g. no deployers are specified).  
    92  
    93  
    94  ## Detailed Design
    95  
    96  The new skaffold *render* uses the `kpt` ["kustomize"](https://github.com/GoogleContainerTools/kpt/issues/1447) function and "helm-inflator" function in lieu of `kustomize` and `helm`. So as `kustomize` resource and `helm` charts can fit into the `kpt` hydration and work together with other kpt validation and mutation functions in a pipeline.
    97  
    98  The new skaffold *deploy* only focuses on WET (See glossary) configurations and uses `kpt live` to deploy the config to the cluster. Here, `kpt` uses ResourceGroup and three-way merge pruning, so it is guaranteed the applied configs are accurate and reliable.
    99  
   100  ### An overview of the scope and internal operation changes
   101  
   102  ![Command Life Cycle](images/cmd-lifecycle.png)
   103  
   104  ### New "render"
   105  
   106  Add a new render (has decided to name to `.manifests`, the following graphs still using ".render") in the `skaffold.yaml`. This section contains two modes to hydrate configuration: One is to point to a declarative Kptfile file via `.manifests.kpt` (a.k.a kpt-managed), the other is to write the hydration pipeline directly in the `skaffold.yaml` (a.k.a skaffold-managed).
   107  
   108  #### kpt-managed mode
   109  
   110  The kpt-managed mode is for customers who are already the `kpt` hydration users (using the "pipeline" in Kptfile) and understand [declarative application management](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/declarative-application-management.md). Thus, there’s no need to ask them to re-write the similar config in skaffold.yaml.
   111  
   112  
   113  ![kpt-managed mode config](images/kpt-managed-mode.png)
   114  
   115  #### skaffold-managed mode
   116  
   117  ![skaffold-managed mode config](images/new-workflow.png)
   118  
   119  The skaffold-managed hydration has three types of operations: `generate`, `transform` and `validate`. The dry config is manipulated through each operation in the order as they are written in the `skaffold.yaml`.
   120  
   121  -  **generate**  defines the source of the configurations. It contains the raw manifests (kubernetes resources), `kustomize` resources (kustomization.yaml files and base/overlay resources)  and/or `helm` charts as the configuration source. Besides, It provides the option to fetch and update the `kpt` packages as resources.
   122  
   123  	*Note*: `helm` is only presented to users as "helm charts". Under the hood, the helm charts are managed by the `kpt`. See kpt [helm-inflator](https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/contrib/helm-inflator) example (the image prvoides minimum helm features, more work is needed before it can be used in skaffold). This allows `skaffold` to unify different config resources and pass them all through the kpt validation pipeline. What’s more, users are no longer required to install `kustomize`, `helm` or `kpt` and to fix the version conflicts.
   124  
   125  - **transform** defines the operations to mutate the configuration. Different than the `kpt` transformers, `skaffold` only accepts a **whitelisted set** of transformers. This is to control the `skaffold dev` qualities and gives a reliable render experience.
   126  
   127  - **validate** defines the operations to validate the configuration. Same as transform, only a whitelisted set of validators are accepted. E.g. `kubeval`, `conftest`.
   128  	
   129  
   130  ### "render" interface in `skaffold.yaml`
   131  
   132  ``` yaml
   133  
   134  apiVersion: skaffold/v3
   135  kind: Config
   136  metadata:
   137     name: skaffold-config
   138  build:
   139  
   140  render:
   141     # Optional. kpt-managed mode. The path to the Kptfile. If provided, the other "render" options are not allowed.
   142     kpt: [string]
   143  
   144     # This field defines the dry manifests from a variety of sources.
   145     generate:
   146        
   147        # Optional. A list of paths to the raw manifests or/and kustomize directory.  
   148        manifests: [array]
   149  
   150  
   151        # Optional. A list of helm charts to fetch. This is done via kpt helm-inflater image under the hood.
   152        helmCharts:
   153           
   154           # Required. The helm chart path.
   155           - path: 
   156           
   157           # Required. The paths to the values.yaml files.
   158           valuesFile: [array]
   159  
   160        # Optional. This field defines a set of transformation operations to run in series
   161        transform: 
   162  
   163           # Required. The transformer name. Can only accept skaffold whitelisted tools.
   164           - name: [string]
   165  
   166        # Optional. This field defines a set of validator operations to run in series.
   167        validate: 
   168  
   169           # Required. The validator image name. Can only accept skaffold whitelisted tool, e.g. kubeval  
   170           - name: [string]      
   171  
   172        
   173        # Optional. The path to the hydrated directory. 
   174        Output: [string]   
   175  
   176        # Optional. The flags passed to the `kpt fn` pipeline command directly.
   177        flags: ...
   178  
   179  deploy: ...
   180  ```
   181  
   182  #### An [example](https://gist.github.com/yuwenma/90610081f0b38a6002fb0b0f8b8567a3) of skaffold-managed hydration
   183  
   184  #### An [example](https://gist.github.com/yuwenma/dbadad4ce420b1ae8bb3a374b6ad9667) of kpt-managed hydration
   185  
   186  ### New “deploy”
   187  
   188  The `deploy` section in `skaffold.yaml` will be greatly simplified:
   189  
   190  - `skaffold` decides to not support `helm` installation (deploy step) and only focuses on `helm` charts (render step). This means no helm deployer is needed.
   191  	- The skaffold team have solicited feedback on whether users require Helm’s release functionality and the signal has been that it is not required or used. We will start without it and if needed add back the functionality.
   192  	- Deployment via Helm is supported by many CI/CD and GitOps tools. Some users also wrap helm with other tools. So they aren't necessarily deploying directly via skaffold.
   193  - Only `kpt live` is used to apply the WET configurations and users do not specify the deployer name in the deploy section. 
   194  
   195  #### "deploy" interface in `skaffold.yaml`
   196  
   197  ```yaml
   198  apiVersion: skaffold/v3
   199  kind: Config
   200  metadata:
   201    name: skaffold-config
   202  build:
   203     …
   204  render:
   205     …
   206  deploy:
   207  
   208     # Optional. The path to the WET configuration. It not provided, using the output from the render step.
   209     dir: [String]
   210  
   211     # Optional. The kpt live inventory ID
   212     inventoryID: [String]
   213  
   214     # Optional. The kpt inventory namespace
   215     inventoryNamespace: [String] 
   216  
   217     # Optional. The `kpt live apply` flags. 
   218     # Unchanged fields.
   219     options: ...
   220  ```
   221  
   222  ### `skaffold` commands and flags
   223  
   224  | command      | `skaffold.yaml` | comments
   225  | :----------- | :-----------: |-----------: |
   226  | `skaffold render` | `render.output` not given| By default, hydrate and show the WET config in stdout `kpt pipeline run --sink-mode=stdout`|
   227  | `skaffold render` | `render.output: [PATH]`| hydrate and store the WET config to PATH ` kpt pipeline run --sink-mode=special-dir --output-dir=PATH` |
   228  | `skaffold render --output [PATH2]`| `render.output: [PATH1]` | Hydrate and store the WET config in PATH2 (override `skaffold.yaml`) `kpt pipeline run --sink-mode=special-dir --output-dir=PATH2`|
   229  | `skaffold deploy` |`deploy.dir` not given|*Render* and deploy
   230  `kpt pipeline run --sink-mode=stdout | kpt live apply --`|
   231  | `skaffold deploy` |`deploy.dir: [PATH]` |Only deploy `kpt live apply [PATH]`|
   232  |`skaffold deploy --render-path [PATH2]`| `deploy.dir: [PATH1]`|Deploy and override PATH1 `kpt live apply [PATH2]`|
   233  | `skaffold dev` | | Build, render and deploy|
   234  
   235  ### Integration of `kpt` pipeline and `skaffold` render 
   236  
   237  Either *kpt-managed* Pipeline or *skaffold-managed* Pipeline is driven by a `kpt fn render` command (see below). This requires a `Kptfile` file. The *kpt-managed* approach finds the `Kptfile` from `.render.kpt`, and the *skaffold-managed* approach creates the `Kptfile` file on the fly.
   238  
   239  ![render command](images/render-cmd.png)
   240  
   241  This `Kptfile` is built as shown below. Since kpt considers all resources under the `Kptfile` directory as the source. `skaffold` will create a temporary directory `.kpt-hydrated` to cache the `kustomize` DRY configs, `helm` charts, and the raw manifests. Before running `kpt`, these resources are copied to the temporary directory, and `kpt` will hydrate the configurations in place.
   242  
   243  ``` yaml
   244  apiVersion: kpt.dev/v1alpha1
   245  kind: Kptfile
   246  metadata:
   247    name: skaffold-kpt-builtin-pipeline
   248  pipeline:
   249     mutators:
   250  
   251        # items directly defined in skaffold.yaml. It can only be the tools skaffold whitelisted. 
   252        - image: <render.transform.customize[0].name> 
   253        # specific arguments that could defer per whitelisted tool.
   254          configPath/configPath:      
   255  
   256        - image: <render.transform.customize[1].name> 
   257        ...
   258  
   259  
   260     validators:
   261    
   262        # items directly defined in skaffold.yaml. It can only be the tools skaffold whitelisted. E.g. kubeval. 
   263        - image: <render.validators.customize[0].name> 
   264        # specific arguments that could defer per whitelisted tool.
   265          configPath/configPath: 
   266  
   267        - image: <render.validators.customize[1].name> 
   268        ...
   269  
   270  ``` 
   271  
   272  The following graph describes the commands and operations to generate the kpt sources.
   273  
   274  ![builtin render](images/builtin-render.png)
   275  
   276  ### Integration of `kpt` live  and `skaffold` deploy
   277  
   278  `kpt` relies on `ResourceGroup` to accurately deploy the WET configurations to the cluster.  This requires the ResourceGroup CRD to be installed on the cluster side. 
   279  
   280  `skaffold dev` and `skaffold deploy` commands will detect and ask for user permissions before installing the `ResourceGroup` controller. It calls the following `kpt` commands. 
   281  
   282  ![deploy command](images/deploy-cmd.png)
   283  
   284  *Note*: `skaffold` v2 will not provide the migration from `kpt` v0.X to `kpt` v1. Users can follow [this guide](https://googlecontainertools.github.io/kpt/reference/live/migrate/) to establish the `kpt` migration themselves.
   285  
   286  ### Builtin `kpt`
   287  
   288  `skaffold` will have `kpt` embedded via go bindata, which ship together with the skaffold binary to guarantee the versions match.
   289  
   290  Currently, `skaffold` requires users to install `helm`, `kubectl`, `kustomize` and `kpt` and manage the version skew themselves. By making `kpt` and `skaffold` a bundle, users no longer need to install ANY other tools (`helm` and `kustomize` are used as `kpt` functions).
   291  
   292  ## Migration Plan
   293  
   294  ### `Helm` "deployer" 
   295  
   296  Customers can choose either to continue using `helm` deployer or migrate to `kpt` in both "render" and "deploy" stages. We provide users an easy approach to migrate `helm` "deployer" to the new skaffold. But if users continue using `helm`, we will not provide no further support for the new `kpt` features.
   297  
   298  This guarantees the `skaffold` v2 is backward compatible with `helm` and users have a seamless experience when introduced to the new render UI. 
   299  
   300  #### The migration command
   301  
   302  Users can run the existing skaffold `fix` command to migrate to the new skaffold.
   303  
   304  This will wipe and recreate the `skaffold.yaml` as below. After the migration, if users make a `helm` config change in `skaffold.yaml`, skaffold dev (and other skaffold commands enabling file watcher) will recreate the following kpt resources.  
   305  
   306  ![Helm migration](images/helm-migration.png)
   307  
   308  #### Under the hood
   309  
   310  Though the new UI looks similar except moving helm from "deploy" to "render", the actual implementation is very different. Instead of calling the `helm` CLI, the `skaffold-helm-inflator` functions are used to convert the `Helm` charts to a kpt [`ResourceList.items`](https://googlecontainertools.github.io/kpt/guides/producer/functions/#resourcelistitems). This function is expected to digest all the `helm` arguments listed in the `skaffold.yaml` reference doc [v2beta16](https://skaffold.dev/docs/references/yaml/#deploy-helm).
   311  
   312  
   313  #### Phase 1
   314  
   315  The [helm-inflator](https://github.com/GoogleContainerTools/kpt-functions-catalog/tree/master/examples/contrib/helm-inflator)) is used and it requires the helm config to be in the form of a ConfigMap resource. Note, this image does not fit into the kpt v1 Kptfile yet.
   316  
   317  ##### Step 1. Create `.kpt-pipeline` directory and run `kpt pkg init .kpt-pipeline/`
   318  
   319  ![helm step 1](images/helm-step1.png)
   320  
   321  ##### Step 2. Create `.kpt-pipeline/config-helm.yaml` file from `skaffold.yaml` `.render.generate.helm`
   322  
   323  ![helm step 2](images/helm-step2.png)
   324  
   325  ##### Step 3. Use the helm-inflator to convert the helm charts
   326  
   327  ![helm step 3](images/helm-step3.png)
   328  
   329  ##### Step 4. Store the converted `helm` resource in the temporary directory
   330  
   331  #### Phase 2
   332  
   333  Most steps are similar to phase 1 except in step 3. Instead of calling the `kpt fn eval` command, we can edit the pipeline in `.kpt-pipeline/Kptfile` as below. (parameters may change, defer to the final helm-inflator-2 image)
   334  
   335  ![helm phase 2](images/helm-phase2.png)
   336  
   337  #### Phase 3
   338  
   339  The `kpt` function format (ConfigMap) and *helm-inflator* images may change significantly in the future. More migration changes will happen defer to the final design of helm-inflator function and the `kpt` function configuration. 
   340  
   341  ### `kustomize` "deployer" 
   342  
   343  `kustomize` deployer should be deprecated in three phases. The goal is to provide the `skaffold` users a seamless experience on migrating to skaffold V2.  
   344  
   345  #### The migration command
   346  
   347  Users can run the existing `skaffold fix` command to migrate to the new skaffold.
   348  
   349  This will wipe and recreate the skaffold.yaml as below.
   350  
   351  ![Kustomize migration](images/kustomize-migration.png)
   352  
   353  #### Under the hood
   354  
   355  ##### Phase 1
   356  Providing a full `kustomize` image requires a lot of design, implementation (tracked [1447](https://github.com/GoogleContainerTools/kpt/issues/1447)) and testing. Before the kustomize image is available, `skaffold` commands continue using the `kustomize` CLI to build the kustomize configs and pass them through the `kpt` validation and mutation pipeline.
   357  
   358  ##### Step 1. Create `.kpt-pipeline/` directory and run `kpt pkg init .kpt-pipeline/.` 
   359  
   360  Same as “helm deployer” migration step 1.
   361  
   362  ##### Step 2. Run `kustomize build`
   363  
   364  Walk through the `.render.generate.manifests` and check if `kustomization.yaml` files exist. If so, run  `kustomize build {render.generate.manifests}` (this may require a tmp dir if manifests contain multiple resources) and store the stdout to `.kpt-pipeline/kustomize-dest`
   365  
   366  #### Phase 2
   367  
   368  Once the `kustomize`  kpt function (tracked [1447](https://github.com/GoogleContainerTools/kpt/issues/1447) is available, define the kustomize in Kptfile. Step 1-3 in phase 1 can be skipped.
   369  
   370  ![kustomize phase 2](images/kustomize-phase2.png)
   371  
   372  #### Phase 3
   373  
   374  Defer to the unified kpt/kustomize, the kustomize and kpt may be further aligned with each other. And more migration changes are needed.