[Docker 부터 Kubernetes 까지] [#3] 커스텀 Docker 이미지 만들어보기

이번 회에선 Docker 커스텀 이미지를 제작하는 방법에 대해 알아보도록 하겠습니다.

Docker 부터 Kubernetes까지 GitHub 레포지토리

https://github.com/serendipity1004/medium-docker-to-kubernetes 에 접속하셔서 횟수 이름으로 브란치를 변경하시면 해당 횟수의 코드를 chekcout 하실 수 있습니다. 예) 3회 -> #3 브란치

더 진행하기전 필수지식

  1. Javascript 언어와 nodeJS 프레임워크 그리고
  2. express 서버에 대한 기본적인 지식
  3. REST API에 대한 기본적인 지식 nodeJS가 설치된 컴퓨터 (https://nodejs.org/en/에서 환경에 맞는 v10 이상의 버전을 설치하시면 됩니다)

이번 회에선 위 두 가지를 어느 정도 알고 계신다는 가정하에 진행하게 되겠습니다.

프로젝트 구조 갖추기

앞으로 프로젝트를 진행하실 폴더를 생성하시고 좋아하시는 IDE에서 실행을 해주세요. 저 같은 경우 대부분 IntelliJ IDEA를 사용합니다. 추가적으로 IDE에서 Dockerfile 문법 체크를 지원하면 플러그인도 같이 설치해주시면 프로젝트 진행하시는데 유리하십니다.

npm init -y
npm i --save express

설치가 완료되시면 아래 코드를 server.js에 붙여넣기 해주시면 됩니다.

const express = require('express');
const app = express();
const port = process.env.PORT;

app.get('/', (req, res) => {
    res.json({
        success: true
    });
});

app.listen(port, () => {
    console.log(`server is listening at localhost:${process.env.PORT}`);
});

굉장히 간단한 서버 코드입니다. 익스프레스 서버를 저희가 환경 변수에 지정한 포트에 실행하여 루트 URL에 GET 요청이 있을 시 {success:true}라는 JSON을 리턴해주는 코드입니다. 아래 커맨드를 이용해 서버를 실행해보도록 하겠습니다.

PORT=3000 node server.js

제대로 실행되셨다면 http://localhost:3000에 접속하셔서 {success:true}라는 JSON 응답을 받으실 수 있을 겁니다. Ctrl + C를 실행해서 서버를 꺼주세요.

도커이미지 세팅하기

루트 폴더에 Dockerfile이라는 파일을 생성하고 아래 코드를 붙여 넣어주세요.

FROM node:10-alpine

WORKDIR /app/usr

# Copy dependencies first for effective caching
COPY package*.json ./

RUN npm install

COPY . .

CMD ["npm", "run", "start"]
  1. FROM node:10-alpine{.dockerfile}

Docker 베이스 이미지를 node라는 이미지에 10-alpine 태그가 붙은 이미지로 사용하라는 뜻입니다. Docker 태그에 대해서는 나중에 더 배워보도록 하겠습니다. 해당 이미지에 대한 설명은 https://hub.docker.com/_/node/ 이곳에서 볼 수 있습니다.

  1. WORKDIR /app/usr

Docker 컨테이너 내부에서 작업 디렉터리를 /app/usr로 지정합니다. 이후 커맨드는 /app/usr 폴더를 기본 폴더로 사용하게 됩니다.

  1. COPY package*.json ./

로컬 디렉터리의 package.json 및 와일드카드에 해당되는 모든 패키징 파일을 (package-lock.json 포함) Docker 컨테이너의 현 위치 (./)로 복사합니다. 위에서 WORKDIR /app/usr를 적용시켰기 때문에 현재 위치는 /app/usr가 됩니다.

  1. RUN npm install

npm install을 실행하여 nodeJS 패키지들을 설치합니다.

  1. COPY . .

로컬의 현재 위치 파일들을 컨테이너 내부의 현 위치로 복사합니다.

  1. CMD [“node”, “server.js”]

마지막으로 node server.js라는 명령어를 실행해 컨테이너 내부에서 server.js를 실행합니다.

3번과 5번 스텝을 왜 통합하지 않는지 의아해하시는 분도 분명 계실 겁니다. 그 이유는 Docker는 라인별로 캐싱을 하기 때문에 디펜던시가 변경돼서 package.json만 변경이 되었을 경우 3번째와 4번째 라인만 실행이 되고 5번째 라인은 저장된 캐시에서 그대로 불러오게 됩니다. 훨씬 더 효율적이여지게 되죠.

완료되셨으면 루트 폴더에. dockerignore 파일을 생성하여 아래 코드를 붙여 넣습니다.

node_modules

.dockerignore 파일은. gitignore 파일과 비슷한 역할을 합니다. Docker 컨테이너를 생성할 때. dockerignore 파일에 있는 모든 사항들은 무시하게 되죠. nodeJS 모듈들은 환경에 따라 디펜던시 버전이 달라질 수 있기 대문에 컨테이너 내부적으로 설치를 하고 로컬 환경에서 따로 옮겨오진 않겠습니다.

이제 환경 변수 설정을 위해 루트 폴더에 .env 파일을 생성하겠습니다. 생성 후 아래 코드를 붙여 넣어주세요.

PORT=3000

좀 전에 server.js를 실행할 때 포트를 커맨드 라인에서 PORT 환경 변수 지정을 해주었는데 Docker 컨테이너 실행 시에는 파일로 여러 환경 변수를 동시에 설정해주도록 하겠습니다.

이제 Docker 파일을 생성할 준비가 됐습니다. 아래 커맨드를 실행하여 이미지를 빌드 해주세요.

docker build -t "nodejs-docker" .

-t 플래그는 태그를 지정하는 플래그입니다. 컨테이너 실행 시 태그를 기반으로 이미지를 지정하게 됩니다. 맨 끝에 ‘.’을 꼭 포함해주시기 바랍니다. 현 위치에서 Docker 컨테이너를 빌드 하라는 뜻입니다.

아래와 같은 응답이 오셨다면 성공입니다.

도커 빌드

응답을 잘 보시면 저희가 작성한 코드를 한 줄 줄 읽어내려가면서 컨테이너가 생성되는 걸 보실 수 있습니다.

그럼 저희가 빌드 한 컨테이너를 실행해보겠습니다.

docker run --env-file .env -p 4000:3000 nodejs-docker

빌드 한 nodejs-docker 이미지를 실행하는 커맨드입니다. — env-file 플래그를 사용해 저희가 생성한 환경 변수 파일을 지정해주었고 -p 플래그로 컨테이너 내부의 3000번 포트를 4000번 포트로 매핑해주었습니다. 이전에 로컬에서 실행한 3000번 포트의 express 서버가 아니라는 걸 확실히 보여드리기 위해 포트를 변경해보았습니다.

http://localhost:4000을 접속해보시면 {success:true}응답이 오는 것을 확인하실 수 있을 겁니다.

이로써 Docker 이미지를 생성하는 기본기에 대해 배워보았습니다. 다음 시간에는 이미지들을 docker hub에 업로드하여 공유하고 퍼블릭 레포지토리에서 이미지를 풀해오는 방법에 대해 알아보도록 하겠습니다.

©Code Factory All Rights Reserved