็†ฑ้–€ๅˆ†้กž
 ่ผ‰ๅ…ฅไธญ…
็›ฎ้Œ„

๐Ÿš€ Kubernetes ๅฎŒๆ•ดๅ…ฅ้–€ๆŒ‡ๅ—:ๅพž้›ถ้ƒจ็ฝฒ K3s ๅˆฐ Pod / Service / Ingress ๅ…จๆต็จ‹ๅฏฆๆˆฐ

    ๐Ÿš€ Kubernetes ๅฎŒๆ•ดๅ…ฅ้–€ๆŒ‡ๅ—:ๅพž้›ถ้ƒจ็ฝฒ K3s ๅˆฐ Pod / Service / Ingress ๅ…จๆต็จ‹ๅฏฆๆˆฐ

    Kubernetes(K8s)ๆ˜ฏ็›ฎๅ‰ๅฎนๅ™จ็ทจๆŽ’็š„ๆฅญ็•Œๆจ™ๆบ–,ไฝ†ๅฎ˜ๆ–น็‰ˆๅฎ‰่ฃ้–€ๆชป้ซ˜、่ณ‡ๆบ้œ€ๆฑ‚ๅคง。
    K3s ๆ˜ฏ็”ฑ Rancher ้–‹็™ผ็š„่ผ•้‡ๅŒ– Kubernetes,ๅฎ‰่ฃๅช้œ€ไธ€่กŒๆŒ‡ไปค,่จ˜ๆ†ถ้ซ”้œ€ๆฑ‚ๅƒ… 512 MB,
    ้žๅธธ้ฉๅˆ Home Lab、Proxmox VM、ๅญธ็ฟ’็’ฐๅขƒ ไฝฟ็”จ,็”Ÿ็”ข็ญ‰็ดšๅŠŸ่ƒฝไธ€ๆจฃๅฎŒๆ•ด。
    ๆœฌ็ฏ‡ๅพžๅฎ‰่ฃๅˆฐ Ingress ๅ…จๆต็จ‹ๅฏฆๆˆฐ,ๅธถไฝ ๅปบ็ซ‹็ฌฌไธ€ๅฅ—ๅฏ็”จ็š„ K3s ๅข้›†。


    ๐Ÿ“‹ ็›ฎ้Œ„

    1. K3s ่ˆ‡ K8s ็š„ๅทฎ็•ฐ
    2. ็’ฐๅขƒ่ฆๅŠƒ่ˆ‡ๅฎ‰่ฃ
    3. kubectl ๅŸบ็คŽๆ“ไฝœ
    4. Namespace ่ˆ‡่ณ‡ๆบ้š”้›ข
    5. ้ƒจ็ฝฒ็ฌฌไธ€ๅ€‹ App(Deployment + Pod)
    6. Service ๅฐๅค–ๆšด้œฒๆœๅ‹™
    7. Ingress ็ตฑไธ€ๅ…ฅๅฃ็ฎก็†
    8. ConfigMap ่ˆ‡ Secret
    9. PV / PVC ๆŒไน…ๅŒ–ๅ„ฒๅญ˜
    10. ๅธธ่ฆ‹ๅ•้กŒๆŽ’ๆŸฅ

    ⚖️ ไธ€、K3s ่ˆ‡ K8s ็š„ๅทฎ็•ฐ

    ้ …็›ฎK8s(ๅฎ˜ๆ–น)K3s(่ผ•้‡็‰ˆ)
    ๅฎ‰่ฃ้›ฃๅบฆ่ค‡้›œ,้œ€ kubeadm / ๅคšๆญฅ้ฉŸไธ€่กŒ curl ๆŒ‡ไปค
    ๆœ€ไฝŽ่จ˜ๆ†ถ้ซ”2 GB+512 MB
    ๅ…งๅปบๅ…ƒไปถ้œ€่‡ช่กŒ้ธ้…Traefik Ingress、CoreDNS、Flannel、Metrics Server ๅ…งๅปบ
    ่ณ‡ๆ–™ๅบซetcdSQLite(ๅ–ฎ็ฏ€้ปž)/ etcd(HA)
    ้ฉ็”จๅ ดๆ™ฏๅคงๅž‹ไผๆฅญๅข้›†Home Lab、้‚Š็ทฃ้‹็ฎ—、ๅญธ็ฟ’、ๅฐๅž‹็”Ÿ็”ข
    kubectl ็›ธๅฎนๆ€งๅฎŒๆ•ดๅฎŒๆ•ด(100% API ็›ธๅฎน)
    ๐Ÿ’ก K3s ๅฎŒๆ•ดๆ”ฏๆดๆ‰€ๆœ‰ Kubernetes API,ๅœจ K3s ๅญธๅˆฐ็š„็Ÿฅ่ญ˜ๅฏไปฅ็›ดๆŽฅ็”จๅœจๆญฃๅผ K8s ็’ฐๅขƒ。

    ๐Ÿ–ฅ️ ไบŒ、็’ฐๅขƒ่ฆๅŠƒ่ˆ‡ๅฎ‰่ฃ

    ๅปบ่ญฐ่ฆๆ ผ

    ็ฏ€้ปž้กžๅž‹่ง’่‰ฒๆœ€ไฝŽ่ฆๆ ผๅปบ่ญฐ่ฆๆ ผ
    Server(Master)ๆŽงๅˆถๅนณ้ข1 CPU / 512 MB2 CPU / 2 GB
    Agent(Worker)ๅŸท่กŒๅทฅไฝœ่ฒ ่ผ‰1 CPU / 512 MB2 CPU / 2 GB

    ๆœฌ็ฏ‡ไปฅ ๅ–ฎ็ฏ€้ปž(all-in-one) ็คบ็ฏ„,OS ็‚บ Ubuntu 22.04 / Debian 12。

    1️⃣ ๅฎ‰่ฃ K3s Server

    # ไธ€้ตๅฎ‰่ฃ(ๅฎ˜ๆ–น่…ณๆœฌ)
    curl -sfL https://get.k3s.io | sh -
    
    # ๅฎ‰่ฃๅฎŒๆˆๅพŒ็ขบ่ช็‹€ๆ…‹
    sudo systemctl status k3s
    
    # ็ขบ่ช็ฏ€้ปžๅŠ ๅ…ฅ
    sudo kubectl get nodes

    ๅฎ‰่ฃๅฎŒๆˆๅพŒ kubectl ๅทฒ่‡ชๅ‹•่จญๅฎš,/etc/rancher/k3s/k3s.yaml ็‚บ kubeconfig ๆช”ๆกˆ。

    2️⃣ ่จญๅฎš kubectl ็ตฆไธ€่ˆฌไฝฟ็”จ่€…ไฝฟ็”จ

    mkdir -p $HOME/.kube
    sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    echo 'export KUBECONFIG=$HOME/.kube/config' >> ~/.bashrc
    source ~/.bashrc
    
    # ้ฉ—่ญ‰
    kubectl get nodes

    3️⃣ ๅŠ ๅ…ฅ Worker ็ฏ€้ปž(ๅคš็ฏ€้ปžๆ™‚)

    # ๅœจ Server ไธŠๅ–ๅพ— Token
    sudo cat /var/lib/rancher/k3s/server/node-token
    
    # ๅœจ Agent ็ฏ€้ปžๅŸท่กŒ
    curl -sfL https://get.k3s.io | K3S_URL=https://<SERVER_IP>:6443 \
      K3S_TOKEN=<NODE_TOKEN> sh -

    ๐Ÿ”ง ไธ‰、kubectl ๅŸบ็คŽๆ“ไฝœ

    ๅธธ็”จๆŒ‡ไปค้€ŸๆŸฅ

    # ๆŸฅ็œ‹็ฏ€้ปž
    kubectl get nodes -o wide
    
    # ๆŸฅ็œ‹ๆ‰€ๆœ‰ Namespace ็š„ Pod
    kubectl get pods -A
    
    # ๆŸฅ็œ‹็‰นๅฎš Namespace
    kubectl get pods -n kube-system
    
    # ๆŸฅ็œ‹่ณ‡ๆบ่ฉณ็ดฐ่ณ‡่จŠ
    kubectl describe pod <pod-name>
    
    # ๆŸฅ็œ‹ Pod ๆ—ฅ่ชŒ
    kubectl logs <pod-name>
    kubectl logs -f <pod-name>   # ๆŒ็บŒ่ผธๅ‡บ
    
    # ้€ฒๅ…ฅ Pod ๅ…ง้ƒจ
    kubectl exec -it <pod-name> -- /bin/bash
    
    # ๅˆช้™ค่ณ‡ๆบ
    kubectl delete pod <pod-name>
    kubectl delete -f manifest.yaml

    ๅฟซ้€Ÿๅˆฅๅ่จญๅฎš(ๅปบ่ญฐๅŠ ๅ…ฅ ~/.bashrc)

    alias k='kubectl'
    alias kga='kubectl get all -A'
    alias kgp='kubectl get pods'
    alias kdp='kubectl describe pod'

    ๐Ÿ“ ๅ››、Namespace ่ˆ‡่ณ‡ๆบ้š”้›ข

    Namespace ๆ˜ฏ K8s ไธญ็š„้‚่ผฏ้š”้›ขๅ–ฎไฝ,ไธๅŒๅฐˆๆกˆ / ็’ฐๅขƒๅปบ่ญฐ็”จไธๅŒ Namespace ็ฎก็†。

    # ๆŸฅ็œ‹ๆ‰€ๆœ‰ Namespace
    kubectl get namespaces
    
    # ๅปบ็ซ‹ Namespace
    kubectl create namespace myapp
    
    # ๅœจๆŒ‡ๅฎš Namespace ๆ“ไฝœ
    kubectl get pods -n myapp
    
    # ่จญๅฎš้ ่จญ Namespace(้ฟๅ…ๆฏๆฌกๅŠ  -n)
    kubectl config set-context --current --namespace=myapp

    K3s ้ ่จญ Namespace:

    • default:้ ่จญๆ“ไฝœ็ฉบ้–“
    • kube-system:็ณป็ตฑๅ…ƒไปถ(CoreDNS、Traefik ็ญ‰)
    • kube-public:ๅ…ฌ้–‹ๅฏ่ฎ€่ณ‡ๆบ

    ๐Ÿณ ไบ”、้ƒจ็ฝฒ็ฌฌไธ€ๅ€‹ App(Deployment + Pod)

    ๆฆ‚ๅฟต่ชชๆ˜Ž

    • Pod:K8s ๆœ€ๅฐ้ƒจ็ฝฒๅ–ฎไฝ,ๅŒ…ๅซไธ€ๅ€‹ๆˆ–ๅคšๅ€‹ Container
    • Deployment:็ฎก็† Pod ็š„ๅ‰ฏๆœฌๆ•ธ้‡、ๆปพๅ‹•ๆ›ดๆ–ฐ、่‡ชๅ‹•้‡ๅ•Ÿ
    • ReplicaSet:็”ฑ Deployment ่‡ชๅ‹•็ฎก็†,็ขบไฟ Pod ๆ•ธ้‡

    ๆ–นๅผไธ€:ๆŒ‡ไปค็›ดๆŽฅ้ƒจ็ฝฒ(ๅฟซ้€Ÿๆธฌ่ฉฆ)

    # ้ƒจ็ฝฒ nginx
    kubectl create deployment nginx --image=nginx:latest --replicas=2
    
    # ๆŸฅ็œ‹็‹€ๆ…‹
    kubectl get deployment nginx
    kubectl get pods -l app=nginx

    ๆ–นๅผไบŒ:YAML ๅฎฃๅ‘Šๅผ้ƒจ็ฝฒ(ๅปบ่ญฐ)

    # deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      namespace: myapp
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.25
            ports:
            - containerPort: 80
            resources:
              requests:
                memory: "64Mi"
                cpu: "100m"
              limits:
                memory: "128Mi"
                cpu: "250m"
    # ๅฅ—็”จ
    kubectl apply -f deployment.yaml
    
    # ๆŸฅ็œ‹ Rollout ็‹€ๆ…‹
    kubectl rollout status deployment/nginx -n myapp
    
    # ๆ›ดๆ–ฐๆ˜ ๅƒๆช”(ๆปพๅ‹•ๆ›ดๆ–ฐ)
    kubectl set image deployment/nginx nginx=nginx:1.26 -n myapp
    
    # ๅ›žๆปพ
    kubectl rollout undo deployment/nginx -n myapp

    ๐ŸŒ ๅ…ญ、Service ๅฐๅค–ๆšด้œฒๆœๅ‹™

    Pod ็š„ IP ๆ˜ฏๅ‹•ๆ…‹็š„,Service ๆไพ›็ฉฉๅฎš็š„ๅญ˜ๅ–ๅ…ฅๅฃ,่‡ชๅ‹•ๅš Load Balancing。

    Service ้กžๅž‹ๆฏ”่ผƒ

    ้กžๅž‹่ชชๆ˜Ž้ฉ็”จๅ ดๆ™ฏ
    ClusterIPๅข้›†ๅ…ง้ƒจ IP,้ ่จญ้กžๅž‹ๆœๅ‹™้–“้€š่จŠ
    NodePort้–‹ๆ”พ Node ็š„ๅ›บๅฎš Port(30000-32767)้–‹็™ผๆธฌ่ฉฆ、็›ดๆŽฅๅญ˜ๅ–
    LoadBalancer้›ฒ็ซฏ็’ฐๅขƒ่‡ชๅ‹•้…็ฝฎๅค–้ƒจ LB้›ฒ็ซฏ(AWS/GCP/Azure)

    ๅปบ็ซ‹ NodePort Service

    # service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-svc
      namespace: myapp
    spec:
      type: NodePort
      selector:
        app: nginx
      ports:
      - protocol: TCP
        port: 80          # Service Port
        targetPort: 80    # Container Port
        nodePort: 30080   # ๅฐๅค– Port(ๅฏ็œ็•ฅ่ฎ“็ณป็ตฑ่‡ชๅ‹•ๅˆ†้…)
    kubectl apply -f service.yaml
    
    # ๆŸฅ็œ‹
    kubectl get svc -n myapp
    
    # ๆธฌ่ฉฆ(ๅพž Host ๅญ˜ๅ–)
    curl http://<NODE_IP>:30080

    ๐Ÿ”€ ไธƒ、Ingress ็ตฑไธ€ๅ…ฅๅฃ็ฎก็†

    K3s ๅ…งๅปบ Traefik Ingress Controller,ๅฏ็”จๅŸŸๅ่ทฏ็”ฑๅˆฐไธๅŒ Service,ไธ้œ€่ฆๆฏๅ€‹ๆœๅ‹™้–‹ไธๅŒ Port。

    Ingress ๆžถๆง‹

    Internet
        ↓
    Traefik(80/443)
        ├── /app-a  →  Service A → Pods
        └── /app-b  →  Service B → Pods

    ๅปบ็ซ‹ Ingress ่ฆๅ‰‡

    # ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx-ingress
      namespace: myapp
      annotations:
        traefik.ingress.kubernetes.io/router.entrypoints: web
    spec:
      rules:
      - host: nginx.local          # ๆœฌๆฉŸๆธฌ่ฉฆๅฏๅŠ ๅˆฐ /etc/hosts
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-svc
                port:
                  number: 80
    kubectl apply -f ingress.yaml
    
    # ๆŸฅ็œ‹ Ingress
    kubectl get ingress -n myapp
    
    # ๆœฌๆฉŸๆธฌ่ฉฆ(ๅŠ ๅˆฐ /etc/hosts)
    echo "<NODE_IP> nginx.local" | sudo tee -a /etc/hosts
    curl http://nginx.local

    ๅคš่ทฏ็”ฑ Ingress ็ฏ„ไพ‹

    spec:
      rules:
      - host: mysite.example.com
        http:
          paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-svc
                port:
                  number: 8080
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-svc
                port:
                  number: 3000

    ๐Ÿ” ๅ…ซ、ConfigMap ่ˆ‡ Secret

    ConfigMap — ๅญ˜ๆ”พ้žๆฉŸๅฏ†่จญๅฎš

    # configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config
      namespace: myapp
    data:
      APP_ENV: production
      LOG_LEVEL: info
      DB_HOST: mariadb-svc
    # ๅœจ Deployment ไธญไฝฟ็”จ ConfigMap
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        envFrom:
        - configMapRef:
            name: app-config

    Secret — ๅญ˜ๆ”พๆฉŸๅฏ†่ณ‡ๆ–™(Base64 ็ทจ็ขผ)

    # ็”ข็”Ÿ base64
    echo -n 'mypassword' | base64
    # ่ผธๅ‡บ:bXlwYXNzd29yZA==
    
    # secret.yaml
    apiVersion: v1
    kind: Secret
    metadata:
      name: db-secret
      namespace: myapp
    type: Opaque
    data:
      DB_PASSWORD: bXlwYXNzd29yZA==
      DB_USER: YWRtaW4=
    # ๅœจ Pod ไธญไฝฟ็”จ Secret
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DB_PASSWORD

    ๐Ÿ’พ ไน、PV / PVC ๆŒไน…ๅŒ–ๅ„ฒๅญ˜

    Pod ้‡ๅ•ŸๅพŒ่ณ‡ๆ–™ๆœƒๆถˆๅคฑ,้œ€่ฆ PersistentVolume(PV) ๅ’Œ PersistentVolumeClaim(PVC) ไฟๅญ˜่ณ‡ๆ–™。

    K3s ๅ…งๅปบ Local Path Provisioner,ๅฏ่‡ชๅ‹•ๅปบ็ซ‹ PV(่ณ‡ๆ–™ๅญ˜ๅœจ Node ๆœฌๆฉŸ็ฃ็ขŸ)。

    ๅปบ็ซ‹ PVC

    # pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: nginx-data
      namespace: myapp
    spec:
      accessModes:
      - ReadWriteOnce
      storageClassName: local-path    # K3s ้ ่จญ StorageClass
      resources:
        requests:
          storage: 1Gi
    # ๅœจ Deployment ๆŽ›่ผ‰ PVC
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: nginx-data
    # ๆŸฅ็œ‹ PVC ็‹€ๆ…‹(Bound = ๅทฒๆŽ›่ผ‰)
    kubectl get pvc -n myapp

    ❓ ๅ、ๅธธ่ฆ‹ๅ•้กŒๆŽ’ๆŸฅ

    ๅ•้กŒ 1:Pod ไธ€็›ด CrashLoopBackOff

    ๆŽ’ๆŸฅๆญฅ้ฉŸ:

    # ๆŸฅ็œ‹่ฉณ็ดฐ้Œฏ่ชค
    kubectl describe pod <pod-name> -n myapp
    
    # ๆŸฅ็œ‹ๆœ€่ฟ‘ 50 ่กŒ Log
    kubectl logs <pod-name> --previous --tail=50 -n myapp

    ๅธธ่ฆ‹ๅŽŸๅ› :ๆ˜ ๅƒไธๅญ˜ๅœจ、็’ฐๅขƒ่ฎŠๆ•ธ็ผบๅฐ‘、่ณ‡ๆบไธ่ถณ(OOMKilled)

    ๅ•้กŒ 2:Pod ็‹€ๆ…‹ Pending

    kubectl describe pod <pod-name> -n myapp
    # ็œ‹ Events ๆฌ„ไฝ

    ๅธธ่ฆ‹ๅŽŸๅ› :Node ่ณ‡ๆบไธ่ถณ(CPU/Memory)、PVC ๆœช Bound、Node ๆœ‰ Taint

    ๅ•้กŒ 3:Service ็„กๆณ•ๅญ˜ๅ–

    # ็ขบ่ช Endpoints ๆ˜ฏๅฆๆœ‰ Pod IP
    kubectl get endpoints <service-name> -n myapp
    
    # ็ขบ่ช Pod Label ๆ˜ฏๅฆ่ˆ‡ Service Selector ไธ€่‡ด
    kubectl get pods --show-labels -n myapp

    ๅ•้กŒ 4:Ingress 404 / ็„กๆณ•่ทฏ็”ฑ

    # ๆŸฅ็œ‹ Traefik ๆ—ฅ่ชŒ
    kubectl logs -n kube-system -l app.kubernetes.io/name=traefik
    
    # ็ขบ่ช Ingress ๆ˜ฏๅฆๆญฃ็ขบๅปบ็ซ‹
    kubectl describe ingress <ingress-name> -n myapp

    ๅ•้กŒ 5:ๆŸฅ็œ‹ๅข้›†ๆ•ด้ซ”่ณ‡ๆบไฝฟ็”จ

    # ้œ€่ฆ Metrics Server(K3s ๅทฒๅ…งๅปบ)
    kubectl top nodes
    kubectl top pods -A

    ๐Ÿ“Œ ็ธฝ็ต

    K3s ่ฎ“ Kubernetes ็š„ๅ…ฅ้–€้–€ๆชปๅคงๅน…้™ไฝŽ,ๅช้œ€ไธ€ๅฐ Linux VM ๅฐฑ่ƒฝ้ซ”้ฉ—ๅฎŒๆ•ด็š„ K8s ๅŠŸ่ƒฝ。
    ๆœฌ็ฏ‡ๆถต่“‹ไบ†ๅพžๅฎ‰่ฃๅˆฐ Deployment → Service → Ingress → ConfigMap → PVC ็š„ๅฎŒๆ•ดๆต็จ‹,
    ้€™ๅฅ—ๆžถๆง‹ๅฏไปฅ็›ดๆŽฅๅปถไผธๅˆฐๅคš็ฏ€้ปžๅข้›†ๆˆ–ๆญฃๅผ K8s ็’ฐๅขƒ,ๅญธ็ฟ’ๆˆๆœฌไธ€ๆฌกๆžๅฎš。

    ๅ…ƒไปถๅŠŸ่ƒฝ
    Deployment็ฎก็† Pod ๅ‰ฏๆœฌ、ๆปพๅ‹•ๆ›ดๆ–ฐ
    Service็ฉฉๅฎšๅ…ฅๅฃ、่ฒ ่ผ‰ๅนณ่กก
    IngressๅŸŸๅ่ทฏ็”ฑ、็ตฑไธ€ๅฐๅค–ๅ…ฅๅฃ
    ConfigMapๆณจๅ…ฅ็’ฐๅขƒ่จญๅฎš
    Secretๅฎ‰ๅ…จๅญ˜ๆ”พๆฉŸๅฏ†
    PVC่ณ‡ๆ–™ๆŒไน…ๅŒ–

    ๐Ÿ’ฌ ไฝ ็š„ Home Lab ๆœ‰ๅœจ่ท‘ Kubernetes ๅ—Ž?ๆˆ–่€…ไฝ ่ฆบๅพ— K3s ๅ’Œ Proxmox ๆญ้…่ตทไพ†ๅฆ‚ไฝ•?ๆญก่ฟŽ็•™่จ€ไบคๆต!

    ๐Ÿ“š ๅปถไผธ้–ฑ่ฎ€

    ๐Ÿ”— ๅˆ†ไบซ้€™็ฏ‡ LINE Facebook X

    ๆฒ’ๆœ‰็•™่จ€:

    ๅผต่ฒผ็•™่จ€

    ๅญ—็ดš