Merge pull request #6 from MealCraft/feature/traefik_who_am_i

Feature/traefik who am i
This commit is contained in:
Jun-te Kim 2025-12-07 10:40:22 +00:00 committed by GitHub
commit 8ae3d78fad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 510 additions and 282 deletions

97
.github/workflows/juntekim.yml vendored Normal file
View file

@ -0,0 +1,97 @@
name: Build juntekim.com
on:
push:
tags:
- "*"
branches:
- "**"
jobs:
Push-to-docker-hub:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Inject slug/short variables
uses: rlespinasse/github-slug-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build Docker Image
run: |
docker build \
-f juntekim_frontend/deployment/Dockerfile \
-t docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG \
juntekim_frontend
- name: Push to Docker Hub
run: |
docker push docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG
run-on-k8s:
runs-on: mealcraft-runners # <-- your ARC scale set label
needs: Push-to-docker-hub
steps:
- uses: actions/checkout@v4
# Install kubectl inside containerMode's default Ubuntu
- name: Install kubectl
run: |
sudo apt-get update
sudo apt-get install -y curl ca-certificates
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -m 0755 kubectl /usr/local/bin/kubectl
- name: Install envsubst
run: |
sudo apt-get update
sudo apt-get install -y gettext # <---- envsubst lives here
# Configure kubeconfig from ARC's service account
- name: Configure kubeconfig
run: |
KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT"
kubectl config set-credentials runner --token="$SA_TOKEN"
kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE"
kubectl config use-context runner-context
- name: Inject slug variables
uses: rlespinasse/github-slug-action@v4
- name: Set namespace
id: ns
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
echo "NAMESPACE=default" >> $GITHUB_ENV
else
echo "NAMESPACE=staging" >> $GITHUB_ENV
fi
- name: Set hostname
run: |
if [ "$NAMESPACE" = "staging" ]; then
echo "HOSTNAME=staging.juntekim.com" >> $GITHUB_ENV
else
echo "HOSTNAME=juntekim.com" >> $GITHUB_ENV
fi
- name: Deploy to Kubernetes
run: |
export IMAGE="docker.io/kimjunte/portfolio_page:$GITHUB_REF_SLUG"
export NAMESPACE HOSTNAME
envsubst < juntekim_frontend/deployment/deployment.yml | kubectl apply -f -
envsubst < juntekim_frontend/deployment/service.yml | kubectl apply -f -
envsubst < juntekim_frontend/deployment/ingressroute.yml | kubectl apply -f -

View file

