Featured image of post 1. Containerize an application

1. Containerize an application

도커 시작하기

Get the app

1
git clone https://github.com/docker/getting-started.git

Build the app’s container image

컨테이너 이미지를 빌드하려면 Dockerfile을 사용해야한다.

Dockerfile?

Dockerfile은 파일 확장자가 없는 간단한 텍스트 기반 파일로서 도커 이미지를 만들기 위한 빌드 스크립트로 활용된다. 도커 이미지는 컨테이너를 생성하는 데 사용되며, Dockerfile은 이러한 이미지를 구성하는 데 필요한 모든 정보를 제공한다.

Dockerfile은 도커 이미지를 생성하는 데 필요한 기본 운영 체제 이미지, 필요한 응용 프로그램, 설정 파일 및 다른 종속성 등 모든 구성 요소를 명시하며, 일반적으로 다음과 같은 명령어로 구성된다.

  • FROM: 기본이 되는 이미지
  • RUN: 새로운 레이어에서 실행될 명령어
  • COPY: 호스트 파일 시스템에서 파일이나 디렉토리를 이미지로 복사
  • ADD: COPY 명령과 유사하지만, URL에서 파일을 다운로드하거나 tar 파일에서 파일을 추출하는 등의 작업을 수행할 수 있음
  • WORKDIR: 명령어가 실행될 작업 디렉토리를 설정
  • ENV: 환경 변수를 설정
  • EXPOSE: 컨테이너가 사용하는 포트
  • CMD: 컨테이너가 시작될 때 실행할 명령어를 설정

Dockerfile에 정의된 모든 명령어는 도커 이미지의 각 레이어로 구성된다. 각 레이어는 독립적으로 캐싱되고 이미지를 다시 빌드할 때 이전에 캐싱된 레이어를 재사용하여 빌드 속도를 향상시켜 도커 이미지를 효율적이고 일관적인 방식으로 생성할 수 있다.

Dockerfile 생성

빌드할 어플리케이션이 있는 디렉터리(/getting-started/app)로 이동하여 Dockerfile 생성 후 필요한 내용을 채운다.

1
2
cd getting-started/app
touch Dockerfile

1
2
3
4
5
6
7
8
# syntax=docker/dockerfile:1
  
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000

빌드

컨테이너 이미지를 빌드한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
docker build -t getting-started .

