만자의 개발일지

[Docker] Dockerfile 생성 후 build하기 (feat. Node.js, S3, EC2) 본문

Docker

[Docker] Dockerfile 생성 후 build하기 (feat. Node.js, S3, EC2)

박만자 2021. 12. 20. 17:22

어플리케이션을 컨테이너화할려면 어떻게 해야할까요?

 

일단 컨테이너를 만들려면 이미지가 있어야 되는데. 컨테이너로 이미지를 만들려면 운영체제(CentOS, Ubuntu 등) 이미지로 새로운 컨테이너를 생성한후 해당 컨테이너에 어플리케이션을 실행 환경을 설치하고 컨테이너를 이미지로 커밋하는 방법이 있습니다.

 

하지만 이러한 방법은 이미지를 새로 생성할 때 마다 일일이 패키지를 설치하고 소스코드를 복제하는 등의 수작업을 요구합니다.

 

도커는 이러한 번거로움을 해결하기 위해 위와 같은 일련의 과정을 손쉽게 기록하고 수행할 수 있는 빌드(build) 명령어를 제공합니다. 

 

Dockerfile

 

이미지를 생성하기 위해 컨테이너에 설치해야 하는 패키지, 추가해야 하는 소스코드, 실행해야 하는 명령어와 셸 스크립트 등을 Dockerfile 이라는 하나의 파일에 기록해 두면 도커는 이 파일을 읽어 컨테이너에서 작업을 수행한 뒤 이미지로 만들어냅니다.

 

Dockerfile을 사용하면 위와같은 번거로움을 줄일 수 있을뿐더러 Git과 같은 개발 도구를 통해 어플리케이션의 빌드 및 배포를 자동화할 수 있습니다.

 

그러면 예제를 통해 Dockerfile을 어떻게 만들고 빌드하는지 알아보겠습니다.


이 예제에서는 간단한 Node.js 어플리케이션을 만들어 S3에 올린 후 EC2에서 불러와 Dockerfile을 이용하여 Docker 이미지로 만든 후 실행해보도록 하겠습니다.

 

Node.js on Docker

디렉토리부터 생성해 주도록 하겠습니다. 디렉토리명은 docker_node_app 으로 해주도록 하겠습니다. 

 

그 다음 package.json 파일을 만들어 줍니다. package.json 파일은 npm init 명령어를 통해 생성하실 수 있고 직접 만들어도 상관은 없습니다. 

{
  "name": "docker_node_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "Manja",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "^4.17.2"
  }
}

package.json 파일을 만든후 npm install 혹은 npm i  명령어를 통해 package.json 파일에 포함된 의존성 패키지들을 설치해줍니다.

 

그 다음 app.js 파일을 만들어 줍니다. app.js 파일 안에는 express.js 프레임워크를 활용하여 간단한 웹 어플리케이션을 만들어줄것입니다.

var express = require('express');
var app = express();

app.get('/', (req, res)=>{
    res.send('<h1>Hello Docker!</h1>')
});

app.listen(3000,'0.0.0.0',()=>{
    console.log('Server Start : port 3000');
});

 

그런 다음 app.js 파일과 package.json 파일을 자신의 S3에 업로드 해줍니다.

 

그 다음 자신의 EC2 인스턴스로 들어와 S3에 있는 파일들을 복사해줍니다.

$ aws s3 cp s3://<bucket-name> ./ --recursive --exclude "*/*"

 

자 이제부터가 중요합니다. 그 전에 EC2에 Docker가 설치가 되있어야 합니다. 만약 되있지 않다면 아래 링크를 참고하여 설치해 주시면됩니다.

https://yoo11052.tistory.com/96?category=981650 

 

[Docker] CentOS Docker 설치 방법

설치 방법 $ sudo yum update -y Docker & Docker Registry 설치 $ yum install -y docker docker-registry 서버가 껏다켜져도 Docker가 실행되게 설정(ON BOOT) $ systemctl enable docker.service Docker 실행 $..

yoo11052.tistory.com

 

Docker 공식 이미지를 사용해 앱을 실행시킬건데, 먼저 이미지를 만들어야 하기 떄문에 Dockerfile 이라는 빈 파일을 생성해 주도록합니다.