@ -4,127 +4,116 @@ on:
workflow_dispatch:
jobs:
bootstrap:
runs-on: mealcraft-runners
container: ubuntu:22.04
# -----------------------------------------------------
# Job 1: Build and push image using GitHub-hosted runner
# -----------------------------------------------------
build-image:
runs-on: ubuntu-latest
steps:
# -----------------------------------------------------
# Checkout
# -----------------------------------------------------
- uses: actions/checkout@v4
- uses: actions/checkout@v4
# -----------------------------------------------------
# Install kubectl
# -----------------------------------------------------
- name: Install kubectl
run: |
apt-get update
apt-get install -y ca-certificates curl
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
install -m 0755 kubectl /usr/local/bin/kubectl
# Docker login on GitHub-hosted runner (has Docker)
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
# -----------------------------------------------------
# Configure kubeconfig using the ARC pod token
# -----------------------------------------------------
- name: Configure kubeconfig
run: |
KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
# Build and push using real Docker daemon
- name: Build & Push Traefik Image
uses: docker/build-push-action@v5
with:
context: ./traefik
file: ./traefik/Dockerfile
push: true
tags: |
docker.io/kimjunte/edge_router:${{ github.sha }}
docker.io/kimjunte/edge_router:latest
kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT"
kubectl config set-credentials runner --token="$SA_TOKEN"
kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE"
kubectl config use-context runner-context
# -----------------------------------------------------
# Job 2: Deploy to MicroK8s using ARC self-hosted runner
# -----------------------------------------------------
deploy:
runs-on: mealcraft-runners
needs: build-image
# -----------------------------------------------------
# Docker Login
# -----------------------------------------------------
- name: Docker Login
uses: ./.github/actions/docker-login
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
steps:
- uses: actions/checkout@v4
# -----------------------------------------------------
# Build & Push the Docker Image (idempotent)
# -----------------------------------------------------
- name: Build Traefik Image
run: |
docker build traefik \
--file traefik/Dockerfile \
--tag docker.io/kimjunte/edge_router:$GITHUB_SHA
# Install kubectl inside containerMode's default Ubuntu
- name: Install kubectl
run: |
sudo apt-get update
sudo apt-get install -y curl ca-certificates
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -m 0755 kubectl /usr/local/bin/kubectl
- name: Push Traefik Image
run: |
docker push docker.io/kimjunte/edge_router:$GITHUB_SHA
# Configure kubeconfig from ARC's service account
- name: Configure kubeconfig
run: |
KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
# -----------------------------------------------------
# Apply Storage Classes + PVCs — idempotent with apply
# -----------------------------------------------------
- name: Apply StorageClass + PV
run: |
kubectl apply -f traefik/storageclass/storageclass.yaml
kubectl apply -f traefik/storageclass/certs-pv.yaml
kubectl get storageclass
kubectl config set-cluster microk8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT"
kubectl config set-credentials runner --token="$SA_TOKEN"
kubectl config set-context runner-context --cluster=microk8s --user=runner --namespace="$NAMESPACE"
kubectl config use-context runner-context
# -----------------------------------------------------
# Apply Traefik CRDs only if missing
# -----------------------------------------------------
- name: Install Traefik CRDs (idempotent)
run: |
if ! kubectl get crd ingressroutes.traefik.containo.us >/dev/null 2>&1; then
echo "Traefik CRDs not found — installing..."
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.10/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.10/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.10/docs/content/user-guides/crd-acme/05-tlsoption.yml
else
echo "Traefik CRDs already installed — skipping."
fi
# -----------------------------------------------------
# ⭐ Inject AWS secrets needed for Traefik Route53 DNS
# -----------------------------------------------------
- name: Apply AWS Secrets
run: |
kubectl create secret generic aws-secrets \
--namespace=default \
--from-literal=AWS_ACCESS_KEY_ID='${{ secrets.AWS_ACCESS_KEY_ID }}' \
--from-literal=AWS_SECRET_ACCESS_KEY='${{ secrets.AWS_SECRET_ACCESS_KEY }}' \
--from-literal=AWS_REGION='${{ secrets.AWS_REGION }}' \
--dry-run=client -o yaml | kubectl apply -f -
# -----------------------------------------------------
# Deploy Traefik — idempotent with kubectl apply
# -----------------------------------------------------
- name: Deploy Traefik (safe repeat)
run: |
echo "Applying Traefik PVC/Deployments/Services/etc…"
kubectl apply -f traefik/edge-router/pvc.yaml
kubectl apply -f traefik/edge-router/traefik-deployment.yml
kubectl apply -f traefik/edge-router/traefik-services.yml
kubectl apply -f traefik/edge-router/middleware.yaml
kubectl apply -f traefik/edge-router/secret-dashboard.yml
kubectl apply -f traefik/edge-router/traefik-ingressroute.yml
# Apply storage classes + PVs
- name: Apply StorageClass + PV
run: |
kubectl apply -f traefik/storageclass/storageclass.yaml
kubectl apply -f traefik/storageclass/certs-pv.yaml
# -----------------------------------------------------
# Deploy whoami — idempotent
# -----------------------------------------------------
- name: Deploy whoami test service
run: |
kubectl apply -f traefik/who-am-i/whoami-deployment.yml
kubectl apply -f traefik/who-am-i/whoami-service.yml
kubectl apply -f traefik/who-am-i/whoami-ingressroute.yml
# # Install Traefik CRDs (idempotent)
# - name: Install Traefik CRDs
# run: |
# kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.11/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
# kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.11/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml
# -----------------------------------------------------
# Create Docker Registry Secrets — idempotent
# -----------------------------------------------------
- name: Create registry secret (default ns)
run: |
kubectl apply -f traefik/docker-registry-credentials/docker-credentials.yml
# Deploy Traefik
- name: Deploy Traefik
run: |
kubectl apply -f traefik/edge-router/pvc.yaml
kubectl apply -f traefik/edge-router/traefik-deployment.yml
kubectl apply -f traefik/edge-router/traefik-services.yml
kubectl apply -f traefik/edge-router/middleware.yaml
kubectl apply -f traefik/edge-router/secret-dashboard.yml
kubectl apply -f traefik/edge-router/traefik-ingressroute.yml
# -----------------------------------------------------
# Create staging namespace if not exists
# -----------------------------------------------------
- name: Create staging namespace
run: |
kubectl get namespace staging >/dev/null 2>&1 || kubectl create namespace staging
# Deploy whoami test app
- name: Deploy whoami
run: |
kubectl apply -f traefik/who-am-i/whoami-deployment.yml
kubectl apply -f traefik/who-am-i/whoami-service.yml
kubectl apply -f traefik/who-am-i/whoami-ingressroute.yml
# -----------------------------------------------------
# Apply registry secret to staging — idempotent
# -----------------------------------------------------
- name: Registry secret in staging namespace
run: |
sed 's/namespace: default/namespace: staging/' \
traefik/docker-registry-credentials/docker-credentials.yml \
| kubectl apply -f -
# Registry secret
- name: Create registry secret (default)
run: kubectl apply -f traefik/docker-registry-credentials/docker-credentials.yml
# Staging namespace
- name: Create staging namespace
run: kubectl get ns staging >/dev/null 2>&1 || kubectl create namespace staging
- name: Registry secret to staging
run: |
sed 's/namespace: default/namespace: staging/' \
traefik/docker-registry-credentials/docker-credentials.yml \
| kubectl apply -f -

