ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Docker Finding/Creating Images 2
    Infra/컨테이너 2022. 8. 20. 12:07

    Custom 코드(Application)를 포함하는  Docker Container 만들기

    어떻게 하면 Docker Hub에서 제공한는 노드 Imag를 기반으로 활용하여 Docker Finding/Creating Images 1에서 실행한 것과 같은 Application을 실행하는 custom Image를 구축할 수 있을까?

     

    custom image를 build하려면, 일단 코드가 포함된 폴더로 이동해야 한다. 그리고 거기에 새로운 file을 만들어야 한다. Dockerfile이라는 파일인데 이것은 Docker에 의해 식별된는 이름이다.

     

    Dockerfile 명령어

     

    Dockerfile에는 custorm imagefmf 빌드할 때 실행하려는 Docker에 대한 명령이 포함된다. 따라서 base image의 설정을 변경할 수 있는 설정 명령이 포함되어 있다.

     

    FROM

    이 명령어를 통해 base image에 custom image를 구축할 수 있다. 그래서 Dockerfile은 보통 이 명령어로 시작한다. 물론 이론적으로는 Docker Image를 처음 부터 빌드할 수 있지만, 언제나 코드에 필요한 기타 tool과 같은 운영 체제 레이어가 필요하다.

     

    FROM node

    위 와 같이 FROM 뒤에는 build하고 싶은 image의 이름을 넣는다. 특정 Image가 나의 local 컴퓨터 환경에 있거나 Docker Hub와 같은 클라우드 환경에 있을 것이다. 위와 같은 node image를 받고 싶은 경우에 image는 Docker Hub에 있을 것이다.

     

    실제로 이 Docker Hub이미지를 기반으로 컨테이너를 실행했을때 해당 이미지가 local 다운로드 및 캐시되었기 때문에 실제로 이 이미지를 기반으로 컨테이너를 실행한 순간 local 컴퓨터에도 존재하게 된다.

     

    이제 FROM node에서 가르키는 node Image는 로컬에 pull된 Docker Hub이미지이다. 중요한 것은 Dockerfile에 위와 같이 적어 놓았을 때 Docker Hub에서 새로 Image를 pull 받은 뒤에 Container를 생성할 수 있는 상태로 준비된다.

     


     

    COPY

    다음 단계로 Docker에게 local 컴퓨터에 있는 파일이 들 중 어떤 파일을 Image안에 넣을지 하는지 알려야 한다.

    COPY..

    Container에는 두가지 개념의 경로가 있다. 첫번째 경로는 Container외부 또는 Image 외부 경로이고 다시 말해 Image로 복사되어야 할 파일들이 있는 local 컴퓨터와 같은 것의 경로이다.

     

    COPY 다음에 첫번째 dot은 Dockerfile이 포함된 경로 동일한 레벨의 폴더를 의미한다. 하지만 Dockerfile은 제외된다.

    즉 COPY . 은 Dockerfile이 포함된 경로에 레벨에 같이 존재하는 모든 파일과 폴더(폴더 하위에 존재하는 폴더와 파일까지)모두 Image에 복사되어야 함을 의미한다.

     

    COPY의 두번째 dot은 그 복사될 파일들이 저장되어야하는 Container내부 혹은 Image 의 경로를 의미한다. 

    모든 Image와 Image를 기반으로 생성된 모든 Container에는 local 컴퓨처의 파일 시스템에서 완정히 분리된 자체 내부 파일 시스템이 있다.

     

    이때 root 폴더 즉 Container의 root entry를 사용하지 않고 사용자가 생성한 서브 폴더를 사용하는 것이 좋다. 이때 서브 폴더의 이름은 어떤것으로 해도 좋다. 

     

    COPY ./app

    예제에서는 app이라는 이름의 폴더를 생성한다.

     

    위와 같이 Dockerfile에 명령어를 적으면 Dockerfile과 동일한 선상에 있는 모든 파일들과 폴더들 그리고 그 폴더들 하위의 폴더들과 파일들이  Container 내부의 app폴더에 복사된다.

     

    app 폴더가 존재하지 않을 때는 자동으로 Image와 Container에 생성된다. COPY 명령어는 첫번째 핵심 단계이다.

     


    RUN Container안에서 npm install

     

    RUN npm install

    이미지에서 특정 명령을 RUN하고 싶다고 알릴 수 있다.

     

    node JS Application의 경우 node JS Application의 모든 종속성을 설치하기 위해, npm install을 실행해야 한다. 

    그래서 예제의 경우 npm install을 실행한다.

     

    하지만 문제가 존재하는데 디폴트로 이러한 모든 명령은 Docker Container 및 Image 작업 디렉토리에서 실행된다. 디폴트로 그 작업 디렉토리는 Container 파일 시스템의 root 폴더이다.

     

    예제에서는 모든 코드를 포함한 파일과 폴더들을 app폴더에 복사하고 있기 때문에 npm install 역시 app 폴더 안에서 실행되어야 한다.

     


     

    WORKDIR

     

    Docker에게 Container에서 실행될  모든 명령이 특정 폴더에서 실행되어야 한다고 알려주는 편리한 방법은 COPY 명령어가 실행되기 전에 WORKDIR 명령어를 설정하는 것이다.

     

     

    FROM node
    
    WORKDIR /app
    
    COPY . /app
    
    RUN npm install

    WORKDIR은 도커 Containerdml 작업 디렉토리를 설정하는 명령어이다. 예제의 경우 /app으로 설정한다. 또 한 해당 명령은 Docker에게 모든 후속 명령어들이 WORKDIR에 지정된 폴더 내부에서 실행될 것을 알리는 것이다.

     

     

    FROM node
    
    WORKDIR /app
    
    COPY . ./
    
    RUN npm install

    작업 디렉토리를 /app으로 설정했다는 사실을 감안하여 dockerfile이 있는 경로에서 모든 것을 복사하도록 하는 COPY명령을 위와 같이 변경할 수있다.

     

    './' 은 Docker Container의 현재 작업 디렉토리를 의미하기 때문이다. 작업 디렉토리를 /app으로 변경했기 때문에 RUN 뿐만 아니라 COPY도 지정된 작업 디렉토리를 기준으로 실행이된다.

     

    이제 Container 내부 파일 시스템 내에서 './' 이 상대 경로는 /app을 나타내는 것이다. 하지만 './'인 상대 경로를 사용하지 않고 절대 경로인 '/app'을 사용해도 좋다.

     


    CMD

    모든 작업이 완료되면 서버를 시작하라는 명령이다. RUN node server.js 라는 명령으로 서버를 실행 할 수도 있지만 이것은 적절한 명령은 아니다. 왜냐하면 이렇게 되면 해당 Image가 빌드될 때마다 실행되기 때문이다. 그래서 해당 명령은 적절하지 않다.

     

    NodeJS server는 custom Image가 빌드 될 때마다 실행되는 것이 아니라(더불어 Image와 실행한다는 개념은 어울리지 않는다.) Container가 start 될 때마다 실행되야 하기 때문이다.

     

    지금까지 예제에서 사용한 명령어들은 모두 이미지 설정을 위한것이다. Image는 Container에 템플릿이어야 한다는 것을 명심해야된다.

     

    즉 Image를 실행하는 것이 아니라 Image를 기반으로 Container를 실행해야 하는 것이다. RUN npm install로 모든 종속성을 설치하는 것은 Application 구동을 위한 환경을 구축하는 일부이지 실질적으로 Applicaion이 작동하는데 관여하는 실행사항은 아니다.

     

    또한 RUN node server.js와 같은 명령어로 서버를 실행하게 설정할 경우 하나의 Image에서 여러개의 Container를 실행하고 싶어서 일경우라 Container를 실행하게 되면, 동시에 여러개의 서버가 실행되게 할 수 있다.

     

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

    그래서 실질적인 node 서버를 실행하기 위해 필요한 명령어가 CMD이다. RUN과의 차이점은 Image가 생성될때 실행되지 않고 Image를 기반으로 Container가 시작될 때 실행된다는 것이다.

     

    이것이 바로 적절한 node 서버 실행 명령으로 Container가 실행 되고 난 후에 node 서버를 실행하게 해주는 명령이다.

    CMD같은 경우는 문법이 조금 달라 명령어를  배열로 전달한다. 위 와 같이 명령어를 두 개의 문자열로 분할 한다.

     

    CMD에 명령어를 특정하지 않으면 base image가 실행되며, 그것이 없는 경우 error가 발생한다.

     

    Docker에게 이미지를 기반으로 Container가 생성될 때마다  그 Container 내부에 있는 설치된 nodeJS를  nodeJS 명령어를 사용하여 server.js 파일을 실행하도록한다.


    EXPOSE

    EXPOSE 8080

    하지만 위와 같은 방식으로 Container안에 Application을 실행하려고 하면, 한가지 결정적인 원인으로 Application이 실행되는 것을 포착하지 못할 것이다.

     

    예제의 Node 웹 서버는 포트 8080에서 수신을 대기하게 된다. 하지만 Docker Container는 local 컴퓨터와 격리되어 있다. 즉 Container에는 자제적인 내부 네트워크가 있는 의미다.

     

    Container 내부에 노드 Application에서 포트 8080을 수신(request)할 때 Container는 해당 포트를 local 컴퓨터 환경에 까지 노출하지 않는다.

     

    따라서 격리된 Container 내부에서만 노드 웹 서버가 request가 들어오기를 수신 대기 중이기 때문에 local 컴퓨터 환경에서는 해당 포트를 통해서 Container안에 NodeJS server에 request를 보낼 수 없다.

     

    그래서 언제나 Dockerfile의 마지막 명령 전에 해당 Image로 Container를 실행할 때 Container가 실행될 local 컴퓨터 환경에 특정 포트를 노출하고 싶다는 것을 알리는 EXPOSE 명령을 추가해야 한다.

     

    그런 후에 위 예제에서 설정된 것처럼 8080포트에 수신이 local 환경에 노출된 Container를 실행할 수 있는 것이다.


    최종 Dockerfile

    FROM node
    
    WORKDIR /app
    
    COPY . /app
    
    RUN npm install
    
    EXPOSE 8080
    
    CMD node server.js

    댓글

Designed by Tistory.