Judaeng

Docker(3) - 이미지 만들고 배포해보기 +Docker Hub 본문

DevOps/Docker

Docker(3) - 이미지 만들고 배포해보기 +Docker Hub

Judaeng 2022. 4. 4. 06:20

Docker를 설치하고 컨테이너를 실행해 보았으니 이번엔 이미지를 만들고 서버에 배포해보도록 하자.

 

Docker 이미지 만들기

Docker는 이미지를 만들기 위해 컨테이너의 상태를 그대로 이미지로 저장하는 단순한 방법을 사용한다.

예를 들어, 어떤 애플리케이션을 이미지로 만든다면 리눅스만 설치된 컨테이너에 애플리케이션을 설치하고 그 상태를 그대로 이미지로 저장한다.

가상 머신의 스냅샷과 비슷한 방식이다.

 

이런 과정은 콘솔에서 명령어를 직접 입력하는 것과 별 차이가 없으므로 쉘 스크립트를 잘 알아야 하지만 좋은 샘플이 많이 공개되어 있어 잘 몰라도 크게 걱정하지 않아도 된다고 한다.

컨테이너의 가벼운 특성과 레이어 개념을 이용하여 생성과 테스트를 빠르게 수행할 수도 있다고 한다.

 

이제부터는 이론이 아닌, 내가 이미지를 만들고, 그 이미지를 실행하고, 실행한 이미지를 Docker hub에 저장하고, 다시 이미지를 불러오는 과정을 정리해보려고 한다.

 

🧑‍💻과정 정리


1. 잘 작성된 프로젝트(?), 가볍게 Hello World를 띄우는 서버를 준비한다.

2. 위에 프로젝트의 이미지를 만들고, 그 이미지를 바로 배포할 수 있지만, Docker Hub에 올리는 과정을 정리한다.

3. Docker Hub에 올라간 이미지를 다시 가져와서 컨테이너로 실행한 후에, 잘 배포되었는지 확인하는 것까지 정리한다.

 

내가 정리한 "과정 정리"

시작하기 전에 Docker가 설치되어 있고, Node.js 애플리케이션의 구조에 대한 기본적인 지식이 있어야 한다.

먼저 간단한 Node.js 웹 애플리케이션을 만든 후에 이 애플리케이션을 위한 Docker 이미지를 만들어서 컨테이너로 실행할 것이다.

Node.js 앱 생성


모든 파일을 넣은 새로운 디렉터리를 만들어야 한다.

npm init을 해서 파일을 만들고, Express.js 프레임워크로 웹앱을 정의하는 server.js까지 만들어야 한다.

'use strict';

const express = require('express');

// 상수
const PORT = 8080;
const HOST = '0.0.0.0';

// 앱
const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

공식 Docker 이미지를 사용해서 Docker 컨테이너 안에서 이 앱을 실행하는 방법을 살펴보자.

먼저 앱의 Docker 이미지를 만들어야 한다.

 

Dockerfile 생성


Dockerfile이라는 빈 파일을 생성한다.

touch Dockerfile

선호하는 텍스트 에디터로 Dockerfile을 연다.

 

가장 먼저 해야 할 것은 어떤 이미지를 사용해서 빌드할 것인지를 정의하는 것이다.

여기서는 Docker Hub에 있는 node의 최신 LTS(장기 지원) 버전인 12를 사용할 것이다.

FROM node:12

다음으로 이미지 안에 애플리케이션 코드를 넣기 위해 디렉터리를 생성할 것이다.

이 디렉터리가 애플리케이션의 작업 디렉터리가 된다.

나는 이것을 앱이 실행할 수 있는 디렉터리라고 생각하고 있다. 절대 경로, 상대 경로 둘 다 맞다.

# 앱 디렉터리 생성
WORKDIR /usr/src/app

이 이미지에는 이미 Node.js와 NPM이 설치되어 있으므로 npm 바이너리로 앱의 의존성을 설치하기만 하면 된다.

버전 4 이하의 npm은 package-lock.json 파일을 생성하지 않을 것이다.

# 앱 의존성 설치
# 가능한 경우(npm@5+) package.json과 package-lock.json을 모두 복사하기 위해
# 와일드카드를 사용
COPY package*.json ./

RUN npm install
# 프로덕션을 위한 코드를 빌드하는 경우
# RUN npm ci --only=production

작업 디렉터리 전체가 아닌 package-json 파일만을 복사하고 있는데, 이는 캐시 된 Docker 레이어의 장점을 활용하기 위함이다.

