Day2 Dockerfile

1. Dockerfile

0) 사전준비

앞서 첫날에는 MSA, Docker에 관해서 알아보았다. 오늘은 그 중에서 프로젝트 안에 있는 Dockerfile을 공부했다.

프로젝트 예시는 앞으로 "eShop on Dapr"라는 것을 사용할 예정이다.

eShop on Dapr Github 주소

1) Dockerfile 명령어

명령어를 알아보기 이전에, Dockerfile을 바탕으로 Docker image가 만들어 진다는 사실을 알았다.

그 방법을 먼저 간단히 살펴보자.

docker build -f /path/to/a/Dockerfile -t testImage:1.0

docker build란 명령어로 image를 간단히 생성히 가능하다.

뒤의 내용들은 옵션이며 내용은 아래와 같다.

  • ' -f ' : docker build 시 참조할 파일의 이름이 Dockerfile이 아니거나, 위치가 현재의 위치에 존재하지 않을 경우 직접 build할 파일을 지정할 수 있다.
  • ' -t ' : build로 생기는 image의 이름을 정할 수 있다. 정하지 않으면 임의의 숫자값으로 나오기 때문에 사용을 추천하는 옵션이다.

- FROM : 베이스 이미지 (image layer 하나로 취급).

어느 이미지에서 시작할 건지를 정해주는 명령어.

- RUN : 새로운 image layer를 생성하고, 필요한 패키지들을 설치할 때 사용함.

표현식은 2가지 방법이 존재한다.

  1. Shell form (default /bin/sh -c on LINUX, cmd /S /C on Windows)
RUN apt-get update -yq \
    && apt-get install curl gnupg -yq \
    && curl -sL https://deb.nodesource.com/setup_10.x | bash \
    && apt-get install nodejs -yq
  1. exec form
RUN ["/bin/bash", "-c", "echo hello"]

- CMD and ENTRYPOINT : 둘 다 image를 바탕으로 생성된 container에서 명령어를 실행한다.

CMD ["dotnet", "WebSPA.dll"]
ENTRYPOINT ["dotnet", "WebSPA.dll"]

둘의 차이점은 아래와 같다.

  • CMD = 추가적인 명령어에 따라서 명령어를 수정해서 실행한다.
  docker run --name <container-name> <image-name>
> This is a test
  docker run --name <container-name> <image-name> echo "Hello"
> Hello
  • ENTRYPOINT = 추가 명령어 존재와 상관없이 무조건 실행
  docker run --name <container-name> <image-name>
> Hello world
  docker run --name <container-name> <image-name> ME
> Hello ME

- HEALTHCHEACK : container의 프로세스 상태를 체크할 수 있다.

명령 옵션들은 아래와 같다.

옵션설명기본값
--interval=Duration헬스 체크 간격30s
--timeout=Duration타임 아웃30s
--retries=N타임아웃횟수3

상태값은 아래와 같다.

EXIT Code설명
0: success컨테이너 정상
1: unhealthy컨테이너 작동 불량
2: starting위의 exit code를 사용하지 않음

container의 상태는 아래와 같이 확인가능하다.

docker container inspect [container name]

위의 옵션들을 적용한 예시이다.

HEALTHCHECK --interval=10s --timeout=3s CMD curl -f http://127.0.0.1/ || exit 1

( 10초마다 위 주소를 체크 하는데, 3초 이상이 걸리거나, 3번의 재시도가 실패하면 unhealthy 상태로 변경해라 )

- COPY and ADD : 둘 다 host OS의 파일이나 디렉토리를 container 안의 지정한 경로로 복사한다.

둘의 차이는 아래와 같다.

COPY <src>... <destination>
COPY ["<src>",... "<destination>"]

ADD <src>... <destination>
ADD ["<src>",... "<destination>"]
  • COPY = container 안으로 정확히 복사만 가능하다.
  • ADD = container 안으로 복사를 하면서 tar 파일처럼 압축된 파일을 해제하거나 하는 기능이 들어있다.

보통 COPY가 투명하게 과정이 보이기 때문에 default로 사용한다.
( COPY는 오직 container 안의 local file들을 단순히 COPY하는 것 밖에 못한다. Docker client로 부터 적혀진 디렉토리에 파일을 추가한다. )
( 반면 ADD는 remote URL을 지원하거나, local-only tar 파일을 추출하는 것 같은 직관적이지 않은 부가기능을 제공한다. )

- ENV and ARG : 둘 다 변수를 설정하는 명령어.

둘의 차이는 아래와 같다.

  • ENV = Dockerfile & container 안에서 변수로 사용가능
  • ARG = Dockerfile에서만 변수로 사용가능

