Files
docs_projectmycelium/docs/cloud/tutorial.md

572 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
sidebar_position: 3
---
# Deployment Tutorials
Learn by example with these practical deployment tutorials for Mycelium Cloud.
## Prerequisites
Before starting these tutorials, ensure you have:
- ✅ Deployed cluster with kubectl access
- ✅ Mycelium running for network access
- ✅ kubectl configured with your cluster
```bash
# Verify your setup
kubectl get nodes
# Should show your cluster nodes
```
## Tutorial 1: Hello World with Nginx
Deploy a simple web server to verify your cluster is working.
### Step 1: Create the Deployment
Save as `hello-world-deploy.yaml`:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
```
Apply it:
```bash
kubectl apply -f hello-world-deploy.yaml
```
### Step 2: Expose the Service
Save as `hello-world-svc.yaml`:
```yaml
apiVersion: v1
kind: Service
metadata:
name: hello-world-service
spec:
selector:
app: hello-world
ports:
- port: 80
targetPort: 80
type: ClusterIP
```
Apply it:
```bash
kubectl apply -f hello-world-svc.yaml
```
### Step 3: Access Your Application
```bash
# Port forward to local machine
kubectl port-forward service/hello-world-service 8080:80
```
Open `http://localhost:8080` you should see the Nginx welcome page!
### Cleanup
```bash
kubectl delete -f hello-world-deploy.yaml
kubectl delete -f hello-world-svc.yaml
```
## Tutorial 2: Python Servers with Load Balancing
Deploy multiple Python HTTP servers to demonstrate load balancing.
### Step 1: Create the Deployments
Save as `python-servers.yaml`:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-server-1
spec:
replicas: 2
selector:
matchLabels:
app: python-server
server-id: "1"
template:
metadata:
labels:
app: python-server
server-id: "1"
spec:
containers:
- name: python-server
image: python:3.9-slim
command: ["python", "-c"]
args:
- |
import http.server, socketserver, json
class Handler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
response = {"server": "Python Server 1", "pod": "$(hostname)"}
self.wfile.write(json.dumps(response).encode())
with socketserver.TCPServer(("", 8000), Handler) as httpd:
httpd.serve_forever()
ports:
- containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-server-2
spec:
replicas: 2
selector:
matchLabels:
app: python-server
server-id: "2"
template:
metadata:
labels:
app: python-server
server-id: "2"
spec:
containers:
- name: python-server
image: python:3.9-slim
command: ["python", "-c"]
args:
- |
import http.server, socketserver, json
class Handler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
response = {"server": "Python Server 2", "pod": "$(hostname)"}
self.wfile.write(json.dumps(response).encode())
with socketserver.TCPServer(("", 8000), Handler) as httpd:
httpd.serve_forever()
ports:
- containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-server-3
spec:
replicas: 2
selector:
matchLabels:
app: python-server
server-id: "3"
template:
metadata:
labels:
app: python-server
server-id: "3"
spec:
containers:
- name: python-server
image: python:3.9-slim
command: ["python", "-c"]
args:
- |
import http.server, socketserver, json
class Handler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
response = {"server": "Python Server 3", "pod": "$(hostname)"}
self.wfile.write(json.dumps(response).encode())
with socketserver.TCPServer(("", 8000), Handler) as httpd:
httpd.serve_forever()
ports:
- containerPort: 8000
```
### Step 2: Create Load Balancing Service
Save as `python-lb-service.yaml`:
```yaml
apiVersion: v1
kind: Service
metadata:
name: python-lb
spec:
selector:
app: python-server
ports:
- port: 80
targetPort: 8000
type: ClusterIP
```
### Step 3: Deploy Everything
```bash
kubectl apply -f python-servers.yaml
kubectl apply -f python-lb-service.yaml
# Wait for pods to be ready
kubectl get pods -l app=python-server
```
### Step 4: Test Load Balancing
```bash
# Port forward the service
kubectl port-forward service/python-lb 8080:80
# In another terminal, test the load balancing
for i in {1..10}; do
curl http://localhost:8080
done
```
You'll see responses from different servers and pods, showing the load balancing in action!
### Cleanup
```bash
kubectl delete -f python-servers.yaml
kubectl delete -f python-lb-service.yaml
```
## Tutorial 3: Stateful Application with Persistent Storage
Deploy a simple application that persists data.
### Step 1: Create Persistent Volume Claim
Save as `storage.yaml`:
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
```
### Step 2: Create Stateful Deployment
Save as `stateful-app.yaml`:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: data-app
spec:
replicas: 1
selector:
matchLabels:
app: data-app
template:
metadata:
labels:
app: data-app
spec:
containers:
- name: app
image: busybox:latest
command: ["sh", "-c"]
args:
- |
echo "Starting data application..."
while true; do
date >> /data/log.txt
echo "Written at $(date)" >> /data/log.txt
sleep 10
done
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
```
### Step 3: Deploy and Verify
```bash
kubectl apply -f storage.yaml
kubectl apply -f stateful-app.yaml
# Wait for pod to be ready
kubectl get pods -l app=data-app
# Check the logs being written
kubectl exec -it $(kubectl get pod -l app=data-app -o name) -- cat /data/log.txt
```
### Step 4: Test Persistence
```bash
# Delete the pod
kubectl delete pod -l app=data-app
# Wait for new pod to start
kubectl get pods -l app=data-app
# Check data persisted
kubectl exec -it $(kubectl get pod -l app=data-app -o name) -- cat /data/log.txt
```
The data from before the pod deletion should still be there!
### Cleanup
```bash
kubectl delete -f stateful-app.yaml
kubectl delete -f storage.yaml
```
## Tutorial 4: Multi-Tier Application
Deploy a simple web app with a database backend.
### Step 1: Deploy Redis Database
Save as `redis.yaml`:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
type: ClusterIP
```
### Step 2: Deploy Frontend Application
Save as `frontend.yaml`:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: nginx:alpine
ports:
- containerPort: 80
env:
- name: REDIS_HOST
value: "redis"
- name: REDIS_PORT
value: "6379"
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 80
type: ClusterIP
```
### Step 3: Deploy and Access
```bash
kubectl apply -f redis.yaml
kubectl apply -f frontend.yaml
# Wait for all pods
kubectl get pods
# Port forward to access frontend
kubectl port-forward service/frontend 8080:80
```
Open `http://localhost:8080` to access your multi-tier application.
### Cleanup
```bash
kubectl delete -f frontend.yaml
kubectl delete -f redis.yaml
```
## Best Practices
### Resource Limits
Always set resource limits:
```yaml
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
```
### Health Checks
Add liveness and readiness probes:
```yaml
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
```
### Labels and Annotations
Use descriptive labels:
```yaml
metadata:
labels:
app: myapp
version: v1.0
environment: production
```
## Troubleshooting
### Pods Not Starting
```bash
# Check pod status
kubectl describe pod <pod-name>
# Check logs
kubectl logs <pod-name>
# Check events
kubectl get events --sort-by='.lastTimestamp'
```
### Service Not Accessible
```bash
# Check service
kubectl describe service <service-name>
# Check endpoints
kubectl get endpoints <service-name>
# Test from within cluster
kubectl run -it --rm debug --image=alpine --restart=Never -- sh
# Then: wget -O- http://service-name
```
### Resource Issues
```bash
# Check node resources
kubectl top nodes
# Check pod resources
kubectl top pods
# Check resource requests/limits
kubectl describe nodes
```
## Next Steps
Now that you've completed these tutorials:
- Deploy your own applications
- Explore [Helm](https://helm.sh/) for package management
- Learn about [Ingress controllers](https://kubernetes.io/docs/concepts/services-networking/ingress/) for advanced routing
- Study [StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) for databases
- Explore [ConfigMaps and Secrets](https://kubernetes.io/docs/concepts/configuration/) for configuration management
---
:::tip Keep Learning
These tutorials cover the basics. The real power of Kubernetes comes from combining these concepts to build complex, scalable applications on Mycelium Cloud!
:::