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

# 도커 기초

### 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를 통해서 암호화 되어있습니다. 파일 내용을 확인하세요.
