Docker Next.js 로컬 배포 스킬
목적
이 스킬은 버전 태그가 지정된 이미지를 사용하여 Next.js 애플리케이션을 Docker로 빌드하고 실행하는 데 사용합니다.
이 스킬은 프로젝트 이름을 하드코딩하지 않아야 합니다. 사용자가 특정 이름을 제공하지 않는 한, 현재 저장소에서 이미지 이름을 추론합니다.
프로젝트 이름 확인
빌드 전에 다음 값을 결정합니다:
PROJECT_NAME=<확인된 프로젝트 이름>
IMAGE_NAME=<확인된 이미지 이름>
IMAGE_VERSION=<확인된 버전>
IMAGE_TAG=${IMAGE_NAME}:${IMAGE_VERSION}
CONTAINER_NAME=<확인된 컨테이너 이름>
ENV_FILE=<확인된 환경 변수 파일>
HOST_PORT=<확인된 호스트 포트>
CONTAINER_PORT=<확인된 컨테이너 포트>
확인 규칙:
-
사용자가 이미지 이름을 제공하면 그 이름을 사용합니다.
-
그렇지 않으면
package.json을 읽고name필드를 사용합니다. -
package.json에name이 없으면 현재 폴더 이름을 사용합니다. -
이미지 이름을 정규화합니다:
- 소문자로 변환
- 공백과 밑줄을 하이픈으로 대체
- 유효하지 않은 Docker 이미지 이름 문자 제거
-
사용자가 버전을 제공하면 그 버전을 사용합니다.
-
그렇지 않으면 기본값
1.0.0을 사용합니다. -
사용자가 컨테이너 이름을 제공하면 그 이름을 사용합니다.
-
그렇지 않으면 정규화된 이미지 이름을 컨테이너 이름으로 사용합니다.
-
사용자가 환경 변수 파일을 제공하면 그 파일을 사용합니다.
-
그렇지 않으면 기본값
.env.production을 사용합니다. -
사용자가 포트를 제공하면 그 포트를 사용합니다.
-
그렇지 않으면 기본값으로
HOST_PORT=4000및CONTAINER_PORT=3000을 사용합니다.
예시:
package.json name: nextjs-skill-app-workshop
PROJECT_NAME=nextjs-skill-app-workshop
IMAGE_NAME=nextjs-skill-app-workshop
IMAGE_VERSION=1.0.0
IMAGE_TAG=nextjs-skill-app-workshop:1.0.0
CONTAINER_NAME=nextjs-skill-app-workshop
ENV_FILE=.env.production
HOST_PORT=4000
CONTAINER_PORT=3000
안전 규칙
빌드 또는 실행 명령을 실행하기 전에:
-
현재 작업 디렉토리가 프로젝트 루트인지 확인합니다.
-
Dockerfile이 존재하는지 확인합니다. -
환경 변수 파일이 존재하는지 확인합니다.
-
Docker가 설치되어 실행 중인지 확인합니다.
-
요청된 이미지 태그가 이미 로컬에 존재하는지 확인합니다.
-
요청된 컨테이너 이름이 이미 존재하는지 확인합니다.
-
환경 변수 파일에서 비밀 정보를 출력하지 않습니다.
-
사용자가 명시적으로 요청하지 않는 한
latest태그를 사용하지 않습니다. -
다음과 같은 파괴적인 정리 명령을 실행하지 않습니다:
docker system prunedocker image prunedocker volume prune
-
사용자의 명시적인 확인 없이 기존 컨테이너를 중지, 제거 또는 교체하지 않습니다.
-
사용자가 명확하게 확인하지 않는 한 기존 버전 태그를 다시 빌드하지 않습니다.
사전 점검
다음 점검을 먼저 실행합니다:
pwd
ls -la
test -f package.json && echo "OK: package.json found" || echo "WARN: package.json not found"
test -f Dockerfile && echo "OK: Dockerfile found" || echo "ERROR: Dockerfile not found"
test -f "$ENV_FILE" && echo "OK: env file found: $ENV_FILE" || echo "ERROR: env file not found: $ENV_FILE"
docker --version
docker info >/dev/null && echo "OK: Docker daemon is running" || echo "ERROR: Docker daemon is not running"
Dockerfile이 없으면 중지하고 문제를 보고합니다.
환경 변수 파일이 없으면 중지하고 문제를 보고합니다. 사용자가 요청하지 않는 한 임시 환경 변수 파일을 생성하지 않습니다.
Docker 데몬이 실행 중이 아니면 중지하고 사용자에게 Docker Desktop 또는 Docker Engine을 시작하도록 알립니다.
권장 보조 명령
package.json에서 이미지 이름을 추론하려면:
node -p "require('./package.json').name"
package.json이 없거나 name이 없으면 현재 디렉토리 이름을 사용합니다:
basename "$PWD"
프로젝트 이름을 수동으로 정규화하려면 소문자 케밥-케이스를 사용합니다.
예시:
My Next App -> my-next-app
nextjs_skill_app -> nextjs-skill-app
버전 태그 확인
빌드 전에 요청된 이미지 태그가 이미 존재하는지 확인합니다:
docker image inspect "$IMAGE_TAG" >/dev/null 2>&1 \
&& echo "EXISTS: $IMAGE_TAG" \
|| echo "AVAILABLE: $IMAGE_TAG"
또한 이 이미지의 기존 로컬 버전을 나열합니다:
docker images "$IMAGE_NAME" --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedSince}}\t{{.Size}}"
요청된 이미지 태그가 이미 존재하는 경우:
docker build를 실행하지 않습니다.- 해당 버전이 로컬에 이미 존재한다고 보고합니다.
- 다음 패치 버전(예:
1.0.1)을 제안합니다. - 사용자에게 새 버전을 사용할지 또는 동일한 태그를 명시적으로 다시 빌드할지 묻습니다.
사용자가 명확하게 확인한 경우에만 기존 태그를 다시 빌드합니다.
컨테이너 이름 확인
컨테이너를 실행하기 전에 컨테이너 이름이 이미 존재하는지 확인합니다:
docker ps -a --filter "name=^/${CONTAINER_NAME}$" \
--format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
같은 이름의 컨테이너가 이미 존재하는 경우:
- 같은 이름으로 다른 컨테이너를 실행하지 않습니다.
- 기존 컨테이너 상태를 보고합니다.
- 사용자에게 중지/제거할지 또는 다른 컨테이너 이름을 사용할지 묻습니다.
- 자동으로 제거하지 않습니다.
빌드 명령
이미지 태그가 존재하지 않으면 다음을 실행합니다:
docker build -t "$IMAGE_TAG" .
빌드 후 이미지가 존재하는지 확인합니다:
docker image inspect "$IMAGE_TAG" >/dev/null \
&& echo "OK: image built successfully: $IMAGE_TAG" \
|| echo "ERROR: image not found after build: $IMAGE_TAG"
실행 명령
이미지가 존재하고 컨테이너 이름을 사용할 수 있으면 다음을 실행합니다:
docker run --restart=always -d \
--name "$CONTAINER_NAME" \
--env-file "$ENV_FILE" \
-p "${HOST_PORT}:${CONTAINER_PORT}" \
"$IMAGE_TAG"
실행 후 검증
컨테이너 실행 후 다음으로 검증합니다:
docker ps --filter "name=^/${CONTAINER_NAME}$" \
--format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
docker logs --tail=80 "$CONTAINER_NAME"
curl -I "http://localhost:${HOST_PORT}"
예상 결과:
- 컨테이너 상태는
Up이어야 합니다. - 포트 매핑에는
${HOST_PORT}->${CONTAINER_PORT}가 포함되어야 합니다. - 로그에 치명적 오류가 없어야 합니다.
curl -I는200,301,302,307또는308과 같은 HTTP 응답을 반환해야 합니다.
curl이 실패하면 로그를 검사하고 원인을 보고합니다.
일반적인 오류 처리
이미지 태그가 이미 존재하는 경우
다음과 같이 보고합니다:
요청한 이미지 태그가 이미 로컬에 존재합니다:
<IMAGE_TAG>
권장 조치:
- 1.0.1과 같은 새로운 패치 버전을 사용하세요.
- 또는 동일한 태그를 다시 빌드할 것임을 명시적으로 확인하세요.
컨테이너 이름이 이미 존재하는 경우
다음과 같이 보고합니다:
컨테이너가 이미 존재합니다:
<CONTAINER_NAME>
중지/제거할지 또는 다른 컨테이너 이름을 제공할지 확인해주세요.
포트가 이미 사용 중인 경우
다음을 확인합니다:
lsof -i :"$HOST_PORT"
포트를 사용 중인 프로세스를 보고하고 사용자가 HOST_PORT를 변경할지 묻습니다.
환경 변수 파일이 없는 경우
다음과 같이 보고합니다:
환경 변수 파일을 찾을 수 없습니다:
<ENV_FILE>
이 파일이 존재할 때까지 --env-file로 컨테이너를 실행할 수 없습니다.
비밀 정보를 출력하거나 추론하지 않습니다.
Docker 데몬이 실행되지 않는 경우
다음과 같이 보고합니다:
Docker는 설치되어 있지만 데몬이 실행 중이 아닙니다.
Docker Desktop 또는 Docker Engine을 시작한 후 사전 점검을 다시 실행하세요.
최종 응답 형식
완료되면 다음을 보고합니다:
결과:
- 프로젝트: <PROJECT_NAME>
- 이미지: <IMAGE_TAG>
- 컨테이너: <CONTAINER_NAME>
- 환경 변수 파일: <ENV_FILE>
- 포트: http://localhost:<HOST_PORT>
- 재시작 정책: always
- 검증: 통과/실패
사용된 명령:
<중요 명령 나열>
참고 사항:
<모든 경고, 기존 이미지/컨테이너 충돌 또는 후속 조치>
워크플로우가 기존 버전 태그, 누락된 환경 변수 파일, 기존 컨테이너, Docker 오류 또는 포트 충돌로 인해 중단되면 차단 문제와 가장 안전한 다음 명령을 명확히 명시합니다.