docs: Update roadmap and implementation plan to mark nginx-nodeport as completed

This commit is contained in:
mik-tf
2025-11-07 12:49:11 -05:00
parent a8f9f9d7cc
commit 9cd3a3cad8
7 changed files with 121 additions and 560 deletions

View File

@@ -1,216 +0,0 @@
# nginx-nodeport - Mycelium Cloud NodePort Website Example
Complete, production-ready example for deploying a secure, globally accessible website on Mycelium Cloud using **NodePort** services.
## 🚀 Quick Start (One Command!)
**Start here if you want EVERYTHING done automatically:**
```bash
cd myceliumcloud-examples/examples/nginx-nodeport
./deploy-and-test.sh
```
That's it! This script will:
1. ✅ Deploy all resources (ConfigMaps, Deployment, Service)
2. ✅ Wait for pods to be ready
3. ✅ Verify service configuration
4. ✅ Update website content with current node information
5. ✅ Apply changes
6. ✅ Run comprehensive tests
7. ✅ Show you the access URL
**Output example:**
```
🎉 Deploy and Test Complete!
==================================
🌐 Access Information:
• URL: http://[552:5984:2d97:72dc:ff0f:39ef:6ec:a48c]:30091
• Node: kc22haven612worker1
To access from a machine with Mycelium installed:
curl -6 "http://[552:5984:2d97:72dc:ff0f:39ef:6ec:a48c]:30091/"
Or open in browser:
http://[552:5984:2d97:72dc:ff0f:39ef:6ec:a48c]:30091
```
---
## 📚 Available Scripts
### 1. `deploy-and-test.sh` - **RECOMMENDED** ⭐
**The ONE script to do everything from scratch**
```bash
./deploy-and-test.sh
```
Does everything: deploy, test, configure, and show results.
### 2. `update-content.sh` - Content Update
**Updates website content with current cluster state**
```bash
./update-content.sh
kubectl rollout restart deployment/nginx-nodeport
```
Updates the ConfigMap and restarts pods to apply changes.
---
## 🔧 Manual Deployment (If You Prefer)
If you want to do it step-by-step yourself:
```bash
# 1. Deploy resources
kubectl apply -f nginx-nodeport-configmaps.yaml
kubectl apply -f nginx-nodeport-deployment.yaml
kubectl apply -f nginx-nodeport-service.yaml
# 2. Wait for ready
kubectl wait --for=condition=ready pod -l app=nginx-nodeport --timeout=60s
# 3. Update content
./update-content.sh
kubectl rollout restart deployment/nginx-nodeport
---
## 🎯 What This Example Teaches
- **NodePort Services** - Standard Kubernetes service exposure
- **IPv6 Support** - Critical dual-stack configuration for Mycelium
- **Pod Isolation** - Security without hostNetwork
- **externalTrafficPolicy: Local** - Preserves source IP
- **Mycelium Integration** - IPv6 address discovery and access
---
## 📊 Architecture
```
User (with Mycelium)
http://[worker-node-mycelium-ipv6]:30091
kube-proxy (dual-stack enabled)
Kubernetes Service (IPv4 + IPv6)
Pod (container port 8080)
nginx → HTML
```
**Key Points:**
- Service type: **NodePort** (not LoadBalancer)
- IP families: **Dual-stack (IPv4 + IPv6)** ⭐ Critical
- Pod network: **Isolated** (no hostNetwork)
- Traffic policy: **Local** (preserves source IP)
- Port: **30091** (NodePort)
---
## 🌐 Access URLs
**Current deployment (1 pod replica):**
- **Only accessible on the node where pod is running**
- Example: `http://[552:5984:2d97:72dc:ff0f:39ef:6ec:a48c]:30091`
**To make accessible on all nodes:**
```bash
kubectl scale deployment nginx-nodeport --replicas=3
./update-content.sh
```
---
## 📁 Files in This Directory
### Configuration
- `nginx-nodeport-deployment.yaml` - Pod configuration
- `nginx-nodeport-service.yaml` - NodePort service (dual-stack)
- `nginx-nodeport-configmaps.yaml` - HTML content + nginx config
### Scripts
- `deploy-and-test.sh` - ⭐ **Main script** (deploy + test)
- `test-nodeport-ipv6.sh` - Testing and validation
- `update-content.sh` - Content updates
- `debug-nodeport.sh` - Diagnostics
### Documentation
- `nginx-nodeport.md` - Complete guide
- `IPV6_FIX.md` - Critical dual-stack configuration
- `TROUBLESHOOTING.md` - Common issues & solutions
- `compare-approaches.md` - Security comparison
- `FINAL_STATUS.md` - Complete implementation status
---
## ✅ Success Indicators
**When working, you'll see:**
- ✅ Service type: `NodePort`
- ✅ NodePort: `30091`
- ✅ IP families: `["IPv4","IPv6"]`
- ✅ Pod status: `Running`
- ✅ Test output: `✅ External Mycelium IPv6 connectivity is working!`
---
## 🚨 Prerequisites
1. **kubectl** installed and configured
2. **Mycelium Cloud cluster** with at least 1 worker node
3. **Mycelium installed** on your local machine (for testing)
4. **IPv6 connectivity** (Mycelium provides this)
---
## 🆘 Getting Help
**Common Issues:**
1. **"Failed to connect" error**
- Check if Mycelium is running on your local machine
- Verify IPv6 connectivity: `ping -6 [ipv6-address]`
2. **"External IPv6 connectivity test failed"**
- This is normal if you don't have Mycelium on your machine
- The service is still working from within the cluster
3. **Service only accessible on one node**
- This is CORRECT with `externalTrafficPolicy: Local` and 1 pod replica
- To make accessible on all nodes, scale to 3 replicas
**Troubleshooting:**
- Run: `./debug-nodeport.sh`
- Check logs: `kubectl logs -l app=nginx-nodeport --tail=50`
- Check service: `kubectl describe svc nginx-nodeport-service`
---
## 🔄 Next Steps
1. **Test scaling:**
```bash
kubectl scale deployment nginx-nodeport --replicas=3
```
2. **Try other nginx variants:**
- [`../nginx-mycelium/`](../nginx-mycelium/) - hostNetwork approach
- [`../nginx-static/`](../nginx-static/) - Simple static site
- LoadBalancer and Ingress variants (coming soon)
## 🎉 Success!
Once deployed and tested, you'll have a **fully functional website accessible via Mycelium IPv6** with:
- ✅ Production-ready security (pod isolation)
- ✅ Standard Kubernetes patterns
- ✅ Dual-stack IPv4/IPv6 support
- ✅ Comprehensive testing and monitoring
**Happy deploying! 🚀**

