mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-25 07:45:22 +02:00
Merge branch 'canary' into fix/docker-cleanup-clears-away-all-unused-residue
This commit is contained in:
@@ -62,16 +62,16 @@ export const getS3Credentials = (destination: Destination) => {
|
||||
const { accessKey, secretAccessKey, region, endpoint, provider } =
|
||||
destination;
|
||||
const rcloneFlags = [
|
||||
`--s3-access-key-id=${accessKey}`,
|
||||
`--s3-secret-access-key=${secretAccessKey}`,
|
||||
`--s3-region=${region}`,
|
||||
`--s3-endpoint=${endpoint}`,
|
||||
`--s3-access-key-id="${accessKey}"`,
|
||||
`--s3-secret-access-key="${secretAccessKey}"`,
|
||||
`--s3-region="${region}"`,
|
||||
`--s3-endpoint="${endpoint}"`,
|
||||
"--s3-no-check-bucket",
|
||||
"--s3-force-path-style",
|
||||
];
|
||||
|
||||
if (provider) {
|
||||
rcloneFlags.unshift(`--s3-provider=${provider}`);
|
||||
rcloneFlags.unshift(`--s3-provider="${provider}"`);
|
||||
}
|
||||
|
||||
return rcloneFlags;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { InferResultType } from "@dokploy/server/types/with";
|
||||
import type { CreateServiceOptions } from "dockerode";
|
||||
import { uploadImageRemoteCommand } from "../cluster/upload";
|
||||
import { getRegistryTag, uploadImageRemoteCommand } from "../cluster/upload";
|
||||
import {
|
||||
calculateResources,
|
||||
generateBindMounts,
|
||||
@@ -29,39 +29,46 @@ export type ApplicationNested = InferResultType<
|
||||
redirects: true;
|
||||
ports: true;
|
||||
registry: true;
|
||||
buildRegistry: true;
|
||||
rollbackRegistry: true;
|
||||
deployments: true;
|
||||
environment: { with: { project: true } };
|
||||
}
|
||||
>;
|
||||
|
||||
export const getBuildCommand = (application: ApplicationNested) => {
|
||||
export const getBuildCommand = async (application: ApplicationNested) => {
|
||||
let command = "";
|
||||
const { buildType, registry } = application;
|
||||
|
||||
if (application.sourceType === "docker") {
|
||||
return "";
|
||||
if (application.sourceType !== "docker") {
|
||||
const { buildType } = application;
|
||||
switch (buildType) {
|
||||
case "nixpacks":
|
||||
command = getNixpacksCommand(application);
|
||||
break;
|
||||
case "heroku_buildpacks":
|
||||
command = getHerokuCommand(application);
|
||||
break;
|
||||
case "paketo_buildpacks":
|
||||
command = getPaketoCommand(application);
|
||||
break;
|
||||
case "static":
|
||||
command = getStaticCommand(application);
|
||||
break;
|
||||
case "dockerfile":
|
||||
command = getDockerCommand(application);
|
||||
break;
|
||||
case "railpack":
|
||||
command = getRailpackCommand(application);
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (buildType) {
|
||||
case "nixpacks":
|
||||
command = getNixpacksCommand(application);
|
||||
break;
|
||||
case "heroku_buildpacks":
|
||||
command = getHerokuCommand(application);
|
||||
break;
|
||||
case "paketo_buildpacks":
|
||||
command = getPaketoCommand(application);
|
||||
break;
|
||||
case "static":
|
||||
command = getStaticCommand(application);
|
||||
break;
|
||||
case "dockerfile":
|
||||
command = getDockerCommand(application);
|
||||
break;
|
||||
case "railpack":
|
||||
command = getRailpackCommand(application);
|
||||
break;
|
||||
}
|
||||
if (registry) {
|
||||
command += uploadImageRemoteCommand(application);
|
||||
|
||||
if (
|
||||
application.registry ||
|
||||
application.buildRegistry ||
|
||||
application.rollbackRegistry
|
||||
) {
|
||||
command += await uploadImageRemoteCommand(application);
|
||||
}
|
||||
|
||||
return command;
|
||||
@@ -79,6 +86,7 @@ export const mechanizeDockerContainer = async (
|
||||
memoryReservation,
|
||||
cpuReservation,
|
||||
command,
|
||||
args,
|
||||
ports,
|
||||
} = application;
|
||||
|
||||
@@ -125,12 +133,16 @@ export const mechanizeDockerContainer = async (
|
||||
Image: image,
|
||||
Env: envVariables,
|
||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||
...(command
|
||||
? {
|
||||
Command: ["/bin/sh"],
|
||||
Args: ["-c", command],
|
||||
}
|
||||
: {}),
|
||||
...(StopGracePeriod !== null &&
|
||||
StopGracePeriod !== undefined && { StopGracePeriod }),
|
||||
...(command && {
|
||||
Command: command.split(" "),
|
||||
}),
|
||||
...(args &&
|
||||
args.length > 0 && {
|
||||
Args: args,
|
||||
}),
|
||||
|
||||
Labels,
|
||||
},
|
||||
Networks,
|
||||
@@ -153,8 +165,6 @@ export const mechanizeDockerContainer = async (
|
||||
})),
|
||||
},
|
||||
UpdateConfig,
|
||||
...(StopGracePeriod !== undefined &&
|
||||
StopGracePeriod !== null && { StopGracePeriod }),
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -169,23 +179,26 @@ export const mechanizeDockerContainer = async (
|
||||
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
await docker.createService(settings);
|
||||
}
|
||||
};
|
||||
|
||||
const getImageName = (application: ApplicationNested) => {
|
||||
const { appName, sourceType, dockerImage, registry } = application;
|
||||
const { appName, sourceType, dockerImage, registry, buildRegistry } =
|
||||
application;
|
||||
const imageName = `${appName}:latest`;
|
||||
if (sourceType === "docker") {
|
||||
return dockerImage || "ERROR-NO-IMAGE-PROVIDED";
|
||||
}
|
||||
|
||||
if (registry) {
|
||||
const { registryUrl, imagePrefix, username } = registry;
|
||||
const registryTag = imagePrefix
|
||||
? `${registryUrl ? `${registryUrl}/` : ""}${imagePrefix}/${imageName}`
|
||||
: `${registryUrl ? `${registryUrl}/` : ""}${username}/${imageName}`;
|
||||
const registryTag = getRegistryTag(registry, imageName);
|
||||
return registryTag;
|
||||
}
|
||||
if (buildRegistry) {
|
||||
const registryTag = getRegistryTag(buildRegistry, imageName);
|
||||
return registryTag;
|
||||
}
|
||||
|
||||
@@ -193,7 +206,14 @@ const getImageName = (application: ApplicationNested) => {
|
||||
};
|
||||
|
||||
export const getAuthConfig = (application: ApplicationNested) => {
|
||||
const { registry, username, password, sourceType, registryUrl } = application;
|
||||
const {
|
||||
registry,
|
||||
buildRegistry,
|
||||
username,
|
||||
password,
|
||||
sourceType,
|
||||
registryUrl,
|
||||
} = application;
|
||||
|
||||
if (sourceType === "docker") {
|
||||
if (username && password) {
|
||||
@@ -209,6 +229,12 @@ export const getAuthConfig = (application: ApplicationNested) => {
|
||||
username: registry.username,
|
||||
serveraddress: registry.registryUrl,
|
||||
};
|
||||
} else if (buildRegistry) {
|
||||
return {
|
||||
password: buildRegistry.password,
|
||||
username: buildRegistry.username,
|
||||
serveraddress: buildRegistry.registryUrl,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -1,44 +1,107 @@
|
||||
import { findAllDeploymentsByApplicationId } from "@dokploy/server/services/deployment";
|
||||
import type { Registry } from "@dokploy/server/services/registry";
|
||||
import { createRollback } from "@dokploy/server/services/rollbacks";
|
||||
import type { ApplicationNested } from "../builders";
|
||||
|
||||
export const uploadImageRemoteCommand = (application: ApplicationNested) => {
|
||||
export const uploadImageRemoteCommand = async (
|
||||
application: ApplicationNested,
|
||||
) => {
|
||||
const registry = application.registry;
|
||||
const buildRegistry = application.buildRegistry;
|
||||
const rollbackRegistry = application.rollbackRegistry;
|
||||
|
||||
if (!registry) {
|
||||
throw new Error("Registry not found");
|
||||
if (!registry && !buildRegistry && !rollbackRegistry) {
|
||||
throw new Error("No registry found");
|
||||
}
|
||||
|
||||
const { registryUrl, imagePrefix, username } = registry;
|
||||
const { appName } = application;
|
||||
const imageName = `${appName}:latest`;
|
||||
const imageName =
|
||||
application.sourceType === "docker"
|
||||
? application.dockerImage || ""
|
||||
: `${appName}:latest`;
|
||||
|
||||
const finalURL = registryUrl;
|
||||
const commands: string[] = [];
|
||||
if (registry) {
|
||||
const registryTag = getRegistryTag(registry, imageName);
|
||||
if (registryTag) {
|
||||
commands.push(`echo "📦 [Enabled Registry Swarm]"`);
|
||||
commands.push(getRegistryCommands(registry, imageName, registryTag));
|
||||
}
|
||||
}
|
||||
if (buildRegistry) {
|
||||
const buildRegistryTag = getRegistryTag(buildRegistry, imageName);
|
||||
if (buildRegistryTag) {
|
||||
commands.push(`echo "🔑 [Enabled Build Registry]"`);
|
||||
commands.push(
|
||||
getRegistryCommands(buildRegistry, imageName, buildRegistryTag),
|
||||
);
|
||||
commands.push(
|
||||
`echo "⚠️ INFO: After the build is finished, you need to wait a few seconds for the server to download the image and run the container."`,
|
||||
);
|
||||
commands.push(
|
||||
`echo "📊 Check the Logs tab to see when the container starts running."`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Build registry tag in correct format: registry.com/owner/image:tag
|
||||
const registryTag = imagePrefix
|
||||
? `${registryUrl ? `${registryUrl}/` : ""}${imagePrefix}/${imageName}`
|
||||
: `${registryUrl ? `${registryUrl}/` : ""}${username}/${imageName}`;
|
||||
if (rollbackRegistry && application.rollbackActive) {
|
||||
const deployment = await findAllDeploymentsByApplicationId(
|
||||
application.applicationId,
|
||||
);
|
||||
if (!deployment || !deployment[0]) {
|
||||
throw new Error("Deployment not found");
|
||||
}
|
||||
const deploymentId = deployment[0].deploymentId;
|
||||
const rollback = await createRollback({
|
||||
appName: appName,
|
||||
deploymentId: deploymentId,
|
||||
});
|
||||
|
||||
const rollbackRegistryTag = getRegistryTag(
|
||||
rollbackRegistry,
|
||||
rollback?.image || "",
|
||||
);
|
||||
if (rollbackRegistryTag) {
|
||||
commands.push(`echo "🔄 [Enabled Rollback Registry]"`);
|
||||
commands.push(
|
||||
getRegistryCommands(rollbackRegistry, imageName, rollbackRegistryTag),
|
||||
);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const command = `
|
||||
echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" ;
|
||||
echo "${registry.password}" | docker login ${finalURL} -u ${registry.username} --password-stdin || {
|
||||
echo "❌ DockerHub Failed" ;
|
||||
exit 1;
|
||||
}
|
||||
echo "✅ Registry Login Success" ;
|
||||
docker tag ${imageName} ${registryTag} || {
|
||||
echo "❌ Error tagging image" ;
|
||||
exit 1;
|
||||
}
|
||||
echo "✅ Image Tagged" ;
|
||||
docker push ${registryTag} || {
|
||||
echo "❌ Error pushing image" ;
|
||||
exit 1;
|
||||
}
|
||||
echo "✅ Image Pushed" ;
|
||||
`;
|
||||
return command;
|
||||
return commands.join("\n");
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
export const getRegistryTag = (registry: Registry, imageName: string) => {
|
||||
const { registryUrl, imagePrefix, username } = registry;
|
||||
return imagePrefix
|
||||
? `${registryUrl ? `${registryUrl}/` : ""}${imagePrefix}/${imageName}`
|
||||
: `${registryUrl ? `${registryUrl}/` : ""}${username}/${imageName}`;
|
||||
};
|
||||
|
||||
const getRegistryCommands = (
|
||||
registry: Registry,
|
||||
imageName: string,
|
||||
registryTag: string,
|
||||
): string => {
|
||||
return `
|
||||
echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" ;
|
||||
echo "${registry.password}" | docker login ${registry.registryUrl} -u ${registry.username} --password-stdin || {
|
||||
echo "❌ DockerHub Failed" ;
|
||||
exit 1;
|
||||
}
|
||||
echo "✅ Registry Login Success" ;
|
||||
docker tag ${imageName} ${registryTag} || {
|
||||
echo "❌ Error tagging image" ;
|
||||
exit 1;
|
||||
}
|
||||
echo "✅ Image Tagged" ;
|
||||
docker push ${registryTag} || {
|
||||
echo "❌ Error pushing image" ;
|
||||
exit 1;
|
||||
}
|
||||
echo "✅ Image Pushed" ;
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
||||
cpuLimit,
|
||||
cpuReservation,
|
||||
command,
|
||||
args,
|
||||
mounts,
|
||||
} = mariadb;
|
||||
|
||||
@@ -73,12 +74,16 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
||||
Image: dockerImage,
|
||||
Env: envVariables,
|
||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||
...(command
|
||||
? {
|
||||
Command: ["/bin/sh"],
|
||||
Args: ["-c", command],
|
||||
}
|
||||
: {}),
|
||||
...(StopGracePeriod !== null &&
|
||||
StopGracePeriod !== undefined && { StopGracePeriod }),
|
||||
...(command && {
|
||||
Command: command.split(" "),
|
||||
}),
|
||||
...(args &&
|
||||
args.length > 0 && {
|
||||
Args: args,
|
||||
}),
|
||||
|
||||
Labels,
|
||||
},
|
||||
Networks,
|
||||
@@ -106,8 +111,6 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
||||
: [],
|
||||
},
|
||||
UpdateConfig,
|
||||
...(StopGracePeriod !== undefined &&
|
||||
StopGracePeriod !== null && { StopGracePeriod }),
|
||||
};
|
||||
try {
|
||||
const service = docker.getService(appName);
|
||||
|
||||
@@ -28,6 +28,7 @@ export const buildMongo = async (mongo: MongoNested) => {
|
||||
databaseUser,
|
||||
databasePassword,
|
||||
command,
|
||||
args,
|
||||
mounts,
|
||||
replicaSets,
|
||||
} = mongo;
|
||||
@@ -121,17 +122,24 @@ ${command ?? "wait $MONGOD_PID"}`;
|
||||
Image: dockerImage,
|
||||
Env: envVariables,
|
||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||
...(StopGracePeriod !== null &&
|
||||
StopGracePeriod !== undefined && { StopGracePeriod }),
|
||||
...(replicaSets
|
||||
? {
|
||||
Command: ["/bin/bash"],
|
||||
Args: ["-c", startupScript],
|
||||
}
|
||||
: {
|
||||
...(command && {
|
||||
Command: ["/bin/bash"],
|
||||
Args: ["-c", command],
|
||||
}),
|
||||
}),
|
||||
: {}),
|
||||
...(command &&
|
||||
!replicaSets && {
|
||||
Command: command.split(" "),
|
||||
}),
|
||||
...(args &&
|
||||
args.length > 0 &&
|
||||
!replicaSets && {
|
||||
Args: args,
|
||||
}),
|
||||
|
||||
Labels,
|
||||
},
|
||||
Networks,
|
||||
@@ -159,8 +167,6 @@ ${command ?? "wait $MONGOD_PID"}`;
|
||||
: [],
|
||||
},
|
||||
UpdateConfig,
|
||||
...(StopGracePeriod !== undefined &&
|
||||
StopGracePeriod !== null && { StopGracePeriod }),
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
@@ -30,6 +30,7 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
||||
cpuLimit,
|
||||
cpuReservation,
|
||||
command,
|
||||
args,
|
||||
mounts,
|
||||
} = mysql;
|
||||
|
||||
@@ -79,12 +80,16 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
||||
Image: dockerImage,
|
||||
Env: envVariables,
|
||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||
...(command
|
||||
? {
|
||||
Command: ["/bin/sh"],
|
||||
Args: ["-c", command],
|
||||
}
|
||||
: {}),
|
||||
...(StopGracePeriod !== null &&
|
||||
StopGracePeriod !== undefined && { StopGracePeriod }),
|
||||
...(command && {
|
||||
Command: command.split(" "),
|
||||
}),
|
||||
...(args &&
|
||||
args.length > 0 && {
|
||||
Args: args,
|
||||
}),
|
||||
|
||||
Labels,
|
||||
},
|
||||
Networks,
|
||||
@@ -112,8 +117,6 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
||||
: [],
|
||||
},
|
||||
UpdateConfig,
|
||||
...(StopGracePeriod !== undefined &&
|
||||
StopGracePeriod !== null && { StopGracePeriod }),
|
||||
};
|
||||
try {
|
||||
const service = docker.getService(appName);
|
||||
|
||||
@@ -28,6 +28,7 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
||||
databaseUser,
|
||||
databasePassword,
|
||||
command,
|
||||
args,
|
||||
mounts,
|
||||
} = postgres;
|
||||
|
||||
@@ -72,12 +73,16 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
||||
Image: dockerImage,
|
||||
Env: envVariables,
|
||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||
...(command
|
||||
? {
|
||||
Command: ["/bin/sh"],
|
||||
Args: ["-c", command],
|
||||
}
|
||||
: {}),
|
||||
...(StopGracePeriod !== null &&
|
||||
StopGracePeriod !== undefined && { StopGracePeriod }),
|
||||
...(command && {
|
||||
Command: command.split(" "),
|
||||
}),
|
||||
...(args &&
|
||||
args.length > 0 && {
|
||||
Args: args,
|
||||
}),
|
||||
|
||||
Labels,
|
||||
},
|
||||
Networks,
|
||||
@@ -105,8 +110,6 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
||||
: [],
|
||||
},
|
||||
UpdateConfig,
|
||||
...(StopGracePeriod !== undefined &&
|
||||
StopGracePeriod !== null && { StopGracePeriod }),
|
||||
};
|
||||
try {
|
||||
const service = docker.getService(appName);
|
||||
|
||||
@@ -26,6 +26,7 @@ export const buildRedis = async (redis: RedisNested) => {
|
||||
cpuLimit,
|
||||
cpuReservation,
|
||||
command,
|
||||
args,
|
||||
mounts,
|
||||
} = redis;
|
||||
|
||||
@@ -70,11 +71,22 @@ export const buildRedis = async (redis: RedisNested) => {
|
||||
Image: dockerImage,
|
||||
Env: envVariables,
|
||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||
Command: ["/bin/sh"],
|
||||
Args: [
|
||||
"-c",
|
||||
command ? command : `redis-server --requirepass ${databasePassword}`,
|
||||
],
|
||||
...(StopGracePeriod !== null &&
|
||||
StopGracePeriod !== undefined && { StopGracePeriod }),
|
||||
...(command || args
|
||||
? {
|
||||
...(command && {
|
||||
Command: command.split(" "),
|
||||
}),
|
||||
...(args &&
|
||||
args.length > 0 && {
|
||||
Args: args,
|
||||
}),
|
||||
}
|
||||
: {
|
||||
Command: ["/bin/sh"],
|
||||
Args: ["-c", `redis-server --requirepass ${databasePassword}`],
|
||||
}),
|
||||
Labels,
|
||||
},
|
||||
Networks,
|
||||
@@ -102,8 +114,6 @@ export const buildRedis = async (redis: RedisNested) => {
|
||||
: [],
|
||||
},
|
||||
UpdateConfig,
|
||||
...(StopGracePeriod !== undefined &&
|
||||
StopGracePeriod !== null && { StopGracePeriod }),
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
@@ -159,7 +159,9 @@ export const sendNtfyNotification = async (
|
||||
const response = await fetch(`${connection.serverUrl}/${connection.topic}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${connection.accessToken}`,
|
||||
...(connection.accessToken && {
|
||||
Authorization: `Bearer ${connection.accessToken}`,
|
||||
}),
|
||||
"X-Priority": connection.priority?.toString() || "3",
|
||||
"X-Title": title,
|
||||
"X-Tags": tags,
|
||||
|
||||
Reference in New Issue
Block a user