mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-18 13:45:23 +02:00
Users deploying to Docker Swarm can now configure resource ulimits (nofile, nproc, etc.) to prevent applications from hitting system limits that cause crashes or degraded performance.
188 lines
3.9 KiB
TypeScript
188 lines
3.9 KiB
TypeScript
import type { InferResultType } from "@dokploy/server/types/with";
|
|
import type { CreateServiceOptions } from "dockerode";
|
|
import {
|
|
calculateResources,
|
|
generateBindMounts,
|
|
generateConfigContainer,
|
|
generateFileMounts,
|
|
generateVolumeMounts,
|
|
prepareEnvironmentVariables,
|
|
} from "../docker/utils";
|
|
import { getRemoteDocker } from "../servers/remote-docker";
|
|
|
|
export type MongoNested = InferResultType<
|
|
"mongo",
|
|
{ mounts: true; environment: { with: { project: true } } }
|
|
>;
|
|
|
|
export const buildMongo = async (mongo: MongoNested) => {
|
|
const {
|
|
appName,
|
|
env,
|
|
externalPort,
|
|
dockerImage,
|
|
memoryLimit,
|
|
memoryReservation,
|
|
cpuLimit,
|
|
cpuReservation,
|
|
databaseUser,
|
|
databasePassword,
|
|
command,
|
|
args,
|
|
mounts,
|
|
replicaSets,
|
|
} = mongo;
|
|
|
|
const startupScript = `
|
|
#!/bin/bash
|
|
${
|
|
replicaSets
|
|
? `
|
|
mongod --port 27017 --replSet rs0 --bind_ip_all &
|
|
MONGOD_PID=$!
|
|
|
|
# Wait for MongoDB to be ready
|
|
while ! mongosh --eval "db.adminCommand('ping')" > /dev/null 2>&1; do
|
|
sleep 2
|
|
done
|
|
|
|
# Check if replica set is already initialized
|
|
REPLICA_STATUS=$(mongosh --quiet --eval "rs.status().ok || 0")
|
|
|
|
if [ "$REPLICA_STATUS" != "1" ]; then
|
|
echo "Initializing replica set..."
|
|
mongosh --eval '
|
|
rs.initiate({
|
|
_id: "rs0",
|
|
members: [{ _id: 0, host: "${appName}:27017", priority: 1 }]
|
|
});
|
|
|
|
// Wait for the replica set to initialize
|
|
while (!rs.isMaster().ismaster) {
|
|
sleep(1000);
|
|
}
|
|
|
|
// Create root user after replica set is initialized and we are primary
|
|
db.getSiblingDB("admin").createUser({
|
|
user: "${databaseUser}",
|
|
pwd: "${databasePassword}",
|
|
roles: ["root"]
|
|
});
|
|
'
|
|
|
|
else
|
|
echo "Replica set already initialized."
|
|
fi
|
|
`
|
|
: ""
|
|
}
|
|
|
|
${command ?? "wait $MONGOD_PID"}`;
|
|
|
|
const defaultMongoEnv = `MONGO_INITDB_ROOT_USERNAME="${databaseUser}"\nMONGO_INITDB_ROOT_PASSWORD="${databasePassword}"${replicaSets ? "\nMONGO_INITDB_DATABASE=admin" : ""}${
|
|
env ? `\n${env}` : ""
|
|
}`;
|
|
|
|
const {
|
|
HealthCheck,
|
|
RestartPolicy,
|
|
Placement,
|
|
Labels,
|
|
Mode,
|
|
RollbackConfig,
|
|
UpdateConfig,
|
|
Networks,
|
|
StopGracePeriod,
|
|
EndpointSpec,
|
|
Ulimits,
|
|
} = generateConfigContainer(mongo);
|
|
|
|
const resources = calculateResources({
|
|
memoryLimit,
|
|
memoryReservation,
|
|
cpuLimit,
|
|
cpuReservation,
|
|
});
|
|
|
|
const envVariables = prepareEnvironmentVariables(
|
|
defaultMongoEnv,
|
|
mongo.environment.project.env,
|
|
mongo.environment.env,
|
|
);
|
|
const volumesMount = generateVolumeMounts(mounts);
|
|
const bindsMount = generateBindMounts(mounts);
|
|
const filesMount = generateFileMounts(appName, mongo);
|
|
|
|
const docker = await getRemoteDocker(mongo.serverId);
|
|
|
|
const settings: CreateServiceOptions = {
|
|
Name: appName,
|
|
TaskTemplate: {
|
|
ContainerSpec: {
|
|
HealthCheck,
|
|
Image: dockerImage,
|
|
Env: envVariables,
|
|
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
|
...(StopGracePeriod !== null &&
|
|
StopGracePeriod !== undefined && { StopGracePeriod }),
|
|
...(replicaSets
|
|
? {
|
|
Command: ["/bin/bash"],
|
|
Args: ["-c", startupScript],
|
|
}
|
|
: {}),
|
|
...(command &&
|
|
!replicaSets && {
|
|
Command: command.split(" "),
|
|
}),
|
|
...(args &&
|
|
args.length > 0 &&
|
|
!replicaSets && {
|
|
Args: args,
|
|
}),
|
|
...(Ulimits && { Ulimits }),
|
|
Labels,
|
|
},
|
|
Networks,
|
|
RestartPolicy,
|
|
Placement,
|
|
Resources: {
|
|
...resources,
|
|
},
|
|
},
|
|
Mode,
|
|
RollbackConfig,
|
|
EndpointSpec: EndpointSpec
|
|
? EndpointSpec
|
|
: {
|
|
Mode: "dnsrr" as const,
|
|
Ports: externalPort
|
|
? [
|
|
{
|
|
Protocol: "tcp" as const,
|
|
TargetPort: 27017,
|
|
PublishedPort: externalPort,
|
|
PublishMode: "host" as const,
|
|
},
|
|
]
|
|
: [],
|
|
},
|
|
UpdateConfig,
|
|
};
|
|
|
|
try {
|
|
const service = docker.getService(appName);
|
|
const inspect = await service.inspect();
|
|
await service.update({
|
|
version: Number.parseInt(inspect.Version.Index),
|
|
...settings,
|
|
TaskTemplate: {
|
|
...settings.TaskTemplate,
|
|
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
|
},
|
|
});
|
|
} catch {
|
|
await docker.createService(settings);
|
|
}
|
|
};
|