33
.vscode/settings.json vendored
View file

@ -1,19 +1,32 @@
{
"jupyter.interactiveWindow.textEditor.executeSelection": true,
"python.REPL.sendToNativeREPL": true,
"notebook.output.scrolling": true,
"terminal.integrated.defaultProfile.linux": "bash",
"editor.rulers": [67],
"terminal.integrated.profiles.linux": {
"bash": {
"path": "/bin/bash"
}
},
// Hot reload setting that needs to be in user settings
// "jupyter.runStartupCommands": [
// "%load_ext autoreload", "%autoreload 2"
// ]
// --- VIM SETTINGS ---
"vim.useSystemClipboard": true,
"vim.enableNeovim": false,
// Allow VSCode native keybindings to override Vim when needed
"vim.handleKeys": {
"<C-p>": false,
"<C-P>": false,
"<C-S-p>": false,
"<C-c>": false,
"<C-v>": false,
"<C-S-v>": false,
"<C-S-c>": false
},
// Make Y, y, p always sync with the system clipboard
// Terminal copy/paste via Ctrl+Shift+C / Ctrl+Shift+V
"terminal.integrated.copyOnSelection": false,
"terminal.integrated.commandsToSkipShell": [
"workbench.action.terminal.copySelection",
"workbench.action.terminal.paste"
],
}

View file

@ -2,17 +2,15 @@ TODO:
- [x] Get a basic nextjs app set up
- [x] Set up new laptop github workflow
- [x] Download next js
- [x] Aws terraform plan and apply configured
- [] Deploy into my new k8s
- [x] k get pods -A works
- [] deploy docker registry credentials
- [] deploy storageclass
- [] deloy traefik customised
- [] deploy who-am-i
- Traefik certs change to staging
- May need to move aws terraform here too
- [] Deploy into my dockercontainer new image
- [x] deploy docker registry credentials
- [x] deploy storageclass
- [x] deloy traefik customised
- [x] deploy who-am-i
- [] deploy next js to juntekim.com
- [] Traefik certs change from staging to production
- [] Merge my code to main
- [] Push from workflow k8s bootstrap

