mirror of
https://github.com/LukeHagar/dokploy.git
synced 2025-12-06 20:37:45 +00:00
Merge pull request #1402 from Dokploy/feat/add-railpack
feat(application): add Railpack as a new build type
This commit is contained in:
@@ -138,11 +138,18 @@ curl -sSL https://nixpacks.com/install.sh -o install.sh \
|
|||||||
&& ./install.sh
|
&& ./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Railpack
|
||||||
|
curl -sSL https://railpack.com/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install Buildpacks
|
# Install Buildpacks
|
||||||
curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.32.1/pack-v0.32.1-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack
|
curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.32.1/pack-v0.32.1-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Pull Request
|
## Pull Request
|
||||||
|
|
||||||
- The `main` branch is the source of truth and should always reflect the latest stable release.
|
- The `main` branch is the source of truth and should always reflect the latest stable release.
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ RUN curl -sSL https://nixpacks.com/install.sh -o install.sh \
|
|||||||
&& ./install.sh \
|
&& ./install.sh \
|
||||||
&& pnpm install -g tsx
|
&& pnpm install -g tsx
|
||||||
|
|
||||||
|
# Install Railpack
|
||||||
|
ARG RAILPACK_VERSION=0.0.37
|
||||||
|
RUN curl -sSL https://railpack.com/install.sh | sh
|
||||||
|
|
||||||
# Install buildpacks
|
# Install buildpacks
|
||||||
COPY --from=buildpacksio/pack:0.35.0 /usr/local/bin/pack /usr/local/bin/pack
|
COPY --from=buildpacksio/pack:0.35.0 /usr/local/bin/pack /usr/local/bin/pack
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import {
|
import {
|
||||||
@@ -25,6 +26,7 @@ enum BuildType {
|
|||||||
paketo_buildpacks = "paketo_buildpacks",
|
paketo_buildpacks = "paketo_buildpacks",
|
||||||
nixpacks = "nixpacks",
|
nixpacks = "nixpacks",
|
||||||
static = "static",
|
static = "static",
|
||||||
|
railpack = "railpack",
|
||||||
}
|
}
|
||||||
|
|
||||||
const mySchema = z.discriminatedUnion("buildType", [
|
const mySchema = z.discriminatedUnion("buildType", [
|
||||||
@@ -53,6 +55,9 @@ const mySchema = z.discriminatedUnion("buildType", [
|
|||||||
z.object({
|
z.object({
|
||||||
buildType: z.literal("static"),
|
buildType: z.literal("static"),
|
||||||
}),
|
}),
|
||||||
|
z.object({
|
||||||
|
buildType: z.literal("railpack"),
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
type AddTemplate = z.infer<typeof mySchema>;
|
type AddTemplate = z.infer<typeof mySchema>;
|
||||||
@@ -173,6 +178,15 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
|
|||||||
Dockerfile
|
Dockerfile
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||||
|
<FormControl>
|
||||||
|
<RadioGroupItem value="railpack" />
|
||||||
|
</FormControl>
|
||||||
|
<FormLabel className="font-normal">
|
||||||
|
Railpack{" "}
|
||||||
|
<Badge className="ml-1 text-xs px-1">New</Badge>
|
||||||
|
</FormLabel>
|
||||||
|
</FormItem>
|
||||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<RadioGroupItem value="nixpacks" />
|
<RadioGroupItem value="nixpacks" />
|
||||||
|
|||||||
@@ -139,6 +139,15 @@ export const ValidateServer = ({ serverId }: Props) => {
|
|||||||
: "Not Created"
|
: "Not Created"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<StatusRow
|
||||||
|
label="Railpack Installed"
|
||||||
|
isEnabled={data?.railpack?.enabled}
|
||||||
|
description={
|
||||||
|
data?.railpack?.enabled
|
||||||
|
? `Installed: ${data?.railpack?.version}`
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
1
apps/dokploy/drizzle/0069_legal_bill_hollister.sql
Normal file
1
apps/dokploy/drizzle/0069_legal_bill_hollister.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TYPE "public"."buildType" ADD VALUE 'railpack';
|
||||||
5119
apps/dokploy/drizzle/meta/0069_snapshot.json
Normal file
5119
apps/dokploy/drizzle/meta/0069_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -484,6 +484,13 @@
|
|||||||
"when": 1740897756774,
|
"when": 1740897756774,
|
||||||
"tag": "0068_complex_rhino",
|
"tag": "0068_complex_rhino",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 69,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741152916611,
|
||||||
|
"tag": "0069_legal_bill_hollister",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -206,6 +206,10 @@ export const serverRouter = createTRPCRouter({
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
version: string;
|
version: string;
|
||||||
};
|
};
|
||||||
|
railpack: {
|
||||||
|
enabled: boolean;
|
||||||
|
version: string;
|
||||||
|
};
|
||||||
isDokployNetworkInstalled: boolean;
|
isDokployNetworkInstalled: boolean;
|
||||||
isSwarmInstalled: boolean;
|
isSwarmInstalled: boolean;
|
||||||
isMainDirectoryInstalled: boolean;
|
isMainDirectoryInstalled: boolean;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export const buildType = pgEnum("buildType", [
|
|||||||
"paketo_buildpacks",
|
"paketo_buildpacks",
|
||||||
"nixpacks",
|
"nixpacks",
|
||||||
"static",
|
"static",
|
||||||
|
"railpack",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export interface HealthCheckSwarm {
|
export interface HealthCheckSwarm {
|
||||||
@@ -383,6 +384,7 @@ const createSchema = createInsertSchema(applications, {
|
|||||||
"paketo_buildpacks",
|
"paketo_buildpacks",
|
||||||
"nixpacks",
|
"nixpacks",
|
||||||
"static",
|
"static",
|
||||||
|
"railpack",
|
||||||
]),
|
]),
|
||||||
herokuVersion: z.string().optional(),
|
herokuVersion: z.string().optional(),
|
||||||
publishDirectory: z.string().optional(),
|
publishDirectory: z.string().optional(),
|
||||||
|
|||||||
@@ -170,6 +170,9 @@ ${installNixpacks()}
|
|||||||
|
|
||||||
echo -e "12. Installing Buildpacks"
|
echo -e "12. Installing Buildpacks"
|
||||||
${installBuildpacks()}
|
${installBuildpacks()}
|
||||||
|
|
||||||
|
echo -e "13. Installing Railpack"
|
||||||
|
${installRailpack()}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return bashCommand;
|
return bashCommand;
|
||||||
@@ -573,6 +576,16 @@ const installNixpacks = () => `
|
|||||||
fi
|
fi
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const installRailpack = () => `
|
||||||
|
if command_exists railpack; then
|
||||||
|
echo "Railpack already installed ✅"
|
||||||
|
else
|
||||||
|
export RAILPACK_VERSION=0.0.37
|
||||||
|
bash -c "$(curl -fsSL https://railpack.com/install.sh)"
|
||||||
|
echo "Railpack version $RAILPACK_VERSION installed ✅"
|
||||||
|
fi
|
||||||
|
`;
|
||||||
|
|
||||||
const installBuildpacks = () => `
|
const installBuildpacks = () => `
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
if [ "$SYS_ARCH" = "aarch64" ] || [ "$SYS_ARCH" = "arm64" ]; then
|
if [ "$SYS_ARCH" = "aarch64" ] || [ "$SYS_ARCH" = "arm64" ]; then
|
||||||
|
|||||||
@@ -38,6 +38,18 @@ export const validateNixpacks = () => `
|
|||||||
fi
|
fi
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const validateRailpack = () => `
|
||||||
|
if command_exists railpack; then
|
||||||
|
version=$(railpack --version | awk '{print $3}')
|
||||||
|
if [ -n "$version" ]; then
|
||||||
|
echo "$version true"
|
||||||
|
else
|
||||||
|
echo "0.0.0 false"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "0.0.0 false"
|
||||||
|
fi
|
||||||
|
`;
|
||||||
export const validateBuildpacks = () => `
|
export const validateBuildpacks = () => `
|
||||||
if command_exists pack; then
|
if command_exists pack; then
|
||||||
version=$(pack --version | awk '{print $1}')
|
version=$(pack --version | awk '{print $1}')
|
||||||
@@ -86,7 +98,7 @@ export const serverValidate = async (serverId: string) => {
|
|||||||
rcloneVersionEnabled=$(${validateRClone()})
|
rcloneVersionEnabled=$(${validateRClone()})
|
||||||
nixpacksVersionEnabled=$(${validateNixpacks()})
|
nixpacksVersionEnabled=$(${validateNixpacks()})
|
||||||
buildpacksVersionEnabled=$(${validateBuildpacks()})
|
buildpacksVersionEnabled=$(${validateBuildpacks()})
|
||||||
|
railpackVersionEnabled=$(${validateRailpack()})
|
||||||
dockerVersion=$(echo $dockerVersionEnabled | awk '{print $1}')
|
dockerVersion=$(echo $dockerVersionEnabled | awk '{print $1}')
|
||||||
dockerEnabled=$(echo $dockerVersionEnabled | awk '{print $2}')
|
dockerEnabled=$(echo $dockerVersionEnabled | awk '{print $2}')
|
||||||
|
|
||||||
@@ -96,6 +108,9 @@ export const serverValidate = async (serverId: string) => {
|
|||||||
nixpacksVersion=$(echo $nixpacksVersionEnabled | awk '{print $1}')
|
nixpacksVersion=$(echo $nixpacksVersionEnabled | awk '{print $1}')
|
||||||
nixpacksEnabled=$(echo $nixpacksVersionEnabled | awk '{print $2}')
|
nixpacksEnabled=$(echo $nixpacksVersionEnabled | awk '{print $2}')
|
||||||
|
|
||||||
|
railpackVersion=$(echo $railpackVersionEnabled | awk '{print $1}')
|
||||||
|
railpackEnabled=$(echo $railpackVersionEnabled | awk '{print $2}')
|
||||||
|
|
||||||
buildpacksVersion=$(echo $buildpacksVersionEnabled | awk '{print $1}')
|
buildpacksVersion=$(echo $buildpacksVersionEnabled | awk '{print $1}')
|
||||||
buildpacksEnabled=$(echo $buildpacksVersionEnabled | awk '{print $2}')
|
buildpacksEnabled=$(echo $buildpacksVersionEnabled | awk '{print $2}')
|
||||||
|
|
||||||
@@ -103,7 +118,7 @@ export const serverValidate = async (serverId: string) => {
|
|||||||
isSwarmInstalled=$(${validateSwarm()})
|
isSwarmInstalled=$(${validateSwarm()})
|
||||||
isMainDirectoryInstalled=$(${validateMainDirectory()})
|
isMainDirectoryInstalled=$(${validateMainDirectory()})
|
||||||
|
|
||||||
echo "{\\"docker\\": {\\"version\\": \\"$dockerVersion\\", \\"enabled\\": $dockerEnabled}, \\"rclone\\": {\\"version\\": \\"$rcloneVersion\\", \\"enabled\\": $rcloneEnabled}, \\"nixpacks\\": {\\"version\\": \\"$nixpacksVersion\\", \\"enabled\\": $nixpacksEnabled}, \\"buildpacks\\": {\\"version\\": \\"$buildpacksVersion\\", \\"enabled\\": $buildpacksEnabled}, \\"isDokployNetworkInstalled\\": $isDokployNetworkInstalled, \\"isSwarmInstalled\\": $isSwarmInstalled, \\"isMainDirectoryInstalled\\": $isMainDirectoryInstalled}"
|
echo "{\\"docker\\": {\\"version\\": \\"$dockerVersion\\", \\"enabled\\": $dockerEnabled}, \\"rclone\\": {\\"version\\": \\"$rcloneVersion\\", \\"enabled\\": $rcloneEnabled}, \\"nixpacks\\": {\\"version\\": \\"$nixpacksVersion\\", \\"enabled\\": $nixpacksEnabled}, \\"buildpacks\\": {\\"version\\": \\"$buildpacksVersion\\", \\"enabled\\": $buildpacksEnabled}, \\"railpack\\": {\\"version\\": \\"$railpackVersion\\", \\"enabled\\": $railpackEnabled}, \\"isDokployNetworkInstalled\\": $isDokployNetworkInstalled, \\"isSwarmInstalled\\": $isSwarmInstalled, \\"isMainDirectoryInstalled\\": $isMainDirectoryInstalled}"
|
||||||
`;
|
`;
|
||||||
client.exec(bashCommand, (err, stream) => {
|
client.exec(bashCommand, (err, stream) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { buildCustomDocker, getDockerCommand } from "./docker-file";
|
|||||||
import { buildHeroku, getHerokuCommand } from "./heroku";
|
import { buildHeroku, getHerokuCommand } from "./heroku";
|
||||||
import { buildNixpacks, getNixpacksCommand } from "./nixpacks";
|
import { buildNixpacks, getNixpacksCommand } from "./nixpacks";
|
||||||
import { buildPaketo, getPaketoCommand } from "./paketo";
|
import { buildPaketo, getPaketoCommand } from "./paketo";
|
||||||
|
import { buildRailpack, getRailpackCommand } from "./railpack";
|
||||||
import { buildStatic, getStaticCommand } from "./static";
|
import { buildStatic, getStaticCommand } from "./static";
|
||||||
|
|
||||||
// NIXPACKS codeDirectory = where is the path of the code directory
|
// NIXPACKS codeDirectory = where is the path of the code directory
|
||||||
@@ -55,6 +56,8 @@ export const buildApplication = async (
|
|||||||
await buildCustomDocker(application, writeStream);
|
await buildCustomDocker(application, writeStream);
|
||||||
} else if (buildType === "static") {
|
} else if (buildType === "static") {
|
||||||
await buildStatic(application, writeStream);
|
await buildStatic(application, writeStream);
|
||||||
|
} else if (buildType === "railpack") {
|
||||||
|
await buildRailpack(application, writeStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (application.registryId) {
|
if (application.registryId) {
|
||||||
@@ -96,6 +99,9 @@ export const getBuildCommand = (
|
|||||||
case "dockerfile":
|
case "dockerfile":
|
||||||
command = getDockerCommand(application, logPath);
|
command = getDockerCommand(application, logPath);
|
||||||
break;
|
break;
|
||||||
|
case "railpack":
|
||||||
|
command = getRailpackCommand(application, logPath);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (registry) {
|
if (registry) {
|
||||||
command += uploadImageRemoteCommand(application, logPath);
|
command += uploadImageRemoteCommand(application, logPath);
|
||||||
|
|||||||
87
packages/server/src/utils/builders/railpack.ts
Normal file
87
packages/server/src/utils/builders/railpack.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import type { WriteStream } from "node:fs";
|
||||||
|
import type { ApplicationNested } from ".";
|
||||||
|
import { prepareEnvironmentVariables } from "../docker/utils";
|
||||||
|
import { getBuildAppDirectory } from "../filesystem/directory";
|
||||||
|
import { spawnAsync } from "../process/spawnAsync";
|
||||||
|
import { execAsync } from "../process/execAsync";
|
||||||
|
|
||||||
|
export const buildRailpack = async (
|
||||||
|
application: ApplicationNested,
|
||||||
|
writeStream: WriteStream,
|
||||||
|
) => {
|
||||||
|
const { env, appName } = application;
|
||||||
|
const buildAppDirectory = getBuildAppDirectory(application);
|
||||||
|
const envVariables = prepareEnvironmentVariables(
|
||||||
|
env,
|
||||||
|
application.project.env,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ensure buildkit container is running, create if it doesn't exist
|
||||||
|
await execAsync(
|
||||||
|
"docker container inspect buildkit >/dev/null 2>&1 || docker run --rm --privileged -d --name buildkit moby/buildkit",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Build the application using railpack
|
||||||
|
const args = ["build", buildAppDirectory, "--name", appName];
|
||||||
|
|
||||||
|
// Add environment variables
|
||||||
|
for (const env of envVariables) {
|
||||||
|
args.push("--env", env);
|
||||||
|
}
|
||||||
|
|
||||||
|
await spawnAsync(
|
||||||
|
"railpack",
|
||||||
|
args,
|
||||||
|
(data) => {
|
||||||
|
if (writeStream.writable) {
|
||||||
|
writeStream.write(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
BUILDKIT_HOST: "docker-container://buildkit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRailpackCommand = (
|
||||||
|
application: ApplicationNested,
|
||||||
|
logPath: string,
|
||||||
|
) => {
|
||||||
|
const { env, appName } = application;
|
||||||
|
const buildAppDirectory = getBuildAppDirectory(application);
|
||||||
|
const envVariables = prepareEnvironmentVariables(
|
||||||
|
env,
|
||||||
|
application.project.env,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Build the application using railpack
|
||||||
|
const args = ["build", buildAppDirectory, "--name", appName];
|
||||||
|
|
||||||
|
// Add environment variables
|
||||||
|
for (const env of envVariables) {
|
||||||
|
args.push("--env", env);
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = `railpack ${args.join(" ")}`;
|
||||||
|
const bashCommand = `
|
||||||
|
echo "Building with Railpack..." >> "${logPath}";
|
||||||
|
docker container inspect buildkit >/dev/null 2>&1 || docker run --rm --privileged -d --name buildkit moby/buildkit;
|
||||||
|
export BUILDKIT_HOST=docker-container://buildkit;
|
||||||
|
${command} >> ${logPath} 2>> ${logPath} || {
|
||||||
|
echo "❌ Railpack build failed" >> ${logPath};
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
echo "✅ Railpack build completed." >> ${logPath};
|
||||||
|
`;
|
||||||
|
|
||||||
|
return bashCommand;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user