บันทึกการเรียนรู้ K3S และ Helm
Medium นี้ เป็นบันทึกการเรียนรู้ K3S และ Helm ของผมในสัปดาห์นี้นะครับ โดยแผนการเรียนรู้ของผมมีรายละเอียดตามในรูปด้านล่างนี้ นะครับ
สำหรับท่านที่จะอ่านบทความนี้, เพื่อให้มีพื้นฐาน kube ก่อน, ผมแนะนำให้อ่านอันนี้ก่อนนะครับ
https://medium.com/t-t-software-solution/%E0%B8%AA%E0%B8%A3%E0%B8%B8%E0%B8%9B%E0%B8%88%E0%B8%B2%E0%B8%81%E0%B8%97%E0%B8%B5%E0%B9%88%E0%B9%80%E0%B8%A3%E0%B8%B5%E0%B8%A2%E0%B8%99-kube-free-class-%E0%B9%82%E0%B8%94%E0%B8%A2-jumpbox-6ff1e53acac0
สำหรับรูปน้องซีโน่ เป็นภาพประกอบเฉยๆ ไม่เกี่ยวข้องกับเนื้อหานะครับ ผมเห็นน่ารักดี เลยเอามาใส่
เตรียม VM และติดตั้ง Ubuntu 24
ผมได้เลือกใช้การติดตั้ง Linux บน VM เพราะว่า อนาคตจะลองเล่นให้มีหลายๆ node และจะลองเชื่อมกันนะครับ, แต่บทความนี้ จะเล่นบน Control Plane ที่เดียว นะครับ
ในการใช้งาน VM บน window ผมเลือกใช้ virtualbox นะครับ โดยสามารถ downlaod ได้จากที่นี่ครับ https://www.virtualbox.org/
เมื่อดาวโหลดมาแล้ว ติดตั้งให้เรียบร้อย จากนั้น ไปเอา Ubuntu ISO มาจากที่นี่
จากนั้น ทำการติดตั้ง Ubuntu 24 ลงใน VM ดังนี้ครับ
ในการใช้งาน ให้กำหนดค่า Network เป็น Bridged Adapter นะครับ
เมื่อติดตั้ง และ restart แล้ว, ให้ตรวจสอบ IP โดยใช้คำสั่งนี้นะครับ
ip addr show
ให้ดูตรงแถวๆสีแดง หรืออื่นๆ แล้วแต่ว่า จะได้ IP อะไรมานะครับ
จากนั้นให้ลอง ssh เข้าไป ถ้าโอเค ก็จะได้ตามรูปนี้ครับ, สำหรับผม ได้ IP 192.168.1.74 มานะคับ
ติดตั้ง K3S
ผมได้ดำเนินการติดตั้ง K3S โดยให้ GPT มันช่วยแนะนำ ซึ่งมีขั้นตอนดังนี้
Installing K3s on Ubuntu 24 is a straightforward process. K3s is a lightweight Kubernetes distribution designed to be easy to install, especially for development and edge computing environments. Below is a step-by-step guide on how to install K3s on Ubuntu 24.
Step 1: Prepare the System
Update the System Ensure your system is up to date before starting the installation:
sudo apt update && sudo apt upgrade -y
Disable Swap (Kubernetes requires that swap is disabled) If swap is enabled, you will need to disable it:
sudo swapoff -a
To permanently disable swap, open the /etc/fstab file and comment out any swap entries:
sudo nano /etc/fstab
Comment out the line related to swap by adding a # at the beginning.
Step 2: Install K3s
Install K3s
The easiest way to install K3s is to use the official installation script. It automatically installs the necessary components and sets up the K3s cluster.
Run the following command to install K3s:
curl -sfL https://get.k3s.io | sh -
The script will download and install K3s along with all its dependencies. Once the installation is complete, the K3s service will be started automatically.
Verify the Installation
After installation, K3s should be running as a systemd service. You can check the status with the following command:
sudo systemctl status k3s
To verify that Kubernetes is running correctly and check the nodes, use kubectl (K3s automatically installs kubectl):
sudo kubectl get nodes
You should see your server node listed as Ready.
กำหนดค่า IP ให้กับ K3S
คือสืบเนื่องจาก เราใช้ VM ผ่าน network ของ window ซึ่ง มันอาจจะมีการเปลี่ยน IP ไปมาได้ ดังนั้น เราจึงต้องรู้วิธีการกำหนดให้ Kube มันรู้จัก IP ด้วย, โดยสำหรับ K3S มันกำหนดค่อนข้างง่าย แตกต่างจากรอบที่ผมลงผ่าน Kubeadm ซึ่งผมไม่ทราบวิธีเปลี่ยน IP ด้วยการลงแบบนั้น
Here’s how you can modify the ExecStart command in the k3s.service file to include IP-specific options:
Edit the k3s.service File:
Open the service file with a text editor:
sudo nano /etc/systemd/system/k3s.service
Add IP Configuration:
In the ExecStart line, you can add flags such as -node-ip or -advertise-address to specify which IP address K3s should use. Suppose your new static IP is 192.168.1.100, you might modify the line like this:
ExecStart=/usr/local/bin/k3s \
server \
--node-ip=192.168.1.74 \
--advertise-address=192.168.1.74
Adjust the IP address as per your requirements.
Save and Close the File:
After making the changes, save the file and exit the editor.
Reload and Restart K3s Service:
Reload the systemd configuration and restart K3s to apply the changes:
sudo systemctl daemon-reload
sudo systemctl restart k3s
Verify the Changes:
Check that K3s is using the new IP address:
sudo kubectl get nodes -o wide
This will show the IP addresses being used by the nodes.
ใช้งาน k3s ด้วย sudo su
บางครั้ง ถ้าเจอแบบนี้
nakorn@k3s01:/$ kubectl get pod
error: error loading config file "/etc/rancher/k3s/k3s.yaml": open /etc/rancher/k3s/k3s.yaml: permission denied
nakorn@k3s01:/$ kubectl get node
error: error loading config file "/etc/rancher/k3s/k3s.yaml": open /etc/rancher/k3s/k3s.yaml: permission denied
เหตุผลมันคือ
If you use the k3s setup for anything professional, such as an IOT solution, edge or anything else in an environment where you do not want unwanted access to this machine: keep using the sudo
command. With above steps you are removing a layer of security from your setup.
If you use the k3s environment for a quick test lab to prepare for certification, tests, playground etc. Then it is probably fine to use above commands. But please stay aware of the role and the use-case of the machine. If it leaves your supervision, wipe it and set it up again.
reference https://0to1.nl/post/k3s-kubectl-permission/
ดังนั้น ผมจึง ตัดสินใจเลือกใช้ sudo su เมื่อทำงานกับ k3s สำหรับการทดสอบ นะครับ
ติดตั้ง Helm
ในบทความนี้ จะเป็นการทำเพื่อการศึกษาเท่านั้น, ผมจึงรันคำสั่งด้วย root ไปเลยนะครับ โดยทำดังนี้ก่อน
sudo su
จากนั้นจึงติดตั้ง Helm ตามขั้นตอนดังนี้
Here’s a step-by-step guide to install Helm in K3s on Ubuntu 24:
Step 1: Update Ubuntu 24
First, ensure that your system is up to date.
sudo apt update && sudo apt upgrade -y
Step 2: Install Helm
Download Helm binary
To install Helm, first download the latest release.
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
รันคำสั่งนี้
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
Verify Helm Installation
After installation, verify Helm by checking the version:
helm version
You should see output confirming Helm’s installation.
This setup should enable you to manage your Kubernetes cluster on Ubuntu 24 using Helm with K3s.
กำหนดค่า KUBECONFIG environment
ถ้าคุณพบ error จากการรันคำสั่งของ helm เช่นข้างล่างนี้
มันเกิดจาก helm ต้องการเข้าถึง kube โดยมันจะไปอ่านค่าจาก environment variable ชื่อ KUBECONFIG ดังนั้น เราสามารถแก้ไข ได้โดยรันคำสั่งนี้
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
คำอธิบาย
The KUBECONFIG
environment variable is used to specify the location of the kubeconfig file, which is necessary for kubectl
to know how to connect to a Kubernetes cluster. The kubeconfig file contains configuration information such as cluster details, credentials, and namespaces, allowing kubectl
to authenticate and communicate with the Kubernetes cluster.
Here’s why you need to export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
:
- Default Config Path: By default, kubectl looks for a kubeconfig file in ~/.kube/config. If your kubeconfig file is located somewhere else, such as /etc/rancher/k3s/k3s.yaml (which is common for K3s), you need to tell kubectl where to find it using the KUBECONFIG environment variable.
- Multiple Config Files: If you’re working with multiple clusters, you may have different kubeconfig files for each cluster. Setting the KUBECONFIG variable allows you to switch between configurations easily by pointing to different kubeconfig files.
- Non-standard Setup: In some cases, especially in managed Kubernetes environments like K3s, the kubeconfig file is located in a system directory (e.g., /etc/rancher/k3s/k3s.yaml) instead of the default user directory (~/.kube/config). Exporting the KUBECONFIG environment variable ensures that kubectl uses the correct file for authentication and cluster connection.
By running export KUBECONFIG=/etc/rancher/k3s/k3s.yaml, you’re instructing kubectl to use this specific kubeconfig file to interact with the K3s cluster.
อย่างไรก็ตาม หากต้องการให้มันมีค่า KUBECONFIG ทุกครั้งที่ restart เครื่องขึ้นมา ให้รันคำสั่งดังนี้
This way, the KUBECONFIG will be set for every session.
echo 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml' >> ~/.bashrc
source ~/.bashrc
ทดสอบ Helm สามารถใช้งานได้
ในขั้นต่อไปนี้ เราจะตรวจสอบว่า Helm สามารถใช้งานได้แล้วหรือยัง โดยทดลองลง nginx ผ่าน Helm ครับ
Step 5: Add Helm Repositories
Helm uses repositories to store charts. You can add the stable repository using the following command:
helm repo add bitnami https://charts.bitnami.com/bitnami
Step 6: Test Helm with K3s
To test that Helm is working with K3s, you can deploy an example chart. For instance, install an NGINX chart:
helm install my-nginx bitnami/nginx
Check the deployed service using:
sudo k3s kubectl get all
ดูดีๆ ว่า Helm มันกำหนด Label อะไรมาให้ pod
ในหัวข้อถัดไปเกี่ยวกับ NodePort ให้ตรวจสอบให้ดีก่อนว่า Label ต่างๆใน pod เป็นอย่างไร เพื่อใช้ในการอ้างอิง
kubectl get pod
kubectl describe pod [pod ของคุณ]
Nginx with NodePort
มาลองใช้ NodePort เพื่อให้ window pc สามารถเข้าถึง nginx ได้ กันครับ
To access your NGINX service via NodePort, you’ll need to expose the NGINX pod as a service using the NodePort type. Here’s how you can do it:
Step 1: Create a NodePort Service for NGINX
Create a YAML file to define the NodePort service for your NGINX deployment.
Create a file called nginx-nodeport-service.yaml:
nano nginx-nodeport-service.yaml
Add the following configuration:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
spec:
type: NodePort
selector:
app.kubernetes.io/name: nginx # This should match the label of your nginx pod
ports:
- protocol: TCP
port: 80 # The port the service will expose inside the cluster
targetPort: 8080 # The port your NGINX container is listening on (from your pod description)
nodePort: 30001 # This is the NodePort that will be exposed to the outside (choose a port between 30000-32767)
Save the file and apply the service:
kubectl apply -f nginx-nodeport-service.yaml
You should see the nginx-service listed with type NodePort and the specified nodePort (in this case 30001).
Example output:
kubectl get svc
เมื่อเข้า URL http://192.168.1.74:30001/ จากเครื่อง window คุณก็จะสามารถเข้าถึง nginx ได้ ดังนี้
Nginx with ingress
มาลองใช้ ingress ในการเข้าถึง nginx ผ่าน window กันครับ
ingress มันจะชี้ไปที่ service ดังนั้น ให้เราตรวจสอบก่อนว่า เราจะให้ ingress มันชี้ไปที่ service ดังนี้
kubectl get svc
จากในรูปข้างล่าง เราจะให้มันชี้ไปที่ my-nginx กันครับ
Create an Ingress resource:
Create a file called nginx-ingress.yaml:
nano nginx-ingress.yaml
เขียนเนื้อหานี้ลงไป
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-nginx-ingress
namespace: default
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
rules:
- host: nginx.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-nginx
port:
number: 80
tls:
- hosts:
- nginx.local
secretName: my-nginx-tls
Apply the Ingress Resource: Run the following command to apply the ingress file:
kubectl apply -f nginx-ingress.yaml
ตรวจสอบว่ามี ingress ที่สร้างขึ้น เกิดขึ้นหรือไม่
kubectl get ingress
ตัวอย่างการรรัน เพื่อตรวจสอบ
จากนั้น แก้ไข host file ใน window
Update hosts
on your local machine: On your Windows PC, open the /etc/hosts
file (usually located in C:\Windows\System32\drivers\etc\hosts
) and add the following line:
192.168.1.74 nginx.local
เมื่อสำเร็จ ให้ลองเข้า http://nginx.local จากเครื่อง window ก็จะสามารถเข้าถึงได้
รู้จักกับ artifacthub.io
ผมให้ GPT มันช่วยอธิบายเป็นภาษาไทยให้ แต่ดูมันน่าจะยังไม่เก่งภาษาไทยมาก ลองอ่านกันดูนะครับ, ไว้วันหลังจะลองใช้ Claude AI ที่มีคนสปอยมาว่า มันเก่งภาษาไทยมากกว่า
Artifact Hub เป็นแพลตฟอร์มที่ใช้สำหรับการค้นหา การติดตั้ง และการจัดการแพ็คเกจสำหรับโครงการต่าง ๆ ใน Kubernetes หรือโครงการที่เกี่ยวข้องกับระบบคลาวด์ โดยเฉพาะการใช้ Kubernetes และ Helm Charts เป็นหลัก
การใช้งาน Artifact Hub
ค้นหาแพ็คเกจ: Artifact Hub ช่วยให้คุณค้นหาและตรวจสอบแพ็คเกจหรือโปรเจ็กต์ต่าง ๆ ที่คุณสามารถนำมาใช้ในระบบของคุณได้ ตัวอย่างเช่น Helm Charts ซึ่งเป็นแพ็คเกจที่ช่วยจัดการการติดตั้งแอปพลิเคชันใน Kubernetes โดยตอนค้นหา ก็ติกตรงสีแดง ด้วยก็ดีครับ
ดูคำสั่งติดตั้งแพ็คเกจ: คุณสามารถใช้ Artifact Hub เพื่อดาวน์โหลดและติดตั้งแพ็คเกจในระบบของคุณ โดยใช้คำสั่งและขั้นตอนที่มีการระบุไว้ในแต่ละโปรเจ็กต์ ตัวอย่างเช่น คำสั่ง helm install
สำหรับติดตั้ง Helm Chart.
Artifact Hub เป็นเครื่องมือที่มีประโยชน์มากสำหรับนักพัฒนาและผู้ดูแลระบบที่ทำงานกับ Kubernetes ช่วยให้การจัดการแพ็คเกจง่ายขึ้นและสะดวกยิ่งขึ้น
ติดตั้ง pgadmin
ให้ทำการค้นหา pgadmin จากใน artifacthub.io สำหรับผมได้เลือกอันข้างล่างนี้มาครับ
https://artifacthub.io/packages/helm/arunalakmal/pgadmin
จากนั้น ทำการเปิดดูคำสั่งที่ใช้ติดตั้ง
จากนั้น เราก็มาลองกันเลยครับ, ก็คือรันตามกรอบแดงนะครับ เสร็จแล้ว ก็จะได้ แบบนี้
มาตรวจสอบกันว่า มีอะไรใหม่ โผล่มาบ้าง ลองรันคำสั่งดังนี้
kubectl get pod | grep pgadmin
kubectl get svc | grep pgadmin
จะพบผลลัพท์ ดังนี้
อธิบาย kubectl port-forward command
ข้อสังเกตุหนึ่ง จากการติดตั้ง pgadmin ผ่าน helm, เราจะพบคำแนะนำตามกรอบแดง
นี่คือ ชุดคำสั่งตามที่เขาแนะนำมา
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=pgadmin,app.kubernetes.io/instance=my-pgadmin" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT
เมื่อลองทำตามดู จะพบดังนี้
เมื่อรันคำสั่ง kubectl port-forward มันจะทำการสร้าง tunnel ชั่วคราวขึ้นมาให้ ซึ่งสามารถเข้าถึงได้ภายใน local mechine เท่านั้น ตามสีเขียว, เมื่อเราปิดมันโดย Ctrl+c เราก็จะเข้าไม่ได้แล้ว ตามสีแดง, ข้างล่างนี้ คือคำอธิบายจาก GPT
The command kubectl -n default port-forward $POD_NAME 8080:$CONTAINER_PORT
is used to forward a port from your local machine to a specific port on a container running inside a Kubernetes pod.
the port-forward
command does not create a Kubernetes Service for you. It simply forwards traffic from a port on your local machine to a port on a specific pod, allowing you to interact with the application running inside the pod as if it were running locally.
ดังนั้น การใช้คำสั่ง kubectl port-forward จึงไม่ใช่วิธีสำหรับการใช้งานถาวรนะครับ
จัดทำ NodePort ให้ pgadmin
ตรวจสอบก่อนว่า label ต่างๆของ pgadmin service เป็นอย่างไร
kubectl get svc | grep pgadmin
kubectl describe svc my-pgadmin
To create a NodePort service for your my-pgadmin
deployment, you can use the following YAML file. The current service is of type ClusterIP
, and we will modify it to be of type NodePort
to expose it outside the cluster.
nano my-pgadmin-nodeport.yaml
Here’s the service definition for your my-pgadmin
service:
my-pgadmin-nodeport.yaml
:
apiVersion: v1
kind: Service
metadata:
name: my-pgadmin
namespace: default
spec:
type: NodePort
selector:
app.kubernetes.io/name: pgadmin
app.kubernetes.io/instance: my-pgadmin
ports:
- protocol: TCP
port: 80 # The port exposed by the service
targetPort: 80 # The port exposed by the container (inside the pod)
nodePort: 30002 # The port on the node where the service will be accessible
Run the following command to apply the service:
kubectl apply -f my-pgadmin-nodeport.yaml
เมื่อรันแล้วจะพบว่า มี my-pgadmin service ที่เป็น NodePort แสดงขึ้นมาดังรูป
เมื่อเข้าผ่าน browser จาก window จะเข้าได้ดังนี้
แล้วจะเอารหัสผ่านจากที่ไหน?
ตอนที่เข้ามาที่ http://192.168.1.74:30002/ ผมก็สับสนว่าจะเอารหัสผ่านจากที่ไหนดี สุดท้ายให้กลับไปดูที่ artifacthub.io มันจะมีส่วนที่เป็น DEFAULT VALUES อยู่ครับ
เมื่อเรากดดู และเลื่อนดูเรื่อยๆ ก็จะพบ default credential ดังนี้
เมื่อลองใช้งาน ก็จะใช้เข้าไปได้ ดังนี้
ติดตั้ง Postgres Database
ผมได้ลองหา postgres และตัดสินใจใช้ตัวนี้นะครับ
อนึ่ง, จริงๆแล้ว ตอนแรก ผมใช้ postgres ของ binami ครับ แต่ปรากฏว่า ติดปัญหาการใช้งาน ซึ่งยังแก้ไขไม่ได้, เลยมาใช้ตัวนี้ก่อนครับ
เมื่อดู INSTALL ของมันแล้ว ก็มาลุยกันเลยครับ
เมื่อตรวจสอบ pod และ service พบดังนี้ครับ
เมื่อดู DEFAULT VALUE จากใน Artifact Hub จะเจอดังนี้ครับ
เข้าไปดู Postgres ด้วย PGadmin
จากใน pgadmin ให้เข้าไปเพิ่ม server ดังนี้ครับ
หลังจากนั้น ก็ใส่รายละเอียดลงไป, หากสำเร็จ มันก็จะกดบันทึก แล้วแสดงด้านซ้ายได้ ก็แปลว่า pgadmin มันเชื่อมกับ postgres ได้แล้ว, โดย 10.43.219.50 มันคือ ClusterIP ของ postgres นะครับ
อย่างไรก็ตาม, ตรง Hostname/address เราจะใส่ my-postgres ก็ connect ได้ เช่นกัน
เป็นอันว่า เราเชื่อมต่อไปยัง postgres จาก pgadmin ได้เรียบร้อยแล้ว นะครับ
ClusterIP และ DNS ใน Kube
ในการที่ pgadmin และ postgres มันสามารถคุยกันได้นั้น, มันมีเหตุผลมาจาก ClusterIP และ Service Name Resolution (DNS นั่นแหละ) ใน Kube ซึ่ง GPT มันได้อธิบายมาให้ดังนี้, กำหนดให้ใน kube มีรายการอ้างอิง ดังต่อไปนี้
The ClusterIP
and service resolution in Kubernetes, like in your case with PostgreSQL (my-postgres
) and pgAdmin, work through internal DNS provided by Kubernetes. Here's how it works:
- ClusterID (ClusterIP): Every service in your Kubernetes cluster is automatically assigned a
ClusterIP
, which is an internal IP address that is only accessible within the cluster. In your case:
my-postgres has a ClusterIP of 10.43.219.50.
my-pgadmin has a ClusterIP of 10.43.185.63.
2. These IPs allow internal pods and services to communicate with each other. You can access my-postgres
from pgAdmin using this ClusterIP
(10.43.219.50
).
3. Service Name Resolution: Kubernetes has an internal DNS system, which means services can be accessed by their names as well. In your case, PostgreSQL is exposed as a service called my-postgres
, and pgAdmin can resolve this name to the corresponding ClusterIP (10.43.219.50
).
4. When you’re using my-postgres
, Kubernetes' DNS automatically resolves this to the correct internal IP (10.43.219.50
), making it easier to manage services without dealing directly with IPs. This is why you can access PostgreSQL using either 10.43.219.50
(the direct IP) or my-postgres
(the service name).
Summary:
- ClusterIP is an internal IP for a service accessible only within the cluster.
- Service Name (
my-postgres
) is resolved by Kubernetes' DNS to its corresponding ClusterIP, making it possible to access services by name or IP.
Helm common command
ผมได้ขอให้ GPT มันช่วยสรุป Helm common command มาให้ เพื่อจะเก็บไว้ใช้เร็วๆ ในอนาคต, มันก็สรุปมาให้แบบนี้นะครับ
สรุปถึงจุดนี้
สิ่งที่ได้เรียนรู้จากการศึกษารอบนี้
- ติดตั้ง K3S
- ติดตั้ง Helm
- ติดตั้ง nginx ผ่าน helm
- รู้จักกับ Artifect Hub
- ติดตั้ง pgadmin ผ่าน helm
- ติดตั้ง postgres ผ่าน helm
- ทำความเข้าใจสิ่งต่างๆใน kube ได้แก่ Ingress, Service, NodePort, PortForward, Helm, Configuration บางอย่างที่เกี่ยวกับ Kube
อย่างไรก็ตาม มีสิ่งตกค้าง ที่ทำไม่สำเร็จในรอบนี้ได้แก่
- การใช้ Traefik เพื่อรันเป็น HTTPS โดยใช้ let’s encrypt ทำไม่สำเร็จ ติดปัญหา the router default-nginx-ingress-nginx-local@kubernetes uses a non-existent resolver: letsencrypt
- ใช้ postgres ที่มาจาก binami ไม่สำเร็จ เพราะ assign credential เข้าไปไม่ได้
ไว้เดี๊ยวมาลองใหม่ โอกาศหน้าครับ, ขอฝากคำคมจาก Jumpbox ที่ผมชอบ เพื่อเป็นกำลังใจให้ทุกคนนะครับ