feat: 新增 Dockerfile 配置模板,总计 60 个组件

Dockerfile 支持:
- 基础镜像 (FROM) + 多阶段构建 + 平台架构
- 元数据 LABEL / 构建参数 ARG
- 环境变量 ENV / 工作目录 WORKDIR
- 文件复制 COPY + chown/chmod + ADD (自动解压/URL)
- 依赖安装: apk/apt/yum/dnf 包管理器 + 应用依赖 + 构建命令
- 端口 EXPOSE / 数据卷 VOLUME
- 用户 USER (非 root 运行)
- 健康检查 HEALTHCHECK (interval/timeout/retries/start-period)
- 入口 ENTRYPOINT / CMD (exec/shell 格式)
- 停止信号 STOPSIGNAL / Shell 指令
This commit is contained in:
cnbugs
2026-07-24 15:12:46 +08:00
parent 4e98eb8c4a
commit 6426eedab5
4 changed files with 515 additions and 71 deletions
+364
View File
@@ -0,0 +1,364 @@
export const dockerfileSchema = {
id: 'dockerfile',
name: 'Dockerfile',
icon: 'Box',
category: '容器化',
description: 'Docker 容器镜像构建文件',
format: 'dockerfile',
fileName: 'Dockerfile',
groups: [
{
title: '基础镜像',
fields: [
{ key: 'baseImage', label: '基础镜像', type: 'text', placeholder: 'nginx:1.24-alpine', default: 'nginx:1.24-alpine', required: true, tip: 'FROM 指令' },
{ key: 'fromPlatform', label: '平台架构', type: 'select', options: [
{ label: '不限制', value: '' },
{ label: 'linux/amd64', value: 'linux/amd64' },
{ label: 'linux/arm64', value: 'linux/arm64' },
], default: '', tip: '多架构构建时指定' },
{ key: 'enableMultiStage', label: '多阶段构建', type: 'switch', default: false, tip: '分离构建和运行阶段' },
{ key: 'builderImage', label: '构建阶段镜像', type: 'text', placeholder: 'node:18-alpine', default: 'node:18-alpine', dependsOn: { key: 'enableMultiStage', value: true } },
{ key: 'builderAs', label: '构建阶段别名', type: 'text', default: 'builder', dependsOn: { key: 'enableMultiStage', value: true } },
],
},
{
title: '元数据 (LABEL)',
fields: [
{ key: 'enableLabels', label: '添加标签', type: 'switch', default: false },
{ key: 'labelMaintainer', label: '维护者', type: 'text', placeholder: 'team@example.com', default: 'team@example.com', dependsOn: { key: 'enableLabels', value: true } },
{ key: 'labelVersion', label: '版本', type: 'text', placeholder: '1.0.0', default: '1.0.0', dependsOn: { key: 'enableLabels', value: true } },
{ key: 'labelDescription', label: '描述', type: 'text', placeholder: 'My application', default: '', dependsOn: { key: 'enableLabels', value: true } },
],
},
{
title: '构建参数 (ARG)',
fields: [
{ key: 'enableArgs', label: '定义构建参数', type: 'switch', default: false, tip: '仅在 docker build --build-arg 时生效' },
{ key: 'args', label: '参数列表 (KEY=VALUE)', type: 'text', placeholder: 'APP_VERSION=1.0.0\nNODE_ENV=production', default: 'APP_VERSION=1.0.0', dependsOn: { key: 'enableArgs', value: true }, tip: '每行一个,格式 KEY 或 KEY=默认值' },
],
},
{
title: '环境变量 (ENV)',
fields: [
{ key: 'enableEnv', label: '设置环境变量', type: 'switch', default: false },
{ key: 'envVars', label: '环境变量 (KEY=VALUE)', type: 'text', placeholder: 'NODE_ENV=production\nAPP_PORT=8080', default: 'NODE_ENV=production\nAPP_PORT=8080', dependsOn: { key: 'enableEnv', value: true }, tip: '每行一个,格式 KEY=VALUE' },
],
},
{
title: '工作目录与用户',
fields: [
{ key: 'enableWorkdir', label: '设置工作目录', type: 'switch', default: true },
{ key: 'workdir', label: '工作目录', type: 'text', default: '/app', dependsOn: { key: 'enableWorkdir', value: true } },
{ key: 'enableUser', label: '切换运行用户', type: 'switch', default: false, tip: '生产环境建议使用非 root 用户' },
{ key: 'userName', label: '用户名或 UID', type: 'text', placeholder: '1001:1001', default: '1001:1001', dependsOn: { key: 'enableUser', value: true } },
{ key: 'enableUseradd', label: '创建用户', type: 'switch', default: false, dependsOn: { key: 'enableUser', value: true }, tip: '在 RUN 中创建用户' },
{ key: 'createUserName', label: '用户名', type: 'text', default: 'appuser', dependsOn: { key: 'enableUseradd', value: true } },
],
},
{
title: '文件复制',
fields: [
{ key: 'enableCopy', label: '复制文件', type: 'switch', default: true },
{ key: 'copySrc', label: '源路径', type: 'text', placeholder: '. 或 ./dist', default: '.', dependsOn: { key: 'enableCopy', value: true } },
{ key: 'copyDest', label: '目标路径', type: 'text', placeholder: '/app', default: '/app', dependsOn: { key: 'enableCopy', value: true } },
{ key: 'enableCopyChown', label: '设置文件所有者', type: 'switch', default: false, dependsOn: { key: 'enableCopy', value: true } },
{ key: 'copyChown', label: '所有者', type: 'text', placeholder: '1001:1001', default: '1001:1001', dependsOn: { key: 'enableCopyChown', value: true } },
{ key: 'enableCopyChmod', label: '设置文件权限', type: 'switch', default: false, dependsOn: { key: 'enableCopy', value: true } },
{ key: 'copyChmod', label: '权限', type: 'text', placeholder: '755', default: '755', dependsOn: { key: 'enableCopyChmod', value: true } },
{ key: 'enableAdd', label: '使用 ADD (自动解压/URL)', type: 'switch', default: false, tip: '需要解压 tar 或下载远程文件时使用' },
{ key: 'addSrc', label: 'ADD 源', type: 'text', placeholder: 'https://example.com/app.tar.gz', default: '', dependsOn: { key: 'enableAdd', value: true } },
{ key: 'addDest', label: 'ADD 目标', type: 'text', default: '/app/', dependsOn: { key: 'enableAdd', value: true } },
],
},
{
title: '依赖安装 (RUN)',
fields: [
{ key: 'packageManager', label: '包管理器', type: 'select', options: [
{ label: '不安装系统包', value: 'none' },
{ label: 'apk (Alpine)', value: 'apk' },
{ label: 'apt (Debian/Ubuntu)', value: 'apt' },
{ label: 'yum (CentOS/RHEL)', value: 'yum' },
{ label: 'dnf (Fedora)', value: 'dnf' },
], default: 'none' },
{ key: 'systemPackages', label: '系统包 (空格分隔)', type: 'text', placeholder: 'curl wget tzdata', default: 'curl ca-certificates tzdata', dependsOn: { key: 'packageManager', valueNotIn: ['none'] } },
{ key: 'enableAppInstall', label: '安装应用依赖', type: 'switch', default: false, tip: 'npm install / pip install / go build 等' },
{ key: 'appInstallCmd', label: '安装命令', type: 'text', placeholder: 'npm ci --only=production', default: 'npm ci --only=production', dependsOn: { key: 'enableAppInstall', value: true } },
{ key: 'enableBuildCmd', label: '构建命令', type: 'switch', default: false, tip: 'npm run build / go build / mvn package 等' },
{ key: 'buildCmd', label: '构建命令', type: 'text', placeholder: 'npm run build', default: 'npm run build', dependsOn: { key: 'enableBuildCmd', value: true } },
{ key: 'enableCleanup', label: '清理缓存', type: 'switch', default: true, dependsOn: { key: 'packageManager', valueNotIn: ['none'] }, tip: '减小镜像体积' },
],
},
{
title: '端口与网络',
fields: [
{ key: 'enableExpose', label: '暴露端口', type: 'switch', default: true },
{ key: 'exposePorts', label: '端口列表', type: 'text', placeholder: '80 443', default: '80', dependsOn: { key: 'enableExpose', value: true }, tip: '空格分隔多个端口' },
],
},
{
title: '健康检查 (HEALTHCHECK)',
fields: [
{ key: 'enableHealthcheck', label: '添加健康检查', type: 'switch', default: false },
{ key: 'healthcheckType', label: '检查方式', type: 'select', options: [
{ label: 'CMD (自定义命令)', value: 'CMD' },
{ label: 'NONE (禁用继承的健康检查)', value: 'NONE' },
], default: 'CMD', dependsOn: { key: 'enableHealthcheck', value: true } },
{ key: 'healthcheckInterval', label: '检查间隔', type: 'text', default: '30s', dependsOn: { key: 'healthcheckType', value: 'CMD' } },
{ key: 'healthcheckTimeout', label: '超时时间', type: 'text', default: '10s', dependsOn: { key: 'healthcheckType', value: 'CMD' } },
{ key: 'healthcheckRetries', label: '重试次数', type: 'number', min: 1, max: 10, default: 3, dependsOn: { key: 'healthcheckType', value: 'CMD' } },
{ key: 'healthcheckStartPeriod', label: '启动等待期', type: 'text', default: '5s', dependsOn: { key: 'healthcheckType', value: 'CMD' } },
{ key: 'healthcheckCmd', label: '检查命令', type: 'text', placeholder: 'curl -f http://localhost/ || exit 1', default: 'curl -f http://localhost:80/ || exit 1', dependsOn: { key: 'healthcheckType', value: 'CMD' }, required: true },
],
},
{
title: '挂载点与数据卷',
fields: [
{ key: 'enableVolume', label: '声明数据卷', type: 'switch', default: false },
{ key: 'volumePaths', label: '挂载路径', type: 'text', placeholder: '/data /var/log/app', default: '/data', dependsOn: { key: 'enableVolume', value: true }, tip: '空格分隔多个路径' },
],
},
{
title: '入口与启动',
fields: [
{ key: 'enableEntrypoint', label: '设置 ENTRYPOINT', type: 'switch', default: false, tip: '容器启动时执行的固定命令' },
{ key: 'entrypointCmd', label: 'ENTRYPOINT 命令', type: 'text', placeholder: '["java", "-jar", "app.jar"]', default: '["node", "server.js"]', dependsOn: { key: 'enableEntrypoint', value: true }, tip: 'JSON 数组格式或 shell 格式' },
{ key: 'enableCmd', label: '设置 CMD', type: 'switch', default: true, tip: '容器启动时的默认参数' },
{ key: 'cmdType', label: 'CMD 格式', type: 'select', options: [
{ label: 'exec 格式 (推荐)', value: 'exec' },
{ label: 'shell 格式', value: 'shell' },
], default: 'exec', dependsOn: { key: 'enableCmd', value: true } },
{ key: 'cmdValue', label: 'CMD 内容', type: 'text', placeholder: '["nginx", "-g", "daemon off;"]', default: '["nginx", "-g", "daemon off;"]', dependsOn: { key: 'enableCmd', value: true } },
],
},
{
title: '信号与停止',
fields: [
{ key: 'enableStopSignal', label: '自定义停止信号', type: 'switch', default: false, tip: 'docker stop 发送的信号' },
{ key: 'stopSignal', label: '停止信号', type: 'select', options: [
{ label: 'SIGTERM (默认)', value: 'SIGTERM' },
{ label: 'SIGQUIT', value: 'SIGQUIT' },
{ label: 'SIGINT', value: 'SIGINT' },
{ label: 'SIGUSR1', value: 'SIGUSR1' },
], default: 'SIGTERM', dependsOn: { key: 'enableStopSignal', value: true } },
{ key: 'enableShell', label: '指定 Shell', type: 'switch', default: false, tip: 'SHELL 指令,RUN 使用的 shell' },
{ key: 'shellPath', label: 'Shell 路径', type: 'text', default: '/bin/sh', dependsOn: { key: 'enableShell', value: true } },
{ key: 'shellFlag', label: 'Shell 参数', type: 'text', default: '-c', dependsOn: { key: 'enableShell', value: true } },
],
},
],
}
export function generateDockerfile(config) {
const lines = []
lines.push(`# Dockerfile - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// Builder stage
if (config.enableMultiStage) {
lines.push(`# ======================== 构建阶段 ========================`)
lines.push(`FROM${config.fromPlatform ? ` --platform=${config.fromPlatform}` : ''} ${config.builderImage} AS ${config.builderAs}`)
lines.push(``)
if (config.enableWorkdir) {
lines.push(`WORKDIR ${config.workdir}`)
}
lines.push(`COPY . .`)
if (config.enableAppInstall && config.appInstallCmd) {
lines.push(`RUN ${config.appInstallCmd}`)
}
if (config.enableBuildCmd && config.buildCmd) {
lines.push(`RUN ${config.buildCmd}`)
}
lines.push(``)
lines.push(`# ======================== 运行阶段 ========================`)
}
// FROM
const platformArg = config.fromPlatform ? ` --platform=${config.fromPlatform}` : ''
if (config.enableMultiStage) {
lines.push(`FROM${platformArg} ${config.baseImage}`)
} else {
lines.push(`FROM${platformArg} ${config.baseImage}`)
}
lines.push(``)
// ARG
if (config.enableArgs && config.args) {
config.args.split('\n').filter(Boolean).forEach(line => {
lines.push(`ARG ${line.trim()}`)
})
lines.push(``)
}
// LABEL
if (config.enableLabels) {
if (config.labelMaintainer) lines.push(`LABEL maintainer="${config.labelMaintainer}"`)
if (config.labelVersion) lines.push(`LABEL version="${config.labelVersion}"`)
if (config.labelDescription) lines.push(`LABEL description="${config.labelDescription}"`)
lines.push(``)
}
// ENV
if (config.enableEnv && config.envVars) {
config.envVars.split('\n').filter(Boolean).forEach(line => {
lines.push(`ENV ${line.trim()}`)
})
lines.push(``)
}
// WORKDIR
if (config.enableWorkdir) {
lines.push(`WORKDIR ${config.workdir}`)
lines.push(``)
}
// Package install
if (config.packageManager && config.packageManager !== 'none') {
const pkgs = (config.systemPackages || '').trim()
if (pkgs) {
if (config.packageManager === 'apk') {
lines.push(`RUN apk add --no-cache ${pkgs}`)
} else if (config.packageManager === 'apt') {
lines.push(`RUN apt-get update && \\`)
lines.push(` apt-get install -y --no-install-recommends ${pkgs} && \\`)
if (config.enableCleanup) {
lines.push(` rm -rf /var/lib/apt/lists/*`)
}
} else if (config.packageManager === 'yum') {
lines.push(`RUN yum install -y ${pkgs} && \\`)
if (config.enableCleanup) {
lines.push(` yum clean all && rm -rf /var/cache/yum`)
}
} else if (config.packageManager === 'dnf') {
lines.push(`RUN dnf install -y ${pkgs} && \\`)
if (config.enableCleanup) {
lines.push(` dnf clean all && rm -rf /var/cache/dnf`)
}
}
lines.push(``)
}
}
// Create user
if (config.enableUser && config.enableUseradd && config.createUserName) {
lines.push(`RUN addgroup -S ${config.createUserName} && adduser -S ${config.createUserName} -G ${config.createUserName}`)
lines.push(``)
}
// COPY from builder stage
if (config.enableMultiStage) {
if (config.enableCopyChown) {
lines.push(`COPY --from=${config.builderAs} --chown=${config.copyChown} ${config.workdir || '/app'} ${config.copyDest}`)
} else {
lines.push(`COPY --from=${config.builderAs} ${config.workdir || '/app'} ${config.copyDest}`)
}
lines.push(``)
}
// COPY
if (config.enableCopy && !config.enableMultiStage) {
let copyFlags = []
if (config.enableCopyChown && config.copyChown) copyFlags.push(`--chown=${config.copyChown}`)
if (config.enableCopyChmod && config.copyChmod) copyFlags.push(`--chmod=${config.copyChmod}`)
const flags = copyFlags.length ? ` ${copyFlags.join(' ')}` : ''
lines.push(`COPY${flags} ${config.copySrc} ${config.copyDest}`)
lines.push(``)
}
// ADD
if (config.enableAdd && config.addSrc) {
lines.push(`ADD ${config.addSrc} ${config.addDest}`)
lines.push(``)
}
// App install (non-multi-stage)
if (!config.enableMultiStage && config.enableAppInstall && config.appInstallCmd) {
lines.push(`RUN ${config.appInstallCmd}`)
lines.push(``)
}
// Build cmd (non-multi-stage)
if (!config.enableMultiStage && config.enableBuildCmd && config.buildCmd) {
lines.push(`RUN ${config.buildCmd}`)
lines.push(``)
}
// VOLUME
if (config.enableVolume && config.volumePaths) {
const paths = config.volumePaths.split(/\s+/).filter(Boolean)
if (paths.length === 1) {
lines.push(`VOLUME ["${paths[0]}"]`)
} else {
lines.push(`VOLUME [${paths.map(p => `"${p}"`).join(', ')}]`)
}
lines.push(``)
}
// EXPOSE
if (config.enableExpose && config.exposePorts) {
lines.push(`EXPOSE ${config.exposePorts}`)
lines.push(``)
}
// USER
if (config.enableUser) {
lines.push(`USER ${config.userName}`)
lines.push(``)
}
// HEALTHCHECK
if (config.enableHealthcheck) {
if (config.healthcheckType === 'NONE') {
lines.push(`HEALTHCHECK NONE`)
} else {
let hc = `HEALTHCHECK`
if (config.healthcheckInterval) hc += ` --interval=${config.healthcheckInterval}`
if (config.healthcheckTimeout) hc += ` --timeout=${config.healthcheckTimeout}`
if (config.healthcheckRetries) hc += ` --retries=${config.healthcheckRetries}`
if (config.healthcheckStartPeriod) hc += ` --start-period=${config.healthcheckStartPeriod}`
hc += ` CMD ${config.healthcheckCmd}`
lines.push(hc)
}
lines.push(``)
}
// STOPSIGNAL
if (config.enableStopSignal) {
lines.push(`STOPSIGNAL ${config.stopSignal}`)
lines.push(``)
}
// SHELL
if (config.enableShell) {
lines.push(`SHELL ["${config.shellPath}", "${config.shellFlag}"]`)
lines.push(``)
}
// ENTRYPOINT
if (config.enableEntrypoint && config.entrypointCmd) {
const val = config.entrypointCmd.trim()
if (val.startsWith('[')) {
lines.push(`ENTRYPOINT ${val}`)
} else {
lines.push(`ENTRYPOINT ["${val}"]`)
}
lines.push(``)
}
// CMD
if (config.enableCmd && config.cmdValue) {
const val = config.cmdValue.trim()
if (config.cmdType === 'exec') {
if (val.startsWith('[')) {
lines.push(`CMD ${val}`)
} else {
lines.push(`CMD ["${val}"]`)
}
} else {
lines.push(`CMD ${val}`)
}
lines.push(``)
}
return lines.join('\n')
}