View file

@ -1,67 +1,179 @@
#!/bin/bash
set -ex
# OPTIONAL: Enable MicroK8s features first
# sudo microk8s enable dns rbac hostpath-storage host-access
# sudo microk8s enable metrics-server
# OPTIONAL: Configure kubectl
# =====================================================================
# OPTIONAL — MicroK8s setup/reset steps (only use when doing a hard reset)
# =====================================================================
# sudo microk8s reset --destroy-storage
# sudo snap remove microk8s
# sudo snap install microk8s --classic
# sudo microk8s enable dns rbac hostpath-storage host-access metrics-server ingress
# sudo microk8s enable metallb:192.168.0.200-192.168.0.220
#
# # Rebuild kubeconfig for your local user (optional)
# microk8s kubectl config view --raw > ~/.kube/config
# chmod 600 ~/.kube/config
# sudo usermod -aG microk8s $USER
# sudo chown -f -R $USER ~/.kube
# helm uninstall arc -n arc-systems || true
NAMESPACE="arc-systems"
RUNNER_NAME="mealcraft-runners"
# # =====================================================================
# # Remove previous ARC installation (safe even if missing)
# # =====================================================================
# helm uninstall arc -n "${NAMESPACE}" || true
# helm uninstall "${RUNNER_NAME}" -n "${NAMESPACE}" || true
# echo "=== Installing ARC Scale Set Controller ==="
# echo "=== Install ARC Scale Set Controller ==="
# helm install arc \
# --namespace arc-systems \
# --namespace "${NAMESPACE}" \
# --create-namespace \
# oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
# helm uninstall mealcraft-runners -n arc-systems || true
# echo "=== Installing MealCraft Runner Scale Set (NO Docker-in-Docker) ==="
# helm install mealcraft-runners \
# --namespace arc-systems \
# helm install "${RUNNER_NAME}" \
# --namespace "${NAMESPACE}" \
# --create-namespace \
# --set runnerScaleSetName="mealcraft-runners" \
# --set runnerScaleSetName="${RUNNER_NAME}" \
# --set githubConfigUrl="https://github.com/MealCraft" \
# --set githubConfigSecret.name="github-secret" \
# --set githubConfigSecret.github_token="$GITHUB_PAT" \
# --set containerMode.type="kubernetes" \
# --set containerMode.kubernetesModeDefaultContainer.image="ubuntu:22.04" \
# --set containerMode.kubernetesModeWorkVolumeClaim.accessModes[0]="ReadWriteOnce" \
# --set containerMode.kubernetesModeWorkVolumeClaim.storageClassName="microk8s-hostpath" \
# --set containerMode.kubernetesModeWorkVolumeClaim.resources.requests.storage="1Gi" \
# --set dockerInDockerEnabled=false \
# --set containerMode.type="runner" \
# --set runnerLabels[0]="mealcraft" \
# oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
echo "=== Applying RBAC for runner ==="
# # =====================================================================
# # RBAC — IMPORTANT
# # Grants permissions to the exact ARC runner SA detected earlier.
# # =====================================================================
microk8s kubectl apply -f - <<'EOF'
echo "=== Applying RBAC for all ARC runners + Traefik ==="
microk8s kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: arc-runner-readonly
name: mealcraft-bootstrap-role
rules:
# ----------------------------------------------------
# Storage
# ----------------------------------------------------
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["*"]
# ----------------------------------------------------
# Core API
# PV, PVC, Namespaces, Secrets, ConfigMaps, Services,
# ServiceAccounts (added for runner + Traefik needs)
# ----------------------------------------------------
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
resources:
- persistentvolumes
- persistentvolumeclaims
- namespaces
- secrets
- configmaps
- services
- serviceaccounts
- endpoints # <-- Traefik requires
- pods # <-- Traefik requires
- nodes # <-- Traefik requires for node discovery
verbs: ["*"]
# ----------------------------------------------------
# Apps: Deployments, DaemonSets, RS, StatefulSets
# ----------------------------------------------------
- apiGroups: ["apps"]
resources: ["deployments", "daemonsets", "replicasets", "statefulsets"]
verbs: ["*"]
# ----------------------------------------------------
# Networking & Ingress
# (Traefik needs watch on ingresses & ingressclasses)
# ----------------------------------------------------
- apiGroups: ["networking.k8s.io", "extensions"]
resources: ["ingresses", "ingressclasses", "*"]
verbs: ["*"]
# ----------------------------------------------------
# Traefik v1 CRDs (old MicroK8s installs)
# ----------------------------------------------------
- apiGroups: ["traefik.containo.us"]
resources: ["*"]
verbs: ["*"]
# ----------------------------------------------------
# Traefik v2 CRDs (modern)
# ----------------------------------------------------
- apiGroups: ["traefik.io"]
resources:
- ingressroutes
- ingressroutetcps
- ingressrouteudps
- middlewares
- middlewaretcps
- traefikservices
- tlsoptions
- tlsstores
- serverstransports
verbs: ["*"]
# ----------------------------------------------------
# CRDs
# ----------------------------------------------------
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: arc-runner-readonly-binding
name: mealcraft-bootstrap-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mealcraft-bootstrap-role
subjects:
- kind: ServiceAccount
name: default
name: mealcraft-runners-gha-rs-no-permission
namespace: arc-systems
EOF
microk8s kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-real-binding
roleRef:
kind: ClusterRole
name: arc-runner-readonly
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mealcraft-bootstrap-role
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: default
EOF
microk8s kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-rbac-fix
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mealcraft-bootstrap-role
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: default
EOF
echo "=== RBAC Applied Successfully ==="
echo "=== ARC installation + RBAC complete ==="

