본 게시글은 유데미(udemy.com)의 < 【한글자막】 Docker & Kubernetes : 실전 가이드 > (Maximilian Schwarzmüller) 강의를 수강한 후 내용을 정리한 것입니다.
도커의 기본, 이미지(image)와 컨테이너(container)
이미지가 템플릿, 청사진, 설계도라면
컨테이너는 이 설계도를 가지고 지은 실제 구조물, 기계, 작동하고 움직이는 어떤 것에 비유할 수 있다.
한 image(=setup instructions)를 기반으로 여러 개의 컨테이너를 만들 수 있고,
컨테이너는 서로 다른 컴퓨터나 환경에서 작동할 수 있다.
이미지는 청사진, 설계도, 공유 패키지에 대응한다.
(setup instructions, blueprints, sharable packages, logic and code a container needs)
반면에 컨테이너는 구현된 실체이고, 실행 가능한 인스턴스이다. (concrete, runnable instances)
스택오버플로우에서는 케이크를 비유로 들어 둘의 차이를 아주 잘 설명해주고 있다.
What is the difference between a Docker image and a container?
When using Docker, we start with a base image. We boot it up, create changes and those changes are saved in layers forming another image. So eventually I have an image for my PostgreSQL instance a...
stackoverflow.com
이미 만들어진(pre-built) custom image 활용하기
프로그래밍의 세계에는 'Don't reinvent the wheel'이라는 유명한 격언이 있다.
즉 남들이 이미 잘 만들어놓은 툴이나 프레임워크를 굳이 또 직접 만들지 말고, 가져다 쓰라는 말이다.
마찬가지로 도커 이미지도 사람들이 이미 잘 만들어놓은 게 무수히 많다(파이썬부터 웹 개발에 필요한 Node.js, 리액트, 딥러닝 환경 등).
처음부터 나 혼자 만들 생각하지 말고 가져다쓰자.
이제 실습을 통해 도커 이미지와 컨테이너를 명령어로 다루는 법을 알아보자.
실습 1: node image를 Docker Hub에서 가져와 쓰기
node라는 이름의 image를 docker hub에서 가져와 쓴다.
하지만 먼저 node라는 이름의 image가 로컬에 존재하는지 확인한 후,
없다면 동일한 이름의 이미지를 Docker Hub에서 가져와 (있다면) 가져다쓴다.
docker run node
interactive mode로 컨테이너를 실행
컨테이너를 실행해도 터미널에 아무런 변화가 없을 수도 있다.
그 이유는 컨테이너를 interactive 모드로 실행하지 않았기 때문이다.
interactive 모드란, 컨테이너 내부를 마치 자기 로컬 컴퓨터의 터미널처럼 명령어를 입력하고 파일에 접근할 수 있는 상태를 말한다.
방법은? 간단하다. docker run 명령어 뒤에 -it 옵션(i = interactive, t = tty)을 붙여주면 된다.
# docker run -it node와 동일
docker run -i -t node
Docker 공식 매뉴얼(https://docs.docker.com/engine/reference/run/)을 보면 아래와 같이 설명하고 있다.
-a=[] : Attach to `STDIN`, `STDOUT` and/or `STDERR`
-t : Allocate a pseudo-tty
--sig-proxy=true: Proxy all received signals to the process (non-TTY mode only)
-i : Keep STDIN open even if not attached
tty(teleypewriter)는 콘솔이나 터미널을 의미한다.
컨테이너를 현재 사용자가 접근하고 사용할 수 있도록 가상 터미널을 띄운다는 옵션을 말한다.
현재 실행 중인 도커 컨테이너 정보를 확인하기
리눅스에서 프로세스를 확인하는 명령어 ps를 docker 뒤에 붙여서 쓰면 된다.
# ps -> "process"
docker ps -a
개발을 잘하려면, 거인의 어깨에 올라서자
우리는 훌륭한 개발자들이 이미 만들어놓은 라이브러리나 API의 도움을 받아 자신의 앱을 빠른 시간 안에 개발할 수 있었다.
도커도 마찬가지다.
남들이 잘 만들어 놓은 이미지를 기반으로 내가 필요한 부분만 추가해서 나만의 이미지를 만들자.
기본적인 환경과 툴을 제공하는 이미지를 Hub에서 가져온 다음에,
내가 개발하고 있는 앱에 수정을 가하고 필요한 부분을 추가하면 '나만의 이미지'를 만들고 배포할 수 있다.
Node image를 활용한 실습
저번에 Dockerfile이란 이미지를 빌드하기 위한 일종의 요약서, 주문서라고 배웠다.
Dockerfile 작성부터 시작해보자.
# FROM baseImage
# The name of the base image to use.
# Either exists in our local machine or in Docker Hub
FROM node
# Set the absolute or relative path to use as the working directory of the Docker container. Will be created if it does not exist
WORKDIR /app
# COPY [flags] source ... dest
# The name of the destination file or folder
COPY . /app
COPY 명령어
COPY 명령어는 왼쪽에서부터 차례로
- 현재 사용자(host)의 파일 시스템 중 복사하고 싶은 경로
- 붙여넣기할 컨테이너 내의 파일 시스템 경로
를 입력하면 된다.
container가 가지고 있는 파일 시스템은 현재 사용자의 파일 시스템과 완전히 독립된,
따로 떨어진(detached) 시스템이라고 생각해야 한다.
이렇게 COPY 명령어 전에 WORKDIR 명령어를 통해 컨테이너의 작업 디렉토리를 설정할 수도 있다.
RUN 명령어
노드 서버를 실행시키고 싶다면 이렇게 Dockerfile을 구성할 수도 있다.
# 윗부분 생략
RUN npm install
RUN node server.js
하지만 이렇게 하면 이미지를 빌드할 때마다 서버를 실행(node server.js
)하는 것이기 때문에 올바르지 않다.
우리가 서버를 실행하고 싶은 시점은 이미지를 빌드할 때가 아니라, 컨테이너를 실행할 때이기 때문이다.
CMD 명령어
이때 RUN 대신 CMD 명령어를 사용하면 된다.
# 윗부분 생략
RUN npm install
CMD node server.js
근데 이것도 틀렸다. CMD의 인자는 문자열의 리스트라는 걸 명시해야 한다.
# 윗부분 생략
RUN npm install
CMD ["node", "server.js"]
# Execute any commands on top of the current image as a new layer and commit the results.
RUN npm install
# Provide defaults for an executing container.
# If an executable is not specified, then `ENTRYPOINT` must be specified as well.
# There can only be one `CMD` instruction in a `Dockerfile`
CMD node server.js
만약 CMD를 dockerfile에 명시하지 않으면 base image의 CMD 부분이 자동으로 실행된다.
그렇기 때문에 아예 CMD 명령어 인자가 없는 base image로 빌드한다면(그럴 리는 거의 없겠지만) 에러가 발생한다.
또한 CMD 명령어는 Dockerfile의 항상 맨 마지막에 위치해야 한다.
이미지를 빌드하고 나서 그 이미지를 바탕으로 컨테이너를 만드는 것이기 때문에,
이미지 빌드에 관여하는 다른 명령어(FROM, WORKDIR, COPY, RUN 등)가 실행되고 난 다음
컨테이너 실행 시 수행되는 명령어인 CMD를 실행하는 게 순서 상 맞기 때문이다.
EXPOSE 명령어
EXPOSE는 내가 실행하고자 하는 컨테이너를 로컬 시스템에서 접근할 수 있도록 포트 번호를 열어놓는 명령어를 말한다.
Dockerfile에서 이미지를 "빌드(build)"하기
Dockerfile을 통해 이미지를 빌드하는 명령어는 "docker build"이다.
# dockerfile을 이용해 이미지를 빌드(나만의 커스텀 이미지 만들기)
# 현재 폴더 안에 Dockerfile이 존재해야 함
docker build .
이제 이미지를 바탕으로 컨테이너를 실행(생성까지 한번에)할 일만 남았다.
이때 컨테이너를 실행한다는 뜻에서 docker run 명령어를 쓴다.
docker build와, docker run 두 명령어 차이를 분명히 알고 있자.
컨테이너를 로컬에서도 접근하게 하는 방법: -it 옵션
그러고 나서 컨테이너를 실행했는데, 터미널에선 아무런 변화가 없다.
포트 번호
컨테이너를 외부(=사용자)에서도 접근하게 하려면, 아래 명령어 형식으로 컨테이너를 실행하면 된다.
docker run -p 3000:80 docker_id
웹 브라우저에서 '컨테이너를 실행하는 서버의 IP:3000' 형식으로 주소창에 입력하고 접속해보자.
만약 자신의 로컬에서 컨테이너를 실행하고 있다면 그냥 localhost:3000 을 웹브라우저에 입력해보자.
EXPOSE에 대한 부가 설명
Dockerfile의 'EXPOSE 어떤 포트번호'는 선택 사항이라고 한다.
컨테이너가 '이 포트번호로 저 스스로를 노출할 겁니다'라고 문서화하는 것이기 때문.
실제로 문서화가 되어있든 되어있지 않든 docker run
을 실행할 때에는 -p
를 사용해서 포트를 노출해야 한다.
하지만 Dockerfile에 'EXPOSE' 파트를 추가해서 이 동작을 문서화하는 게 모범적인 사용법이라고 한다.
'도커와 쿠버네티스' 카테고리의 다른 글
[2주차] Part 4: 도커 이미지 공유하기(push, pull) (0) | 2024.01.09 |
---|---|
[2주차] Part 3: 도커 이미지와 컨테이너를 관리하기 (1) | 2024.01.09 |
[2주차] Part 2: 이미지는 읽기 전용(read-only) 파일일 뿐이다 (1) | 2024.01.09 |
[1주차] Part 2: 도커 실습 시작하기 (1) | 2024.01.02 |
[1주차] Part 1: 우리가 도커(Docker)를 써야 하는 이유 (1) | 2024.01.02 |