1️⃣ 도커란?
도커가 어떻게 탄생하였는지, 도커는 무엇인지, 가상환경과의 차이점은 무엇인지에 대해 알아보고자 한다.
✅ 도커는 어떻게 탄생했을까?
현재 개발자들은 수많은 애플리케이션을 개발하며 협업을 통해 이를 만들어내고 있다.
특히 현대의 개발 환경에서는 여러 개발자가 함께 작업하는 협업 과정이 필수적이다.
☑️ 개발 환경 문제, 어떻게 해결할 수 있을까?
만약 개발자가 각자 다른 환경에서 작업한다면 어떨까?
운영 체제, 라이브러리 버전, 설정 값 등이 조금만 달라도 개발 중인 소프트웨어가 제대로 작동하지 않을 수 있다.
이런 환경 차이로 인해 생기는 의존성 문제는 협업뿐만 아니라 배포 과정에서도 골칫거리이다.
예를 들어, 개발 환경에서는 잘 실행되던 코드가 운영 환경에서는 실행되지 않거나 오류가 발생하는 일이 흔하다.
이는 개발 프로세스를 지연시키고, 때로는 시스템 전체의 안정성을 위협할 수도 있다.
☑️ 도커의 탄생
이러한 문제를 해결하기 위해, "어플리케이션과 그 환경을 하나의 단위로 묶을 수는 없을까?"
라는 아이디어에서 도커가 탄생했다.
도커는 컨테이너라는 기술을 활용해 애플리케이션과 그 의존성을 하나로 패키징하여
어디서든 동일하게 실행할 수 있도록 한다.
1. 환경 불일치 문제: 개발 환경, 테스트 환경, 운영 환경 간의 차이를 제거.
2. 의존성 문제: 어플리케이션 실행에 필요한 모든 요소를 하나의 단위로 묶어 일관성 유지.
3. 배포의 간소화: 복잡한 설정 없이 동일한 환경에서 실행 가능.
결과적으로, 도커는 위와 같은 문제를 해결하기 위해 등장했다.
✅ 도커(Docker)란?
도커는 애플리케이션을 컨테이너라는 가상화된 환경에서 실행할 수 있게 해주는 플랫폼이다.
컨테이너를 사용하면 애플리케이션과 그 의존성을 하나의 패키지로 묶어 어디서나 일관되게 실행할 수 있다.
☑️ 가상환경 vs 도커
가상환경(Virtual Environment)과 도커(Docker)는
모두 소프트웨어 개발에서 격리된 환경을 제공한다는 공통점이 있지만, 동작 방식과 목적이 크게 다르다.
구분 | 가상환경 | 도커 |
격리 수준 | 언어(Python 등)와 라이브러리 수준 격리 | 운영 체제(OS) 수준 격리 |
목적 | 특정 언어의 의존성 충돌 방지 | 애플리케이션 + 실행 환경을 패키징 및 이식성 제공 |
운영방식 | 호스트 OS와 직접 연결, 가볍고 간단 애플리케이션이 호스트 OS와 완전히 독립적이지 않음. |
컨테이너로 격리, 배포 및 실행 환경 이식성 강화 애플리케이션과 OS의 종속성을 함께 묶어 배포 |
이식성 | 동일한 OS 환경에서만 실행 가능 | 환경에 상관없이 동일하게 실행 가능 |
리소스 | 가벼움 | 비교적 가벼움 (VM보다는 가볍지만 가상환경보다 무거움) |
☑️ 도커의 핵심 개념
도커는 이미지, 컨테이너, 도커 파일, 도커 허브라는 네 가지 핵심 개념을 중심으로 동작한다.
아래의 이미지를 통해 각 개념의 관계를 쉽게 이해할 수 있다.
🔸 1. 이미지
이미지는 컨테이너를 생성하기 위한 템플릿이다.
애플리케이션 실행에 필요한 코드, 라이브러리, 의존성을 포함하며 읽기 전용으로 저장된다.
- 위 그림의 Images 부분에 보이는 우분투(ubuntu)와 같은 이미지는 특정 환경을 설정하는 데 사용된다.
- 이미지를 기반으로 컨테이너가 생성된다.
🔸 2. 컨테이너
컨테이너는 이미지를 실행하여 생성된 격리된 실행 환경이다.
- 위 그림의 Containers 부분은 여러 컨테이너가 독립적으로 실행되는 모습을 보여준다.
- 컨테이너는 애플리케이션과 그 실행 환경을 하나로 묶어 동일한 상태로 어디서든 실행할 수 있도록 한다.
🧐 컨테이너와 이미지를 나눈 이유?
컨테이너와 이미지를 나눈 이유는 유연성과 재사용성을 극대화하기 위해서이다.
도커의 핵심 설계 철학 중 하나는 "한 번 빌드하고, 어디서나 실행한다"이다.
이를 달성하기 위해 이미지와 컨테이너를 분리하여 역할을 명확히 했다.
🎯 1. 이미지(Image): 실행 환경의 정의
- 이미지는 컨테이너를 생성하기 위한 정적 템플릿이다.
- 애플리케이션 실행에 필요한 모든 요소(코드, 라이브러리, 설정)를 포함하지만 변경되지 않는 읽기 전용 상태를 유지한다.
- 이미지를 한 번 생성하면 이를 기반으로 다수의 컨테이너를 생성할 수 있다.
- 목적: 재사용성과 일관성 확보. 동일한 이미지를 어디서든 사용할 수 있도록 설계되었다.
🎯 2. 컨테이너(Container): 실행 환경의 인스턴스
- 컨테이너는 이미지를 기반으로 실행되는 동적 인스턴스이다.
- 실행 중에는 쓰기 가능한 레이어가 추가되어 컨테이너 내부에서 상태가 변경될 수 있다.
(예: 애플리케이션 로그 생성, 파일 추가 등) - 컨테이너는 특정 작업이 끝나거나 삭제되면 해당 상태가 초기화되고 다시 이미지를 기반으로 재생성될 수 있다.
- 목적: 유연성. 하나의 이미지를 바탕으로 다양한 환경에서 독립적으로 실행될 수 있도록 설계되었다.
재사용성: 이미지를 여러 컨테이너에서 재사용하여 효율적으로 실행 환경을 관리.
일관성: 이미지는 불변 상태로 유지되므로 동일한 환경에서 애플리케이션 실행 보장.
유연성: 컨테이너는 이미지에 기반한 독립적인 실행 환경을 제공하므로 다양한 상태와 작업 가능.
효율성: 이미지를 공유하고 빠르게 컨테이너를 생성할 수 있어 개발과 배포 속도 향상.
🔸 3. 도커 파일 (Dockerfile)
도커 파일은 이미지를 생성하기 위한 설정 파일이다.
- 위 그림에서 docker build 명령어는 도커 파일을 읽고 이미지를 생성하는 과정을 나타낸다.
- 도커 파일은 애플리케이션 빌드 과정과 환경을 코드로 관리하며, 반복 가능한 환경 설정이 가능하다.
🔸 4. 도커 허브 (Docker Hub)
도커 허브는 도커 이미지를 저장하고 공유할 수 있는 공식 레지스트리 서비스이다.
- 위 그림의 Registry는 도커 허브에서 이미지를 가져오거나 저장하는 과정을 설명한다.
- 예: $ docker pull nginx 명령어로 Nginx 이미지를 가져와 바로 컨테이너로 실행할 수 있다.
☑️ 도커의 동작 흐름
- 개발자가 도커 파일(Dockerfile)을 작성하고, 이를 기반으로 이미지를 빌드(docker build)한다.
⬇️ - 빌드된 이미지는 도커 허브(Docker Hub) 또는 로컬 저장소에 저장된다.
⬇️ - 이미지를 기반으로 컨테이너가 생성(docker run)되어 애플리케이션이 실행된다.
⬇️ - 필요 시, 도커 허브에서 이미지를 다운로드(docker pull)하여 재사용할 수 있다.
2️⃣ 도커 이미지 관리
도커 이미지는 컨테이너를 실행하는 데 필요한 핵심 요소이다.
아래에서는 도커 이미지 생성, 태그 및 버전 관리, 그리고 도커 허브 사용법을 중심으로 정리하고자 한다.
✅도커 이미지 생성 방법
도커 이미지는 Dockerfile이라는 설정 파일을 통해 생성된다.
Dockerfile은 이미지 빌드에 필요한 명령어를 포함하며, 애플리케이션 환경을 코드로 관리할 수 있다.
자바 프로젝트를 기준으로 예시를 들어보고자 한다.
☑️ 프로젝트 준비
Spring Boot 프로젝트를 빌드하고 실행 가능한 JAR 파일(app.jar)을 생성한다.
Maven 또는 Gradle로 ./target/app.jar 생성.
☑️ Dockerfile 작성
# 1. Base Image 설정
FROM openjdk:17-jdk-slim
# 2. 작업 디렉토리 설정
WORKDIR /app
# 3. JAR 파일 복사
COPY target/app.jar /app/app.jar
# 4. 네트워크 포트 설정
EXPOSE 8080
# 5. 실행 명령어
CMD ["java", "-jar", "app.jar"]
- FROM: 기본 이미지 설정
- openjdk:17-jdk-slim: Java 17 런타임 환경을 제공하는 가벼운 이미지.
- openjdk:17-jdk-slim: Java 17 런타임 환경을 제공하는 가벼운 이미지.
- WORKDIR: 작업 디렉토리 설정
- 이후 모든 명령은 /app 디렉토리를 기준으로 실행된다.
- 이후 모든 명령은 /app 디렉토리를 기준으로 실행된다.
- COPY: 파일/디렉토리 복사
- 로컬 target/app.jar 파일을 컨테이너 내부 /app/app.jar 위치로 복사.
- 로컬 target/app.jar 파일을 컨테이너 내부 /app/app.jar 위치로 복사.
- EXPOSE: 컨테이너가 사용하는 포트 정의
- 컨테이너가 외부와 통신하기 위해 8080 포트를 사용하도록 설정.
- 컨테이너가 외부와 통신하기 위해 8080 포트를 사용하도록 설정.
- CMD: 컨테이너 실행 시 기본으로 실행할 명령어 정의
- Java 애플리케이션 JAR 파일 실행.
☑️ 이미지 빌드
docker build -t my-java-app:1.0 .
- -t : 이미지에 이름(my-java-app)과 태그(1.0) 지정
- . : Dockerfile 위치
✅도커 이미지 관리
태그를 사용해 자바 애플리케이션의 다양한 버전을 관리할 수 있다.
☑️ 태그 지정
docker build -t my-java-app:1.0 .
my-java-app:1.0에서 1.0은 버전을 의미
이미지를 빌드할 때 -t 옵션을 통해 태그를 지정할 수 있다.
☑️ 추가 태그 지정
docker tag my-java-app:1.0 my-java-app:latest
docker tage 명령어를 통해 동일한 이미지에 추가적으로 latest 태그를 부여하여 최신 버전으로 설정할 수 있다.
☑️ 이미지 확인
docker images
docker images 명령어를 통해 생성된 모든 이미지를 확인할 수 있다.
REPOSITORY TAG IMAGE ID CREATED SIZE
my-java-app 1.0 abc123456789 5 minutes ago 200MB
my-java-app latest abc123456789 5 minutes ago 200MB
☑️ 불필요한 태그/이미지 삭제
docker rmi my-java-app:1.0
docker rmi 명령어를 통해 오래된 태크나 이미지를 삭제할 수 있다.
✅도커 허브 사용법
도커 허브를 활용하여 자바 애플리케이션 이미지를 저장하거나 배포할 수 있다.
☑️ 로그인
docker login
도커 허브 계정에 로그인한다.
☑️ 이미지 태그 변경
docker tag my-java-app:1.0 mydockerhubusername/my-java-app:1.0
도커 허브에 업로드할 수 있도록 사용자 이름을 포함한 태그로 변경한다.
☑️ 이미지 푸시
docker push mydockerhubusername/my-java-app:1.0
docker push 명령어를 통해 이미지를 도커 허브에 업로드한다.
☑️ 이미지 다운로드
docker pull mydockerhubusername/my-java-app:1.0
docker pull 명령어를 통해 다른 환경에서 이미지를 다운 받아 실행한다.
☑️ 컨테이너 실행
docker run -d --name my-app-container -p 8080:8080 my-java-app:1.0
- -d: 백그라운드에서 실행.
- --name: 컨테이너 이름 지정.
- -p: 호스트 포트(8080)와 컨테이너 포트(8080) 연결.
docker run 명령어를 통해 생성한 이미지를 기반으로 컨테이너를 실행한다.