# 도커 기초

### Introduction

1. Docker가 설치되어 있는지 확인

   ```
   docker --version
   ```
2. 생성된 모든 컨테이너 목록 확인

   ```
   docker container ls -a
   ```
3. Docker 실행 옵션 확인 - [Docker 구조](https://docs.docker.com/get-started/overview/#docker-architecture)&#x20;

   ```
   sudo systemctl status docker.service --no-pager
   ```
4. containerd 상태 확인 - <https://www.docker.com/blog/docker-engine-1-11-runc/>

   ```
   sudo systemctl status containerd.service --no-pager
   ```
5. Docker CLI로 컨테이너 생성

   ```
   docker container run --name nginx --detach --publish 8080:80 nginx
   ```
6. 현재 실행중인 컨테이너 목록 확인

   ```
   docker container ls
   ```
7. 로컬호스트에 연동된 포트로 HTTP 요청&#x20;

   ```
   curl localhost:8080
   ```
8. runc가 생성한 컨테이너 확인

   ```
   sudo runc --root /run/docker/runtime-runc/moby list
   ```
9. 컨테이너를 통해서 실행된 프로세스 확인&#x20;

   ```
   sudo runc --root /run/docker/runtime-runc/moby ps \
   $(sudo runc --root /run/docker/runtime-runc/moby list -q)
   ```
10. 위에서 생성한 컨테이너 삭제 시도&#x20;

    ```
    docker container rm nginx
    ```
11. 실행중인 컨테이너 정지

    ```
    docker container stop nginx
    ```
12. 컨테이너 삭제&#x20;

    ```
    docker container rm nginx
    ```
13. 생성된 모든 컨테이너 목록 확인

    ```
    docker container ls -a
    ```
14. 지난 30분간 Docker에서 발생한 이벤트 확인

    ```
    docker system events --since '30m' --until $(date +%s)
    ```

### 컨테이너 이미지 구조

1. Apache 컨테이너 이미지 다운로드

   ```
   docker image pull apache
   ```
2. [Docker Hub](https://hub.docker.com/)에서 Apache 컨테이너 이미지 검색
3. Apache 컨테이너 이미지 다운로드

   ```
   docker image pull httpd
   ```
4. Docker Hub에서 *latest* 태그를 가진 Apache 컨테이너 이미지의 상세 내용 확인
5. Docker Hub에서 *alpine* 태그를 가진 Apache 컨테이너 이미지의 상세 내용 확인
6. Alpine 리눅스를 사용하는 Apache 컨테이너 이미지 다운로드

   ```
   docker image pull httpd:alpine
   ```
7. 로컬호스트에 저장된 컨테이너 이미지 확인

   ```
   docker image ls
   ```
8. *alpine* 태그를 가진 Apache 컨테이너 이미지의 상세 내용 확인

   ```
   docker image inspect httpd:alpine
   ```
9. *alpine* 태그를 가진 Apache 컨테이너 이미지 삭제&#x20;

   ```
   docker image rm httpd:alpine
   ```
10. *bookworm* 태그를 가진 NGINX 컨테이너 이미지 다운로드

    ```
    docker image pull nginx:bookworm
    ```
11. 로컬호스트에 저장된 컨테이너 이미지 확인

    ```
    docker image ls
    ```
12. *bookworm* 태그를 가진 NGINX 컨테이너 이미지 삭제

    ```
    docker image rm nginx:bookworm
    ```
13. 새로운 컨테이너 이미지 빌드

    ```
    cat <<EOF | docker image build -t flask -
    FROM python
    RUN apt update && apt install -y curl
    RUN useradd developer
    CMD ['python']
    RUN pip install Flask
    EOF
    ```
14. 로컬호스트에 저장된 컨테이너 이미지 확인

    ```
    docker image ls
    ```
15. 컨테이너 이미지 빌드에 사용한 베이스 이미지 다운로드&#x20;

    ```
    docker image pull python
    ```
16. python과 flask 이미지의 Layer 비교

    ```
    diff <(docker image inspect python:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') <(docker image inspect flask:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') -y
    ```
17. flask 이미지의 상세 내용 확인

    ```
    docker image inspect flask:latest 
    ```
18. 마지막에 수행되는 명령만 변경해서 새로운 이미지 빌드

    ```
    cat <<EOF | docker image build -t boto3 -
    FROM python
    RUN apt update && apt install -y curl
    RUN useradd developer
    CMD ['python']
    RUN pip install boto3
    EOF
    ```
19. flask와 boto3 이미지의 Layer 비교

    ```
    diff <(docker image inspect flask:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') <(docker image inspect boto3:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') -y
    ```
20. 이미지 삭제&#x20;

    ```
    docker image prune -a --force
    ```

### 이미지 생성 및 공유

1. 데모 애플리케이션 소스코드 다운로드

   ```
   cd ~/environment && git clone https://github.com/youngwjung/express-hello-world.git && cd express-hello-world
   ```
2. 애플리케이션 구동에 필요한 라이브러리 설치

   ```
   npm install
   ```
3. 애플리케이션 구동

   ```
   node app.js
   ```
4. 새로운 터미널을 열고 웹 애플리케이션이 구동하는지 확인

   ```
   curl -w "\n" localhost:8080
   ```
5. 기존 터미널로 돌아와서 `Ctrl+C` 를 입력해서 애플리케이션 정지
6. Dockerfile 리뷰&#x20;
7. 컨테이너 이미지 빌드

   ```
   docker image build -t express-hello-world .
   ```
8. 컨테이너 실행

   ```
   docker container run --name hello-world -d -p 8080:3000 express-hello-world
   ```
9. 컨테이너가 정상적으로 실행 되었는지 확인

   ```
   curl -w "\n" localhost:8080
   ```
10. 컨테이너 삭제

    ```
    docker container rm hello-world --force
    ```
11. ECR 리포지토리 생성&#x20;

    ```
    aws ecr create-repository \
    --repository-name express-hello-world \
    --no-cli-pager
    ```
12. 위에서 생성한 ECR 리포지토리의 URI를 확인하고 환경변수로 지정

    ```
    {
        export ECR_REPO=$(aws ecr describe-repositories --repository-name express-hello-world \
        --query 'repositories[0].repositoryUri' \
        --output text)
        
        echo $ECR_REPO
    }
    ```
13. 위에서 생성한 컨테이너 이미지에 새로운 태그 부여

    ```
    docker image tag express-hello-world $ECR_REPO
    ```
14. 컨테이너 이미지 목록 확인

    ```
    docker image ls
    ```
15. 컨테이너 이미지를 ECR 리포지토리로 업로드

    ```
    docker image push $ECR_REPO
    ```
16. ECR 레지스트리로 로그인

    ```
    {
        export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
        export AWS_REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]')
        aws ecr get-login-password | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
    }
    ```
17. 컨테이너 이미지를 ECR 리포지토리로 업로드

    ```
    docker image push $ECR_REPO
    ```
18. 이미지가 정상적으로 업로드 되었는지 확인

    ```
    aws ecr list-images --repository-name express-hello-world
    ```
19. 로컬호스트에 생성된 모든 컨테이너 삭제

    ```
    docker container rm $(docker container ls -aq) --force
    ```
20. 로컬호스트에 저장된 모드 컨테이너 이미지 삭제

    ```
    {
        docker image prune --all --force
        docker system prune --all --force
    }
    ```
21. ECR 리포지토리에 저장된 이미지로 컨테이너 생성

    ```
    docker container run --name hello-world -d -p 8080:3000 $ECR_REPO
    ```
22. 컨테이너가 정상적으로 실행 되었는지 확인

    ```
    curl -w "\n" localhost:8080
    ```
23. 컨테이너 및 이미지 삭제

    ```
    {
        docker container rm hello-world --force
        docker image prune -a --force
        rm -rf ~/environment/express-hello-world
        aws ecr delete-repository --repository-name express-hello-world --force
    }
    ```
24. 아래의 요구 사항에 맞게 컨테이너 이미지를 만들고 실행하세요.
    1. Docker Hub에 있는 [NGINX](https://hub.docker.com/_/nginx) 이미지 사용
    2. 웹사이트 루트를 호출하면 Hello, Container가 표시어야 함
    3. 로컬호스트의 8080포트를 컨테이너에서 실행되는 NGINX 웹서버의 포트와 연동

<details>

<summary>문제 답안</summary>

1. Dockerfile 생성

   ```
   FROM nginx:alpine
   RUN echo "Hello, Container" > /usr/share/nginx/html/index.html
   ```
2. 이미지 생성&#x20;

   ```
   docker image build -t my-nginx .
   ```
3. 컨테이너 실행&#x20;

   ```
   docker container run -p 8080:80 my-nginx 
   ```
4. 웹서버 호출&#x20;

   ```
   curl localhost:8080
   ```

</details>

### 이미지 경량화

1. 데모 애플리케이션 소스코드 다운로드

   ```
   cd ~/environment && git clone https://github.com/youngwjung/echo-hello-world.git && cd echo-hello-world
   ```
2. 애플리케이션 구동

   ```
   go run main.go
   ```
3. 새로운 터미널을 열고 웹 애플리케이션이 구동하는지 확인

   ```
   curl -w "\n" localhost:8080
   ```
4. 기존 터미널로 돌아와서 `Ctrl+C` 를 입력해서 애플리케이션 정지
5. Dockerfile 리뷰&#x20;
6. 컨테이너 이미지 빌드

   ```
   docker image build -t echo-hello-world .
   ```
7. 컨테이너 실행

   ```
   docker container run --name hello-world -d -p 8080:8080 echo-hello-world
   ```
8. 컨테이너가 정상적으로 실행 되었는지 확인

   ```
   curl -w "\n" localhost:8080
   ```
9. 컨테이너 삭제

   ```
   docker container rm hello-world --force
   ```
10. 컨테이너 이미지 크기 확인

    ```
    docker image ls
    ```
11. 멀티 스테이지로 짜여진 Dockerfile 리뷰&#x20;
12. 컨테이너 이미지 빌드

    ```
    docker image build -t echo-hello-world:multistage . -f Dockerfile_multistage
    ```
13. 컨테이너 이미지 크기 확인

    ```
    docker image ls
    ```
14. 새로운 이미지 빌드

    ```
    cat <<EOF | docker image build -t boto3 -
    FROM python
    RUN apt update && apt install -y curl
    RUN useradd developer
    RUN pip install boto3
    CMD ['python']
    EOF
    ```
15. 컨테이너 이미지 크기 확인

    ```
    docker image ls boto3
    ```
16. 14번 명령어에 명시된 Dockerfile을 수정해서 경량화된 이미지를 생성하세요.

<details>

<summary>문제 답안</summary>

1. 이미지 생성&#x20;

   ```
   cat <<EOF | docker image build -t boto3:slim -
   FROM python:alpine 
   RUN apk update --no-cache && apk add curl --no-cache
   RUN adduser -D developer
   RUN pip install boto3 --no-cache-dir
   CMD ['python']
   EOF
   ```
2. 컨테이너 이미지 크기 확인

   ```
   docker image ls boto3
   ```
3. 이미지 삭제&#x20;

   ```
   {
       docker image prune -a --force
       docker system prune -a --force
       rm -rf ~/environment/echo-hello-world
   }
   ```

</details>

### &#xD;컨테이너 네트워크

1. 호스트에 있는 네트워크 인터페이스 목록 확인

   ```
   ip a
   ```
2. 컨테이너 생성

   ```
   docker container run --name nginx -d nginx
   ```
3. 컨테이너에 부여된 IP 확인

   ```
   docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}'
   ```
4. 컨테이너에서 실행중인 NGINX 웹서버 호출

   ```
   curl $(docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}')
   ```
5. 호스트에 있는 네트워크 인터페이스 목록 확인

   ```
   ip a
   ```
6. 컨테이너 안에 있는 네트워크 인터페이스 목록 확인

   ```
   docker exec nginx ip a
   ```
7. 컨테이너에 ip 프로그램 설치

   ```
   {
       docker container exec nginx apt update
       docker container exec nginx apt install iproute2 -y
   }
   ```
8. 컨테이너 안에 있는 네트워크 인터페이스 목록 확인

   ```
   docker exec nginx ip a
   ```
9. 호스트에 있는 네트워크 인터페이스 목록 확인

   ```
   ip a
   ```
10. 컨테이너 로그 확인&#x20;

    ```
    docker logs nginx
    ```
11. 컨테이너 삭제

    ```
    docker container rm nginx --force
    ```
12. Docker 네크워크 목록 확인

    ```
    docker network ls
    ```
13. 컨테이너 재생성&#x20;

    ```
    docker container run --network host --name nginx -d nginx
    ```
14. 컨테이너 안에 있는 네트워크 인터페이스 목록 확인

    ```
    {
        docker container exec nginx apt update
        docker container exec nginx apt install iproute2 -y
        docker container exec nginx ip a
    }
    ```
15. 웹브라우저에서 Cloud9 인스턴스의 공인 IP로 접속되는지 확인 - 아래 명령어로 주소 확인 가능

    ```
    echo "$(curl -s ifconfig.io)"
    ```
16. 연결에 실패할 경우에는 아래의 명령어를 실행해서 보안그룹에 인바운드 규칙 추가

    ```
    {
        TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
        
        aws ec2 authorize-security-group-ingress \
        --group-id $(aws ec2 describe-security-groups \
        --filters Name=group-name,Values=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/security-groups) \
        --query "SecurityGroups[0].GroupId" --output text) \
        --protocol tcp \
        --port 80 \
        --cidr 0.0.0.0/0
    }
    ```
17. 컨테이너 삭제

    ```
    docker container rm nginx --force
    ```
18. 컨테이너 재생성&#x20;

    ```
    docker container run --publish 8080:80 --name nginx -d nginx
    ```
19. 웹브라우저에서 포트포워딩한 포트를 통해서 컨테이너로 접근되는지 확인 - 아래 명령어로 주소 확인 가능

    ```
    echo "$(curl -s ifconfig.io):8080"
    ```
20. 연결에 실패할 경우에는 아래의 명령어를 실행해서 보안그룹에 인바운드 규칙 추가

    ```
    {
        TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
        
        aws ec2 authorize-security-group-ingress \
        --group-id $(aws ec2 describe-security-groups \
        --filters Name=group-name,Values=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/security-groups) \
        --query "SecurityGroups[0].GroupId" --output text) \
        --protocol tcp \
        --port 8080 \
        --cidr 0.0.0.0/0
    }
    ```
21. Iptable의 모든 규칙 확인&#x20;

    ```
    sudo iptables-save
    ```
22. DOCKER 규칙 확인&#x20;

    ```
    sudo iptables -t nat -L DOCKER -n | column -t
    ```
23. 컨테이너 삭제

    ```
    docker container rm nginx --force
    ```
24. DOCKER 규칙 확인&#x20;

    ```
    sudo iptables -t nat -L DOCKER -n | column -t
    ```
25. 컨테이너 재생성&#x20;

    ```
    docker container run --publish 127.0.0.1:8080:80 --name nginx -d nginx
    ```
26. 웹브라우저에서 포트포워딩한 포트를 통해서 컨테이너로 접근되는지 확인 - 아래 명령어로 주소 확인 가능

    ```
    echo "$(curl -s ifconfig.io):8080"
    ```
27. Loopback 주소로 접속 시도

    ```
    curl localhost:8080
    ```
28. 새로운 컨테이너 생성

    ```
    docker container run --name busybox -d busybox sleep 3600
    ```
29. 새로 생성한 컨테이너에서 NGINX 컨테이너에 접근이 되는지 확인

    ```
    docker container exec busybox \
    ping $(docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}')
    ```
30. 컨테이너 삭제

    ```
    docker container rm busybox --force
    ```
31. 새로운 Docker 네크워크 생성

    ```
    docker network create --subnet 192.168.0.0/16 my_net 
    ```
32. Docker 네크워크 목록 확인

    ```
    docker network ls
    ```
33. 위에서 생성한 Docker 네트워크를 사용하는 컨테이너 생성

    ```
    docker container run --name client --network my_net -d praqma/network-multitool sleep 3600
    ```
34. 새로 생성한 컨테이너에서 NGINX 컨테이너에 접근이 되는지 확인

    ```
    docker container exec client \
    curl -sv -m 3 $(docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}')
    ```
35. 새로 생성한 Docker 네트워크를 사용하는 Apache 컨테이너 생성

    ```
    docker container run --name httpd --network my_net -d httpd
    ```
36. 동일한 Docker 네트워크를 사용하는 컨테이너에서 Apache 컨테이너에 접근이 되는지 확인

    ```
    docker container exec client \
    curl -s $(docker container inspect httpd --format '{{.NetworkSettings.Networks.my_net.IPAddress}}')
    ```
37. 컨테이너 이름으로 Apache 컨테이너에 접근이 되는지 확인

    ```
    docker container exec client \
    curl -s httpd
    ```
38. 컨테이너 이름으로 도메인 주소 검색 시도

    ```
    docker container exec client \
    dig httpd
    ```
39. Apache 컨테이너의 IP 주소 확인

    ```
    docker container inspect httpd \
    --format '{{.NetworkSettings.Networks.my_net.IPAddress}}'
    ```
40. 리소스 정리

    ```
    {
        docker container rm $(docker container ls -aq) --force
        docker image prune --all --force
        docker network rm my_net
    }
    ```
41. 아래의 요구 사항에 맞게 컨테이너 이미지를 만들고 실행하세요.
    1. Docker Hub에 있는 `mysql:5.7` 이미지 사용
    2. 로컬호스트의 3366 포트를 컨테이너에서 실행되는 MySQL 데이터베이스의 포트와 연동
    3. 로컬호스트에서 아래의 명령어를 실행해서 DB에 접속

       ```
       mysql -h 127.0.0.1 -P 3366 -u root -p
       ```

<details>

<summary>문제 답안</summary>

```
docker container run -d -p 3366:3306 -e MYSQL_ROOT_PASSWORD=asdf1234 mysql:5.7
```

</details>

### 컨테이너 스토리지

1. 리소스 정리&#x20;

   ```
   {
       docker container rm $(docker container ls -aq) --force
       docker volume prune --force
   }
   ```
2. MySQL 컨테이너 생성

   ```
   docker container run --name mysql -d -p 3306:3306 \
   -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
   ```
3. 데이터베이스 및 레코드 생성

   ```
   mysql -h 127.0.0.1 -u root <<EOF
   CREATE DATABASE test;
   CREATE TABLE test.messages (message VARCHAR(250));
   INSERT INTO test.messages VALUES ('hello');
   EOF
   ```
4. 위에서 생성한 데이터를 확인&#x20;

   ```
   mysql -h 127.0.0.1 -u root -e "SELECT message FROM test.messages;"
   ```
5. 만약 MySQL 컨테이너를 삭제하면 위에서 생성한 데이터는 어떻게 되나요?
6. 컨테이너 생성에 사용된 명령 및 메타데이터(Dockerfile에 명시된 내용) 확인

   ```
   docker image history mysql:5.7 --format '{{.CreatedBy}}'
   ```
7. MySQL 컨테이너에 마운트된 볼륨 확인

   ```
   docker container inspect mysql --format '{{json .Mounts}}' | jq
   ```
8. Docker 볼륨 목록 확인

   ```
   docker volume ls
   ```
9. MySQL 컨테이너에 마운트된 볼륨 ID를 환경 변수로 저장

   ```
   export MYSQL_VOL_ID=$(docker volume ls -q)
   ```
10. 만약 MySQL 컨테이너를 삭제하고 재생성하면 위에서 생성한 데이터가 새로 생성된 컨테이너에 연동될까요?
11. MySQL 컨테이너 재생성&#x20;

    ```
    {
        docker container rm mysql --force 
        docker container run --name mysql -d -p 3306:3306 \
        -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
    }
    ```
12. 데이터 확인&#x20;

    ```
    mysql -h 127.0.0.1 -u root -e "SELECT message FROM test.messages;"
    ```
13. Docker 볼륨 목록 확인

    ```
    docker volume ls
    ```
14. MySQL 컨테이너 삭제

    ```
    docker container rm mysql --force
    ```
15. MySQL 컨테이너 재생성&#x20;

    ```
    docker container run --name mysql -d -p 3306:3306 \
    --mount source=$MYSQL_VOL_ID,target=/var/lib/mysql \
    -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
    ```
16. 데이터 확인&#x20;

    ```
    mysql -h 127.0.0.1 -u root -e "SELECT message FROM test.messages;"
    ```
17. MySQL 컨테이너 삭제

    ```
    docker container rm mysql --force
    ```
18. Docker 볼륨 목록 확인

    ```
    docker volume ls
    ```
19. 사용하지 않는 볼륨 삭제&#x20;

    ```
    docker volume prune --force
    ```
20. Docker 볼륨 생성&#x20;

    ```
    docker volume create mysql
    ```
21. MySQL 컨테이너 생성&#x20;

    ```
    docker container run --name mysql -d -p 3306:3306 \
    --mount source=mysql,target=/var/lib/mysql \
    -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
    ```
22. MySQL 컨테이너에 마운트된 볼륨 확인

    ```
    docker container inspect mysql --format '{{json .Mounts}}' | jq
    ```
23. 리소스 정리&#x20;

    ```
    {
        docker container rm $(docker container ls -aq) --force
        docker volume prune --force
    }
    ```
24. 디렉토리 생성

    ```
    mkdir -p $HOME/environment/nginx/html
    ```
25. HTML 문서 생성&#x20;

    ```
    echo "Hello, Docker" > $HOME/environment/nginx/html/index.html
    ```
26. NGINX 컨테이너 생성

    ```
    docker container run --name nginx -d -p 8080:80 \
    --mount type=bind,source=$HOME/environment/nginx/html,target=/usr/share/nginx/html \
    nginx
    ```
27. NGINX 웹서버 호출

    ```
    curl localhost:8080
    ```
28. HTML 문서에 내용 추가 &#x20;

    ```
    echo "Hello, Volume" >> $HOME/environment/nginx/html/index.html
    ```
29. NGINX 웹서버 호출

    ```
    curl localhost:8080
    ```
30. 컨테이너의 `/usr/share/nginx/html` 경로에 있는 파일 확인

    ```
    docker container exec nginx ls /usr/share/nginx/html
    ```
31. 컨테어너와 연동된 디렉토리에 새로운 파일 생성&#x20;

    ```
    touch $HOME/environment/nginx/html/new-file-from-host.txt
    ```
32. 컨테이너의 `/usr/share/nginx/html` 경로에 있는 파일 확인

    ```
    docker container exec nginx ls /usr/share/nginx/html
    ```
33. 컨테이너에서 호스트와 연동된 디렉토리에 새로운 파일 생성

    ```
    docker container exec nginx touch /usr/share/nginx/html/new-file-from-container.txt
    ```
34. 로컬호스트의  `$HOME/environment/nginx/html` 경로에 있는 파일 확인

    ```
    ls $HOME/environment/nginx/html
    ```
35. 리소스 정리

    ```
    {
        docker container rm $(docker container ls -aq) --force
        rm -rf $HOME/environment/nginx
    }
    ```
36. 아래의 요구 사항에 맞게 컨테이너 이미지를 만들고 실행하세요.
    1. my-app 이라는 이름의 Docker 볼륨 생성
    2. Docker 허브에 있는 NGINX 이미지로 컨테이너를 생성하고 위에서 생성한 my-app 볼륨을 `/opt/app` 경로에 마운트
    3. NGINX 컨테이너 `/opt/app/` 경로에 hello.txt 파일을 생성하고 내용으로 world를 추가
    4. Docker 허브에 있는 Apache 이미지로 컨테이너를 생성하고 위에서 생성한 my-app 볼륨을 `/usr/app` 경로에 마운트를 하되 읽기 권한만 부여
    5. Apache 컨테이너 `/usr/app/` 경로에 hello.txt 파일이 있는지 확인 하고 내용 확인
    6. Apache 컨테이너에서 `/usr/app/hello.txt` 파일을 열고 수정이 가능한지 확인

<details>

<summary>문제 답안</summary>

1. my-app 이라는 이름의 Docker 볼륨 생성

   ```
   docker volume create my-app
   ```
2. Docker 허브에 있는 NGINX 이미지로 컨테이너를 생성하고 위에서 생성한 my-app 볼륨을 `/opt/app` 경로에 마운트

   ```
   docker container run --name nginx -d \
   --mount src=my-app,dst=/opt/app \
   nginx
   ```
3. NGINX 컨테이너 `/opt/app/` 경로에 hello.txt 파일을 생성하고 내용으로 world를 추가

   ```
   docker container exec -it nginx bash
   echo "world" > /opt/app/hello.txt
   cat /opt/app/hello.txt
   exit
   ```
4. Docker 허브에 있는 Apache 이미지로 컨테이너를 생성하고 위에서 생성한 my-app 볼륨을 `/usr/app` 경로에 마운트를 하되 읽기 권한만 부여

   ```
   docker container run --name httpd -d \
   --mount src=my-app,dst=/usr/app,ro \
   httpd
   ```
5. Apache 컨테이너 `/usr/app/` 경로에 hello.txt 파일이 있는지 확인 하고 내용 확인

   ```
   docker container exec -it httpd cat /usr/app/hello.txt
   ```
6. Apache 컨테이너에서 `/usr/app/hello.txt` 파일을 열고 수정이 가능한지 확인

   ```
   docker container exec -it httpd bash
   echo "hello" > /usr/app/hello.txt
   exit
   ```

</details>

### 컨테이너 디버깅

1. 리소스 정리&#x20;

   ```
   {
       docker container rm $(docker container ls -aq) --force
       docker volume prune --force
   }
   ```
2. NGINX 컨테이너 생성

   ```
   docker container run --name nginx -d nginx
   ```
3. 컨테이너에서 프로세스를 실행하는 유저 확인

   ```
   docker container exec nginx id
   ```
4. 컨테이너에 생성되어 있는 유저 목록 확인

   ```
   docker container exec nginx cat /etc/passwd
   ```
5. NGINX 컨테이너 삭제&#x20;

   ```
   docker container rm nginx --force
   ```
6. NGINX 컨테이너 재생성하고 nginx 유저로 프로세스 실행

   ```
   docker container run --name nginx -d -u nginx nginx
   ```
7. 실행중인 컨테이너 목록 확인

   ```
   docker container ls
   ```
8. 모든 컨테이너 목록 확인

   ```
   docker container ls -a
   ```
9. NGINX 컨테이너 상태에 대한 상세 내용 확인

   ```
   docker container inspect nginx --format '{{json .State}}' | jq
   ```
10. NGINX 컨테이너 로그 확인

    ```
    docker container logs nginx
    ```
11. NGINX 컨테이너의 로그 파일이 저장되는 경로 확인  &#x20;

    ```
    {
        export NGINX_LOG_PATH=$(docker container inspect nginx --format '{{.LogPath}}')
        echo $NGINX_LOG_PATH
    }
    ```
12. 로그 파일 내용 확인&#x20;

    ```
    sudo cat $NGINX_LOG_PATH
    ```
13. NGINX 컨테이너 삭제&#x20;

    ```
    docker container rm nginx --force
    ```
14. 삭제된 컨테이너의 로그 파일이 남아 있는지 확인

    ```
    sudo cat $NGINX_LOG_PATH
    ```
15. NGINX 컨테이너 재생성

    ```
    docker container run --name nginx -d nginx
    ```
16. NGINX 컨테이너 환경에 bash 프로세스 실행

    ```
    docker container exec -it nginx bash
    ```
17. NGINX 설정 파일 확인

    ```
    cat /etc/nginx/nginx.conf
    ```
18. NGINX 프로세스의 PID 파일이 생성되는 경로의 권한 확인

    ```
    ls -al /var/run
    ```
19. 실행중인 프로세스 목록 확인

    ```
    ps aux
    ```
20. 실행중인 프로세스의 리소스 사용량 확인

    ```
    top
    ```
21. bash 프로세스 종료&#x20;

    ```
    exit
    ```
22. NGINX 컨테이너에서 실행중인 프로세스 목록 확인

    ```
    docker container top nginx
    ```
23. NGINX 컨테이너가 사용중인 리소스 사용량 확인

    ```
    docker container stats nginx
    ```
24. 새로운 컨테이너 생성

    ```
    docker container run --name echo -d youngwjung/echo
    ```
25. 컨테이너가 실행중인지 확인하고 실행중이지 않다면 어떤 이유인지 확인
26. 컨테이너 로그 확인&#x20;

    ```
    docker container logs echo
    ```
27. 컨테이너 로그에 `Hello, Docker`가 출력되도록 컨테이너 생성&#x20;

    ```
    docker container run --name hello-docker -d youngwjung/echo Hello, Docker
    ```
28. 컨테이너 로그 확인&#x20;

    ```
    docker container logs hello-docker
    ```
29. 컨테이너 로그에 현재 시간이 출력 되도록 컨테이너 생성

    ```
    docker container run --name date -d --entrypoint date youngwjung/echo
    ```
30. 컨테이너 로그 확인&#x20;

    ```
    docker container logs date
    ```
31. 리소스 정리&#x20;

    ```
    {
        docker container rm $(docker container ls -aq) --force
        docker volume prune --force
        docker image prune --all --force
    }
    ```
32. 아래의 내용들을 수행해서 문제 해결
    1. 컨테이너 생성&#x20;

       ```
       docker container run --name file -d youngwjung/docker-lab:file
       ```
    2. 컨테이너 안에 `/app/password.txt` 파일의 내용을 확인
    3. 새로운 컨테이너 생성

       ```
       docker container run --name env -d youngwjung/docker-lab:env
       ```
    4. 애플리케이션 로그 파일을 참고해서 애플리케이션이 정상적으로 실행되고 종료되도록 설정\
       애플리케이션이 정상 실행/종료되면 애플리케이션 로그를 통해서 다음 단계에서 필요한 정보를 확인 가능&#x20;
    5. 새로운 컨테이너 생성

       ```
       docker container run --name port -d youngwjung/docker-lab:port
       ```
    6. TCP 서버가 구동중이고 이전 단계에서 확인한 암호를 TCP 서버로 전송하게 되면 다음 단계에서 필요한 정보를 확인 가능
    7. 새로운 컨테이너 생성

       ```
       docker container run --name copy -d youngwjung/docker-lab:copy
       ```
    8. 컨테이너 안에 `/message.txt.gpg` 파일이 GPG를 통해서 암호화 되어있습니다. 파일 내용을 확인하세요.


---

# 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-docker.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.
