[V1] Docker - 100-hours-a-week/KTB4-10th-Cloud GitHub Wiki
- Dockerfile
→ Spring Boot Backend 이미지를 어떻게 만들지 정의
- docker-compose.yml
→ Backend 이미지 + DB 이미지를 EC2에서 어떻게 같이 실행할지 정의
[ 1. Docker File ]
1.1. 작성시 고려사항
-
빌드에는 필요하지만, 최종 컨테이너 이미지에는 필요 없는 환경을 제거할 수 있도록 단계를 2개로 나눠 이미지 만드는 방법
- BUILD PHASE / RUN PHASE
→ 사용이유 : 가벼운 크기의 이미지 사용가능
-
도커 파일의 순서 == 실행 순서
- 도커가 명령어의 결과를 레이어로 저장
- 해당 레이어가 쌓여 도커 이미지를 만듦
- 만약 하단 레이어의 코드가 변경 → 그 이후는 전부 재실행
→ 변경이 없는 것들을 최대한 먼저 실행
-
“도커 레이어 캐시”
- 위에서 부터 실행하며 만들어진 결과를 재사용해서 다음 빌드를 빠르게 하는 기능
-
“캐시 마운트”
https://docs.docker.com/build/cache/optimize/
- 일반적인 도커
- 명령어와 파일이 레이어 구축이후 변경 → 레이어 무효화 및 빌드 과정에서 레이어 재구축
⇒ 캐시마운트 : 빌드 중에 사용할 영구 캐시 위치 지정
- 여러번 읽고 쓰기 가능
- 레이어 재구성시에도 새 패키지나 변경된 패키지만 다운하면 됨
- 일반적인 도커
-
Daemon
- 백그라운드에서 계속 살아있으면서 작업 요청을 기다리는 프로세스
- ex) gradle daemon
- 첫 시행에서 gradle 프로세스 띄우고 종료하지않고 백그라운드에 유지 (빌드 속도에 도움)
- 빌드에서 no daemon이유
- jar만들고 끝내는 일회성 작업에 계속 띄워둘 필요가 없음
-
사용자
- 별다른 설정이 없으면 도커파일 → root 권한 실행의 가능성
- 만약 컨테이너 탈취되면 호스트에 접근이 되는 보안 취약점
⇒ 실행권한 최소화가 필요
--system : 일반 사용자용 그룹X, 애플리케이션, 서비스 실행용 시스템 그룹 useradd --system --gid spring spring -> spring이라는 그룹의 spring이라는 사람 - 별다른 설정이 없으면 도커파일 → root 권한 실행의 가능성
1.2. 도커 파일
# 1. Build(멀티스테이지 빌드)
# 빌드를 위해 도구 모음 jdk 제공
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /app
COPY gradlew .
COPY gradle gradle
COPY build.gradle.kts .
COPY settings.gradle.kts .
#의존성을 먼저 다운로드
# cache mount를 이용해 Gradle 캐시를 빌드 간 재사용
RUN --mount=type=cache,target=/root/.gradle \
./gradlew dependencies --no-daemon
COPY src src
#jar생성도 cache mount
RUN --mount=type=cache,target=/root/.gradle \
./gradlew bootJar --no-daemon
# 2. Run
# 자바 21 환경 jre 제공
FROM eclipse-temurin:21-jre
WORKDIR /app
# 애플리케이션 실행용 Non-root 사용자/그룹 생성
RUN groupadd --system kgb \
&& useradd --system --gid kgb kgbUser
#위의 빌드단계에서 생성된 jar만 복사
#jar의 소유권도 지정
COPY --from=builder --chown=kgbUser:kgb /app/build/libs/*.jar app.jar
#사용자 지정
USER kgbUser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
[ 2. Docker Compose ]
- 고려사항 (변경할 사항)
- 현재 환경변수는 백엔드 env.example 기반
- 배포 DB 생성 이후 password 추가 필요
- 실제 구성되는 백엔드에 따라 환경도 추가하거나 삭제가 필요
- ai
- 도커 컴포즈
- 여러개의 도커 컨테이너를 하나의 파일로 정의하고 동시에 실행 및 관리할 수 있는 도구
- 고려사항
-
로컬에서 도커파일 이용해 직접 빌드하는 방식은 제외
→ GHCR에서 이미지 pull 해옴
→ 이미지 태그는 CD 단계에서 주입
- ci-cd 하나의 yaml 사용으로 못찾는 문제 방지
-
services:
backend:
# CI에서 GHCR에 Push한 Backend 이미지 사용
# GHCR_OWNER, IMAGE_TAG는 CD에서 동적으로 전달
image: ghcr.io/${GHCR_OWNER}/ktb4-10-be:${IMAGE_TAG}
# Host -> Backend Container
ports:
- "8080:8080"
environment:
# Docker 내부에서 db 접근(컴포즈 서비스명 사용)
DB_URL: jdbc:mysql://db:3306/kgb
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
# S3
S3_BUCKET_NAME: kgb-s3-storage
AWS_REGION: ap-northeast-2
# AI
AI_SERVER_URL: ${AI_SERVER_URL}
# MySQL 상태가 확인 후 Backend 시작
depends_on:
db:
condition: service_healthy
# Container 비정상 종료 또는 EC2 재부팅 시 자동 재시작
restart: unless-stopped
db:
image: mysql:8.4
environment:
# 최초 DB 생성 시 생성할 Database
MYSQL_DATABASE: kgb
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
# DB 데이터를 Container와 분리하여 영속화
volumes:
- db-data:/var/lib/mysql
# MySQL이 실제 연결 가능한 상태인지 확인
healthcheck:
test:
[
"CMD-SHELL",
"mysqladmin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD"
]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
# Container 비정상 종료 또는 EC2 재부팅 시 자동 재시작
restart: unless-stopped
# DB Container가 삭제/재생성되어도 DB 데이터 유지
volumes:
db-data: