@nathapp/na-cli 1.0.6 → 1.0.8
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/README.md +28 -2
- package/bunfig.toml +3 -0
- package/dist/templates/k8s-deployment/.gitignore-rename +2 -0
- package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/values.yaml +1 -1
- package/dist/templates/k8s-deployment/resources/charts/mysql/values.yaml +5 -1
- package/dist/templates/k8s-deployment/resources/charts/redis/values.yaml +1 -1
- package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/values.yaml +1 -1
- package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/ingressroutetcp.yaml +1 -0
- package/dist/templates/k8s-deployment/services/charts/sample-nginx/values.yaml +6 -8
- package/dist/templates/k8s-deployment/templates/_cronjob.tpl +1 -1
- package/dist/templates/k8s-deployment/templates/_deployment.tpl +2 -2
- package/dist/templates/k8s-deployment/templates/_ingressroutetcp.tpl +135 -0
- package/dist/templates/k8s-deployment/templates/_job.tpl +1 -1
- package/dist/templates/k8s-deployment/templates/_pod.tpl +2 -2
- package/dist/templates/k8s-deployment/templates/_statefulset.tpl +2 -2
- package/dist/templates/k8s-deployment/templates/root-pull-secret.yaml +4 -2
- package/dist/templates/k8s-deployment/templates/root-secret.yaml +4 -2
- package/dist/templates/k8s-deployment/test-values.yaml +10 -0
- package/dist/templates/k8s-deployment/values.yaml +1 -1
- package/dist/templates/k8s-helm-chart/templates/ingressroutetcp.yaml +1 -0
- package/dist/templates/k8s-helm-chart/templates/job.yaml +1 -0
- package/dist/templates/k8s-helm-chart/values.yaml +127 -13
- package/dist/templates/nestjs-api/.gitignore-rename +1 -0
- package/dist/templates/nestjs-api/.oxlintrc.json +18 -0
- package/dist/templates/nestjs-api/Dockerfile +15 -21
- package/dist/templates/nestjs-api/README.md +22 -30
- package/dist/templates/nestjs-api/package.json +58 -72
- package/dist/templates/nestjs-api/vitest.config.mts +33 -0
- package/dist/templates/nestjs-library/.gitignore-rename +1 -0
- package/dist/templates/nestjs-library/.npmignore-rename +5 -2
- package/dist/templates/nestjs-library/.oxlintrc.json +18 -0
- package/dist/templates/nestjs-library/README.md +24 -0
- package/dist/templates/nestjs-library/package.json +43 -33
- package/dist/templates/nestjs-library/vitest.config.mts +29 -0
- package/dist/utils/template.js +1 -1
- package/dist/utils/template.js.map +1 -1
- package/package.json +3 -2
- package/dist/templates/nestjs-api/test/jest-e2e.json +0 -12
- package/dist/templates/nestjs-api/test/jest-test.json +0 -26
- package/dist/templates/nestjs-library/test/jest-test.json +0 -23
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ You can provide answers directly via command-line flags. If both `--template` an
|
|
|
39
39
|
- `--k8s_chart_registry_host`: `aliyun`, `aws`, `dockerhub`, or `custom`.
|
|
40
40
|
- `--k8s_image_name`: Full image name (default: `bitnami/kafka`).
|
|
41
41
|
- `--k8s_image_version`: Version tag (default: `1.0.0`).
|
|
42
|
-
- `--k8s_chart_kind`: `Deployment`, `StatefulSet`, or `
|
|
42
|
+
- `--k8s_chart_kind`: `Deployment`, `StatefulSet`, `CronJob`, or `Job` (default: `Deployment`). A generated `Job` chart runs as a `post-install,post-upgrade` Helm hook (a plain Job's pod template is immutable, so upgrades would fail). Switching it to `pre-install,pre-upgrade` (e.g. migrations before the app rolls out) only works if everything it references is created outside the chart (`fromKeyRef` secrets/config, an existing pull secret): pre-install hooks run before the release's own objects exist.
|
|
43
43
|
- `--k8s_chart_registry_region`: (For Aliyun/AWS) default: `ap-southeast-3`.
|
|
44
44
|
- `--k8s_chart_aws_account_id`: (For AWS) default: `123456789`.
|
|
45
45
|
|
|
@@ -61,6 +61,23 @@ The CLI understands the relationship between infrastructure projects and service
|
|
|
61
61
|
|
|
62
62
|
This allows you to manage modular services within a master deployment project without manually navigating to sub-folders.
|
|
63
63
|
|
|
64
|
+
#### Deployment defaults (`k8s-deployment` / `k8s-helm-chart`)
|
|
65
|
+
|
|
66
|
+
- **Ingress**: Traefik (`className: traefik`, `web` entrypoint), no TLS in the chart. TLS is
|
|
67
|
+
expected to terminate upstream (e.g. Cloudflare Tunnel). Hosts are flat:
|
|
68
|
+
`{{SERVICE_BASE_NAME}}-<chart>.{{SERVICE_BASE_DOMAIN}}`, where `SERVICE_BASE_NAME` is the release name.
|
|
69
|
+
- **TCP routing**: set `ingressRouteTCP` in a chart's values to render a Traefik `IngressRouteTCP`.
|
|
70
|
+
- **Review apps**: merge requests run `make review`, deploying release `<project>-<branch-slug>`
|
|
71
|
+
with `test-values.yaml` into `REVIEW_KUBE_NAMESPACE` (default `<CI_KUBE_NAMESPACE>-review`,
|
|
72
|
+
never the production namespace). Names over 30 chars become `<first 24>-<5-digit cksum>`.
|
|
73
|
+
GitLab stops it via `stop-review` when the MR is merged or closed, or after one week.
|
|
74
|
+
Review apps run branch code with cluster access: scope `KUBECONFIG` per environment
|
|
75
|
+
(`production` = protected credential, `review/*` = credential limited to the review namespace).
|
|
76
|
+
- **CI image**: `HELM_CI_IMAGE` (default `alpine/helm:3.22.0`). Pin deploy jobs to a runner that
|
|
77
|
+
can reach the cluster with `default.tags`.
|
|
78
|
+
- **Lint**: `make lint` render-checks both releases with `helm template` against `values.yaml`
|
|
79
|
+
and `test-values.yaml`.
|
|
80
|
+
|
|
64
81
|
---
|
|
65
82
|
|
|
66
83
|
### 3. Environment Variable Conversion
|
|
@@ -86,9 +103,18 @@ na yml-env -i config.yaml -o .env
|
|
|
86
103
|
## Available Templates
|
|
87
104
|
The CLI currently supports the following project types:
|
|
88
105
|
- `db-schema`: Database migration and schema projects.
|
|
89
|
-
- `k8s-deployment`:
|
|
106
|
+
- `k8s-deployment`: Umbrella Helm deployment project (resources + services releases, GitLab CI with review apps).
|
|
90
107
|
- `k8s-helm-chart`: Comprehensive Helm chart bootstrapping.
|
|
91
108
|
- `mxw-base-api-express`: Express-based API boilerplate.
|
|
92
109
|
- `ts-library`: TypeScript library project.
|
|
93
110
|
- `nestjs-api`: Professional NestJS setup with platform choices.
|
|
94
111
|
- `vuexy-portal`: Frontend portal based on the Vuexy template.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Development
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
bun install
|
|
119
|
+
bun run test # builds dist/, then runs test/ (helm-dependent tests skip when helm is absent)
|
|
120
|
+
```
|
package/bunfig.toml
ADDED
|
@@ -4,12 +4,16 @@ kind: StatefulSet
|
|
|
4
4
|
replicaCount: 1
|
|
5
5
|
image:
|
|
6
6
|
repository: mysql
|
|
7
|
-
tag: "
|
|
7
|
+
tag: "8.4"
|
|
8
8
|
pullPolicy: IfNotPresent
|
|
9
9
|
|
|
10
10
|
service:
|
|
11
11
|
type: ClusterIP
|
|
12
12
|
port: 3306
|
|
13
13
|
|
|
14
|
+
# MySQL 8.4 notes: the container refuses to start with an empty root password, so set it
|
|
15
|
+
# (from a CI variable, never committed); mysql_native_password is off by default, so old
|
|
16
|
+
# clients need `mysql-native-password=ON` under [mysqld] in a mounted mysql.cnf (config +
|
|
17
|
+
# volumeMounts); a 5.7 data volume cannot be opened by 8.4 directly (upgrade via 8.0).
|
|
14
18
|
secret:
|
|
15
19
|
MYSQL_ROOT_PASSWORD: ""
|
package/dist/templates/k8s-deployment/services/charts/sample-nginx/templates/ingressroutetcp.yaml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{{- include "root.ingressroutetcp" $ }}
|
|
@@ -28,16 +28,14 @@ service:
|
|
|
28
28
|
port: 80
|
|
29
29
|
|
|
30
30
|
ingress:
|
|
31
|
+
className: "traefik"
|
|
31
32
|
annotations:
|
|
32
|
-
|
|
33
|
-
nginx.ingress.kubernetes.io/rewrite-target: /$1
|
|
33
|
+
traefik.ingress.kubernetes.io/router.entrypoints: web
|
|
34
34
|
hosts:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
hosts:
|
|
40
|
-
- www.sample.com
|
|
35
|
+
- host: "{{SERVICE_BASE_NAME}}-sample.{{SERVICE_BASE_DOMAIN}}"
|
|
36
|
+
paths:
|
|
37
|
+
- path: "/"
|
|
38
|
+
pathType: "Prefix"
|
|
41
39
|
|
|
42
40
|
readinessProbe:
|
|
43
41
|
httpGet:
|
|
@@ -238,9 +238,9 @@ spec:
|
|
|
238
238
|
claimName: {{ include (print $.Chart.Name ".fullname") $ }}-{{ .claimName }}
|
|
239
239
|
{{- end }}
|
|
240
240
|
{{- else }}
|
|
241
|
-
|
|
241
|
+
- {{ toYaml . | nindent 10 | trim }}
|
|
242
242
|
{{- end }}
|
|
243
243
|
{{- end }}
|
|
244
244
|
{{- end }}
|
|
245
245
|
{{- end }}
|
|
246
|
-
{{- end }}
|
|
246
|
+
{{- end }}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{{- define "root.ingressroutetcp" -}}
|
|
2
|
+
{{- if and .Values.enabled .Values.ingressRouteTCP -}}
|
|
3
|
+
{{- $fullName := include (print $.Chart.Name ".fullname") . -}}
|
|
4
|
+
{{- $svcPort := .Values.service.port -}}
|
|
5
|
+
apiVersion: traefik.io/v1alpha1
|
|
6
|
+
kind: IngressRouteTCP
|
|
7
|
+
metadata:
|
|
8
|
+
name: {{ .Values.ingressRouteTCP.name | default (printf "%s-tcp" $fullName) }}
|
|
9
|
+
{{- if .Values.ingressRouteTCP.annotations }}
|
|
10
|
+
annotations:
|
|
11
|
+
{{- with .Values.ingressRouteTCP.annotations }}
|
|
12
|
+
{{- toYaml . | nindent 4 }}
|
|
13
|
+
{{- end }}
|
|
14
|
+
{{- end }}
|
|
15
|
+
labels:
|
|
16
|
+
{{- include (print $.Chart.Name ".labels") . | nindent 4 }}
|
|
17
|
+
spec:
|
|
18
|
+
{{- if .Values.ingressRouteTCP.entryPoints }}
|
|
19
|
+
entryPoints:
|
|
20
|
+
{{- range .Values.ingressRouteTCP.entryPoints }}
|
|
21
|
+
- {{ include "root.global" (list $ .) }}
|
|
22
|
+
{{- end }}
|
|
23
|
+
{{- end }}
|
|
24
|
+
routes:
|
|
25
|
+
{{- if .Values.ingressRouteTCP.routes }}
|
|
26
|
+
{{- range $routeIndex, $route := .Values.ingressRouteTCP.routes }}
|
|
27
|
+
- match: {{ include "root.global" (list $ $route.match) }}
|
|
28
|
+
{{- if $route.priority }}
|
|
29
|
+
priority: {{ $route.priority }}
|
|
30
|
+
{{- end }}
|
|
31
|
+
{{- if $route.middlewares }}
|
|
32
|
+
middlewares:
|
|
33
|
+
{{- range $route.middlewares }}
|
|
34
|
+
- name: {{ include "root.global" (list $ .name) }}
|
|
35
|
+
{{- if .namespace }}
|
|
36
|
+
namespace: {{ include "root.global" (list $ .namespace) }}
|
|
37
|
+
{{- end }}
|
|
38
|
+
{{- end }}
|
|
39
|
+
{{- end }}
|
|
40
|
+
{{- if $route.services }}
|
|
41
|
+
services:
|
|
42
|
+
{{- range $route.services }}
|
|
43
|
+
- name: {{ include "root.global" (list $ .name) | default $fullName }}
|
|
44
|
+
{{- if .namespace }}
|
|
45
|
+
namespace: {{ include "root.global" (list $ .namespace) }}
|
|
46
|
+
{{- end }}
|
|
47
|
+
{{- if .port }}
|
|
48
|
+
port: {{ .port }}
|
|
49
|
+
{{- else if $svcPort }}
|
|
50
|
+
port: {{ $svcPort }}
|
|
51
|
+
{{- end }}
|
|
52
|
+
{{- if .weight }}
|
|
53
|
+
weight: {{ .weight }}
|
|
54
|
+
{{- end }}
|
|
55
|
+
{{- if .terminationDelay }}
|
|
56
|
+
terminationDelay: {{ .terminationDelay }}
|
|
57
|
+
{{- end }}
|
|
58
|
+
{{- if .proxyProtocol }}
|
|
59
|
+
proxyProtocol:
|
|
60
|
+
version: {{ .proxyProtocol.version }}
|
|
61
|
+
{{- end }}
|
|
62
|
+
{{- if .serversTransport }}
|
|
63
|
+
serversTransport: {{ include "root.global" (list $ .serversTransport) }}
|
|
64
|
+
nativeLB: {{ .nativeLB | default false }}
|
|
65
|
+
nodePortLB: {{ .nodePortLB | default false }}
|
|
66
|
+
{{- end }}
|
|
67
|
+
{{- end }}
|
|
68
|
+
{{- end }}
|
|
69
|
+
{{- end }}
|
|
70
|
+
{{- end }}
|
|
71
|
+
{{- if .Values.ingressRouteTCP.host }}
|
|
72
|
+
- match: HostSNI(`{{ include "root.global" (list . .Values.ingressRouteTCP.host) }}`)
|
|
73
|
+
{{- if .Values.ingressRouteTCP.middlewares }}
|
|
74
|
+
middlewares:
|
|
75
|
+
{{- range .Values.ingressRouteTCP.middlewares }}
|
|
76
|
+
- name: {{ include "root.global" (list $ .name) }}
|
|
77
|
+
{{- if .namespace }}
|
|
78
|
+
namespace: {{ include "root.global" (list $ .namespace) }}
|
|
79
|
+
{{- end }}
|
|
80
|
+
{{- end }}
|
|
81
|
+
{{- end }}
|
|
82
|
+
services:
|
|
83
|
+
- name: {{ $fullName }}
|
|
84
|
+
port: {{ $svcPort }}
|
|
85
|
+
{{- if .Values.ingressRouteTCP.terminationDelay }}
|
|
86
|
+
terminationDelay: {{ .Values.ingressRouteTCP.terminationDelay }}
|
|
87
|
+
{{- end }}
|
|
88
|
+
{{- if .Values.ingressRouteTCP.proxyProtocol }}
|
|
89
|
+
proxyProtocol:
|
|
90
|
+
version: {{ .Values.ingressRouteTCP.proxyProtocol.version }}
|
|
91
|
+
{{- end }}
|
|
92
|
+
{{- if .Values.ingressRouteTCP.serversTransport }}
|
|
93
|
+
serversTransport: {{ include "root.global" (list . .Values.ingressRouteTCP.serversTransport) }}
|
|
94
|
+
{{- end }}
|
|
95
|
+
nativeLB: {{ .Values.ingressRouteTCP.nativeLB | default false }}
|
|
96
|
+
nodePortLB: {{ .Values.ingressRouteTCP.nodePortLB | default false }}
|
|
97
|
+
{{- end }}
|
|
98
|
+
{{- if .Values.ingressRouteTCP.tls }}
|
|
99
|
+
tls:
|
|
100
|
+
{{- with .Values.ingressRouteTCP.tls }}
|
|
101
|
+
{{- if .secretName }}
|
|
102
|
+
secretName: {{ include "root.global" (list $ .secretName) }}
|
|
103
|
+
{{- end }}
|
|
104
|
+
{{- if .options }}
|
|
105
|
+
options:
|
|
106
|
+
name: {{ include "root.global" (list $ .options.name) }}
|
|
107
|
+
{{- if .options.namespace }}
|
|
108
|
+
namespace: {{ include "root.global" (list $ .options.namespace) }}
|
|
109
|
+
{{- end }}
|
|
110
|
+
{{- end }}
|
|
111
|
+
{{- if .certResolver }}
|
|
112
|
+
certResolver: {{ include "root.global" (list $ .certResolver) }}
|
|
113
|
+
{{- end }}
|
|
114
|
+
{{- if .domains }}
|
|
115
|
+
domains:
|
|
116
|
+
{{- range .domains }}
|
|
117
|
+
- main: {{ include "root.global" (list $ .main) }}
|
|
118
|
+
{{- if .sans }}
|
|
119
|
+
sans:
|
|
120
|
+
{{- range .sans }}
|
|
121
|
+
- {{ include "root.global" (list $ .) }}
|
|
122
|
+
{{- end }}
|
|
123
|
+
{{- end }}
|
|
124
|
+
{{- end }}
|
|
125
|
+
{{- end }}
|
|
126
|
+
{{- if .store }}
|
|
127
|
+
store: {{ include "root.global" (list $ .store) }}
|
|
128
|
+
{{- end }}
|
|
129
|
+
{{- if .passthrough }}
|
|
130
|
+
passthrough: {{ .passthrough }}
|
|
131
|
+
{{- end }}
|
|
132
|
+
{{- end }}
|
|
133
|
+
{{- end }}
|
|
134
|
+
{{- end }}
|
|
135
|
+
{{- end }}
|
|
@@ -206,9 +206,9 @@ spec:
|
|
|
206
206
|
claimName: {{ include (print $.Chart.Name ".fullname") $ }}-{{ .claimName }}
|
|
207
207
|
{{- end }}
|
|
208
208
|
{{- else }}
|
|
209
|
-
|
|
209
|
+
- {{ toYaml . | nindent 6 | trim }}
|
|
210
210
|
{{- end }}
|
|
211
211
|
{{- end }}
|
|
212
212
|
{{- end }}
|
|
213
213
|
{{- end }}
|
|
214
|
-
{{- end }}
|
|
214
|
+
{{- end }}
|
|
@@ -236,9 +236,9 @@ spec:
|
|
|
236
236
|
claimName: {{ include (print $.Chart.Name ".fullname") $ }}-{{ .claimName }}
|
|
237
237
|
{{- end }}
|
|
238
238
|
{{- else }}
|
|
239
|
-
|
|
239
|
+
- {{ toYaml . | nindent 10 | trim }}
|
|
240
240
|
{{- end }}
|
|
241
241
|
{{- end }}
|
|
242
242
|
{{- end }}
|
|
243
243
|
{{- end }}
|
|
244
|
-
{{- end }}
|
|
244
|
+
{{- end }}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
{{-
|
|
1
|
+
{{- /* global.secret may be absent, null or "" */ -}}
|
|
2
|
+
{{- $pull := ((.Values.global | default dict).secret | default dict).pull }}
|
|
3
|
+
{{- if $pull }}
|
|
2
4
|
apiVersion: v1
|
|
3
5
|
kind: Secret
|
|
4
6
|
metadata:
|
|
5
7
|
name: {{ print $.Release.Name "-pull" }}
|
|
6
8
|
type: kubernetes.io/dockerconfigjson
|
|
7
9
|
data:
|
|
8
|
-
{{- with
|
|
10
|
+
{{- with $pull }}
|
|
9
11
|
.dockerconfigjson: {{ .auth | b64enc | printf "{\"auths\":{\"%s\":{\"auth\":\"%s\"}}}" .host | b64enc }}
|
|
10
12
|
{{- end }}
|
|
11
13
|
{{- end }}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
{{-
|
|
1
|
+
{{- /* global.secret may be absent, null or "" */ -}}
|
|
2
|
+
{{- $root := ((.Values.global | default dict).secret | default dict).root }}
|
|
3
|
+
{{- if $root }}
|
|
2
4
|
apiVersion: v1
|
|
3
5
|
kind: Secret
|
|
4
6
|
metadata:
|
|
5
7
|
name: {{ print $.Release.Name "-root" }}
|
|
6
8
|
type: Opaque
|
|
7
9
|
data:
|
|
8
|
-
{{- with
|
|
10
|
+
{{- with $root }}
|
|
9
11
|
{{- range $key, $value := . }}
|
|
10
12
|
{{- $key | nindent 2 }}{{- ": " -}}
|
|
11
13
|
{{- if eq (typeOf $value) "string" -}}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Values for non-default-branch releases (merge request review apps).
|
|
2
|
+
# Layered on top of the chart's values.yaml by `make run-install` / `make review`.
|
|
3
|
+
#
|
|
4
|
+
# The release name is <project>-<branch-slug>, so each review app already gets its
|
|
5
|
+
# own hosts: <project>-<branch-slug>-<service>.<SERVICE_BASE_DOMAIN>
|
|
6
|
+
# Keep SERVICE_BASE_DOMAIN the Cloudflare zone itself (one label deep): the free
|
|
7
|
+
# Universal SSL wildcard does not cover *.sub.example.com.
|
|
8
|
+
global:
|
|
9
|
+
root:
|
|
10
|
+
SERVICE_BASE_DOMAIN: "example.com"
|
|
@@ -29,7 +29,7 @@ global:
|
|
|
29
29
|
root:
|
|
30
30
|
SERVICE_DOMAIN: "WKS"
|
|
31
31
|
SERVICE_BASE_SCHEMA: "https"
|
|
32
|
-
SERVICE_BASE_DOMAIN: "
|
|
32
|
+
SERVICE_BASE_DOMAIN: "example.com"
|
|
33
33
|
SERVICE_BASE_DOMAIN_CERT: "ssl-example.com"
|
|
34
34
|
MYSQL_BASE_SCHEMA: "mysql"
|
|
35
35
|
MYSQL_BASE_DATABASE: "dev"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{{- include "root.ingressroutetcp" $ }}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{{- include "root.job" $ }}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
enabled: true
|
|
2
2
|
kind: <%= chartKind %>
|
|
3
|
-
|
|
3
|
+
<% if (chartKind === 'Job') { %>
|
|
4
|
+
# A Job's pod template is immutable, so a plain Job fails any `helm upgrade` that changes it
|
|
5
|
+
# (e.g. a new image tag). As a Helm hook it is recreated on every install/upgrade instead.
|
|
6
|
+
# post-install/post-upgrade runs after this release's own Secret, ConfigMap, ServiceAccount
|
|
7
|
+
# and pull secret exist. pre-install/pre-upgrade (e.g. DB migrations before the new app rolls
|
|
8
|
+
# out) runs BEFORE them on the first install, so then every reference must be external:
|
|
9
|
+
# secret/config entries via fromKeyRef, an existing imagePullSecrets name, and volumes from
|
|
10
|
+
# objects created outside the chart.
|
|
11
|
+
annotations:
|
|
12
|
+
helm.sh/hook: post-install,post-upgrade
|
|
13
|
+
helm.sh/hook-weight: "0"
|
|
14
|
+
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
|
15
|
+
restartPolicy: Never
|
|
16
|
+
<% } %>replicaCount: 1
|
|
4
17
|
image:
|
|
5
18
|
repository: <%= containerRegistry %>
|
|
6
19
|
tag: "<%= containerVersion %>"
|
|
@@ -8,28 +21,121 @@ image:
|
|
|
8
21
|
|
|
9
22
|
imagePullSecrets: "{{Release.Name}}-pull"
|
|
10
23
|
|
|
24
|
+
# Plain values, injected as env:
|
|
25
|
+
# env:
|
|
26
|
+
# NODE_ENV: "production"
|
|
27
|
+
# ConfigMap entries (also injected as env); a value may reference an external ConfigMap:
|
|
28
|
+
# config:
|
|
29
|
+
# LOG_LEVEL: "info"
|
|
30
|
+
# DB_NAME:
|
|
31
|
+
# fromKeyRef: "master-db-config"
|
|
32
|
+
# Secret entries (also injected as env). Never commit real values here: reference an
|
|
33
|
+
# existing Secret, or pass them from CI variables.
|
|
34
|
+
# secret:
|
|
35
|
+
# DATABASE_URL:
|
|
36
|
+
# fromKeyRef: "<%= chartName %>-db"
|
|
37
|
+
|
|
38
|
+
# Overrides the image command, wrapped in /bin/sh -c:
|
|
39
|
+
# beforeScript:
|
|
40
|
+
# - "echo starting"
|
|
41
|
+
# script:
|
|
42
|
+
# - "node dist/main.js"
|
|
43
|
+
|
|
44
|
+
# initContainers:
|
|
45
|
+
# - name: volume-permissions
|
|
46
|
+
# image: busybox:1.36
|
|
47
|
+
# command: ["sh", "-c", "chown 1000:1000 /data"]
|
|
48
|
+
# volumeMounts:
|
|
49
|
+
# - name: data-storage
|
|
50
|
+
# mountPath: /data
|
|
51
|
+
|
|
52
|
+
# securityContext:
|
|
53
|
+
# runAsUser: 1000
|
|
54
|
+
# runAsGroup: 3000
|
|
55
|
+
# fsGroup: 2000
|
|
56
|
+
|
|
57
|
+
# Set requests on anything that runs as a review app, so previews cannot starve the cluster.
|
|
58
|
+
# resources:
|
|
59
|
+
# requests:
|
|
60
|
+
# cpu: 50m
|
|
61
|
+
# memory: 128Mi
|
|
62
|
+
# limits:
|
|
63
|
+
# memory: 512Mi
|
|
64
|
+
|
|
11
65
|
service:
|
|
12
66
|
type: ClusterIP
|
|
13
67
|
port: 80
|
|
14
68
|
targetPort: 80
|
|
69
|
+
# Extra ports (e.g. SMTP next to a web UI):
|
|
70
|
+
# ports:
|
|
71
|
+
# - port: 2500
|
|
72
|
+
# name: smtp
|
|
73
|
+
# Proxy to a host outside the cluster instead of pods:
|
|
74
|
+
# type: ExternalName
|
|
75
|
+
# externalName: 10.0.0.10
|
|
15
76
|
|
|
77
|
+
# TLS terminates at the Cloudflare edge and reaches Traefik over the tunnel as plain
|
|
78
|
+
# HTTP, so no tls block by default. The host is flat (one label under the base domain)
|
|
79
|
+
# to stay inside Cloudflare's one-level Universal SSL wildcard; SERVICE_BASE_NAME is the
|
|
80
|
+
# release name, which differs per branch (at most 30 chars, so keep chart names to 32
|
|
81
|
+
# chars or less to stay under the 63-char DNS label limit).
|
|
82
|
+
# For direct exposure with cert-manager, use the websecure entrypoint and add:
|
|
83
|
+
# tls:
|
|
84
|
+
# - secretName: SERVICE_BASE_DOMAIN_CERT
|
|
85
|
+
# hosts:
|
|
86
|
+
# - "{{SERVICE_BASE_NAME}}-<%= chartName %>.{{SERVICE_BASE_DOMAIN}}"
|
|
16
87
|
ingress:
|
|
17
|
-
className: "
|
|
88
|
+
className: "traefik"
|
|
18
89
|
annotations:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
90
|
+
traefik.ingress.kubernetes.io/router.entrypoints: web
|
|
91
|
+
# Attach Traefik middlewares (<namespace>-<name>@kubernetescrd), e.g. a noindex header:
|
|
92
|
+
# traefik.ingress.kubernetes.io/router.middlewares: "default-noindex-headers@kubernetescrd"
|
|
93
|
+
# Backend speaks HTTPS:
|
|
94
|
+
# traefik.ingress.kubernetes.io/service.serversscheme: https
|
|
23
95
|
|
|
24
96
|
hosts:
|
|
25
|
-
- host:
|
|
97
|
+
- host: "{{SERVICE_BASE_NAME}}-<%= chartName %>.{{SERVICE_BASE_DOMAIN}}"
|
|
26
98
|
paths:
|
|
27
|
-
- path: "
|
|
28
|
-
pathType: "
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
99
|
+
- path: "/"
|
|
100
|
+
pathType: "Prefix"
|
|
101
|
+
|
|
102
|
+
# Traefik IngressRoute instead of Ingress (multiple routes, priorities, cross-namespace
|
|
103
|
+
# services such as an auth outpost). Disable `ingress` when using it.
|
|
104
|
+
# ingressRoute:
|
|
105
|
+
# entryPoints:
|
|
106
|
+
# - web
|
|
107
|
+
# routes:
|
|
108
|
+
# - match: Host(`{{SERVICE_BASE_NAME}}-<%= chartName %>.{{SERVICE_BASE_DOMAIN}}`)
|
|
109
|
+
# kind: Rule
|
|
110
|
+
# priority: 10
|
|
111
|
+
# services:
|
|
112
|
+
# - port: 80
|
|
113
|
+
# # scheme: https
|
|
114
|
+
# # serversTransport: "{{Release.Name}}-<%= chartName %>-transport"
|
|
115
|
+
# # middlewares:
|
|
116
|
+
# # - name: noindex-headers
|
|
117
|
+
# # namespace: default
|
|
118
|
+
|
|
119
|
+
# Backend transport for ingressRoute services (e.g. self-signed HTTPS upstream).
|
|
120
|
+
# Default name: <release>-<chart>-transport.
|
|
121
|
+
# serversTransport:
|
|
122
|
+
# insecureSkipVerify: true
|
|
123
|
+
|
|
124
|
+
# A Traefik Middleware owned by this chart. Default name: <release>-<chart>.
|
|
125
|
+
# middleware:
|
|
126
|
+
# headers:
|
|
127
|
+
# customResponseHeaders:
|
|
128
|
+
# X-Robots-Tag: "noindex, nofollow"
|
|
129
|
+
|
|
130
|
+
# Raw TCP routing through Traefik (databases, brokers), matched by SNI. SNI only exists
|
|
131
|
+
# inside TLS, so a named host needs `tls` (passthrough, or Traefik terminating); without
|
|
132
|
+
# TLS only the catch-all HostSNI(`*`) matches.
|
|
133
|
+
# ingressRouteTCP:
|
|
134
|
+
# entryPoints:
|
|
135
|
+
# - websecure
|
|
136
|
+
# host: "{{SERVICE_BASE_NAME}}-<%= chartName %>-tcp.{{SERVICE_BASE_DOMAIN}}"
|
|
137
|
+
# tls:
|
|
138
|
+
# passthrough: true
|
|
33
139
|
|
|
34
140
|
readinessProbe:
|
|
35
141
|
httpGet:
|
|
@@ -37,3 +143,11 @@ readinessProbe:
|
|
|
37
143
|
port: 80
|
|
38
144
|
initialDelaySeconds: 10
|
|
39
145
|
periodSeconds: 5
|
|
146
|
+
|
|
147
|
+
# volumeMounts:
|
|
148
|
+
# - name: data-storage
|
|
149
|
+
# mountPath: /data
|
|
150
|
+
# volumes:
|
|
151
|
+
# - name: data-storage
|
|
152
|
+
# persistentVolumeClaim:
|
|
153
|
+
# claimName: "{{Release.Name}}-<%= chartName %>"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"plugins": ["typescript", "oxc"],
|
|
4
|
+
"categories": {
|
|
5
|
+
"correctness": "error"
|
|
6
|
+
},
|
|
7
|
+
"env": {
|
|
8
|
+
"node": true,
|
|
9
|
+
"es2022": true,
|
|
10
|
+
"vitest": true
|
|
11
|
+
},
|
|
12
|
+
"ignorePatterns": ["dist/", "node_modules/", "coverage/", ".turbo/"],
|
|
13
|
+
"rules": {
|
|
14
|
+
"typescript/no-explicit-any": "off",
|
|
15
|
+
"typescript/explicit-module-boundary-types": "off",
|
|
16
|
+
"no-unused-vars": "off"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,39 +1,33 @@
|
|
|
1
|
-
##
|
|
1
|
+
## multi-stage build optimized for kaniko cache
|
|
2
|
+
## keep the bun image version in step with `packageManager`: bun.lock is versioned per bun release
|
|
2
3
|
FROM nathapp/apline-jq:3.18 AS deps
|
|
3
4
|
|
|
4
5
|
# https://stackoverflow.com/a/58487433
|
|
5
|
-
#
|
|
6
|
+
# Strip the version so a release bump does not invalidate the dependency layers
|
|
7
|
+
COPY package.json /tmp/
|
|
8
|
+
RUN jq '{ name, dependencies, devDependencies, scripts, packageManager }' < /tmp/package.json > /tmp/deps.json
|
|
6
9
|
|
|
7
|
-
COPY package.json package-lock.json /tmp/
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
RUN jq '{ name, lockfileVersion, requires, packages, dependencies }' < /tmp/package-lock.json > /tmp/deps-lock.json
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
FROM nathapp/node-bun:22.21.0-1.2.23-alpine AS builder
|
|
11
|
+
FROM nathapp/node-bun:24.22.0-1.4.3-alpine-builder AS builder
|
|
14
12
|
WORKDIR /app/
|
|
15
13
|
|
|
16
14
|
COPY --from=deps /tmp/deps.json ./package.json
|
|
17
|
-
COPY
|
|
18
|
-
|
|
19
|
-
ADD ./bun.lockb ./tsconfig.json ./tsconfig.build.json ./nest-cli.json /app/
|
|
15
|
+
COPY bun.lock ./
|
|
20
16
|
|
|
21
17
|
## install dependencies first
|
|
22
|
-
RUN bun install --
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
RUN bun install --frozen-lockfile
|
|
19
|
+
COPY tsconfig.json tsconfig.build.json nest-cli.json ./
|
|
20
|
+
COPY src ./src
|
|
25
21
|
RUN bun run build
|
|
26
22
|
|
|
27
23
|
|
|
28
|
-
FROM nathapp/node-bun:22.
|
|
24
|
+
FROM nathapp/node-bun:24.22.0-1.4.3-alpine
|
|
29
25
|
WORKDIR /app/
|
|
30
26
|
|
|
31
|
-
COPY bun.lockb ./
|
|
32
27
|
COPY --from=deps /tmp/deps.json ./package.json
|
|
33
|
-
COPY
|
|
34
|
-
|
|
35
|
-
RUN bun install --freeze-lockfile --production
|
|
28
|
+
COPY bun.lock ./
|
|
29
|
+
RUN bun install --frozen-lockfile --production --ignore-scripts
|
|
36
30
|
|
|
37
31
|
COPY --from=builder /app/dist /app/dist
|
|
38
|
-
COPY package
|
|
39
|
-
CMD ["bun", "run", "start:prod"]
|
|
32
|
+
COPY package.json ./
|
|
33
|
+
CMD ["bun", "run", "start:prod"]
|