주석에 언급된 npm ci 커맨드는 프로덕션 환경을 위한 더 빠르고, 신뢰할 수 있고, 재현 가능한 빌드를 제공한다.

npm ci에 대한 자세한 이야기는 여기에서 알아볼 수 있다.

 

Docker 이미지 안에 앱의 소스코드를 넣기 위해 COPY 지시어를 사용한다.

# 앱 소스 추가
COPY . .

앱이 8080포트에 바인딩되어 있으므로 EXPOSE 지시어를 사용해서 docker 데몬에 매핑한다.

EXPOSE 8080

마지막으로 런타임을 정의하는 CMD로 앱을 실행하는 중요 명령어를 정의해야 한다.

여기서는 서버를 구동하도록 node server.js을 실행하는 기본 npm start을 사용할 것이다.

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

Dockerfile은 다음과 같아야 한다.

FROM node:12

# 앱 디렉터리 생성
WORKDIR /usr/src/app

# 앱 의존성 설치
# 가능한 경우(npm@5+) package.json과 package-lock.json을 모두 복사하기 위해
# 와일드카드를 사용
COPY package*.json ./

RUN npm install
# 프로덕션을 위한 코드를 빌드하는 경우
# RUN npm ci --only=production

# 앱 소스 추가
COPY . .

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

.dockerignore 파일


Dockerfile과 같은 디렉터리에 .dockerignore 파일을 다음 내용으로 만들어보자.

node_modules
npm-debug.log

이는 Docker 이미지에 로컬 모듈과 디버깅 로그를 복사하는 것을 막아서 이미지 내에서 설치한 모듈을 덮어쓰지 않게 한다.

이미지 빌드


작성한 Dockerfile이 있는 디렉터리로 가서 Docker 이미지를 빌드하는 다음 명령어를 실행해보자.

-t 플래그로 이미지에 태그를 추가할 수 있어 나중에 docker images 명령어로 쉽게 찾을 수 있다.

docker build . -t <your username>/node-web-app

image build

Docker가 빌드한 이미지 리스트를 보여준다.

이미지 빌드한 이미지 List

이미지 실행


-d로 이미지를 실행하면 분리 모드로 컨테이너를 실행해서 백그라운드에서 컨테이너가 돌아가도록 한다.

-p 플래그는 공개 포트를 컨테이너 내의 비공개 포트로 리다이렉트한다.

앞에서 만든 이미지를 실행해보자.

docker run -p 49160:8080 -d <your username>/node-web-app

앱의 로그를 출력해보자.

# 컨테이너 아이디를 확인합니다
$ docker ps

# 앱 로그를 출력합니다
$ docker logs <container id>

# 예시
Running on http://localhost:8080

컨테이너 안에 들어가 봐야 한다면 exec 명령어를 사용할 수 있다.

# 컨테이너에 들어갑니다
$ docker exec -it <container id> /bin/bash

아래 사진은 내가 이미지를 빌드하고, 실행하고, 컨테이너 아이디 확인 후에 로그도 출력해보고, exec 명령어를 사용해서 컨테이너 안까지 들어가기를 확인한 사진이다.

테스트


앱을 테스트하려면 Docker 매핑된 앱 포트를 확인한다.

$ docker ps

# 예시
ID            IMAGE                                COMMAND    ...   PORTS
ecce33b30ebf  <your username>/node-web-app:latest

위 예시에서 Docker가 컨테이너 내의 8080 포트를 머신의 49160 포트로 매핑했다.

 

이제 curl로 앱을 호출할 수도 있다. (필요하다면 sudo apt-get install curl로 설치해주자.)

$ curl -i localhost:49160

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 12
ETag: W/"c-M6tWOb/Y57lesdjQuHeB1P/qTV0"
Date: Mon, 13 Nov 2017 20:53:59 GMT
Connection: keep-alive

Hello world

curl로 실습한 것을 캡쳐

간단한 Node.js 애플리케이션을 Docker로 실행하는 것을 성공적으로 마쳤다.

잘 뜬다. Hello World !!!

Docker Hub 사용하기


지금까지 해왔던 과정을 정리하고, 이미지를 업로드를 한다.

Docker Hub에 업로드를 했을 땐, 내가 만든 Hello World 이미지를 삭제하고 Docker Hub에 업로드한 이미지를 가져와서 pull) 다시 컨테이너로 띄워보는 것이다.

 