$ touch Dockerfile

 

그 다음에 자신이 사용하는 텍스트 에디터로 Dockerfile을 여시면 됩니다. 저는 Amazon Linux에서 기본적으로 제공하는 vi 에디터를 사용하도록 하겠습니다.

$ sudo vi Dockerfile

 

그 다음 아래와 같이 Dockerfile을 구성합니다.

# 최신 Node.js LTS 버전
FROM node:16.13.1

# Node.js 앱을 위한 app 폴더 생성
RUN mkdir -p /app

# 어플리케이션 폴더를 WORKDIR명령어로 지정 - 서버 가동용
WORKDIR /app

# 가능한 package.json 과 package-lock.json을 모두 복사하기 위해서 와일드 카드 사용
COPY package*.json /app/

# 의존성 설치
RUN npm install

# 앱 소스코드 추가
COPY app.js /app/

# 앱이 3000번 포트에 바인딩 되어있기 때문에 컨테이너의 3000번 포트를 열어줌
EXPOSE 3000
# 인자값을 지정하지 않을시 node app.js를 실행
CMD [ "node", "app.js" ]

 

이미지 빌드

Dockerfile을 만들었으니 이제 작성한 Dockerfile을 가지고 이미지를 빌드해 봅시다. 작성한 Dockerfile이 있는 디렉토리로 가서 다음과같은 빌드 명령어를 실행해 줍니다. docker build 명령어를 통해 이미지를 빌드할 수 있습니다.

$ sudo docker build . -t <image name>

sudo docker build . -t my-node-app

-t 옵션으로 이미지 이름을 지정해 줄 수 있습니다. 저는 아래와 같이 실행해 주었습니다.

 

docker images 명령어를 통해 이미지가 잘 생성되었는지 확인해 줍니다.

$ sudo docker images

REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
my-node-app  latest    0ea88f35c349   9 minutes ago   910MB
node         16.13.1   affe728e127a   2 weeks ago     905MB

 

컨테이너 실행

이미지를 만들었으니 이제 만든 이미지를 가지고 컨테이너를 생성하여 실행시켜 봅시다.

 

docker run 명령어는 컨테이너를 생성과 동시에 구동시킵니다.

$ sudo docker run --name web-app-server -p 3000:3000 -d my-node-app 

$ sudo docker run --name web-app-server -p 3000:3000 -d my-node-app npm start

--name 옵션으로 컨테이너의 이름을 지정할 수 있습니다. 이름은 web-app-server로 지정해 주겠습니다.

그 다음 -p 옵션을 통해 포트바인딩을 해줍니다. 서버의 3000번 포트로 요청이 들어오면 컨테이너의 3000번포트로 넘겨주겠다는 의미입니다.

-d 옵션으로 컨테이너를 백그라운드에서 실행시켜줍니다. 그 다음 컨테이너에서 실행할 이미지를 지정해줍니다.

 

첫번째 명령어로 입력해도 잘 작동되지만 두번째 명령어로 지정해도 잘 작동됩니다. 그 이유는 아까 package.json 파일에서 npm start를 설정해 주었기 때문입니다. 그리고 Dockerfile에서 CMD로 인자값을 받을 수 있도록 지정해 주었기 때문에 가능한 겁니다. 만약 CMD 가아니라 ENTRYPOINT 였다면 두번째는 실행이 안될것입니다.

CMD 와 ENTRYPOINT 의 차이는 시작시 실행 명령에 대한 Default 지정 여부입니다.

 

그 다음 컨테이너가 잘 구동이 되었는지 확인해 봅시다.

docker ps 명령어를 통해 현재 컨테이너의 상태를 확인할 수 있습니다.

$ sudo docker ps -a

-a 옵션은 컨테이너의 stop 여부와 상관없이 모든 컨테이너의 상태를 출력합니다.


자 이제 웹앱서버의 3000번 포트로 접속을 해봅시다.

잘 되는 것을 보실 수 있습니다.

이처럼 Dockerfile을 활용하면 보다 손쉽게 이미지를 만들고 컨테이너를 실행할 수 있습니다.

 

 

참고

Comments