Docker 개념

김진효·2026년 8월 27일

[CS] 면접 대비

목록 보기
11/11

'따라하며 배우는 도커와 CI 환경' 책을 읽고 리뷰를 쓸까 하다가 개념을 전체적으로 정리해두면 좋을 것 같아서 남기는 글 🫠


🐋 Docker 란

도커란 애플리케이션을 "컨테이너"라는 표준화된 유닛으로 패키징해서 신속하게 구축, 테스트, 배포, 실행할 수 있게 해주는 소프트웨어 플랫폼
→ 컨테이너를 사용해 응용프로그램을 더 쉽게 만들고 배포하고 실행할 수 있도록 설계

컨테이너와 이미지

이미지를 통해 컨테이너를 만든다!
이미지: 애플리케이션과 그 실행에 필요한 시스템, 라이브러리를 포함하는 읽기 전용 실행 템플릿
컨테이너: 이미지 기반으로 실행한 인스턴스

Docker 컨테이너와 가상머신(VM)의 차이

docker-containerized-and-vm
가상머신(VM)은 하이퍼바이저 기반(물리 하드웨어 위에서 여러 가상 머신을 구동)으로, 전체 운영 체제(OS)를 포함하여 자체 커널, 하드웨어 드라이버, 프로그램 및 애플리케이션 등 더 많은 리소스를 포함하고 있어 무겁다
따라서 단 하나의 애플리케이션만 격리하기 위해 가상 머신을 생성하는 건 비효율적이다
다만 더 강력한 격리와 보안 제공
컨테이너는 여러 개의 컨테이너를 실행해도 동일한 커널을 공유하며, 필요한 애플리케이션과 그 종속성만을 포함하여 가볍고 빠르다
실행 시간이 짧고 리소스 사용도 효율적
각 컨테이너는 사용자 공간에서 격리된 프로세스로 실행

Docker를 쓰는 이유

서로 협업하면서 일어날 수 있는 상황을 가정해보자!

  1. 개발 환경 불일치

    A : 프로젝트 실행하려니까 갑자기 이런 에러가 나면서 안돼요 (java 17)
    B : 제 컴퓨터에서는 되는데요? (java 11)

    🔎 문법과 라이브러리 의존성이 미묘하게 어긋나면서 개발 환경 불일치로 오류가 일어날 수 있음
    ✅ 도커를 쓴다면 개발, 테스트, 운영 환경을 일치시켜 환경 차이로 인한 문제를 원천 차단할 수 있다!

  2. 복잡한 설치 과정 생략
    물론물론 이런 일이 실무에는 없겠지만 개발을 막 배우기 시작한 시점에 팀 프로젝트를 하다가 아직 배포 전이라 프론트엔드 A가 백엔드 API를 연동해서 테스트를 해봐야 하는 상황이라고 하자

    A: API 연동 테스트 할 건데 어떻게 해야 하나요?
    B: 앗 먼저 Java랑 MySQL 까시구요 스크립트 한 번 돌리시고 앗 그리고 Redis도 포트 열어서 띄워두셔야하는데...
    A: (백엔드 DB 세팅까지 해야하는거..?)

    🔎 이렇게 API 연결 하나를 위해서 프론트엔드 개발자가 데이터베이스와 백엔드 다 로컬에 직접 구축하게 되면 환경 세팅에만 하루를 쓰게 될 수도 있다
    ✅ 도커를 쓴다면 프론트엔드는 백엔드 쪽에서 미리 만들어놓은 docker-compose.yml 파일 하나만 받아다가 컨테이너 실행하기만 하면 된다


Docker 실행 방식

docker-architecture
1. 도커 클라이언트(CLI) 에서 명령(요청)

예) docker run hello-world

2-1. 도커 서버(데몬)
해당 이미지가 로컬에 이미 다운로드 되어있는지 확인 (이미지 캐시 보관 장소)
없으면 아래와 같이 출력되며 docker가 어떤 단계를 따르는지 확인해볼 수 있음

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete
d5e71e642bf5: Download complete
Digest: sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243cc
Status: Downloaded newer image for hello-world:latest

2-2. 도커 허브와 연결하여 이미지 가져와서 로컬에 보관 후 이미지 이용하여 컨테이너 생성하게 된다
이는 명령어 실행 후 나오는 출력 결과에서도 확인 가능

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64)
3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal.
  1. 이후 컨테이너가 프로그램을 실행