View file

@ -2,64 +2,10 @@ import Image from "next/image";
export default function Home() {
return (
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
</main>
<div className="flex h-screen flex-col items-center justify-center space-y-6">
<h1 className="text-3xl font-bold text-center">
Impatient with actions, Patient with results
</h1>
</div>
);
}

View file

@ -0,0 +1,17 @@
# Base image
FROM mcr.microsoft.com/devcontainers/typescript-node
# Set working directory
WORKDIR /app
# Copy ONLY the frontend project
COPY ../ .
# Install dependencies and build
RUN npm install && npm run build
# Expose
EXPOSE 3000
# Start
CMD ["npm", "start"]

View file

@ -0,0 +1,26 @@
kind: Deployment
apiVersion: apps/v1
metadata:
namespace: ${NAMESPACE}
name: portfolio-page
labels:
app: portfolio-page
spec:
replicas: 1
selector:
matchLabels:
app: portfolio-page
template:
metadata:
labels:
app: portfolio-page
spec:
containers:
- name: portfolio-page
image: kimjunte/portfolio_page:$GITHUB_REF_SLUG
imagePullPolicy: Always
ports:
- name: portfolioport
containerPort: 3000
imagePullSecrets:
- name: registrypullsecret

View file

@ -0,0 +1,19 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: juntekim-portfolio-page
namespace: ${NAMESPACE}
spec:
entryPoints:
- websecure
routes:
- match: "Host(`${HOSTNAME}`) || Host(`www.${HOSTNAME}`)"
kind: Rule
services:
- name: portfolio-page
port: 80
passHostHeader: false
tls:
certResolver: myresolver
domains:
- main: ${HOSTNAME}

View file

@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: portfolio-page
namespace: ${NAMESPACE}
spec:
ports:
- protocol: TCP
name: portfolioport
port: 80
targetPort: 3000
selector:
app: portfolio-page

View file

@ -1,7 +1,10 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
namespace: default
name: test-auth
spec:
basicAuth:
secret: authsecret

View file

@ -2,6 +2,7 @@ apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: certs-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany

View file

