Skip to content

Commit dcd1df3

Browse files
authored
Merge pull request #637 from xenonwellz/feat/stack-env-support
Feat: added env support to Dokploy stack compose
2 parents 18c6d08 + 7369b54 commit dcd1df3

File tree

7 files changed

+104
-73
lines changed

7 files changed

+104
-73
lines changed

apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -211,21 +211,17 @@ const Service = (
211211
<TabsList
212212
className={cn(
213213
"md:grid md:w-fit max-md:overflow-y-scroll justify-start",
214-
data?.serverId ? "md:grid-cols-6" : "md:grid-cols-7",
214+
data?.serverId ? "md:grid-cols-7" : "md:grid-cols-7",
215215
data?.composeType === "docker-compose"
216216
? ""
217-
: "md:grid-cols-6",
217+
: "md:grid-cols-7",
218218
data?.serverId && data?.composeType === "stack"
219-
? "md:grid-cols-5"
219+
? "md:grid-cols-6"
220220
: "",
221221
)}
222222
>
223223
<TabsTrigger value="general">General</TabsTrigger>
224-
{data?.composeType === "docker-compose" && (
225-
<TabsTrigger value="environment">
226-
Environment
227-
</TabsTrigger>
228-
)}
224+
<TabsTrigger value="environment">Environment</TabsTrigger>
229225
{!data?.serverId && (
230226
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
231227
)}
Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,59 @@
11
import {
2-
type DomainSchema,
3-
type Schema,
4-
type Template,
5-
generateBase64,
6-
generatePassword,
7-
generateRandomDomain,
2+
type DomainSchema,
3+
type Schema,
4+
type Template,
5+
generateBase64,
6+
generatePassword,
7+
generateRandomDomain,
88
} from "../utils";
99

1010
export function generate(schema: Schema): Template {
11-
const mainDomain = generateRandomDomain(schema);
12-
const apiKey = generateBase64(64);
13-
const postgresPassword = generatePassword();
11+
const mainDomain = generateRandomDomain(schema);
12+
const apiKey = generateBase64(64);
13+
const postgresPassword = generatePassword();
1414

15-
const domains: DomainSchema[] = [
16-
{
17-
host: mainDomain,
18-
port: 8080,
19-
serviceName: "evolution-api",
20-
},
21-
];
15+
const domains: DomainSchema[] = [
16+
{
17+
host: mainDomain,
18+
port: 8080,
19+
serviceName: "evolution-api",
20+
},
21+
];
2222

23-
const envs = [
24-
`SERVER_URL=https://${mainDomain}`,
25-
"AUTHENTICATION_TYPE=apikey",
26-
`AUTHENTICATION_API_KEY=${apiKey}`,
27-
"AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true",
23+
const envs = [
24+
`SERVER_URL=https://${mainDomain}`,
25+
"AUTHENTICATION_TYPE=apikey",
26+
`AUTHENTICATION_API_KEY=${apiKey}`,
27+
"AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true",
2828

29-
"LANGUAGE=en",
30-
"CONFIG_SESSION_PHONE_CLIENT=Evolution API",
31-
"CONFIG_SESSION_PHONE_NAME=Chrome",
32-
"TELEMETRY=false",
33-
"TELEMETRY_URL=",
29+
"LANGUAGE=en",
30+
"CONFIG_SESSION_PHONE_CLIENT=Evolution API",
31+
"CONFIG_SESSION_PHONE_NAME=Chrome",
32+
"TELEMETRY=false",
33+
"TELEMETRY_URL=",
3434

35-
"POSTGRES_DATABASE=evolution",
36-
"POSTGRES_USERNAME=postgresql",
37-
`POSTGRES_PASSWORD=${postgresPassword}`,
38-
"DATABASE_ENABLED=true",
39-
"DATABASE_PROVIDER=postgresql",
40-
`DATABASE_CONNECTION_URI=postgres://postgresql:${postgresPassword}@evolution-postgres:5432/evolution`,
41-
"DATABASE_SAVE_DATA_INSTANCE=true",
42-
"DATABASE_SAVE_DATA_NEW_MESSAGE=true",
43-
"DATABASE_SAVE_MESSAGE_UPDATE=true",
44-
"DATABASE_SAVE_DATA_CONTACTS=true",
45-
"DATABASE_SAVE_DATA_CHATS=true",
46-
"DATABASE_SAVE_DATA_LABELS=true",
47-
"DATABASE_SAVE_DATA_HISTORIC=true",
35+
"POSTGRES_DATABASE=evolution",
36+
"POSTGRES_USERNAME=postgresql",
37+
`POSTGRES_PASSWORD=${postgresPassword}`,
38+
"DATABASE_ENABLED=true",
39+
"DATABASE_PROVIDER=postgresql",
40+
`DATABASE_CONNECTION_URI=postgres://postgresql:${postgresPassword}@evolution-postgres:5432/evolution`,
41+
"DATABASE_SAVE_DATA_INSTANCE=true",
42+
"DATABASE_SAVE_DATA_NEW_MESSAGE=true",
43+
"DATABASE_SAVE_MESSAGE_UPDATE=true",
44+
"DATABASE_SAVE_DATA_CONTACTS=true",
45+
"DATABASE_SAVE_DATA_CHATS=true",
46+
"DATABASE_SAVE_DATA_LABELS=true",
47+
"DATABASE_SAVE_DATA_HISTORIC=true",
4848

49-
"CACHE_REDIS_ENABLED=true",
50-
"CACHE_REDIS_URI=redis://evolution-redis:6379",
51-
"CACHE_REDIS_PREFIX_KEY=evolution",
52-
"CACHE_REDIS_SAVE_INSTANCES=true",
53-
];
49+
"CACHE_REDIS_ENABLED=true",
50+
"CACHE_REDIS_URI=redis://evolution-redis:6379",
51+
"CACHE_REDIS_PREFIX_KEY=evolution",
52+
"CACHE_REDIS_SAVE_INSTANCES=true",
53+
];
5454

55-
return {
56-
domains,
57-
envs,
58-
};
55+
return {
56+
domains,
57+
envs,
58+
};
5959
}

apps/dokploy/templates/formbricks/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export function generate(schema: Schema): Template {
2626
`NEXTAUTH_SECRET=${secretBase}`,
2727
`ENCRYPTION_KEY=${encryptionKey}`,
2828
`CRON_SECRET=${cronSecret}`,
29-
3029
];
3130

3231
const mounts: Template["mounts"] = [];

apps/dokploy/templates/listmonk/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function generate(schema: Schema): Template {
1717
];
1818

1919
const envs = [
20-
`# visit the page to setup your super admin user`,
20+
"# visit the page to setup your super admin user",
2121
"# check config.toml in Advanced / Volumes for more options",
2222
];
2323

packages/server/src/services/compose.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,17 @@ export const stopCompose = async (composeId: string) => {
558558
}
559559
}
560560

