Thứ Sáu, 18 tháng 7, 2025

Debug exec pod with no any command support

 Một ngày đẹp trời pod bị lỗi. Bạn thử ngay lệnh "kubectl exec -it ..." vào pod kiểm tra.

Nhưng quãi đạn, pod không hỗ trợ bất kỳ 1 command nào:

  • Không có /bin/bash/bin/sh...???
  • Không có ls, cd...???
  • Không có netstat, telnet, traceroute...???

Ngớ người đặt dấu chấm hỏi, hóa ra pod này dùng images distroless siêu bảo mật (https://github.com/GoogleContainerTools/distroless). Nó giúp gia tăng độ an toàn cho pod tránh khỏi các cuộc tấn công leo thang khi chiếm được quyền điều khiển Pod.

Vậy admin k8s cluster phải làm sao??? -> bạn vẫn còn 1 cứu tinh. Đó chính là kubectl debug để tạo ra Ephemeral Container trong pod đang chạy.

2.Xây dựng

Bước 1: Tạo pod distroless images

vim HelloJava.java

package examples;

public class HelloJava {
    public static void main(String[] args) {
        System.out.println("Hello world");
        int number = 0;

        while (true) {
            System.out.println(number);
            number++;

            try {
                Thread.sleep(1000); // Nghỉ 1 giây (1000 milliseconds)
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }        
    }
}

Thực hiện build image bằng Dockerfile như sau

vim Dockerfile

FROM openjdk:17-jdk-slim AS build-env
COPY . /app/examples
WORKDIR /app
RUN javac examples/*.java
RUN jar cfe main.jar examples.HelloJava examples/*.class 

FROM gcr.io/distroless/java17-debian12
COPY --from=build-env /app /app
WORKDIR /app
CMD ["main.jar"]

docker build -t java-less:v1 .

=> [build-env 2/5] COPY . /app/examples                                                                                                                                                                 3.8s
=> [build-env 3/5] WORKDIR /app                                                                                                                                                                         0.1s
=> [build-env 4/5] RUN javac examples/*.java                                                                                                                                                            3.1s
=> [build-env 5/5] RUN jar cfe main.jar examples.HelloJava examples/*.class                                                                                                                             0.6s
=> [stage-1 2/3] COPY --from=build-env /app /app                                                                                                                                                        0.1s
=> [stage-1 3/3] WORKDIR /app                                                                                                                                                                           0.1s
=> exporting to image                                                                                                                                                                                   0.1s
=> => exporting layers                                                                                                                                                                                  0.1s
=> => writing image sha256:417e708c31976902                                                                                                             0.0s
=> => naming to docker.io/library/java-less:v1   

Sau khi build được images, ta thực hiện đẩy lên docker-hub, private-registry hoặc đẩy local bằng docker save , import ctr.

Với 2 cách đầu quá thường xuyên làm rồi. Tôi sẽ test cách 3.

# Save image ra file và scp sang các server worker-node
docker image save docker.io/library/java-less:v1 > java-less.tar
scp java-less.tar ${IP_OF_WORKER_NODE}

# Import local images vào k8s
ssh ${IP_OF_WORKER_NODE}
ctr -n=k8s.io images ls
ctr -n=k8s.io images import java-less.tar
ctr -n=k8s.io images ls | grep java
#(Kết quả):  docker.io/library/java-less:v1

Ta thực hiện tạo deployment.yaml với imagePullPolicy: Never để load image trực tiếp từ worker-node (không tải từ docker-hub hoặc private registry).

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: app1
  name: app1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
      - image: docker.io/library/java-less:v1
        name: java-less
        imagePullPolicy: Never
kubectl apply -f deployment.yaml
kubectl get pod
#NAME                    READY   STATUS    RESTARTS   AGE
# app1-686584fffd-gsmw8   1/1     Running   0          3s
# app1-686584fffd-lm88h   1/1     Running   0          3s

3.Test tình huống

# Không tồn tại /bin/bash
kubectl exec -it app1-686584fffd-gsmw8 -- /bin/bash
#error: Internal error occurred: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "": OCI runtime exec failed: exec failed: unable to start container process: exec: "/bin/bash": stat /bin/bash: no such file or directory: unknown

# Không tồn tại /bin/sh
kubectl exec -it app1-686584fffd-gsmw8 -- /bin/sh
#OCI runtime exec failed: exec failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory: unknown

# Chỉ hỗ trợ đúng lệnh java
kubectl exec -it app1-686584fffd-gsmw8 -- "java" "-version"
#openjdk version "17.0.15" 2025-04-15

Vậy làm sao để test netstat, ping, ps???

kubectl debug -it ${TÊN_POD} --target=${TÊN_CONAINER} --image=${TÊN_IMAGES_BUSYBOX}
# Lệnh chạy kubectl debug
kubectl debug -it app1-686584fffd-gsmw8 --target=java-less --image=busybox

# ps fauxww
PID   USER     TIME  COMMAND
    1 root      0:00 /usr/bin/java -jar main.jar
  118 root      0:00 sh
  124 root      0:00 ps fauxww


# lsof -p 1
1       /usr/lib/jvm/java-17-openjdk-amd64/bin/java     0       /dev/null
1       /usr/lib/jvm/java-17-openjdk-amd64/bin/java     1       pipe:[580092]
1       /usr/lib/jvm/java-17-openjdk-amd64/bin/java     2       pipe:[580093]
1       /usr/lib/jvm/java-17-openjdk-amd64/bin/java     3       /usr/lib/jvm/java-17-openjdk-amd64/lib/modules
1       /usr/lib/jvm/java-17-openjdk-amd64/bin/java     4       /app/main.jar
118     /bin/sh 0       /dev/pts/0
118     /bin/sh 1       /dev/pts/0
118     /bin/sh 2       /dev/pts/0
118     /bin/sh 10      /dev/tty


# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=111 time=27.020 ms
64 bytes from 8.8.8.8: seq=1 ttl=111 time=27.246 ms

Đã giải quyết xong đầu bài đưa ra. Xong.

Debug exec pod with no any command support

  Một ngày đẹp trời pod bị lỗi. Bạn thử ngay lệnh "kubectl exec -it ..." vào pod kiểm tra. Nhưng quãi đạn, pod không hỗ trợ bất kỳ...