Docker를 처음 접하면 보통 "개발할 때 편한 실행 도구" 정도로 이해하게 됩니다. 실제로도 Docker는 로컬 환경을 빠르게 띄우고 의존성을 함께 묶는 데 큰 도움을 줍니다. 하지만 조금만 범위를 넓혀 보면 Docker는 단순 실행 도구를 넘어, 환경을 통일하고 배포 절차를 단순화하며 운영 방식을 표준화하는 기술로 연결됩니다.
특히 "어제 내 노트북에서는 되던 코드가 오늘 서버에서는 왜 안 되는가" 같은 문제를 줄여 준다는 점에서, Docker의 가장 중요한 역할 중 하나는 일관된 환경을 제공하는 데 있습니다. 이 지점부터 Docker는 개발 편의성의 영역을 넘어 환경 구성과 배포, 그리고 인프라의 이야기로 자연스럽게 이어집니다.
이 글은 그래서 Docker 기술 자체를 먼저 가볍게 설명한 뒤, 환경 구성 도구로서의 의미, 배포 방식으로서의 가치, 마지막으로 인프라 레이어에서 맡는 역할까지 순서대로 정리해 보려 합니다.
이 글의 흐름
- Docker 기술은 무엇인가
- 학생이 맥에서 가장 먼저 만나게 되는 이미지들
- Docker가 일관된 환경 구성을 어떻게 돕는가
- Docker Compose로 여러 컨테이너를 함께 다루는 방법
- Docker가 왜 인프라 이야기로 이어지는가
이번 글에서 새로 나오는 용어
- 이미지(Image): 애플리케이션과 실행 환경을 묶어 둔 배포 단위로, 서버마다 같은 결과를 재현하는 기준점입니다.
- 컨테이너(Container): 이미지를 실제로 실행한 인스턴스로, 프로세스 격리와 자원 제한을 적용할 수 있습니다.
- 볼륨(Volume): 컨테이너를 삭제해도 남겨 둘 데이터를 저장하는 영역으로, 데이터베이스나 업로드 파일을 보존할 때 사용합니다.
- 브리지 네트워크(Bridge Network): 여러 컨테이너가 내부적으로 통신하는 가상 네트워크로, 서비스 간 연결 방식을 제어합니다.
읽기 카드
- 예상 소요 시간: 20분
- 사전 준비: 리눅스 프로세스, 포트, 환경 변수 개념
- 읽고 나면: Docker를 개발 도구와 인프라 도구 두 관점에서 구분해 설명할 수 있습니다.
Docker 기술은 무엇인가
Docker는 애플리케이션과 그 실행 환경을 이미지로 묶고, 그 이미지를 컨테이너라는 형태로 실행하는 기술입니다. 여기서 핵심은 "앱만 옮기는 것"이 아니라 "앱이 실행되는 조건까지 함께 옮긴다"는 점입니다.
전통적으로는 서버마다 언어 런타임, 시스템 패키지, 라이브러리 버전을 직접 설치해야 했습니다. 이 방식은 익숙하지만, 서버가 늘어날수록 작은 차이가 장애로 이어지기 쉽습니다. Docker는 이 실행 조건을 이미지 안에 고정함으로써, 같은 소프트웨어를 더 예측 가능한 방식으로 옮길 수 있게 합니다.
즉, Docker는 가상머신처럼 운영체제 전체를 가상화하는 기술이라기보다, 프로세스를 격리된 단위로 실행하면서 배포 단위를 표준화하는 기술에 가깝습니다. 이 특성 덕분에 Docker는 개발과 운영 사이의 간극을 줄이는 공통 기반이 됩니다.
맥에서 Docker를 쓴다고 해서 macOS 위에 바로 리눅스 프로세스가 뜨는 것은 아닙니다. 실제로는 Docker Desktop 같은 도구가 내부에 리눅스 실행 환경을 만들고, 그 위에서 컨테이너가 돌아갑니다. 학생 입장에서는 이 구조 덕분에 맥에서도 우분투나 알파인 같은 리눅스 환경을 비교적 부담 없이 실습할 수 있습니다.
학생이 맥에서 가장 먼저 만나게 되는 이미지들
처음 Docker를 배울 때는 "어떤 이미지를 띄워 봐야 하는가"가 막막할 수 있습니다. 이때는 목적이 분명한 몇 가지 공식 이미지만 익혀도 감을 잡기 쉽습니다.
1. Ubuntu 이미지
ubuntu:24.04 같은 이미지는 리눅스 서버 실습에 가장 직관적입니다. apt를 사용해 패키지를 설치할 수 있고, 많은 입문 자료가 우분투 기준으로 작성되어 있어서 따라가기 쉽습니다.
docker run -it --rm ubuntu:24.04 bash
이 명령으로 들어가면 학생들은 맥 터미널 안에서 우분투 셸을 바로 경험할 수 있습니다. 패키지 설치, 파일 생성, 프로세스 확인 같은 기초 실습을 할 때 가장 무난한 출발점입니다.
2. Alpine 이미지
alpine:3.20 계열은 매우 가볍고 빠른 이미지입니다. 기본 셸은 bash가 아니라 sh이고, 패키지 관리자도 apt 대신 apk를 사용합니다. 그래서 "작고 단순한 리눅스 환경"과 "배포용 경량 이미지"를 이해할 때 좋습니다.
docker run -it --rm alpine:3.20 sh
알파인은 빠르게 뜨고 이미지 크기도 작아서, 컨테이너가 꼭 무거운 가상머신일 필요는 없다는 점을 보여 주기 좋습니다. 반대로 익숙한 유틸리티가 빠져 있는 경우도 많아서, 실습 환경과 배포 환경의 trade-off를 설명하기에도 적합합니다.
3. MySQL 같은 서비스 이미지
데이터베이스 이미지는 Docker가 "앱 실행기"를 넘어 "실습용 인프라 구성 도구"가 되는 순간을 보여 줍니다. 예를 들어 mysql:8.4 이미지는 환경 변수, 포트, 볼륨만 정하면 곧바로 데이터베이스를 띄울 수 있습니다.
docker run -d --name mysql-lab \
-e MYSQL_ROOT_PASSWORD=your-root-password \
-e MYSQL_DATABASE=sample \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
mysql:8.4
이런 공식 서비스 이미지는 이미 자주 쓰는 유틸과 시작 스크립트가 잘 정리되어 있어서, 학생들이 설치 문서와 초기 설정에 시간을 너무 많이 쓰지 않도록 도와줍니다. 즉, Docker 이미지는 단순한 압축 파일이 아니라 "특정 역할을 바로 수행할 수 있게 준비된 실행 단위"라는 감각을 주기 좋습니다.
Docker가 일관된 환경 구성을 어떻게 돕는가
Docker가 널리 쓰이게 된 가장 큰 이유 중 하나는 환경 차이를 줄여 주기 때문입니다. 개발자마다 운영체제가 다르고, 로컬에 설치된 패키지 버전이 다르고, 서버마다 설정이 조금씩 다르면 애플리케이션의 동작도 흔들리기 쉽습니다.
Docker는 이 문제를 "환경도 코드처럼 고정한다"는 방식으로 다룹니다. 어떤 베이스 이미지를 쓰는지, 어떤 패키지를 설치하는지, 어떤 시작 명령으로 실행하는지를 Dockerfile과 Compose 파일에 남기면, 실행 환경이 문서가 아니라 실제 배포 단위로 관리됩니다.
예를 들어 팀원 모두가 같은 이미지로 앱을 띄우면, "내 컴퓨터에서는 됐는데"라는 말이 줄어듭니다. 운영 서버도 같은 이미지를 받아 실행하면, 개발 환경과 운영 환경 사이의 간극 역시 줄어듭니다.
여기서 Docker의 가치는 단순 편의성이 아니라 재현성입니다.
- 새 팀원이 들어와도 같은 환경을 빠르게 띄울 수 있습니다.
- CI에서도 로컬과 비슷한 조건으로 테스트할 수 있습니다.
- 운영 서버에서도 같은 이미지 태그를 기준으로 상태를 확인할 수 있습니다.
즉, Docker는 환경을 "설명하는 도구"가 아니라 환경을 "복제 가능한 형태로 제공하는 도구"라고 보는 편이 더 정확합니다.
Docker Compose로 여러 컨테이너를 함께 다루는 방법
여기서부터는 docker run을 여러 번 치는 방식보다 Docker Compose를 먼저 익히는 편이 좋습니다. 이유는 간단합니다. 실제 실습이나 서비스 운영에서는 컨테이너를 하나만 띄우는 경우보다, 앱과 데이터베이스와 보조 도구를 함께 다루는 경우가 훨씬 많기 때문입니다.
특히 학생들이 맥에서 Docker를 쓸 때 Compose가 편한 이유는, "우분투 실습 컨테이너 하나", "가벼운 알파인 테스트 컨테이너 하나", "MySQL 데이터베이스 하나"처럼 여러 환경을 한 파일에서 관리할 수 있기 때문입니다.
services:
ubuntu-lab:
image: ubuntu:24.04
command: ["bash", "-lc", "sleep infinity"]
stdin_open: true
tty: true
alpine-lab:
image: alpine:3.20
command: ["sh", "-lc", "sleep infinity"]
stdin_open: true
tty: true
mysql:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: your-root-password
MYSQL_DATABASE: sample
MYSQL_USER: student
MYSQL_PASSWORD: your-app-password
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
restart: unless-stopped
volumes:
mysql-data:
이 파일 하나만 있으면 세 가지 실습 환경을 함께 올리고 내릴 수 있습니다.
docker compose up -d
docker compose ps
docker compose exec ubuntu-lab bash
docker compose exec alpine-lab sh
docker compose exec mysql mysql -u student -p
docker compose down
여기서 중요한 포인트는 다음과 같습니다.
- 서비스 이름이 곧 관리 단위가 됩니다.
ubuntu-lab,alpine-lab,mysql처럼 이름을 붙이면 어떤 컨테이너에 들어가야 하는지 바로 알 수 있습니다. - 환경 구성이 파일에 남습니다. 누가 다시 실행해도 같은 이미지, 같은 포트, 같은 볼륨 구성이 재현됩니다.
- 데이터는 볼륨으로 분리합니다.
mysql-data볼륨이 있기 때문에 컨테이너를 내렸다가 다시 올려도 데이터베이스 파일은 유지됩니다. - 실습 흐름이 단순해집니다. 터미널 명령을 길게 복사하기보다
compose.yaml한 장으로 환경을 공유할 수 있습니다.
Compose를 먼저 배우면 Docker를 "컨테이너 하나 띄우는 명령어 모음"이 아니라 "실행 환경 전체를 선언하는 방식"으로 이해하게 됩니다. 이 관점이 바로 인프라 학습으로 이어지는 핵심입니다.
실제로는 아래 네 가지 정도만 익혀도 초반 실습은 거의 충분합니다.
docker compose up -d: 백그라운드에서 전체 환경을 띄웁니다.docker compose ps: 어떤 서비스가 살아 있는지 확인합니다.docker compose exec <service> <shell>: 특정 컨테이너 안으로 들어갑니다.docker compose down: 전체 환경을 정리합니다.
여기서 MySQL 데이터를 완전히 초기화하고 다시 시작하고 싶다면 docker compose down -v를 사용하면 됩니다. 반대로 데이터를 남기고 컨테이너만 내리고 싶다면 docker compose down까지만 쓰는 편이 안전합니다.
Docker가 배포 방식을 어떻게 바꾸는가
환경이 고정되면 다음으로 바뀌는 것은 배포 방식입니다. 전통적인 배포는 서버에 접속해서 패키지를 설치하고, 코드를 내려받고, 프로세스를 다시 시작하는 식으로 진행되는 경우가 많았습니다. 이 방식은 익숙하지만, 서버마다 설치 상태가 조금씩 달라질 수 있고 되돌리기도 쉽지 않습니다.
Docker는 배포 단위를 이미지로 바꾸면서 배포를 더 단순한 흐름으로 재정의합니다.
이 흐름의 핵심은 "서버에서 다시 만들지 않는다"는 점입니다. 한 번 검증한 이미지를 그대로 가져가므로, 배포 서버는 빌드 머신이 아니라 실행 머신에 가까워집니다. 이 변화만으로도 운영 복잡도가 크게 줄어듭니다.
이 방식이 중요한 이유는 다음과 같습니다.
- 재현성: 같은 이미지 태그를 쓰면 어디서 실행해도 거의 같은 결과가 나옵니다.
- 교체 가능성: 문제가 생긴 컨테이너를 수정하기보다 새 컨테이너로 교체하는 흐름을 만들기 쉽습니다.
- 표준화: 로그 경로, 포트 노출, 환경 변수 주입, 시작 명령을 코드로 남길 수 있습니다.
배포 관점에서 보면 Docker는 더 이상 로컬 실행 도구가 아닙니다. 어떤 이미지를 언제 빌드할지, 어떤 태그를 붙일지, 어떤 레지스트리에 저장할지, 실패하면 어느 버전으로 되돌릴지까지 이어지는 운영 절차의 중심이 됩니다.
Docker가 왜 인프라 이야기로 이어지는가
이 지점부터 Docker는 자연스럽게 인프라 레이어로 들어옵니다. 이유는 단순합니다. 배포와 운영은 결국 네트워크, 스토리지, 상태 확인, 복구 절차와 연결되기 때문입니다. 컨테이너를 잘 띄우는 것만으로는 서비스가 운영되지 않습니다.
Docker를 인프라로 다루기 시작하면 Dockerfile 한 장보다 더 넓은 범위를 보게 됩니다.
1. 네트워크
컨테이너는 기본적으로 서로 분리되어 있습니다. 그래서 어떤 서비스가 어느 네트워크에 붙는지, 외부에 노출되는 포트는 무엇인지, 내부 통신만 허용할 서비스는 무엇인지를 설계해야 합니다. 이 시점부터 Docker는 애플리케이션 실행기가 아니라 네트워크 경계의 일부가 됩니다.
2. 스토리지
컨테이너는 교체될 수 있지만 데이터는 남아야 합니다. 데이터베이스, 업로드 파일, 캐시 디렉터리 중 무엇을 볼륨에 둘지 정하지 않으면 재배포가 곧 데이터 손실로 이어질 수 있습니다.
3. 관찰 가능성
운영 환경에서는 "실행 중인가"보다 "정상인가"가 중요합니다. 그래서 로그를 어디서 읽는지, 헬스 체크를 어떻게 붙이는지, 재시작 정책은 무엇인지가 함께 설계되어야 합니다.
4. 배포 절차
컨테이너를 수동으로 띄우는 것과 배포 절차를 만든 것은 다릅니다. 이미지 빌드, 태그 규칙, 레지스트리 업로드, 서버 반영, 실패 시 롤백까지 이어져야 Docker는 인프라 역할을 제대로 합니다.
가장 단순한 운영 단위: Docker Compose
작은 규모의 서비스나 학습 환경에서는 Kubernetes 같은 큰 오케스트레이션 도구보다 Docker Compose가 더 좋은 출발점일 수 있습니다. 중요한 것은 "최신 기술"이 아니라 "운영자가 짧은 문서로 상태를 이해할 수 있는가"이기 때문입니다. 학생 입장에서도 Compose는 여러 실습용 컨테이너를 한 번에 정리하는 가장 실용적인 첫 단계입니다. 다만 Compose는 주로 로컬 개발, 학습, 단일 호스트 배포에 잘 맞고, 여러 서버를 묶는 대규모 운영에는 보통 별도 오케스트레이터를 사용합니다.
services:
app:
image: ghcr.io/example/app:2026-03-17
ports:
- "8000:8000"
env_file:
- .env
restart: unless-stopped
depends_on:
- db
db:
image: postgres:16
volumes:
- postgres-data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres-data:
위 파일에는 이미 인프라 판단이 들어 있습니다. 어떤 이미지를 쓸지, 어떤 포트를 열지, 어떤 데이터는 남길지, 프로세스가 죽으면 어떻게 다시 띄울지가 모두 코드로 표현되어 있기 때문입니다. 그래서 Compose는 입문 단계에서는 실습 환경 정의서이고, 단일 서버 기준의 소규모 운영 단계에서는 작은 서비스의 배포 정의서 역할을 합니다.
흔한 오해
"Docker를 쓰면 곧바로 운영이 쉬워진다"
반은 맞고 반은 틀립니다. 실행 환경의 차이를 줄여 주는 것은 맞지만, 로그 수집, 비밀 관리, 이미지 태그 전략, 데이터 백업을 설계하지 않으면 오히려 문제를 더 감춥니다.
"Docker는 개발자 도구라서 인프라와는 별개다"
로컬 개발에서 시작하는 경우가 많아서 그렇게 느껴질 뿐입니다. 실제로는 Docker를 기준으로 배포 파이프라인과 서버 운영 절차가 만들어지는 순간 인프라의 핵심 레이어가 됩니다.
"컨테이너가 있으니 서버는 신경 쓰지 않아도 된다"
컨테이너는 서버를 추상화하지만 없애지는 않습니다. 커널, 디스크, 메모리, 네트워크, 방화벽, 백업 정책은 여전히 서버와 함께 관리해야 합니다.
마무리
그래서 Docker는 출발은 개발 편의 도구처럼 보일 수 있어도, 실제로는 일관된 환경 제공에서 시작해 배포 표준화와 운영 절차 설계로 이어지는 기술입니다. 이 흐름 전체를 보면 Docker를 인프라 카테고리에서 다루는 이유가 분명해집니다.
이 시리즈에서는 앞으로 "Docker를 설치하는 법"보다 "Docker를 운영 레이어로 쓰기 시작하면 무엇을 같이 설계해야 하는가"를 중심으로 다룰 예정입니다. 우분투처럼 익숙한 실습용 이미지, 알파인처럼 가벼운 배포용 이미지, MySQL 같은 서비스 이미지를 Compose로 함께 다루기 시작하면 Docker는 금방 인프라 문맥으로 넘어갑니다. 다음 글에서는 Dockerfile과 이미지 태그 전략이 왜 일관된 환경과 배포 신뢰성에 직접 연결되는지 이어서 정리해 보겠습니다.
💬 댓글
이 글에 대한 의견을 남겨주세요