# 컨테이너 기초

### Chroot

1. 새로운 루트 디렉토리로 사용할 디렉토리 생성

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

   ```
   sudo chroot ~/environment/new-root
   ```
3. 새로운 루트로 사용할 디렉토리 하위에 bin 디렉토리 생성

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

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

   ```
   sudo chroot ~/environment/new-root
   ```
6. Bash 실행을 위해서 필요한 라이브러리 연관성 확인

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

   ```
   {
       mkdir ~/environment/new-root/lib64

       cp /lib64/libtinfo.so.6 ~/environment/new-root/lib64
       cp /lib64/libc.so.6 ~/environment/new-root/lib64
       cp /lib64/ld-linux-x86-64.so.2 ~/environment/new-root/lib64
   }
   ```
8. 루트 디렉토리 변경 재시도

   ```
   sudo chroot ~/environment/new-root
   ```
9. 현재 작업중인 디렉토리 확인

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

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

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

    ```
    {
        cp /bin/ls ~/environment/new-root/bin
        cp /lib64/libselinux.so.1 ~/environment/new-root/lib64
        cp /lib64/libcap.so.2 ~/environment/new-root/lib64
        cp /lib64/libpcre2-8.so.0 ~/environment/new-root/lib64
    }
    ```
13. 루트 디렉토리 변경

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

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

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

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

<details>

<summary>문제 답안</summary>

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

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

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

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

   ```
   exit
   ```

</details>

### Container Image

1. Docker Hub에 있는 nginx 이미지로 컨테이너 생성&#x20;

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

   ```
   docker container ls -a
   ```
3. nginx 컨테이너에 포함된 파일들을 저장할 디렉토리 생성 &#x20;

   ```
   mkdir ~/environment/nginx
   ```
4. 위에서 생성한 디렉토리로 nginx 컨테이너의 파일들을 복사

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

   ```
   docker inspect $(docker container ls -aq -f name=nginx) --format='{{.Config.Cmd}}'
   ```
6. nginx 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 변경

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

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

   ```
   curl localhost
   ```
9. 연습 문제
   1. 두번째 터미널에서 ubuntu 이미지로 컨테이너를 생성
   2. 해당 컨테이너의 파일들을 \~/environment/ubuntu 로 복사
   3. \~/environment/ubuntu 디렉토리로 루트 디렉토리로 변경. 단 /bin/bash가 아닌 /bin/sh 를 실행

<details>

<summary>문제 답안</summary>

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

   ```
   docker create --name ubuntu ubuntu
   ```
2. ubuntu 컨테이너에 포함된 파일들을 저장할 디렉토리 생성 &#x20;

   ```
   mkdir ~/environment/ubuntu
   ```
3. 위에서 생성한 디렉토리로 ubuntu 컨테이너의 파일들을 복사

   ```
   docker cp $(sudo docker container ls -aq -f name=ubuntu):/ ~/environment/ubuntu
   ```
4. ubuntu 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 변경

   ```
   sudo chroot ~/environment/ubuntu /bin/sh
   ```
5. 현재 작업중인 디렉토리 확인

   ```
   pwd
   ```
6. 파일 목록 확인&#x20;

   ```
   ls
   ```
7. 정상 동작시 새로운 루트 디렉토리로 실행된 sh 프로세스 종료

   ```
   exit
   ```

</details>

### Network Namespace

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

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

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

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

   ```
   sudo ip netns exec nginx ip -br link
   ```
6. nginx 네트워크 네임스페이스의 루프백 인터페이스 구동

   ```
   sudo ip netns exec nginx ip link set dev lo up
   ```
7. nginx 네트워크 네임스페이스를 사용하면서 nginx 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 변경

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

   ```
   nginx -g "daemon off;"
   ```
9. 두번째 터미널로 이동해서 Nginx 웹서버 구동 확인

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

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

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

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

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

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

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

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

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

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

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

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

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

    ```
    sudo ip netns exec nginx ip -br link
    ```
25. nginx 네트워크 네임스페이스를 사용하면서 nginx 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 변경

    ```
    sudo ip netns exec nginx chroot ~/environment/nginx
    ```
