k3s-deployer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs +1 -0
- package/index.d.ts +193 -0
- package/index.mjs +4 -0
- package/package.json +47 -0
- package/src/bootstrap/index.cjs +211 -0
- package/src/detect/index.cjs +461 -0
- package/src/dns/cloudflare.cjs +163 -0
- package/src/execute/index.cjs +386 -0
- package/src/index.cjs +67 -0
- package/src/mobile/index.cjs +1093 -0
- package/src/mobile/web-android-emulator-adapter.cjs +701 -0
- package/src/plan/index.cjs +200 -0
- package/src/runtime/index.cjs +16 -0
- package/src/runtime/local-runner.cjs +69 -0
- package/src/runtime/ssh-runner.cjs +206 -0
- package/src/shared/source.cjs +145 -0
- package/src/shared/utils.cjs +104 -0
- package/src/templates/dockerfile.cjs +114 -0
- package/src/templates/manifests.cjs +291 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const fs = require('node:fs/promises');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
|
|
5
|
+
function slugify(value) {
|
|
6
|
+
return String(value || '')
|
|
7
|
+
.trim()
|
|
8
|
+
.toLowerCase()
|
|
9
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
10
|
+
.replace(/^-+|-+$/g, '')
|
|
11
|
+
.replace(/--+/g, '-');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function toDatabaseName(value) {
|
|
15
|
+
return String(value || '')
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.replace(/[^a-z0-9]+/g, '')
|
|
18
|
+
.slice(0, 32) || 'appdb';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hashText(value) {
|
|
22
|
+
return crypto.createHash('sha1').update(String(value || '')).digest('hex');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function exists(filePath) {
|
|
26
|
+
try {
|
|
27
|
+
await fs.access(filePath);
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function readIfExists(filePath) {
|
|
35
|
+
if (!(await exists(filePath))) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return fs.readFile(filePath, 'utf8');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function readJsonIfExists(filePath) {
|
|
42
|
+
const text = await readIfExists(filePath);
|
|
43
|
+
if (!text) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return JSON.parse(text);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function listImmediateDirectories(rootPath) {
|
|
50
|
+
const entries = await fs.readdir(rootPath, { withFileTypes: true });
|
|
51
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function ensureDir(dirPath) {
|
|
55
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function shellQuote(value) {
|
|
59
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function posixRelative(rootPath, targetPath) {
|
|
63
|
+
const relative = path.relative(rootPath, targetPath) || '.';
|
|
64
|
+
return relative.split(path.sep).join(path.posix.sep);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function uniqueBy(items, keyFn) {
|
|
68
|
+
const map = new Map();
|
|
69
|
+
for (const item of items) {
|
|
70
|
+
map.set(keyFn(item), item);
|
|
71
|
+
}
|
|
72
|
+
return Array.from(map.values());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function filterPublicEnv(envMap) {
|
|
76
|
+
return Object.fromEntries(
|
|
77
|
+
Object.entries(envMap || {}).filter(([key]) =>
|
|
78
|
+
key.startsWith('VITE_') || key.startsWith('NEXT_PUBLIC_') || key.startsWith('REACT_APP_'),
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function deriveHostAddress(target) {
|
|
84
|
+
if (!target || target.kind === 'local') {
|
|
85
|
+
return target && target.hostAddress ? target.hostAddress : '127.0.0.1';
|
|
86
|
+
}
|
|
87
|
+
return target.hostAddress || target.host;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
deriveHostAddress,
|
|
92
|
+
ensureDir,
|
|
93
|
+
exists,
|
|
94
|
+
filterPublicEnv,
|
|
95
|
+
hashText,
|
|
96
|
+
listImmediateDirectories,
|
|
97
|
+
posixRelative,
|
|
98
|
+
readIfExists,
|
|
99
|
+
readJsonIfExists,
|
|
100
|
+
shellQuote,
|
|
101
|
+
slugify,
|
|
102
|
+
toDatabaseName,
|
|
103
|
+
uniqueBy,
|
|
104
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
function joinCommand(command) {
|
|
2
|
+
return Array.isArray(command) ? command.join(' ') : String(command || '');
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function renderNodeDockerfile(unit) {
|
|
6
|
+
const startCommand = joinCommand(unit.build.start || ['npm', 'start']);
|
|
7
|
+
const buildCommand = unit.build.build ? `RUN ${joinCommand(unit.build.build)}` : '';
|
|
8
|
+
return `FROM node:22-alpine
|
|
9
|
+
WORKDIR /app
|
|
10
|
+
COPY package*.json ./
|
|
11
|
+
COPY yarn.lock* pnpm-lock.yaml* ./
|
|
12
|
+
RUN npm install -g pnpm yarn >/dev/null 2>&1 || true
|
|
13
|
+
RUN if [ -f yarn.lock ]; then yarn install --frozen-lockfile; elif [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; else npm install; fi
|
|
14
|
+
COPY . .
|
|
15
|
+
${buildCommand}
|
|
16
|
+
EXPOSE ${unit.port || 3000}
|
|
17
|
+
CMD ${JSON.stringify(['sh', '-lc', startCommand])}
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function renderPythonDockerfile(unit) {
|
|
22
|
+
const installCommand = joinCommand(unit.build.install);
|
|
23
|
+
const startCommand = joinCommand(unit.build.start);
|
|
24
|
+
return `FROM python:3.12-slim
|
|
25
|
+
WORKDIR /app
|
|
26
|
+
COPY requirements.txt ./
|
|
27
|
+
RUN ${installCommand}
|
|
28
|
+
COPY . .
|
|
29
|
+
EXPOSE ${unit.port || 8000}
|
|
30
|
+
CMD ${JSON.stringify(['sh', '-lc', startCommand])}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function renderSpringDockerfile(unit) {
|
|
35
|
+
const buildCommand = joinCommand(unit.build.build);
|
|
36
|
+
const startCommand = joinCommand(unit.build.start);
|
|
37
|
+
return `FROM maven:3.9-eclipse-temurin-21 AS build
|
|
38
|
+
WORKDIR /app
|
|
39
|
+
COPY . .
|
|
40
|
+
RUN ${buildCommand}
|
|
41
|
+
FROM eclipse-temurin:21-jre
|
|
42
|
+
WORKDIR /app
|
|
43
|
+
COPY --from=build /app/target/*.jar /app/app.jar
|
|
44
|
+
COPY --from=build /app/build/libs/*.jar /app/app.jar
|
|
45
|
+
EXPOSE ${unit.port || 8080}
|
|
46
|
+
CMD ${JSON.stringify(['sh', '-lc', startCommand.replace('$(find target build/libs -name "*.jar" | head -n 1)', '/app/app.jar')])}
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function renderGoDockerfile(unit) {
|
|
51
|
+
const buildCommand = joinCommand(unit.build.build);
|
|
52
|
+
return `FROM golang:1.23 AS build
|
|
53
|
+
WORKDIR /app
|
|
54
|
+
COPY go.mod go.sum* ./
|
|
55
|
+
RUN go mod download
|
|
56
|
+
COPY . .
|
|
57
|
+
RUN ${buildCommand}
|
|
58
|
+
FROM alpine:3.20
|
|
59
|
+
WORKDIR /app
|
|
60
|
+
COPY --from=build /app/app /app/app
|
|
61
|
+
EXPOSE ${unit.port || 8080}
|
|
62
|
+
CMD ["./app"]
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function renderRustDockerfile(unit) {
|
|
67
|
+
return `FROM rust:1.82 AS build
|
|
68
|
+
WORKDIR /app
|
|
69
|
+
COPY . .
|
|
70
|
+
RUN cargo build --release
|
|
71
|
+
FROM debian:bookworm-slim
|
|
72
|
+
WORKDIR /app
|
|
73
|
+
COPY --from=build /app/target/release /app/target/release
|
|
74
|
+
EXPOSE ${unit.port || 3000}
|
|
75
|
+
CMD ["sh", "-lc", ${JSON.stringify(joinCommand(unit.build.start))}]
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function renderRubyDockerfile(unit) {
|
|
80
|
+
return `FROM ruby:3.3
|
|
81
|
+
WORKDIR /app
|
|
82
|
+
COPY Gemfile Gemfile.lock* ./
|
|
83
|
+
RUN bundle install
|
|
84
|
+
COPY . .
|
|
85
|
+
EXPOSE ${unit.port || 3000}
|
|
86
|
+
CMD ${JSON.stringify(['sh', '-lc', joinCommand(unit.build.start)])}
|
|
87
|
+
`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function createGeneratedDockerfile(unit) {
|
|
91
|
+
if (['react', 'nextjs', 'vue', 'angular', 'nestjs'].includes(unit.framework)) {
|
|
92
|
+
return renderNodeDockerfile(unit);
|
|
93
|
+
}
|
|
94
|
+
if (unit.framework === 'django') {
|
|
95
|
+
return renderPythonDockerfile(unit);
|
|
96
|
+
}
|
|
97
|
+
if (unit.framework === 'springboot') {
|
|
98
|
+
return renderSpringDockerfile(unit);
|
|
99
|
+
}
|
|
100
|
+
if (['gin', 'echo', 'fiber'].includes(unit.framework)) {
|
|
101
|
+
return renderGoDockerfile(unit);
|
|
102
|
+
}
|
|
103
|
+
if (['axum', 'actix-web'].includes(unit.framework)) {
|
|
104
|
+
return renderRustDockerfile(unit);
|
|
105
|
+
}
|
|
106
|
+
if (['rails', 'sinatra'].includes(unit.framework)) {
|
|
107
|
+
return renderRubyDockerfile(unit);
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`Unsupported Dockerfile generation for ${unit.framework}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
createGeneratedDockerfile,
|
|
114
|
+
};
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
function yamlValue(value) {
|
|
2
|
+
return JSON.stringify(String(value));
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function renderKeyValueBlock(entries, indent) {
|
|
6
|
+
return Object.entries(entries)
|
|
7
|
+
.map(([key, value]) => `${' '.repeat(indent)}${key}: ${yamlValue(value)}`)
|
|
8
|
+
.join('\n');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function createSecretManifest(name, namespace, envMap) {
|
|
12
|
+
if (!envMap || Object.keys(envMap).length === 0) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const encoded = Object.fromEntries(
|
|
16
|
+
Object.entries(envMap).map(([key, value]) => [key, Buffer.from(String(value)).toString('base64')]),
|
|
17
|
+
);
|
|
18
|
+
return `apiVersion: v1
|
|
19
|
+
kind: Secret
|
|
20
|
+
metadata:
|
|
21
|
+
name: ${name}
|
|
22
|
+
namespace: ${namespace}
|
|
23
|
+
type: Opaque
|
|
24
|
+
data:
|
|
25
|
+
${renderKeyValueBlock(encoded, 2)}
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createConfigMapManifest(name, namespace, envMap) {
|
|
30
|
+
if (!envMap || Object.keys(envMap).length === 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return `apiVersion: v1
|
|
34
|
+
kind: ConfigMap
|
|
35
|
+
metadata:
|
|
36
|
+
name: ${name}
|
|
37
|
+
namespace: ${namespace}
|
|
38
|
+
data:
|
|
39
|
+
${renderKeyValueBlock(envMap, 2)}
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function createTargetNodePlacement(indent = 6) {
|
|
44
|
+
const prefix = ' '.repeat(indent);
|
|
45
|
+
const nested = ' '.repeat(indent + 2);
|
|
46
|
+
const nestedMore = ' '.repeat(indent + 4);
|
|
47
|
+
return `${prefix}nodeSelector:
|
|
48
|
+
${nested}k3s-deployer-target: "true"
|
|
49
|
+
${prefix}tolerations:
|
|
50
|
+
${nested}- key: node-role.kubernetes.io/control-plane
|
|
51
|
+
${nestedMore}operator: Exists
|
|
52
|
+
${nestedMore}effect: NoSchedule
|
|
53
|
+
${nested}- key: node-role.kubernetes.io/master
|
|
54
|
+
${nestedMore}operator: Exists
|
|
55
|
+
${nestedMore}effect: NoSchedule`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createDeploymentManifest(spec) {
|
|
59
|
+
const imagePullPolicy =
|
|
60
|
+
spec.imagePullPolicy ||
|
|
61
|
+
(/^(localhost|127\.0\.0\.1)(:\d+)?\//.test(spec.image)
|
|
62
|
+
? 'IfNotPresent'
|
|
63
|
+
: 'Always');
|
|
64
|
+
const envFrom = [];
|
|
65
|
+
if (spec.secretName) {
|
|
66
|
+
envFrom.push(
|
|
67
|
+
` - secretRef:\n name: ${spec.secretName}`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (spec.configMapName) {
|
|
71
|
+
envFrom.push(
|
|
72
|
+
` - configMapRef:\n name: ${spec.configMapName}`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
const volumeMounts = spec.volumeMountPath
|
|
76
|
+
? ` volumeMounts:
|
|
77
|
+
- name: app-storage
|
|
78
|
+
mountPath: ${spec.volumeMountPath}`
|
|
79
|
+
: '';
|
|
80
|
+
const volumes = spec.volumeClaimName
|
|
81
|
+
? ` volumes:
|
|
82
|
+
- name: app-storage
|
|
83
|
+
persistentVolumeClaim:
|
|
84
|
+
claimName: ${spec.volumeClaimName}`
|
|
85
|
+
: '';
|
|
86
|
+
return `apiVersion: apps/v1
|
|
87
|
+
kind: Deployment
|
|
88
|
+
metadata:
|
|
89
|
+
name: ${spec.name}
|
|
90
|
+
namespace: ${spec.namespace}
|
|
91
|
+
spec:
|
|
92
|
+
replicas: 1
|
|
93
|
+
selector:
|
|
94
|
+
matchLabels:
|
|
95
|
+
app: ${spec.name}
|
|
96
|
+
strategy:
|
|
97
|
+
type: RollingUpdate
|
|
98
|
+
rollingUpdate:
|
|
99
|
+
maxSurge: 25%
|
|
100
|
+
maxUnavailable: 25%
|
|
101
|
+
template:
|
|
102
|
+
metadata:
|
|
103
|
+
labels:
|
|
104
|
+
app: ${spec.name}
|
|
105
|
+
spec:
|
|
106
|
+
${createTargetNodePlacement(6)}
|
|
107
|
+
containers:
|
|
108
|
+
- name: ${spec.name}
|
|
109
|
+
image: ${spec.image}
|
|
110
|
+
imagePullPolicy: ${imagePullPolicy}
|
|
111
|
+
ports:
|
|
112
|
+
- containerPort: ${spec.port}
|
|
113
|
+
${envFrom.length ? ` envFrom:\n${envFrom.join('\n')}` : ''}${volumeMounts ? `\n${volumeMounts}` : ''}${volumes ? `\n${volumes}` : ''}
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function createServiceManifest(spec) {
|
|
118
|
+
const nodePort = spec.nodePort ? `\n nodePort: ${spec.nodePort}` : '';
|
|
119
|
+
return `apiVersion: v1
|
|
120
|
+
kind: Service
|
|
121
|
+
metadata:
|
|
122
|
+
name: ${spec.name}
|
|
123
|
+
namespace: ${spec.namespace}
|
|
124
|
+
spec:
|
|
125
|
+
type: ${spec.nodePort ? 'NodePort' : 'ClusterIP'}
|
|
126
|
+
selector:
|
|
127
|
+
app: ${spec.targetName || spec.name}
|
|
128
|
+
ports:
|
|
129
|
+
- protocol: TCP
|
|
130
|
+
port: ${spec.port}
|
|
131
|
+
targetPort: ${spec.targetPort || spec.port}${nodePort}
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function createIngressManifest(spec) {
|
|
136
|
+
return `apiVersion: networking.k8s.io/v1
|
|
137
|
+
kind: Ingress
|
|
138
|
+
metadata:
|
|
139
|
+
name: ${spec.name}
|
|
140
|
+
namespace: ${spec.namespace}
|
|
141
|
+
annotations:
|
|
142
|
+
kubernetes.io/ingress.class: nginx
|
|
143
|
+
cert-manager.io/cluster-issuer: letsencrypt-production
|
|
144
|
+
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
|
145
|
+
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
|
|
146
|
+
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"
|
|
147
|
+
nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
|
|
148
|
+
spec:
|
|
149
|
+
ingressClassName: nginx
|
|
150
|
+
tls:
|
|
151
|
+
- hosts:
|
|
152
|
+
- ${spec.domain}
|
|
153
|
+
secretName: ${spec.tlsSecretName || `${spec.serviceName}-tls`}
|
|
154
|
+
rules:
|
|
155
|
+
- host: ${spec.domain}
|
|
156
|
+
http:
|
|
157
|
+
paths:
|
|
158
|
+
- path: /
|
|
159
|
+
pathType: Prefix
|
|
160
|
+
backend:
|
|
161
|
+
service:
|
|
162
|
+
name: ${spec.serviceName}
|
|
163
|
+
port:
|
|
164
|
+
number: ${spec.servicePort || 80}
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function createPersistentVolumeClaim(name, namespace, size) {
|
|
169
|
+
return `apiVersion: v1
|
|
170
|
+
kind: PersistentVolumeClaim
|
|
171
|
+
metadata:
|
|
172
|
+
name: ${name}
|
|
173
|
+
namespace: ${namespace}
|
|
174
|
+
spec:
|
|
175
|
+
accessModes:
|
|
176
|
+
- ReadWriteOnce
|
|
177
|
+
resources:
|
|
178
|
+
requests:
|
|
179
|
+
storage: ${size}
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function createDatabaseManifests(input) {
|
|
184
|
+
const manifests = [];
|
|
185
|
+
const serviceName = `${input.projectSlug}-${input.kind}`;
|
|
186
|
+
|
|
187
|
+
if (input.kind === 'sqlite') {
|
|
188
|
+
manifests.push(createPersistentVolumeClaim(`${serviceName}-pvc`, input.namespace, '1Gi'));
|
|
189
|
+
return manifests;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const pvcKinds = new Set(['postgresql', 'mysql', 'mongodb', 'elasticsearch']);
|
|
193
|
+
if (pvcKinds.has(input.kind)) {
|
|
194
|
+
manifests.push(createPersistentVolumeClaim(`${serviceName}-pvc`, input.namespace, '1Gi'));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const imageByKind = {
|
|
198
|
+
postgresql: 'postgres:16',
|
|
199
|
+
mysql: 'mysql:8.4',
|
|
200
|
+
mongodb: 'mongo:7',
|
|
201
|
+
redis: 'redis:7',
|
|
202
|
+
elasticsearch: 'docker.elastic.co/elasticsearch/elasticsearch:8.15.0',
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const envLines = [];
|
|
206
|
+
if (input.kind === 'postgresql') {
|
|
207
|
+
envLines.push(' - name: POSTGRES_DB\n value: appdb');
|
|
208
|
+
envLines.push(' - name: POSTGRES_USER\n value: app');
|
|
209
|
+
envLines.push(' - name: POSTGRES_PASSWORD\n value: apppass');
|
|
210
|
+
}
|
|
211
|
+
if (input.kind === 'mysql') {
|
|
212
|
+
envLines.push(' - name: MYSQL_DATABASE\n value: appdb');
|
|
213
|
+
envLines.push(' - name: MYSQL_USER\n value: app');
|
|
214
|
+
envLines.push(' - name: MYSQL_PASSWORD\n value: apppass');
|
|
215
|
+
envLines.push(' - name: MYSQL_ROOT_PASSWORD\n value: rootpass');
|
|
216
|
+
}
|
|
217
|
+
if (input.kind === 'elasticsearch') {
|
|
218
|
+
envLines.push(' - name: discovery.type\n value: single-node');
|
|
219
|
+
envLines.push(' - name: xpack.security.enabled\n value: "false"');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const ports = {
|
|
223
|
+
postgresql: 5432,
|
|
224
|
+
mysql: 3306,
|
|
225
|
+
mongodb: 27017,
|
|
226
|
+
redis: 6379,
|
|
227
|
+
elasticsearch: 9200,
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const mountPathByKind = {
|
|
231
|
+
postgresql: '/var/lib/postgresql/data',
|
|
232
|
+
mysql: '/var/lib/mysql',
|
|
233
|
+
mongodb: '/data/db',
|
|
234
|
+
elasticsearch: '/usr/share/elasticsearch/data',
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const volumeMount = mountPathByKind[input.kind]
|
|
238
|
+
? ` volumeMounts:
|
|
239
|
+
- name: data
|
|
240
|
+
mountPath: ${mountPathByKind[input.kind]}`
|
|
241
|
+
: '';
|
|
242
|
+
const volumes = mountPathByKind[input.kind]
|
|
243
|
+
? ` volumes:
|
|
244
|
+
- name: data
|
|
245
|
+
persistentVolumeClaim:
|
|
246
|
+
claimName: ${serviceName}-pvc`
|
|
247
|
+
: '';
|
|
248
|
+
|
|
249
|
+
manifests.push(`apiVersion: apps/v1
|
|
250
|
+
kind: Deployment
|
|
251
|
+
metadata:
|
|
252
|
+
name: ${serviceName}
|
|
253
|
+
namespace: ${input.namespace}
|
|
254
|
+
spec:
|
|
255
|
+
replicas: 1
|
|
256
|
+
selector:
|
|
257
|
+
matchLabels:
|
|
258
|
+
app: ${serviceName}
|
|
259
|
+
template:
|
|
260
|
+
metadata:
|
|
261
|
+
labels:
|
|
262
|
+
app: ${serviceName}
|
|
263
|
+
spec:
|
|
264
|
+
${createTargetNodePlacement(6)}
|
|
265
|
+
containers:
|
|
266
|
+
- name: ${serviceName}
|
|
267
|
+
image: ${imageByKind[input.kind]}
|
|
268
|
+
ports:
|
|
269
|
+
- containerPort: ${ports[input.kind]}
|
|
270
|
+
${envLines.length ? ` env:\n${envLines.join('\n')}\n` : ''}${volumeMount ? `${volumeMount}\n` : ''}${volumes ? `${volumes}\n` : ''}`);
|
|
271
|
+
|
|
272
|
+
manifests.push(
|
|
273
|
+
createServiceManifest({
|
|
274
|
+
name: serviceName,
|
|
275
|
+
namespace: input.namespace,
|
|
276
|
+
port: ports[input.kind],
|
|
277
|
+
}),
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
return manifests;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = {
|
|
284
|
+
createConfigMapManifest,
|
|
285
|
+
createDatabaseManifests,
|
|
286
|
+
createDeploymentManifest,
|
|
287
|
+
createIngressManifest,
|
|
288
|
+
createPersistentVolumeClaim,
|
|
289
|
+
createSecretManifest,
|
|
290
|
+
createServiceManifest,
|
|
291
|
+
};
|