먼저 우리가 만든 어플리케이션을 docker를 사용하여 실행시킬 수 있어야 한다.
docker에 대한 기본적인 개념은 안다고 가정하고 바로 스타트!
우리의 프로젝트를 docker image로 만드려면 Dockerfile을 작성해야한다.
Dockerfile이란 이미지를 만들기 위한 설정 파일이면서, 컨테이너가 어떻게 실행시켜야 하는지에 대한 설정을 정의하는 파일이다.
Dockerfile을 만드는 순서는 이미지가 필요한 것이 무엇인지를 생각하면서 작성하면 된다.
1. 가장 먼저 이미지의 기반이 되는 베이스 이미지를 적어주고,
2. 어플리케이션을 실행하기 위해 추가적으로 필요한 정보를 다운받을 수 있는 명령어를 적어준다.
3. 그 다음 이 이미지로 생성할 컨테이너에서 실행시킬 명령어를 적어주면 된다.
Dockerfile 작성 시 사용되는 명령어들을 알아보자
FROM <이미지 이름>:<태그>
# node 이미지 사용
FROM node:20:10.0-alpine
<이미지 이름>:<태그> 형식으로 작성하면 되는데, 태그가 없을 경우 가장 최신 이미지를 다운받는다.
docker hub에서 원하는 이미지를 검색해서 사용하면 된다.
우리 프로젝트의 경우 node v20.10.0을 사용하고 있어서 node:20:10.0-alpine
을 베이스 이미지로 명시해줬는데, 뒤에 붙은 alpine의 의미는 node 20.10.0 이미지 중에 가장 작은 사이즈의 이미지로 딱 필요한 것만 담겨져있는 이미지를 의미한다.
WORKDIR <작업 폴더 경로>
# 예시
WORKDIR /usr/src/app
WORKDIR을 지정하면 이후에 실행되는 명령어들은 해당 디렉토리를 기준이로 실행이 된다.
COPY <호스트 컴퓨터의 폴더/파일> <이미지 내 경로>
# package.json, yarn.lock 복사
COPY package.json ./
COPY yarn.lock ./
RUN <커맨드>
RUN ["<커맨드>", "<파라미터>", ..]
# package 설치
RUN yarn install
이미지를 만들 때 실행시켜야할 커맨드가 있을 때 사용한다.
패키지 매니저로 yarn을 사용하고 있어서 package 설치를 위해 yarn install
을 RUN
명령어로 실행시켜주었다.
EXPOSE <포트>/<프로토콜>
근데 이렇게 선언한다고 해서 호스트의 특정 포트와 연결되는건 아니고 이 이미지로 만들어진 컨테이너는 EXPOSE로 지정된 포트와 프로토콜로 접근이 가능하다의 의미가 된다고 한다. 호스트의 특정 포트와 매핑을 하려면 컨테이너화 할 때 -p 옵션을 사용해서 포트 연결을 해줘야 한다.
CMD ["<커맨드>", "<파라미터1>", ..]
CMD ["<파라미터1>", "<파라미터2>"]
CMD <커맨드>
# nest 실행
CMD ["yarn", "start:dev"]
개발 서버에 배포하기 위해 yarn start:dev
를 실행시켜주었다.
찾아보니까 몇가지 더 있긴 한데 아직 사용을 안해봐서 따로 적진 않았다.
딱 지금 사용하고 있는 것만 적었는데 좀 더 docker 사용에 익숙해지면 다른 명령어도 사용하지 않을까 싶다. 아직은 완전 간단하게 nestjs 프로젝트를 실행시킬 수 있을 정도로만 작성했기 때문에 나중에 빌드/배포 시간이 많이 걸린다던가 CMD 명령어 실행에 있어서 유연함이 필요하다던가 하면 ENTRYPOINT를 사용한다던지, RUN 명령어 사용을 줄인다던지.. 하지 않을까 ..
.gitignore와 같은 역할을 하는 파일인데, docker image를 만들 때 .dockerignore에 명시되어있는 폴더 및 파일은 이미지에 포함되지 않도록 해준다.
보통 node_modules나 dist 폴더를 넣는 것 같다.
위의 명령어들을 사용해서 만든 Dockerfile이다.
FROM node:20.10.0-alpine3.18
WORKDIR /usr/src/app
COPY package.json ./
COPY yarn.lock ./
RUN yarn install
COPY . .
EXPOSE 5001
CMD ["yarn", "start:dev"]
위에 작성한 내용을 풀어서 설명을 해보면 다음과 같다.
node:20.10.0-alpine3.18
을 베이스 이미지로 사용해서 노드 환경에서 실행/usr/src/app
으로 지정/usr/src/app
으로 복사yarn start:dev
를 실행하도록 함이렇게 하니까 일단 실행은 잘 되고 있어서 최종본으로 사용하고 있긴 한데 아마 조만간 바꿀 것 같긴 하다.
이미지 사이즈 확인해보니까 엄청 커가지고..
Dockerfile로 이미지를 만드려면 Dockerfile이 위치해있는 곳에서 다음을 실행시키면 된다.
docker build -t <이미지 태그> <현재 경로>
여기서 -t는 이미지에 태그를 설정할 수 있게 해주는 옵션인데, 태그 설정을 하면 우리가 지정한 태그명으로 이미지를 사용할 수 있어서 편하다.
위 커맨드를 실행하면 터미널에서 우리가 dockerfile에 적어둔 내용이 실행되는걸 볼 수 있다. 완료되고 docker images
를 실행시켜보면 만들어진 이미지를 확인해볼 수 있다.
컨테이너 실행도 명령어 한줄이면 실행 가능하다.
docker run -d -p <로컬 port>:<컨테이너 내 사용 port> <이미지 태그>
-d 는 detached 모드로 컨테이너를 백그라운드에서 실행시킬 수 있도록 해주고, -p는 EXPOSE에서 얘기했던 것처럼 로컬 port와 컨테이너 내부 port를 매핑시키는 옵션이다.
위 명령어를 사용하면 localhost의 지정 포트로 들어오면 컨테이너의 지정 포트로 요청이 들어가서 응답을 받을 수 있다.
우리가 만든 프로젝트를 docker image로 만들어서 컨테이너로 실행시켰을 때 잘 되는 것을 확인했으니 그 다음에는 이 과정이 특정 브랜치에 코드가 merge/push 될 때 실행될 수 있도록 해야한다.
다음에는 github actions를 어떻게 사용했는지 정리해보자!