561+
if (compose.composeType === "stack") {
562+
if (compose.serverId) {
563+
await execAsyncRemote(
564+
compose.serverId,
565+
`docker stack rm ${compose.appName}`,
566+
);
567+
} else {
568+
await execAsync(`docker stack rm ${compose.appName}`);
569+
}
570+
}
571+
561572
await updateCompose(composeId, {
562573
composeStatus: "idle",
563574
});

packages/server/src/utils/builders/compose.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
createWriteStream,
33
existsSync,
44
mkdirSync,
5+
readFileSync,
56
writeFileSync,
67
} from "node:fs";
78
import { dirname, join } from "node:path";
@@ -12,8 +13,12 @@ import {
1213
writeDomainsToCompose,
1314
writeDomainsToComposeRemote,
1415
} from "../docker/domain";
15-
import { encodeBase64, prepareEnvironmentVariables } from "../docker/utils";
16-
import { execAsyncRemote } from "../process/execAsync";
16+
import {
17+
encodeBase64,
18+
getEnviromentVariablesObject,
19+
prepareEnvironmentVariables,
20+
} from "../docker/utils";
21+
import { execAsync, execAsyncRemote } from "../process/execAsync";
1722
import { spawnAsync } from "../process/spawnAsync";
1823

1924
export type ComposeNested = InferResultType<
@@ -30,12 +35,12 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
3035
createEnvFile(compose);
3136

