@hed-hog/cli 0.0.49 → 0.0.51
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/dist/package.json +1 -1
- package/dist/src/modules/developer/developer.service.d.ts +15 -3
- package/dist/src/modules/developer/developer.service.js +479 -564
- package/dist/src/modules/developer/developer.service.js.map +1 -1
- package/dist/src/templates/deployment/DEPLOYMENT.md.ejs +217 -0
- package/dist/src/templates/deployment/helm.service.chart.yaml.ejs +6 -0
- package/dist/src/templates/deployment/helm.service.deployment.yaml.ejs +20 -0
- package/dist/src/templates/deployment/helm.service.service.yaml.ejs +14 -0
- package/dist/src/templates/deployment/helm.service.values.yaml.ejs +7 -0
- package/dist/src/templates/deployment/k8s.cert-manager-issuer.yaml.ejs +14 -0
- package/dist/src/templates/deployment/k8s.deployment.yaml.ejs +14 -0
- package/dist/src/templates/deployment/k8s.ingress.yaml.ejs +54 -0
- package/dist/src/templates/deployment/k8s.service.yaml.ejs +6 -0
- package/dist/src/templates/deployment/workflow.deploy.yml.ejs +133 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/src/templates/deployment/admin.Dockerfile.ejs +0 -14
- package/dist/src/templates/deployment/api.Dockerfile.ejs +0 -12
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Deployment Guide
|
|
2
|
+
|
|
3
|
+
This project is configured for deployment to **<%= config.provider === 'digitalocean' ? 'Digital Ocean Kubernetes' : config.provider %>** using **<%= config.cicd === 'github-actions' ? 'GitHub Actions' : config.cicd %>**.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Make sure you have the following tools installed:
|
|
8
|
+
|
|
9
|
+
- `kubectl` - Kubernetes CLI
|
|
10
|
+
- `doctl` - Digital Ocean CLI
|
|
11
|
+
- `gh` - GitHub CLI
|
|
12
|
+
- `helm` - Kubernetes package manager
|
|
13
|
+
|
|
14
|
+
## Initial Setup
|
|
15
|
+
|
|
16
|
+
### 1. Configure Digital Ocean
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Authenticate with Digital Ocean
|
|
20
|
+
doctl auth init
|
|
21
|
+
|
|
22
|
+
# Get your cluster kubeconfig
|
|
23
|
+
doctl kubernetes cluster kubeconfig save <%= config.clusterName %>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
<% if (config.createNamespace) { %>### 2. Create Kubernetes Namespace
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
kubectl create namespace <%= config.namespace %>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
<% } else { %>### 2. Verify Namespace
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Verify the namespace exists
|
|
36
|
+
kubectl get namespace <%= config.namespace %>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
<% } %>### 3. Configure GitHub Secrets
|
|
40
|
+
|
|
41
|
+
Add the following secrets to your GitHub repository:
|
|
42
|
+
|
|
43
|
+
1. `DIGITALOCEAN_ACCESS_TOKEN` - Your Digital Ocean API token
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Get your DO token and add it to GitHub
|
|
47
|
+
gh secret set DIGITALOCEAN_ACCESS_TOKEN
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
<% if (config.setupSSL) { %>### 4. Install cert-manager
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Install cert-manager for SSL certificates
|
|
54
|
+
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
|
|
55
|
+
|
|
56
|
+
# Wait for cert-manager to be ready
|
|
57
|
+
kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=cert-manager -n cert-manager --timeout=300s
|
|
58
|
+
|
|
59
|
+
# Apply the ClusterIssuer
|
|
60
|
+
kubectl apply -f k8s/cert-manager-issuer.yaml
|
|
61
|
+
```
|
|
62
|
+
<% } %>
|
|
63
|
+
<% if (config.setupIngress) { %>### <%= config.setupSSL ? '5' : '4' %>. Install NGINX Ingress Controller
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Install NGINX Ingress Controller
|
|
67
|
+
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
|
|
68
|
+
helm repo update
|
|
69
|
+
|
|
70
|
+
helm install nginx-ingress ingress-nginx/ingress-nginx \
|
|
71
|
+
--namespace ingress-nginx \
|
|
72
|
+
--create-namespace \
|
|
73
|
+
--set controller.publishService.enabled=true
|
|
74
|
+
|
|
75
|
+
# Wait for the load balancer IP
|
|
76
|
+
kubectl get service nginx-ingress-ingress-nginx-controller -n ingress-nginx --watch
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Important:** After the LoadBalancer gets an external IP, configure your DNS:
|
|
80
|
+
|
|
81
|
+
<% if (config.domain) { %>- Point `<%= config.domain %>` to the LoadBalancer IP
|
|
82
|
+
<% if (config.apps.includes('api')) { %>- Point `api.<%= config.domain %>` to the LoadBalancer IP
|
|
83
|
+
<% } %><% } %>
|
|
84
|
+
<% } %>
|
|
85
|
+
## Deployment
|
|
86
|
+
|
|
87
|
+
### Using GitHub Actions (Automatic)
|
|
88
|
+
|
|
89
|
+
Push to the `<%= config.deployBranch || 'production' %>` branch:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git add .
|
|
93
|
+
git commit -m "Deploy to production"
|
|
94
|
+
git push origin <%= config.deployBranch || 'production' %>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The GitHub Actions workflow will automatically:
|
|
98
|
+
1. Apply cluster configuration (namespace, Kubernetes manifests, and Helm charts)
|
|
99
|
+
2. Build and push application Docker images
|
|
100
|
+
3. Update deployments and wait for rollout
|
|
101
|
+
|
|
102
|
+
### Manual Deployment
|
|
103
|
+
|
|
104
|
+
#### Option 1: Apply cluster config manually (same as workflow)
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
kubectl create namespace <%= config.namespace %> --dry-run=client -o yaml | kubectl apply -f -
|
|
108
|
+
<% if (config.setupSSL) { %>kubectl apply -f k8s/cert-manager-issuer.yaml
|
|
109
|
+
<% } %><% config.apps.forEach((app) => { %>kubectl apply -f k8s/<%= app %>/ -n <%= config.namespace %>
|
|
110
|
+
<% }); %><% if (config.setupIngress) { %>kubectl apply -f k8s/ingress.yaml -n <%= config.namespace %>
|
|
111
|
+
<% } %>```
|
|
112
|
+
|
|
113
|
+
<% if ((config.infraServices || []).length > 0) { %>#### Additional infrastructure services (generated from <%= config.composeFileName || 'docker-compose' %>)
|
|
114
|
+
|
|
115
|
+
The CLI generated Helm charts for the selected services under `helm/services` using the same image names and versions from compose.
|
|
116
|
+
|
|
117
|
+
Run the following commands to create these services in your cluster:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
<% (config.infraServices || []).forEach((service) => { %>helm upgrade --install <%= config.appName %>-<%= service.name %> ./helm/services/<%= service.name %> --namespace <%= config.namespace %> --create-namespace
|
|
121
|
+
<% }); %>```
|
|
122
|
+
<% } %>
|
|
123
|
+
|
|
124
|
+
#### Option 2: Build and deploy application images
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
<% if (config.apps.includes('api')) { %>docker build -t <%= config.containerRegistry %>/<%= config.appName %>-api:latest -f apps/api/Dockerfile .
|
|
128
|
+
docker push <%= config.containerRegistry %>/<%= config.appName %>-api:latest
|
|
129
|
+
kubectl set image deployment/<%= config.appName %>-api <%= config.appName %>-api=<%= config.containerRegistry %>/<%= config.appName %>-api:latest -n <%= config.namespace %>
|
|
130
|
+
kubectl rollout status deployment/<%= config.appName %>-api -n <%= config.namespace %>
|
|
131
|
+
|
|
132
|
+
<% } %><% if (config.apps.includes('admin')) { %>docker build -t <%= config.containerRegistry %>/<%= config.appName %>-admin:latest \
|
|
133
|
+
--build-arg NEXT_PUBLIC_API_BASE_URL=<%= config.domain ? `https://api.${config.domain}` : '' %> \
|
|
134
|
+
--build-arg NEXT_PUBLIC_API_URL=<%= config.domain ? `https://api.${config.domain}` : '' %> \
|
|
135
|
+
-f apps/admin/Dockerfile .
|
|
136
|
+
docker push <%= config.containerRegistry %>/<%= config.appName %>-admin:latest
|
|
137
|
+
kubectl set image deployment/<%= config.appName %>-admin <%= config.appName %>-admin=<%= config.containerRegistry %>/<%= config.appName %>-admin:latest -n <%= config.namespace %>
|
|
138
|
+
kubectl rollout status deployment/<%= config.appName %>-admin -n <%= config.namespace %>
|
|
139
|
+
<% } %><% (config.apps || []).filter((app) => app !== 'api' && app !== 'admin').forEach((app) => { %>
|
|
140
|
+
docker build -t <%= config.containerRegistry %>/<%= config.appName %>-<%= app %>:latest -f apps/<%= app %>/Dockerfile .
|
|
141
|
+
docker push <%= config.containerRegistry %>/<%= config.appName %>-<%= app %>:latest
|
|
142
|
+
kubectl set image deployment/<%= config.appName %>-<%= app %> <%= config.appName %>-<%= app %>=<%= config.containerRegistry %>/<%= config.appName %>-<%= app %>:latest -n <%= config.namespace %>
|
|
143
|
+
kubectl rollout status deployment/<%= config.appName %>-<%= app %> -n <%= config.namespace %>
|
|
144
|
+
<% }); %>```
|
|
145
|
+
|
|
146
|
+
## Monitoring
|
|
147
|
+
|
|
148
|
+
### Check Deployment Status
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Check pods
|
|
152
|
+
kubectl get pods -n <%= config.namespace %>
|
|
153
|
+
|
|
154
|
+
# Check deployments
|
|
155
|
+
kubectl get deployments -n <%= config.namespace %>
|
|
156
|
+
|
|
157
|
+
# Check services
|
|
158
|
+
kubectl get services -n <%= config.namespace %>
|
|
159
|
+
|
|
160
|
+
<% if (config.setupIngress) { %># Check ingress
|
|
161
|
+
kubectl get ingress -n <%= config.namespace %>
|
|
162
|
+
<% } %># View logs
|
|
163
|
+
<% config.apps.forEach((app) => { %>kubectl logs -f deployment/<%= config.appName %>-<%= app %> -n <%= config.namespace %>
|
|
164
|
+
<% }); %>```
|
|
165
|
+
|
|
166
|
+
### Scaling
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Scale a deployment
|
|
170
|
+
<% config.apps.forEach((app) => { %>kubectl scale deployment/<%= config.appName %>-<%= app %> --replicas=3 -n <%= config.namespace %>
|
|
171
|
+
<% }); %>```
|
|
172
|
+
|
|
173
|
+
## Rollback
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# View rollout history
|
|
177
|
+
<% config.apps.forEach((app) => { %>kubectl rollout history deployment/<%= config.appName %>-<%= app %> -n <%= config.namespace %>
|
|
178
|
+
<% }); %>
|
|
179
|
+
# Rollback to previous version
|
|
180
|
+
<% config.apps.forEach((app) => { %>kubectl rollout undo deployment/<%= config.appName %>-<%= app %> -n <%= config.namespace %>
|
|
181
|
+
<% }); %>```
|
|
182
|
+
|
|
183
|
+
## Troubleshooting
|
|
184
|
+
|
|
185
|
+
### View Pod Events
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
kubectl describe pod <pod-name> -n <%= config.namespace %>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### View Cluster Events
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
kubectl get events -n <%= config.namespace %> --sort-by='.lastTimestamp'
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Access Pod Shell
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
<% config.apps.forEach((app) => { %>kubectl exec -it deployment/<%= config.appName %>-<%= app %> -n <%= config.namespace %> -- /bin/sh
|
|
201
|
+
<% }); %>```
|
|
202
|
+
|
|
203
|
+
## URLs
|
|
204
|
+
|
|
205
|
+
<% if (config.domain) { %>- **Admin Panel:** https://<%= config.domain %>
|
|
206
|
+
<% if (config.apps.includes('api')) { %>- **API:** https://api.<%= config.domain %>
|
|
207
|
+
<% } %><% } else { %>- Configure your domain and update DNS records as described above
|
|
208
|
+
<% } %>
|
|
209
|
+
|
|
210
|
+
## Further Reading
|
|
211
|
+
|
|
212
|
+
- [Digital Ocean Kubernetes Documentation](https://docs.digitalocean.com/products/kubernetes/)
|
|
213
|
+
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
|
214
|
+
- [Kubernetes Documentation](https://kubernetes.io/docs/home/)
|
|
215
|
+
- [Helm Documentation](https://helm.sh/docs/)
|
|
216
|
+
<% if (config.setupSSL) { %>- [cert-manager Documentation](https://cert-manager.io/docs/)
|
|
217
|
+
<% } %>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
apiVersion: apps/v1
|
|
2
|
+
kind: Deployment
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ .Values.serviceName }}
|
|
5
|
+
namespace: {{ .Values.namespace }}
|
|
6
|
+
spec:
|
|
7
|
+
replicas: {{ .Values.replicas }}
|
|
8
|
+
selector:
|
|
9
|
+
matchLabels:
|
|
10
|
+
app: {{ .Values.serviceName }}
|
|
11
|
+
template:
|
|
12
|
+
metadata:
|
|
13
|
+
labels:
|
|
14
|
+
app: {{ .Values.serviceName }}
|
|
15
|
+
spec:
|
|
16
|
+
containers:
|
|
17
|
+
- name: {{ .Values.serviceName }}
|
|
18
|
+
image: {{ .Values.image }}
|
|
19
|
+
ports:
|
|
20
|
+
- containerPort: {{ .Values.service.port }}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: v1
|
|
2
|
+
kind: Service
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ .Values.serviceName }}
|
|
5
|
+
namespace: {{ .Values.namespace }}
|
|
6
|
+
spec:
|
|
7
|
+
type: {{ .Values.service.type }}
|
|
8
|
+
selector:
|
|
9
|
+
app: {{ .Values.serviceName }}
|
|
10
|
+
ports:
|
|
11
|
+
- name: tcp
|
|
12
|
+
protocol: TCP
|
|
13
|
+
port: {{ .Values.service.port }}
|
|
14
|
+
targetPort: {{ .Values.service.port }}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: cert-manager.io/v1
|
|
2
|
+
kind: ClusterIssuer
|
|
3
|
+
metadata:
|
|
4
|
+
name: letsencrypt-prod
|
|
5
|
+
spec:
|
|
6
|
+
acme:
|
|
7
|
+
server: https://acme-v02.api.letsencrypt.org/directory
|
|
8
|
+
email: <%= config.email %>
|
|
9
|
+
privateKeySecretRef:
|
|
10
|
+
name: letsencrypt-prod
|
|
11
|
+
solvers:
|
|
12
|
+
- http01:
|
|
13
|
+
ingress:
|
|
14
|
+
class: nginx
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: apps/v1 kind: Deployment metadata: name: <%= config.appName %>-<%=
|
|
2
|
+
app %> namespace: <%= config.namespace %> labels: app: <%= config.appName %>-<%=
|
|
3
|
+
app %> spec: replicas: <%= config.appReplicas?.[app] ?? 2 %> selector:
|
|
4
|
+
matchLabels: app: <%= config.appName %>-<%= app %> template: metadata: labels:
|
|
5
|
+
app: <%= config.appName %>-<%= app %> spec: containers: - name: <%=
|
|
6
|
+
config.appName %>-<%= app %> image: <%= config.containerRegistry %>/<%=
|
|
7
|
+
config.appName %>-<%= app %>:latest ports: - containerPort: <%=
|
|
8
|
+
config.appPorts?.[app] ?? (app === 'api' ? 3000 : 80) %> env: - name: NODE_ENV
|
|
9
|
+
value: "production" resources: requests: memory: "256Mi" cpu: "100m" limits:
|
|
10
|
+
memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: <%= app === 'api' ?
|
|
11
|
+
'/health' : '/' %> port: <%= config.appPorts?.[app] ?? (app === 'api' ? 3000 :
|
|
12
|
+
80) %> initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path:
|
|
13
|
+
<%= app === 'api' ? '/health' : '/' %> port: <%= config.appPorts?.[app] ?? (app
|
|
14
|
+
=== 'api' ? 3000 : 80) %> initialDelaySeconds: 10 periodSeconds: 5
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<%
|
|
2
|
+
var selectedApps = config.apps || [];
|
|
3
|
+
var extraApps = selectedApps.filter(function (app) {
|
|
4
|
+
return app !== 'api' && app !== 'admin';
|
|
5
|
+
});
|
|
6
|
+
var appPorts = config.appPorts || {};
|
|
7
|
+
%>
|
|
8
|
+
apiVersion: networking.k8s.io/v1
|
|
9
|
+
kind: Ingress
|
|
10
|
+
metadata:
|
|
11
|
+
name: <%= config.appName %>-ingress
|
|
12
|
+
namespace: <%= config.namespace %>
|
|
13
|
+
annotations:
|
|
14
|
+
kubernetes.io/ingress.class: "nginx"
|
|
15
|
+
<% if (config.setupSSL) { %> cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
16
|
+
<% } %>spec:
|
|
17
|
+
<% if (config.setupSSL) { %> tls:
|
|
18
|
+
- hosts:
|
|
19
|
+
- <%= config.domain %>
|
|
20
|
+
<% if (selectedApps.includes('api')) { %> - api.<%= config.domain %>
|
|
21
|
+
<% } %><% extraApps.forEach(function (app) { %> - <%= app %>.<%= config.domain %>
|
|
22
|
+
<% }); %> secretName: <%= config.appName %>-tls
|
|
23
|
+
<% } %> rules:
|
|
24
|
+
<% if (selectedApps.includes('admin')) { %> - host: <%= config.domain %>
|
|
25
|
+
http:
|
|
26
|
+
paths:
|
|
27
|
+
- path: /
|
|
28
|
+
pathType: Prefix
|
|
29
|
+
backend:
|
|
30
|
+
service:
|
|
31
|
+
name: <%= config.appName %>-admin
|
|
32
|
+
port:
|
|
33
|
+
number: <%= appPorts.admin || 80 %>
|
|
34
|
+
<% } %><% if (selectedApps.includes('api')) { %> - host: api.<%= config.domain %>
|
|
35
|
+
http:
|
|
36
|
+
paths:
|
|
37
|
+
- path: /
|
|
38
|
+
pathType: Prefix
|
|
39
|
+
backend:
|
|
40
|
+
service:
|
|
41
|
+
name: <%= config.appName %>-api
|
|
42
|
+
port:
|
|
43
|
+
number: <%= appPorts.api || 3000 %>
|
|
44
|
+
<% } %><% extraApps.forEach(function (app) { %> - host: <%= app %>.<%= config.domain %>
|
|
45
|
+
http:
|
|
46
|
+
paths:
|
|
47
|
+
- path: /
|
|
48
|
+
pathType: Prefix
|
|
49
|
+
backend:
|
|
50
|
+
service:
|
|
51
|
+
name: <%= config.appName %>-<%= app %>
|
|
52
|
+
port:
|
|
53
|
+
number: <%= appPorts[app] || 80 %>
|
|
54
|
+
<% }); %>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
apiVersion: v1 kind: Service metadata: name: <%= config.appName %>-<%= app %>
|
|
2
|
+
namespace: <%= config.namespace %> labels: app: <%= config.appName %>-<%= app %>
|
|
3
|
+
spec: type: ClusterIP ports: - port: <%= config.appPorts?.[app] ?? (app ===
|
|
4
|
+
'api' ? 3000 : 80) %> targetPort: <%= config.appPorts?.[app] ?? (app === 'api' ?
|
|
5
|
+
3000 : 80) %> protocol: TCP name: http selector: app: <%= config.appName %>-<%=
|
|
6
|
+
app %>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
name: Deploy to Kubernetes
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- <%= config.deployBranch || 'production' %>
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
env:
|
|
8
|
+
REGISTRY: <%= config.containerRegistry %>
|
|
9
|
+
CLUSTER_NAME: <%= config.clusterName %>
|
|
10
|
+
NAMESPACE: <%= config.namespace %>
|
|
11
|
+
API_PUBLIC_URL: <%= config.domain ? `https://api.${config.domain}` : '' %>
|
|
12
|
+
jobs:
|
|
13
|
+
apply-cluster-config:
|
|
14
|
+
name: Apply Kubernetes and Helm configs
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout code
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
- name: Install doctl
|
|
20
|
+
uses: digitalocean/action-doctl@v2
|
|
21
|
+
with:
|
|
22
|
+
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
23
|
+
- name: Set up Helm
|
|
24
|
+
uses: azure/setup-helm@v4
|
|
25
|
+
- name: Save DigitalOcean kubeconfig
|
|
26
|
+
run: doctl kubernetes cluster kubeconfig save ${{ env.CLUSTER_NAME }}
|
|
27
|
+
- name: Ensure namespace exists
|
|
28
|
+
run: |
|
|
29
|
+
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
|
|
30
|
+
- name: Apply Kubernetes manifests
|
|
31
|
+
run: |
|
|
32
|
+
<% if (config.setupSSL) { %> kubectl apply -f k8s/cert-manager-issuer.yaml
|
|
33
|
+
<% } %><% (config.apps || []).forEach((app) => { %> kubectl apply -f k8s/<%= app %> -n ${{ env.NAMESPACE }}
|
|
34
|
+
<% }); %><% if (config.setupIngress) { %> kubectl apply -f k8s/ingress.yaml -n ${{ env.NAMESPACE }}
|
|
35
|
+
<% } %><% if ((config.infraServices || []).length > 0) { %> - name: Apply Helm chart(s)
|
|
36
|
+
run: |
|
|
37
|
+
<% config.infraServices.forEach((service) => { %> helm upgrade --install <%= config.appName %>-<%= service.name %> ./helm/services/<%= service.name %> \
|
|
38
|
+
--namespace ${{ env.NAMESPACE }} \
|
|
39
|
+
--create-namespace
|
|
40
|
+
<% }); %><% } %>
|
|
41
|
+
|
|
42
|
+
<% if (config.apps.includes('api')) { %> deploy-api:
|
|
43
|
+
name: Deploy API
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
needs: apply-cluster-config
|
|
46
|
+
steps:
|
|
47
|
+
- name: Checkout code
|
|
48
|
+
uses: actions/checkout@v4
|
|
49
|
+
- name: Install doctl
|
|
50
|
+
uses: digitalocean/action-doctl@v2
|
|
51
|
+
with:
|
|
52
|
+
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
53
|
+
- name: Log in to Container Registry
|
|
54
|
+
run: doctl registry login
|
|
55
|
+
- name: Build and push Docker image
|
|
56
|
+
run: |
|
|
57
|
+
docker build -t ${{ env.REGISTRY }}/<%= config.appName %>-api:${{ github.sha }} \
|
|
58
|
+
-f apps/api/Dockerfile .
|
|
59
|
+
docker push ${{ env.REGISTRY }}/<%= config.appName %>-api:${{ github.sha }}
|
|
60
|
+
docker tag ${{ env.REGISTRY }}/<%= config.appName %>-api:${{ github.sha }} \
|
|
61
|
+
${{ env.REGISTRY }}/<%= config.appName %>-api:latest
|
|
62
|
+
docker push ${{ env.REGISTRY }}/<%= config.appName %>-api:latest
|
|
63
|
+
- name: Save DigitalOcean kubeconfig
|
|
64
|
+
run: doctl kubernetes cluster kubeconfig save ${{ env.CLUSTER_NAME }}
|
|
65
|
+
- name: Deploy to Kubernetes
|
|
66
|
+
run: |
|
|
67
|
+
kubectl set image deployment/<%= config.appName %>-api \
|
|
68
|
+
<%= config.appName %>-api=${{ env.REGISTRY }}/<%= config.appName %>-api:${{ github.sha }} \
|
|
69
|
+
-n ${{ env.NAMESPACE }}
|
|
70
|
+
kubectl rollout status deployment/<%= config.appName %>-api -n ${{ env.NAMESPACE }}
|
|
71
|
+
|
|
72
|
+
<% } %><% if (config.apps.includes('admin')) { %> deploy-admin:
|
|
73
|
+
name: Deploy ADMIN
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
needs: apply-cluster-config
|
|
76
|
+
steps:
|
|
77
|
+
- name: Checkout code
|
|
78
|
+
uses: actions/checkout@v4
|
|
79
|
+
- name: Install doctl
|
|
80
|
+
uses: digitalocean/action-doctl@v2
|
|
81
|
+
with:
|
|
82
|
+
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
83
|
+
- name: Log in to Container Registry
|
|
84
|
+
run: doctl registry login
|
|
85
|
+
- name: Build and push Docker image
|
|
86
|
+
run: |
|
|
87
|
+
docker build -t ${{ env.REGISTRY }}/<%= config.appName %>-admin:${{ github.sha }} \
|
|
88
|
+
--build-arg NEXT_PUBLIC_API_BASE_URL=${{ env.API_PUBLIC_URL }} \
|
|
89
|
+
--build-arg NEXT_PUBLIC_API_URL=${{ env.API_PUBLIC_URL }} \
|
|
90
|
+
-f apps/admin/Dockerfile .
|
|
91
|
+
docker push ${{ env.REGISTRY }}/<%= config.appName %>-admin:${{ github.sha }}
|
|
92
|
+
docker tag ${{ env.REGISTRY }}/<%= config.appName %>-admin:${{ github.sha }} \
|
|
93
|
+
${{ env.REGISTRY }}/<%= config.appName %>-admin:latest
|
|
94
|
+
docker push ${{ env.REGISTRY }}/<%= config.appName %>-admin:latest
|
|
95
|
+
- name: Save DigitalOcean kubeconfig
|
|
96
|
+
run: doctl kubernetes cluster kubeconfig save ${{ env.CLUSTER_NAME }}
|
|
97
|
+
- name: Deploy to Kubernetes
|
|
98
|
+
run: |
|
|
99
|
+
kubectl set image deployment/<%= config.appName %>-admin \
|
|
100
|
+
<%= config.appName %>-admin=${{ env.REGISTRY }}/<%= config.appName %>-admin:${{ github.sha }} \
|
|
101
|
+
-n ${{ env.NAMESPACE }}
|
|
102
|
+
kubectl rollout status deployment/<%= config.appName %>-admin -n ${{ env.NAMESPACE }}
|
|
103
|
+
<% } %><% (config.apps || []).filter((app) => app !== 'api' && app !== 'admin').forEach((app) => { %>
|
|
104
|
+
deploy-<%= app %>:
|
|
105
|
+
name: Deploy <%= app.toUpperCase() %>
|
|
106
|
+
runs-on: ubuntu-latest
|
|
107
|
+
needs: apply-cluster-config
|
|
108
|
+
steps:
|
|
109
|
+
- name: Checkout code
|
|
110
|
+
uses: actions/checkout@v4
|
|
111
|
+
- name: Install doctl
|
|
112
|
+
uses: digitalocean/action-doctl@v2
|
|
113
|
+
with:
|
|
114
|
+
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
115
|
+
- name: Log in to Container Registry
|
|
116
|
+
run: doctl registry login
|
|
117
|
+
- name: Build and push Docker image
|
|
118
|
+
run: |
|
|
119
|
+
docker build -t ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }} \
|
|
120
|
+
-f apps/<%= app %>/Dockerfile .
|
|
121
|
+
docker push ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }}
|
|
122
|
+
docker tag ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }} \
|
|
123
|
+
${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:latest
|
|
124
|
+
docker push ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:latest
|
|
125
|
+
- name: Save DigitalOcean kubeconfig
|
|
126
|
+
run: doctl kubernetes cluster kubeconfig save ${{ env.CLUSTER_NAME }}
|
|
127
|
+
- name: Deploy to Kubernetes
|
|
128
|
+
run: |
|
|
129
|
+
kubectl set image deployment/<%= config.appName %>-<%= app %> \
|
|
130
|
+
<%= config.appName %>-<%= app %>=${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }} \
|
|
131
|
+
-n ${{ env.NAMESPACE }}
|
|
132
|
+
kubectl rollout status deployment/<%= config.appName %>-<%= app %> -n ${{ env.NAMESPACE }}
|
|
133
|
+
<% }); %>
|