32. Decoupling Deployment

Date started: 2023-11-17 Date accepted: 2023-02-01

Status

Accepted

Relates to:

Supercedes:

Authors

Context

Since the beginning of our project, we’ve had an emphasis on providing an integrated experience for the user, automating all steps through build, test, deployment, and release to higher environments.

Some challenges:

See also RHTAP-1873.

Decision

We are going to decouple the deployment from the build, test, and release portions of our system.

Deployment:

Test and promotion:

Out of scope

Some other interesting ideas that are floating around these days, but which should be taken up in other ADRs, if we take them up at all:

Use Case Descriptions

During onboarding: whereas today when a user requests a new appstudio tier namespace, the tier template includes an Environment that the integration-service will promote to. Tomorrow, the appstudio tier template should no longer include an Environment which on its own will cause integration-service to not trigger a deployment when testing completes. Instead, the appstudio tier template should include a ReleasePlan with a reference to the push-to-registry release pipeline. This new default ReleasePlan should carry parameters such that whenever a Snapshot is successfully tested, a Release is created that re-tags the images in build-time quay repositories with a tag like :released or :validated (name tbd). The push-to-registry pipeline can use the appstudio-pipeline service account in the user’s dev workspace, which already has push access to the repository in question.

flowchart TD
    NSTierTemplate --> |provides| ReleasePlan
    A[fa:fa-code-commit Git Commit] --> |webhook| PipelinesAsCode
    PipelinesAsCode --> |creates| build[Build PipelineRun]
    build --> |triggers| integration-service
    integration-service --> |asks| decision{Is there a ReleasePlan?}
    ReleasePlan --> |influences| decision
    decision --> |yes| Release
    build --> |pushes the image| quay.io/redhat-user-workloads/tenant/component
    Release --> |tags the image for release| quay.io/redhat-user-workloads/tenant/component
    quay.io/redhat-user-workloads/tenant/component --> renovatebot[User provided RenovateBot]
    renovatebot --> |updates| gitops-repo[User provided GitOps repo]
    gitops-repo --> |causes deployment via| argocd[User provided ArgoCD]
    argocd --> |deploys to| cluster[User provided cluster]

Outside of the Konflux member cluster, the user is responsible for acquiring a gitops repo and deployment environments of their choice, manually laying out their application resources in the repo (assisted by tools like kam), specifying image references by tag to match the :released or :validated tagging schem mentioned above, configuring ArgoCD to deploy from their gitops repo, and configuring renovatebot to propagate image updates by digest to their gitops repo. Really, ArgoCD here is just an example and other gitops tools could be used; renovate could even update Helm repos with the new images. Options for the user are not limited.

For manual creation of new environments - the user manages this directly using a combination of their gitops repo and argo, outside of the Konflux member cluster.

For automated testing in ephemeral environments - the user specifies an IntegrationTestScenario CR, which references a pipeline which (somehow) creates a resourceClaim. After a build completes, the integration-service creates the PipelineRun which causes the resource driver associated with the resourceClaim to provision the requested compute. The resource driver injects the kubeconfig for the ephemeral compute into the pod, to be used by the test TaskRun. The user’s test TaskRun is responsible for deploying the user’s app based on the Snapshot provided by integration-service as a parameter and the kubeconfig injected into the TaskRun pod by the resource driver before running tests. The resource driver should cleanup after itself after the test TaskRun and its corresponding pod complete.

flowchart TD
    User --> |provides| IntegrationTestScenario
    User --> |provides| testpipeline
    commit[fa:fa-code-commit Git Commit] --> |webhook| PipelinesAsCode
    PipelinesAsCode --> |creates| build[Build PipelineRun]
    build --> |triggers| integration-service
    integration-service --> |consults| IntegrationTestScenario
    IntegrationTestScenario --> |references| testpipeline
    testpipeline --> |is used to create| testpipelinerun
    testpipelinerun --> |prompts| driver[Resource Driver]
    driver --> |creates| compute[Compute - cluster, namespace, or other external resource]
    driver --> |creates| kubeconfig
    kubeconfig --> |is injected into pod of| testpipelinerun[Test PipelineRun]
    integration-service --> |creates| testpipelinerun[Test PipelineRun]
    testpipelinerun --> |deploys user app to| compute
    testpipelinerun --> |executes tests against| compute

Consequences

Implementation

Some of these phases can be done at the same time.