Docker Vibe Coding 가이드
Docker로 Vibe Coding을 활용하는 방법을 배웁니다. 컨테이너화 표준 도구를 AI로 구현해보세요.
개요
Docker는 애플리케이션을 컨테이너로 패키징하고 실행할 수 있는 플랫폼입니다. 일관된 환경, 빠른 배포, 리소스 격리가 장점입니다. 2013년 Solomon Hykes가 공개한 이래, Docker는 소프트웨어 배포와 개발 환경 구성의 표준으로 자리 잡았으며, OCI(Open Container Initiative) 표준의 기반이 되었습니다.
- 일관된 환경: 개발/운영 동일
- 빠른 배포: 컨테이너 순식간에 실행
- 리소스 격리: 프로세스 격리
- 이식성: 어디서나 실행
- Docker Compose: 멀티 컨테이너
- 레이어 캐싱: 변경된 부분만 다시 빌드하여 속도 극대화
- 버전 관리: 이미지 태그로 롤백 및 배포 이력 관리
적합한 상황
- 개발 환경 구축 - 팀 전체가 동일한 환경에서 작업
- CI/CD 파이프라인 - 빌드, 테스트, 배포 자동화
- 마이크로서비스 - 서비스별 독립 배포 및 스케일링
- 클라우드 배포 - AWS ECS, GKE, Azure Container Instances
- 로컬 데이터베이스 및 서비스 실행 - Redis, PostgreSQL, MongoDB 등 즉시 실행
컨테이너 vs VM
| 특성 | 컨테이너 | VM |
|---|---|---|
| 부팅 시간 | 초 단위 | 분 단위 |
| 크기 | MB 단위 | GB 단위 |
| 격리 수준 | 프로세스 (namespace/cgroup) | 하드웨어 (하이퍼바이저) |
| 오버헤드 | 낮음 | 높음 |
| 커널 공유 | 호스트 커널 공유 | 독립 커널 |
| 밀도 | 수십~수백 개 동시 실행 | 수 개~수십 개 |
이미지 레이어 구조
Docker 이미지는 여러 개의 읽기 전용 레이어로 구성됩니다. Dockerfile의 각 명령어(FROM, RUN, COPY 등)가 하나의 레이어를 생성하며,
컨테이너 실행 시 최상단에 쓰기 가능한 레이어가 추가됩니다. 이 구조 덕분에 여러 컨테이너가 동일한 베이스 레이어를 공유하여 디스크 공간을 절약합니다.
Docker 이미지 레이어 구조 - 읽기 전용 이미지 레이어를 여러 컨테이너가 공유하고, 각 컨테이너는 독립적인 쓰기 가능 레이어를 가짐 (Copy-on-Write)
컨테이너가 이미지 레이어의 파일을 수정하면, 해당 파일이 쓰기 가능 레이어로 복사된 후 수정됩니다. 원본 이미지 레이어는 변경되지 않으므로, 다른 컨테이너에 영향을 주지 않습니다. 이 방식을 Copy-on-Write (CoW)라고 하며, 스토리지 효율성의 핵심입니다.
Dockerfile
이미지를 만들기 위한 설정 파일입니다. 각 명령어가 하나의 레이어를 생성하므로, 효율적인 레이어 구성이 빌드 성능과 이미지 크기에 직접 영향을 줍니다.
Dockerfile 예시
# Node.js 앱
FROM node:20-alpine
WORKDIR /app
# 패키지 설치 (레이어 캐싱 활용)
COPY package*.json ./
RUN npm ci --only=production
# 소스 복사
COPY . .
# 포트 노출
EXPOSE 3000
# 실행
CMD ["node", "server.js"]
Multi-stage Build
빌드 환경과 런타임 환경을 분리하여 최종 이미지 크기를 대폭 줄입니다. 빌드 도구, 소스 코드, 개발 의존성은 최종 이미지에 포함되지 않습니다.
# 빌드 스테이지
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 런타임 스테이지
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/server.js"]
Multi-stage Build 고급 패턴
Go나 Rust처럼 정적 바이너리를 생성하는 언어에서는 최종 이미지를 scratch 또는 distroless로 구성하여 극한의 경량화가 가능합니다.
# Go 앱 Multi-stage (최종 이미지 ~10MB)
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app/server ./cmd/server
# scratch: 완전 빈 이미지 (쉘 없음, 디버깅 불가)
FROM scratch
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]
.dockerignore
불필요한 파일을 빌드 컨텍스트에서 제외하여 빌드 속도를 높이고 이미지 크기를 줄입니다.
node_modules
npm-debug.log
.git
.gitignore
README.md
Dockerfile
docker-compose.yml
.env
*.md
tests/
coverage/
.vscode/
.idea/
dist/
*.log
이미지 빌드 최적화
프로덕션 환경에서 Docker 이미지의 크기와 빌드 속도는 배포 효율에 직접적인 영향을 줍니다. 다음 전략들을 조합하면 빌드 시간과 이미지 크기를 크게 줄일 수 있습니다.
레이어 캐싱 전략
Docker는 각 레이어를 캐시하며, 이전 레이어가 변경되면 이후 모든 레이어를 재빌드합니다. 따라서 변경 빈도가 낮은 명령어를 위에 배치하는 것이 핵심입니다.
# 잘못된 순서: 소스 변경마다 npm ci 재실행
COPY . .
RUN npm ci # 매번 재실행됨
# 올바른 순서: 의존성 파일만 먼저 복사
COPY package*.json ./
RUN npm ci # package.json 변경 시에만 재실행
COPY . . # 소스 변경은 이 레이어만 영향
경량 베이스 이미지
베이스 이미지 선택은 최종 이미지 크기에 결정적 영향을 줍니다.
| 이미지 | 크기 | 특징 | 권장 용도 |
|---|---|---|---|
node:20 |
~1.1GB | Debian 기반, 전체 도구 포함 | 개발/디버깅 |
node:20-slim |
~250MB | Debian 최소 설치 | 일반 프로덕션 |
node:20-alpine |
~180MB | Alpine Linux 기반, musl libc | 경량 프로덕션 |
gcr.io/distroless/nodejs20 |
~130MB | 쉘 없음, Node.js만 포함 | 보안 중시 프로덕션 |
Alpine은 musl libc를 사용하므로 glibc 의존 네이티브 모듈(예: bcrypt, sharp)에서
호환성 문제가 발생할 수 있습니다. 이 경우 -slim 이미지를 사용하거나, Alpine에서 빌드 도구를 설치하세요:
RUN apk add --no-cache python3 make g++
레이어 수 줄이기
여러 RUN 명령어를 &&로 결합하면 레이어 수를 줄이고, 중간 파일이 최종 레이어에 남지 않습니다.
# 비효율: 3개 레이어, 캐시 파일 잔존
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# 효율: 1개 레이어, 캐시 파일 제거됨
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
기본 명령어
자주 사용하는 Docker 명령어입니다.
명령어 예시
# 이미지 빌드
docker build -t myapp:latest .
# 컨테이너 실행
docker run -d -p 3000:3000 --name myapp myapp:latest
# 실행 중인 컨테이너 확인
docker ps
# 로그 확인
docker logs myapp
# 컨테이너 중지/삭제
docker stop myapp
docker rm myapp
# 이미지 목록
docker images
# 사용하지 않는 리소스 정리
docker system prune -a --volumes
볼륨 전략
Docker 컨테이너는 기본적으로 상태를 유지하지 않습니다(stateless). 컨테이너를 삭제하면 내부 데이터도 사라집니다. 영속적인 데이터를 관리하려면 볼륨(Volume)을 사용해야 합니다.
볼륨 유형 비교
| 유형 | 명령어 예시 | 특징 | 사용 사례 |
|---|---|---|---|
| Named Volume | -v pgdata:/var/lib/postgresql/data |
Docker가 관리, 호스트 경로 무관 | 데이터베이스, 영속 데이터 |
| Bind Mount | -v $(pwd)/src:/app/src |
호스트 디렉토리 직접 마운트 | 개발 환경 소스 코드 |
| tmpfs | --tmpfs /tmp:rw,size=64m |
메모리에만 저장, 컨테이너 종료 시 사라짐 | 임시 파일, 세션 데이터 |
| Anonymous Volume | -v /app/node_modules |
자동 생성, 참조 어려움 | 빌드 캐시 (비권장) |
볼륨 관리 명령어
# Named Volume 생성
docker volume create mydata
# Named Volume으로 컨테이너 실행
docker run -d -v mydata:/data --name mydb postgres:15-alpine
# Bind Mount로 개발 환경 구성
docker run -d \
-v $(pwd)/src:/app/src:ro \
-v $(pwd)/config:/app/config:ro \
-v nodemodules:/app/node_modules \
-p 3000:3000 myapp:dev
# 볼륨 목록 확인
docker volume ls
# 볼륨 상세 정보
docker volume inspect mydata
# 사용하지 않는 볼륨 정리
docker volume prune
개발 시 소스 코드는 Bind Mount로, node_modules는 Named Volume으로 분리하면
호스트와 컨테이너 간 의존성 충돌을 방지하면서 실시간 코드 변경 반영(Hot Reload)이 가능합니다.
Docker 네트워크
Docker는 컨테이너 간 통신과 외부 네트워크 연결을 위한 여러 네트워크 드라이버를 제공합니다.
기본 bridge 네트워크 외에도 host, overlay, macvlan, none 모드를 지원합니다.
Docker Bridge 네트워크 구조 - 외부 트래픽이 호스트 포트 매핑을 통해 컨테이너에 도달하고, 컨테이너 간에는 브리지 네트워크를 통해 통신
네트워크 모드 상세
| 모드 | 명령어 | 격리 | 성능 | 사용 사례 |
|---|---|---|---|---|
| bridge (기본) | --network bridge |
높음 | 약간의 오버헤드 | 일반적인 컨테이너 실행 |
| host | --network host |
없음 (호스트 공유) | 네이티브 성능 | 고성능 네트워크 요구 |
| overlay | --network overlay |
높음 | 약간의 오버헤드 | 멀티 호스트 (Swarm/K8s) |
| macvlan | --network macvlan |
높음 | 네이티브에 가까움 | 물리 네트워크 직접 연결 |
| none | --network none |
완전 격리 | - | 네트워크 불필요한 배치 작업 |
사용자 정의 네트워크
사용자 정의 브리지 네트워크는 기본 브리지보다 많은 장점을 제공합니다: 자동 DNS 해석, 더 나은 격리, 동적 연결/해제 등.
# 사용자 정의 네트워크 생성
docker network create --driver bridge myapp-network
# 네트워크에 컨테이너 연결
docker run -d --name api --network myapp-network myapi:latest
docker run -d --name db --network myapp-network postgres:15-alpine
# 컨테이너 간 통신 (DNS 자동 해석)
# api 컨테이너에서 "db" 호스트명으로 접속 가능
docker exec api ping db
# 네트워크 목록
docker network ls
# 네트워크 상세 정보
docker network inspect myapp-network
Docker Compose
멀티 컨테이너 애플리케이션을 YAML 파일 하나로 정의하고 관리합니다. 서비스 간 의존성, 네트워크, 볼륨을 선언적으로 구성할 수 있습니다.
docker-compose.yml
services:
app:
build: .
ports:
- "3000:3000"
depends_on:
- db
environment:
- DATABASE_URL=postgresql://db:5432/mydb
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=dev
- POSTGRES_PASSWORD=dev
- POSTGRES_DB=mydb
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Compose 명령어
# 서비스 시작
docker-compose up -d
# 서비스 중지
docker-compose down
# 볼륨까지 함께 삭제
docker-compose down -v
# 로그 확인
docker-compose logs -f
# 특정 서비스만 실행
docker-compose up db
# 서비스 재빌드
docker-compose up --build -d
Health Check
컨테이너 상태를 주기적으로 확인하여 서비스의 정상 동작을 보장합니다.
services:
app:
image: node:20
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 10s
timeout: 5s
retries: 5
서비스 의존성 관리
depends_on에 condition을 지정하면 단순 시작 순서가 아니라, 의존 서비스가 실제로 준비될 때까지 대기할 수 있습니다.
services:
app:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:15-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 5s
timeout: 3s
retries: 10
redis:
image: redis:7-alpine
Compose Profiles
프로파일을 사용하면 환경에 따라 실행할 서비스를 선택적으로 제어할 수 있습니다.
services:
app:
build: .
ports:
- "3000:3000"
db:
image: postgres:15-alpine
adminer:
image: adminer
ports:
- "8080:8080"
profiles:
- debug
prometheus:
image: prom/prometheus
profiles:
- monitoring
grafana:
image: grafana/grafana
profiles:
- monitoring
# 기본 서비스만 실행 (app, db)
docker-compose up -d
# debug 프로파일 포함 실행
docker-compose --profile debug up -d
# 모니터링 포함 실행
docker-compose --profile monitoring up -d
Compose Secrets
민감한 정보를 환경 변수 대신 Docker Secrets로 안전하게 전달합니다.
services:
db:
image: postgres:15-alpine
secrets:
- db_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
app:
build: .
secrets:
- db_password
- api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt
docker inspect로 컨테이너의 환경 변수를 확인할 수 있으므로, 비밀번호나 API 키를 환경 변수에 직접 넣는 것은 위험합니다.
프로덕션에서는 Docker Secrets, HashiCorp Vault, AWS Secrets Manager 등을 사용하세요.
Node.js + DB 예시
Node.js 앱과 PostgreSQL을 함께 실행하는 완전한 예시입니다.
전체 예시
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: always
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
restart: always
redis:
image: redis:7-alpine
restart: always
volumes:
pgdata:
보안 모범 사례
Docker 컨테이너는 기본적으로 root 사용자로 실행됩니다. 프로덕션 환경에서는 보안 강화를 위해 여러 조치를 취해야 합니다.
Non-root 사용자 실행
컨테이너 탈출(container escape) 취약점이 발생하더라도 피해를 최소화하려면 비root 사용자로 실행해야 합니다.
FROM node:20-alpine
# 전용 사용자 생성
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup package*.json ./
RUN npm ci --only=production
COPY --chown=appuser:appgroup . .
# 비root 사용자로 전환
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]
읽기 전용 파일 시스템
컨테이너 파일 시스템을 읽기 전용으로 마운트하면, 악성 코드가 파일을 생성하거나 수정하는 것을 방지할 수 있습니다.
# 읽기 전용 파일 시스템 + tmpfs로 필요한 쓰기 영역만 허용
docker run -d \
--read-only \
--tmpfs /tmp:rw,size=64m \
--tmpfs /var/run:rw \
-p 3000:3000 \
myapp:latest
리소스 제한
CPU와 메모리 제한을 설정하여 단일 컨테이너가 호스트 전체 리소스를 소진하는 것을 방지합니다.
services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: '0.5' # CPU 50% 제한
memory: 512M # 메모리 512MB 제한
reservations:
cpus: '0.25' # 최소 CPU 보장
memory: 256M # 최소 메모리 보장
이미지 보안 스캐닝
이미지에 알려진 취약점(CVE)이 포함되어 있는지 빌드 단계에서 스캔하세요.
# Docker Scout (Docker Desktop 내장)
docker scout cves myapp:latest
# Trivy (오픈소스 스캐너)
trivy image myapp:latest
# Snyk
snyk container test myapp:latest
# CI/CD에서 취약점 발견 시 빌드 실패
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest
- 최신 베이스 이미지 유지 (
docker pull로 주기적 업데이트) - 불필요한 패키지 미설치 (
--no-install-recommends) COPY대신ADD사용 자제 (URL 다운로드 방지)--cap-drop ALL로 Linux capabilities 제거 후 필요한 것만 추가.dockerignore에.env,.git, 인증서 파일 포함
디버깅
컨테이너 문제 해결을 위한 핵심 명령어들입니다.
로그 확인
# 실시간 로그 스트리밍
docker logs -f myapp
# 최근 100줄만 확인
docker logs --tail 100 myapp
# 타임스탬프 포함
docker logs -t myapp
# 특정 시간 이후 로그
docker logs --since 2h myapp
# Compose에서 특정 서비스 로그
docker-compose logs -f app
컨테이너 접속
# 실행 중인 컨테이너에 쉘 접속
docker exec -it myapp /bin/sh
# 특정 명령어 실행
docker exec myapp cat /app/config.json
# 환경 변수 확인
docker exec myapp env
# 네트워크 상태 확인
docker exec myapp netstat -tlnp
상세 정보 확인
# 컨테이너 상세 정보 (JSON)
docker inspect myapp
# IP 주소만 추출
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
# 마운트된 볼륨 확인
docker inspect -f '{{json .Mounts}}' myapp | python3 -m json.tool
# 실시간 리소스 사용량 모니터링
docker stats
# 특정 컨테이너 리소스 확인
docker stats myapp --no-stream
# 컨테이너 프로세스 확인
docker top myapp
# 파일 시스템 변경 사항 확인
docker diff myapp
문제 해결 시 권장 순서: 1) docker ps -a로 상태 확인 →
2) docker logs로 에러 로그 확인 →
3) docker inspect로 설정 검증 →
4) docker exec로 내부 진입하여 상세 조사 →
5) docker stats로 리소스 문제 확인
프로덕션 배포 팁
개발 환경에서 잘 동작하던 컨테이너도 프로덕션에서는 추가적인 설정이 필요합니다.
재시작 정책
| 정책 | 설명 | 사용 사례 |
|---|---|---|
no |
재시작 안 함 (기본값) | 일회성 작업 |
on-failure[:max] |
비정상 종료 시 재시작 (횟수 제한 가능) | 배치 작업 |
always |
항상 재시작 (수동 중지 제외) | 일반 서비스 |
unless-stopped |
수동 중지 전까지 항상 재시작 | 프로덕션 서비스 |
로깅 드라이버
프로덕션에서는 컨테이너 로그를 중앙 로그 시스템으로 전송해야 합니다.
services:
app:
image: myapp:latest
logging:
driver: "json-file"
options:
max-size: "10m" # 로그 파일 최대 크기
max-file: "3" # 로그 파일 최대 개수
compress: "true" # 로테이션된 로그 압축
json-file 드라이버는 기본적으로 로그 크기 제한이 없습니다. 로그가 무한히 쌓이면 디스크 공간이 소진되어
호스트 전체가 중단될 수 있습니다. 반드시 max-size와 max-file을 설정하세요.
프로덕션 Compose 예시
services:
app:
image: myapp:1.2.3 # 명시적 태그 (latest 금지)
ports:
- "3000:3000"
restart: unless-stopped
read_only: true
tmpfs:
- /tmp:rw,size=64m
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
depends_on:
db:
condition: service_healthy
db:
image: postgres:15-alpine
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
memory: 1G
secrets:
- db_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
pgdata:
secrets:
db_password:
file: ./secrets/db_password.txt
Docker vs Podman 비교
Podman은 Red Hat이 개발한 Docker 호환 컨테이너 런타임입니다. 데몬리스 아키텍처와 기본 rootless 실행이 특징이며, Docker CLI와 거의 동일한 명령어를 사용합니다.
| 특성 | Docker | Podman |
|---|---|---|
| 아키텍처 | 데몬 기반 (dockerd) | 데몬리스 (fork/exec) |
| 기본 실행 권한 | root (rootless 가능) | rootless (기본) |
| Compose 지원 | Docker Compose (네이티브) | podman-compose / docker-compose 호환 |
| Kubernetes 통합 | 별도 도구 필요 | podman generate kube 내장 |
| OCI 호환 | 지원 | 지원 |
| Systemd 통합 | 제한적 | podman generate systemd 내장 |
| 이미지 호환 | Docker Hub 기본 | Docker Hub 호환 + 다중 레지스트리 |
| Windows/macOS | Docker Desktop | Podman Desktop |
| 라이선스 | 기업용 유료 (250인 이상) | Apache 2.0 (완전 무료) |
# Docker와 Podman 명령어 비교 (거의 동일)
docker run -d -p 8080:80 nginx # Docker
podman run -d -p 8080:80 nginx # Podman
# alias 설정으로 전환
alias docker=podman
- Docker 추천: Docker Desktop 생태계가 필요하거나, 기존 Docker 기반 CI/CD가 구축된 경우
- Podman 추천: 보안이 중요한 엔터프라이즈 환경, RHEL/CentOS 기반 시스템, 데몬 없는 아키텍처 선호 시
- 두 도구 모두 OCI 호환이므로 빌드한 이미지는 서로 교환 가능
모범 사례 요약
- Multi-stage Build: 빌드 결과물만 포함하여 이미지 크기 최소화
- .dockerignore: 불필요 파일 제외로 빌드 컨텍스트 경량화
- 명시적 태그: 버전 명시 (
latest피하기,myapp:1.2.3사용) - 시크릿 관리: Docker Secrets 또는 외부 비밀 관리 시스템 사용
- Non-root 사용자:
USER명령어로 비root 실행 - Healthcheck: 모든 서비스에 상태 확인 설정
- 리소스 제한: CPU/메모리 limits 필수 설정
- 로그 관리: 로그 크기 제한 및 중앙 로깅 시스템 연동
- 보안 스캐닝: CI/CD 파이프라인에 이미지 취약점 스캔 포함
- 레이어 최적화: 변경 빈도 기준 Dockerfile 명령어 정렬
AI 도구(Claude, ChatGPT 등)에게 Docker 관련 작업을 요청할 때는 다음 정보를 함께 제공하세요: 1) 사용 언어/프레임워크, 2) 필요한 서비스(DB, 캐시 등), 3) 개발/프로덕션 용도 구분. 이 세 가지만 명확히 하면 AI가 최적의 Dockerfile과 Compose 설정을 생성해줍니다.