Author: kanakorn.h

  • [บันทึกกันลืม] ปัญหา Kubernetes มี Disk Pressure แล้วทำให้ pods อยู่ในสถานะ Evicted ค้างจำนวนมาก

    ปัญหา: เมื่อใช้คำสั่ง kubectl get pod -A แล้ว พบว่า มี pod แสดงสถานะ Evicted เป็นจำนวนมาก (จริง ๆ แล้วมีสถานะอื่นที่ไม่ใช่ Running จำนวนมาก)

    ตรวจสอบ: สันนิษฐานว่า Disk เต็ม ใช้คำสั่ง kubectl describe node | grep -i DiskPressure พบว่า KubeletHasDiskPressure แสดงว่า มีปัญหาอะไรสักอย่างกับ Storage และเมื่อดูด้วย kubectl logs -f pod/thepodname -n thenamespace พบว่า “attempting to reclaim ephemeral-storage”

    แนวทางการแก้ปัญหา: แต่ละ node ติดตั้งแบบแบ่ง Partition ให้ OS เป็น / (พื้นที่ 100 GB) และ พื้นที่ใช้งานจริง เป็น /data (2.5 TB) ตรวจสอบด้วยคำสั่ง df -h / พบว่า มีการใช้พื้นที่ เกิน 80%

    ปัญหานี้เคยเกิดขึ้นกับตอนใช้ Docker แก้ไขโดยการย้าย /var/lib/docker ไปไว้ที่ /data/docker ซึ่งมีพื้นที่มากกว่า แต่ในระบบ Kubernetes ใช้ containerd และ kubelet

    วิธีย้าย containerd ไปไว้ใน /data ตามลำดับ

    ที่ nodeX (ควรทำทีละ node)

    sudo mkdir /data/containerd
    sudo mkdir /data/containerd/var
    sudo mkdir /data/containerd/run
    sudo mkdir /data/kubelet

    กลับมาที่ control plane, ให้ทำการ drain ด้วยคำสั่ง ต่อไปนี้ แล้วรอจนเสร็จ

    sudo kubectl drain --delete-emptydir-data --ignore-daemonsets nodeX

    กลับมาที่ nodeX ทำการย้ายข้อมูลของ containerd และ kubelet มาไว้ที่ใหม่

    sudo systemctl stop containerd
    sudo systemctl stop kubelet
    sudo rsync -av /var/lib/containerd/ /data/containerd/var/
    sudo rsync -av /run/containerd/ /data/containerd/run/
    sudo rsync -av /var/lib/kubelet/ /data/kubelet/

    แก้ไข /etc/systemd/system/kubelet.service.d/10-kubeadm.conf เพิ่ม –root-dir=/data/kubelet

    # Note: This dropin only works with kubeadm and kubelet v1.11+
    [Service]
    Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --root-dir=/data/kubelet"
    Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
    # This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
    EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
    # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
    # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
    EnvironmentFile=-/etc/default/kubelet
    ExecStart=
    ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS

    สร้าง containerd configuration

    cd /etc/containerd/
    sudo containerd config default > /etc/containerd/config.toml

    แก้ไข containerd configuration ดังนี้

    root = "/data/containerd/var"
    state = "/data/containerd/run"

    จากนั้น start containerd และ kubelet กลับมา

    sudo systemctl start containerd
    sudo systemctl start kubelet

    กลับไปที่ control plane แล้วเอา nodeX กลับมาทำงานเหมือนเดิม

    sudo kubectl uncordon nodeX

    ตรวจสอบ nodeX ว่า DiskPressure มีสถานะเป็น KubeletHasNoDiskPressure หรือไม่ด้วยคำสั่ง

    sudo kubectl describe node nodeX

    ถ้าเรียบร้อยแล้ว กลับไปที่ nodeX เพื่อลบข้อมูลเก่า (เฉพาะ /var/lib/containerd/)

    sudo rm -rf /var/lib/containerd/*

    จากนั้นวนทำทีละ node จนครบ

  • [บันทึกกันลืม] วิธีหาไฟล์ที่มีคำที่ต้องการ โดยแสดงเฉพาะ ชื่อไฟล์เท่านั้น

    โจทย์ ต้องการหาไฟล์ที่มีคำว่า text_pattern จากทุกไฟล์ในไดเรคทอรี่ /path/to/ ที่มีนามสกุล .ipynb แต่ต้องไม่มีคำว่า checkpoint ใน path หรือชื่อไฟล์

    find /path/to -name "*.ipynb" ! -name "*checkpoint*" -type f -print0 | while read -r -d '' i; do
        if grep -q "text_pattern" "$i"; then
             echo "$i"  # Output only the filename if the pattern is found
        fi;
    done
  • [บันทึกกันลืม] แก้ปัญหา rejoin node rke2 ไม่ได้

    ปัญหา

    node หนึ่งใน Rancher ใช้งานได้ตามปรกติ แต่ไป sudo apt update; sudo apt upgrade แล้วเกิดเหตุให้ ต้อง restart node ปัญหาที่เกิดขึ้นคือ pod ที่มาสร้างบน node นี้ไม่สามารถติดต่อกับระบบได้เลย

    อาการ

    pod จะ CrashLoopBackOff ตลอด หรือถ้าดู event จะเห็น timeout ตลอดครับ

    วิธีแก้ไข

    ได้ลอง format เครื่องก็แล้ว ทำหลายอย่างแล้วก็ไม่หาย ขอบคุณ คุณธนกร กิจศรีนภดล (เทียน) ได้ไปค้นหาวิธีการแก้ไขมาให้ โดยเหตุมาจาก Kernel ของ Ubuntu 20.04 กับ kernel ของ rke2 รุ่นที่ใช้งานอยู่ มี Bug เรื่อง UDP ตาม Link นี้

    Root cause คือ: kernel bug  affects udp + vxlan when using the offloading feature of the kernel

    สรุปคือ ใช้คำสั่งนี้

    sudo ethtool -K flannel.1 tx-checksum-ip-generic off

    ผลการแก้ไข

    หายสนิท ใช้งานได้ต่อไป

  • [บันทึกกันลืม] วิธีป้องกันไม่ให้ผู้ใช้ดาวน์โหลดสิ่งใด ๆ ออกไปจาก Jupyter Notebook/Lab ได้

    ปัญหา

    การใช้ Jupyter Notebook/Lab (aka. Jupyter) นั้นมีข้อดีคือ เราสามารถจำกัดการเข้าถึงข้อมูลที่ละเอียดอ่อนได้ อย่างเช่นเราสามารถตั้งค่าการ access ของ database user ได้จาก private ip ของ Jupyter ได้ แต่ก็ยังมีช่องโหว่คือ ผู้ใช้สามารถ Export file แล้ว download ออกไปได้

    ** Caution: บันทึกนี้ไม่สามารถป้องการการ scp และ API call เพื่อ upload ไปยัง Google Drive, Owncloud ได้ **

    ในที่นี้ ใช้ Jupyter ผ่าน Docker/Kubernetes

    แนวทางการแก้ไข

    Credit:

    เปิด Terminal แล้วพิมพ์คำสั่งต่อไปนี้ เพื่อปิด เมนู

    # disable downloads from File > Download
    jupyter labextension disable @jupyterlab/docmanager-extension:download
    # disable downloads from the context menu in the file browser
    jupyter labextension disable @jupyterlab/filebrowser-extension:download

    แต่ก็ยังมีทางให้เรียกผ่าน URL ได้อยู่ดี จึงต้อง disable การเรียกผ่าน HTTP protocol ได้ จึงต้องปิดด้วยการปิดการเรียก File handler อีกชั้น โดยประกอบด้วย 2 ขั้นตอน

    1. การแก้ไขไฟล์ $HOME/.jupyter/jupyter_notebook_config.py

    import os, sys
    sys.path.append('$HOME/.jupyter/')
    c.ContentsManager.files_handler_class = 'handlers.ForbidFilesHandler'
    c.ContentsManager.files_handler_params = {}

    2. สร้างไฟล์ $HOME/.jupyter/handlers.py

    # Creating ForbidFilesHandler class, overriding the default files_handler_class
    cat <<END >$HOME/.jupyter/handlers.py
    from tornado import web
    from notebook.base.handlers import IPythonHandler
    
    class ForbidFilesHandler(IPythonHandler):
      @web.authenticated
      def head(self, path):
        self.log.info("HEAD: File download forbidden.")
        raise web.HTTPError(403)
    
      @web.authenticated
      def get(self, path, include_body=True):
        self.log.info("GET: File download forbidden.")
        raise web.HTTPError(403)
    
    END

    จากนั้น restart jupyter container

    ผลคือ

    หวังว่าจะเป็นประโยชน์ครับ

  • [บันทึกกันลืม] kubernetes certificate expired

    ถ้าท่านที่รัน Kubernetes นานพอ ก็จะได้เจอปัญหานี้ พอดี cluster ผมใช้งานมาครบ 365 วันนี้พอดี เราก็มือใหม่ซะด้วยสิ ทีนี้ ว้าวุ่นเลย อิอิ

    ปัญหา

    เมื่อใช้คำสั่งต่าง ๆ บน control plane แล้วได้ error ประมาณนี้

    Unable to connect to the server: x509: certificate has expired or is not yet valid:

    สาเหตุ

    Certificate ของ kubernetes cluster มีวันหมดอายุ และวันนี้มันหมดอายุไปแล้ว

    วิธีตรวจสอบ

    kubeadm certs check-expiration

    วิธีแก้ไข

    kubeadm certs renew all
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

    จาก Managing Expired Certificates in Kubernetes Clusters บอกว่า ให้ restart container ที่เกี่ยวข้องกับ

    kube-apiserver, kube-scheduler, kube-controller-manager, and etcd

    โดยใช้คำสั่ง

    for i in $(crictl ps 2>/dev/null | egrep 'etcd|api|sch|control'| cut -d' ' -f 1) ; do crictl stop $i ;done

    ตรวจสอบผล

    kubeadm certs check-expiration

    หวังว่าจะเป็นประโยชน์

  • [บันทึกกันลืม] แก้ปัญหา kube-flannel เกิด CrashLoopBackOff

    Problem reproduce

    kubectl describe pod/airflow-postgresql-0 -n airflow

    result:

    Warning  FailedCreatePodSandBox  26m                   kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "ad25da9611dd6ae39e9124ccbd497783db28b2e2de333128f18ee148e01952d7": plugin type="flannel" failed (add): loadFlannelSubnetEnv failed: open /run/flannel/subnet.env: no such file or directory

    Resolution

    edit file /run/flannel/subnet.env and paste the content *ON EVERY NODES*:

    FLANNEL_NETWORK=10.244.0.0/16
    FLANNEL_SUBNET=10.244.0.1/24
    FLANNEL_MTU=1450
    FLANNEL_IPMASQ=true

    Hope this help

  • [บันทึกกันลืม] วิธีกำหนดให้ pod สร้างเฉพาะบน node ที่ต้องการ

    Kubernetes cluster สามารถกระจายตัวไปในหลาย ๆ ดาต้าเซนเตอร์ได้ แต่ในบางงาน เช่น การใช้ Airflow ในการเข้าถึงข้อมูลบนระบบฐานข้อมูล ซึ่งจำกัดการเข้าถึงได้เฉพาะจากบาง IP range เท่านั้น สามารถทำได้โดยการกำหนด ‘label’ ให้ nodes ที่ต้องการ และ nodeSelector ของ pods หรือ resources

    วิธีกำหนด label ให้ node

    ใช้คำสั่งต่อไปนี้ เพื่อ label ว่า ‘database-access=true’ ให้ node ชื่อ ‘dc1node1’ ซึ่งเป็น node ที่สามารถเข้าถึงฐานข้อมูลได้

    kubectl label node/dc1node1 database-access=true

    วิธีระบุ Pod/Resource ให้เลือก node ที่ต้องการ

    ใช้คำสั่งเพื่อ edit เช่น

    kubectl edit statefulset.apps/airflow-worker -n airflow

    จากนั้นเลื่อนไปที่

    spec: containers: initContainers: nodeSelector:

    ตั้งค่า

    database-access: "true"

    เมื่อทำมีการ reschedule ก็จะไปใช้ node ที่มี label ตามที่กำหนด

    หวังว่าจะมีประโยชน์ครับ

  • [บันทึกกันลืม] วิธีเพิ่ม Node (Ubuntu 22.04) เข้า Kubernetes cluster (version 1.25.0)

    Adding a new node running Ubuntu 22.04 to Kubernetes version 1.25.0 cluster.

    swapoff -a
    sed -i 's/\/swap.img/#\/swap.img/g' /etc/fstab
    echo 1 > /proc/sys/net/ipv4/ip_forward
    modprobe overlay
    modprobe br_netfilter
    sysctl --system
    apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
    add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
    apt update -y
    apt install -y containerd
    mkdir /etc/containerd
    containerd config default > /etc/containerd/config.toml
    sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
    systemctl restart containerd
    systemctl enable containerd
    apt -y install curl vim git wget apt-transport-https gpg
    mkdir /etc/apt/keyrings
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.25/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.25/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
    apt update -y
    apt install -y  kubelet=1.25.16-1.1 kubeadm=1.25.16-1.1
    apt-mark hold kubelet kubeadm kubectl
    systemctl enable kubelet
    kubeadm join <IP>:6443 --token <TOKEN> --discovery-token-ca-cert-hash sha256:<SHA256>

    Hope this help.

  • [บันทึกกันลืม] ย้าย docker ไปไว้ที่ partition อื่น

    ปัญหา

    ถ้าติดตั้ง docker บน Linux โดยค่าเริ่มต้นจะสร้างที่เก็บพวก image, container และ volumns ต่าง ๆ ไว้ที่ /var/lib/docker เมื่อใช้งานไปเรื่อย ๆ จะทำให้ / เต็ม

    วิธีการแก้ไข

    ควร mount disk partition ใหม่นอก / เข้ามา เช่น ‘/otherpartition’ จาก disk อีกลูก แล้วสร้างไดเรคทอรี่ ‘docker’ แล้ว copy ข้อมูลทั้งหมดจาก /var/lib/docker ไปยัง /otherpartition/docker

    rsync  -apv /var/lib/docker /otherpartition/docker

    จากนั้นสร้างไฟล์

    /etc/docker/daemon.json
    { 
       "data-root": "/otherpartition/docker" 
    }

    จากนั้น restart docker

    systemctl restart docker

    หวังว่าเป็นประโยชน์