diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..383711dd --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,99 @@ +name: Production 배포 +on: + push: + branches: + - feature/76-kan-131-cicd +env: + DOCKERHUB_USERNAME: meonghanyang + DOCKERHUB_IMAGE_NAME: server + +jobs: + build-deploy: + name: Production 배포 + runs-on: ubuntu-latest + + steps: + - name: 기본 체크아웃 + uses: actions/checkout@v3 + + - name: JDK 21 버전 설정 + uses: actions/setup-java@v3 + with: + distribution: 'corretto' + java-version: '21' + + - name: Gradlew 실행 권한 설정 + run: chmod +x ./gradlew + + - name: Gradle 빌드 + id: gradle + uses: gradle/gradle-build-action@v2 + with: + arguments: | + build + --scan + -x test + cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }} + + - name: Dockerhub 로그인 + uses: docker/login-action@v3 + with: + username: ${{ env.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }} + + - name: Docker 메타데이터 추출 + id: metadata + uses: docker/metadata-action@v5.5.0 + env: + DOCKERHUB_IMAGE_FULL_NAME: ${{ env.DOCKERHUB_USERNAME }}/${{ env.DOCKERHUB_IMAGE_NAME }} + with: + images: ${{ env.DOCKERHUB_IMAGE_FULL_NAME }} + tags: + ${{ github.run_number }} + flavor: | + latest=false + + - name: Docker 이미지 빌드 및 도커허브로 푸시 + uses: docker/build-push-action@v6.0.1 + with: + file: scripts/Dockerfile + context: . + push: true + tags: ${{ steps.metadata.outputs.tags }} + + - name: 환경변수 주입 + run: | + echo "${{ secrets.APPLICATION_SECRETS }}" > .env + + - name: 서버로 .env 파일 전송 + uses: burnett01/rsync-deployments@7.0.1 + with: + switches: -avzr --delete + remote_host: ${{ secrets.EC2_HOST }} + remote_user: ${{ secrets.EC2_USERNAME }} + remote_key: ${{ secrets.EC2_PRIVATE_KEY }} + path: .env + remote_path: /home/${{ secrets.EC2_USERNAME }}/ + + - name: 서버로 docker compose 파일 전송 + uses: burnett01/rsync-deployments@7.0.1 + with: + switches: -avzr --delete + remote_host: ${{ secrets.EC2_HOST }} + remote_user: ${{ secrets.EC2_USERNAME }} + remote_key: ${{ secrets.EC2_PRIVATE_KEY }} + path: scripts/docker-compose.yml + remote_path: /home/${{ secrets.EC2_USERNAME }}/ + + - name: EC2로 배포 + uses: appleboy/ssh-action@master + env: + IMAGE_FULL_URL: ${{ steps.metadata.outputs.tags }} + with: + host: ${{ secrets.EC2_HOST }} + username: ${{ secrets.EC2_USERNAME }} + key: ${{ secrets.EC2_PRIVATE_KEY }} + envs: IMAGE_FULL_URL, DOCKERHUB_IMAGE_NAME # docker-compose.yml 에서 사용할 환경 변수 + script: | + echo "${{ secrets.DOCKERHUB_ACCESS_TOKEN }}" | docker login -u "${{ env.DOCKERHUB_USERNAME }}" --password-stdin + docker compose up --build -d \ No newline at end of file diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 00000000..fb0d81ee --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,5 @@ +FROM amazoncorretto:21-alpine-jdk +ARG JAR_FILE=build/libs/*.jar +COPY ${JAR_FILE} app.jar +EXPOSE 8080 +ENTRYPOINT ["java","-jar","/app.jar"] diff --git a/scripts/docker-compose.yml b/scripts/docker-compose.yml new file mode 100644 index 00000000..3b89873b --- /dev/null +++ b/scripts/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.3" + +services: + traefik: + image: "traefik:v3.2" + container_name: "traefik" + command: + - "--log.level=DEBUG" + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entryPoints.web.address=:80" + - "--entryPoints.websecure.address=:443" + - "--certificatesresolvers.myresolver.acme.tlschallenge=true" + - "--certificatesresolvers.myresolver.acme.email=meonghanyang@example.com" + - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" + ports: + - "443:443" + - "8000:8080" + volumes: + - "./letsencrypt:/letsencrypt" + - "/var/run/docker.sock:/var/run/docker.sock:ro" + + backend: + image: ${IMAGE_FULL_URL} + container_name: ${DOCKERHUB_IMAGE_NAME} + restart: always + environment: + - TZ=Asia/Seoul + ports: + - '8080:8080' + env_file: .env + volumes: + - "./client_secret.json:/client_secret.json" + labels: + - "traefik.enable=true" + - "traefik.http.routers.backend.rule=Host(`api.test-wonchae.p-e.kr`)" + - "traefik.http.routers.backend.entrypoints=websecure" + - "traefik.http.routers.backend.tls.certresolver=myresolver" \ No newline at end of file