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
+75 -35
View File
@@ -235,47 +235,87 @@ export const k8sCronJobSchema = {
],
}
function toYaml(obj, indent = 0) {
const lines = []
const prefix = ' '.repeat(indent)
for (const [key, value] of Object.entries(obj)) {
// ======================== YAML 生成器 ========================
function toYaml(obj, indent) {
indent = indent || 0
var lines = []
var prefix = ''
for (var p = 0; p < indent; p++) prefix += ' '
var keys = Object.keys(obj)
for (var ki = 0; ki < keys.length; ki++) {
var key = keys[ki]
var value = obj[key]
if (value === null || value === undefined || value === '') continue
if (Array.isArray(value)) {
lines.push(`${prefix}${key}:`)
for (const item of value) {
lines.push(prefix + key + ':')
for (var ai = 0; ai < value.length; ai++) {
var item = value[ai]
if (typeof item === 'object' && item !== null) {
const entries = Object.entries(item).filter(([, v]) => v !== null && v !== undefined && v !== '')
if (entries.length === 0) continue
const first = entries[0]
lines.push(`${prefix} - ${first[0]}: ${typeof first[1] === 'object' ? '' : first[1]}`)
if (typeof first[1] === 'object') {
lines.push(toYaml(first[1], indent + 3))
}
for (let i = 1; i < entries.length; i++) {
const [k, v] = entries[i]
if (typeof v === 'object') {
lines.push(`${prefix} ${k}:`)
lines.push(toYaml(v, indent + 4))
} else {
lines.push(`${prefix} ${k}: ${v}`)
}
}
lines.push(renderArrayObject(item, indent + 1))
} else {
lines.push(`${prefix} - ${item}`)
lines.push(prefix + ' - ' + item)
}
}
} else if (typeof value === 'object') {
lines.push(`${prefix}${key}:`)
lines.push(prefix + key + ':')
lines.push(toYaml(value, indent + 1))
} else {
lines.push(`${prefix}${key}: ${value}`)
lines.push(prefix + key + ': ' + value)
}
}
return lines.join('\n')
}
function renderArrayObject(item, indent) {
var prefix = ''
for (var p = 0; p < indent; p++) prefix += ' '
var entries = Object.entries(item).filter(function(pair) { return pair[1] !== null && pair[1] !== undefined && pair[1] !== '' })
if (entries.length === 0) return ''
var lines = []
var first = entries[0]
var fk = first[0], fv = first[1]
if (Array.isArray(fv)) {
lines.push(prefix + '- ' + fk + ':')
for (var ai = 0; ai < fv.length; ai++) {
var arrItem = fv[ai]
if (typeof arrItem === 'object' && arrItem !== null) {
lines.push(renderArrayObject(arrItem, indent + 2))
} else {
lines.push(prefix + ' - ' + arrItem)
}
}
} else if (typeof fv === 'object' && fv !== null) {
lines.push(prefix + '- ' + fk + ':')
lines.push(toYaml(fv, indent + 2))
} else {
lines.push(prefix + '- ' + fk + ': ' + fv)
}
for (var i = 1; i < entries.length; i++) {
var k = entries[i][0], v = entries[i][1]
if (v === null || v === undefined || v === '') continue
if (Array.isArray(v)) {
lines.push(prefix + ' ' + k + ':')
for (var ai = 0; ai < v.length; ai++) {
var arrItem = v[ai]
if (typeof arrItem === 'object' && arrItem !== null) {
lines.push(renderArrayObject(arrItem, indent + 2))
} else {
lines.push(prefix + ' - ' + arrItem)
}
}
} else if (typeof v === 'object') {
lines.push(prefix + ' ' + k + ':')
lines.push(toYaml(v, indent + 2))
} else {
lines.push(prefix + ' ' + k + ': ' + v)
}
}
return lines.join('\n')
}
export function generateK8sCronJobYaml(config) {
const container = {
var container = {
name: config.name,
image: config.image,
imagePullPolicy: config.imagePullPolicy,
@@ -299,9 +339,9 @@ export function generateK8sCronJobYaml(config) {
// 环境变量
if (config.enableEnv && config.envVars) {
container.env = config.envVars.split('\n').filter(Boolean).map(line => {
const [k, ...v] = line.split('=')
return { name: k.trim(), value: v.join('=').trim() }
container.env = config.envVars.split('\n').filter(Boolean).map(function(line) {
var idx = line.indexOf('=')
return { name: line.substring(0, idx).trim(), value: line.substring(idx + 1).trim() }
})
}
if (config.enableEnvFromConfigMap || config.enableEnvFromSecret) {
@@ -311,11 +351,11 @@ export function generateK8sCronJobYaml(config) {
}
// 卷挂载
const volumes = []
var volumes = []
if (config.enableVolumeMount) {
container.volumeMounts = [{ name: config.volumeName, mountPath: config.volumeMountPath, readOnly: config.volumeReadOnly || undefined }]
const vol = { name: config.volumeName }
const vt = config.volumeType
var vol = { name: config.volumeName }
var vt = config.volumeType
if (vt === 'emptyDir') vol.emptyDir = {}
else if (vt === 'pvc') vol.persistentVolumeClaim = { claimName: config.pvcClaimName }
else if (vt === 'configMap') vol.configMap = { name: config.configMapName }
@@ -335,7 +375,7 @@ export function generateK8sCronJobYaml(config) {
}
}
const podSpec = {
var podSpec = {
containers: [container],
restartPolicy: config.restartPolicy,
}
@@ -351,7 +391,7 @@ export function generateK8sCronJobYaml(config) {
podSpec.securityContext = { fsGroup: config.fsGroup }
}
const cronjob = {
var cronjob = {
apiVersion: 'batch/v1',
kind: 'CronJob',
metadata: {
@@ -377,7 +417,7 @@ export function generateK8sCronJobYaml(config) {
},
}
const header = `# K8s CronJob - 由 ConfTemplate 生成\n# 生成时间: ${new Date().toLocaleString('zh-CN')}\n# 部署命令: kubectl apply -f ${config.fileName || 'cronjob.yaml'}\n`
var header = '# K8s CronJob - 由 ConfTemplate 生成\n# 生成时间: ' + new Date().toLocaleString('zh-CN') + '\n# 部署命令: kubectl apply -f ' + (config.fileName || 'cronjob.yaml') + '\n'
return header + '\n' + toYaml(cronjob)
}