[Docker] 도커 파일 최적화

스윗포테이토·2022년 12월 13일
1

docker

목록 보기
1/2
post-custom-banner

도커의 장점은 각 프로젝트에 맞는 이미지를 설치하고, 이 환경을 docker-compose로 관리함으로써 팀원 모두가 같은 환경에서 개발할 수 있고 또한 배포할 때 따로 환경 세팅을 하지 않아도 된다.

그러나 도커 파일을 대충 작성하면 도커를 빌드하고 올리는 과정에서 시간이 많이 소요되어서 오히려 효율적이지 못할 수 있다. 처음 대충 쓸데는 컨테이너 수도 적고, 시간이 많이 필요하지 않았었는데 점점 컨테이너가 많이 추가되면서 윈도우 빌드는 정말 오래 걸리는 사태가 발생했다. 따라서 현재 도커파일을 수정하면서 최적화를 조금 시켜보려고 한다.

shell vs exec

Dockerfile의 CMD, RUN 등 실행 명령어를 전달할 때 shell type과 exec type이 있다.

  • shell type
    RUN env
  • exec type
    CMD ["env"]

shell type은 항상 쉘을 통해 실행되므로 불필요한 프로세스가 실행될 수 있다. 따라서 쉘 기능이 필요한게 아니라면 exec type으로 작성하는 것이 좋다고 한다. 또한 쉘(/bin/sh)은 docker stop 등으로 인한 종료 요청을 무시하기 때문에 강제종료가 이루어질 수 있다. 따라서 gracefully shut down 될 수 있도록 하려면 exec type을 써야 한다.

프로세스 수 줄이기

개발할 때는 npm start를 통해 프론트 서버를 띄우고 있는데, 이게 실행되는 과정을 볼 필요가 있다.

우선 npm start를 통해 컨테이너를 띄운 상황을 보자.

  • 컨테이너 접속

    docker exec -it frontend /bin/sh

    컨테이너에 접속해 top을 통해 실행 중인 프로세스를 조회해보면,

    현재 npm start를 위해 총 3개의 프로세스가 쓰이는 것을 볼 수 있다.
    npm startnode를 실행하고, node가 start 스크립트를 실행하는 것을 볼 수 있다. 따라서 CMD 자체를 [ "node", "node_modules/react-scripts/scripts/start.js"]로 바꿔주었다.

    CMD [ "node", "node_modules/react-scripts/scripts/start.js" ]


    확인해보니 프로세스 수가 하나로 줄은 것을 알 수 있다.

캐싱 활용하기

기본적으로 Dockerfile의 명령어 단위로 레이어가 생성되고 캐싱이 이루어진다. 변경사항이 없고 캐싱된 레이어가 있다면, 새로 만들지 않고 전에 쌓았던 레이어를 재활용하는 것이다. 그러나 한번 변경사항이 생기면 그 이후부터는 모조리 새로 생성하게 된다. 따라서 Dockerfile의 작성 순서 또한 빌드 시간에 영향을 미칠 것이다.

따라서 패키지 등의 설치에서 의존성을 고려하면서도, 자주 바뀌는 것을 가능한 뒤쪽으로 배치하고 자주 변하지 않는 부분을 앞쪽에 배치하는 것이 좋다.

예를 들어, 리액트의 경우

FROM node:16-alpine3.15
WORKDIR /client

COPY [".", "."]

RUN ["npm", "install", "react-scripts", "-g", "--slient"]
RUN ["npm", "install", "--silent"]

CMD ["node", "node_modules/react-scripts/scripts/start.js"]

이렇게 되면 3번째 명령어인 COPY에 의해 소스코드가 바뀔 때마다 npm install이 새로 진행될 것이다. 그러나 npm install은 패키지가 변경할 때만 실행하면 된다. 따라서

FROM node:16-alpine3.15

WORKDIR /client

# install package
COPY ["package*.json", "./"]
RUN ["npm", "install", "react-scripts", "-g", "--slient"]
RUN ["npm", "install", "--silent"]

# run npm server
COPY [".", "."]
CMD ["node", "node_modules/react-scripts/scripts/start.js"]

package.json 만 미리 복사하여 패키지가 변하지 않았을 경우 COPY 이전 단계까지는 캐싱된 레이어를 사용하도록 작성할 수 있다.

추가) 변경사항을 판단하는 기준

  • 기본적으로 명령어 문자열의 변경사항을 감지한다.
  • ADDCOPY의 경우, 해당 파일의 변경사항까지 감지한다.

dockerignore 활용

Dockerfile에서 빌드에 필요한 소스코드 등을 COPY [".", "."]를 통해 전부 복사하는 경우가 있다. 이 경우 빌드에 필요하지 않은 파일이 로컬에 저장되어 있다면 dockerignore 파일을 작성해서 제외해주는 것이 좋다. 용량이 적은 파일 한 두개 정도는 큰 문제가 되지 않지만, node_modules와 같이 용량이 조금 있는 폴더의 경우 제외하면 빌드 시간 단축에 큰 도움이 된다. 나의 경우, 도커 이미지에서 npm install을 하기 때문에 로컬의 node_modules를 복사해갈 필요가 없었다. 따라서 .dockerignore 파일을 생성해서 제외시켜주었다.


reference

Dockerfile 최적화하기
[Docker] Dockerfile cache 및 작성 Tip

profile
나의 삽질이 미래의 누군가를 구할 수 있다면...
post-custom-banner

0개의 댓글