3237
const logContent = `
33-
App Name: ${appName}
34-
Build Compose 🐳
35-
Detected: ${mounts.length} mounts 📂
36-
Command: docker ${command}
37-
Source Type: docker ${sourceType}
38-
Compose Type: ${composeType} ✅`;
38+
App Name: ${appName}
39+
Build Compose 🐳
40+
Detected: ${mounts.length} mounts 📂
41+
Command: docker ${command}
42+
Source Type: docker ${sourceType}
43+
Compose Type: ${composeType} ✅`;
3944
const logBox = boxen(logContent, {
4045
padding: {
4146
left: 1,
@@ -46,7 +51,6 @@ Compose Type: ${composeType} ✅`;
4651
borderStyle: "double",
4752
});
4853
writeStream.write(`\n${logBox}\n`);
49-
5054
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
5155

5256
await spawnAsync(
@@ -62,6 +66,9 @@ Compose Type: ${composeType} ✅`;
6266
env: {
6367
NODE_ENV: process.env.NODE_ENV,
6468
PATH: process.env.PATH,
69+
...(composeType === "stack" && {
70+
...getEnviromentVariablesObject(compose.env, compose.project.env),
71+
}),
6572
},
6673
},
6774
);
@@ -85,6 +92,7 @@ export const getBuildComposeCommand = async (
8592
const command = createCommand(compose);
8693
const envCommand = getCreateEnvFileCommand(compose);
8794
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
95+
const exportEnvCommand = getExportEnvCommand(compose);
8896

8997
const newCompose = await writeDomainsToComposeRemote(
9098
compose,
@@ -120,6 +128,8 @@ Compose Type: ${composeType} ✅`;
120128
121129
cd "${projectPath}";
122130
131+
${exportEnvCommand}
132+
123133
docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; }
124134
125135
echo "Docker Compose Deployed: ✅" >> "${logPath}"
@@ -153,9 +163,7 @@ export const createCommand = (compose: ComposeNested) => {
153163
sourceType === "raw" ? "docker-compose.yml" : compose.composePath;
154164
let command = "";
155165

156-
if (composeType === "docker-compose") {
157-
command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`;
158-
} else if (composeType === "stack") {
166+
if (composeType === "stack") {
159167
command = `stack deploy -c ${path} ${appName} --prune`;
160168
}
161169

@@ -219,3 +227,17 @@ touch ${envFilePath};
219227
echo "${encodedContent}" | base64 -d > "${envFilePath}";
220228
`;
221229
};
230+
231+
const getExportEnvCommand = (compose: ComposeNested) => {
232+
if (compose.composeType !== "stack") return "";
233+
234+
const envVars = getEnviromentVariablesObject(
235+
compose.env,
236+
compose.project.env,
237+
);
238+
const exports = Object.entries(envVars)
239+
.map(([key, value]) => `export ${key}=${JSON.stringify(value)}`)
240+
.join("\n");
241+
242+
return exports ? `\n# Export environment variables\n${exports}\n` : "";
243+
};

packages/server/src/utils/docker/utils.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,12 +278,15 @@ export const prepareEnvironmentVariables = (
278278
return resolvedVars;
279279
};
280280

281-
export const prepareBuildArgs = (input: string | null) => {
282-
const pairs = (input ?? "").split("\n");
281+
export const getEnviromentVariablesObject = (
282+
input: string | null,
283+
projectEnv?: string | null,
284+
) => {
285+
const envs = prepareEnvironmentVariables(input, projectEnv);
283286

284287
const jsonObject: Record<string, string> = {};
285288

286-
for (const pair of pairs) {
289+
for (const pair of envs) {
287290
const [key, value] = pair.split("=");
288291
if (key && value) {
289292
jsonObject[key] = value;

0 commit comments

Comments
 (0)