[Infra] React Pipeline 구축

[Infra] React Pipeline 구축

Dockerfile

## 1. Build React App
FROM node:alpine as builder
WORKDIR /app
COPY package*.json .
RUN npm ci --force
COPY . .
RUN npm run build

## 2. React를 Nginx로 Serve
FROM nginx:latest

RUN rm /etc/nginx/conf.d/default.conf
COPY ./nginx.conf /etc/nginx/conf.d
RUN ls -al
WORKDIR /usr/share/nginx/html

COPY --from=builder /app/dist /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

 

  • nginx.conf
server {
    listen 80;
    location / {
        root    /usr/share/nginx/html;
        index   index.html;
        try_files $uri $uri/ /index.html;
    }
}

 

=> Dockerfile와 nginx.conf 파일을 frontend 폴더에 추가

 

Tool

  • plugin - Nodejs 설치
  • Jenkins 관리 - Tools 접속
  • frontend 버전에 따라 nodejs 설정 -> 없는 경우, jenkins 컨테이너에 접속해서 직접 설치

Pipeline

  • 멀티브런치를 이용해 분리했을 경우, Manged File > groovy file > pipeline jenkins 파일 생성해서 작성
pipeline {
    agent any
    tools {
        nodejs "nodejs"
    }
    options {
        disableConcurrentBuilds()
    }
  • tools: 파이프라인에서 사용할 도구를 정의, nodejs 도구를 사용
  • options: 파이프라인 옵션을 설정, disableConcurrentBuilds()를 호출하여 동시 빌드를 비활성화

checkout

    stages {
        stage('Checkout') {
            steps {
                git branch: env.GIT_BRANCH, credentialsId: '{git 사용자 계정}', url: '{git url}'
                script {
                    def branchName = sh(script: "git rev-parse --abbrev-ref HEAD", returnStdout: true).trim()
                    if (branchName != 'develop') {
                        echo "This job only runs on the develop branch. Current branch is ${branchName}. Aborting the build."
                        currentBuild.result = 'ABORTED'
                        return
                    }
                }
            }
        }

 

  • git branch를 통해 서버로 pull을 받음

Build

        stage('Build Frontend') {
            steps {
                script {
                    def currentDir = sh(script: 'pwd', returnStdout: true).trim()
                    echo "The current directory is: ${currentDir}"
                    dir("./frontend") {
                        sh 'npm install'
                        sh 'npm run build'
                    }
                    dir("./frontend") {
                        sh 'docker rmi -f {docker image:tag}'
                        sh 'docker build -t {docker image:tag} .'
                    }
                }
            }
        }
  • frontend 폴더에서 frontend를 빌드한 후 docker image로 build

Deploy

        stage('Deploy Frontend') {
            steps {
                script {
                    sh 'docker-compose down'
                    sh 'docker-compose up -d frontend'
                }
            }
        }

 

  • docker-compose로 기존에 올라간 컨테이너를 내리고, 다시 빌드한 이미지를 올림

 

docker-compose.yml

  • 서버에서 jenkins > workspace > {해당 파이프라인 폴더} 경로 내에 추가
version: '3'

services:
  frontend:
    image: {frontend 빌드 이미지:tag}
    container_name: frontend
    networks:
      - infra
    ports:
    - "3000:80"
    environment:
      - VIRTUAL_HOST=${HOST}
      - LETSENCRYPT_HOST=${HOST}
      - LETSENCRYPT_EMAIL=${EMAIL}

networks:
  infra:
    external: true

 

HealthCheck

  • 제대로 올라갔는지 Health Check
        stage('Health Check Frontend') {
            steps {
                script {
                    def maxRetries = 60
                    def retries = 0
                    def success = false
                    while (!success && retries < maxRetries) {
                        try {
                            response = sh(script: "curl -s -o /dev/null -w '%{http_code}' -k {사이트 url}", returnStdout: true).trim()
                            if (response == '200') {
                                success = true
                                echo "Service is up and running"
                            } else {
                                throw new Exception("Service response code: ${response}")
                            }
                        } catch (Exception ignored) {
                            retries++
                            echo "Attempt ${retries}/60: Service not ready, response code: ${response}"
                            if (response == '000') {
                                echo "Network connection failed, retrying..."
                            } else {
                                echo "Unexpected response code, retrying..."
                            }
                            sleep(time: 1, unit: 'SECONDS')
                        }
                    }
                    if (!success) {
                        error("Health check failed after ${maxRetries} attempts")
                    }
                }
            }
        }
    }

 

'Infra' 카테고리의 다른 글

[Infra] BackEnd Blue-Green 배포  (1) 2024.05.27
[Infra] Spring Boot Pipeline 구축  (0) 2024.05.25
[Infra] Nginx 설정  (0) 2024.05.25
[Infra] Docker-Compose 를 통한 DB 구축  (0) 2024.05.25
[Infra] Docker 설치  (0) 2024.05.25