Docker Hub 가입하는 과정은 따로 정리하지 않겠지만, 간단하게 정리하자면 ID, PASSWORD 생성하고, 무료 플랜을 선택했다. 그다음은 로그인!

 

Docker Hub Repository 생성하기

Image를 업로드하기 위한 Docker Hub repository를 먼저 생성해야 한다.

Repository 생성하기

그다음엔 Create Repository 버튼을 누르고 저장소 생성화면으로 들어간다.

저장소의 이름을 지정하고, 공개 저장소로 할지 사설 저장소로 할지 선택한 후 Create 버튼을 클릭하여 저장소를 생성한다.

공개 저장소(Pubilc)는 누구나 접근이 가능한 저장소이고, 사설 저장소(Private)는 자신만이 접근 가능한 저장소이다.

 

무료 플랜에서는 공개 저장소(Pubilc)는 무제한으로 생성할 수 있지만, 사설 저장소(Private)1개까지만 생성할 수 있다고 한다.

아래와 같이 저장소가 생성된 것을 확인할 수 있다.

Docker 이미지 업로드하기

명령 프롬프트 상에서 docker login 명령어로 로그인할 수가 있다.

ID와 패스워드는 Docker Hub에 가입한 계정 정보를 입력하면 된다.

계정 정보 입력

업로드할 Docker 이미지를 생성한다.

Docker Hub의 저장소 이름인 "alinos/helloworld"와 동일하게 맞춰 줘야 한다.

새로운 이미지 이름은 "alinos/helloworld:1.0"으로 생성한다. 

commit은 실행 중인 컨테이너도 가능하고, 종료된 컨테이너 ID를 이용해도 새로운 생성이 가능하다고 한다.

# 종료된 docker 컨테이너의 ID 확인하기 옵션 -a
docker ps -a

# docker 컨테이너 조회하기
docker ps

# commit 명령어를 사용하여 종료된 docker 컨테이너 상태 그대로의 이미지를 생성한다.
docker commit [컨테이너 ID] [이미지 이름]

docker images
# 새로운 이미지가 생성된 것을 확인

이미지 생성

생성된 Docker 이미지를 Docker Hub 저장소에 업로드한다.

이미지 Docker Hub에 업로드

아래 사진과 같이 Docker Hub 저장소에서 업로드된 내용을 확인할 수 있다.

Docker 이미지 다운로드하기

Docker Hub 저장소에 저장된 Docker 이미지를 다운로드하는 방법이다.

아래 사진처럼 docker hub 저장소에 태그 내용을 pull 해오면 된다.

docker pull [레포지토리명:Tag]

실행은 컨테이너 실행 명령어로 실행해주면 된다.

 

 

🤔 블로그 정리 후, 느낀 점

나는 이미지를 만들고 로컬에 배포하는 과정은 subicura님의 블로그를 따라 진행해보진 않았다.

내겐 너무 진입장벽이 크다고 느낀 것 같다ㅋㅋ😂
"따라 하기만 하면 되는데 뭐가 어려워!!!"라고 생각할 수도 있지만 어쨌든 난 그랬다.

그래서 난 처음에 이미지를 만들고, Docker Hub에 올리고, 이미지를 가져오고, 배포하는 과정을 Node.js 웹 앱의 도커 라이징이라는 Node.js org 문서를 통해 공부하게 되었다.

생각보다 너무 정리가 잘되어 있었고 따라만 해도 Docker를 이해하기엔 충분했다.

Docker라는 기술 스택을 이론으로 공부할 때는 복잡하고 어려웠던 것 같다.

하지만 실습을 하기 시작하니, 생각보다 쉽다는 느낌이 들었다.

Docker가 어떤 식으로 동작하는지, 어떤 역할을 해주는지 공부하고, docker 명령어도 계속 공부하는 것이 좋겠다. 🤮

 

📝이번 게시물을 만들기 위해 참고한 사이트

1. 초보를 위한 도커 안내서 - 이미지 만들고 배포하기 

2. Node.js 웹 앱의 도커 라이징

3. pyrasis 블로그 - 잘 정리되어 있음

4. Docker Documentation

5. Node.js.org(ko) 문서

6. Docker Hub 가입 및 저장소 생성하기

7. Docker Hub 사이트에서 저장(push) 및 가져오기(pull)

8. katacoda - Docker 등을 쉽게 실습 해볼 수 있는 공간

'DevOps > Docker' 카테고리의 다른 글

Docker(2) - 설치하고 컨테이너 실행해보기  (0) 2022.04.01
Docker(1) - 알아보기  (0) 2022.04.01
Comments