Skip to content

Commit 1c6915f

Browse files
Preview Environments Documentation (#455)
Documents basic lifecycle of preview environments, and also links out to a quick demo. Backfilled demo videos for upgrade assistant and flows.
1 parent 2789727 commit 1c6915f

6 files changed

Lines changed: 164 additions & 12 deletions

File tree

generated/routes.json

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
},
3030
"/getting-started/first-steps/cli-quickstart": {
3131
"relPath": "/getting-started/first-steps/cli-quickstart.md",
32-
"lastmod": "2025-05-08T09:00:26.000Z"
32+
"lastmod": "2025-05-08T12:32:16.000Z"
3333
},
3434
"/getting-started/first-steps/existing-cluster": {
3535
"relPath": "/getting-started/first-steps/existing-cluster.md",
@@ -121,7 +121,7 @@
121121
},
122122
"/plural-features/continuous-deployment/observer": {
123123
"relPath": "/plural-features/continuous-deployment/observer.md",
124-
"lastmod": "2025-04-28T11:49:02.395Z"
124+
"lastmod": "2025-05-10T04:29:16.000Z"
125125
},
126126
"/plural-features/k8s-upgrade-assistant": {
127127
"relPath": "/plural-features/k8s-upgrade-assistant/index.md",
@@ -215,13 +215,17 @@
215215
"relPath": "/plural-features/flows/flow-ai.md",
216216
"lastmod": "2025-04-18T18:30:29.000Z"
217217
},
218+
"/plural-features/flows/preview-environments": {
219+
"relPath": "/plural-features/flows/preview-environments.md",
220+
"lastmod": "2025-05-11T22:10:38.846Z"
221+
},
218222
"/plural-features/flows/mcp": {
219223
"relPath": "/plural-features/flows/mcp.md",
220224
"lastmod": "2025-04-18T18:30:29.000Z"
221225
},
222226
"/plural-features/observability": {
223227
"relPath": "/plural-features/observability/index.md",
224-
"lastmod": "2025-04-30T21:17:22.000Z"
228+
"lastmod": "2025-05-10T04:27:39.000Z"
225229
},
226230
"/plural-features/observability/prometheus": {
227231
"relPath": "/plural-features/observability/prometheus.md",
@@ -241,11 +245,11 @@
241245
},
242246
"/plural-features/observability/observability-webhooks/datadog": {
243247
"relPath": "/plural-features/observability/observability-webhooks/datadog.md",
244-
"lastmod": "2025-04-30T21:17:22.000Z"
248+
"lastmod": "2025-05-10T04:27:39.000Z"
245249
},
246250
"/plural-features/observability/observability-webhooks/grafana": {
247251
"relPath": "/plural-features/observability/observability-webhooks/grafana.md",
248-
"lastmod": "2025-04-30T21:17:22.000Z"
252+
"lastmod": "2025-05-10T04:27:39.000Z"
249253
},
250254
"/plural-features/pr-automation": {
251255
"relPath": "/plural-features/pr-automation/index.md",
@@ -285,23 +289,23 @@
285289
},
286290
"/examples/continuous-deployment": {
287291
"relPath": "/examples/continuous-deployment/index.md",
288-
"lastmod": "2025-05-07T11:15:56.000Z"
292+
"lastmod": "2025-05-10T04:28:20.000Z"
289293
},
290294
"/examples/continuous-deployment/helm-basic-with-inline-values": {
291295
"relPath": "/examples/continuous-deployment/helm-basic-with-inline-values.md",
292-
"lastmod": "2025-05-07T11:12:43.000Z"
296+
"lastmod": "2025-05-10T04:28:20.000Z"
293297
},
294298
"/examples/continuous-deployment/helm-basic-with-values-file": {
295299
"relPath": "/examples/continuous-deployment/helm-basic-with-values-file.md",
296-
"lastmod": "2025-05-07T11:12:43.000Z"
300+
"lastmod": "2025-05-10T04:28:20.000Z"
297301
},
298302
"/examples/continuous-deployment/kustomize-inflate-helm": {
299303
"relPath": "/examples/continuous-deployment/kustomize-inflate-helm.md",
300-
"lastmod": "2025-05-07T11:12:43.000Z"
304+
"lastmod": "2025-05-10T04:28:20.000Z"
301305
},
302306
"/examples/continuous-deployment/kustomize-stack-with-liquid": {
303307
"relPath": "/examples/continuous-deployment/kustomize-stack-with-liquid.md",
304-
"lastmod": "2025-05-07T11:12:43.000Z"
308+
"lastmod": "2025-05-10T04:28:20.000Z"
305309
},
306310
"/faq": {
307311
"relPath": "/faq/index.md",
@@ -361,7 +365,7 @@
361365
},
362366
"/deployments/cli-quickstart": {
363367
"relPath": "/getting-started/first-steps/cli-quickstart.md",
364-
"lastmod": "2025-05-08T09:00:26.000Z"
368+
"lastmod": "2025-05-08T12:32:16.000Z"
365369
},
366370
"/deployments/existing-cluster": {
367371
"relPath": "/getting-started/first-steps/existing-cluster.md",

pages/plural-features/flows/index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ Further, because it gives us a clear circumference to understand what's related
3030

3131
Further, Plural Flows can vector index prs, query app log data and respond to incoming alerts, extending the capabilities of our AI insight engine to be able to be a general troubleshooting tool for application code errors alongside the built-in support for Kubernetes misconfiguration.
3232

33-
3433
# Demo Video
3534

3635
To see this all in action, feel free to browse our live demo video on Youtube for all that can be done with Plural Flows:
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: Flow Preview Environments
3+
description: Easily create a first class PR preview environment experience within Flows
4+
---
5+
6+
## Overview
7+
8+
Preview environments are a powerful software testing pattern whereby you create a near clone of a dev environment with the code of a feature branch during the duration of a pull request. This has a few great benefits:
9+
10+
1. Reduces churn in your dev environment, improving overall stability - which is a common failure in large organizations with many in-flight changes
11+
2. Makes it easier to test code in isolation - the code only has the changes happening in your branch
12+
3. Reduces dev data corruption issues - true if you implement database forking as part of the preview, making it easy to test things like schema migrations
13+
14+
This is extremely easy to implement with Plural because of a few things:
15+
16+
* GitOps patterns make it really easy to redeploy and reconfigure services
17+
* Plural already has the webhook and event system to track PR updates natively implemented within its server
18+
* Plural also already has a secure way of managing SCM credentials, so it can natively implement the Github/Gitlab comment feedback to make an ideal DevEx around preview environments
19+
20+
## Demo Video
21+
22+
If you just want to see it in action, here's a quick YouTube video demo:
23+
24+
{% embed url="https://youtu.be/9hoiQnkgnzQ" aspectRatio="16 / 9" /%}
25+
26+
27+
## How to Implement
28+
29+
Implementing preview environments is quite simple. You functionally just need to register one custom resource, a `PreviewEnvironmentTemplate` like below:
30+
31+
```yaml
32+
apiVersion: deployments.plural.sh/v1alpha1
33+
kind: PreviewEnvironmentTemplate
34+
metadata:
35+
name: test
36+
spec:
37+
flowRef:
38+
kind: Flow
39+
name: flow-test
40+
41+
referenceServiceRef:
42+
kind: ServiceDeployment
43+
name: flow-test-dev
44+
namespace: flow-test
45+
46+
template:
47+
namespace: "flow-test-pr-{{ pr.number }}"
48+
name: "flow-test-pr-{{ pr.number }}"
49+
helm:
50+
values:
51+
image:
52+
tag: "sha-{{ commitSha | slice: 0, 7 }}"
53+
```
54+
55+
This will then tell Plural to create a preview environment clone of the `flow-test-dev` `ServiceDeployment` whenever a PR has the following annotation in its body:
56+
57+
```
58+
Plural Flow: flow-test
59+
Plural Preview: test # notice this is the same as the name of the PreviewEnvironmentTemplate
60+
```
61+
62+
the `template` field customizes how you'll override the setting of the source service, in this case it will:
63+
64+
1. deploy it in the `flow-test-pr-{{ pr.number }}` namespace
65+
2. Override the image with `sha-{{ commitSha | slice: 0, 7 }}` (basically the sha image tag we've configured GH actions to build with)
66+
67+
To see how the image was built, you can consult one of our example repos [here](https://github.com/pluralsh/plrl-cd-demo/blob/main/.github/workflows/push.yaml#L48), but the image tagging is easy to accomplish with github actions using:
68+
69+
70+
```yaml
71+
env:
72+
DOCKER_METADATA_PR_HEAD_SHA: 'true' # necessary for docker to tag with the commit of the actual branch, not github's phantom pr branch
73+
74+
jobs:
75+
publish-docker:
76+
...
77+
- name: Docker meta
78+
id: meta
79+
uses: docker/metadata-action@v5
80+
with:
81+
# replace with your registry
82+
images: |
83+
ghcr.io/pluralsh/plrl-cd-test
84+
# generate Docker tags based on the following events/attributes
85+
tags: |
86+
type=sha
87+
type=ref,event=pr
88+
type=ref,event=branch
89+
type=semver,pattern={{version}}
90+
- name: Build and push
91+
uses: docker/build-push-action@v5
92+
with:
93+
context: "."
94+
file: "./Dockerfile"
95+
push: true
96+
tags: ${{ steps.meta.outputs.tags }}
97+
labels: ${{ steps.meta.outputs.labels }}
98+
platforms: linux/amd64
99+
cache-from: type=gha
100+
cache-to: type=gha,mode=max
101+
build-args: |
102+
GIT_COMMIT=${{ github.sha }}
103+
```
104+
105+
## Constraints
106+
107+
Plural enforces a few constraints on how preview environments can be created:
108+
109+
1. They will only deploy to the same cluster as their source service
110+
2. They will only deploy to a namespace with a name that's prefixed by the original service's namespace
111+
- this is to prevent preview environments from jumping tenants, but also still make it easy to prevent them from trampling the original service.
112+

pages/plural-features/k8s-upgrade-assistant/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ Deprecations will be surfaced at the cluster level in the "Status" column of the
1313
To see deprecations relevant to a specific service, navigate to the Service details page. You'll see a notification that you can click to review any changes that need to be made:
1414

1515
![](/assets/deployments/deprecation-warning.png)
16+
17+
To see it all end-to-end, here's a demo video to show the experience:
18+
19+
{% embed url="https://youtu.be/fJmTrELoAKU" aspectRatio="16 / 9" /%}

src/generated/graphql.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,10 @@ export type ConsoleInstance = {
573573
insertedAt?: Maybe<Scalars['DateTime']['output']>;
574574
/** the name of this instance (globally unique) */
575575
name: Scalars['String']['output'];
576+
/** the network configuration for this instance */
577+
network?: Maybe<ConsoleInstanceNetwork>;
578+
/** custom oidc configuration for this instance */
579+
oidc?: Maybe<ConsoleInstanceOidc>;
576580
owner?: Maybe<User>;
577581
/** the region this instance is hosted in */
578582
region: Scalars['String']['output'];
@@ -594,6 +598,10 @@ export type ConsoleInstanceAttributes = {
594598
cloud: CloudProvider;
595599
/** the name of this instance (globally unique) */
596600
name: Scalars['String']['input'];
601+
/** use this to add network security settings to this instance */
602+
network?: InputMaybe<ConsoleNetworkAttributes>;
603+
/** use this to add custom oidc configuration to this instance */
604+
oidc?: InputMaybe<ConsoleOidcAttributes>;
597605
/** the region to deploy to (provider specific) */
598606
region: Scalars['String']['input'];
599607
/** a heuristic size of this instance */
@@ -614,6 +622,18 @@ export type ConsoleInstanceEdge = {
614622
node?: Maybe<ConsoleInstance>;
615623
};
616624

625+
export type ConsoleInstanceNetwork = {
626+
__typename?: 'ConsoleInstanceNetwork';
627+
allowedCidrs?: Maybe<Array<Maybe<Scalars['String']['output']>>>;
628+
};
629+
630+
export type ConsoleInstanceOidc = {
631+
__typename?: 'ConsoleInstanceOidc';
632+
clientId?: Maybe<Scalars['String']['output']>;
633+
clientSecret?: Maybe<Scalars['String']['output']>;
634+
issuer?: Maybe<Scalars['String']['output']>;
635+
};
636+
617637
export enum ConsoleInstanceStatus {
618638
DatabaseCreated = 'DATABASE_CREATED',
619639
DatabaseDeleted = 'DATABASE_DELETED',
@@ -632,9 +652,21 @@ export enum ConsoleInstanceType {
632652

633653
export type ConsoleInstanceUpdateAttributes = {
634654
configuration?: InputMaybe<ConsoleConfigurationUpdateAttributes>;
655+
network?: InputMaybe<ConsoleNetworkAttributes>;
656+
oidc?: InputMaybe<ConsoleOidcAttributes>;
635657
size?: InputMaybe<ConsoleSize>;
636658
};
637659

660+
export type ConsoleNetworkAttributes = {
661+
allowedCidrs?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
662+
};
663+
664+
export type ConsoleOidcAttributes = {
665+
clientId?: InputMaybe<Scalars['String']['input']>;
666+
clientSecret?: InputMaybe<Scalars['String']['input']>;
667+
issuer?: InputMaybe<Scalars['String']['input']>;
668+
};
669+
638670
export enum ConsoleSize {
639671
Large = 'LARGE',
640672
Medium = 'MEDIUM',

src/routing/docs-structure.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export const docsStructure: DocSection[] = [
140140
sections: [
141141
{ path: 'create-a-flow', title: 'Create a flow' },
142142
{ path: 'flow-ai', title: 'Plural AI and Flows' },
143+
{ path: 'preview-environments', title: 'Preview Environments' },
143144
{ path: 'mcp', title: 'Flow MCP Server Integration' },
144145
],
145146
},

0 commit comments

Comments
 (0)