diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1934a7d --- /dev/null +++ b/.env.example @@ -0,0 +1,35 @@ +# Webhook-based Deployment Configuration +# Copy this to .env and customize for your environment + +# Webhook Security +WEBHOOK_SECRET=your-webhook-secret-here + +# Your Domain Configuration +BASE_DOMAIN=your-domain.com +WEBHOOK_DOMAIN=webhook.your-domain.com +KNATIVE_DOMAIN=your-domain.com + +# Application Domains +DEV_DOMAIN=2048-dev.your-domain.com +STAGING_DOMAIN=2048-staging.your-domain.com +PROD_DOMAIN=2048.your-domain.com + +# Canonical Knative Domains +DEV_CANONICAL_DOMAIN=game-2048-dev.game-2048-dev.dev.your-domain.com +STAGING_CANONICAL_DOMAIN=game-2048-staging.game-2048-staging.staging.your-domain.com +PROD_CANONICAL_DOMAIN=game-2048-prod.game-2048-prod.your-domain.com + +# Paths and Configuration +MANIFESTS_PATH=/home/administrator/k8s-game-2048/manifests +KUBECONFIG_PATH=/etc/rancher/k3s/k3s.yaml + +# Deployment Options +DEPLOY_INGRESS=true +WEBHOOK_REPLICAS=1 + +# GitHub Repository (for container registry) +GITHUB_REPOSITORY=your-username/k8s-game-2048 +CONTAINER_REGISTRY=ghcr.io + +# Email for SSL certificates +CERT_EMAIL=your-email@your-domain.com diff --git a/.gitignore b/.gitignore index 36fdcba..d308d05 100644 --- a/.gitignore +++ b/.gitignore @@ -28,9 +28,19 @@ Thumbs.db # Environment files .env .env.local -.env.development.local -.env.test.local -.env.production.local +.env.development +.env.staging +.env.production +webhook_secret.txt + +# Personal deployment files +manifests/personal/ +config/personal/ + +# Backup files with potentially sensitive data +*.backup +*.bak +backup-* # Logs logs diff --git a/Dockerfile.webhook b/Dockerfile.webhook new file mode 100644 index 0000000..32ff12c --- /dev/null +++ b/Dockerfile.webhook @@ -0,0 +1,45 @@ +FROM python:3.11-slim + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + curl \ + wget \ + gnupg2 \ + software-properties-common \ + apt-transport-https \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Install kubectl +RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \ + && chmod +x kubectl \ + && mv kubectl /usr/local/bin/ + +# Install Docker CLI +RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \ + && apt-get update \ + && apt-get install -y docker-ce-cli \ + && rm -rf /var/lib/apt/lists/* + +# Install Python dependencies +RUN pip install --no-cache-dir flask requests + +# Create app directory +WORKDIR /app + +# Copy webhook handler script +COPY webhook-handler.py /app/ + +# Create manifests directory +RUN mkdir -p /app/manifests + +# Expose port +EXPOSE 8080 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \ + CMD curl -f http://localhost:8080/health || exit 1 + +# Run the application +CMD ["python", "webhook-handler.py"] diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md new file mode 100644 index 0000000..b93d4eb --- /dev/null +++ b/docs/ENVIRONMENT.md @@ -0,0 +1,103 @@ +# Environment Configuration + +This repository uses environment variables to keep personal information (domains, emails, repository names) out of the public codebase. + +## Quick Setup + +1. **Copy the environment template:** + ```bash + cp .env.example .env + ``` + +2. **Edit `.env` with your information:** + ```bash + nano .env + ``` + +3. **Update these key values:** + - `BASE_DOMAIN` - Your domain (e.g., `example.com`) + - `GITHUB_REPOSITORY` - Your GitHub repo (e.g., `username/k8s-game-2048`) + - `CERT_EMAIL` - Your email for SSL certificates + - `WEBHOOK_SECRET` - Generate with: `openssl rand -hex 32` + +## Environment Variables + +### Required Variables + +| Variable | Description | Example | +|----------|-------------|---------| +| `BASE_DOMAIN` | Your base domain | `example.com` | +| `WEBHOOK_DOMAIN` | Webhook endpoint domain | `webhook.example.com` | +| `GITHUB_REPOSITORY` | Your GitHub repository | `username/k8s-game-2048` | +| `CERT_EMAIL` | Email for SSL certificates | `admin@example.com` | +| `WEBHOOK_SECRET` | Secret for webhook security | Generated 64-char hex | + +### Auto-generated Domains + +The following domains are automatically generated from `BASE_DOMAIN`: + +- **Development**: `2048-dev.{BASE_DOMAIN}` +- **Staging**: `2048-staging.{BASE_DOMAIN}` +- **Production**: `2048.{BASE_DOMAIN}` + +### Canonical Knative Domains + +- **Dev**: `game-2048-dev.game-2048-dev.dev.{BASE_DOMAIN}` +- **Staging**: `game-2048-staging.game-2048-staging.staging.{BASE_DOMAIN}` +- **Production**: `game-2048-prod.game-2048-prod.{BASE_DOMAIN}` + +## Security + +- **Never commit `.env`** - It's in `.gitignore` for security +- **Use strong webhook secrets** - Generate with `openssl rand -hex 32` +- **Rotate secrets regularly** - Update webhook secret periodically + +## Deployment Scripts + +### Setup Webhook Handler +```bash +./scripts/setup-webhook-deployment.sh +``` + +### Prepare Environment-Specific Manifests +```bash +./scripts/prepare-deployment.sh +``` + +### Sanitize Repository (for public sharing) +```bash +./scripts/sanitize-repo.sh +``` + +## GitHub Secrets + +After setting up your `.env`, configure these GitHub repository secrets: + +1. Go to your repository Settings โ†’ Secrets and variables โ†’ Actions +2. Add these secrets from your `.env` file: + +``` +WEBHOOK_SECRET= +DEV_WEBHOOK_URL=https:///webhook/deploy +STAGING_WEBHOOK_URL=https:///webhook/deploy +PROD_WEBHOOK_URL=https:///webhook/deploy +KNATIVE_DOMAIN= +``` + +## Template System + +The repository uses a template system to keep personal information secure: + +- **`manifests/templates/`** - Sanitized templates with placeholders +- **`manifests/`** - Your actual deployment manifests (gitignored) +- **`.env.example`** - Template for environment configuration + +## Development Workflow + +1. Clone repository +2. Copy `.env.example` to `.env` +3. Update `.env` with your configuration +4. Run `./scripts/prepare-deployment.sh` +5. Deploy with `./scripts/setup-webhook-deployment.sh` + +This ensures your personal information stays private while keeping the codebase shareable. diff --git a/manifests/webhook/webhook-handler.yaml b/manifests/webhook/webhook-handler.yaml index 275e8be..6e28241 100644 --- a/manifests/webhook/webhook-handler.yaml +++ b/manifests/webhook/webhook-handler.yaml @@ -30,7 +30,7 @@ metadata: labels: app: webhook-handler spec: - replicas: 2 # For high availability + replicas: 1 # Start with 1 for testing selector: matchLabels: app: webhook-handler @@ -40,6 +40,37 @@ spec: app: webhook-handler spec: serviceAccountName: webhook-handler + initContainers: + - name: setup + image: python:3.11-slim + command: + - /bin/bash + - -c + - | + set -e + echo "๐Ÿš€ Setting up webhook handler dependencies..." + + # Update and install basic tools + apt-get update + apt-get install -y curl wget + + # Install kubectl + echo "๐Ÿ“ฆ Installing kubectl..." + curl -LO "https://dl.k8s.io/release/v1.28.0/bin/linux/amd64/kubectl" + chmod +x kubectl + cp kubectl /shared/kubectl + + # Install Python dependencies + echo "๐Ÿ“ฆ Installing Python dependencies..." + pip install flask requests + + # Copy requirements to shared volume + pip freeze > /shared/requirements.txt + + echo "โœ… Setup completed!" + volumeMounts: + - name: shared-tools + mountPath: /shared containers: - name: webhook-handler image: python:3.11-slim @@ -57,16 +88,40 @@ spec: configMapKeyRef: name: webhook-handler-config key: MANIFESTS_PATH + - name: PATH + value: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/shared" command: - /bin/bash - -c - | - apt-get update && apt-get install -y curl - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x kubectl && mv kubectl /usr/local/bin/ - curl -fsSL https://get.docker.com | sh - pip install flask - python /app/webhook-handler.py + set -e + echo "๐ŸŽฏ Starting webhook handler..." + + # Install Python dependencies from init container + if [ -f /shared/requirements.txt ]; then + pip install -r /shared/requirements.txt + else + pip install flask requests + fi + + # Make kubectl available + cp /shared/kubectl /usr/local/bin/ 2>/dev/null || echo "kubectl already available" + chmod +x /usr/local/bin/kubectl 2>/dev/null || true + + # Set up kubeconfig + mkdir -p /root/.kube + cp /etc/kubeconfig/config /root/.kube/config + chmod 600 /root/.kube/config + + # Test connectivity + echo "๐Ÿ” Testing Kubernetes connectivity..." + kubectl version --client || echo "โš ๏ธ kubectl client test failed" + kubectl cluster-info || echo "โš ๏ธ cluster connectivity test failed, but continuing..." + + # Start the webhook handler + echo "๐Ÿš€ Starting Flask application..." + cd /app + exec python webhook-handler.py volumeMounts: - name: webhook-handler-script mountPath: /app/webhook-handler.py @@ -76,20 +131,25 @@ spec: - name: docker-socket mountPath: /var/run/docker.sock - name: kubeconfig - mountPath: /root/.kube/config - subPath: config + mountPath: /etc/kubeconfig + - name: shared-tools + mountPath: /shared livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 3 + readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 - readinessProbe: - httpGet: - path: /health - port: 8080 - initialDelaySeconds: 5 - periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 3 resources: requests: memory: "256Mi" @@ -104,16 +164,18 @@ spec: defaultMode: 0755 - name: manifests hostPath: - path: /home/administrator/k8s-game-2048/manifests # Update this path + path: /home/administrator/k8s-game-2048/manifests type: Directory - name: docker-socket hostPath: path: /var/run/docker.sock type: Socket - name: kubeconfig - hostPath: - path: /etc/rancher/k3s/k3s.yaml # Default k3s kubeconfig location - type: File + secret: + secretName: webhook-kubeconfig + defaultMode: 0600 + - name: shared-tools + emptyDir: {} --- apiVersion: v1 kind: Service diff --git a/manifests/webhook/webhook-ingress.yaml b/manifests/webhook/webhook-ingress.yaml index ddd3318..17249bf 100644 --- a/manifests/webhook/webhook-ingress.yaml +++ b/manifests/webhook/webhook-ingress.yaml @@ -27,10 +27,10 @@ metadata: spec: tls: - hosts: - - webhook.yourdomain.com # Replace with your actual domain + - webhook.wa.darknex.us secretName: webhook-tls rules: - - host: webhook.yourdomain.com # Replace with your actual domain + - host: webhook.wa.darknex.us http: paths: - path: / diff --git a/scripts/prepare-deployment.sh b/scripts/prepare-deployment.sh new file mode 100755 index 0000000..e52f36d --- /dev/null +++ b/scripts/prepare-deployment.sh @@ -0,0 +1,77 @@ +#!/bin/bash +set -e + +# Environment-aware deployment script +echo "๐Ÿš€ Environment-aware deployment script..." + +# Load environment variables +if [ -f ".env" ]; then + echo "๐Ÿ“‹ Loading configuration from .env file..." + export $(grep -v '^#' .env | xargs) +else + echo "โŒ No .env file found! Please create one from .env.example" + exit 1 +fi + +# Validate required environment variables +required_vars=( + "BASE_DOMAIN" + "WEBHOOK_DOMAIN" + "KNATIVE_DOMAIN" + "GITHUB_REPOSITORY" + "CONTAINER_REGISTRY" +) + +for var in "${required_vars[@]}"; do + if [ -z "${!var}" ]; then + echo "โŒ Required environment variable $var is not set!" + exit 1 + fi +done + +echo "โœ… Environment validation passed" +echo " Base Domain: $BASE_DOMAIN" +echo " Webhook Domain: $WEBHOOK_DOMAIN" +echo " GitHub Repository: $GITHUB_REPOSITORY" + +# Function to substitute environment variables in manifests +substitute_env_vars() { + local source_dir="$1" + local target_dir="$2" + + echo "๐Ÿ“ Substituting environment variables: $source_dir -> $target_dir" + + # Create target directory + mkdir -p "$target_dir" + + # Process all YAML files + for file in "$source_dir"/*.yml "$source_dir"/*.yaml; do + if [ -f "$file" ]; then + local basename=$(basename "$file") + local target_file="$target_dir/$basename" + + # Substitute environment variables + envsubst < "$file" > "$target_file" + echo " โœ… $basename" + fi + done +} + +# Create deployment-ready manifests from templates +if [ -d "manifests/templates" ]; then + echo "๐Ÿ”„ Creating deployment manifests from templates..." + + substitute_env_vars "manifests/templates/dev" "manifests/dev" + substitute_env_vars "manifests/templates/staging" "manifests/staging" + substitute_env_vars "manifests/templates/prod" "manifests/prod" + substitute_env_vars "manifests/templates" "manifests" + + echo "โœ… Deployment manifests ready" +else + echo "โš ๏ธ No templates directory found, using existing manifests" +fi + +echo "" +echo "๐ŸŽฏ Ready for deployment with your environment configuration!" +echo " Run: kubectl apply -f manifests/dev/" +echo " Or use: ./scripts/setup-webhook-deployment.sh" diff --git a/scripts/sanitize-repo.sh b/scripts/sanitize-repo.sh new file mode 100755 index 0000000..62bcbeb --- /dev/null +++ b/scripts/sanitize-repo.sh @@ -0,0 +1,107 @@ +#!/bin/bash +set -e + +# Script to sanitize repository by replacing hardcoded values with placeholders +echo "๐Ÿงน Sanitizing repository - removing hardcoded personal information..." + +# Load environment variables to know what to replace +if [ -f ".env" ]; then + source .env +else + echo "โŒ No .env file found!" + exit 1 +fi + +# Function to replace in file if it exists +replace_in_file() { + local file="$1" + local search="$2" + local replace="$3" + + if [ -f "$file" ]; then + sed -i "s|${search}|${replace}|g" "$file" + echo "โœ… Updated $file" + fi +} + +# Replace domain names in all relevant files +echo "๐Ÿ“ Replacing domain names with placeholders..." + +# README.md +replace_in_file "README.md" "$DEV_DOMAIN" "2048-dev.example.com" +replace_in_file "README.md" "$STAGING_DOMAIN" "2048-staging.example.com" +replace_in_file "README.md" "$PROD_DOMAIN" "2048.example.com" +replace_in_file "README.md" "$GITHUB_REPOSITORY" "your-username/k8s-game-2048" + +# GitHub workflows - replace all hardcoded domains +for workflow in .github/workflows/*.yml; do + if [ -f "$workflow" ]; then + replace_in_file "$workflow" "$DEV_CANONICAL_DOMAIN" "game-2048-dev.game-2048-dev.dev.example.com" + replace_in_file "$workflow" "$STAGING_CANONICAL_DOMAIN" "game-2048-staging.game-2048-staging.staging.example.com" + replace_in_file "$workflow" "$PROD_CANONICAL_DOMAIN" "game-2048-prod.game-2048-prod.example.com" + replace_in_file "$workflow" "$DEV_DOMAIN" "2048-dev.example.com" + replace_in_file "$workflow" "$STAGING_DOMAIN" "2048-staging.example.com" + replace_in_file "$workflow" "$PROD_DOMAIN" "2048.example.com" + replace_in_file "$workflow" "$GITHUB_REPOSITORY" "your-username/k8s-game-2048" + fi +done + +# Scripts +for script in scripts/*.sh; do + if [ -f "$script" ]; then + replace_in_file "$script" "$DEV_DOMAIN" "2048-dev.example.com" + replace_in_file "$script" "$STAGING_DOMAIN" "2048-staging.example.com" + replace_in_file "$script" "$PROD_DOMAIN" "2048.example.com" + replace_in_file "$script" "$DEV_CANONICAL_DOMAIN" "game-2048-dev.game-2048-dev.dev.example.com" + replace_in_file "$script" "$STAGING_CANONICAL_DOMAIN" "game-2048-staging.game-2048-staging.staging.example.com" + replace_in_file "$script" "$PROD_CANONICAL_DOMAIN" "game-2048-prod.game-2048-prod.example.com" + replace_in_file "$script" "$KNATIVE_DOMAIN" "example.com" + replace_in_file "$script" "$WEBHOOK_DOMAIN" "webhook.example.com" + replace_in_file "$script" "$GITHUB_REPOSITORY" "your-username/k8s-game-2048" + fi +done + +# Manifests - create template versions +echo "๐Ÿ“‚ Creating template manifests..." +mkdir -p manifests/templates + +# Copy current manifests to templates and sanitize +cp -r manifests/dev manifests/templates/ +cp -r manifests/staging manifests/templates/ +cp -r manifests/prod manifests/templates/ +cp manifests/*.yaml manifests/templates/ 2>/dev/null || true + +# Sanitize template manifests +for file in manifests/templates/**/*.yml manifests/templates/**/*.yaml manifests/templates/*.yaml; do + if [ -f "$file" ]; then + replace_in_file "$file" "$DEV_DOMAIN" "2048-dev.example.com" + replace_in_file "$file" "$STAGING_DOMAIN" "2048-staging.example.com" + replace_in_file "$file" "$PROD_DOMAIN" "2048.example.com" + replace_in_file "$file" "$DEV_CANONICAL_DOMAIN" "game-2048-dev.game-2048-dev.dev.example.com" + replace_in_file "$file" "$STAGING_CANONICAL_DOMAIN" "game-2048-staging.game-2048-staging.staging.example.com" + replace_in_file "$file" "$PROD_CANONICAL_DOMAIN" "game-2048-prod.game-2048-prod.example.com" + replace_in_file "$file" "dev.$KNATIVE_DOMAIN" "dev.example.com" + replace_in_file "$file" "staging.$KNATIVE_DOMAIN" "staging.example.com" + replace_in_file "$file" "$KNATIVE_DOMAIN" "example.com" + replace_in_file "$file" "$GITHUB_REPOSITORY" "your-username/k8s-game-2048" + replace_in_file "$file" "$CERT_EMAIL" "admin@example.com" + fi +done + +# Package.json +replace_in_file "package.json" "$GITHUB_REPOSITORY" "your-username/k8s-game-2048" + +# Documentation +replace_in_file "docs/WEBHOOK_DEPLOYMENT.md" "$KNATIVE_DOMAIN" "example.com" + +echo "" +echo "โœ… Repository sanitization completed!" +echo "" +echo "๐Ÿ“‹ Summary of changes:" +echo "- Replaced all domain references with example.com" +echo "- Replaced GitHub repository with placeholder" +echo "- Created template manifests in manifests/templates/" +echo "- Personal information is now only in .env file (which is .gitignored)" +echo "" +echo "โš ๏ธ Note: Current manifests still contain your actual domains for deployment" +echo " Template manifests are sanitized for public repository" diff --git a/scripts/setup-webhook-deployment.sh b/scripts/setup-webhook-deployment.sh index d3393a3..c379315 100755 --- a/scripts/setup-webhook-deployment.sh +++ b/scripts/setup-webhook-deployment.sh @@ -4,15 +4,30 @@ set -e # Webhook-based Deployment Setup Script for k8s-game-2048 echo "๐Ÿš€ Setting up webhook-based deployment for k8s-game-2048..." -# Configuration +# Load configuration from .env file +if [ -f ".env" ]; then + echo "๐Ÿ“‹ Loading configuration from .env file..." + export $(grep -v '^#' .env | xargs) +else + echo "โš ๏ธ No .env file found, using defaults" +fi + +# Configuration with fallbacks WEBHOOK_SECRET="${WEBHOOK_SECRET:-$(openssl rand -hex 32)}" MANIFESTS_PATH="${MANIFESTS_PATH:-/home/administrator/k8s-game-2048/manifests}" -WEBHOOK_DOMAIN="${WEBHOOK_DOMAIN:-webhook.$(hostname -f)}" +WEBHOOK_DOMAIN="${WEBHOOK_DOMAIN:-webhook.wa.darknex.us}" +KNATIVE_DOMAIN="${KNATIVE_DOMAIN:-wa.darknex.us}" +KUBECONFIG_PATH="${KUBECONFIG_PATH:-/etc/rancher/k3s/k3s.yaml}" +DEPLOY_INGRESS="${DEPLOY_INGRESS:-true}" +WEBHOOK_REPLICAS="${WEBHOOK_REPLICAS:-1}" echo "๐Ÿ“‹ Configuration:" echo " Webhook Secret: ${WEBHOOK_SECRET:0:8}..." echo " Manifests Path: $MANIFESTS_PATH" echo " Webhook Domain: $WEBHOOK_DOMAIN" +echo " Knative Domain: $KNATIVE_DOMAIN" +echo " Deploy Ingress: $DEPLOY_INGRESS" +echo " Replicas: $WEBHOOK_REPLICAS" # Step 1: Create webhook system namespace echo "" @@ -26,6 +41,19 @@ kubectl create secret generic webhook-secret \ -n webhook-system \ --dry-run=client -o yaml | kubectl apply -f - +# Step 2.5: Create kubeconfig secret for webhook handler +echo "๐Ÿ”‘ Creating kubeconfig secret..." +if [ -f "$KUBECONFIG_PATH" ]; then + kubectl create secret generic webhook-kubeconfig \ + --from-file=config="$KUBECONFIG_PATH" \ + -n webhook-system \ + --dry-run=client -o yaml | kubectl apply -f - +else + echo "โš ๏ธ Kubeconfig not found at $KUBECONFIG_PATH" + echo "Please create the webhook-kubeconfig secret manually:" + echo "kubectl create secret generic webhook-kubeconfig --from-file=config=~/.kube/config -n webhook-system" +fi + # Step 3: Update webhook handler manifests with correct paths echo "๐Ÿ”ง Updating webhook handler manifests..." sed -i "s|/home/administrator/k8s-game-2048/manifests|$MANIFESTS_PATH|g" manifests/webhook/webhook-handler.yaml @@ -89,7 +117,7 @@ echo " - WEBHOOK_SECRET: $WEBHOOK_SECRET" echo " - DEV_WEBHOOK_URL: https://$WEBHOOK_DOMAIN/webhook/deploy" echo " - STAGING_WEBHOOK_URL: https://$WEBHOOK_DOMAIN/webhook/deploy" echo " - PROD_WEBHOOK_URL: https://$WEBHOOK_DOMAIN/webhook/deploy" -echo " - KNATIVE_DOMAIN: your-knative-domain.com" +echo " - KNATIVE_DOMAIN: $KNATIVE_DOMAIN" echo "" echo "2. Expose webhook handler externally:" if [ "$DEPLOY_INGRESS" != "true" ]; then @@ -121,5 +149,5 @@ echo "WEBHOOK_SECRET | $WEBHOOK_SECRET" echo "DEV_WEBHOOK_URL | https://$WEBHOOK_DOMAIN/webhook/deploy" echo "STAGING_WEBHOOK_URL | https://$WEBHOOK_DOMAIN/webhook/deploy" echo "PROD_WEBHOOK_URL | https://$WEBHOOK_DOMAIN/webhook/deploy" -echo "KNATIVE_DOMAIN | your-knative-domain.com" +echo "KNATIVE_DOMAIN | $KNATIVE_DOMAIN" echo "===============================|"