목차

Dockerfile이 있는데 빌드 서버가 필요할까?

대부분의 프로그래밍 언어는 프로젝트를 빌드하기 위해 다양한 도구가 필요함

- 신규로 참여한 개발자는 이 도구를 설치하는데 시간을 허비 할 수 있다.  ( 빌드 서버와 버전이 달라지는 것만으로 빌드가 실패 할 수 있음)

 

이런 경우에 빌드 툴 체인을 한 번에 패키딩해서 공유할 수 있다면 편하다 → Dockerfile 스크립트

  1. 개발에 필요한 모든 도구를 배포하는 Dockerfile 스크립트 작성하여 모두 이미지로 만든다.

  2. 애플리케이션 패키징을 위한 Dockerfile 스크립트에서 이 이미지를 사용해 소스 코드를 컴파일함으써 애플리케이션을 패키징

 

위의 워크플로(멀티 스테이지 빌드)를 적용한 Dockerfile 스크립트

FROM diamol/base AS build-stage
RUN echo 'Building...' > /build.txt

FROM diamol/base AS test-stage
COPY --from=build-stage /build.txt /build.txt
RUN echo 'Building...' >> /build.txt

FROM diamol/base
COPY --from=test-stage /build.txt /build.txt
CMD  cat /build.txt

  - 모든 stage 는 FROM 으로 시작하는데 빌드 단계에 필요에 의해 AS 를 이용하여 이름을 붙일 수 있다.

 

실행과정을 표현한 그림 -  각 빌드 단계는 서로 격리돼 있다.

 

현재 폴더에 있는 Dockerfile 실행하여 multi-stage 이미지 빌드

docker image build -t multi-stage .

 

Terminal 출력 결과
Docker 에서 확인한 Log

  • build-stage = 빌드 도구가 설치된 기반 이미지를 사용하여 빌드
  • test-stage =  빌드한 바이너리를 복사해서 단위 테스를 수행
  • 마지막으로 build-stage 에서 빌드하고 test-stage에서 테스트까지 성공적으로 마친 바이너리를 이 이미지에 복사해서 넣는다.

이 과정을 표현한 그림

애플리케이션 빌드 실전예제: Node.js 소스 코드

컨테이너화된 Node.js 애플리케이션을 실행하려면

- Node.js 런타임 과 소스 코드가 애플리케이션 이미지에 포함되어야 함.

(ch04/exercises/access-log 에 있는 파일)

npm 을 사용해 Node.js 애플리케이션을 빌드하는 Dokcerfile 스크립트

FROM diamol/node AS builder

WORKDIR /src
COPY src/package.json .
RUN npm install

# app
FROM diamol/node

EXPOSE 80
CMD ["node", "server.js"]

WORKDIR /app
COPY --from=builder /src/node_modules/ /app/node_modules/
COPY src/ .

 

1. Dockerfile 실행하여 이미지 빌드

docker image build -t access-log .

 

2. 빌드 한 access-log 이미지로 컨테이너로 실행, 이 컨테이너를 nat 네트워크에 연결하며 80번 포트를 공개하라.

docker container run --name accesslog -d -p 801:80 --network nat access-log
  •  -d (Detached mode)  = 백그라운드에서 실행
  • -p  = 포트 맵핑
  • 이때 "docker: Error response from daemon: network nat not found." 라는 문구가 뜰 수 있다.
docker network ls

    이용해서 네트워크를 확인하여 nat 의 존재 여부를 한 번더 확인 후 없으면

 

  nat 생성 후  다시  2번 에서 실행된 명령어 실행

docker network create -d bridge nat

 

성공적으로 이미지가 컨테이너에 담기면

http://localhost:801/stats 에 접속하여 결과를 확인

 

멀티 스테이지 Dockerfile 스크립트 이해하기

컨테이너 안에서 애플리케이션을 빌드하는 것이 유용한 이유

  1. 표준화 = 어떤 운영체제를 사용하든 모든 과정은 도커 컨테이너 내부에서 이루어 진다.
    • 컨테이너가 빌드하기 위한 모든 도구들의 정확한 버전을 보유하고 있으므로 빌드 실패를 크게 줄인다.
  2. 성능향상 = 멀티 스테이지 빌드의 각 단계는 자신만의 캐시를 따로 갖는다.
    • 처음에 Dockerfile 스크립트를 세심하게 최적화해서 작성한다면  이후로 캐시 재사용을 통해 90% 이상의 빌드 단계에서 시간을 절약할 수 있다. - 이유 : 빌드 중에 각 인트스럭션에 해당하는 레이어 캐시를 보유(3장에서 자세한 내용참고)
  3. 빌드 과정의 세밀한 조정하며 이미지를 가능한 한 작게 유지 가능
    • 예 ) curl 을 이용하여 인터넷을 통해 필요한 파일을 다운 받는다.  이 과정을 빌드 초기 단계에 모아 놓는다면 최종 이미제는 curl 을 포함시키지 않아도 된다. → 이미지 크기 줄여서 애플리케이션 시작 시간을 단축 가능

