feat: add docker registry upload

This commit is contained in:
Mauricio Siu
2024-05-13 01:18:27 -06:00
parent e9245cee2c
commit 6c792564ae
41 changed files with 18267 additions and 1072 deletions

View File

@@ -13,6 +13,7 @@ import { buildCustomDocker } from "./docker-file";
import { buildHeroku } from "./heroku";
import { buildNixpacks } from "./nixpacks";
import { buildPaketo } from "./paketo";
import { uploadImage } from "../cluster/upload";
// NIXPACKS codeDirectory = where is the path of the code directory
// HEROKU codeDirectory = where is the path of the code directory
@@ -20,7 +21,7 @@ import { buildPaketo } from "./paketo";
// DOCKERFILE codeDirectory = where is the exact path of the (Dockerfile)
export type ApplicationNested = InferResultType<
"applications",
{ mounts: true; security: true; redirects: true; ports: true }
{ mounts: true; security: true; redirects: true; ports: true; registry: true }
>;
export const buildApplication = async (
application: ApplicationNested,
@@ -42,6 +43,10 @@ export const buildApplication = async (
} else if (buildType === "dockerfile") {
await buildCustomDocker(application, writeStream);
}
if (application.registryId) {
await uploadImage(application, writeStream);
}
await mechanizeDockerContainer(application);
writeStream.write("Docker Deployed: ✅");
} catch (error) {
@@ -67,6 +72,7 @@ export const mechanizeDockerContainer = async (
cpuReservation,
command,
ports,
replicas,
} = application;
const resources = calculateResources({
@@ -104,7 +110,7 @@ export const mechanizeDockerContainer = async (
},
Mode: {
Replicated: {
Replicas: 1,
Replicas: replicas,
},
},
EndpointSpec: {

View File

@@ -0,0 +1,67 @@
import type { ApplicationNested } from "../builders";
import { execAsync } from "../process/execAsync";
import { spawnAsync } from "../process/spawnAsync";
import type { WriteStream } from "node:fs";
export const uploadImage = async (
application: ApplicationNested,
writeStream: WriteStream,
) => {
const registry = application.registry;
if (!registry) {
throw new Error("Registry not found");
}
const { registryUrl, imagePrefix } = registry;
const { appName } = application;
const imageName = `${appName}:latest`;
let finalURL = registryUrl;
let registryTag = `${registryUrl}/${imageName}`;
if (imagePrefix) {
registryTag = `${registryUrl}/${imagePrefix}/${imageName}`;
}
// registry.digitalocean.com/<my-registry>/<my-image>
// index.docker.io/siumauricio/app-parse-multi-byte-port-e32uh7:latest
if (registry.registryType === "selfHosted") {
finalURL =
process.env.NODE_ENV === "development" ? "localhost:5000" : registryUrl;
registryTag = `${finalURL}/${imageName}`;
}
try {
console.log(finalURL, registryTag);
writeStream.write(
`📦 [Enabled Registry] Uploading image to ${registry.registryType} | ${registryTag} | ${finalURL}\n`,
);
await spawnAsync(
"docker",
["login", finalURL, "-u", registry.username, "-p", registry.password],
(data) => {
if (writeStream.writable) {
writeStream.write(data);
}
},
);
await spawnAsync("docker", ["tag", imageName, registryTag], (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
});
await spawnAsync("docker", ["push", registryTag], (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
});
} catch (error) {
console.log(error);
throw error;
}
};

View File

@@ -47,10 +47,7 @@ export const removeDomain = async (appName: string, uniqueKey: number) => {
}
};
export const createRouterConfig = async (
app: ApplicationNested,
domain: Domain,
) => {
const createRouterConfig = async (app: ApplicationNested, domain: Domain) => {
const { appName, redirects, security } = app;
const { certificateType } = domain;

View File

@@ -0,0 +1,67 @@
import { loadOrCreateConfig } from "./application";
import type { FileConfig, HttpRouter } from "./file-types";
import type { Registry } from "@/server/api/services/registry";
import { removeDirectoryIfExistsContent } from "../filesystem/directory";
import { REGISTRY_PATH } from "@/server/constants";
import { dump } from "js-yaml";
import { join } from "node:path";
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
export const manageRegistry = async (registry: Registry) => {
if (!existsSync(REGISTRY_PATH)) {
mkdirSync(REGISTRY_PATH, { recursive: true });
}
const appName = "dokploy-registry";
const config: FileConfig = loadOrCreateConfig(appName);
const serviceName = `${appName}-service`;
const routerName = `${appName}-router`;
config.http = config.http || { routers: {}, services: {} };
config.http.routers = config.http.routers || {};
config.http.services = config.http.services || {};
config.http.routers[routerName] = await createRegistryRouterConfig(registry);
config.http.services[serviceName] = {
loadBalancer: {
servers: [{ url: `http://${appName}:5000` }],
passHostHeader: true,
},
};
const yamlConfig = dump(config);
const configFile = join(REGISTRY_PATH, "registry.yml");
writeFileSync(configFile, yamlConfig);
};
export const removeSelfHostedRegistry = async () => {
await removeDirectoryIfExistsContent(REGISTRY_PATH);
};
const createRegistryRouterConfig = async (registry: Registry) => {
const { registryUrl } = registry;
const url =
process.env.NODE_ENV === "production"
? registryUrl
: "dokploy-registry.docker.localhost";
const routerConfig: HttpRouter = {
rule: `Host(\`${url}\`)`,
service: "dokploy-registry-service",
...(process.env.NODE_ENV === "production"
? {
middlewares: ["redirect-to-https"],
}
: {}),
entryPoints: [
"web",
...(process.env.NODE_ENV === "production" ? ["websecure"] : []),
],
...(process.env.NODE_ENV === "production"
? {
tls: { certResolver: "letsencrypt" },
}
: {}),
};
return routerConfig;
};