26. IP 주소 확인&#x20;

    ```
    hostname -I
    ```
27. Nginx 웹서버 실행&#x20;

    ```
    nginx -g "daemon off;"
    ```
28. 두번째 터미널로 이동해서 IP 주소 확인

    ```
    hostname -I
    ```
29. Nginx 웹서버 구동 확인

    ```
    curl 192.168.1.2
    ```
30. 첫번째 터미널로 이동
31. Ctrl+C를 입력해서 Nginx 프로세스 종료
32. Nginx 접근 로그 확인&#x20;

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

### PID Namespace

1. 첫번째 터미널에서 Nginx 웹서버 구동&#x20;

   ```
   nginx -g "daemon off;"
   ```
2. 두번째 터미널에 ubuntu 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 사용하는 sh 프로세스 실행&#x20;

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

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

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

   ```
   nginx -g "daemon off;"
   ```
7. 만약 nginx 프로세스 재기동에 실패할 경우 세번째 터미널로 이동해서 아래의 명령어로 모든 nginx 프로세스를 종료하고 위의 명령어 재실행

   ```
   sudo pkill nginx
   ```
8. 세번째 터미널로 이동해서 리눅스 네임스페이스 목록 확인

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

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

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

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

    ```
    sudo ls -Li /proc/SH_PID/ns/pid
    ```
13. 두번째 터미널로 이동해서 /proc 파일시스템 마운트

    ```
    {
        chown -R root:root .
        mount -t proc proc /proc
    }
    ```
14. nginx 프로세스의 PID를 확인&#x20;

    ```
    ps aux | grep nginx
    ```
15. ubuntu 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 실행되고 있는 sh 프로세스 종료

    ```
    exit
    ```
16. 새로운 PID 네임스페이스를 생성하고 ubuntu 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 하는 sh 프로세스 실행

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

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

    ```
    ps aux
    ```
19. 세번째 터미널로 이동해서 첫번째 터미널에서 구동중인 nginx 프로세스의 PID 확인

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

    ```
    kill -9 NGINX_PID
    ```
21. 세번째 터미널로 이동해서 PID 네임스페이스 목록 확인

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

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

    ```
    sudo kill -9 SH_PID
    ```
24. 두번째 터미널로 이동해서 sh 프로세스가 종료되었는지 확인&#x20;
25. PID 네임스페이스 목록 확인

    ```
    sudo lsns -t pid
    ```

### Cgroup

1. 두번째 터미널로 이동해서 새로운 PID 네임스페이스를 생성하고 ubuntu 컨테이너 파일들이 저장된 디렉토리를 루트 디렉토리로 하는 sh 프로세스 실행

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

   ```
   {
       mknod /root/null c 1 3
       yes > /root/null
   }
   ```
3. 세번째 터미널로 이동해서 CPU 사용량 확인

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

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

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

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

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

   ```
   sudo cgset -r cpu.max="300000 1000000" ubuntu
   ```
9. CPU 사용량 확인

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

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

    ```
    {
        mknod /root/zero c 1 5
        head -c 1000M /root/zero | tail
    }
    ```

<details>

<summary>문제 답안</summary>

1. 세번째 터미널로 이동해서 메모리 제한량 설정&#x20;

   ```
   sudo cgset -r memory.max=100M ubuntu
   ```
2. 두번째 터미널로 이동해서 메모리 부하 발생

   ```
   {
     mknod /tmp/zero c 1 5
     head -c 1000M /tmp/zero | tail
   }
   ```
3. 메모리 부하를 발생하는 프로세스가 강제 종료될 경우 아래의 명령어로 원인 파악

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

</details>

### 리소스 정리

1. 모든 터미널을 닫고 새로운 터미널 생성
2. 리소스 삭제

   ```
   {
       sudo umount -l ubuntu/proc
       sudo rm -rf new-root nginx ubuntu
       docker container rm $(docker ps -aq)
       sudo cgdelete -g cpu,memory:/ubuntu
       docker image prune --all --force
   }
   ```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://container.youngwjung.com/intro-container.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
