Skip to content

Commit 95ea4c4

Browse files
author
Mateus Medeiros
committed
test local dns
1 parent 732330f commit 95ea4c4

5 files changed

Lines changed: 74 additions & 27 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
# CoreDNS ConfigMap patch to rewrite external API hostname to internal Kubernetes service
3+
# This solves the Angular SSR + hydration duplicate HTTP request issue by:
4+
# 1. SSR pod and browser both use the same external URL (api.writefluency.com)
5+
# 2. Inside the cluster, CoreDNS rewrites api.writefluency.com -> wf-api.writefluency.svc.cluster.local
6+
# 3. This avoids hairpin NAT timeouts and ensures Angular transfer cache works correctly
7+
#
8+
# Apply with: kubectl apply -f coredns-rewrite.yaml
9+
# Then restart CoreDNS: kubectl -n kube-system rollout restart deployment coredns
10+
#
11+
apiVersion: v1
12+
kind: ConfigMap
13+
metadata:
14+
name: coredns
15+
namespace: kube-system
16+
data:
17+
Corefile: |
18+
.:53 {
19+
errors
20+
health {
21+
lameduck 5s
22+
}
23+
ready
24+
# Rewrite external API hostname to internal service for in-cluster requests
25+
# This enables SSR and browser to use the same URL while avoiding hairpin NAT
26+
rewrite name api.writefluency.com wf-api.writefluency.svc.cluster.local
27+
kubernetes cluster.local in-addr.arpa ip6.arpa {
28+
pods insecure
29+
fallthrough in-addr.arpa ip6.arpa
30+
ttl 30
31+
}
32+
prometheus :9153
33+
forward . /etc/resolv.conf {
34+
max_concurrent 1000
35+
}
36+
cache 30
37+
loop
38+
reload
39+
loadbalance
40+
}

src/host/WriteFluency.AppHost/deploy-k8s.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ set -e
44

55
KUBE_CONTEXT=$1
66

7+
# Create cert-manager namespace first (required before applying cert-manager resources)
8+
kubectl create namespace cert-manager --dry-run=client -o yaml | kubectl apply -f -
9+
710
./generate-k8s-secret.sh
811

912
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
@@ -13,5 +16,15 @@ kubectl rollout status deployment cert-manager -n cert-manager --timeout=120s
1316
kubectl rollout status deployment cert-manager-webhook -n cert-manager --timeout=120s
1417
kubectl rollout status deployment cert-manager-cainjector -n cert-manager --timeout=120s
1518

19+
# Apply CoreDNS rewrite configuration to resolve external API URL to internal service
20+
# This prevents duplicate HTTP requests in Angular SSR by ensuring both SSR and browser use the same URL
21+
echo "🔧 Applying CoreDNS rewrite configuration..."
22+
kubectl apply -f ./aspirate-overlays/coredns-rewrite.yaml
23+
24+
echo "🔄 Restarting CoreDNS to apply configuration..."
25+
kubectl -n kube-system rollout restart deployment coredns
26+
kubectl -n kube-system rollout status deployment coredns --timeout=60s
27+
28+
echo "✅ CoreDNS configuration applied successfully"
1629

1730
aspirate apply -i ./aspirate-overlays --non-interactive --kube-context "$KUBE_CONTEXT"

src/host/WriteFluency.AppHost/generate-k8s-secret.sh

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,8 @@ if [ "$GITHUB_ACTIONS" = "true" ]; then
2121
propositions_daily_requests_limit="${Propositions__DailyRequestsLimit}"
2222
propositions_limit_per_topic="${Propositions__LimitPerTopic}"
2323
propositions_news_request_limit="${Propositions__NewsRequestLimit}"
24-
25-
# Create image pull secret for GHCR
26-
echo "🔑 Creating GHCR image pull secret..."
27-
kubectl create secret docker-registry ghcr-secret \
28-
--docker-server=ghcr.io \
29-
--docker-username="${GHCR_USERNAME}" \
30-
--docker-password="${GHCR_TOKEN}" \
31-
--namespace=writefluency \
32-
--dry-run=client -o yaml | kubectl apply -f -
24+
ghcr_username="${GHCR_USERNAME}"
25+
ghcr_token="${GHCR_TOKEN}"
3326