연습: 멀티 스테이지 빌드와 Dockerfile 스크립트 최적화

Dockerfile 스트크립트

FROM diamol/golang 

WORKDIR web
COPY index.html .
COPY main.go .

RUN go build -o /web/server
RUN chmod +x /web/server

CMD ["/web/server"]
ENV USER=sixeyed
EXPOSE 80

 

해결해야 할 문제

  • 지금 있는 Dockerfile 스크립트로 이미지를 빌드한다. 이어서 Dockerfile 스크립트를 최적화한 다음 새로운 이미지를 빌드하라.
  • 현재 이미지는 리눅스 환경에서 약 800MB, 윈도 환경에서 약 5.2GB 크기다. 최적화 된 이미지의 크기는 리눅스 환경에서 약 15MB, 윈도 환경에서 약 260MB가 되도록하라.
  • 현재 Dockerfile 스크립트에 포함된 HTML 파일의 내용을 수정하면 7 단계의 빌드 단계를 재수행한다.
  • Dockerfile 스크립트를 최적화해서 HTML 파일을 수정하더라도 재수행하는 빌드 단계가 한 단계가 되도록 하라.

[힌트] 주어진 Dockerfile 스트크립트와 같은 애플리케이션을 실행하는 Dockerfile

더보기
FROM diamol/golang AS builder

COPY main.go .
RUN go build -o /server

# app
FROM diamol/base
ENV IMAGE_API_URL="http://iotd/image" \
    ACCESS_API_URL="http://accesslog/access-log"

CMD ["/web/server"]

WORKDIR /web
COPY index.html .
COPY --from=builder /server .
RUN chmod +x server

 

최적화 후

FROM diamol/golang AS builder

COPY main.go .
RUN go build -o /server
RUN chmod +x /server

# 프로덕션 이미지
FROM diamol/base

EXPOSE 80
CMD ["/web/server"]
ENV USER="sixeyed"

WORKDIR web
COPY --from=builder /server .
COPY index.html .

 

설명

      1. 멀티 스테이지 이용하여 이미지의 크기 감소 
        • builder 스테이지에서 빌드된 바이너리를 프로덕션 스테이지로 복사
          • builder 스테이지에서 필요한 도구와 라이브러리를 설치
            • diamol/golang 이미지를 기반으로 하고, main.go 파일을 복사한 후 /server로 실행 파일을 빌드
          • 프로덕션 스테이지에서 index.html/server만 포함되므로 더 경량화된 이미지 생성가능
      2. builder 스테이지에서 권한을 부여하여 중복되는 작업 제거 
        • RUN chmod +x /server를 통해 실행 권한을 부여 (빌드과정에서 부여하는 것이 적합)
          • 이유 = 빌드 과정에서 파일의 실행 권한을 한 번 설정하면, 이후 단계에서 반복적으로 설정할 필요가 없다. 즉, 빌드 과정에서 chmod +x를 실행하면, 해당 명령이 한 번만 실행되고 이후 단계에서는 캐시를 재사용
      3. 멀티 스테이지 이용하여 중복될수 있는 문제 해결
        1. builder 스테이지에서 권한을 부여하여 중복되는 작업 제거
          • RUN chmod +x /server를 통해 실행 권한을 부여 (빌드과정에서 부여하는 것이 적합)
            • 유 = 빌드 과정에서 파일의 실행 권한을 한 번 설정하면, 이후 단계에서 반복적으로 설정할 필요가 없다. 즉, 빌드 과정에서 chmod +x를 실행하면, 해당 명령이 한 번만 실행되고 이후 단계에서는 캐시를 재사용
        2. ENVWORKDIR를 프로덕션 스테이지에 배치하여 중복 작업 방지
          • 프로덕션 단계에만 필요한 설정(ENV, WORKDIR)은 빌더 단계에서 실행할 필요가 없으므로, 프로덕션 스테이지에 배치하여 불필요한 중복 작업을 제거
        3. 불필요한 이미지 레이어 생성 방지
          • Docker는 각 명령어(RUN, COPY, ENV, WORKDIR 등)를 실행할 때마다 새로운 이미지 레이어를 생성
          • builder프로덕션 스테이지 구별이 없으므로 불필요한 레이어 생성 → 이미지 전체에 영향
        •  

+ Recent posts