Point at dokploy-deploy-action for rollouts

This commit is contained in:
2026-08-09 03:38:24 +03:00
parent 096e5c0974
commit c06d3386a6
4 changed files with 2041 additions and 133 deletions

View File

@@ -18,46 +18,52 @@ const adminPassword = config.requireSecret("adminPassword");
// ---------------------------------------------------------------- structure
const shop = new dokploy.Project("shop", {
name: "shop",
description: "Storefront and its backing services",
// Shared by every service in the project.
env: "TZ=Europe/Bucharest",
name: "shop",
description: "Storefront and its backing services",
// Shared by every service in the project.
env: "TZ=Europe/Bucharest",
});
// Dokploy creates a default "production" environment with the project; add a
// second one for staging.
const staging = new dokploy.Environment("staging", {
name: "staging",
description: "Pre-production",
projectId: shop.id,
env: "LOG_LEVEL=debug",
name: "staging",
description: "Pre-production",
projectId: shop.id,
env: "LOG_LEVEL=debug",
});
// ------------------------------------------------------------------ secrets
const postgresPassword = new random.RandomPassword("postgres", { length: 32, special: false });
const redisPassword = new random.RandomPassword("redis", { length: 32, special: false });
const postgresPassword = new random.RandomPassword("postgres", {
length: 32,
special: false,
});
const redisPassword = new random.RandomPassword("redis", {
length: 32,
special: false,
});
// --------------------------------------------------------------- datastores
const db = new dokploy.Postgres("db", {
name: "shop-db",
environmentId: shop.defaultEnvironmentId,
dockerImage: "postgres:16-alpine",
databaseName: "shop",
databaseUser: "shop",
databasePassword: postgresPassword.result,
memoryLimit: "1g",
cpuLimit: "1",
memoryReservation: "256m",
name: "shop-db",
environmentId: shop.defaultEnvironmentId,
dockerImage: "postgres:16-alpine",
databaseName: "shop",
databaseUser: "shop",
databasePassword: postgresPassword.result,
memoryLimit: "1g",
cpuLimit: "1",
memoryReservation: "256m",
});
const cache = new dokploy.Redis("cache", {
name: "shop-cache",
environmentId: shop.defaultEnvironmentId,
dockerImage: "redis:7-alpine",
databasePassword: redisPassword.result,
memoryLimit: "256m",
name: "shop-cache",
environmentId: shop.defaultEnvironmentId,
dockerImage: "redis:7-alpine",
databasePassword: redisPassword.result,
memoryLimit: "256m",
});
// ----------------------------------------------------------- the web service
@@ -65,63 +71,65 @@ const cache = new dokploy.Redis("cache", {
// Dokploy resolves service names on the shared Docker network, so the database
// is reachable by its generated appName.
const storefrontEnv = pulumi
.all([db.appName, postgresPassword.result, cache.appName, redisPassword.result])
.apply(([dbHost, dbPass, cacheHost, cachePass]) => [
`DATABASE_URL=postgresql://shop:${dbPass}@${dbHost}:5432/shop`,
`REDIS_URL=redis://:${cachePass}@${cacheHost}:6379`,
"NODE_ENV=production",
].join("\n"));
.all([db.appName, postgresPassword.result, cache.appName, redisPassword.result])
.apply(([dbHost, dbPass, cacheHost, cachePass]) =>
[
`DATABASE_URL=postgresql://shop:${dbPass}@${dbHost}:5432/shop`,
`REDIS_URL=redis://:${cachePass}@${cacheHost}:6379`,
"NODE_ENV=production",
].join("\n"),
);
const storefront = new WebService("storefront", {
environmentId: shop.defaultEnvironmentId,
description: "Public storefront",
github: {
githubId: githubProviderId,
owner: "acme",
repository: "storefront",
branch: "main",
},
env: storefrontEnv,
replicas: 2,
memoryLimit: "1g",
cpuLimit: "1",
domains: [{ host: "shop.example.com", port: 3000 }],
environmentId: shop.defaultEnvironmentId,
description: "Public storefront",
github: {
githubId: githubProviderId,
owner: "acme",
repository: "storefront",
branch: "main",
},
env: storefrontEnv,
replicas: 2,
memoryLimit: "1g",
cpuLimit: "1",
domains: [{ host: "shop.example.com", port: 3000 }],
});
new dokploy.Redirect("storefront-www", {
applicationId: storefront.application.id,
regex: String.raw`^https://www\.shop\.example\.com/(.*)`,
replacement: "https://shop.example.com/${1}",
permanent: true,
applicationId: storefront.application.id,
regex: String.raw`^https://www\.shop\.example\.com/(.*)`,
replacement: "https://shop.example.com/${1}",
permanent: true,
});
new dokploy.Mount("storefront-uploads", {
serviceId: storefront.application.id,
serviceType: "application",
type: "volume",
mountPath: "/app/uploads",
volumeName: "storefront-uploads",
serviceId: storefront.application.id,
serviceType: "application",
type: "volume",
mountPath: "/app/uploads",
volumeName: "storefront-uploads",
});
// ------------------------------- an internal tool behind basic auth (staging)
new WebService("admin", {
environmentId: staging.id,
dockerImage: "traefik/whoami:latest",
domains: [{ host: "admin.staging.example.com", port: 80 }],
basicAuth: { username: "ops", password: adminPassword },
environmentId: staging.id,
dockerImage: "traefik/whoami:latest",
domains: [{ host: "admin.staging.example.com", port: 80 }],
basicAuth: { username: "ops", password: adminPassword },
});
// -------------------------------------------------------------- compose stack
const observability = new dokploy.Compose("observability", {
name: "observability",
environmentId: shop.defaultEnvironmentId,
composeType: "docker-compose",
sourceType: "raw",
// Preserve volumes if this stack is ever destroyed.
deleteVolumes: false,
composeFile: `services:
name: "observability",
environmentId: shop.defaultEnvironmentId,
composeType: "docker-compose",
sourceType: "raw",
// Preserve volumes if this stack is ever destroyed.
deleteVolumes: false,
composeFile: `services:
uptime:
image: louislam/uptime-kuma:1
volumes:
@@ -134,13 +142,13 @@ volumes:
});
new dokploy.Domain("observability", {
composeId: observability.id,
domainType: "compose",
serviceName: "uptime",
host: "status.example.com",
port: 3001,
https: true,
certificateType: "letsencrypt",
composeId: observability.id,
domainType: "compose",
serviceName: "uptime",
host: "status.example.com",
port: 3001,
https: true,
certificateType: "letsencrypt",
});
export const projectId = shop.id;

1850
examples/typescript/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,33 +2,36 @@ import * as pulumi from "@pulumi/pulumi";
import * as dokploy from "@maxvojtkov/pulumi-dokploy";
export interface DomainSpec {
host: string;
port: number;
https?: boolean;
path?: string;
host: string;
port: number;
https?: boolean;
path?: string;
}
export interface WebServiceArgs {
environmentId: pulumi.Input<string>;
description?: pulumi.Input<string>;
environmentId: pulumi.Input<string>;
description?: pulumi.Input<string>;
/** Either a prebuilt image or a GitHub repository, not both. */
dockerImage?: pulumi.Input<string>;
github?: {
githubId: pulumi.Input<string>;
owner: pulumi.Input<string>;
repository: pulumi.Input<string>;
branch: pulumi.Input<string>;
};
/** Either a prebuilt image or a GitHub repository, not both. */
dockerImage?: pulumi.Input<string>;
github?: {
githubId: pulumi.Input<string>;
owner: pulumi.Input<string>;
repository: pulumi.Input<string>;
branch: pulumi.Input<string>;
};
env?: pulumi.Input<string>;
replicas?: pulumi.Input<number>;
memoryLimit?: pulumi.Input<string>;
cpuLimit?: pulumi.Input<string>;
env?: pulumi.Input<string>;
replicas?: pulumi.Input<number>;
memoryLimit?: pulumi.Input<string>;
cpuLimit?: pulumi.Input<string>;
domains?: DomainSpec[];
/** username/password pair to put the whole service behind basic auth. */
basicAuth?: { username: pulumi.Input<string>; password: pulumi.Input<string> };
domains?: DomainSpec[];
/** username/password pair to put the whole service behind basic auth. */
basicAuth?: {
username: pulumi.Input<string>;
password: pulumi.Input<string>;
};
}
/**
@@ -36,38 +39,53 @@ export interface WebServiceArgs {
* Pulumi equivalent of the `web-service` Terraform module.
*/
export class WebService extends pulumi.ComponentResource {
public readonly application: dokploy.Application;
public readonly domains: dokploy.Domain[];
public readonly application: dokploy.Application;
public readonly domains: dokploy.Domain[];
constructor(name: string, args: WebServiceArgs, opts?: pulumi.ComponentResourceOptions) {
super("dokploy:index:WebService", name, {}, opts);
const child = { parent: this };
constructor(name: string, args: WebServiceArgs, opts?: pulumi.ComponentResourceOptions) {
super("dokploy:index:WebService", name, {}, opts);
const child = { parent: this };
this.application = new dokploy.Application(name, {
name,
environmentId: args.environmentId,
description: args.description,
env: args.env,
replicas: args.replicas,
memoryLimit: args.memoryLimit,
cpuLimit: args.cpuLimit,
...(args.github
? {
sourceType: "github",
buildType: "nixpacks",
autoDeploy: true,
githubId: args.github.githubId,
owner: args.github.owner,
repository: args.github.repository,
branch: args.github.branch,
}
: {
sourceType: "docker",
dockerImage: args.dockerImage,
}),
}, child);
this.application = new dokploy.Application(
name,
{
name,
environmentId: args.environmentId,
description: args.description,
env: args.env,
replicas: args.replicas,
memoryLimit: args.memoryLimit,
cpuLimit: args.cpuLimit,
...(args.github
? {
sourceType: "github",
buildType: "nixpacks",
autoDeploy: true,
githubId: args.github.githubId,
owner: args.github.owner,
repository: args.github.repository,
branch: args.github.branch,
}
: {
sourceType: "docker",
dockerImage: args.dockerImage,
}),
sourceType: "gitea",
buildType: "dockerfile",
autoDeploy: true,
giteaId: "test",
owner: "test",
repository: "test",
branch: "main",
},
child,
);
this.domains = (args.domains ?? []).map((d, i) => new dokploy.Domain(`${name}-domain-${i}`, {
this.domains = (args.domains ?? []).map(
(d, i) =>
new dokploy.Domain(
`${name}-domain-${i}`,
{
applicationId: this.application.id,
domainType: "application",
host: d.host,
@@ -75,19 +93,26 @@ export class WebService extends pulumi.ComponentResource {
path: d.path,
https: d.https ?? true,
certificateType: (d.https ?? true) ? "letsencrypt" : "none",
}, child));
},
child,
),
);
if (args.basicAuth) {
new dokploy.Security(`${name}-auth`, {
applicationId: this.application.id,
username: args.basicAuth.username,
password: args.basicAuth.password,
}, child);
}
this.registerOutputs({
application: this.application,
domains: this.domains,
});
if (args.basicAuth) {
new dokploy.Security(
`${name}-auth`,
{
applicationId: this.application.id,
username: args.basicAuth.username,
password: args.basicAuth.password,
},
child,
);
}
this.registerOutputs({
application: this.application,
domains: this.domains,
});
}
}