diff --git a/deploy/k8s/api.yaml b/deploy/k8s/api.yaml index c6ccfa7..972dd69 100644 --- a/deploy/k8s/api.yaml +++ b/deploy/k8s/api.yaml @@ -32,11 +32,9 @@ spec: labels: app.kubernetes.io/name: insurance-api spec: - imagePullSecrets: - - name: gitea-registry containers: - name: api - image: git.junggomoa.com/chpark/insurance-api:latest + image: localhost:5000/insurance/api:latest imagePullPolicy: Always ports: - name: http @@ -95,36 +93,11 @@ metadata: labels: app.kubernetes.io/name: insurance-api spec: - type: ClusterIP + type: NodePort selector: app.kubernetes.io/name: insurance-api ports: - name: http port: 4000 targetPort: http ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: insurance-api - namespace: insurance - annotations: - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.tls: "true" -spec: - ingressClassName: traefik - tls: - - hosts: - - api.insurance.junggomoa.com - secretName: insurance-api-tls - rules: - - host: api.insurance.junggomoa.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: insurance-api - port: - number: 4000 + nodePort: 30201 diff --git a/deploy/k8s/deployment.yaml b/deploy/k8s/deployment.yaml index a458fb6..6be7806 100644 --- a/deploy/k8s/deployment.yaml +++ b/deploy/k8s/deployment.yaml @@ -5,7 +5,6 @@ metadata: namespace: insurance labels: app.kubernetes.io/name: insurance-web - app.kubernetes.io/component: frontend spec: replicas: 2 revisionHistoryLimit: 3 @@ -21,19 +20,14 @@ spec: metadata: labels: app.kubernetes.io/name: insurance-web - annotations: - kubectl.kubernetes.io/restartedAt: "placeholder-will-be-patched-by-ci" spec: - imagePullSecrets: - - name: gitea-registry containers: - name: web - image: git.junggomoa.com/chpark/insurance:latest + image: localhost:5000/insurance/web:latest imagePullPolicy: Always ports: - name: http containerPort: 80 - protocol: TCP readinessProbe: httpGet: path: /health @@ -53,9 +47,3 @@ spec: limits: cpu: 300m memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - runAsNonRoot: false - capabilities: - drop: ["ALL"] - add: ["CHOWN", "SETGID", "SETUID", "NET_BIND_SERVICE"] diff --git a/deploy/k8s/ingress.yaml b/deploy/k8s/ingress.yaml deleted file mode 100644 index 19b341d..0000000 --- a/deploy/k8s/ingress.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: insurance-web - namespace: insurance - annotations: - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.tls: "true" -spec: - ingressClassName: traefik - tls: - - hosts: - - insurance.junggomoa.com - secretName: insurance-tls - rules: - - host: insurance.junggomoa.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: insurance-web - port: - number: 80 diff --git a/deploy/k8s/ingressroute-traefik.yaml b/deploy/k8s/ingressroute-traefik.yaml deleted file mode 100644 index e2e6f16..0000000 --- a/deploy/k8s/ingressroute-traefik.yaml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: insurance-web - namespace: insurance -spec: - entryPoints: - - websecure - routes: - - match: Host(`insurance.junggomoa.com`) - kind: Rule - services: - - name: insurance-web - port: 80 - tls: - secretName: insurance-tls ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: insurance-web-http - namespace: insurance -spec: - entryPoints: - - web - routes: - - match: Host(`insurance.junggomoa.com`) - kind: Rule - middlewares: - - name: insurance-redirect-https - services: - - name: insurance-web - port: 80 ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: insurance-redirect-https - namespace: insurance -spec: - redirectScheme: - scheme: https - permanent: true diff --git a/deploy/k8s/service.yaml b/deploy/k8s/service.yaml index f1a1802..4f1ada4 100644 --- a/deploy/k8s/service.yaml +++ b/deploy/k8s/service.yaml @@ -6,11 +6,11 @@ metadata: labels: app.kubernetes.io/name: insurance-web spec: - type: ClusterIP + type: NodePort selector: app.kubernetes.io/name: insurance-web ports: - name: http port: 80 targetPort: http - protocol: TCP + nodePort: 30200 diff --git a/deploy/traefik-dynamic.yml b/deploy/traefik-dynamic.yml new file mode 100644 index 0000000..0a3f613 --- /dev/null +++ b/deploy/traefik-dynamic.yml @@ -0,0 +1,30 @@ +http: + routers: + insurance-web: + rule: "Host(`insurance.junggomoa.com`)" + entryPoints: + - web + - websecure + service: insurance-web + tls: + certResolver: le + + insurance-api: + rule: "Host(`api.insurance.junggomoa.com`)" + entryPoints: + - web + - websecure + service: insurance-api + tls: + certResolver: le + + services: + insurance-web: + loadBalancer: + servers: + - url: "http://127.0.0.1:30200" + + insurance-api: + loadBalancer: + servers: + - url: "http://127.0.0.1:30201" diff --git a/scripts/deploy-remote.sh b/scripts/deploy-remote.sh new file mode 100644 index 0000000..33f5054 --- /dev/null +++ b/scripts/deploy-remote.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -e +export KUBECONFIG=/home/chpark/.kube/config +SUDO="echo qlalfqjsgh11 | sudo -S" + +cd /home/chpark +if [ -d insurance ]; then + echo "[*] Updating insurance repo" + cd insurance && git pull origin master +else + echo "[*] Cloning insurance repo" + git clone https://git.junggomoa.com/chpark/insurance.git + cd insurance +fi + +echo "[*] Building web image" +docker build \ + --build-arg EXPO_PUBLIC_API_BASE=https://api.insurance.junggomoa.com \ + -t localhost:5000/insurance/web:latest \ + -f Dockerfile . + +echo "[*] Building api image" +docker build -t localhost:5000/insurance/api:latest -f server/Dockerfile server + +echo "[*] Pushing to local registry" +docker push localhost:5000/insurance/web:latest +docker push localhost:5000/insurance/api:latest + +echo "[*] Applying Kubernetes manifests" +kubectl apply -f deploy/k8s/namespace.yaml + +POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-$(openssl rand -hex 24)}" +JWT_SECRET="${JWT_SECRET:-$(openssl rand -hex 32)}" + +kubectl -n insurance create secret generic postgres-credentials \ + --from-literal=username=insurance \ + --from-literal=password="$POSTGRES_PASSWORD" \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl -n insurance create secret generic api-secrets \ + --from-literal=jwtSecret="$JWT_SECRET" \ + --from-literal=databaseUrl="postgresql://insurance:${POSTGRES_PASSWORD}@postgres:5432/insurance?schema=public" \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl apply -f deploy/k8s/postgres.yaml +kubectl -n insurance rollout status statefulset/postgres --timeout=180s + +kubectl apply -f deploy/k8s/api.yaml +kubectl -n insurance rollout restart deployment/insurance-api || true +kubectl -n insurance rollout status deployment/insurance-api --timeout=240s + +kubectl apply -f deploy/k8s/deployment.yaml +kubectl apply -f deploy/k8s/service.yaml +kubectl -n insurance rollout restart deployment/insurance-web || true +kubectl -n insurance rollout status deployment/insurance-web --timeout=180s + +echo "[*] Installing Traefik dynamic routing" +eval "$SUDO cp deploy/traefik-dynamic.yml /opt/docker/traefik/dynamic/insurance.yml" +eval "$SUDO chmod 644 /opt/docker/traefik/dynamic/insurance.yml" + +echo "[*] Saving secrets for reuse" +cat > /home/chpark/.insurance-secrets < { + const conn = new Client(); + let stdout = ''; + let stderr = ''; + conn + .on('ready', () => { + conn.exec(cmd, (err, stream) => { + if (err) { conn.end(); return reject(err); } + stream.on('close', (code) => { conn.end(); resolve({ code, stdout, stderr }); }) + .on('data', (data) => { const s = data.toString(); stdout += s; if (!silent) process.stdout.write(s); }) + .stderr.on('data', (data) => { const s = data.toString(); stderr += s; if (!silent) process.stderr.write(s); }); + }); + }) + .on('error', reject) + .connect({ host: HOST, port: PORT, username: USER, password: PASS, readyTimeout: 30000 }); + }); +} + +module.exports = { run }; + +if (require.main === module) { + const cmd = process.argv.slice(2).join(' '); + if (!cmd) { + console.error('usage: node ssh-run.js '); + process.exit(1); + } + run(cmd).then(r => process.exit(r.code)).catch(e => { console.error(e.message); process.exit(1); }); +}