Repository navigation
[BUILD] 배포 자동화 세팅 #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
06fe675
[Build] CI/CD 파이프라인 및 Docker 배포 설정 추가
sunm2n 7be6d1b
[Fix] CI ruff 규칙 위반 수정
sunm2n 50fb8df
[Build] CI에서 ruff format --check 단계 제거
sunm2n 61b190e
[Build] CI에 테스트용 INTERNAL_API_KEY 추가 및 mypy 단계 제거
sunm2n 40d5a73
[Build] CI에 docker build 추가 및 CD 배포 상태 검증 보강
sunm2n File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| .git | ||
| .github | ||
| .gitignore | ||
| .idea | ||
| .vscode | ||
| __pycache__/ | ||
| *.py[cod] | ||
| .venv/ | ||
| venv/ | ||
| env/ | ||
| .pytest_cache/ | ||
| .ruff_cache/ | ||
| .mypy_cache/ | ||
| .coverage | ||
| htmlcov/ | ||
| coverage.xml | ||
| tests/ | ||
| test-sites/ | ||
| docs/ | ||
| *.md | ||
| .env | ||
| .env.* | ||
| data/ | ||
| *.db | ||
| *.db-journal | ||
| *.db-wal | ||
| *.db-shm | ||
| *.log | ||
| logs/ | ||
| node_modules/ | ||
| .DS_Store | ||
| Dockerfile | ||
| .dockerignore | ||
| .pre-commit-config.yaml | ||
| Makefile |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| name: CD | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: [CI] | ||
| types: [completed] | ||
| branches: [main] | ||
| workflow_dispatch: # 수동 실행 (테스트/재배포/롤백) | ||
|
|
||
| permissions: | ||
| id-token: write # OIDC | ||
| contents: read | ||
|
|
||
| jobs: | ||
| build-and-push: | ||
| if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| sha: ${{ steps.vars.outputs.sha }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ github.event.workflow_run.head_sha || github.sha }} | ||
| - id: vars | ||
| run: echo "sha=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" | ||
| - uses: docker/setup-buildx-action@v3 | ||
| - uses: docker/login-action@v3 | ||
| with: | ||
| username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
| password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
| - uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| push: true | ||
| tags: | | ||
| ${{ vars.IMAGE_NAME }}:latest | ||
| ${{ vars.IMAGE_NAME }}:${{ steps.vars.outputs.sha }} | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
|
|
||
| deploy: | ||
| needs: build-and-push | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: aws-actions/configure-aws-credentials@v4 | ||
| with: | ||
| role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} | ||
| aws-region: ${{ vars.AWS_REGION }} | ||
| - name: Deploy via SSM SendCommand | ||
| run: | | ||
| cmd_id=$(aws ssm send-command \ | ||
| --instance-ids "${{ secrets.APP_INSTANCE_ID }}" \ | ||
| --document-name "AWS-RunShellScript" \ | ||
| --comment "deploy fastapi ${{ needs.build-and-push.outputs.sha }}" \ | ||
| --parameters commands='[ | ||
| "set -e", | ||
| "cd ${{ vars.DEPLOY_DIR }}", | ||
| "docker compose pull ${{ vars.DEPLOY_SERVICE }}", | ||
| "docker compose up -d ${{ vars.DEPLOY_SERVICE }}", | ||
| "docker image prune -f" | ||
| ]' \ | ||
| --query "Command.CommandId" --output text) | ||
| echo "CommandId=$cmd_id" | ||
| # 완료까지 폴링 후 상태 검증 | ||
| for i in $(seq 1 30); do | ||
| status=$(aws ssm get-command-invocation \ | ||
| --command-id "$cmd_id" \ | ||
| --instance-id "${{ secrets.APP_INSTANCE_ID }}" \ | ||
| --query "Status" --output text 2>/dev/null || echo Pending) | ||
| echo "status=$status" | ||
| case "$status" in | ||
| Success) break ;; | ||
| Failed|Cancelled|TimedOut) | ||
| aws ssm get-command-invocation --command-id "$cmd_id" \ | ||
| --instance-id "${{ secrets.APP_INSTANCE_ID }}" \ | ||
| --query "StandardErrorContent" --output text | ||
| exit 1 ;; | ||
| esac | ||
| sleep 10 | ||
| done | ||
| # 루프가 타임아웃(300s)으로 끝났는데 Success 가 아니면 배포 실패로 처리. | ||
| # break 없이 빠져나온 Pending/InProgress 상태를 성공으로 오인하지 않도록 명시 검증. | ||
| if [ "$status" != "Success" ]; then | ||
| echo "deploy did not reach Success within timeout (last status=$status)" | ||
| exit 1 | ||
| fi | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [dev] | ||
| push: | ||
| branches: [dev, main] | ||
|
|
||
| jobs: | ||
| check: | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| TLDEXTRACT_CACHE: /tmp/tldextract # 리눅스 러너 캐시 경로 보정 | ||
| INTERNAL_API_KEY: test-ci-key # 테스트용 더미값 — Settings 필수 필드라 없으면 import 단계에서 실패 | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '3.11' | ||
| cache: pip | ||
| - run: pip install -e ".[dev]" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ruff와 pytest만 돌고 docker build .가 없습니다. Dockerfile, .dockerignore, entrypoint.sh, 패키징 문제는 merge 후 CD에서야 터질 수 있습니다. CI에 최소 docker build . 추가를 권장드립니다! |
||
| - name: Ruff lint | ||
| run: ruff check app tests | ||
| - name: Pytest | ||
| run: pytest | ||
| - name: Docker build | ||
| run: docker build -t linclean-fastapi:ci . | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| FROM python:3.11-slim | ||
|
|
||
| ENV PYTHONUNBUFFERED=1 \ | ||
| PYTHONDONTWRITEBYTECODE=1 \ | ||
| PIP_NO_CACHE_DIR=1 \ | ||
| PIP_DISABLE_PIP_VERSION_CHECK=1 \ | ||
| # app 이 site-packages 에 설치돼 alembic/uvicorn 이 그쪽을 import 하므로 | ||
| # SQLite 경로를 절대경로로 고정 (PROJECT_ROOT 추론이 site-packages 를 가리켜 | ||
| # 쓰기 불가 위치에 DB 디렉토리를 만들려다 실패하는 문제 방지). | ||
| SQLITE_PATH=/app/data/linclean.db \ | ||
| TLDEXTRACT_CACHE=/tmp/tldextract | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| # hatchling 이 app 패키지를 빌드해야 하므로 install 전에 소스 복사 | ||
| COPY pyproject.toml ./ | ||
| COPY app ./app | ||
| RUN pip install . | ||
|
|
||
| # 마이그레이션 + 기동 스크립트 | ||
| COPY alembic.ini ./ | ||
| COPY alembic ./alembic | ||
| COPY entrypoint.sh ./ | ||
| RUN chmod +x entrypoint.sh | ||
|
|
||
| # non-root + 데이터 디렉토리(SQLite) 소유권 | ||
| RUN useradd -m -u 1000 appuser \ | ||
| && mkdir -p /app/data \ | ||
| && chown -R appuser:appuser /app | ||
| USER appuser | ||
|
|
||
| EXPOSE 8000 | ||
|
|
||
| HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \ | ||
| CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/api/v1/health').status==200 else 1)" | ||
|
|
||
| ENTRYPOINT ["./entrypoint.sh"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #!/bin/sh | ||
| set -e | ||
| alembic upgrade head | ||
| exec uvicorn app.main:app --host 0.0.0.0 --port 8000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSM 상태가 Success도 아니고 Failed/Cancelled/TimedOut도 아닌 채 30회 폴링이 끝나면 그냥 루프를 빠져나와 job이 성공합니다. Pending/InProgress/Delayed가 계속돼도 배포 성공으로 보일 수 있습니다.
루프 뒤에 status == Success 검증을 추가해서 아니라면 exit 1 을 해야할 것 같습니다!