1. 수동으로 docker 컨테이너 실행의 불편함 개선
앱을 실행하기 전 mysql, redis, redis-test 컨테이너를 직접 켜줘야했는데 아무래도 cmd 창에 직접 입력하는 게 좀 번거롭다고 생각하였다.
Docker Compose를 활용하면 한 번에 실행하고 종료할 수 있는데 예전에 CICD 도커에서 띄울 때 잠깐 사용하다 말았어서 정리 후 적용해보려고 한다.
Docker Compose는 단일 서버에서 여러 개의 컨테이너를 하나의 서비스로 정의해서 묶음으로 관리할 수 있는 작업 환경을 제공하는 관리 도구이다.
도커 컴포즈는 여러 개의 컨테이너의 옵션과 환경을 정의한 파일을 읽어 컨텥이너를 순차적으로 생성하는 방식으로 동작한다.
Docker Desktop을 사용하고 있어서 Docker Compose를 설치할 필요는 없지만 필요한 사람들을 위해 설치 명령어를 아래에 적어놓았다.
// Linux
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
// Window
https://www.docker.com/products/docker-desktop/
docker-compose.yml을 작성해야하는데 docker-compose 명령어를 보다보니 docker 켜는거나 docker-compose 켜는 거나 명령어 입력은 똑같다는 생각이 들지만 나중에 정말 컨테이너들을 왕창 띄운다면 유용할 거니까 둘 다 익숙해져야 한다.
docker-compose.yml
version: "3.8"
services:
mysql-container:
image: mysql:8.0
container_name: mysql-container
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
redis-container:
image: redis:latest
container_name: redis-container
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
mysql_data:
redis_data:
docker-compose.test.yml
version: "3.8"
services:
redis-test-container:
image: redis:latest
container_name: redis-test-container
restart: unless-stopped
ports:
- "6380:6379"
volumes:
- redis_test_data:/data
volumes:
redis_test_data:
docker-compose에서는 mySQL을 띄워주고 init_database에서 fortune-app과 fortune-app-test DB 둘 다 생성하도록 하였다.
redis는 yml를 분리해서 컨테이너를 생성하였다.
환경 변수를 따로 .env에 분리하였고 .gitignore에 추가하는 것을 잊지 말자.
2. Docker-Compose(도커 컴포즈) 실행 및 중지 명령어
Docker-Compose 명령어는 아래와 같다.
# 운영 환경과 테스트 환경 실행
docker-compose up -d
docker-compose -f docker-compose.test.yml up -d
docker ps
# 운영 환경과 테스트 환경 삭제
docker-compose down
docker stop redis-test-container && docker rm redis-test-container
3. 도커 기본 명령어와 도커 파일 작성법
도커는 컨테이너 기반의 가상화 플랫폼으로 애플리케이션을 OS에 독립적으로 패키징하여 실행할 수 있게 한다.
이미지는 컨테이너 실행을 위한 파일 시스템과 애플리케이션 설정이 포함된 패키지이고 컨테이너는 도커 이미지로부터 실행된 인스턴스다.
기본적인 컨테이너 및 이미지 관련 도커 명령어는 아래와 같다.
1. 실행 중인 컨테이너 목록 조회
docker ps
2. 중지된 컨테이너 포함 모든 컨테이너 목록 조회
docker ps -a
3. 로컬에 저장된 이미지 목록 조회
docker images
4. 컨테이너 실행
docker run [옵션] 이미지명
5. 컨테이너 중지
docker stop 컨테이너_ID
6. 컨테이너 삭제
docker rm 컨테이너_ID
7. 도커 이미지 삭제
docker rmi 이미지_ID
8. 실행 중인 컨테이너 접속
docker exec -it 컨테이너_ID /bin/bash
9. 컨테이너 로그 확인
docker logs 컨테이너_ID
Dockerfile 빌드 및 실행 명령어는 아래와 같다.
1. 현재 디렉토리의 Dockerfile을 기반으로 도커 이미지 생성
docker build -t 이미지명 .
2. 컨테이너를 백그라운드에 실행하고 포트 매핑
docker run -d -p 8080:80 이미지명
3. 특정 이름을 가진 컨테이너 실행 후 접속
docker run --name 컨테이너명 -it 이미지명 /bin/bash
4. docker-compose.yml 기반으로 여러 개 컨테이너 실행
docker-compose up -d
Dockerfile은 컨테이너를 생성하는 설정 파일로 애플리케이션 실행 환경을 정의하며 작성법은 아래와 같다.
// 1. 베이스 이미지 설정
FROM openjdk:17
// 2. 작업 디렉토리 설정
WORKDIR /app
// 3. 애플리케이션 실행 파일 복사
COPY ./target/app.jar app.jar
// 4. 컨테이너에서 실행할 명령어
CMD ["java", "-jar", "app.jar"]
Dockerfile의 주요 명령어는 아래와 같다.
FROM // 베이스 이미지 지정 ex) ubuntu, node, openjdk
WORKDIR // 컨테이너 내부에서 작업 디렉토리 설정
COPY // 호스트의 파일을 컨테이너로 복사
RUN // 컨테이너 생성 시 실행할 명령어
CMD // 컨테이너 실행 시 기본적으로 실행될 명령어(1개만 존재 가능)
ENTRYPOINT // CMD와 유사하지만 실행 시 옵션 추가 가능
EXPOSE // 컨테이너가 사용할 포트 지정
ENV // 환경 변수 설정
VOLUME // 데이터 저장소 설정
ARG // 빌드 시 전달할 변수 설정
그래서 내 프로젝트에서 작성한 DockerFile은 간단하다.
FROM openjdk:17
WORKDIR /app
COPY build/libs/fortune-app-backend-0.0.1-SNAPSHOT.jar app.jar
CMD ["java", "-jar", "app.jar"]
app 디렉토리에서 빌드한 앱 jar를 실행 시키는데 Docker-Compose.yml에 fortune-app도 띄워주도록 하였다.
services:
mysql-container:
image: mysql:8.0
container_name: mysql-container
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
redis-container:
image: redis:latest
container_name: redis-container
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
fortune-app:
build: .
container_name: fortune-app
restart: unless-stopped
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql-container:3306/${MYSQL_DATABASE}
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: ${MYSQL_ROOT_PASSWORD}
SPRING_REDIS_HOST: redis-container
SPRING_REDIS_PORT: 6379
depends_on:
- mysql-container
- redis-container
volumes:
mysql_data:
redis_data:
아이디 root에 비밀번호 root인데 나중에 운영할 때는 꼭 바꾸자.
이제는 아래 명령어로 간단하게 다 띄울 수 있다. 도커와 도커 컴포즈 최고..
위에랑 같지 않냐고 묻는다면 그냥 설정 바꿔서 spring boot도 띄우게 추가해서 명령어는 같다.
# 운영 환경과 테스트 환경 실행
docker-compose up -d
docker-compose -f docker-compose.test.yml up -d
docker ps
# 운영 환경과 테스트 환경 삭제
docker-compose down
docker stop redis-test-container && docker rm redis-test-container
4. JWT vs 세션 기반 인증
JWT는 마이크로서비스 아키텍처 환경(여러 개의 서비스가 분리된 경우), SPA(React/Vue 등), 서버 부하를 줄이고 싶거나 OAuth2 로그인과 연동해야 하는 경우 주로 사용한다.
각 서비스가 서로 독립적으로 운영되면 세션 공유가 어렵고 JWT를 사용하면 편리하다.
또한 백엔드와 프론트엔드가 분리된 경우 세션을 유지하기 어려우므로 JWT를 API 요청 헤더에 포함하여 인증하는 방식이 적합하며 JWT는 stateless 인증 방식이므로 서버가 세션을 관리할 필요가 없다.
다만 토큰을 쉽게 만료시키기 어렵고 토큰이 길고 매 요청마다 포함해야 해서 네트워크 트래픽이 증가할 수 있다.
보안 이슈 또한 존재해서 Refresh Token을 함께 사용해야 한다.
세션 기반 인증은 전통적인 웹 어플리케이션(Spring MVC + Thymeleaf 등)과 보안이 중요한 서비스(은행, 금융), 서버에서 인증 상태를 직접 관리해야 하는 경우 많이 사용한다.
로그인 후 JSESSIONID 쿠키를 사용하여 인증을 유지하는데 서버 부담이 증가할 수도 있고 분산 서버 환경에서는 세션 공유를 위한 Redis 같은 세션 저장소가 필요하다.
'dev > 프로젝트' 카테고리의 다른 글
[프로젝트] CICD (Github Actions, EC2, Docker, Putty, SSH) 적용 (9) | 2025.01.23 |
---|---|
[프로젝트] CICD (6) | 2025.01.23 |
[프로젝트] On-Premise & Cloud (16) | 2025.01.21 |
[프로젝트] Redis & OAuth2 적용 (6) | 2025.01.21 |
[프로젝트] Custom Exception & Redis (6) | 2025.01.19 |