본문 바로가기
개발공부 개발새발/Docker

Docker ) 도커 이미지를 만들고 컨테이너를 실행하자. with Dockerfile

by 휴일이 2024. 2. 26.

Docker 실행..

docker run node
  • 노드를 기반으로 컨테이너를 실행한다.
  • 하지만, 노드에 의해 노출된 인터렉티브 쉘은 우리에게 자동으로 노출되지 않기 때문에 이 명령어를 사용해도 컨테이너만 생성될 뿐 아무 변화도 없다.
docker run -it node
  • 도커 컨테이너 내부에서 호스팅 머신으로 대화형 세션을 노출하고 싶다고 알린다.
  • 그러면 기본 노드 명령을 실행할 수 있는 인터렉티브 노드 터미널로 접속이 가능하다!

→ 우리 컴퓨터 안에서 노드가 설치되진 않았지만 노드가 실제로 컨테이너 안에서 실행중이며, 노드와 상호작용 할 수 있다는 걸 알 수 있다.

 

 

터미널로 나와보면,…

 

  • 도커 컨테이너 내의 노드 버전과 내 컴퓨터에 있는 노드 버전이 다른 걸 알 수 있다.
  • 나는 아까 컨테이너 안의 노드와 상호작용 했다는 뜻!

→ 이렇게 하면 시스템에 노드를 설치할 필요가 없다!

Dockerfile

자체 이미지를 빌드할 때 실행하려는 도커 명령 → 설정 명령이 포함되어 있다.

FROM node

WORKDIR /app

COPY . /app

RUN npm install 

EXPOSE 80

CMD ["node", "server.js"]
FROM node
  • 실행에 필요한 운영체제 레이어, 도커 허브 상의 이미지 이름으로 넣는다.
WORKDIR /app
  • 모든 후속 명령이 해당 디렉토리에서 실행한다.
COPY . /app
  • 로컬 머신에 있는 파일이 이미지에 들어가야하는지 알린다.
  • 프로젝트 루트 디렉토리의 모든 폴더가 → 컨테이너 내부의 /app 에 복사된다.
  • 첫번째 . : 컨테이너 외부(이미지 외부 경로) 이미지로 복사되어야 할 파일이 있는 곳.
    • 도커 파일이 있는 경로라고 알려준다. 이 때, 도커 파일은 제외된다.
    • 이 프로젝트의 모든 폴더, 하위 폴더를 이미지화 한다고 알린다.
  • 두번째 /app : 이미지 저장 경로.
    • . 이라고 하면 도커 컨테이너의 루트 엔트리
      • 사용자가 선택한 서브 폴더를 사용하는 것이 좋다. (이름 지정 가능) → 존재하지 않으면 자동으로 만들어짐
    • ./ 라고 쓰면 도커 컨테이너의 현재 작업 디렉토리, 즉 /app 에 복사된다.
    • 하지만 보통 현재 작업 디렉토리를 명확하게 하기 위해 /app 으로 명시적으로 설정하는 게 좋다.
RUN npm install
  • 해당 명령은 /app 디렉토리 안에서 실행된다. → WORKDIR 지정해줘야 함.
EXPOSE 80
  • 도커 마지막 명령 전, 어떤 포트에 연결되어야 하는지 로컬 머신에게 지시한다.
CMD ["node", "server.js"]
  • server.js 파일을 실행하도록 지시한다.
  • 이미지를 실행시킬 때 실행되는 명령어가 아니라, 이미지를 기반으로 컨테이너가 시작될 때 실행되는 명령어.
  • 띄어쓰기를 기준으로 배열로 줘야 함.
  • CMD 에 명령어를 특정하지 않으면 베이스 이미지가 실행되고, 에러 발생.

 

💡 이미지는 컨테이너의 템플릿 임을 명심하자.
”이미지를 실행”시키는 것이 아니라, 이미지를 기반으로 “컨테이너를 실행”시키는 것!




 

이미지 빌드

docker build .
  • Dockerfile 로 도커 이미지를 빌드하는 명령어
    • . → 이 명령을 실행하는 곳과 동일한 곳에 Dockerfile 이 존재한다.
    • . 앞에 이미지 이름을 써서 지정할 수 있다.
      • docker build node_server:v1.0.0 .
        • 이미지 이름 : node_server
        • 태그 : v1.0.0