Docker 컨테이너 생명주기

docker_container_lifecycle


Docker Hub

도커허브는 도커 레지스트리 (컨테이너 이미지를 저장하고 공유하는 중앙 집중식 위치)
다양한 공개 Docker 이미지가 저장되어 있고, 빌드된 이미지도 저장할 수 있음
docker-compose.yml에서 build 대신 image:<도커아이디>/<도커이미지이름> 으로 도커이미지를 실제로 빌드 하는게 아닌 도커 허브에 빌드된 도커 이미지를 사용

services:
  # 로컬 Dockerfile을 빌드해서 사용하는 경우
  my-app:
    build: .

  # 도커 허브에 이미 올라가 있는 이미지를 그대로 가져다 쓰는 경우
  my-app:
    image: ppnyoong/my-app:latest

Dockerfile

도커 이미지를 만들기 위한 설정 파일
이 파일 안에는 이미지를 생성하는 데 필요한 명령어들이 순서대로 기술
→ 도커 컨테이너가 어떻게 행동해야 하는지에 대한 설정을 정의
docker build 명령어를 사용하여 Dockerfile로부터 이미지를 생성할 수 있으며, 이 과정에서 각 명령어가 순차적으로 실행

예시 및 설명

FROM node:10
WORKDIR /usr/src/app

COPY package.json ./
RUN npm install

COPY ./ ./
EXPOSE 8080

CMD ["node","server.js"]
  • FROM
    이미지 생성 시 기반이 되는 이미지 레이어 명시
    <이미지 이름>:<태그> 형식으로 작성
    태그를 붙이지 않으면 자동으로 가장 최신 버전으로 내려 받음
  • WORKDIR <경로>
    향후 명령이 실행될 위치와 디렉터리 파일이 컨테이너 이미지 내부에 복사될 위치가 지정 → 작업 디렉터리 설정
  • COPY
    로컬에 있는 파일을 도커 이미지로 복사 (도커 컨테이너 안으로 복사)
  • EXPOSE
    포트 지정
  • RUN
    도커 이미지가 생성되기 전에 수행할 셸 명령어
  • CMD
    컨테이너가 시작됐을 때 실행할 실행 파일 또는 셸 스크립트
    해당 명령어는 도커 파일 내에서 한 번만 사용 가능

COPY 지시자를 나누어 효율적으로 빌드하기

Dockerfile-copy-cache

소스코드 변경만 일어난 경우에는 종속성까지 다시 내려받을 필요가 없다
종속성을 내려받는 단계를 나누어 종속성에 변화가 있을때만 다시 내려받고 없으면 캐시(cache)를 이용해 해당 과정 생략
→ 빌드 결과 출력에서 Using Cache 가 뜨는걸 확인할 수 있다


Docker Volume

코드 수정 시 소스 코드를 복사하는 게 아니라 호스트 디렉터리에 있는 파일들을 참조해서 사용
→ COPY 해서 재빌드할 필요를 줄이고 바로바로 작업 내용 확인 가능

예시 코드

docker_volume
-v는 바인드 마운트, 익명 볼륨
앞은 익명 볼륨을 나타내고 뒤는 바인드를 나타낸다 -v 호스트 경로:컨테이너 경로

  • PWD(print working directory)
    현재 작업 중인 디렉터리의 절대 경로를 출력하는 명령어

Docker Compose

하나의 파일에서 여러 Docker 컨테이너를 정의하고 한번에 실행하기 위한 도구
docker-compose.yaml 파일로 구성

명령어

  • 실행 docker-compose up
    --build 를 붙이면 이미지 있든 없든 이미지 빌드하고 시작
  • 정지 docker-compose stop
  • 정지+삭제 docker-compose down

예시 및 설명

version: '3.8' 			# 도커 컴포즈의 버전

