mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-09-14 02:56:13 +05:00
fix: deploy monitoring as a swarm service instead of a standalone container (#5055)
Monitoring was the only component still using docker.createContainer directly instead of docker.createService like every other Dokploy component (postgres, traefik, forward-auth, etc). This meant it never benefited from Swarm's own reconciliation, relying only on Docker's restart policy with no self-healing if the daemon didn't come back cleanly after a reboot. Also removed the try/catch that silently swallowed setup errors, which made the UI report success even when the container/service failed to start.
This commit is contained in:
parent
f12ecc3350
commit
3848fa9c0d
@ -1,16 +1,13 @@
|
||||
import { findServerById } from "@dokploy/server/services/server";
|
||||
import { getWebServerSettings } from "@dokploy/server/services/web-server-settings";
|
||||
import type { ContainerCreateOptions } from "dockerode";
|
||||
import type { CreateServiceOptions } from "dockerode";
|
||||
import { IS_CLOUD } from "../constants";
|
||||
import { getDokployImageTag } from "../services/settings";
|
||||
import { pullImage, pullRemoteImage } from "../utils/docker/utils";
|
||||
import { execAsync, execAsyncRemote } from "../utils/process/execAsync";
|
||||
import { getRemoteDocker } from "../utils/servers/remote-docker";
|
||||
|
||||
export const setupMonitoring = async (serverId: string) => {
|
||||
const server = await findServerById(serverId);
|
||||
|
||||
const containerName = "dokploy-monitoring";
|
||||
const getMonitoringImage = () => {
|
||||
let imageName = "dokploy/monitoring:latest";
|
||||
|
||||
if (
|
||||
@ -21,134 +18,174 @@ export const setupMonitoring = async (serverId: string) => {
|
||||
imageName = "dokploy/monitoring:canary";
|
||||
}
|
||||
|
||||
const settings: ContainerCreateOptions = {
|
||||
name: containerName,
|
||||
Env: [`METRICS_CONFIG=${JSON.stringify(server?.metricsConfig)}`],
|
||||
Image: imageName,
|
||||
HostConfig: {
|
||||
// Memory: 100 * 1024 * 1024, // 100MB en bytes
|
||||
// PidMode: "host",
|
||||
// CapAdd: ["NET_ADMIN", "SYS_ADMIN"],
|
||||
// Privileged: true,
|
||||
RestartPolicy: {
|
||||
Name: "always",
|
||||
return imageName;
|
||||
};
|
||||
|
||||
const deployMonitoringService = async (
|
||||
docker: Awaited<ReturnType<typeof getRemoteDocker>>,
|
||||
serviceName: string,
|
||||
settings: CreateServiceOptions,
|
||||
) => {
|
||||
try {
|
||||
const service = docker.getService(serviceName);
|
||||
const inspect = await service.inspect();
|
||||
await service.update({
|
||||
version: Number.parseInt(inspect.Version.Index),
|
||||
...settings,
|
||||
TaskTemplate: {
|
||||
...settings.TaskTemplate,
|
||||
ForceUpdate: (inspect.Spec.TaskTemplate.ForceUpdate ?? 0) + 1,
|
||||
},
|
||||
PortBindings: {
|
||||
[`${server.metricsConfig.server.port}/tcp`]: [
|
||||
});
|
||||
console.log("Monitoring Updated ✅");
|
||||
} catch (error: any) {
|
||||
if (error?.statusCode && error.statusCode !== 404) {
|
||||
throw error;
|
||||
}
|
||||
await docker.createService(settings);
|
||||
console.log("Monitoring Started ✅");
|
||||
}
|
||||
};
|
||||
|
||||
export const setupMonitoring = async (serverId: string) => {
|
||||
const server = await findServerById(serverId);
|
||||
|
||||
const serviceName = "dokploy-monitoring";
|
||||
const imageName = getMonitoringImage();
|
||||
|
||||
const settings: CreateServiceOptions = {
|
||||
Name: serviceName,
|
||||
TaskTemplate: {
|
||||
ContainerSpec: {
|
||||
Image: imageName,
|
||||
Env: [`METRICS_CONFIG=${JSON.stringify(server?.metricsConfig)}`],
|
||||
Mounts: [
|
||||
{
|
||||
HostPort: server.metricsConfig.server.port.toString(),
|
||||
Type: "bind",
|
||||
Source: "/var/run/docker.sock",
|
||||
Target: "/var/run/docker.sock",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/sys",
|
||||
Target: "/host/sys",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/etc/os-release",
|
||||
Target: "/etc/os-release",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/proc",
|
||||
Target: "/host/proc",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/etc/dokploy/monitoring/monitoring.db",
|
||||
Target: "/app/monitoring.db",
|
||||
},
|
||||
],
|
||||
},
|
||||
Binds: [
|
||||
"/var/run/docker.sock:/var/run/docker.sock:ro",
|
||||
"/sys:/host/sys:ro",
|
||||
"/etc/os-release:/etc/os-release:ro",
|
||||
"/proc:/host/proc:ro",
|
||||
"/etc/dokploy/monitoring/monitoring.db:/app/monitoring.db",
|
||||
],
|
||||
NetworkMode: "host",
|
||||
Networks: [{ Target: "host" }],
|
||||
Placement: {
|
||||
Constraints: ["node.role==manager"],
|
||||
},
|
||||
},
|
||||
ExposedPorts: {
|
||||
[`${server.metricsConfig.server.port}/tcp`]: {},
|
||||
Mode: {
|
||||
Replicated: {
|
||||
Replicas: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const docker = await getRemoteDocker(serverId);
|
||||
try {
|
||||
await execAsyncRemote(
|
||||
serverId,
|
||||
"mkdir -p /etc/dokploy/monitoring && touch /etc/dokploy/monitoring/monitoring.db",
|
||||
);
|
||||
if (serverId) {
|
||||
await pullRemoteImage(imageName, serverId);
|
||||
}
|
||||
|
||||
// Check if container exists
|
||||
const container = docker.getContainer(containerName);
|
||||
try {
|
||||
await container.inspect();
|
||||
await container.remove({ force: true });
|
||||
console.log("Removed existing container");
|
||||
} catch {
|
||||
// Container doesn't exist, continue
|
||||
}
|
||||
|
||||
await docker.createContainer(settings);
|
||||
const newContainer = docker.getContainer(containerName);
|
||||
await newContainer.start();
|
||||
|
||||
console.log("Monitoring Started ");
|
||||
} catch (error) {
|
||||
console.log("Monitoring Not Found: Starting ", error);
|
||||
}
|
||||
await execAsyncRemote(
|
||||
serverId,
|
||||
"mkdir -p /etc/dokploy/monitoring && touch /etc/dokploy/monitoring/monitoring.db",
|
||||
);
|
||||
await pullRemoteImage(imageName, serverId);
|
||||
await deployMonitoringService(docker, serviceName, settings);
|
||||
};
|
||||
|
||||
export const setupWebMonitoring = async () => {
|
||||
const webServerSettings = await getWebServerSettings();
|
||||
|
||||
const containerName = "dokploy-monitoring";
|
||||
let imageName = "dokploy/monitoring:latest";
|
||||
const serviceName = "dokploy-monitoring";
|
||||
const imageName = getMonitoringImage();
|
||||
const port = webServerSettings?.metricsConfig?.server?.port;
|
||||
|
||||
if (
|
||||
(getDokployImageTag() !== "latest" ||
|
||||
process.env.NODE_ENV === "development") &&
|
||||
!IS_CLOUD
|
||||
) {
|
||||
imageName = "dokploy/monitoring:canary";
|
||||
}
|
||||
|
||||
const settings: ContainerCreateOptions = {
|
||||
name: containerName,
|
||||
Env: [`METRICS_CONFIG=${JSON.stringify(webServerSettings?.metricsConfig)}`],
|
||||
Image: imageName,
|
||||
HostConfig: {
|
||||
// Memory: 100 * 1024 * 1024, // 100MB en bytes
|
||||
// PidMode: "host",
|
||||
// CapAdd: ["NET_ADMIN", "SYS_ADMIN"],
|
||||
// Privileged: true,
|
||||
RestartPolicy: {
|
||||
Name: "always",
|
||||
},
|
||||
PortBindings: {
|
||||
[`${webServerSettings?.metricsConfig?.server?.port}/tcp`]: [
|
||||
const settings: CreateServiceOptions = {
|
||||
Name: serviceName,
|
||||
TaskTemplate: {
|
||||
ContainerSpec: {
|
||||
Image: imageName,
|
||||
Env: [
|
||||
`METRICS_CONFIG=${JSON.stringify(webServerSettings?.metricsConfig)}`,
|
||||
],
|
||||
Mounts: [
|
||||
{
|
||||
HostPort: webServerSettings?.metricsConfig?.server?.port.toString(),
|
||||
Type: "bind",
|
||||
Source: "/var/run/docker.sock",
|
||||
Target: "/var/run/docker.sock",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/sys",
|
||||
Target: "/host/sys",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/etc/os-release",
|
||||
Target: "/etc/os-release",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/proc",
|
||||
Target: "/host/proc",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/etc/dokploy/monitoring/monitoring.db",
|
||||
Target: "/app/monitoring.db",
|
||||
},
|
||||
],
|
||||
},
|
||||
Binds: [
|
||||
"/var/run/docker.sock:/var/run/docker.sock:ro",
|
||||
"/sys:/host/sys:ro",
|
||||
"/etc/os-release:/etc/os-release:ro",
|
||||
"/proc:/host/proc:ro",
|
||||
"/etc/dokploy/monitoring/monitoring.db:/app/monitoring.db",
|
||||
],
|
||||
// NetworkMode: "host",
|
||||
Placement: {
|
||||
Constraints: ["node.role==manager"],
|
||||
},
|
||||
},
|
||||
ExposedPorts: {
|
||||
[`${webServerSettings?.metricsConfig?.server?.port}/tcp`]: {},
|
||||
Mode: {
|
||||
Replicated: {
|
||||
Replicas: 1,
|
||||
},
|
||||
},
|
||||
EndpointSpec: {
|
||||
Ports: [
|
||||
{
|
||||
TargetPort: port,
|
||||
PublishedPort: port,
|
||||
Protocol: "tcp",
|
||||
PublishMode: "host",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const docker = await getRemoteDocker();
|
||||
try {
|
||||
await execAsync(
|
||||
"mkdir -p /etc/dokploy/monitoring && touch /etc/dokploy/monitoring/monitoring.db",
|
||||
);
|
||||
await pullImage(imageName);
|
||||
|
||||
const container = docker.getContainer(containerName);
|
||||
try {
|
||||
await container.inspect();
|
||||
await container.remove({ force: true });
|
||||
console.log("Removed existing container");
|
||||
} catch {}
|
||||
|
||||
await docker.createContainer(settings);
|
||||
const newContainer = docker.getContainer(containerName);
|
||||
await newContainer.start();
|
||||
|
||||
console.log("Monitoring Started ");
|
||||
} catch (error) {
|
||||
console.log("Monitoring Not Found: Starting ", error);
|
||||
}
|
||||
await execAsync(
|
||||
"mkdir -p /etc/dokploy/monitoring && touch /etc/dokploy/monitoring/monitoring.db",
|
||||
);
|
||||
await pullImage(imageName);
|
||||
await deployMonitoringService(docker, serviceName, settings);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user