Author: kanakorn.h

  • [บันทึกกันลืม] แก้ปัญหา 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

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

  • [บันทึกันลืม] Shell script เพื่อทำงาน parallel ด้วย screen

    Parellel processing

    เมื่อเราเขียน shell script เพื่อทำหลาย ๆ งานพร้อมกัน เช่น มีข้อมูล 1,000,000 รายการ ถ้าวิธีแบบ Sequential ก็เริ่มจาก 1, 2, 3, …, 1,000,000 ซึ่งก็จะเสียเวลามาก เพราะต้องรอให้ งานที่ 1 เสร็จก่อน แล้วถึงไปทำงานที่ 2, 3 ถ้าแต่ละงานให้เวลา 1 วินาที ก็ต้องใช้เวลา 1,000,000 วินาที กว่าจะเสร็จ

    แต่ถ้าเราแบ่ง เป็น 100 process ย่อย ๆ แต่ละ process จัดการ 10,000 รายการ ก็จะใช้เวลาลดลง (เมื่อ resources เหลือเฟือ) ทั้งนี้ก็ขึ้นกับประสิทธิภาพเครื่องคอมพิวเตอร์ด้วย

    เช่น เรามี process.py หน้าตาประมาณนี้

    import time
    import sys
    def processing(start_position, steps):
        # something blah
        for i in range(start_position, start_position+steps):
            print(f'processing {i}')
            time.sleep(1)
    
    def main():
        start_position=sys.argv[1]
        steps=sys.argv[2]
        processing(start_position, steps)
    
    if __name__ == "__main__":
        main()
    

    เดิมเราก็จะใช้เครื่องหมาย & เพื่อทำให้ไปอยู่ background

    !/bin/bash
    for i in $(seq 1 100); do
        python3 process.py $i 10000 &amp;
    done
    

    ปัญหาคือ เราจะไม่สามารถดูได้ว่า ตอนนี้ แต่ละ process ไปถึงไหนแล้ว

    screen

    screen เป็น Utility ที่ทำให้เราสามารถส่งคำสั่งไปทำงาน แล้วค่อยสลับเข้าไปดูได้ เทคนิคการใช้งานคำสั่ง screen บน Linux

    เราก็เปลี่ยนจากการใช้ & ต่อท้าย เป็น screen แทนดังนี้

    !/bin/bash
    for i in $(seq 1 100); do
        screen -S p$i -dm python3 process.py $i 10000
    done
    
    

    วิธีนี้ ทำให้สามารถใช้คำสั่ง

    screen -ls
    

    และ

    screen -r p1
    

    เพื่อเข้าไปดูว่า ตอนนี้ process p1 ทำงานถึงไหนแล้ว

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

  • [บันทึกกันลืม] วิธีติดตั้ง mariadb package สำหรับ python บน Ubuntu

    เรามักเข้าใจว่าแค่ใข้คำสั่ง

    pip install mariadb

    แล้วจะก็จะเรียกใช้งานได้ แต่จริง ๆ แล้ว ไม่ใช่ เพราะจะต้องติดตั้ง package บน OS (ในที่นี้จะเป็น Ubuntu 20.04 – focal)

    sudo apt install libmariadb3 libmariadb-dev

    แต่จะติดตั้ง package นี้ได้ จะต้องติดตั้ง MariaDB Connector/C Community Server package repository (CS)

    ซึ่งขั้นตอนต้นฉบับของ mariadb นั้น ก็ช่าง …. ซับซ้อน ลิงค์ไปมา

    https://mariadb.com/docs/server/connect/programming-languages/python/install/#Prerequisites_for_Source_Distributions

    https://mariadb.com/docs/server/connect/programming-languages/c/install/

    ซึ่งจุดใหญ่ใจความคือ การติดตั้ง repository ให้ได้ แล้วก็จะติดตั้ง package ได้

    เลยบันทึกกันลืมไว้ที่นี่ copy วางได้เลย

    sudo apt install wget -y
    wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
    echo "367a80b01083c34899958cdd62525104a3de6069161d309039e84048d89ee98b  mariadb_repo_setup" \
        | sha256sum -c -
    chmod +x mariadb_repo_setup
    sudo ./mariadb_repo_setup \
       --os-type='ubuntu' \
       --os-version='focal' \
       --mariadb-server-version="mariadb-10.6"
    sudo apt update -y
    sudo apt install libmariadb3 libmariadb-dev -y
    pip3 install mariadb
    

    เท่านี้แหล่ะ

    Update สำหรับ Ubuntu 22.04

    ไม่รู้ว่าเกี่ยวกับการเป็น Ubuntu pro หรือไม่ แต่ libssl1.1 ไม่สามารถลงตรง ๆ ได้ ต้องทำดังนี้

    wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb
    sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb
    sudo apt install libmariadbclient-dev