init
This commit is contained in:
308
BOOTSTRAP.md
Normal file
308
BOOTSTRAP.md
Normal file
@@ -0,0 +1,308 @@
|
||||
# Yandex Cloud Production Cluster — Bootstrap Guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [ ] `kubeconfig` file placed at `~/infra/yandex-prod/kubeconfig`
|
||||
- [ ] `kubectl` context pointing to the new `yc-prod` cluster
|
||||
- [ ] Domain `prod.t01tt.tech` DNS managed (can be updated later in Phase 5)
|
||||
- [ ] `git` and `helm` installed locally
|
||||
|
||||
---
|
||||
|
||||
## Phase 0: Verify Cluster Access
|
||||
|
||||
```bash
|
||||
export KUBECONFIG=~/infra/yandex-prod/kubeconfig
|
||||
|
||||
kubectl get nodes
|
||||
# Expected: 3 nodes Ready, 2CPU/8GB each
|
||||
|
||||
kubectl get sc
|
||||
# Expected: yc-network-hdd (default), yc-network-ssd, yc-network-nvme, ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Bootstrap Gitea (internal access only)
|
||||
|
||||
Gitea hosts the Git repo that ArgoCD reads. Deploy it first, but without ingress — we access it via port-forward.
|
||||
|
||||
```bash
|
||||
kubectl apply -f bootstrap/gitea/namespace.yaml
|
||||
kubectl apply -f bootstrap/gitea/pvc.yaml
|
||||
kubectl apply -f bootstrap/gitea/deployment.yaml
|
||||
kubectl apply -f bootstrap/gitea/service.yaml
|
||||
# NOTE: Do NOT apply ingress.yaml yet — no Traefik or cert-manager exists
|
||||
```
|
||||
|
||||
Wait for Gitea to be ready, then port-forward and configure:
|
||||
|
||||
```bash
|
||||
kubectl wait deploy/gitea -n gitea --for=condition=available --timeout=120s
|
||||
|
||||
# Port-forward in a separate terminal:
|
||||
kubectl port-forward svc/gitea 3000:3000 -n gitea
|
||||
```
|
||||
|
||||
1. Open **http://localhost:3000** in a browser
|
||||
2. Fill out the install form:
|
||||
- Database: **SQLite3** (default)
|
||||
- Site Title: **Gitea**
|
||||
- Domain: **git.prod.t01tt.tech**
|
||||
- Application URL: **https://git.prod.t01tt.tech**
|
||||
- Create admin account (username/password/email — save these)
|
||||
3. Click "Install Gitea"
|
||||
4. Create a new repository: **`yandex-prod`** (must be **public**, owned by admin)
|
||||
5. Close the port-forward (Ctrl+C)
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Push Repository to Gitea
|
||||
|
||||
```bash
|
||||
cd ~/infra/yandex-prod
|
||||
|
||||
git init
|
||||
git remote add origin http://localhost:3000/<admin-user>/yandex-prod.git
|
||||
# Or, once Gitea ingress works later, use:
|
||||
# git remote add origin https://git.prod.t01tt.tech/<admin-user>/yandex-prod.git
|
||||
|
||||
git add -A
|
||||
git commit -m "initial bootstrap: infrastructure manifests"
|
||||
git push -u origin main
|
||||
# Enter Gitea admin credentials when prompted
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Install ArgoCD (internal access only)
|
||||
|
||||
```bash
|
||||
bash bootstrap/argocd/install.sh
|
||||
# Saves the admin password — copy it
|
||||
```
|
||||
|
||||
Add the Gitea repository to ArgoCD:
|
||||
|
||||
```bash
|
||||
# Via port-forward:
|
||||
kubectl port-forward svc/argocd-server 8080:80 -n argocd &
|
||||
sleep 2
|
||||
|
||||
# Login and add repo:
|
||||
ARGOCD_PASS=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
|
||||
argocd login localhost:8080 --username admin --password "${ARGOCD_PASS}" --insecure
|
||||
|
||||
argocd repo add http://gitea.gitea.svc.cluster.local:3000/<admin-user>/yandex-prod.git \
|
||||
--name yandex-prod \
|
||||
--type git
|
||||
```
|
||||
|
||||
Deploy the root app:
|
||||
|
||||
```bash
|
||||
kubectl apply -f argocd/app-of-apps.yaml
|
||||
```
|
||||
|
||||
ArgoCD will now sync child apps according to their sync waves. You can watch progress:
|
||||
|
||||
```bash
|
||||
argocd app list
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Let the Sync Waves Run
|
||||
|
||||
Sync order (automated by ArgoCD via `argocd.argoproj.io/sync-wave` annotations):
|
||||
|
||||
| Wave | App | What happens |
|
||||
|------|-----|-------------|
|
||||
| **-2** | `traefik` | DaemonSet deployed on all 3 nodes. NLB created → external IP provisioned |
|
||||
| **-1** | `cert-manager` | cert-manager operator + CRDs installed |
|
||||
| **0** | `cert-manager-issuers` | `letsencrypt-production` + `letsencrypt-staging` ClusterIssuers created |
|
||||
| **0** | `monitoring` | VM k8s-stack (metrics) + Grafana ingress deployed |
|
||||
| **0** | `loki` | Loki single-binary deployed |
|
||||
| **0** | `cnpg-operator` | CloudNativePG operator installed |
|
||||
| **1** | `cnpg-cluster` | `shared-pg` 3-node PostgreSQL cluster + 8 databases created |
|
||||
|
||||
**Verify Traefik IP:**
|
||||
|
||||
```bash
|
||||
kubectl get svc traefik -n traefik -w
|
||||
# Wait for EXTERNAL-IP to appear. Example output:
|
||||
# traefik LoadBalancer 10.x.x.x <pending> 80:3xxxx/TCP,443:3xxxx/TCP 30s
|
||||
# traefik LoadBalancer 10.x.x.x 158.160.x.x 80:3xxxx/TCP,443:3xxxx/TCP 60s
|
||||
```
|
||||
|
||||
Take the EXTERNAL-IP — this is your NLB IP. You'll need it in Phase 5.
|
||||
|
||||
**Verify state:**
|
||||
|
||||
```bash
|
||||
kubectl get pods -A
|
||||
# Expected running pods:
|
||||
# traefik: traefik-xxxxx (3 pods, DaemonSet)
|
||||
# cert-manager: cert-manager-xxxxx, cert-manager-cainjector-xxxxx, cert-manager-webhook-xxxxx
|
||||
# metrics: vm-k8s-stack-* pods (vmsingle, alertmanager, grafana, node-exporter, kube-state-metrics, vmagent)
|
||||
# metrics: loki-0
|
||||
# cnpg-system: cnpg-operator-xxxxx
|
||||
# cnpg: shared-pg-1, shared-pg-2, shared-pg-3 (may take a minute to start)
|
||||
|
||||
kubectl get clusterissuer
|
||||
# Expected: letsencrypt-production (True), letsencrypt-staging (True)
|
||||
|
||||
kubectl get cluster -n cnpg
|
||||
# Expected: shared-pg (3/3 instances ready)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: DNS + Expose Gitea & ArgoCD
|
||||
|
||||
Now that Traefik has an external IP and cert-manager is running, we can:
|
||||
1. Point DNS at the NLB IP
|
||||
2. Create the Gitea and ArgoCD ingress resources (with TLS)
|
||||
|
||||
### 5.1 Update DNS
|
||||
|
||||
Point the following records to the Traefik NLB IP (from Phase 4):
|
||||
|
||||
```
|
||||
git.prod.t01tt.tech → <NLB-IP>
|
||||
argocd.prod.t01tt.tech → <NLB-IP>
|
||||
grafana.prod.t01tt.tech → <NLB-IP>
|
||||
```
|
||||
|
||||
Also create a wildcard for future hosts:
|
||||
```
|
||||
*.prod.t01tt.tech → <NLB-IP>
|
||||
```
|
||||
|
||||
### 5.2 Apply Ingresses
|
||||
|
||||
```bash
|
||||
kubectl apply -f bootstrap/gitea/ingress.yaml
|
||||
kubectl apply -f bootstrap/argocd/ingress.yaml
|
||||
```
|
||||
|
||||
### 5.3 Wait for TLS Certificates
|
||||
|
||||
```bash
|
||||
kubectl get certificate -A -w
|
||||
# Wait for all to show Ready=True:
|
||||
# gitea gitea-tls True
|
||||
# argocd argocd-tls True
|
||||
# metrics grafana-tls True
|
||||
```
|
||||
|
||||
**Troubleshooting:** If certificates are stuck in `Pending`:
|
||||
- Check DNS resolves: `dig git.prod.t01tt.tech` — must return the NLB IP
|
||||
- Check cert-manager logs: `kubectl logs -n cert-manager deploy/cert-manager`
|
||||
- Check challenge: `kubectl get challenges -A`
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Verify Everything
|
||||
|
||||
### Gitea
|
||||
```
|
||||
https://git.prod.t01tt.tech
|
||||
```
|
||||
Login with the admin credentials from Phase 1. Verify the `yandex-prod` repo exists.
|
||||
|
||||
### ArgoCD
|
||||
```
|
||||
https://argocd.prod.t01tt.tech
|
||||
```
|
||||
Login with `admin` + password from Phase 3. All apps should show green (`Synced` + `Healthy`).
|
||||
|
||||
The Ingress health may show `Healthy` immediately (by design — see `values.yaml` customization).
|
||||
|
||||
### Grafana
|
||||
```
|
||||
https://grafana.prod.t01tt.tech
|
||||
```
|
||||
Login with `admin` / `change-me`. Check that VM k8s-stack dashboards are available.
|
||||
|
||||
### PostgreSQL
|
||||
```bash
|
||||
kubectl get databases -n cnpg
|
||||
# Expected: 8 Database resources, one per homeserver
|
||||
|
||||
kubectl get pods -n cnpg
|
||||
# Expected: shared-pg-1, shared-pg-2, shared-pg-3 (Running)
|
||||
```
|
||||
|
||||
### ArgoCD Repo Connection
|
||||
```bash
|
||||
argocd repo list
|
||||
# Expected: the Gitea repo with status "Successful"
|
||||
```
|
||||
|
||||
If not connected, re-add via ArgoCD CLI:
|
||||
```bash
|
||||
argocd repo add http://gitea.gitea.svc.cluster.local:3000/<admin-user>/yandex-prod.git \
|
||||
--name yandex-prod \
|
||||
--type git
|
||||
```
|
||||
|
||||
Or in the ArgoCD UI: Settings → Repositories → Connect repo.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Post-Bootstrap Checklist
|
||||
|
||||
- [ ] All ArgoCD apps `Synced` and `Healthy`
|
||||
- [ ] `https://git.prod.t01tt.tech` — Gitea accessible, SSL valid
|
||||
- [ ] `https://argocd.prod.t01tt.tech` — ArgoCD accessible, SSL valid
|
||||
- [ ] `https://grafana.prod.t01tt.tech` — Grafana accessible, SSL valid, datasources working
|
||||
- [ ] `kubectl get pv` — PVCs bound for all stateful components
|
||||
- [ ] CNPG `shared-pg` cluster status: `kubectl get cluster -n cnpg` shows 3/3 ready
|
||||
- [ ] Certificates all `Ready`: `kubectl get certificate -A | grep False` (should return nothing)
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference: Service URLs
|
||||
|
||||
| Service | URL | Auth |
|
||||
|---------|-----|------|
|
||||
| Gitea | `https://git.prod.t01tt.tech` | Admin user from Phase 1 |
|
||||
| ArgoCD | `https://argocd.prod.t01tt.tech` | `admin` / password from Phase 3 |
|
||||
| Grafana | `https://grafana.prod.t01tt.tech` | `admin` / `change-me` |
|
||||
| Traefik dashboard | `kubectl port-forward -n traefik daemonset/traefik 9000:9000` | Internal only |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Traefik NLB stuck in `<pending>`
|
||||
Yandex Cloud NLB provisioning can take a few minutes. Check:
|
||||
```bash
|
||||
kubectl describe svc traefik -n traefik
|
||||
```
|
||||
If it's stuck for >5 minutes, verify the Yandex annotations are correct.
|
||||
|
||||
### Certificates stuck in `Pending`
|
||||
1. Verify DNS: `dig git.prod.t01tt.tech` → must return the NLB IP
|
||||
2. Check Traefik is listening: `curl -k https://<NLB-IP> -H "Host: git.prod.t01tt.tech"` → should return 404 (expected, just verifying Traefik responds)
|
||||
3. Check orders: `kubectl get orders -A`
|
||||
|
||||
### CNPG cluster not becoming ready
|
||||
```bash
|
||||
kubectl describe cluster shared-pg -n cnpg
|
||||
kubectl logs -n cnpg-system deploy/cnpg-controller-manager
|
||||
```
|
||||
Common issue: pods can't schedule due to `podAntiAffinityType: required`. Ensure all 3 nodes exist and PVCs can bind.
|
||||
|
||||
### Gitea UI shows wrong URL after first login
|
||||
Gitea caches the ROOT_URL from the `deployment.yaml` env vars. If you change the domain, update:
|
||||
```bash
|
||||
kubectl set env deploy/gitea -n gitea \
|
||||
GITEA__server__DOMAIN=git.prod.t01tt.tech \
|
||||
GITEA__server__ROOT_URL=https://git.prod.t01tt.tech
|
||||
kubectl rollout restart deploy/gitea -n gitea
|
||||
```
|
||||
|
||||
### ArgoCD apps showing "Unknown" health
|
||||
This is normal for Ingress resources — the custom health check in `bootstrap/argocd/values.yaml` marks all Ingresses as `Healthy` once synced. For other resources, check the app details in ArgoCD UI for the specific error.
|
||||
25
argocd/app-of-apps.yaml
Normal file
25
argocd/app-of-apps.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: root-app
|
||||
namespace: argocd
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: http://gitea.gitea.svc.cluster.local:3000/gitea/yandex-prod.git
|
||||
targetRevision: main
|
||||
path: argocd/apps
|
||||
directory:
|
||||
recurse: true
|
||||
include: "*.yaml"
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: argocd
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
25
argocd/apps/cert-manager-issuers.yaml
Normal file
25
argocd/apps/cert-manager-issuers.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: cert-manager-issuers
|
||||
namespace: argocd
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "0"
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: http://gitea.gitea.svc.cluster.local:3000/gitea/yandex-prod.git
|
||||
targetRevision: main
|
||||
path: manifests/cert-manager
|
||||
directory:
|
||||
recurse: true
|
||||
include: "*.yaml"
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: cert-manager
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
24
argocd/apps/cert-manager.yaml
Normal file
24
argocd/apps/cert-manager.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: cert-manager
|
||||
namespace: argocd
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "-1"
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://charts.jetstack.io
|
||||
chart: cert-manager
|
||||
targetRevision: ">=1.18.0"
|
||||
helm:
|
||||
values: |
|
||||
installCRDs: true
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: cert-manager
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
27
argocd/apps/cnpg-cluster.yaml
Normal file
27
argocd/apps/cnpg-cluster.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: cnpg-cluster
|
||||
namespace: argocd
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "1"
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: http://gitea.gitea.svc.cluster.local:3000/gitea/yandex-prod.git
|
||||
targetRevision: main
|
||||
path: manifests/cnpg
|
||||
directory:
|
||||
recurse: true
|
||||
include: "*.yaml"
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: cnpg
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
19
argocd/apps/cnpg-operator.yaml
Normal file
19
argocd/apps/cnpg-operator.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: cnpg-operator
|
||||
namespace: argocd
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://cloudnative-pg.github.io/charts
|
||||
chart: cloudnative-pg
|
||||
targetRevision: ">=0.23.0"
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: cnpg-system
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
56
argocd/apps/loki.yaml
Normal file
56
argocd/apps/loki.yaml
Normal file
@@ -0,0 +1,56 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: loki
|
||||
namespace: argocd
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "0"
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://grafana.github.io/helm-charts
|
||||
chart: loki
|
||||
targetRevision: ">=6.0.0"
|
||||
helm:
|
||||
values: |
|
||||
deploymentMode: SingleBinary
|
||||
loki:
|
||||
auth_enabled: false
|
||||
commonConfig:
|
||||
replication_factor: 1
|
||||
storage:
|
||||
type: filesystem
|
||||
schemaConfig:
|
||||
configs:
|
||||
- from: "2025-01-01"
|
||||
store: tsdb
|
||||
objectStore: filesystem
|
||||
schema: v13
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
limits_config:
|
||||
retention_period: 30d
|
||||
reject_old_samples: true
|
||||
reject_old_samples_max_age: 168h
|
||||
|
||||
singleBinary:
|
||||
replicas: 1
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 20Gi
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: metrics
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
119
argocd/apps/monitoring.yaml
Normal file
119
argocd/apps/monitoring.yaml
Normal file
@@ -0,0 +1,119 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: monitoring
|
||||
namespace: argocd
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "0"
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
sources:
|
||||
- repoURL: https://victoriametrics.github.io/helm-charts/
|
||||
chart: victoria-metrics-k8s-stack
|
||||
targetRevision: ">=0.30.0"
|
||||
helm:
|
||||
values: |
|
||||
fullnameOverride: vm-k8s-stack
|
||||
namespaceOverride: metrics
|
||||
|
||||
vmsingle:
|
||||
enabled: true
|
||||
spec:
|
||||
retentionPeriod: "30d"
|
||||
replicaCount: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
storage:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 30Gi
|
||||
|
||||
alertmanager:
|
||||
enabled: true
|
||||
spec:
|
||||
replicaCount: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
storage:
|
||||
volumeClaimTemplate:
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
config:
|
||||
route:
|
||||
receiver: blackhole
|
||||
receivers:
|
||||
- name: blackhole
|
||||
|
||||
grafana:
|
||||
enabled: true
|
||||
adminUser: admin
|
||||
adminPassword: change-me
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 2Gi
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
|
||||
prometheus-node-exporter:
|
||||
enabled: true
|
||||
|
||||
kube-state-metrics:
|
||||
enabled: true
|
||||
|
||||
kubelet:
|
||||
enabled: true
|
||||
|
||||
kubeApiServer:
|
||||
enabled: false
|
||||
|
||||
kubeControllerManager:
|
||||
enabled: false
|
||||
|
||||
kubeScheduler:
|
||||
enabled: false
|
||||
|
||||
kubeProxy:
|
||||
enabled: false
|
||||
|
||||
kubeEtcd:
|
||||
enabled: false
|
||||
|
||||
- repoURL: http://gitea.gitea.svc.cluster.local:3000/gitea/yandex-prod.git
|
||||
targetRevision: main
|
||||
path: manifests/metrics/grafana
|
||||
directory:
|
||||
recurse: true
|
||||
include: "*.yaml"
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: argocd
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
84
argocd/apps/traefik.yaml
Normal file
84
argocd/apps/traefik.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: argocd
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "-2"
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://traefik.github.io/charts
|
||||
chart: traefik
|
||||
targetRevision: ">=37.0.0"
|
||||
helm:
|
||||
values: |
|
||||
deployment:
|
||||
kind: DaemonSet
|
||||
|
||||
ingressClass:
|
||||
enabled: true
|
||||
isDefaultClass: true
|
||||
|
||||
additionalArguments:
|
||||
- "--api.dashboard=true"
|
||||
- "--ping=true"
|
||||
- "--metrics.prometheus=true"
|
||||
- "--metrics.prometheus.entrypoint=metrics"
|
||||
- "--providers.kubernetesingress.ingressclass=traefik"
|
||||
- "--providers.kubernetesingress.ingressendpoint.publishedservice=traefik/traefik"
|
||||
- "--accesslog=true"
|
||||
- "--log.level=INFO"
|
||||
|
||||
ports:
|
||||
web:
|
||||
port: 8080
|
||||
exposedPort: 80
|
||||
redirectTo: websecure
|
||||
websecure:
|
||||
port: 8443
|
||||
exposedPort: 443
|
||||
metrics:
|
||||
port: 9100
|
||||
expose: false
|
||||
traefik:
|
||||
port: 9000
|
||||
expose: false
|
||||
|
||||
service:
|
||||
type: LoadBalancer
|
||||
annotations:
|
||||
service.beta.kubernetes.io/yandex-load-balancer-name: traefik
|
||||
service.beta.kubernetes.io/yandex-load-balancer-specification: '{"type": "network-load-balancer"}'
|
||||
service.beta.kubernetes.io/yandex-load-balancer-type: external
|
||||
|
||||
podAnnotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "9100"
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: traefik
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
26
bootstrap/argocd/ingress.yaml
Normal file
26
bootstrap/argocd/ingress.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: argocd
|
||||
namespace: argocd
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- argocd.prod.t01tt.tech
|
||||
secretName: argocd-tls
|
||||
rules:
|
||||
- host: argocd.prod.t01tt.tech
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: argocd-server
|
||||
port:
|
||||
number: 80
|
||||
29
bootstrap/argocd/install.sh
Executable file
29
bootstrap/argocd/install.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
KUBECONFIG="/home/mrt0rtikize/infra/yandex-prod/kubeconfig"
|
||||
KCTL="kubectl --kubeconfig ${KUBECONFIG}"
|
||||
|
||||
echo "=== Installing ArgoCD ==="
|
||||
|
||||
helm repo add argo https://argoproj.github.io/argo-helm 2>/dev/null || true
|
||||
helm repo update
|
||||
|
||||
helm upgrade --install argocd argo/argo-cd \
|
||||
--namespace argocd \
|
||||
--create-namespace \
|
||||
--values "$(dirname "$0")/values.yaml" \
|
||||
--wait \
|
||||
--timeout 300s
|
||||
|
||||
echo ""
|
||||
echo "=== ArgoCD installed ==="
|
||||
echo ""
|
||||
echo "To access ArgoCD UI:"
|
||||
echo " kubectl --kubeconfig ${KUBECONFIG} port-forward svc/argocd-server -n argocd 8080:80"
|
||||
echo ""
|
||||
echo "Admin password:"
|
||||
kubectl --kubeconfig ${KUBECONFIG} -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Login with username: admin"
|
||||
20
bootstrap/argocd/values.yaml
Normal file
20
bootstrap/argocd/values.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
server:
|
||||
extraArgs:
|
||||
- --insecure
|
||||
|
||||
configs:
|
||||
params:
|
||||
server.insecure: true
|
||||
cm:
|
||||
timeout.reconciliation: 180s
|
||||
helm.timeoutSeconds: "300"
|
||||
resource.customizations.health.networking.k8s.io_Ingress: |
|
||||
hs = {}
|
||||
hs.status = "Healthy"
|
||||
hs.message = "Ingress is synced"
|
||||
return hs
|
||||
|
||||
redis:
|
||||
image:
|
||||
repository: docker.io/library/redis
|
||||
tag: 7.4-alpine
|
||||
64
bootstrap/gitea/deployment.yaml
Normal file
64
bootstrap/gitea/deployment.yaml
Normal file
@@ -0,0 +1,64 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gitea
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: gitea
|
||||
spec:
|
||||
containers:
|
||||
- name: gitea
|
||||
image: gitea/gitea:1.24
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http
|
||||
- containerPort: 22
|
||||
name: ssh
|
||||
env:
|
||||
- name: GITEA__database__DB_TYPE
|
||||
value: sqlite3
|
||||
- name: GITEA__server__DOMAIN
|
||||
value: git.prod.t01tt.tech
|
||||
- name: GITEA__server__ROOT_URL
|
||||
value: https://git.prod.t01tt.tech
|
||||
- name: GITEA__server__HTTP_PORT
|
||||
value: "3000"
|
||||
- name: GITEA__server__SSH_PORT
|
||||
value: "22"
|
||||
- name: GITEA__service__DISABLE_REGISTRATION
|
||||
value: "true"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 3000
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 3000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: gitea-data
|
||||
26
bootstrap/gitea/ingress.yaml
Normal file
26
bootstrap/gitea/ingress.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- git.prod.t01tt.tech
|
||||
secretName: gitea-tls
|
||||
rules:
|
||||
- host: git.prod.t01tt.tech
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: gitea
|
||||
port:
|
||||
number: 3000
|
||||
4
bootstrap/gitea/namespace.yaml
Normal file
4
bootstrap/gitea/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: gitea
|
||||
11
bootstrap/gitea/pvc.yaml
Normal file
11
bootstrap/gitea/pvc.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-data
|
||||
namespace: gitea
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
15
bootstrap/gitea/service.yaml
Normal file
15
bootstrap/gitea/service.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
spec:
|
||||
selector:
|
||||
app: gitea
|
||||
ports:
|
||||
- name: http
|
||||
port: 3000
|
||||
targetPort: 3000
|
||||
- name: ssh
|
||||
port: 22
|
||||
targetPort: 22
|
||||
5
kubeconfig
Normal file
5
kubeconfig
Normal file
@@ -0,0 +1,5 @@
|
||||
# Placeholder for Yandex Cloud Managed Kubernetes kubeconfig.
|
||||
# Copy your kubeconfig here before running bootstrap.
|
||||
#
|
||||
# Example:
|
||||
# yc managed-kubernetes cluster get-credentials --id <cluster-id> --external --kubeconfig kubeconfig
|
||||
29
manifests/cert-manager/cluster-issuers.yaml
Normal file
29
manifests/cert-manager/cluster-issuers.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-production
|
||||
spec:
|
||||
acme:
|
||||
email: i_am@rogov.al
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-production-account-key
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
class: traefik
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-staging
|
||||
spec:
|
||||
acme:
|
||||
email: i_am@rogov.al
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-staging-account-key
|
||||
server: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
class: traefik
|
||||
30
manifests/cnpg/cluster.yaml
Normal file
30
manifests/cnpg/cluster.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
name: shared-pg
|
||||
namespace: cnpg
|
||||
spec:
|
||||
instances: 3
|
||||
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||
|
||||
storage:
|
||||
size: 20Gi
|
||||
storageClass: yc-network-ssd
|
||||
|
||||
affinity:
|
||||
podAntiAffinityType: required
|
||||
|
||||
bootstrap:
|
||||
initdb:
|
||||
database: postgres
|
||||
owner: postgres
|
||||
|
||||
postgresql:
|
||||
parameters:
|
||||
shared_buffers: "256MB"
|
||||
effective_cache_size: "768MB"
|
||||
maintenance_work_mem: "64MB"
|
||||
max_connections: "200"
|
||||
|
||||
monitoring:
|
||||
enablePodMonitor: true
|
||||
87
manifests/cnpg/databases.yaml
Normal file
87
manifests/cnpg/databases.yaml
Normal file
@@ -0,0 +1,87 @@
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: synapse-mrt0rtikize
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: synapse_mrt0rtikize
|
||||
owner: synapse_mrt0rtikize
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: mas-mrt0rtikize
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: mas_mrt0rtikize
|
||||
owner: mas_mrt0rtikize
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: synapse-t0rt1k
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: synapse_t0rt1k
|
||||
owner: synapse_t0rt1k
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: mas-t0rt1k
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: mas_t0rt1k
|
||||
owner: mas_t0rt1k
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: synapse-roglog
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: synapse_roglog
|
||||
owner: synapse_roglog
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: mas-roglog
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: mas_roglog
|
||||
owner: mas_roglog
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: synapse-uretra
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: synapse_uretra
|
||||
owner: synapse_uretra
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Database
|
||||
metadata:
|
||||
name: mas-uretra
|
||||
namespace: cnpg
|
||||
spec:
|
||||
name: mas_uretra
|
||||
owner: mas_uretra
|
||||
clusterRef:
|
||||
name: shared-pg
|
||||
4
manifests/cnpg/namespace.yaml
Normal file
4
manifests/cnpg/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: cnpg
|
||||
63
manifests/cnpg/secrets.yaml
Normal file
63
manifests/cnpg/secrets.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: mrt0rtikize-pg-creds
|
||||
namespace: cnpg
|
||||
labels:
|
||||
cnpg.io/reload: ""
|
||||
type: kubernetes.io/basic-auth
|
||||
stringData:
|
||||
synapse: |
|
||||
username: synapse_mrt0rtikize
|
||||
password: change-me-synapse
|
||||
mas: |
|
||||
username: mas_mrt0rtikize
|
||||
password: change-me-mas
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: t0rt1k-pg-creds
|
||||
namespace: cnpg
|
||||
labels:
|
||||
cnpg.io/reload: ""
|
||||
type: kubernetes.io/basic-auth
|
||||
stringData:
|
||||
synapse: |
|
||||
username: synapse_t0rt1k
|
||||
password: change-me-synapse
|
||||
mas: |
|
||||
username: mas_t0rt1k
|
||||
password: change-me-mas
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: roglog-pg-creds
|
||||
namespace: cnpg
|
||||
labels:
|
||||
cnpg.io/reload: ""
|
||||
type: kubernetes.io/basic-auth
|
||||
stringData:
|
||||
synapse: |
|
||||
username: synapse_roglog
|
||||
password: change-me-synapse
|
||||
mas: |
|
||||
username: mas_roglog
|
||||
password: change-me-mas
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: uretra-pg-creds
|
||||
namespace: cnpg
|
||||
labels:
|
||||
cnpg.io/reload: ""
|
||||
type: kubernetes.io/basic-auth
|
||||
stringData:
|
||||
synapse: |
|
||||
username: synapse_uretra
|
||||
password: change-me-synapse
|
||||
mas: |
|
||||
username: mas_uretra
|
||||
password: change-me-mas
|
||||
26
manifests/metrics/grafana/ingress.yaml
Normal file
26
manifests/metrics/grafana/ingress.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: metrics
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- grafana.prod.t01tt.tech
|
||||
secretName: grafana-tls
|
||||
rules:
|
||||
- host: grafana.prod.t01tt.tech
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: vm-k8s-stack-grafana
|
||||
port:
|
||||
number: 80
|
||||
4
manifests/metrics/namespace.yaml
Normal file
4
manifests/metrics/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: metrics
|
||||
Reference in New Issue
Block a user