-
Docker Layer를 기반으로 하는 아키텍쳐 ImageInfra/컨테이너 2022. 8. 21. 13:09
Image의 Layer
custom image를 build한 후에 소스코드의 수정사항이 없이 다시 또다른 custom image를 build해서 만들어 내면 매우 빠른 속도로 새로운 custorm image가 만들어 지는 것을 확인할 수 있다.
이때 CACHED(캐시되었다)라는 메시지를 볼 수 있다. 왜냐하면 Docker는 기본적으로 위 모든 명령에 대해 명령어를 다시 실행 했을 때의 결과가 이전과 동일하다는 것을 인식했기 때문이다.
동인한 작업 디렉토리를 가지고 있고(/app), 복사할 코드는 전혀 변경되지 않았으며, 복사가 필요한 새 파일도 변경된 파일도 없음으로 Docker는 실제로 그 명령을 다시 거칠 필요가 없다고 추론한 것이다.
image를 build할 때마다 도커는 모든 명령 결과를 캐시하고 image를 다시 빌드할 때 명령을 다시 실행할 필요가 없으면 이렇게 캐시된 결과를 사용한다. 이것을 레이어 기반 아키텍처라고 한다.
모든 명령은 Dockerfile의 레이어를 나타낸다. 그리고 image는 이러한 다양한 명령을 기반으로 여러 레이어 단계를 간단하게 구성하게 된다. 또한 image는 읽기 전용이므로 즉 일단 명령이 실행되고 image가 빌드되면, image가 잠기고 image를 다시 build하지 않는 한 그 코드를 변경할 수 없다.
Layer 추가 개념의 Container
모든 명령어를 기반으로 하는 image 레이어는 레이어를 생성하고, 이러한 레이어는 캐시된다. 그런 다음 image를 기반으로 Container를 실행하면 그 컨테이너는 기본적으로 Dockerfile에 지정한 명령을 실행한 결과로 코드를 실행 중 이 되는 Container의 Application은 image위에 새로운 레이어가 추가되는 개념이다.
이렇게 하면 image를 실행할 때만 활성화되는 최종 레이어가 추가된다. 최종명령(CMD) 이전의 모든 명령은 이미 image의 일부이지만 또 각각 별도의 레이어(layer)이기도 하다
아무런 변경사항이 없으면 최종명령 이전의 레이어는 캐시에서 사용할 수 있다.
소스코드 변경 사항이 있을 때 custom image 다시build
<section> //<h2>My Course Goal!</h2> <h2>My Course Goal!!!!!!!</h2> <h3>${userGoal}</h3> </section>
이제 원본 소스코드에서 무언가 코드를 수정하면 그 소스코드를 원본으로 하여 custom image를 build할 때 앞전에 수정 사항이 없이 또 같은 소스코드를 build할 때 보다는 시간이 더 걸린다는 것을 알 수 있다.
왜냐하면 캐시의 일부 결과만을 사용하기 때문이다. 위 사진에서 보면 image build시 [2/4] 단계에서는 캐시의 작업 디렉토리 명령을 사용했지만 [3/4]단계인 COPY명령의 경우에는 캐시를 사용하지 않고 새롭게 layer를 만들었다.
Docker가 복사해야할 파일을 스캔하고 하나의 파일의 코드가 변경된 것을 감지하여 모든 파일을 다시 복사하기 때문이다. 또한 하나의 레이어가 변경될 때마다 다른 모든 레이어가 다시 build된다. 즉, 한 레이어가 변경될 때마다 모든 후속 레이어도 다시 실행된다.
Docker는 npm install(종속성 설치를 위한 명령어)이 특정 레이어가 변하기 전과 변하기 후에 동일한 결과를 산출할지 그 여부를 알 수 없기 때문이다. Docker는 파일을 다시 복사 하고 npm install에 영향을 줄 수 있는 위치와 변경한 파일에 대한 심층적인 분석을 수행하지 않는다.
Docker의 캐시와 레이어는 다시 실행해야 하는 항목만 다시 build하여 다시 실행하여 image의 생성 속도를 높이기 위해 존재한다. 물론 이것은 매우 유용한 메커니즘이다.
또한 그것은 불필요한 경우에도 코드에서 무엇인가를 변경한 후에 custorm image를 build할 때는 그때 마다 npm install을 다시 실행해야 한다는 것을 의미한다. 사실 프로젝트의 종속성을 관리하는 package.json에서 무언가를 변경하지 않는 한 npm install을 다시 실행할 필요가 없다. 하지만 Docker는 이것을 구분하지 못한다.
즉 server.js의 코드만 수정한 경우 해당 프로젝트에 필요한 종속성에 영향을 미치지 않으므로 사실상 npm install를 다시 실행할 필요가 없다.
Dockerfile 명령어 재배치
FROM node WORKDIR /app COPY . /app RUN npm install EXPOSE 8080 CMD node server.js
Dockerfile에 대한 최적화 가능성의 첫번째 부분이 있다. 위 와 같이 Dockerfile에 동일 선상에 있는 경로의 파일들과 폴더를 모두 복사한 다음 npm install을 실행하는 다시 말해 server.js와 package.json을 app이라는 폴더의 하위 파일로 한번에 복사하는 대신
FROM node WORKDIR /app COPY package.json /app RUN npm install COPY . /app EXPOSE 8080 CMD node server.js
npm install 후에 모두를 복사하고, npm install을 실행하기 전에 package.json 파일도 /app에 복사한다. 이로써, 소스코드를 복사하기 전에 npm install(RUN)레이어가 오게 되는 것이다.
따라서 앞으로는 소스 코드를 변경할 때마다 소스코드 복사명령(COPY)명령 앞의 npm install(RUN)을 통한 프로젝트를 위한 종속성 설치 실행 레이어가 포함되었다는 이유로 무효화되지 않는다.
이제 "COPY . /app" 뒤에 존재하는 명령어들만 다시 실행되며 완료되는데 어느 정도 시간이 걸리는 npm install(RUN)을 다시 실행해야 하는 것보다 성능이 좋을 것이다.
이제 수정된 Dockerfile을 다시 build하면 [3/5]~[4/5] 단계에서 npm install을 실행하여 종속성을 실행하고 [5/5]단계에서 프로젝트의 소스코드들을 COPY해 오는 것을 확인할 수 있다.
위에서 build한 custom image를 사용하여 Container를 run하고 브라우저를 통해 localhost:7000에 접속하면 이전에 변경한 소스 코드 <h2> 태그를 제외하고는 별다른 이전의 접속한 노드서버와 별다른 차이점이 없다는 것을 확인할 수 있다.
stop으로 해당 Container를 종료하고 소스코드를 다시 업데이트하여 <h2> tag의 모든 느낌표를 제거하고 해당 소스코드를 기반으로 또 새로운 custom image를 build하면 build속도가 다시 매우 빨라진 것을 확인 할 수 있고,
이는 Docker package.json에는 변경사항이 없음을 확인하고 노드 Application에 종속성을 설치한는 과정을 모두 캐시에서 가져왔기 때문이다.
이것은 작은 최적화이지만 이 최적화보다 더 중요한 것은 우리가 그것을 왜 하는지 이해하고 이런 레이어 기반 접근방식 레이어 기반의 아키텍쳐를 이해하는 것이다. 이것이 Docker와 Docker image에 핵심 개념이다.
첫번째 중간 정리
결국 Docker는 우리의 코드에 관한 모든 것이다. 그 코드는 특정 Application을 구축하기 위해서 존재한다. 예를 들어 그 Application이 웹 애플리케이션이라고 해보자
Application을 구성하는 코드를 Image라고 불리는 것에 집어 넣는다. 거기에 소스코드를 넣을 뿐만 아니라 그 코드를 실행하는데 필요한 도구인 실행 환경도 넣는다.
Dockerfile을 생성하여 세부적인 명령을 그것을 통해 제공하여 환경을 설정한다 가령 다음과 같은 것이다.1) Image에 무엇을 집어 넣을 것인지, 2)어떤 Image를 base image를 사용할 것인지, 3)어떤 코드와 어떤 종속성이 복사 될 것인지, npm install과 같은 종속성 설치를 위한 설정단계가 요구되는지, 4)Container 내부 포트를 개방해 궁극적으로 local 환경 즉 외부 에서 Container를 다룰 수 있도록 수신대기를 하는 것 등등
Docker는 궁극적으로 Image가 아니라 Container에 관한 것이라는 것도 중요한 포인트이다. 하지만 Image 또한 중요한 빌딩 블록이며 Container의 blueprint(청사진)이자 템플릿이다.
그런 다음 Image인 청산진을 인스턴스화 해서 그것을 기반으로한 여러 Container를 실행할 수 있다. Image는 직접 작성한 코드 등이 포함된 것이고, 지금 까지 배운 Container는 Image위에 추가된 얇은 레이어일 뿐이다.
하지만 Container는 여전히 Image를 기반으로 하는 실행 애플리케이션이기도 하다. 그러나 일단 실행되면 실행중인 다른 Container와는 독립적인 *stand alone이다.
*stand alone : [정보·통신 ] 컴퓨터나 프로그램이 다른 컴퓨터나 프로그램에 접속되어 있지 않고 독립적으로 작동하는 상태. ⇒규범 표기는 미확정이다.
여기서 강조해야 하는 것은 Container가 Image에서 코드와 환경을 새로은 Container로 복사하거나 새 파일로 복사하지 않는 다는 것이다. 그런일은 벌어지지 않는다. 단지 Container는 Image에 저장된 환경을 사용한다.
예를 들어 Container는 노드 서버 프로세스는 애플리케이션을 실행하기 위해 resource, memory등을 할당한다. 하지만 코드를 복사하지는 않는다.
코드는 오로지 한 번 Image에 복사될 뿐이다. 그리고 그 Image와 그 안에 복사된 코드는 Container어라는 형태로 활용되는 것이다. 이것이 Docker의 관리법이며 핵심 아이디어이다.
Application을 포함하는 격리된 환경이 Container로 존재한다. 그리고 해당 Application을 실행하는데 필요한 모든 환경을 예를 들어 Node JS와 같은 도구를 그 Container 내부에 포함한다.
'Infra > 컨테이너' 카테고리의 다른 글
Docker Container 중지 & 재시작 (0) 2022.08.22 Docker Image와 Comtainer 관리 (0) 2022.08.22 Docker custom Image의 동작방식(소스코드에 변경사항이 있을 경우) (0) 2022.08.21 Docker Custom Image (0) 2022.08.20 Docker Finding/Creating Images 2 (0) 2022.08.20