mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Compare commits
1 Commits
fix/issues
...
407-featur
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7f44f65bc |
@@ -11,6 +11,7 @@ import { z } from "zod";
|
|||||||
const addEnvironmentSchema = z.object({
|
const addEnvironmentSchema = z.object({
|
||||||
env: z.string(),
|
env: z.string(),
|
||||||
buildArgs: z.string(),
|
buildArgs: z.string(),
|
||||||
|
buildSecrets: z.record(z.string(), z.string()),
|
||||||
});
|
});
|
||||||
|
|
||||||
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
|
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
|
||||||
@@ -36,6 +37,7 @@ export const ShowEnvironment = ({ applicationId }: Props) => {
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
env: data?.env || "",
|
env: data?.env || "",
|
||||||
buildArgs: data?.buildArgs || "",
|
buildArgs: data?.buildArgs || "",
|
||||||
|
buildSecrets: data?.buildSecrets || {},
|
||||||
},
|
},
|
||||||
resolver: zodResolver(addEnvironmentSchema),
|
resolver: zodResolver(addEnvironmentSchema),
|
||||||
});
|
});
|
||||||
@@ -44,6 +46,7 @@ export const ShowEnvironment = ({ applicationId }: Props) => {
|
|||||||
mutateAsync({
|
mutateAsync({
|
||||||
env: data.env,
|
env: data.env,
|
||||||
buildArgs: data.buildArgs,
|
buildArgs: data.buildArgs,
|
||||||
|
buildSecrets: data.buildSecrets,
|
||||||
applicationId,
|
applicationId,
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
@@ -69,25 +72,63 @@ export const ShowEnvironment = ({ applicationId }: Props) => {
|
|||||||
placeholder={["NODE_ENV=production", "PORT=3000"].join("\n")}
|
placeholder={["NODE_ENV=production", "PORT=3000"].join("\n")}
|
||||||
/>
|
/>
|
||||||
{data?.buildType === "dockerfile" && (
|
{data?.buildType === "dockerfile" && (
|
||||||
<Secrets
|
<>
|
||||||
name="buildArgs"
|
<Secrets
|
||||||
title="Build-time Variables"
|
name="buildArgs"
|
||||||
description={
|
title="Build-time Variables"
|
||||||
<span>
|
description={
|
||||||
Available only at build-time. See documentation
|
<span>
|
||||||
<a
|
Available only at build-time. See documentation
|
||||||
className="text-primary"
|
<a
|
||||||
href="https://docs.docker.com/build/guide/build-args/"
|
className="text-primary"
|
||||||
target="_blank"
|
href="https://docs.docker.com/build/guide/build-args/"
|
||||||
rel="noopener noreferrer"
|
target="_blank"
|
||||||
>
|
rel="noopener noreferrer"
|
||||||
here
|
>
|
||||||
</a>
|
here
|
||||||
.
|
</a>
|
||||||
</span>
|
.
|
||||||
}
|
</span>
|
||||||
placeholder="NPM_TOKEN=xyz"
|
}
|
||||||
/>
|
placeholder="NPM_TOKEN=xyz"
|
||||||
|
/>
|
||||||
|
<Secrets
|
||||||
|
name="buildSecrets"
|
||||||
|
title="Build Secrets"
|
||||||
|
description={
|
||||||
|
<span>
|
||||||
|
Secrets available only during build-time and not in the
|
||||||
|
final image. See documentation
|
||||||
|
<a
|
||||||
|
className="text-primary"
|
||||||
|
href="https://docs.docker.com/build/building/secrets/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
here
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
placeholder="API_TOKEN=xyz"
|
||||||
|
transformValue={(value) => {
|
||||||
|
// Convert the string format to object
|
||||||
|
const lines = value.split("\n").filter((line) => line.trim());
|
||||||
|
return Object.fromEntries(
|
||||||
|
lines.map((line) => {
|
||||||
|
const [key, ...valueParts] = line.split("=");
|
||||||
|
return [key.trim(), valueParts.join("=").trim()];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
formatValue={(value) => {
|
||||||
|
// Convert the object back to string format
|
||||||
|
return Object.entries(value as Record<string, string>)
|
||||||
|
.map(([key, val]) => `${key}=${val}`)
|
||||||
|
.join("\n");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-row justify-end">
|
<div className="flex flex-row justify-end">
|
||||||
<Button isLoading={isLoading} className="w-fit" type="submit">
|
<Button isLoading={isLoading} className="w-fit" type="submit">
|
||||||
|
|||||||
2
apps/dokploy/drizzle/0072_milky_lyja.sql
Normal file
2
apps/dokploy/drizzle/0072_milky_lyja.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "application" ADD COLUMN "buildSecrets" text;--> statement-breakpoint
|
||||||
|
ALTER TABLE "user_temp" DROP COLUMN "enableLogRotation";
|
||||||
5131
apps/dokploy/drizzle/meta/0072_snapshot.json
Normal file
5131
apps/dokploy/drizzle/meta/0072_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -505,6 +505,13 @@
|
|||||||
"when": 1741460060541,
|
"when": 1741460060541,
|
||||||
"tag": "0071_flaky_black_queen",
|
"tag": "0071_flaky_black_queen",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 72,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741481694393,
|
||||||
|
"tag": "0072_milky_lyja",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -298,6 +298,7 @@ export const applicationRouter = createTRPCRouter({
|
|||||||
await updateApplication(input.applicationId, {
|
await updateApplication(input.applicationId, {
|
||||||
env: input.env,
|
env: input.env,
|
||||||
buildArgs: input.buildArgs,
|
buildArgs: input.buildArgs,
|
||||||
|
buildSecrets: input.buildSecrets,
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ export const applications = pgTable("application", {
|
|||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
buildArgs: text("buildArgs"),
|
buildArgs: text("buildArgs"),
|
||||||
|
buildSecrets: json("buildSecrets").$type<Record<string, string>>(),
|
||||||
memoryReservation: text("memoryReservation"),
|
memoryReservation: text("memoryReservation"),
|
||||||
memoryLimit: text("memoryLimit"),
|
memoryLimit: text("memoryLimit"),
|
||||||
cpuReservation: text("cpuReservation"),
|
cpuReservation: text("cpuReservation"),
|
||||||
@@ -353,6 +354,7 @@ const createSchema = createInsertSchema(applications, {
|
|||||||
autoDeploy: z.boolean(),
|
autoDeploy: z.boolean(),
|
||||||
env: z.string().optional(),
|
env: z.string().optional(),
|
||||||
buildArgs: z.string().optional(),
|
buildArgs: z.string().optional(),
|
||||||
|
buildSecrets: z.record(z.string(), z.string()).optional(),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
memoryReservation: z.string().optional(),
|
memoryReservation: z.string().optional(),
|
||||||
@@ -499,11 +501,12 @@ export const apiSaveGitProvider = createSchema
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const apiSaveEnvironmentVariables = createSchema
|
export const apiSaveEnvironmentVariables = z
|
||||||
.pick({
|
.object({
|
||||||
applicationId: true,
|
applicationId: z.string(),
|
||||||
env: true,
|
env: z.string().optional(),
|
||||||
buildArgs: true,
|
buildArgs: z.string().optional(),
|
||||||
|
buildSecrets: z.record(z.string(), z.string()).optional(),
|
||||||
})
|
})
|
||||||
.required();
|
.required();
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ table application {
|
|||||||
previewLimit integer [default: 3]
|
previewLimit integer [default: 3]
|
||||||
isPreviewDeploymentsActive boolean [default: false]
|
isPreviewDeploymentsActive boolean [default: false]
|
||||||
buildArgs text
|
buildArgs text
|
||||||
|
buildSecrets json
|
||||||
memoryReservation text
|
memoryReservation text
|
||||||
memoryLimit text
|
memoryLimit text
|
||||||
cpuReservation text
|
cpuReservation text
|
||||||
|
|||||||
@@ -12,8 +12,14 @@ export const buildCustomDocker = async (
|
|||||||
application: ApplicationNested,
|
application: ApplicationNested,
|
||||||
writeStream: WriteStream,
|
writeStream: WriteStream,
|
||||||
) => {
|
) => {
|
||||||
const { appName, env, publishDirectory, buildArgs, dockerBuildStage } =
|
const {
|
||||||
application;
|
appName,
|
||||||
|
env,
|
||||||
|
publishDirectory,
|
||||||
|
buildArgs,
|
||||||
|
buildSecrets,
|
||||||
|
dockerBuildStage,
|
||||||
|
} = application;
|
||||||
const dockerFilePath = getBuildAppDirectory(application);
|
const dockerFilePath = getBuildAppDirectory(application);
|
||||||
try {
|
try {
|
||||||
const image = `${appName}`;
|
const image = `${appName}`;
|
||||||
@@ -25,6 +31,10 @@ export const buildCustomDocker = async (
|
|||||||
application.project.env,
|
application.project.env,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const secrets = buildSecrets
|
||||||
|
? Object.entries(buildSecrets).map(([key, value]) => `${key}=${value}`)
|
||||||
|
: [];
|
||||||
|
|
||||||
const dockerContextPath = getDockerContextPath(application);
|
const dockerContextPath = getDockerContextPath(application);
|
||||||
|
|
||||||
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
|
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
|
||||||
@@ -36,6 +46,12 @@ export const buildCustomDocker = async (
|
|||||||
for (const arg of args) {
|
for (const arg of args) {
|
||||||
commandArgs.push("--build-arg", arg);
|
commandArgs.push("--build-arg", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const secret of secrets) {
|
||||||
|
const [key] = secret.split("=");
|
||||||
|
commandArgs.push("--secret", `id=${key},env=${key}`);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Do not generate an environment file when publishDirectory is specified,
|
Do not generate an environment file when publishDirectory is specified,
|
||||||
as it could be publicly exposed.
|
as it could be publicly exposed.
|
||||||
@@ -54,6 +70,10 @@ export const buildCustomDocker = async (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
cwd: dockerContextPath || defaultContextPath,
|
cwd: dockerContextPath || defaultContextPath,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
...Object.fromEntries(secrets.map((s) => s.split("="))),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -65,8 +85,14 @@ export const getDockerCommand = (
|
|||||||
application: ApplicationNested,
|
application: ApplicationNested,
|
||||||
logPath: string,
|
logPath: string,
|
||||||
) => {
|
) => {
|
||||||
const { appName, env, publishDirectory, buildArgs, dockerBuildStage } =
|
const {
|
||||||
application;
|
appName,
|
||||||
|
env,
|
||||||
|
publishDirectory,
|
||||||
|
buildArgs,
|
||||||
|
buildSecrets,
|
||||||
|
dockerBuildStage,
|
||||||
|
} = application;
|
||||||
const dockerFilePath = getBuildAppDirectory(application);
|
const dockerFilePath = getBuildAppDirectory(application);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -79,6 +105,10 @@ export const getDockerCommand = (
|
|||||||
application.project.env,
|
application.project.env,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const secrets = buildSecrets
|
||||||
|
? Object.entries(buildSecrets).map(([key, value]) => `${key}=${value}`)
|
||||||
|
: [];
|
||||||
|
|
||||||
const dockerContextPath =
|
const dockerContextPath =
|
||||||
getDockerContextPath(application) || defaultContextPath;
|
getDockerContextPath(application) || defaultContextPath;
|
||||||
|
|
||||||
@@ -92,6 +122,11 @@ export const getDockerCommand = (
|
|||||||
commandArgs.push("--build-arg", arg);
|
commandArgs.push("--build-arg", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const secret of secrets) {
|
||||||
|
const [key] = secret.split("=");
|
||||||
|
commandArgs.push("--secret", `id=${key},env=${key}`);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Do not generate an environment file when publishDirectory is specified,
|
Do not generate an environment file when publishDirectory is specified,
|
||||||
as it could be publicly exposed.
|
as it could be publicly exposed.
|
||||||
@@ -105,6 +140,14 @@ export const getDockerCommand = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export secrets as environment variables
|
||||||
|
if (secrets.length > 0) {
|
||||||
|
command += "\n# Export build secrets\n";
|
||||||
|
for (const secret of secrets) {
|
||||||
|
command += `export ${secret}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
command += `
|
command += `
|
||||||
echo "Building ${appName}" >> ${logPath};
|
echo "Building ${appName}" >> ${logPath};
|
||||||
cd ${dockerContextPath} >> ${logPath} 2>> ${logPath} || {
|
cd ${dockerContextPath} >> ${logPath} 2>> ${logPath} || {
|
||||||
|
|||||||
Reference in New Issue
Block a user