refactor: update

This commit is contained in:
Mauricio Siu
2024-12-25 01:32:07 -06:00
parent ce34fe3cd8
commit 5e7486859f

View File

@@ -9,325 +9,325 @@ import type { FileConfig } from "../utils/traefik/file-types";
import type { MainTraefikConfig } from "../utils/traefik/types"; import type { MainTraefikConfig } from "../utils/traefik/types";
export const TRAEFIK_SSL_PORT = export const TRAEFIK_SSL_PORT =
Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443;
export const TRAEFIK_PORT = export const TRAEFIK_PORT =
Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80;
export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.1.2"; export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.1.2";
interface TraefikOptions { interface TraefikOptions {
enableDashboard?: boolean; enableDashboard?: boolean;
env?: string[]; env?: string[];
serverId?: string; serverId?: string;
additionalPorts?: { additionalPorts?: {
targetPort: number; targetPort: number;
publishedPort: number; publishedPort: number;
publishMode?: "ingress" | "host"; publishMode?: "ingress" | "host";
}[]; }[];
} }
export const initializeTraefik = async ({ export const initializeTraefik = async ({
enableDashboard = false, enableDashboard = false,
env, env,
serverId, serverId,
additionalPorts = [], additionalPorts = [],
}: TraefikOptions = {}) => { }: TraefikOptions = {}) => {
const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId);
const imageName = `traefik:v${TRAEFIK_VERSION}`; const imageName = `traefik:v${TRAEFIK_VERSION}`;
const containerName = "dokploy-traefik"; const containerName = "dokploy-traefik";
const settings: CreateServiceOptions = { const settings: CreateServiceOptions = {
Name: containerName, Name: containerName,
TaskTemplate: { TaskTemplate: {
ContainerSpec: { ContainerSpec: {
Image: imageName, Image: imageName,
Env: env, Env: env,
Mounts: [ Mounts: [
{ {
Type: "bind", Type: "bind",
Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`,
Target: "/etc/traefik/traefik.yml", Target: "/etc/traefik/traefik.yml",
}, },
{ {
Type: "bind", Type: "bind",
Source: DYNAMIC_TRAEFIK_PATH, Source: DYNAMIC_TRAEFIK_PATH,
Target: "/etc/dokploy/traefik/dynamic", Target: "/etc/dokploy/traefik/dynamic",
}, },
{ {
Type: "bind", Type: "bind",
Source: "/var/run/docker.sock", Source: "/var/run/docker.sock",
Target: "/var/run/docker.sock", Target: "/var/run/docker.sock",
}, },
], ],
}, },
Networks: [{ Target: "dokploy-network" }], Networks: [{ Target: "dokploy-network" }],
Placement: { Placement: {
Constraints: ["node.role==manager"], Constraints: ["node.role==manager"],
}, },
}, },
Mode: { Mode: {
Replicated: { Replicated: {
Replicas: 1, Replicas: 1,
}, },
}, },
Labels: { Labels: {
"traefik.enable": "true", "traefik.enable": "true",
}, },
EndpointSpec: { EndpointSpec: {
Ports: [ Ports: [
{ {
TargetPort: 443, TargetPort: TRAEFIK_SSL_PORT,
PublishedPort: TRAEFIK_SSL_PORT, PublishedPort: TRAEFIK_SSL_PORT,
PublishMode: "host", PublishMode: "host",
}, },
{ {
TargetPort: 80, TargetPort: TRAEFIK_PORT,
PublishedPort: TRAEFIK_PORT, PublishedPort: TRAEFIK_PORT,
PublishMode: "host", PublishMode: "host",
}, },
...(enableDashboard ...(enableDashboard
? [ ? [
{ {
TargetPort: 8080, TargetPort: 8080,
PublishedPort: 8080, PublishedPort: 8080,
PublishMode: "host" as const, PublishMode: "host" as const,
}, },
] ]
: []), : []),
...additionalPorts.map((port) => ({ ...additionalPorts.map((port) => ({
TargetPort: port.targetPort, TargetPort: port.targetPort,
PublishedPort: port.publishedPort, PublishedPort: port.publishedPort,
PublishMode: port.publishMode || ("host" as const), PublishMode: port.publishMode || ("host" as const),
})), })),
], ],
}, },
}; };
const docker = await getRemoteDocker(serverId); const docker = await getRemoteDocker(serverId);
try { try {
if (serverId) { if (serverId) {
await pullRemoteImage(imageName, serverId); await pullRemoteImage(imageName, serverId);
} else { } else {
await pullImage(imageName); await pullImage(imageName);
} }
const service = docker.getService(containerName); const service = docker.getService(containerName);
const inspect = await service.inspect(); const inspect = await service.inspect();
const existingEnv = inspect.Spec.TaskTemplate.ContainerSpec.Env || []; const existingEnv = inspect.Spec.TaskTemplate.ContainerSpec.Env || [];
const updatedEnv = !env ? existingEnv : env; const updatedEnv = !env ? existingEnv : env;
const updatedSettings = { const updatedSettings = {
...settings, ...settings,
TaskTemplate: { TaskTemplate: {
...settings.TaskTemplate, ...settings.TaskTemplate,
ContainerSpec: { ContainerSpec: {
...(settings?.TaskTemplate as ContainerTaskSpec).ContainerSpec, ...(settings?.TaskTemplate as ContainerTaskSpec).ContainerSpec,
Env: updatedEnv, Env: updatedEnv,
}, },
}, },
}; };
await service.update({ await service.update({
version: Number.parseInt(inspect.Version.Index), version: Number.parseInt(inspect.Version.Index),
...updatedSettings, ...updatedSettings,
}); });
console.log("Traefik Started ✅"); console.log("Traefik Started ✅");
} catch (error) { } catch (error) {
await docker.createService(settings); await docker.createService(settings);
console.log("Traefik Not Found: Starting ✅"); console.log("Traefik Not Found: Starting ✅");
} }
}; };
export const createDefaultServerTraefikConfig = () => { export const createDefaultServerTraefikConfig = () => {
const { DYNAMIC_TRAEFIK_PATH } = paths(); const { DYNAMIC_TRAEFIK_PATH } = paths();
const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, "dokploy.yml"); const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, "dokploy.yml");
if (existsSync(configFilePath)) { if (existsSync(configFilePath)) {
console.log("Default traefik config already exists"); console.log("Default traefik config already exists");
return; return;
} }
const appName = "dokploy"; const appName = "dokploy";
const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`;
const config: FileConfig = { const config: FileConfig = {
http: { http: {
routers: { routers: {
[`${appName}-router-app`]: { [`${appName}-router-app`]: {
rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`,
service: `${appName}-service-app`, service: `${appName}-service-app`,
entryPoints: ["web"], entryPoints: ["web"],
}, },
}, },
services: { services: {
[`${appName}-service-app`]: { [`${appName}-service-app`]: {
loadBalancer: { loadBalancer: {
servers: [{ url: serviceURLDefault }], servers: [{ url: serviceURLDefault }],
passHostHeader: true, passHostHeader: true,
}, },
}, },
}, },
}, },
}; };
const yamlStr = dump(config); const yamlStr = dump(config);
mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true });
writeFileSync( writeFileSync(
path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`),
yamlStr, yamlStr,
"utf8", "utf8"
); );
}; };
export const getDefaultTraefikConfig = () => { export const getDefaultTraefikConfig = () => {
const configObject: MainTraefikConfig = { const configObject: MainTraefikConfig = {
providers: { providers: {
...(process.env.NODE_ENV === "development" ...(process.env.NODE_ENV === "development"
? { ? {
docker: { docker: {
defaultRule: defaultRule:
"Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)", "Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)",
}, },
} }
: { : {
swarm: { swarm: {
exposedByDefault: false, exposedByDefault: false,
watch: false, watch: false,
}, },
docker: { docker: {
exposedByDefault: false, exposedByDefault: false,
}, },
}), }),
file: { file: {
directory: "/etc/dokploy/traefik/dynamic", directory: "/etc/dokploy/traefik/dynamic",
watch: true, watch: true,
}, },
}, },
entryPoints: { entryPoints: {
web: { web: {
address: `:${TRAEFIK_PORT}`, address: `:${TRAEFIK_PORT}`,
}, },
websecure: { websecure: {
address: `:${TRAEFIK_SSL_PORT}`, address: `:${TRAEFIK_SSL_PORT}`,
...(process.env.NODE_ENV === "production" && { ...(process.env.NODE_ENV === "production" && {
http: { http: {
tls: { tls: {
certResolver: "letsencrypt", certResolver: "letsencrypt",
}, },
}, },
}), }),
}, },
}, },
api: { api: {
insecure: true, insecure: true,
}, },
...(process.env.NODE_ENV === "production" && { ...(process.env.NODE_ENV === "production" && {
certificatesResolvers: { certificatesResolvers: {
letsencrypt: { letsencrypt: {
acme: { acme: {
email: "test@localhost.com", email: "test@localhost.com",
storage: "/etc/dokploy/traefik/dynamic/acme.json", storage: "/etc/dokploy/traefik/dynamic/acme.json",
httpChallenge: { httpChallenge: {
entryPoint: "web", entryPoint: "web",
}, },
}, },
}, },
}, },
}), }),
}; };
const yamlStr = dump(configObject); const yamlStr = dump(configObject);
return yamlStr; return yamlStr;
}; };
export const getDefaultServerTraefikConfig = () => { export const getDefaultServerTraefikConfig = () => {
const configObject: MainTraefikConfig = { const configObject: MainTraefikConfig = {
providers: { providers: {
swarm: { swarm: {
exposedByDefault: false, exposedByDefault: false,
watch: false, watch: false,
}, },
docker: { docker: {
exposedByDefault: false, exposedByDefault: false,
}, },
file: { file: {
directory: "/etc/dokploy/traefik/dynamic", directory: "/etc/dokploy/traefik/dynamic",
watch: true, watch: true,
}, },
}, },
entryPoints: { entryPoints: {
web: { web: {
address: `:${TRAEFIK_PORT}`, address: `:${TRAEFIK_PORT}`,
}, },
websecure: { websecure: {
address: `:${TRAEFIK_SSL_PORT}`, address: `:${TRAEFIK_SSL_PORT}`,
http: { http: {
tls: { tls: {
certResolver: "letsencrypt", certResolver: "letsencrypt",
}, },
}, },
}, },
}, },
api: { api: {
insecure: true, insecure: true,
}, },
certificatesResolvers: { certificatesResolvers: {
letsencrypt: { letsencrypt: {
acme: { acme: {
email: "test@localhost.com", email: "test@localhost.com",
storage: "/etc/dokploy/traefik/dynamic/acme.json", storage: "/etc/dokploy/traefik/dynamic/acme.json",
httpChallenge: { httpChallenge: {
entryPoint: "web", entryPoint: "web",
}, },
}, },
}, },
}, },
}; };
const yamlStr = dump(configObject); const yamlStr = dump(configObject);
return yamlStr; return yamlStr;
}; };
export const createDefaultTraefikConfig = () => { export const createDefaultTraefikConfig = () => {
const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths();
const mainConfig = path.join(MAIN_TRAEFIK_PATH, "traefik.yml"); const mainConfig = path.join(MAIN_TRAEFIK_PATH, "traefik.yml");
const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, "acme.json"); const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, "acme.json");
if (existsSync(acmeJsonPath)) { if (existsSync(acmeJsonPath)) {
chmodSync(acmeJsonPath, "600"); chmodSync(acmeJsonPath, "600");
} }
if (existsSync(mainConfig)) { if (existsSync(mainConfig)) {
console.log("Main config already exists"); console.log("Main config already exists");
return; return;
} }
const yamlStr = getDefaultTraefikConfig(); const yamlStr = getDefaultTraefikConfig();
mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true });
writeFileSync(mainConfig, yamlStr, "utf8"); writeFileSync(mainConfig, yamlStr, "utf8");
}; };
export const getDefaultMiddlewares = () => { export const getDefaultMiddlewares = () => {
const defaultMiddlewares = { const defaultMiddlewares = {
http: { http: {
middlewares: { middlewares: {
"redirect-to-https": { "redirect-to-https": {
redirectScheme: { redirectScheme: {
scheme: "https", scheme: "https",
permanent: true, permanent: true,
}, },
}, },
}, },
}, },
}; };
const yamlStr = dump(defaultMiddlewares); const yamlStr = dump(defaultMiddlewares);
return yamlStr; return yamlStr;
}; };
export const createDefaultMiddlewares = () => { export const createDefaultMiddlewares = () => {
const { DYNAMIC_TRAEFIK_PATH } = paths(); const { DYNAMIC_TRAEFIK_PATH } = paths();
const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, "middlewares.yml"); const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, "middlewares.yml");
if (existsSync(middlewaresPath)) { if (existsSync(middlewaresPath)) {
console.log("Default middlewares already exists"); console.log("Default middlewares already exists");
return; return;
} }
const yamlStr = getDefaultMiddlewares(); const yamlStr = getDefaultMiddlewares();
mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true });
writeFileSync(middlewaresPath, yamlStr, "utf8"); writeFileSync(middlewaresPath, yamlStr, "utf8");
}; };