Docker는 애플리케이션을 신속하게 구축, 테스트 및 배포할 수 있는 컨테이너 기반의 오픈소스 가상화 플랫폼입니다. 애플리케이션을 해당 환경과 함께 "컨테이너"라는 격리된 공간에 패키징하여, 개발 환경과 운영 환경의 차이로 인해 발생하는 문제를 해결합니다.
### 1.2 이미지(Image)와 컨테이너(Container)
-**이미지(Image)**: 애플리케이션을 실행하는 데 필요한 모든 것(코드, 런타임, 시스템 도구, 라이브러리 등)을 포함하는 읽기 전용 템플릿입니다. 이미지는 계층(Layer)으로 구성되어 있어 효율적인 빌드와 배포가 가능합니다.
-**컨테이너(Container)**: 이미지의 실행 가능한 인스턴스입니다. 하나의 이미지로 여러 개의 독립적인 컨테이너를 생성할 수 있으며, 각 컨테이너는 격리된 환경에서 실행됩니다.
### 1.3 Dockerfile 작성법
`Dockerfile`은 Docker 이미지를 생성하기 위한 지침이 담긴 텍스트 파일입니다. Docker는 이 파일을 읽어 순서대로 명령을 실행하여 이미지를 빌드합니다.
주요 `Dockerfile` 명령어는 다음과 같습니다. ([공식 문서 참고](https://docs.docker.com/reference/dockerfile/))
-`FROM`: 생성할 이미지의 기반이 될 베이스 이미지를 지정합니다. (예: `FROM python:3.9-slim`)
-`WORKDIR`: `RUN`, `CMD`, `ENTRYPOINT`, `COPY`, `ADD` 명령이 실행될 작업 디렉토리를 설정합니다.
-`COPY` 또는 `ADD`: 호스트 머신의 파일이나 디렉토리를 컨테이너 안으로 복사합니다.
-`RUN`: 이미지 빌드 과정에서 필요한 스크립트나 명령을 실행합니다. 주로 애플리케이션 의존성 설치 등에 사용됩니다.
-`CMD` 또는 `ENTRYPOINT`: 컨테이너가 시작될 때 실행될 기본 명령을 설정합니다.
-`EXPOSE`: 컨테이너가 외부에 노출할 포트를 지정합니다.
**Dockerfile 예시 (`Dockerfile` - Spring Boot)**
```dockerfile
# 1단계: Maven을 사용하여 애플리케이션 빌드 (빌드 환경)
FROM maven:3.8-eclipse-temurin-17 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
# 2단계: 빌드된 애플리케이션을 실행 환경으로 복사
FROM eclipse-temurin:17-jre-focal
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
# 컨테이너가 8080번 포트를 외부에 노출
EXPOSE 8080
# 컨테이너 시작 시 JAR 파일 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
```
## 2. Docker Compose 활용
### 2.1 Docker Compose란 무엇인가?
Docker Compose는 여러 개의 컨테이너로 구성된 애플리케이션을 정의하고 실행하기 위한 도구입니다. `docker-compose.yml`이라는 YAML 파일을 사용하여 애플리케이션의 서비스, 네트워크, 볼륨 등을 설정할 수 있습니다. 이를 통해 복잡한 애플리케이션도 단일 명령어로 쉽게 관리할 수 있습니다.
### 2.2 `docker-compose.yml` 작성법
-`version`: 사용할 Docker Compose 파일 형식을 지정합니다. (현재는 `services` 등 최상위 요소만으로 구성 가능)
-`services`: 애플리케이션을 구성하는 각 컨테이너(서비스)를 정의합니다.
-`image`: 서비스의 기반이 될 Docker 이미지를 지정합니다.
-`build`: Docker 이미지를 직접 빌드할 때 `Dockerfile`이 있는 경로를 지정합니다.
-`ports`: `HOST:CONTAINER` 형식으로 호스트와 컨테이너 간의 포트를 매핑합니다.
-`volumes`: `HOST:CONTAINER` 형식으로 호스트와 컨테이너 간의 디렉토리나 파일을 공유(마운트)합니다.
-`environment`: 컨테이너 내에서 사용할 환경 변수를 설정합니다.
-`networks`: 서비스들이 사용할 네트워크를 정의합니다.
-`volumes`: 데이터를 영속적으로 저장하기 위한 볼륨을 정의합니다.
**docker-compose.yml 예시 (`docker-compose.yml` - Spring Boot)**
```yaml
services:
web:
build:.
container_name:my_java_app
ports:
-"8080:8080"
environment:
-SPRING_PROFILES_ACTIVE=development
```
위 예시는 `web` 서비스를 정의합니다.
-`web` 서비스는 현재 디렉토리의 `Dockerfile`을 사용하여 이미지를 빌드하고, 호스트의 8080번 포트를 컨테이너의 8080번 포트와 연결합니다.
-`container_name`으로 컨테이너의 이름을 지정하고, `environment`를 통해 스프링 부트의 `development` 프로파일을 활성화합니다.
## 3. Shell Script를 이용한 배포 자동화
### 3.1 왜 Shell Script를 사용하는가?
애플리케이션을 배포하는 과정은 일반적으로 다음과 같은 반복적인 작업들을 포함합니다.
1. 최신 소스코드 가져오기
2. Docker 이미지 빌드
3. 기존 컨테이너 중지 및 삭제
4. 새로운 컨테이너 실행
5. 불필요한 리소스 정리
이러한 과정들을 Shell Script로 작성해두면, 단일 명령어 실행만으로 전체 배포 과정을 자동화할 수 있어 실수를 줄이고 효율성을 높일 수 있습니다.
### 3.2 배포 스크립트 예시 (`deploy.sh`)
```bash
#!/bin/bash
# 스크립트 실행 중 오류 발생 시 즉시 중단
set-e
echo"배포 스크립트를 시작합니다..."
# 1. 최신 버전의 소스 코드 받기 (main 브랜치 기준)
echo"최신 소스코드를 가져옵니다..."
git pull origin main
# 2. Docker 이미지 빌드 (캐시 사용 안함)
echo"Docker 이미지를 빌드합니다..."
docker-compose build --no-cache
# 3. 기존 컨테이너 중지 및 삭제
echo"기존 컨테이너를 중지하고 삭제합니다..."
docker-compose down
# 4. 새로운 컨테이너 실행 (백그라운드에서 실행)
echo"새로운 컨테이너를 실행합니다..."
docker-compose up -d
# 5. 불필요한 Docker 이미지 정리
echo"불필요한 Docker 이미지를 정리합니다..."
docker image prune -f
echo"배포가 성공적으로 완료되었습니다!"
```
**스크립트 실행 권한 부여:**
스크립트를 실행하기 전에 실행 권한을 부여해야 합니다.
```bash
chmod +x deploy.sh
```
**스크립트 실행:**
```bash
./deploy.sh
```
## 4. 실전 예제: 간단한 Java Spring Boot 웹 애플리케이션 배포
아래는 Java 17과 내장 Tomcat을 사용하는 Spring Boot 웹 애플리케이션을 Docker, Docker Compose, 그리고 배포 스크립트로 배포하는 전체 예제입니다.