- WORKDIR : 명령을 실행하기 위한 디렉토리 지정.

  • 작업 디렉토리를 지정하면 이후에는 이 지정된 값을 기준으로 동작함.
  • 즉 terminal의 cd 명령어와 비슷하다.

- LABEL : image version, 작성자, 코멘트 처럼 image의 metadata를 입력할 때 사용

LABEL title="webserver"
LABEL version="2.0"

- EXPOSE : container가 대기할 네트워크 port를 알려줌.

( 보통 평균적으로 많이 쓰는 port를 사용, Apache: 80, MongoDB: 27017 )

하지만 이 명령 자체가 port를 실행하여 listening 상태로 올려주지는 않기 때문에 실제로 port를 열기 위해서는 container run -p 로 컨테이너를 실행할때 옵션으로 실행시켜 줘야 함

dockerfile을 작성하는 사람과 container를 실행할 사람 사이에서 공개port를 알려주기 위한 구문

- VOLUME : container를 삭제하면 안의 모든 데이터가 유실되기 때문에 보존할 데이터는 VOLUME을 사용해서 host OS에 저장하고, container 간의 데이터 공유 가능

FROM centos:7
VOLUME ["/var/log/", "/data/"]

/var/log 의 데이터와, /data/ 의 데이터는 host OS의 /var/lib/docker/volumes/ 에 저장된다.

2) eShop on Dapr's Dockerfiles

eShop on Dapr의 Dockerfile 중에서 2가지를 위에서 공부한 내용을 바탕으로 읽어보자.

// src/Services/Basket/Basekt.API/Dockerfile

ARG NET_IMAGE=5.0-buster-slim // NET_IMAGE라는 dockerfile에서만 쓸 수 있는 변수 설정
FROM mcr.microsoft.com/dotnet/aspnet:${NET_IMAGE} AS base // 시작할 image를 정하고 이름을 base로 설정
WORKDIR /app // app에서 시작하고
EXPOSE 80 // 80 port로 진행

FROM mcr.microsoft.com/dotnet/sdk:${NET_IMAGE} AS build // image 를 build라고 명명
WORKDIR /src // 디렉토리 변경

// <src>를 <destination>에 COPY 함 (1번만 진행)
COPY ["src/ApiGateways/Aggregators/Web.Shopping.HttpAggregator/Web.Shopping.HttpAggregator.csproj", "src/ApiGateways/Aggregators/Web.Shopping.HttpAggregator/"]
COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"]
COPY ["src/BuildingBlocks/WebHost/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHost/WebHost.Customization/"]
COPY ["src/Services/Basket/Basket.API/Basket.API.csproj", "src/Services/Basket/Basket.API/"]
COPY ["src/Services/Catalog/Catalog.API/Catalog.API.csproj", "src/Services/Catalog/Catalog.API/"]
COPY ["src/Services/Identity/Identity.API/Identity.API.csproj", "src/Services/Identity/Identity.API/"]
COPY ["src/Services/Ordering/Ordering.API/Ordering.API.csproj", "src/Services/Ordering/Ordering.API/"]
COPY ["src/Services/Payment/Payment.API/Payment.API.csproj", "src/Services/Payment/Payment.API/"]
COPY ["src/Web/WebSPA/WebSPA.csproj", "src/Web/WebSPA/"]
COPY ["src/Web/WebStatus/WebStatus.csproj", "src/Web/WebStatus/"]
COPY ["docker-compose.dcproj", "./"]
COPY ["NuGet.config", "./"]
COPY ["eShopOnDapr.sln", "./"]
RUN dotnet restore "eShopOnDapr.sln" // 이 명령어를 실행함 (eShopOnDapr.sln에 있는 종속성 및 모든 도구 복원)

COPY . . // 현재까지 진행된 모든 자료를 현재 디렉토리에 복사
WORKDIR "/src/src/Services/Basket/Basket.API" // 작업경로 변경

FROM build AS publish // 위에 정의한 build를 publish로 재정의
RUN dotnet publish --no-restore "Basket.API.csproj" -c Release -o /app/publish // 뒤의 명령어를 실행함 (복원을 실행하지 않고, Basket.API.csproj 를 Release 구성으로 /app/publish 에 출력)

FROM base AS final // 위에서 정의한 base image를 final로 재정의
WORKDIR /app // 작업경로 변경
COPY --from=publish /app/publish . // publish로 부터 /app/publish 의 내용을 현재 경로에 복사 
ENTRYPOINT ["dotnet", "Basket.API.dll"] // dotnet Basket.API.dll 실행

