DevOps/Docker

[Docker] 유틸리티 컨테이너

샤아이인 2022. 10. 1.

 

유틸리티 컨테이너는 사실 공식용어는 아니라고 합니다.

 

원래는 애플리케이션 자체를 컨테이너에 담아 실행시켰다면, 유틸리티 컨테이너는 특정 환경만 포함하는 컨테이너를 의미합니다.

 

1. 유틸리티 컨테이너

예를 들어 local 환경에 node가 설치돼있지 않다면 애플리케이션을 실행할 수 있을까요?

 

또한 node는 pacakage.json을 통해 종속성 관리를 하는데, 보통 npm init 같은 명령어를 통해 초기화하여 사용합니다.

하지만 우리의 환경에 node.js가 설치되있지 않다면 어떻게 사용할까요?

 

이런 경우 유틸리티 컨테이너를 통해서 실행환경만 이용하면 된다!


▶ -it -d

우선 몇가지 명령어에 대하여 살펴봅시다.

docker run -it -d node

위 명령어는 input, tty 모드와 detach 모드를 옵션으로 추가해주었다.

즉, 명령을 입력할 수는 없지만, 내부적으로 컨테이너는 여전히 입력을 기다리고 있으니 계속 실행됩니다.

ps를 통해 살펴보면 sleepy_bohr 이라는 이름의 node 컨테이너가 실행 중임을 알 수 있습니다.

 

▶ exec

docker exec 를 통해서 실행 중인 컨테이너 내부에서 특정 명령을 실행할 수 있습니다.

즉, 실행중인 컨테이너에게 추가적인 명령을 전달하는 방식입니다. 명령이 수행되도 컨테이너가 종료되지 않습니다.

docker exec -it <컨테이너 이름> npm init

 

 

이제 다음 명령어를 통해 컨테이너 내부를 초기화해봅시다.

docker exec -it sleepy_bohr npm init

즉, 로컬에 node를 설치하지 않고도 npm 명령어를 사용하게 된 것입니다.

컨테이너 내부에서 수행되기 때문입니다.

 

하지만 이는 유용하지는 않습니다. 컨테이너 내부 프로젝트가 있다면 접근할 수가 없기 때문입니다.

 

▶ docker run -it node npm init

일반적으로 run을 실행하면 기본적으로 수행되는 동작이 이미지마다 지정되어 있습니다.

node 같은 경우 docker run node를 실행하면 node.js의 쉘과 커뮤니케이션을 할 수 있죠!

 

하지만 다음과 같이 node 뒤에 <npm init>을 추가하여 디폴트 명령을 덮어씌울 수 있습니다.

docker run -it node npm init

그러면 node의 쉘 모드가 진행되는 것 이 아니라, npm init을 수행하게 됩니다.

만약 Dockerfile에 CMD를 지정해 두었다면, 해당 CMD 또한 무시되고 위에서 오버 라이딩 한 npm init이 수행되어버립니다.

 

또한 초기화 작업 이후, 컨테이너가 종료됩니다.

 

2. 유틸리티 컨테이너 구축

사용자에게 이미지에 대한 모든 권한을 부여하고, 사용자가 이미지에 대한 모든 명령을 실행할 수 있도록 합시다.

 

우선 경량화 버전의 노드를 사용하는 Dockerfile을 하나 만들어봅시다.

FROM node:14-alpine

WORKDIR /app

이후 "docker build -t node-util . "을 통해 빌드해줍시다. node-util이라는 이미지가 생성되었습니다!

 

이번에는 해당 이미지를 이용해서 프로젝트를 초기화하고, 우리의 로컴 컴퓨터에 미러링 해봅시다!

 

즉, 컨테이너를 통해서 로컬의 프로젝트를 초기화하겠다는 것이 목표입니다!

 

초기화 전의 디렉터리 상태는 다음과 같습니다.

Docker 파일 말고는 비어있다

 

이후 다음 명령어를 통해 컨테이너의 node를 사용하여 로컬 프로젝트를 초기화해봅시다!

docker run -it -v /Users/shine/study/docker-study/shine-util:/app node-util npm init

결과는 다음과 같이, 원래는 없던 package.json 파일이 생성되었습니다!

또한 run 명령어를 수행할 때 기본 동작을 npm init으로 덮어씌웠기 때문에, 초기화 후 컨테이너는 소멸됩니다.

 

3. ENTRYPOINT

위에서 Dockerfile의 CMD 부분은 "docker run -it node npm init"에서 npm init에 의해 덮어씌워 진다 말한 적이 있습니다.

 

하지만 ENTRYPOINT는 다릅니다.

ENTRYPOINT에 지정한 명령 뒤에 추가되어 npm init이 수행되게 됩니다.

 

FROM node:14-alpine

WORKDIR /app

ENTRYPOINT [ "npm" ]

위와 같이 ENTRYPOINT를 추가해 준 후, 다시 빌드해봅시다!

docker build -t mynpm .

 

이후 다음과 같이 명령을 수행하면 이전과 같이 package.json이 생성됩니다.

docker run -it -v /Users/shine/study/docker-study/shine-util:/app mynpm init

주의해서 볼 점이 있는데, 이전과 달리 init 만 명시해주었습니다!

이는 ENTRYPOINT에 이미 "npm"이 있기 때문입니다!!

 

4. Docker Compose 사용

위의 명령을 다음과 같이 컴포즈 파일로 만들어봅시다!

version: '3.8'
services:
  npm:
    build: ./
    stdin_open: true
    tty: true
    volumes:
      - ./:/app

 

이후 다음과 같이 명령을 수행합니다.

docker-compose run npm init

run 이후 npm 명령은 컴포즈 파일에 지정한 service의 이름입니다.

하지만 위 명령은 수행된 뒤에 컨테이너가 자동 소멸되지가 않습니다. 이를 위해 "--rm" 옵션을 추가해주면 됩니다.

docker-compose run --rm npm init

 

댓글