View File

@@ -0,0 +1,71 @@
#!/bin/bash
# Diagnostic script to debug NodePort networking issues
# This helps identify why some URLs work and others don't
echo "🔍 NodePort Networking Diagnostics"
echo "=================================="
echo ""
# Check pod locations
echo "📍 Current Pod Locations:"
kubectl get pods -l app=nginx-nodeport -o wide
echo ""
# Check node information
echo "🌐 Node Information:"
kubectl get nodes -o wide
echo ""
# Check service status
echo "🔧 Service Status:"
kubectl get svc nginx-nodeport-service
echo ""
# Test connectivity to each node
echo "🧪 Connectivity Tests:"
echo ""
PODS=$(kubectl get pods -l app=nginx-nodeport -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.nodeName}{"\n"}{end}')
while IFS=$'\t' read -r pod_name node_name; do
echo "Testing pod: $pod_name on node: $node_name"
# Get IPv6 for this specific node
IPV6=$(kubectl get node "$node_name" -o jsonpath='{range .status.addresses[?(@.type=="InternalIP")]}{.address}{"\n"}{end}' | grep -E '^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$' | head -1)
if [ ! -z "$IPV6" ]; then
echo " Node IPv6: $IPV6"
echo " Testing connectivity: curl -6 --connect-timeout 5 http://[$IPV6]:30091/health"
# Test HTTP connectivity
if curl -6 --connect-timeout 5 -s "http://[$IPV6]:30091/health" >/dev/null 2>&1; then
echo " ✅ HTTP connectivity: WORKING"
else
echo " ❌ HTTP connectivity: FAILED"
fi
# Test ICMP connectivity
echo " Testing ping: ping -6 -c 2 -W 3 $IPV6"
if ping -6 -c 2 -W 3 "$IPV6" >/dev/null 2>&1; then
echo " ✅ ICMP connectivity: WORKING"
else
echo " ❌ ICMP connectivity: FAILED"
fi
else
echo " ❌ No IPv6 found for node: $node_name"
fi
echo ""
done <<< "$PODS"
echo "📊 Summary:"
echo "This shows which nodes actually have pods and whether they're accessible"
echo ""
echo "If some URLs work and others don't, it means:"
echo " ✅ Working URLs: Nodes with good Mycelium connectivity"
echo " ❌ Failed URLs: Nodes with poor Mycelium connectivity or network issues"
echo ""
echo "To fix connectivity issues:"
echo " 1. Check Mycelium status on affected nodes"
echo " 2. Restart Mycelium on nodes with failed connectivity"
echo " 3. Scale to replicas only on nodes with good connectivity"

View File