3427
else
3528
echo "🔐 Running locally — using .NET user secrets"
@@ -48,8 +41,19 @@ else
4841
propositions_daily_requests_limit=$(jq -r '.["Propositions:DailyRequestsLimit"]' "$USER_SECRETS")
4942
propositions_limit_per_topic=$(jq -r '.["Propositions:LimitPerTopic"]' "$USER_SECRETS")
5043
propositions_news_request_limit=$(jq -r '.["Propositions:NewsRequestLimit"]' "$USER_SECRETS")
44+
ghcr_username=$(jq -r '.["GHCR_USERNAME"]' "$USER_SECRETS")
45+
ghcr_token=$(jq -r '.["GHCR_TOKEN"]' "$USER_SECRETS")
5146
fi
5247

48+
# Create image pull secret for GHCR
49+
echo "🔑 Creating GHCR image pull secret..."
50+
kubectl create secret docker-registry ghcr-secret \
51+
--docker-server=ghcr.io \
52+
--docker-username="${ghcr_username}" \
53+
--docker-password="${ghcr_token}" \
54+
--namespace=writefluency \
55+
--dry-run=client -o yaml | kubectl apply -f -
56+
5357
kubectl apply -f - <<EOF
5458
apiVersion: v1
5559
kind: Secret

src/webapp/src/app/app.config.server.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,15 @@ import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
22
import { provideServerRendering, withRoutes } from '@angular/ssr';
33
import { appConfig } from './app.config';
44
import { serverRoutes } from './app.routes.server';
5-
import { provideApi } from 'src/api/listen-and-write/provide-api';
6-
import { environment } from '../enviroments/enviroment';
75

8-
// Server-side API URL - uses Aspire service discovery in Kubernetes
9-
// Aspire sets: services__wf-api__http__0=http://wf-api:8080
10-
// Falls back to build-time environment for local development
11-
const aspireApiUrl = process.env['services__wf-api__http__0'];
12-
const serverApiUrl = aspireApiUrl || environment.apiUrl;
13-
14-
console.log(`[SSR] Using API URL: ${serverApiUrl}`);
6+
// SSR now uses the same external API URL as the browser (from environment)
7+
// CoreDNS rewrite rule in Kubernetes will resolve api.writefluency.com to internal service
8+
// This ensures Angular transfer cache works correctly (no duplicate HTTP requests)
159

1610
const serverConfig: ApplicationConfig = {
1711
providers: [
18-
provideServerRendering(withRoutes(serverRoutes)),
19-
// Override the API URL for server-side rendering
20-
provideApi(serverApiUrl)
12+
provideServerRendering(withRoutes(serverRoutes))
13+
// No API URL override - uses the same provideApi from appConfig
2114
]
2215
};
2316

src/webapp/src/server.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@ import { environment } from './enviroments/enviroment';
1010

1111
const browserDistFolder = join(import.meta.dirname, '../browser');
1212

13-
// Use Aspire service discovery environment variables for SSR
14-
// Aspire sets: services__wf-api__http__0=http://wf-api:8080
15-
// In Kubernetes: Uses Aspire service discovery
16-
// In local dev: Falls back to environment.apiUrl
17-
const aspireApiUrl = process.env['services__wf-api__http__0'];
18-
const apiUrl = aspireApiUrl || environment.apiUrl;
13+
// Server now uses the same external API URL as the browser
14+
// CoreDNS rewrite in k8s resolves api.writefluency.com to wf-api service internally
15+
const apiUrl = environment.apiUrl;
1916

2017
console.log(`[Server] Using API URL: ${apiUrl}`);
2118

0 commit comments

Comments
 (0)