-
Notifications
You must be signed in to change notification settings - Fork 0
Joonseok week10 #112
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
base: Joonseok
Are you sure you want to change the base?
Joonseok week10 #112
Changes from all commits
5a1b6b2
c3c94f6
77e96b0
552e17b
861a4a1
6825dd8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ "main" ] | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: main 체크아웃 | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: 자바 설정 | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| distribution: 'temurin' | ||
| java-version: '21' | ||
|
|
||
| - name: gradlew 실행 권한 부여 | ||
| run: chmod +x gradlew | ||
| working-directory: ./Joonseok | ||
|
|
||
| - name: gradle 세팅 | ||
| uses: gradle/actions/setup-gradle@v4 | ||
|
|
||
| - name: gradle 빌드 | ||
| run: ./gradlew clean build -x test | ||
| working-directory: ./Joonseok | ||
|
|
||
| - name: Docker Hub 로그인 | ||
| uses: docker/login-action@v2 | ||
| with: | ||
| username: ${{ secrets.DOCKER_USERNAME }} | ||
| password: ${{ secrets.DOCKER_TOKEN }} | ||
|
|
||
| - name: Docker Buildx 설정 | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Docker 이미지 빌드 및 푸시 | ||
| uses: docker/build-push-action@v7 | ||
| with: | ||
| context: ./Joonseok | ||
| push: true | ||
| tags: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGENAME }}:latest | ||
| platforms: linux/amd64, linux/arm64 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| name: CD | ||
|
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.
현재 Useful? React with 👍 / 👎.
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. GitHub Actions 워크플로는 저장소 루트의 |
||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: ["CI"] | ||
| types: [completed] | ||
| branches: [main] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| BACKEND_IMAGE: ${{ secrets.DOCKER_USERNAME }}/kkumteul-backend | ||
| FASTAPI_IMAGE: ${{ secrets.DOCKER_USERNAME }}/kkumteul-ai | ||
|
|
||
| jobs: | ||
| deploy: | ||
| name: Deploy to EC2 | ||
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Copy deploy files to EC2 | ||
| uses: appleboy/scp-action@v0.1.7 | ||
| with: | ||
| host: ${{ secrets.SERVER_HOST }} | ||
| username: ${{ secrets.SERVER_USER }} | ||
| key: ${{ secrets.SERVER_SSH_KEY }} | ||
| port: 22 | ||
|
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. 배포 파일을 복사할 때 경로가 저장소 루트 기준으로 해석됩니다. 현재 설정은 |
||
| source: "docker-compose.yml,nginx/conf.d/default.conf" | ||
|
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. 이 Useful? React with 👍 / 👎. |
||
| target: "/home/${{ secrets.SERVER_USER }}/app" | ||
|
|
||
| - name: Deploy over SSH | ||
| uses: appleboy/ssh-action@v1.2.0 | ||
| with: | ||
| host: ${{ secrets.SERVER_HOST }} | ||
| username: ${{ secrets.SERVER_USER }} | ||
| key: ${{ secrets.SERVER_SSH_KEY }} | ||
| port: 22 | ||
| envs: BACKEND_IMAGE | ||
|
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.
Useful? React with 👍 / 👎. |
||
| script: | | ||
| cd /home/${{ secrets.SERVER_USER }}/app | ||
| echo "BACKEND_IMAGE=${BACKEND_IMAGE}:latest" > .env | ||
| echo "FASTAPI_IMAGE=${FASTAPI_IMAGE}:latest" >> .env | ||
|
|
||
| echo "[1/4] Pull latest images..." | ||
| docker pull ${BACKEND_IMAGE}:latest | ||
| docker pull ${FASTAPI_IMAGE}:latest | ||
|
|
||
| echo "[2/4] Restart with docker compose..." | ||
| docker compose up -d --remove-orphans | ||
|
|
||
| echo "[3/4] Force-recreate nginx for config changes..." | ||
| docker compose up -d --force-recreate nginx | ||
|
|
||
| echo "[4/4] Cleanup unused images..." | ||
| docker image prune -f | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| FROM eclipse-temurin:21-jdk | ||
| WORKDIR /app | ||
|
|
||
| ARG JAR_FILE=build/libs/*.jar | ||
| COPY ${JAR_FILE} project.jar | ||
|
Comment on lines
+4
to
+5
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.
Spring Boot Gradle 플러그인은 기본적으로 실행 가능한 Useful? React with 👍 / 👎. |
||
|
|
||
| ENTRYPOINT ["java", "-Dspring.profiles.active=docker", "-jar", "project.jar"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| <aside> | ||
| 💡 | ||
|
|
||
| </aside> | ||
|
|
||
| - 클라우드 컴퓨팅이란? | ||
|
|
||
| <aside> | ||
| 🖥️ | ||
|
|
||
| ### 저희는 어떻게 웹 서비스를 이용하는거죠…? | ||
|
|
||
| </aside> | ||
|
|
||
| 인터넷을 통해 필요할 때마다 컴퓨팅 리소스, 즉 물리적 또는 가상 서버, 데이터 스토리지, 네트워킹 기능, 애플리케이션 개발 툴, 소프트웨어, AI 기반 분석 플랫폼 등에 사용한 만큼만 접근할 수 있는 서비스 | ||
|
|
||
| 온-프레미스 방식과 대조되는 방식으로, 보안성이 다소 떨어질 수 있으나, 유연성과 확장성이 매우 뛰어나다. | ||
|
|
||
| - 비용 및 효율성 | ||
| - 속도 및 민첩성 | ||
| - 무제한 확장성 | ||
| - 전략적 가치 향상 | ||
|
|
||
| 현대적인 클라우드 아키텍처는 이하의 항목을 포함한다. | ||
|
|
||
| - 데이터 센터 | ||
| - 네트워킹 기능 | ||
| - 가상화 | ||
| - AWS? GCP? | ||
|
|
||
| <aside> | ||
| ❓ | ||
|
|
||
| ### 클라우드 컴퓨팅 플랫폼. 뭐 써야 돼요? | ||
|
|
||
| </aside> | ||
|
|
||
| ### AWS | ||
|
|
||
| Amazon Web Service의 약자. | ||
| 클라우드 컴퓨팅에 필요한 거의 모든 서비스를 제공하며, 사용한 만큼의 비용만 지불하면 되는 형태이다. | ||
|
|
||
| EC2라고 불리는 다양한 가상 컴퓨터를 제공한다. 리소스 선택폭도 굉장히 넓은 편 | ||
|
|
||
| 저장공간 역시 넓다 | ||
|
|
||
| 네트워크 인프라 역시 더 크다. | ||
|
|
||
| ### GCP | ||
|
|
||
| Google Cloud Platform | ||
| AI 및 기계 학습 부문에서 빠르게 주목받고 있다. | ||
| 가격 측면에서 더욱 직관적이지만, 솔루션이나 가격 유연성이 부족하다. | ||
|
|
||
| AWS 만큼의 선택폭은 없지만, 사용하면 할 수록 자동 할인이 있다. | ||
|
|
||
| AI 학습이나, Google Cloud와 연결할 수 있다는 장점이 있다. | ||
|
|
||
| 프라이빗, 데이터 집약적 운영에 더 강하다. | ||
|
|
||
| - 환경변수 처리 방법과 왜 환경변수로 민감 정보를 가려야 하는가? | ||
| 1. 서버에 직접 등록한다. | ||
| Github가 제공하는 CI/CD 등 기능 사용 불가 | ||
| 2. Git Secrets에 등록한다 | ||
| CI/CD 사용 가능 | ||
|
|
||
| 환경변수는 대부분 비용과 직결되는 문제로, 해커에 의한 악의적 요청으로 지불해야 할 대금이 폭증하지 않도록 가린다. | ||
|
|
||
| - yml 환경 분리 방법 | ||
|
|
||
| 각 환경마다 빌드해야 할 것과 빌드 하지 말아야 할 것들을 분리하여 | ||
| `@Profile(value = NAME )` 으로 분기한다 | ||
|
|
||
| 메인 설정 파일인 application.yml(applicaiton.properties)에 환경변수로 | ||
| `spring.profiles.active=${이름}` 으로 환경마다 다른 설정 파일을 주입하도록 한다. | ||
|
|
||
| - Docker와 .jar vs Docker 이미지 | ||
|
|
||
| Docker는 개발자와 개발자, 개발 환경과 운영 환경의 차이를 없애기 위해 프로젝트를 애플리케이션 단위로 포장하는 툴이다. | ||
|
|
||
| .jar : java 빌드 산출물. JVM에 의해 읽히는 바이트 파일 등 | ||
|
|
||
| Docker 이미지 : Dockerfile에 의해 생성되는 산출물. 애플리케이션 실행에 필요한 모든 것들을 담고 있다. | ||
| --- | ||
| - Sticky Session vs Session Clustering | ||
|
|
||
| stateful 서버의 한계점. 서버를 확장할 때, 세션 저장소 의존성이 생기므로, 확장성과 유연성이 떨어진다. | ||
|
|
||
| ### Stick sesison | ||
|
|
||
| 세션은 각 서버에 저장되어 종속적인 방식. | ||
|
|
||
| 인프라가 단순해지고, 로컬 메모리 접근이므로 빠르다. | ||
|
|
||
| - 세션이 서버 종속이므로 서버가 다운되면 세션도 전부 사라진다. | ||
| - 한 서버에 무거운 세션이 pinned → 부하 불균등 문제 | ||
|
|
||
| ### Session Clustering | ||
|
|
||
| 모든 서버가 세션을 공유한다. | ||
|
|
||
| 1. 세션 복제식 | ||
| 2. 외부 저장 서버 | ||
|
|
||
| 장점 : 스티키 세션의 단점을 해결 | ||
|
|
||
| 단점 : 접속마다 네트워킹 왕복 필요 → 오버헤드 상승 | ||
|
|
||
| - blue-green 배포 | ||
|
|
||
| 서버를 2개 띄우고, 트래픽을 통째로 전환하는 무중단 배포 전략 | ||
|
|
||
| - Blue : 현재 트래픽을 받는 서버 | ||
| - Green : 유휴 상태에 있는 서버 | ||
| - 새 버전 업로드 | ||
| - 스모크 테스트 | ||
| - 헬스 체크… | ||
|
|
||
| 모든 테스트가 종료되면 모든 트래픽을 현재 Blue → Green으로 이동 후 Green을 Blue 서버로 지정 | ||
|
|
||
| 장애 발생 시, 기존 Blue로 즉시 전환하면 되므로 문제 없음 | ||
|
|
||
| - Gzip 압축 및 캐싱 | ||
|
|
||
| ### Gzip 압축 | ||
|
|
||
| HTTP 응답 본문을 DEFLATE 알고리즘으로 압축하고, wire로 보내는 본문 인코딩 방법. | ||
| HTTP 응답 본문은 반복 패턴이 많아서 크게 이득볼 수 있다. | ||
|
|
||
| - 클라이언트가 `Accept-Encoding: gzip, deflate, br`로 압축 해제 가능함을 알림 | ||
| - 서버가 압축 후 `Content-Encoding: gzip` + `Vary: Accept-Encoding` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| upstream backend { | ||
| least_conn; | ||
| server app1:8080 weight=3; | ||
| server app2:8080 weight=1; | ||
| } | ||
|
|
||
| server { | ||
| listen 80; | ||
| server_name _; | ||
|
|
||
| location / { | ||
| proxy_pass http://backend; | ||
| proxy_set_header Host $host; | ||
| proxy_set_header X-Real-IP $remote_addr; | ||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| proxy_set_header X-Forwarded-Proto $scheme; | ||
|
|
||
| proxy_connect_timeout 60s; | ||
| proxy_send_timeout 60s; | ||
| proxy_read_timeout 60s; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.umc.study.global.web.controller; | ||
|
|
||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| import java.net.InetAddress; | ||
| import java.net.UnknownHostException; | ||
| import java.util.Map; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/server") | ||
| public class ServerInfoController { | ||
|
|
||
| @GetMapping("/info") | ||
| public ResponseEntity<Map<String, String>> getServerInfo() throws UnknownHostException { | ||
|
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. 컨트롤러 메서드가 |
||
| InetAddress host = InetAddress.getLocalHost(); | ||
| return ResponseEntity.ok(Map.of( | ||
| "hostname", host.getHostName(), | ||
| "ip", host.getHostAddress() | ||
| )); | ||
| } | ||
| } | ||
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.
현재 CI가
main브랜치 push에서만 실행됩니다. 이번 PR의 기준 브랜치가Joonseok이고 학습 PR 검증 목적도 있으므로pull_request또는 대상 브랜치 전략을 함께 정의하는 것을 권장합니다. CI는 코드가 합쳐진 뒤보다 합치기 전에 피드백을 주는 역할이 크기 때문에 실행 시점을 명확히 잡을 필요가 있습니다.