Skip to content

Latest commit

 

History

History
482 lines (349 loc) · 16.6 KB

step-01.md

File metadata and controls

482 lines (349 loc) · 16.6 KB

STEP 01: Dockerfile 및 Docker Compose 파일 생성하기

이 단계에서는 기본 프로젝트에서 제공한 각각의 앱을 컨테이너화 시킬 수 있는 Dockerfile 파일과 오케스트레이션 할 수 있는 Docker Compose 파일을 생성합니다.

사전 준비 사항

각 사전 준비사항의 설치 여부 확인은 STEP 00: 개발 환경 설정하기 문서를 참고해주세요.

기본 프로젝트 복사

이 워크샵을 위해 필요한 기본 프로젝트를 준비해 뒀습니다. 이 프로젝트가 제대로 작동하는지 확인합니다. 기본 프로젝트의 프로젝트 구조는 아래와 같습니다.

eShopLite
└── src
    ├── eShopLite.WebApp
    ├── eShopLite.WeatherApi
    ├── eShopLite.ProductApi
    ├── eShopLite.ProductData
    └── eShopLite.DataEntities
  1. 터미널을 열고 아래 명령어를 차례로 실행시켜 실습 디렉토리를 만들고 기본 프로젝트를 복사합니다.

    # Bash/Zsh
    REPOSITORY_ROOT=$(git rev-parse --show-toplevel)
    cd $REPOSITORY_ROOT
    
    mkdir -p workshop && cp -a save-points/step-00/. workshop/
    # PowerShell
    $REPOSITORY_ROOT = git rev-parse --show-toplevel
    cd $REPOSITORY_ROOT
    
    New-Item -Type Directory -Path workshop -Force && Copy-Item -Path ./save-points/step-00/* -Destination ./workshop -Recurse -Force

기본 프로젝트 빌드 및 실행

  1. 아래 명령어를 통해 전체 프로젝트를 빌드합니다.

    cd $REPOSITORY_ROOT/workshop
    
    dotnet restore && dotnet build
  2. 터미널 창을 세 개 열고 각각 아래 명령어를 실행시켜 애플리케이션을 실행합니다.

    # Terminal 1
    cd $REPOSITORY_ROOT/workshop
    dotnet run --project ./src/eShopLite.WeatherApi
    # Terminal 2
    cd $REPOSITORY_ROOT/workshop
    dotnet run --project ./src/eShopLite.ProductApi
    # Terminal 3
    cd $REPOSITORY_ROOT/workshop
    dotnet watch run --project ./src/eShopLite.WebApp

    터미널마다 $REPOSITORY_ROOT 값을 인식하지 못할 수 있습니다. 이 때는 각 터미널 별로 아래 명령어를 다시 실행시켜 주세요.

    # Bash/Zsh
    REPOSITORY_ROOT=$(git rev-parse --show-toplevel)
    # PowerShell
    $REPOSITORY_ROOT = git rev-parse --show-toplevel
  3. 자동으로 웹 브라우저가 열리면서 https://localhost:7000 또는 http://localhost:5000 주소로 접속합니다. 만약 자동으로 웹 브라우저가 열리지 않았다면 수동으로 주소를 입력합니다.

  4. 웹브라우저에서 /weather 또는 /products 경로로 접속하셔 각각 페이지가 정상적으로 보이는지 확인합니다.

  5. 각 터미널 창에서 Ctrl+C를 눌러 애플리케이션을 종료합니다.

  6. 터미널을 하나만 남겨두고 모두 종료합니다.

Dockerfile을 이용한 컨테이너 이미지 생성

기본 프로젝트는 각 애플리케이션마다 의존성을 갖고 있습니다. 이 의존성 구조는 아래와 같습니다.

eShopLite
└── src
    ├── eShopLite.WebApp
    │   └── eShopLite.DataEntities
    ├── eShopLite.ProductApi
    │   └── eShopLite.ProductData
    │       └── eShopLite.DataEntities
    └── eShopLite.WeatherApi
        └── eShopLite.DataEntities

따라서, 개별 애플리케이션마다 독립적인 컨테이너 이미지를 생성할 때 이 의존성을 해결해야 합니다.

이 시점부터는 Docker Desktop 애플리케이션이 실행중이어야 합니다. 작업표시줄에 Docker 아이콘이 보이지 않는다면 Docker Desktop을 실행해주세요.

Dockerfile 생성: eShopLite.WebApp

  1. 워크샵 루트 디렉토리로 이동합니다.

    cd $REPOSITORY_ROOT/workshop
  2. 아래 명령어를 통해 Dockerfile.webapp을 생성합니다.

    # Bash/Zsh
    touch Dockerfile.webapp
    # PowerShell
    New-Item -Type File -Path Dockerfile.webapp -Force
  3. Dockerfile.webapp을 열고 아래 내용을 입력합니다.

    # syntax=docker/dockerfile:1
    
    FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build
    
    COPY ./src/eShopLite.WebApp /source/eShopLite.WebApp
    COPY ./src/eShopLite.DataEntities /source/eShopLite.DataEntities
    
    WORKDIR /source/eShopLite.WebApp
    
    RUN dotnet publish -c Release -o /app
    
    FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine AS final
    
    WORKDIR /app
    
    COPY --from=build /app .
    
    USER $APP_UID
    
    ENTRYPOINT ["dotnet", "eShopLite.WebApp.dll"]

    참고: Dockerfile.webappeShopLite.WebApp 프로젝트를 컨테이너 이미지로 빌드하기 위한 Dockerfile입니다.

    • Dockefile.webapp의 위치는 eShopLite.sln 파일의 위치와 동일한 디렉토리에 있어야 합니다.
    • eShopLite.WebApp 프로젝트와 eShopLite.DataEntities 프로젝트를 모두 복사해서 의존성을 해결합니다.
  4. 아래 명령어를 실행시켜 eShopLite.WebApp 프로젝트를 컨테이너 이미지로 빌드합니다.

    docker build . -f ./Dockerfile.webapp -t eshoplite-webapp:latest
  5. 아래 명령어를 실행시켜 빌드한 컨테이너 이미지를 실행합니다.

    docker run -d -p 3000:8080 --name eshoplite-webapp eshoplite-webapp:latest
  6. 웹 브라우저에서 http://localhost:3000 주소로 접속하여 페이지가 정상적으로 보이는지 확인합니다.

  7. /weather 또는 /products 경로로 접속하여 각각 페이지에 에러가 발생하는지 확인합니다.

    이 시점에서는 에러가 발생해야 합니다.

  8. 아래 명령어를 실행시켜 컨테이너를 종료하고 컨테이너 및 컨테이너 이미지를 삭제합니다.

    docker stop eshoplite-webapp
    docker rm eshoplite-webapp --force
    docker rmi eshoplite-webapp:latest --force

Dockerfile 생성: eShopLite.ProductApi

  1. 워크샵 루트 디렉토리로 이동합니다.

    cd $REPOSITORY_ROOT/workshop
  2. 아래 명령어를 통해 Dockerfile.productapi을 생성합니다.

    # Bash/Zsh
    touch Dockerfile.productapi
    # PowerShell
    New-Item -Type File -Path Dockerfile.productapi -Force
  3. Dockerfile.productapi을 열고 아래 내용을 입력합니다.

    # syntax=docker/dockerfile:1
    
    FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build
    
    COPY ./src/eShopLite.ProductApi /source/eShopLite.ProductApi
    COPY ./src/eShopLite.ProductData /source/eShopLite.ProductData
    COPY ./src/eShopLite.DataEntities /source/eShopLite.DataEntities
    
    WORKDIR /source/eShopLite.ProductApi
    
    RUN dotnet publish -c Release -o /app
    
    FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine AS final
    
    WORKDIR /app
    
    COPY --from=build /app .
    
    RUN chown $APP_UID /app
    
    USER $APP_UID
    
    RUN touch /app/Database.db
    
    ENTRYPOINT ["dotnet", "eShopLite.ProductApi.dll"]

    참고: Dockerfile.productapieShopLite.ProductApi 프로젝트를 컨테이너 이미지로 빌드하기 위한 Dockerfile입니다.

    • Dockefile.productapi의 위치는 eShopLite.sln 파일의 위치와 동일한 디렉토리에 있어야 합니다.
    • eShopLite.ProductApi 프로젝트와 eShopLite.ProductData, eShopLite.DataEntities 프로젝트를 모두 복사해서 의존성을 해결합니다.
  4. 아래 명령어를 실행시켜 eShopLite.ProductApi 프로젝트를 컨테이너 이미지로 빌드합니다.

    docker build . -f ./Dockerfile.productapi -t eshoplite-productapi:latest
  5. 아래 명령어를 실행시켜 빌드한 컨테이너 이미지를 실행합니다.

    docker run -d -p 3030:8080 --name eshoplite-productapi eshoplite-productapi:latest
  6. 웹 브라우저에서 http://localhost:3030 주소로 접속하여 404 에러가 보이는지 확인합니다.

  7. /api/products 경로로 접속하여 데이터가 정상적으로 보이는지 확인합니다.

  8. 아래 명령어를 실행시켜 컨테이너를 종료하고 컨테이너 및 컨테이너 이미지를 삭제합니다.

    docker stop eshoplite-productapi
    docker rm eshoplite-productapi --force
    docker rmi eshoplite-productapi:latest --force

Dockerfile 생성: eShopLite.WeatherApi

🚨🚨🚨 도전‼️ 🚨🚨🚨

위의 Dockerfile.webappDockerfile.productapi 작성 방법을 참고하여 eShopLite.WeatherApi 프로젝트를 컨테이너 이미지로 빌드하는 Dockerfile.weatherapi를 작성해보세요.

  • Dockerfile.weatherapieShopLite.WeatherApi 프로젝트를 컨테이너 이미지로 빌드하기 위한 Dockerfile입니다.
  • Dockefile.weatherapi의 위치는 eShopLite.sln 파일의 위치와 동일한 디렉토리에 있어야 합니다.

Dockerfile.weatherapi를 작성했다면 아래 순서대로 실행해보세요.

  1. 아래 명령어를 실행시켜 eShopLite.WeatherApi 프로젝트를 컨테이너 이미지로 빌드합니다.

    docker build . -f ./Dockerfile.weatherapi -t eshoplite-weatherapi:latest
  2. 아래 명령어를 실행시켜 빌드한 컨테이너 이미지를 실행합니다.

    docker run -d -p 3031:8080 --name eshoplite-weatherapi eshoplite-weatherapi:latest
  3. 웹 브라우저에서 http://localhost:3031 주소로 접속하여 404 에러가 보이는지 확인합니다.

  4. /api/weatherforecast 경로로 접속하여 데이터가 정상적으로 보이는지 확인합니다.

  5. 아래 명령어를 실행시켜 컨테이너를 종료하고 컨테이너 및 컨테이너 이미지를 삭제합니다.

    docker stop eshoplite-weatherapi
    docker rm eshoplite-weatherapi --force
    docker rmi eshoplite-weatherapi:latest --force

컨테이너 오케스트레이션: Docker Network

앞서 작성한 세 개의 Dockerfile을 이용해 컨테이너 오케스트레이션을 합니다.

  1. 아래 명령어를 실행시켜 eShopLite.WebApp, eShopLite.ProductApi, eShopLite.WeatherApi 컨테이너 이미지를 빌드합니다.

    cd $REPOSITORY_ROOT/workshop
    docker build . -f ./Dockerfile.webapp -t eshoplite-webapp:latest
    docker build . -f ./Dockerfile.productapi -t eshoplite-productapi:latest
    docker build . -f ./Dockerfile.weatherapi -t eshoplite-weatherapi:latest
  2. 아래 명령어를 실행시켜 빌드한 컨테이너 이미지를 실행시킵니다.

    docker run -d -p 3000:8080 --name eshoplite-webapp eshoplite-webapp:latest
    docker run -d -p 3030:8080 --name eshoplite-productapi eshoplite-productapi:latest
    docker run -d -p 3031:8080 --name eshoplite-weatherapi eshoplite-weatherapi:latest
  3. 웹 브라우저를 열고 http://localhost:3000 주소로 접속하여 페이지가 정상적으로 보이는지 확인합니다.

  4. /weather 또는 /products 경로로 접속하여 각각 페이지에 에러가 발생하는지 확인합니다.

    이 시점에서도 여전히 에러가 발생해야 합니다.

  5. 아래 명령어를 실행시켜 모든 컨테이너를 종료하고 삭제합니다.

    docker stop eshoplite-webapp
    docker rm eshoplite-webapp --force
    
    docker stop eshoplite-productapi
    docker rm eshoplite-productapi --force
    
    docker stop eshoplite-weatherapi
    docker rm eshoplite-weatherapi --force
  6. src/eShopLite.WebApp/Program.cs 파일을 열고 아래와 같이 코드를 수정합니다.

    // 변경 전
    builder.Services.AddHttpClient<ProductApiClient>(client =>
    {
        client.BaseAddress = new("http://localhost:5051");
    });
    
    builder.Services.AddHttpClient<WeatherApiClient>(client =>
    {
        client.BaseAddress = new("http://localhost:5050");
    });
    // 변경 후
    builder.Services.AddHttpClient<ProductApiClient>(client =>
    {
        client.BaseAddress = new("http://productapi:8080");
    });
    
    builder.Services.AddHttpClient<WeatherApiClient>(client =>
    {
        client.BaseAddress = new("http://weatherapi:8080");
    });
  7. eShopLite.WebApp 프로젝트의 컨테이너 이미지를 다시 빌드합니다.

    docker build . -f ./Dockerfile.webapp -t eshoplite-webapp:latest
  8. 아래 명령어를 실행시켜 네트워크를 생성합니다.

    docker network create eshoplite
  9. 아래 명령어를 실행시켜 eShopLite.WebApp, eShopLite.ProductApi, eShopLite.WeatherApi 컨테이너 이미지를 실행합니다.

    docker run -d -p 3000:8080 --network eshoplite --network-alias webapp --name eshoplite-webapp eshoplite-webapp:latest
    docker run -d -p 3030:8080 --network eshoplite --network-alias productapi --name eshoplite-productapi eshoplite-productapi:latest
    docker run -d -p 3031:8080 --network eshoplite --network-alias weatherapi --name eshoplite-weatherapi eshoplite-weatherapi:latest
  10. 웹 브라우저를 열고 http://localhost:3000 주소로 접속하여 페이지가 정상적으로 보이는지 확인합니다.

  11. /weather 또는 /products 경로로 접속하여 각 페이지가 정상적으로 보이는지 확인합니다.

  12. 아래 명령어를 실행시켜 컨테이너와 네트워크를 삭제합니다.

    docker stop eshoplite-webapp
    docker rm eshoplite-webapp --force
    
    docker stop eshoplite-productapi
    docker rm eshoplite-productapi --force
    
    docker stop eshoplite-weatherapi
    docker rm eshoplite-weatherapi --force
    
    docker network rm eshoplite --force
  13. 아래 명령어를 실행시켜 컨테이너 이미지를 삭제합니다.

    docker rmi eshoplite-webapp:latest --force
    docker rmi eshoplite-productapi:latest --force
    docker rmi eshoplite-weatherapi:latest --force

컨테이너 오케스트레이션: Docker Compose

이번에는 Docker Compose를 이용해 컨테이너 오케스트레이션을 합니다.

  1. 아래 명령어를 실행시켜 compose.yaml 파일을 생성합니다.

    # Bash/Zsh
    cd $REPOSITORY_ROOT/workshop
    touch compose.yaml
    # PowerShell
    cd $REPOSITORY_ROOT/workshop
    New-Item -Type File -Path compose.yaml -Force
    • compose.yaml의 위치는 eShopLite.sln 파일의 위치와 동일한 디렉토리에 있어야 합니다.
  2. compose.yaml 파일을 열고 아래 내용을 입력합니다.

    name: eShopLite
    
    services:
      productapi:
        container_name: productapi
        build:
          context: .
          dockerfile: ./Dockerfile.productapi
          target: final
        ports:
          - 3030:8080
      weatherapi:
        container_name: weatherapi
        build:
          context: .
          dockerfile: ./Dockerfile.weatherapi
          target: final
        ports:
          - 3031:8080
      webapp:
        container_name: webapp
        build:
          context: .
          dockerfile: ./Dockerfile.webapp
          target: final
        ports:
          - 3000:8080
        depends_on:
          - productapi
          - weatherapi
  3. 아래 명령어를 실행시켜 컨테이너를 실행합니다.

    docker compose up --build
  4. 웹 브라우저를 열고 http://localhost:3000 주소로 접속하여 페이지가 정상적으로 보이는지 확인합니다.

  5. /weather 또는 /products 경로로 접속하여 각 페이지가 정상적으로 보이는지 확인합니다.

  6. 터미널 창에서 Ctrl+C를 눌러 애플리케이션을 종료합니다.

  7. 아래 명령어를 실행시켜 컨테이너와 네트워크, 컨테이너 이미지를 한 번에 삭제합니다.

    docker compose down --rmi local

축하합니다! Dockerfile 및 Docker Compose 파일 생성하기 실습이 끝났습니다. 이제 STEP 02: Testcontainers로 API 테스트하기 단계로 넘어가세요.