From 4d597a16506809a97086f7e65cfeb7fbfc486561 Mon Sep 17 00:00:00 2001 From: Lectom C Han Date: Tue, 13 Oct 2026 10:02:55 +0900 Subject: [PATCH] feat: dockerize and deploy Storybook --- .dockerignore | 18 +++++++++ .gitea/workflows/deploy-storybook.yml | 55 +++++++++++++++++++++++++++ Dockerfile | 15 ++++++++ README.md | 29 ++++++++++++++ compose.yaml | 6 +++ 5 files changed, 123 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitea/workflows/deploy-storybook.yml create mode 100644 Dockerfile create mode 100644 compose.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..60e6d64 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +.git +.github +.agents +.codex +node_modules +**/node_modules +dist +**/dist +storybook-static +theme-dist +coverage +test-results +playwright-report +_local +*.log +.env +.env.* +!.env.example diff --git a/.gitea/workflows/deploy-storybook.yml b/.gitea/workflows/deploy-storybook.yml new file mode 100644 index 0000000..de48ad5 --- /dev/null +++ b/.gitea/workflows/deploy-storybook.yml @@ -0,0 +1,55 @@ +name: Deploy Storybook + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: storybook-deployment + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Prepare SSH credentials + env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + DEPLOY_KNOWN_HOSTS: ${{ vars.DEPLOY_KNOWN_HOSTS }} + run: | + install -d -m 700 "$HOME/.ssh" + printf '%s\n' "$DEPLOY_SSH_KEY" > "$HOME/.ssh/deploy_key" + chmod 600 "$HOME/.ssh/deploy_key" + printf '%s\n' "$DEPLOY_KNOWN_HOSTS" > "$HOME/.ssh/deploy_known_hosts" + chmod 600 "$HOME/.ssh/deploy_known_hosts" + + - name: Update checkout and deploy on host + env: + DEPLOY_HOST: ${{ vars.DEPLOY_HOST }} + DEPLOY_USER: ${{ vars.DEPLOY_USER }} + DEPLOY_PATH: ${{ vars.DEPLOY_PATH }} + DEPLOY_PORT: ${{ vars.DEPLOY_PORT }} + run: | + test -n "$DEPLOY_HOST" + test -n "$DEPLOY_USER" + test -n "$DEPLOY_PATH" + test -n "$DEPLOY_PORT" + DEPLOY_PATH_B64="$(printf '%s' "$DEPLOY_PATH" | base64 | tr -d '\n')" + ssh \ + -i "$HOME/.ssh/deploy_key" \ + -p "$DEPLOY_PORT" \ + -o BatchMode=yes \ + -o StrictHostKeyChecking=yes \ + -o UserKnownHostsFile="$HOME/.ssh/deploy_known_hosts" \ + "$DEPLOY_USER@$DEPLOY_HOST" \ + "DEPLOY_PATH_B64=$DEPLOY_PATH_B64 bash -se" <<'REMOTE' + set -euo pipefail + DEPLOY_PATH="$(printf '%s' "$DEPLOY_PATH_B64" | base64 -d)" + cd "$DEPLOY_PATH" + git fetch origin main + git checkout main + git pull --ff-only origin main + docker compose down && STORYBOOK_PORT=6024 docker compose up -d --build + REMOTE diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ca0be75 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM node:24-alpine AS build + +WORKDIR /app + +COPY package.json package-lock.json ./ +COPY packages ./packages +RUN npm ci + +COPY . . +RUN npm run build +RUN npm run build-storybook + +FROM nginx:1.29-alpine AS service +COPY --from=build /app/storybook-static /usr/share/nginx/html +EXPOSE 80 diff --git a/README.md b/README.md index fe6475d..058479e 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,35 @@ Windows에서는 Clone한 루트의 `.\start-storybook.bat`를 실행하거나 정적 Storybook 빌드는 `npm run build-storybook`, 앱 빌드는 `npm run build`, 타입 확인은 `npm run typecheck`입니다. 명령은 루트 package.json의 현재 scripts를 기준으로 합니다. +## Docker로 Storybook 실행 + +Docker Engine과 Docker Compose plugin만 있으면 호스트에 Node.js/npm이나 프로젝트 의존성을 설치하지 않고 Storybook을 실행할 수 있습니다. 저장소 루트에서 실행하면 Docker 이미지 안에서 `npm ci`, 앱 빌드, 정적 Storybook 빌드를 수행한 뒤 nginx가 결과를 제공합니다. + +```sh +docker compose up -d --build +``` + +기본 주소는 **http://localhost:6024/** 입니다. 6024가 사용 중이면 로컬 실행 포트를 변경할 수 있습니다. + +```sh +STORYBOOK_PORT=6025 docker compose up -d --build +``` + +PowerShell에서는 다음과 같이 실행합니다. + +```powershell +$env:STORYBOOK_PORT = "6025" +docker compose up -d --build +``` + +상태와 로그는 `docker compose ps`, `docker compose logs -f storybook`으로 확인하고, 중지할 때는 `docker compose down`을 실행합니다. 소스 변경 후 `docker compose up -d --build`를 실행하면 이미지를 다시 빌드하고 서비스를 갱신합니다. + +### Gitea Actions 배포 + +`.gitea/workflows/deploy-storybook.yml`은 `main`에 push되거나 수동 실행될 때 SSH로 배포 서버의 기존 저장소를 갱신하고, 그 서버에서 `docker compose down && docker compose up -d --build`를 실행합니다. 빌드와 호스팅은 배포 서버에서 이뤄지며 Storybook 산출물을 별도로 전송하지 않습니다. 서비스는 배포 서버의 **6024 포트**를 사용합니다. + +저장소 Actions Variables에 `DEPLOY_HOST` (`10.13.10.4`), `DEPLOY_USER` (`user`), `DEPLOY_PATH` (`/home/user/services/HMDesign`), `DEPLOY_PORT` (`22`), `DEPLOY_KNOWN_HOSTS` (배포 서버의 검증된 SSH host key)를 설정하고, Actions Secret에 `DEPLOY_SSH_KEY`를 등록합니다. 배포 서버 계정은 해당 경로의 저장소에서 `origin/main`을 가져올 수 있어야 하며 Docker Engine/Compose plugin 실행 권한이 필요합니다. Actions Runner는 SSH로 배포 서버에 접속할 수 있어야 합니다. + 문서 내부 링크 검사는 프로젝트 루트에서 `node scripts/check-doc-links.mjs`로 실행합니다. `.git`이 있으면 기존 Git 추적·비추적(ignored 제외) Markdown 수집을 유지하고, `.git` 없는 압축 해제본에서는 파일 시스템과 루트·하위 `.gitignore`의 현재 경로·와일드카드·제외/예외 규칙으로 수집합니다. `.git` 메타데이터와 ignored 폴더는 순회하지 않습니다. Node만 있으면 독립 실행할 수 있으며 결과에 `collectionMode`, 실제 MD/링크 수와 문제 목록을 출력합니다. 종료 코드 0은 통과, 1은 링크 오류, 2는 수집 실행 오류입니다. 회귀 검사는 `node --test scripts/check-doc-links.test.mjs`입니다(두 수집 방식 비교에는 Git 필요). ## 기존 Component 기반 새 React 화면 diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..cb5ee3f --- /dev/null +++ b/compose.yaml @@ -0,0 +1,6 @@ +services: + storybook: + build: . + ports: + - "${STORYBOOK_PORT:-6024}:80" + restart: unless-stopped