// src/Web/WebSPA/Dockerfile

ARG NODE_IMAGE=15.12.0-alpine3.12 // Node_IMAGE란 dockerfile 변수
ARG NET_IMAGE=5.0-buster-slim //  NET_IMAGE란 dockerfile 변수
FROM mcr.microsoft.com/dotnet/aspnet:${NET_IMAGE} AS base // 해당 이미지를 불러오고 base라고 명명
WORKDIR /app // 디렉토리 /app으로 변경
EXPOSE 80 // 80 port를 사용함을 명시

RUN apt-get update -yq \
    && apt-get install curl gnupg -yq \
    && curl -sL https://deb.nodesource.com/setup_10.x | bash \
    && apt-get install nodejs -yq // node js를 설치함

FROM node:${NODE_IMAGE} as node-build // node base image를 불러옴
WORKDIR /web // 디렉토리 변경
COPY src/Web/WebSPA/package.json .
COPY src/Web/WebSPA/package-lock.json .
COPY src/Web/WebSPA . // 각각의 파일들을 현재의 위치에 복사
RUN npm i npm@6.14.11 -g && npm update && npm install && npm run build:prod // npm을 글로벌로 설치하고 npm 사용된 library 들을 설치하고 build 함

FROM mcr.microsoft.com/dotnet/sdk:${NET_IMAGE} AS build // base image를 불러오고 이름을 build라고 함

RUN apt-get update -yq \
    && apt-get install curl gnupg -yq \
    && curl -sL https://deb.nodesource.com/setup_10.x | bash \
    && apt-get install nodejs -yq // node js를 설치한다.
WORKDIR /src // 디렉토리 변경

COPY ["src/ApiGateways/Aggregators/Web.Shopping.HttpAggregator/Web.Shopping.HttpAggregator.csproj", "src/ApiGateways/Aggregators/Web.Shopping.HttpAggregator/"]
COPY ["src/BuildingBlocks/EventBus/EventBus/EventBus.csproj", "src/BuildingBlocks/EventBus/EventBus/"]
COPY ["src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj", "src/BuildingBlocks/EventBus/IntegrationEventLogEF/"]
COPY ["src/BuildingBlocks/WebHost/WebHost.Customization/WebHost.Customization.csproj", "src/BuildingBlocks/WebHost/WebHost.Customization/"]
COPY ["src/Services/Basket/Basket.API/Basket.API.csproj", "src/Services/Basket/Basket.API/"]
COPY ["src/Services/Catalog/Catalog.API/Catalog.API.csproj", "src/Services/Catalog/Catalog.API/"]
COPY ["src/Services/Identity/Identity.API/Identity.API.csproj", "src/Services/Identity/Identity.API/"]
COPY ["src/Services/Ordering/Ordering.API/Ordering.API.csproj", "src/Services/Ordering/Ordering.API/"]
COPY ["src/Services/Payment/Payment.API/Payment.API.csproj", "src/Services/Payment/Payment.API/"]
COPY ["src/Web/WebSPA/WebSPA.csproj", "src/Web/WebSPA/"]
COPY ["src/Web/WebStatus/WebStatus.csproj", "src/Web/WebStatus/"]
COPY ["docker-compose.dcproj", "./"]
COPY ["NuGet.config", "./"]
COPY ["eShopOnDapr.sln", "./"] // 해당 디렉토리에 앞의 내용들을 복사
RUN dotnet restore "eShopOnDapr.sln" // 명령어 실행 (eShopOnDapr.sln에 있는 종속성 및 모든 도구 복원)

COPY . . // 모든 내용을 현재 디렉토리에 복사
COPY --from=node-build /web/wwwroot /src/src/Web/WebSPA/wwwroot/ // 위 node-build image layer로 부터 /web/wwwroot 를 /src/src/Web/WebSPA/wwwroot/로 복사
WORKDIR /src/src/Web/WebSPA // 디렉토리 변경
RUN dotnet publish --no-restore -c Release -o /app // 뒤의 명령어를 실행함 (복원을 실행하지 않고, Basket.API.csproj 를 Release 구성으로 /app 에 출력)

FROM build AS publish // build image layer의 이름을 publish로 변경

FROM base AS final // base image layer의 이름을 final로 변경
WORKDIR /app // 디렉토리 변경
COPY --from=publish /app . // publish image layer로 부터 /app 의 내용물을 현재 위치에 복사
ENTRYPOINT ["dotnet", "WebSPA.dll"] // dotnet WebSPA.dll 실행

좋은 웹페이지 즐겨찾기