실행하면

[+] Building 2.1s (9/9) FINISHED                                                                                                                                                                            docker:desktop-linux
 => [internal] load build definition from Dockerfile                                                                                                                                                                        0.0s
 => => transferring dockerfile: 2.06kB                                                                                                                                                                                      0.0s
 => [internal] load .dockerignore                                                                                                                                                                                           0.0s
 => => transferring context: 2B                                                                                                                                                                                             0.0s
 => [internal] load metadata for docker.io/library/node:latest                                                                                                                                                              0.0s
 => [1/4] FROM docker.io/library/node                                                                                                                                                                                       0.0s
 => [internal] load build context                                                                                                                                                                                           0.0s
 => => transferring context: 10.43kB                                                                                                                                                                                        0.0s
 => [2/4] WORKDIR /app                                                                                                                                                                                                      0.0s
 => [3/4] COPY . /app                                                                                                                                                                                                       0.0s
 => [4/4] RUN npm install                                                                                                                                                                                                   1.9s
 => exporting to image                                                                                                                                                                                                      0.1s
 => => exporting layers                                                                                                                                                                                                     0.1s
 => => writing image sha256:4d1f959dcb74b20608582aeb4e4d9313e0f0e7c45ecca18f95ae5ca718cf2bd9  

→ 내가 쓴 Dockerfile 이 실행된다.

  • 제일 아랫줄이 이미지 id
docker run 4d1f959dcb74b20608582aeb4e4d9313e0f0e7c45ecca18f95ae5ca718cf2bd9
  • 이걸 실행하면 도커 컨테이너가 멈추지 않고 실행된다.
  • 컨테이너가 시작될 때 실행된 명령어 CMD ["node", "server.js"] 가 완료되지 않았기 때문 !
  • 하지만 로컬에서 작동되지 않는다. 왜일까?

일단 컨테이너를 종료하자

# 내 로컬에 만들어져있는 모든 컨테이너 목록 보기
docker ps -a

# 컨테이너 목록
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS                  PORTS     NAMES
bd1de1d2926b   4d1f959dcb74   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes            80/tcp    distracted_jennings

# 자동으로 만들어진 컨테이너 이름을 넣어서 정지시킨다. (container id 를 넣어도 됨)
docker stop distracted_jennings

# 컨테이너 삭제
docker rm distracted_jennings

왜 안될까요?

 

  • 보면 요 노드 서버는 80 포트에서 요청을 받는다.
  • 우리가 도커파일에서 EXPOSE 80 라고 80 포트를 사용한다고 해놓긴 했지만, 사실 이건 documentation 용…ㅎㅎ → 그래도 추가는 해줍시다!
  • 80 포트를 사용하도록 설정해주쟈 ㅎ_ㅎ
# -p : publish
# 어떤 로컬 포트에 액세스 해야 하는지 알려준다.

# 로컬포트:내부 도커 컨테이너 노출 포트 (여기서는 80)
docker run -p 3000:80 4d1f959dcb74

이렇게 컨테이너를 실행시키고 http://localhost:3000 에 접속하쟈

 

 

 

 

 

성고옹~ 🫡

 

 

💡 결국 EXPOSE 80 은 선택 사항이고 이 포트를 사용할 것임을 문서화하는 작업이다. 실제로 도커 컨테이너를 빌드할 때 -p 를 사용해야만 실제 포트가 노출된다. 그래도 문서화하는 것이 모범적인 사용법이라고 한다.

 

 

💡 아이디를 사용하는 모든 docker 명령은 항상 전체 id 를 복사 / 붙여넣기 할 필요는 없다!
첫 번째로 시작하는 문자 몇 개를 써도 충분하다.
만약, image id 가 a 로 시작하는 컨테이너가 단 한 개 라면? → docker run a 명령어로 해당 컨테이너를 실행 가능하다!

 

728x90

'개발공부 개발새발 > Docker' 카테고리의 다른 글

Docker ) Network  (0) 2024.03.29
Docker ) ARG 와 ENV  (0) 2024.03.18
Docker ) 도커 볼륨과 바인드 마운트  (0) 2024.03.18
Docker ) 이미지, 컨테이너 관리.  (0) 2024.03.03
Docker ) 도커 이미지 기초  (1) 2024.02.28