@@ -1,312 +0,0 @@
#!/bin/bash
# Dynamic Mycelium IPv6 Address Discovery Script for Multi-Replica NodePort
# This script fetches Mycelium IPv6 addresses from ALL nodes where pods are running
# Works correctly with externalTrafficPolicy: Local and multiple replicas
set -e
echo "🔍 Discovering Mycelium IPv6 addresses for ALL pod nodes..."
# Get ALL nginx-nodeport pods
POD_COUNT=$(kubectl get pods -l app=nginx-nodeport --no-headers | wc -l)
echo "Found $POD_COUNT pods running"
if [ "$POD_COUNT" -eq 0 ]; then
echo "❌ No nginx-nodeport pod found!"
echo "Please deploy the nginx-nodeport example first:"
echo " kubectl apply -f nginx-nodeport-deployment.yaml"
exit 1
fi
# Collect all node information
declare -A NODE_IPV6_MAP
declare -a NODES_WITH_PODS
declare -a IPV6_ADDRESSES
echo "Collecting node information for all pods..."
# Read pod data into array first to avoid subshell issues
mapfile -t POD_DATA < <(kubectl get pods -l app=nginx-nodeport -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.nodeName}{"\n"}{end}')
for line in "${POD_DATA[@]}"; do
IFS=$'\t' read -r pod_name node_name <<< "$line"
if [ ! -z "$node_name" ] && [ "${NODE_IPV6_MAP[$node_name]+isset}" = "" ]; then
echo "Pod $pod_name is on node $node_name"
# Get IPv6 address for this node
IPV6=$(kubectl get node "$node_name" -o jsonpath='{range .status.addresses[?(@.type=="InternalIP")]}{.address}{"\n"}{end}' | grep -E '^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$' | head -1)
if [ ! -z "$IPV6" ]; then
NODE_IPV6_MAP[$node_name]=$IPV6
NODES_WITH_PODS+=("$node_name")
IPV6_ADDRESSES+=("$IPV6")
echo " ✅ Node $node_name has IPv6: $IPV6"
else
echo " ❌ No IPv6 found for node $node_name"
fi
fi
done
# Build the IPv6 addresses string
IPV6_LIST=""
FIRST=true
for ipv6 in "${IPV6_ADDRESSES[@]}"; do
if [ "$FIRST" = true ]; then
IPV6_LIST="$ipv6"
FIRST=false
else
IPV6_LIST="$IPV6_LIST $ipv6"
fi
done
if [ ${#IPV6_ADDRESSES[@]} -eq 0 ]; then
echo "❌ No IPv6 addresses found for any pod nodes!"
exit 1
fi
echo "✅ Found ${#IPV6_ADDRESSES[@]} accessible nodes with pods:"
for i in "${!NODES_WITH_PODS[@]}"; do
echo " ${NODES_WITH_PODS[$i]}: ${IPV6_ADDRESSES[$i]}"
done
# Generate HTML content with all accessible addresses
cat > /tmp/index.html << 'HTML_EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mycelium Cloud - Nginx NodePort Website</title>
<meta http-equiv="refresh" content="30">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
text-align: center;
max-width: 900px;
padding: 2rem;
background: rgba(255, 255, 255, 0.1);
border-radius: 20px;
backdrop-filter: blur(10px);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
}
h1 {
font-size: 3rem;
margin-bottom: 1rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.subtitle {
font-size: 1.2rem;
margin-bottom: 2rem;
opacity: 0.9;
}
.ipv6-info {
background: rgba(255, 255, 255, 0.1);
padding: 1rem;
border-radius: 10px;
margin: 1rem 0;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
}
.status {
display: inline-block;
padding: 0.5rem 1rem;
background: #4CAF50;
border-radius: 25px;
font-weight: bold;
margin: 0.5rem;
}
.status.nodeport {
background: #2196F3;
}
.timestamp {
font-size: 0.8rem;
opacity: 0.7;
margin-top: 1rem;
}
.features {
text-align: left;
margin: 2rem 0;
}
.feature {
margin: 0.5rem 0;
padding: 0.5rem;
background: rgba(255, 255, 255, 0.1);
border-radius: 5px;
}
.security-badge {
background: #FF9800;
color: white;
padding: 0.5rem 1rem;
border-radius: 15px;
font-weight: bold;
margin: 1rem;
display: inline-block;
}
.urls {
background: rgba(255, 255, 255, 0.15);
padding: 1.5rem;
border-radius: 10px;
margin: 1.5rem 0;
text-align: left;
}
.urls h3 {
margin-top: 0;
color: #FFD700;
}
.urls ul {
list-style: none;
padding: 0;
}
.urls li {
margin: 1rem 0;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
background: rgba(255, 255, 255, 0.1);
padding: 0.8rem;
border-radius: 6px;
}
.urls code {
background: rgba(0, 0, 0, 0.3);
padding: 0.3rem 0.6rem;
border-radius: 4px;
display: inline-block;
}
.working {
color: #4CAF50;
font-weight: bold;
}
.node-info {
font-size: 0.8rem;
opacity: 0.8;
margin-top: 0.5rem;
}
</style>
<script>
function updateTimestamp() {
const now = new Date();
document.getElementById('timestamp').textContent =
'Last updated: ' + now.toLocaleString();
}
function getIPv6Address() {
// Extract IPv6 from the current connection
const ipv6Pattern = /\[([0-9a-f:]+)\]/;
const match = window.location.href.match(ipv6Pattern);
if (match) {
document.getElementById('current-ipv6').textContent = match[1];
} else {
document.getElementById('current-ipv6').textContent = 'Not accessed via IPv6';
}
}
window.onload = function() {
updateTimestamp();
getIPv6Address();
setInterval(updateTimestamp, 1000);
};
</script>
</head>
<body>
<div class="container">
<h1>🌐 Mycelium Cloud</h1>
<div class="subtitle">
Secure NodePort Website Hosting with IPv6!
</div>
<div class="status nodeport">
✅ NODEPORT SECURE
</div>
<div class="security-badge">
🔒 ENHANCED SECURITY
</div>
<div class="ipv6-info">
<strong>Connected via IPv6:</strong><br>
<span id="current-ipv6">Loading...</span>
</div>
<div class="urls">
<h3>🌐 Access URLs (NodePort: 30091)</h3>
<p><strong>Your website is accessible via these Mycelium worker node IPv6 addresses:</strong></p>
<ul>
HTML_EOF
# Add all accessible IPv6 addresses to the HTML
for i in "${!IPV6_ADDRESSES[@]}"; do
ipv6="${IPV6_ADDRESSES[$i]}"
node="${NODES_WITH_PODS[$i]}"
echo " <li><code>http://[$ipv6]:30091</code> <span class=\"working\">✅ WORKING</span><div class=\"node-info\">Node: $node</div></li>" >> /tmp/index.html
done
cat >> /tmp/index.html << 'HTML_EOF'
</ul>
<div style="background: rgba(76, 175, 80, 0.2); padding: 1rem; border-radius: 8px; margin: 1rem 0; border-left: 4px solid #4CAF50;">
<strong>✅ Success:</strong> All <code>REPLICA_COUNT</code> replicas are accessible with <code>externalTrafficPolicy: Local</code><br>
Service is available on all <code>REPLICA_COUNT</code> nodes where pods are running.
</div>
<p><em>Anyone with Mycelium installed can access your website from any of these URLs from anywhere in the world!</em></p>
</div>
<div class="features">
<h3>🚀 Key Features:</h3>
<div class="feature">🛡️ Enhanced security with network isolation</div>
<div class="feature">🌍 Peer-to-peer global access via NodePort</div>
<div class="feature">🔒 Standard Kubernetes service patterns</div>
<div class="feature">⚡ Clean pod networking without hostNetwork</div>
<div class="feature">🖥️ Multi-replica, multi-node Kubernetes cluster</div>
<div class="feature">🔄 Dynamic IPv6 discovery and routing</div>
</div>
<div class="timestamp" id="timestamp">
Loading timestamp...
</div>
<div style="margin-top: 2rem; font-size: 0.8rem;">
Mycelium Cloud NodePort Demo<br>
Security-First IPv6 Website Hosting<br>
<strong>Auto-updated every 30 seconds</strong>
</div>
</div>
</body>
</html>
HTML_EOF
# Replace the replica count placeholder
sed -i "s/REPLICA_COUNT/${#IPV6_ADDRESSES[@]}/g" /tmp/index.html
echo "📝 Generated HTML content for ${#IPV6_ADDRESSES[@]} accessible nodes"
# Update the ConfigMap
echo "🔄 Updating ConfigMap..."
kubectl create configmap nginx-nodeport-content --from-file=index.html=/tmp/index.html --dry-run=client -o yaml | kubectl apply -f -
echo "✅ Successfully updated nginx-nodeport-content ConfigMap"
echo ""
echo "🔄 To apply changes to running pods, restart the deployment:"
echo " kubectl rollout restart deployment/nginx-nodeport"
echo ""
echo "🌐 Website will be accessible at ALL of these URLs:"
for i in "${!IPV6_ADDRESSES[@]}"; do
echo " http://[${IPV6_ADDRESSES[$i]}]:30091 (Node: ${NODES_WITH_PODS[$i]})"
done
echo ""
echo "📊 Summary:"
echo " Total replicas: $POD_COUNT"
echo " Accessible nodes: ${#IPV6_ADDRESSES[@]}"
echo " All URLs working: ✅ YES"
echo ""
# Cleanup
rm -f /tmp/index.html
echo "✅ Multi-replica update complete!"