[+] Building 26.1s (13/13) FINISHED                                                                         
 => [internal] load build definition from Dockerfile                                                   0.0s
 => => transferring dockerfile: 186B                                                                   0.0s
 => [internal] load .dockerignore                                                                      0.0s
 => => transferring context: 2B                                                                        0.0s
 => resolve image config for docker.io/docker/dockerfile:1                                             2.4s
 => docker-image://docker.io/docker/dockerfile:1@sha256:39b85bbfa7536a5feceb7372a0817649ecb2724562a38  3.4s
 => => resolve docker.io/docker/dockerfile:1@sha256:39b85bbfa7536a5feceb7372a0817649ecb2724562a38360f  0.0s
 => => sha256:9d0cd65540a143ce38aa0be7c5e9efeed30d3580d03667f107cd76354f2bee65 10.82MB / 10.82MB       3.2s
 => => sha256:39b85bbfa7536a5feceb7372a0817649ecb2724562a38360f4d6a7782a409b14 8.40kB / 8.40kB         0.0s
 => => sha256:7f44e51970d0422c2cbff3b20b6b5ef861f6244c396a06e1a96f7aa4fa83a4e6 482B / 482B             0.0s
 => => sha256:a28edb2041b8f23c38382d8be273f0239f51ff1f510f98bccc8d0e7f42249e97 2.90kB / 2.90kB         0.0s
 => => extracting sha256:9d0cd65540a143ce38aa0be7c5e9efeed30d3580d03667f107cd76354f2bee65              0.2s
 => [internal] load .dockerignore                                                                      0.0s
 => [internal] load build definition from Dockerfile                                                   0.0s
 => [internal] load metadata for docker.io/library/node:18-alpine                                      2.3s
 => [internal] load build context                                                                      0.1s
 => => transferring context: 4.59MB                                                                    0.1s
 => [1/4] FROM docker.io/library/node:18-alpine@sha256:ca5d399560a9d239cbfa28eec00417f1505e5e108f3ec6  8.3s
 => => resolve docker.io/library/node:18-alpine@sha256:ca5d399560a9d239cbfa28eec00417f1505e5e108f3ec6  0.0s
 => => sha256:fefc7d195eee885e1f309ca2b5eff078b537b766f6bd949f8eb69fe895088821 2.41MB / 2.41MB         1.8s
 => => sha256:ca5d399560a9d239cbfa28eec00417f1505e5e108f3ec6938d230767eaa81f61 1.43kB / 1.43kB         0.0s
 => => sha256:46f34dda633f5708462f6d6ee7ef829535bd0ee04b82cbe28dcccb5df74b3eb1 1.16kB / 1.16kB         0.0s
 => => sha256:a966e12937d2cdbf1cf501f972673875426566c53820a3fe54c2a15b0ad93639 6.50kB / 6.50kB         0.0s
 => => sha256:c41833b44d910632b415cd89a9cdaa4d62c9725dc56c99a7ddadafd6719960f9 3.26MB / 3.26MB         0.6s
 => => sha256:762c2470eea4dfd0e37925b903f27172a7b89fd8b11bb8cf61554941c3293636 47.28MB / 47.28MB       6.7s
 => => extracting sha256:c41833b44d910632b415cd89a9cdaa4d62c9725dc56c99a7ddadafd6719960f9              0.1s
 => => sha256:06fc22ed341f1d0c400e6972828f8731f3544007cda80ea1d333fe15acf0a28b 448B / 448B             1.2s
 => => extracting sha256:762c2470eea4dfd0e37925b903f27172a7b89fd8b11bb8cf61554941c3293636              1.4s
 => => extracting sha256:fefc7d195eee885e1f309ca2b5eff078b537b766f6bd949f8eb69fe895088821              0.1s
 => => extracting sha256:06fc22ed341f1d0c400e6972828f8731f3544007cda80ea1d333fe15acf0a28b              0.0s
 => [2/4] WORKDIR /app                                                                                 0.1s
 => [3/4] COPY . .                                                                                     0.0s
 => [4/4] RUN yarn install --production                                                                8.6s
 => exporting to image                                                                                 0.7s
 => => exporting layers                                                                                0.7s
 => => writing image sha256:8b52580feb5e556abf813797e2003cbb30d53dfeee0f865fde0f16de6354c6a1           0.0s
 => => naming to docker.io/library/getting-started        

docker build 명령은 Dockerfile을 사용하여 새 컨테이너 이미지를 빌드한다.

명령 실행 후 많은 레이어들을 다운로드 하게 되었는데, 이는 도커 파일 작성시 기본이 되는 이미지를 FROM으로 명시했기 때문이다. 하지만 해당 이미지가 존재하지 않았기 때문에 다운로드 하게 된다.

도커가 이미지를 다운로드한 후에는 Dockerfile에서 지시한대로 애플리케이션을 복사하고 yarn을 사용하여 애플리케이션의 종속성을 설치한다. CMD로 이미지에서 컨테이너를 시작할 때 실행할 기본 명령을 지정할 수 있다.

명령에 사용된 -t 옵션을 명시하면 이미지에 태그를 설정할 수 있으며, 입력된 getting-started로 이름을 지정하여 컨테이너를 실행할 때 해당 이미지를 참조할 수 있게 된다.

명령의 마지막에 있는 .는 도커가 현재 디렉토리에서 Dockerfile을 찾아야 한다는 것을 알린다.

Start an app container

이미지가 있다면 docker run명령을 통해 컨테이너에서 애플리케이션을 실행할 수 있다.

1
2
3
docker run -dp 3000:3000 getting-started

2b5285b3ebfa65b51a44116c620e56b96b787874c71b25c8643b6a9ee137cb49
  • -d: 새 컨테이너를 백그라운드 모드로 실행한다.
  • -p 호스트의 포트와 컨테이너의 포트간 매핑을 생성한다. 포트 매핑이 없다면 애플리케이션에 접근할 수 없다.

명령이 정상적으로 수행되었다면 http://localhost:3000 링크를 통해 애플리케이션에 접근할 수 있다.

컨테이너를 간단히 확인해 보면, getting-started 이미지를 사용하고 있으며 포트 3000으로 실행 중인 컨테이너가 적어도 하나 있어야 하고, 컨테이너를 확인하려면 CLI 또는 Docker Desktop의 그래픽 인터페이스를 사용할 수 있다.

1
2
3
4
docker ps 

CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS         PORTS                    NAMES
2b5285b3ebfa   getting-started   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   0.0.0.0:3000->3000/tcp   youthful_yonath