> For the complete documentation index, see [llms.txt](https://kubernetes.youngwjung.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kubernetes.youngwjung.com/overview/intro-container/lab.md).

# 실습

해당 실습은 AWS 환경에서 Ubuntu Server 20.04 LTS 에서 실습을 진행하다고 가정하고 작성되었습니다.

### Install Docker

```
sudo apt update && sudo apt install -y docker.io
```

### Chroot

1. 루트 유저로 전환

   ```
   sudo -i
   ```
2. /tmp 디렉토리 하위에 새로운 루트 디렉토리로 사용할 디렉토리 생성

   ```
   mkdir /tmp/new-root
   ```
3. 위에서 생성한 디렉토리를 루트 디렉토리로 변경 시도

   ```
   chroot /tmp/new-root
   ```
4. 새로운 루트로 사용할 디렉토리 하위에 bin 디렉토리를 생성

   ```
   mkdir /tmp/new-root/bin
   ```
5. 호스트에 있는 /bin/bash 파일을 새로운 루트 디렉토리로 사용할 디렉토리 하위의 bin 디렉토리로 복사

   ```
   cp /bin/bash /tmp/new-root/bin
   ```
6. 루트 디렉토리 변경 재시도

   ```
   chroot /tmp/new-root
   ```
7. bash 명령어 실행에 필요한 연관 라이브러리 파일 확인

   ```
   ldd /bin/bash
   ```
8. 새로운 루트로 사용할 디렉토리로 Bash 프로세스 실행에 필요한 연관 라이브러리 복사&#x20;

   ```
   {
       mkdir /tmp/new-root/lib/x86_64-linux-gnu -p
       mkdir /tmp/new-root/lib64

       cp /lib/x86_64-linux-gnu/libtinfo.so.6 /tmp/new-root/lib/x86_64-linux-gnu
       cp /lib/x86_64-linux-gnu/libdl.so.2 /tmp/new-root/lib/x86_64-linux-gnu
       cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/new-root/lib/x86_64-linux-gnu
       cp /lib64/ld-linux-x86-64.so.2 /tmp/new-root/lib64
   }
   ```
9. 루트 디렉토리 변경 재시도

   ```
   chroot /tmp/new-root
   ```
10. 현재 작업중인 디렉토리 확인

    ```
    pwd
    ```
11. 아래의 명령어를 실행해서 새로운 루트 디렉토리로 실행된 Bash 프로세스 종료

    ```
    exit
    ```
12. 새로운 루트로 사용할 디렉토리 하위에 텍스트 파일 생성

    ```
    date > /tmp/new-root/date.txt
    ```
13. 새로운 루트로 사용할 디렉토리로 /bin/ls 파일 및 ls 프로세스 실행에 필요한 연관 라이브러리 복사

    ```
    {
        cp /bin/ls /tmp/new-root/bin
        cp /lib/x86_64-linux-gnu/libselinux.so.1 /tmp/new-root/lib/x86_64-linux-gnu
        cp /lib/x86_64-linux-gnu/libpcre2-8.so.0 /tmp/new-root/lib/x86_64-linux-gnu
        cp /lib/x86_64-linux-gnu/libpthread.so.0 /tmp/new-root/lib/x86_64-linux-gnu
    }
    ```
14. 루트 디렉토리 변경

    ```
    chroot /tmp/new-root
    ```
15. 위에서 생성한 텍스트파일이 보이는지 확인

    ```
    ls
    ```
16. 현재 작업중인 디렉토리 확인

    ```
    pwd
    ```
17. 새로운 루트 디렉토리로 실행된 Bash 프로세스 종료

    ```
    exit
    ```
18. 새로운 루트로 사용할 디렉토리로 /bin/cat 파일 및 cat 프로세스 실행에 필요한 연관 라이브러리 복사하고 루트 디렉토리를 변경하고 cat 명령어로 텍스트 파일 내용 확인

<details>

<summary>문제 답안</summary>

1. 새로운 루트로 사용할 디렉토리로 /bin/cat 파일 및 cat 프로세스 실행에 필요한 연관 라이브러리 복사

   ```
   cp /bin/cat /tmp/new-root/bin
   ```
2. 루트 디렉토리 변경

   ```
   chroot /tmp/new-root
   ```
3. 위에서 생성한 텍스트 파일 내용 확인

   ```
   cat date.txt
   ```
4. 새로운 루트 디렉토리로 실행된 Bash 프로세스 종료

   ```
   exit
   ```

</details>

### Docker Image

1. 도커 허브에 있는 nginx 이미지로 컨테이너 생성&#x20;

   ```
   docker create --name nginx nginx 
   ```
2. 로컬 호스트에 생성된 컨테이너 목록  확인

   ```
   docker container ls -a
   ```
3. /tmp/nginx 디렉토리 생성 &#x20;

   ```
   mkdir /tmp/nginx
   ```
4. /tmp/nginx 디렉토리로 nginx 컨테이너의 파일들을 복사

   ```
   docker cp $(docker container ls -aq -f name=nginx):/ /tmp/nginx
   ```
5. nginx 컨테이너가 실행될때 수행되는 명령어 확인&#x20;

   ```
   docker inspect $(docker container ls -aq -f name=nginx) --format='{{.Config.Cmd}}'
   ```
6. /tmp/nginx 디렉토리로 루트 디렉토리로 변경

   ```
   chroot /tmp/nginx
   ```
7. Nginx 웹서버 실행&#x20;

   ```
   nginx -g "daemon off;"
   ```
8. 새로운 SSH 세션을 열고 Nginx 웹서버 구동 확인&#x20;

   ```
   curl localhost
   ```
9. 위에서 새로 연결한 SSH 세션에서 ubuntu 이미지로 컨테이너를 생성하고 해당 컨테이너의 파일들을 /tmp/ubuntu 로 복사하고 /tmp/ubuntu 디렉토리로 루트 디렉토리로 변경. 단 /bin/bash가 아닌 /bin/sh 를 실행

<details>

<summary>문제 답안</summary>

1. ubuntu 이미지로 도커 컨테이너 생성

   ```
   sudo docker create --name ubuntu ubuntu
   ```
2. /tmp/ubuntu 디렉토리 생성 &#x20;

   ```
   mkdir /tmp/ubuntu
   ```
3. /tmp/ubuntu 디렉토리로 ubuntu 컨테이너의 파일들을 복사

   ```
   sudo docker cp $(sudo docker container ls -aq -f name=ubuntu):/ /tmp/ubuntu
   ```
4. /tmp/ubuntu 디렉토리로 루트 디렉토리로 변경

   ```
   sudo chroot /tmp/ubuntu /bin/sh
   ```
5. 정상 동작시 새로운 루트 디렉토리로 실행된 sh 프로세스 종료

   ```
   exit
   ```

</details>

### Network Namespace

1. 첫번째 세션에서 Ctrl+C를 입력해서 Nginx 프로세스 종료
2. 새로운 루트 디렉토리로 실행된 Bash 프로세스 종료

   ```
   exit
   ```
3. 새로운 네트워크 네임스페이스 생성

   ```
   ip netns add nginx
   ```
4. 네트워크 네임스페이스 생성 확인

   ```
   ip netns list
   ```
5. 위에서 생성한 네트워크 네임스페이스의 네트워크 디바이스 목록 확인

   ```
   ip netns exec nginx ip -br link
   ```
6. 위에서 생성한 네트워크 네임스페이스의 루프백 인터페이스 구동

   ```
   ip netns exec nginx ip link set dev lo up
   ```
7. 위에서 생성한 네트워크 네임스페이스를 사용하면서 /tmp/nginx 디렉토리로 루트 디렉토리로 변경

   ```
   ip netns exec nginx chroot /tmp/nginx
   ```
8. Nginx 웹서버 실행&#x20;

   ```
   nginx -g "daemon off;"
   ```
9. 두번째 SSH 세션으로 이동해서 Nginx 웹서버 구동 확인

   ```
   curl localhost
   ```
10. 위에서 생성한 네트워크 네임스페이스의 루프백 인터페이스를 통해서 접근 시도

    ```
    sudo ip netns exec nginx curl localhost
    ```
11. 첫번째 SSH 세션으로 이동
12. Ctrl+C를 입력해서 Nginx 프로세스 종료
13. 새로운 루트 디렉토리로 실행된 Bash 프로세스 종료

    ```
    exit
    ```
14. 디폴트 네트워크 네임스페이스에 가상 네트워크 인터페이스 추가

    ```
    ip link add veth0 type veth peer name veth1
    ```
15. 생성된 가상 네트워크 인터페이스 확인&#x20;

    ```
    ip -br link
    ```
16. 디폴트 네트워크 네임스페이스에 생성된 네트워크 디바이스 veth1를 nginx 네트워크 네임스페이스로 이동

    ```
    ip link set veth1 netns nginx
    ```
17. 디폴트 네트워크 네임스페이스의 네트워크 디바이스 목록 확인

    ```
    ip -br link
    ```
18. nginx 네트워크 네임스페이스의 네트워크 디바이스 목록 확인

    ```
    ip netns exec nginx ip -br link
    ```
19. 네트워크 디바이스 veth0에 IP 주소 할당

    ```
    ip addr add 192.168.1.1/24 dev veth0
    ```
20. 네트워크 디바이스 veth1에 IP 주소 할당

    ```
    ip netns exec nginx ip addr add 192.168.1.2/24 dev veth1
    ```
21. 네트워크 디바이스 veth0 구동

    ```
    ip link set dev veth0 up
    ```
22. 네트워크 디바이스 veth1 구동

    ```
    ip netns exec nginx ip link set dev veth1 up
    ```
23. 디폴트 네트워크 네임스페이스의 네트워크 디바이스 상태 확인

    ```
    ip -br link
    ```
24. nginx 네트워크 네임스페이스의 네트워크 디바이스 상태 확인

    ```
    ip netns exec nginx ip -br link
    ```
25. 위에서 생성한 네트워크 네임스페이스를 사용하면서 /tmp/nginx 디렉토리로 루트 디렉토리로 변경

    ```
    ip netns exec nginx chroot /tmp/nginx
    ```
26. Nginx 웹서버 실행&#x20;

    ```
    nginx -g "daemon off;"
    ```
27. 두번째 SSH 세션으로 이동해서 Nginx 웹서버 구동 확인

    ```
    curl 192.168.1.2
    ```
28. 첫번째 SSH 세션으로 이동
29. Ctrl+C를 입력해서 Nginx 프로세스 종료
30. Nginx 접근 로그 확인&#x20;

    ```
    cat /var/log/nginx/access.log       
    ```

### PID Namespace

1. 첫번째 SSH 세션에서 Nginx 웹서버 구동&#x20;

   ```
   nginx -g "daemon off;"
   ```
2. 두번째 SSH 세션에 /tmp/ubuntu를 루트 디렉토리로 사용하는 sh 프로세스 실행&#x20;

   ```
   sudo chroot /tmp/ubuntu /bin/sh
   ```
3. 새로운 SSH 세션을 열고 첫번째 세션에서 구동한 nginx 프로세스의 PID를 확인&#x20;

   ```
   ps aux | grep nginx
   ```
4. 두번째 SSH 세션에서 kill 명령어를 통해서 모든 nginx 프로세스 종료를 시도

   ```
   kill -9 NGINX_PID
   ```
5. 첫번째 SSH 세션으로 이동해서 실제로 nginx 프로세스가 종료되었는지 확인
6. 첫번째 SSH 세션으로 이동해서 종료된 nginx 프로세스를 재기동&#x20;

   ```
   nginx -g "daemon off;"
   ```
7. 세번째 SSH 세션으로 이동해서 리눅스 네임스페이스 목록 확인

   ```
   lsns
   ```
8. nginx 프로세스의 PID를 확인&#x20;

   ```
   ps aux | grep nginx
   ```
9. nginx 프로세스가 실행되는 PID 네임스페이스 확인

   ```
   sudo ls -Li /proc/NGINX_PID/ns/pid
   ```
10. sh 프로세스의 PID를 확인

    ```
    ps aux | grep /bin/sh
    ```
11. sh 프로세스가 실행되는 PID 네임스페이스 확인

    ```
    sudo ls -Li /proc/SH_PID/ns/pid
    ```
12. 두번째 SSH 세션으로 이동해서 /proc 파일시스템 마운트

    ```
    mount -t proc proc /proc
    ```
13. nginx 프로세스의 PID를 확인&#x20;

    ```
    ps aux | grep nginx
    ```
14. /tmp/ubuntu 디렉토리로 루트 디렉토리로 실행되고 있는 sh 프로세스 종료

    ```
    exit 
    ```
15. 새로운 PID 네임스페이스를 생성하고 /tmp/ubuntu 디렉토리로 루트 디렉토리로 하는 sh 프로세스 실행

    ```
    sudo unshare --pid --fork chroot /tmp/ubuntu /bin/sh
    ```
16. /proc 파일시스템 마운트

    ```
    mount -t proc proc /proc
    ```
17. 실행중인 프로세스 목록 확인&#x20;

    ```
    ps aux
    ```
18. 세번째 세션으로 이동해서 첫번째 세션에서 구동중인 nginx 프로세스의 PID 확인

    ```
    ps aux | grep nginx
    ```
19. 두번째 SSH 세션으로 (PID가 격리된 ubuntu 환경) 이동해서 nginx 프로세스 종료 시도 &#x20;

    ```
    kill -9 NGINX_PID
    ```
20. 세번째 SSH 세션으로 이동해서 PID 네임스페이스 목록 확인

    ```
    sudo lsns -t pid
    ```
21. sh 프로세스의 PID를 확인

    ```
    ps aux | grep /bin/sh
    ```
22. sh 프로세스 종료 시도

    ```
    sudo kill -9 SH_PID
    ```
23. PID 네임스페이스 목록 확인

    ```
    sudo lsns -t pid
    ```

### Cgroup

1. 두번째 SSH 세션으로 이동해서 새로운 PID 네임스페이스를 생성하고 /tmp/ubuntu 디렉토리로 루트 디렉토리로 하는 sh 프로세스 실행

   ```
   sudo unshare --pid --fork chroot /tmp/ubuntu /bin/sh
   ```
2. 아래와 같은 명령어를 실행해서 CPU 부하를 발생

   ```
   mknod /dev/null c 1 3
   yes > /dev/null
   ```
3. 세번째 SSH 세션으로 이동해서 CPU 사용량 확인

   ```
   top
   ```
4. cgroup-tools 설치

   ```
   sudo apt install cgroup-tools -y
   ```
5. 새로운 cgroup 생성&#x20;

   ```
   sudo cgcreate -g cpu,memory,blkio,devices,freezer:/ubuntu
   ```
6. 격리된 ubuntu 환경에서 실행중인 sh 프로세스의 PID를 확인

   ```
   ps aux | grep /bin/sh
   ```
7. sh 프로세스에  위에서 생성한 cgroup 부여&#x20;

   ```
   sudo cgclassify -g cpu,memory,blkio,devices,freezer:ubuntu SH_PID
   ```
8. CPU 사용률을 30%로 제한&#x20;

   ```
   sudo cgset -r cpu.cfs_quota_us=30000 ubuntu
   ```
9. CPU 사용량 확인

   ```
   top
   ```
10. 두번째 SSH 세션으로 이동해서 실행중인 프로세스를 종료
11. CPU 부하를 다시 발생시키고 CPU 사용률이 30%로 제한되는지 확인&#x20;

    ```
    yes > /dev/null
    ```
12. 메모리 사용량을 100M로 제한하고 아래와 같은 명령어를 실행해서 확인&#x20;

    ```
    yes | tr \\n x | head -c 1048576000 | grep n
    ```

<details>

<summary>문제 답안</summary>

```
sudo cgset -r memory.limit_in_bytes=100M ubuntu
```

메모리 부하를 발생하는 프로세스가 강제 종료될 경우 아래의 명령어로 원인 파악

```
dmesg | tail -n 100
```

</details>