services:				# 이곳에 실행하려는 컨테이너들을 정의
  # 공식 이미지를 사용하는 Redis 서비스
  redis-server:			# 컨테이너 이름
    image: redis:alpine	# 컨테이너에서 사용하는 이미지
    restart: always

  # 로컬 Dockerfile을 빌드하여 사용하는 Node.js 앱 서비스
  node-app:				# 컨테이너 이름
    build: .          	# 현재 디렉터리의 Dockerfile 빌드
    ports:
      - "8080:8080"   	# 포트매핑 "로컬:컨테이너 포트"
    depends_on:			
      - redis-server  	# redis-server가 먼저 시작되도록 설정
    environment:		# 환경 변수
      - REDIS_HOST=redis-server
      - REDIS_PORT=6379
  • restart 옵션 비교
    • always 언제나 다시 시작
      컨테이너가 멈추면 이유를 불문하고 무조건 다시 실행
      용도: 데이터베이스나 웹서버 처럼 서버가 켜져 있는 한 무조건 항상 살려두어야 할 서비스의 경우 사용
    • unless-stopped 멈추지 않았다면 다시 시작
      docker stop으로 직접 멈춰놓은 경우에는 서버가 재부팅 되어도 자동으로 켜지지 않게
      용도: 점검하려고 꺼둔거 그대로 유지하기 위해 (실무)
    • no (기본값)
      컨테이너가 죽어도 절대로 자동으로 다시 시작하지 않음
      용도: 일회성 작업 (데이터 백업, 스크립트 실행, 마이그레이션)
    • on-failure 실패했을 때만 다시 시작
      컨테이너가 에러로 죽었을 때만 다시 시작
      용도: 특정 배치 작업이나 에러 발생 시 재시도가 필요한 프로그램

Dockerfile과 docker-compose

Dockerfile은 컨테이너 이미지를 빌드하는 방법에 대한 지침을 제공하고, compose 파일은 실행 중인 컨테이너를 정의 (compose 파일은 특정 서비스에 사용할 이미지를 빌드하기 위해 Dockerfile을 참조하는 경우가 많음)


Docker 명령어

  • 도커 버전 확인 docker version
  • 도커 실행 테스트 docker run hello-world
    참고로 docker run = docker create + docker start
  • 도커 이미지의 내부 파일 구조 보기 docker run <이미지> ls
  • 컨테이너 실행 확인 명령어
    • 실행 중인 컨테이너 docker ps (ps=process status)
    • 전체 컨테이너 docker ps -a (a=all)
    • 자세한 정보 확인 docker inspect <컨테이너명>
  • 로그확인 명령어 docker logs <컨테이너명>
  • 실행 중인 컨테이너에 명령어 전달 docker exec -it <컨테이너명> <명령어>
    → it(interactive terminal) 명령어를 계속 실행할 수 있도록 실행 유지(종료 x)
  • 실행 중인 컨테이너에서 터미널 사용 docker exec -it <컨테이너명> sh
  • 컨테이너 실행 중지
    • 작업 모두 마치고 중지(SIGTERM+SIGKILL) docker stop <컨테이너명>
    • 즉시 중지(SIGKILL) docker kill <컨테이너명>
  • 도커 이미지 삭제 docker rmi <이미지>
  • 도커 이미지 나열 docker images

docker ps 출력결과 자세히 보기

CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                  NAMES
a1b2c3d4e5f6   nginx:latest   "/docker-entrypoint.…"   2 hours ago     Up 2 hours     0.0.0.0:80->80/tcp     web-server
  • CONTAINER ID
    컨테이너의 고유한 아이디 해시값
    실제로는 더 길지만 일부분만 출력된다
  • IMAGE
    컨테이너 생성 시 사용한 도커 이미지 이름
  • COMMAND
    컨테이너 시작 시 실행될 명령어
    대부분 이미지에 내장돼 있으므로 별도 설정이 필요하지 않음
  • CREATED
    컨테이너가 생성된 시각
  • STATUS
    컨테이너의 상태
    실행 중은 Up, 종료는 Exited, 일시 정지는 Pause
  • PORTS
    컨테이너가 개방한 포트와 호스트에 연결한 포트
    특별한 설정을 하지 않은 경우 출력되지 않음
  • NAMES
    컨테이너의 고유한 이름
    컨테이너 생성 시 --name 옵션으로 이름을 설정하지 않으면 도커 엔진이 임의로 형용사와 명사를 조합해 설정
    id와 마찬가지로 중복이 안 되고 이름을 변경할 수는 있음 (docker rename <원래 이름> <변경할 이름>)


참고

Docker docs
따라하며 배우는 도커와 CI 환경
[따라하며 배우는 도커와 CI 환경] Docker 개념
"Docker 없어도 되지 않나요?" — 면접관이 듣고 싶은 진짜 대답
[면접] 기술 면접 - Docker
도커 면접 질문 20선 정리 실무 개발자라면 꼭 알아야 할 핵심 개념

0개의 댓글