IT STUDY LOG
[Docker] 04. 애플리케이션 컨테이너화 본문
# 학습 목표
- 컨테이너 기술이 무엇인지, Docker가 왜 필요한지 알 수 있다.
- 컨테이너와 이미지, 레지스트리가 무엇인지 이해할 수 있다.
- 대표적인 레지스트리인 Docker Hub에서 이미지를 검색하고, 사용할 수 있다.
- 한 개의 이미지를 이용해서 컨테이너를 구축할 수 있다.
- 두 개 이상의 이미지를 이용해서 컨테이너를 구축하고 서로가 어떻게 연결되는 지 알 수 있다.
- Docker CLI에서 명령어를 사용해서 이미지를 생성/수정/배포하고, 컨테이너를 생성/삭제할 수 있다.
- Dockerfile을 이용해 이미지를 생성할 수 있다.
- 애플리케이션을 컨테이너화할 수 있다.
# 학습 내용
1. Node.js 웹 앱의 컨테이너화 (Node.js 웹 앱의 도커라이징)
Node.js 앱 생성
Step 1 : package.json 파일 생성
# package.json
{
"name": "docker_web_app",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "roheerumi <roheerumi@example.com>",
"main": "server.js",
"scripts": {
"start": "[start] roheerumi node server.js"
},
"dependencies": {
"express": "^4.16.1"
}
}
Step 2 : npm install
Step 3 : Express.js 프레임워크로 웹앱을 정의하는 server.js 생성
$ vim server.js
$ cat 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('헬로우 월드');
});
app.listen(PORT, HOST, () => {
console.log(`(!) Running on http://${HOST}:${PORT}`);
});
Dockerfile 생성
Step 1 : Dockerfile 이름으로 빈 파일을 생성
$ touch Dockerfile
Step 2 : Dockerfile 설정 - layered architecture로 작성 내용이 순차적으로 실행
# Dockerfile 내용
# 사용할 이미지 지정
FROM node:16
# 이미지 안에 애플리케이션 코드를 넣기 위한 디렉토리 설정
WORKDIR /usr/src/app
# 이 이미지에는 이미 Node.js와 NPM이 설치되어 있으므로 npm 바이너리로 앱의 의존성을 설치하기만 하면 됨
# 앱 의존성 설치
# 가능한 경우(npm@5+) package.json과 package-lock.json을 모두 복사하기 위해 와일드카드를 사용
COPY package*.json ./
# 현재는 개발 목적으로 빌드
RUN npm install
# 프로덕션을 위한 코드를 빌드하는 경우 : RUN npm ci --omit=dev
# 도커 이미지 안에 앱의 소스 코드를 추가
COPY . .
# 앱이 바인딩 되어 있는 포트와 docker 데몬 매핑
EXPOSE 8080
# 런타임을 정의하는 CMD로 앱 실행 명령어를 정의(서버를 구동하도록 node server.js을 실행하는 기본 npm start을 사용)
CMD [ "node", "server.js" ]
(1) 어떤 이미지를 사용해 빌드할 것인지 정의
# 사용할 이미지 지정
FROM node:16
(2) 이미지 안에 애플리케이션 코드를 넣기 위한 디렉터리를 생성(애플리케이션의 작업 디렉터리)
# 이미지 안에 애플리케이션 코드를 넣기 위한 디렉토리 설정
WORKDIR /usr/src/app
(3) COPY 명령어를 사용해 파일을 복사하고 앱 의존성 설치 명령어 작성
# 이 이미지에는 이미 Node.js와 NPM이 설치되어 있으므로 npm 바이너리로 앱의 의존성을 설치하기만 하면 됨
# 앱 의존성 설치
# 가능한 경우(npm@5+) package.json과 package-lock.json을 모두 복사하기 위해 와일드카드를 사용
COPY package*.json ./
# 현재는 개발 목적으로 빌드
RUN npm install
# 프로덕션을 위한 코드를 빌드하는 경우 : RUN npm ci --omit=dev
- 작업 디렉터리 전체가 아닌 package.json 파일만을 복사하는 이유는 캐시된 Docker 레이어의 장점을 활용하기 위함(참고 레퍼런스 : 여기)
- npm ci 커맨드는 프로덕션 환경을 위한 더 빠르고, 신뢰할 수 있고, 재현 가능한 빌드(참고 레퍼런스 : 여기)
(4) 빌드 이후 Docker 이미지 안에 앱 소스코드 넣기
# 도커 이미지 안에 앱의 소스 코드를 추가
COPY . .
(5) 포트 바인딩을 통해 docker 데몬에 매핑
# 앱이 바인딩 되어 있는 포트와 docker 데몬 매핑
EXPOSE 8080
(6) 런타임을 정의하는 CMD로 앱을 실행하는 중요 명령어를 정의
# 런타임을 정의하는 CMD로 앱 실행 명령어를 정의(서버를 구동하도록 node server.js을 실행하는 기본 npm start을 사용)
CMD [ "node", "server.js" ]
Dockerfile과 같은 디렉터리에 .dockerignore 파일 작성
Step 1 : 로컬 모듈, 디버깅 로그 복사를 방지해 이미지 내에서 설치한 모듈을 덮어쓰지 않도록 설정
# .dockerignore 파일
node_modules
npm-debug.log
이미지 빌드
Step 1 : 작성한 Dockerfile이 있는 디렉터리에서 Docker 이미지 빌드
- -t 플래그로 이미지에 태그를 추가하면 나중에 docker images 명령어로 찾는 것이 용이
$ docker build . -t <your username>/node-web-app
[+] Building 381.1s (10/10) FINISHED
=> [internal] load .dockerignore 0.5s
=> => transferring context: 68B 0.1s
=> [internal] load build definition from Dockerfile 1.1s
=> => transferring dockerfile: 948B 0.0s
=> [internal] load metadata for docker.io/library/node:16 3.3s
=> [1/5] FROM docker.io/library/node:16@sha256:f6cab97e26064145d6b9bc3a025dbdae84a49d54d4f0ce7f9755a849acab5492 325.9s
=> => resolve docker.io/library/node:16@sha256:f6cab97e26064145d6b9bc3a025dbdae84a49d54d4f0ce7f9755a849acab5492 0.4s
=> => sha256:f6cab97e26064145d6b9bc3a025dbdae84a49d54d4f0ce7f9755a849acab5492 776B / 776B 0.0s
=> => sha256:2a6a4c07cfbed3ee02ce3ca986af5b896058d0632d0101f64fecb33ccdd11561 2.21kB / 2.21kB 0.0s
=> => sha256:26ed31aaee8c72a23f99458066bef1b173830b587d33b73e080c444c3a56fa0c 7.56kB / 7.56kB 0.0s
=> => sha256:4e2befb7f5d18aa27b3619ddf1b93607e62ca82d0c627557537c149893346d86 50.45MB / 50.45MB 7.3s
=> => sha256:792af667f62688dbef1f3ffeeca2daa6d448a62b6cacd604f1c4fc043d6cc2a6 7.86MB / 7.86MB 4.4s
=> => sha256:3e37868ebf669334a2dbdb206ac7b84d8f8d184a40dfb8c9bc501b29cda12548 10.00MB / 10.00MB 3.8s
=> => sha256:591fe17e35ddac86d63495a7708b07af369e0d67d8742880f1e73cf1a205e028 51.87MB / 51.87MB 15.8s
=> => sha256:5d54aff43b9d5a82025cbae68c26151d48ce3e061018e8547a567ee0de7ca4a3 4.20kB / 4.20kB 8.0s
=> => extracting sha256:4e2befb7f5d18aa27b3619ddf1b93607e62ca82d0c627557537c149893346d86 31.3s
=> => sha256:b9cba6e3073a1f2eac2d50c107bba6dbb76de0325854a3a0e7c6f52ae8fc5521 191.85MB / 191.85MB 91.1s
=> => sha256:25065f4ea402b1639bda3d01ad17a90193d0fd96ef621adbab815abca06c2d87 34.79MB / 34.79MB 33.4s
=> => sha256:af7e68a31189113e65df0a44497cc86862bbc6f277b2333c71417c097280b1b1 2.27MB / 2.27MB 37.0s
=> => extracting sha256:792af667f62688dbef1f3ffeeca2daa6d448a62b6cacd604f1c4fc043d6cc2a6 10.1s
=> => sha256:521ff15762da6c44f2f4d25b7960f777503e80685d55b3fe2222df503849e79a 450B / 450B 93.5s
=> => extracting sha256:3e37868ebf669334a2dbdb206ac7b84d8f8d184a40dfb8c9bc501b29cda12548 1.7s
=> => extracting sha256:591fe17e35ddac86d63495a7708b07af369e0d67d8742880f1e73cf1a205e028 16.0s
=> => extracting sha256:b9cba6e3073a1f2eac2d50c107bba6dbb76de0325854a3a0e7c6f52ae8fc5521 140.1s
=> => extracting sha256:5d54aff43b9d5a82025cbae68c26151d48ce3e061018e8547a567ee0de7ca4a3 0.0s
=> => extracting sha256:25065f4ea402b1639bda3d01ad17a90193d0fd96ef621adbab815abca06c2d87 14.4s
=> => extracting sha256:af7e68a31189113e65df0a44497cc86862bbc6f277b2333c71417c097280b1b1 0.7s
=> => extracting sha256:521ff15762da6c44f2f4d25b7960f777503e80685d55b3fe2222df503849e79a 0.0s
=> [internal] load build context 0.7s
=> => transferring context: 23.58kB 0.0s
=> [2/5] WORKDIR /usr/src/app 10.8s
=> [3/5] COPY package*.json ./ 0.9s
=> [4/5] RUN npm install 20.7s
=> [5/5] COPY . . 7.4s
=> exporting to image 10.4s
=> => exporting layers 8.4s
=> => writing image sha256:75e71246f7a047a09fa2365bce7e9d831fa4bafb2c5265abe29d5aec71d5cabf 0.9s
=> => naming to docker.io/<your username>/node-web-app
Step 2 : 빌드한 이미지 조회
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
roheerumi/node-web-app latest 75e71246f7a0 3 minutes ago 914MB
이미지 실행
Step 1 : 이미지 실행
- -d 옵션: 백그라운드 실행
- -p : 공개 포트를 컨테이너 내의 비공개 포트로 리다이렉트
$ docker run -p 49160:8080 -d roheerumi/node-web-app
7d8ae72b31c68d2548d3aae1af7dfccbcf8c3123ef81e517346aeaca15103f9b
Step 2 : 앱 로그 출력
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d8ae72b31c6 roheerumi/node-web-app "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:49160->8080/tcp, :::49160->8080/tcp vigilant_bhabha
$ docker logs 7d8a
(!) Running on http://0.0.0.0:9878
Step 3 : exec 명령어를 통해 컨테이너 안에 들어가 보기
$ docker exec -it vigilant_bhabha /bin/bash
root@7d8ae72b31c6:/usr/src/app# ls
Dockerfile node_modules package-lock.json package.json server.js
테스트
Step 1 : 테스트를 위해 Docker에 매핑된 앱 포트를 확인
- 아래 예시는 Docker가 컨테이너 내의 8080 포트를 머신의 49160 포트로 매핑했다는 뜻
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d8ae72b31c6 roheerumi/node-web-app "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:49160->8080/tcp, :::49160->8080/tcp vigilant_bhabha
Step 2 : 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: 16
ETag: W/"10-CGzrD/CGWCEkEFrrZF1re2kLDRU"
Date: Wed, 12 Apr 2023 08:17:39 GMT
Connection: keep-alive
Keep-Alive: timeout=5
헬로우 월드
Docker Container 중지 후 중지된 컨테이너 삭제
$ docker container stop distracted_benz
distracted_benz
$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
d2e80d76c127dbeae76ee0c39b554771678d98c055962baeefe86670491294ad
7d8ae72b31c68d2548d3aae1af7dfccbcf8c3123ef81e517346aeaca15103f9b
Total reclaimed space: 8B
$ docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# References
- Stack Overflow에 Docker 태그로 올라온 질문
'devops bootcamp 4 > 클라우드 서비스 운영' 카테고리의 다른 글
[AWS] 02. AWS 서비스 소개 (0) | 2023.04.14 |
---|---|
[AWS] 01. 클라우드 컴퓨팅 (0) | 2023.04.14 |
[Docker] 03. Docker Image 다루기 (0) | 2023.04.12 |
[Docker] 02. Docker CLI (0) | 2023.04.12 |
[Docker] 01. 왜 Docker인가? (0) | 2023.04.11 |