@ -1,18 +1,8 @@
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: default
name: traefik-ingress-controller
---
kind: Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik-deployment
labels:
app: traefik
name: traefik
namespace: default
spec:
replicas: 1
selector:
@ -24,30 +14,52 @@ spec:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
volumes:
- name: acme
persistentVolumeClaim:
claimName: certs-pvc
containers:
- name: traefik
image: traefik:v2.10
image: traefik:v2.11
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
- name: admin
containerPort: 8080
volumeMounts:
- name: acme
mountPath: /acme
args:
- --api.insecure
- --accesslog=True
- --entrypoints.web.Address=:80
- --entrypoints.websecure.Address=:443
- --providers.kubernetescrd
- --api.dashboard
- --serverstransport.insecureskipverify=true
# TLS (HTTPS)
- "--certificatesresolvers.myresolver.acme.dnschallenge=true"
- "--certificatesresolvers.myresolver.acme.httpChallenge=false"
- "--certificatesresolvers.myresolver.acme.tlsChallenge=false"
- "--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53"
- "--certificatesresolvers.myresolver.acme.email=junte.kim@mealcraft.com"
- "--certificatesresolvers.myresolver.acme.storage=/certs/acme.json"
- "--certificatesresolvers.myresolver.acme.httpChallenge.entryPoint=web"
- "--api.dashboard=true"
- "--api.insecure=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
# Redirect HTTP → HTTPS
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--providers.kubernetescrd.allowexternalnameservices=true"
# Providers
- "--providers.kubernetescrd=true"
- "--providers.kubernetescrd.allowCrossNamespace=true"
# TLS + ACME
- "--certificatesresolvers.myresolver.acme.email=junte.kim@mealcraft.com"
- "--certificatesresolvers.myresolver.acme.storage=/acme/acme.json"
- "--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53"
# STAGING (uncomment for first-time)
# - "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
env:
- name: AWS_REGION
valueFrom:
secretKeyRef:
name: aws-secrets
key: AWS_REGION
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
@ -58,24 +70,3 @@ spec:
secretKeyRef:
name: aws-secrets
key: AWS_SECRET_ACCESS_KEY
- name: AWS_REGION
valueFrom:
secretKeyRef:
name: aws-secrets
key: AWS_REGION
ports:
- name: web
containerPort: 80
- name: admin
containerPort: 8080
- name: websecure
containerPort: 443
volumeMounts:
- name: cert-volume
mountPath: /certs
imagePullSecrets:
- name: registrypullsecret
volumes:
- name: cert-volume
persistentVolumeClaim:
claimName: certs-pvc

View file

@ -7,10 +7,11 @@ spec:
entryPoints:
- websecure
routes:
- match: Host(`www.traefik.mealcraft.com`, `traefik.mealcraft.com`) && PathPrefix(`/api`, `/dashboard`)
- match: (Host(`traefik.mealcraft.com`) || Host(`www.traefik.mealcraft.com`)) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
kind: Rule
middlewares:
- name: test-auth
namespace: default
services:
- name: traefik
port: 8080

View file

@ -2,18 +2,18 @@ apiVersion: v1
kind: Service
metadata:
name: traefik
namespace: default
spec:
type: LoadBalancer
ports:
- protocol: TCP
name: web
port: 80
- protocol: TCP
name: websecure
port: 443
- protocol: TCP
name: admin
port: 8080
selector:
app: traefik
ports:
- name: web
port: 80
targetPort: 80
- name: websecure
port: 443
targetPort: 443
- name: admin
port: 8080
targetPort: 8080

View file

@ -19,6 +19,6 @@ spec:
- key: kubernetes.io/hostname
operator: In
values:
- gpd
- mist

View file

@ -7,7 +7,8 @@ spec:
entryPoints:
- websecure
routes:
- match: "Host(`www.whoami.mealcraft.com`, `whoami.mealcraft.com`)"
- match: (Host(`whoami.mealcraft.com`) || Host(`www.whoami.mealcraft.com`))
kind: Rule
services:
- name: whoami

View file

@ -2,6 +2,7 @@ apiVersion: v1
kind: Service
metadata:
name: whoami
namespace: default
spec:
ports: