기록/CI&CD

[AWS] 같은 브랜치에 있는 프론트엔드, 백엔드 자동배포하기 (6) Jenkinsfile, vue & springboot Dockerfile 작성

5월._. 2022. 8. 18.
728x90

1. 프로젝트 구조

프로젝트 구조는 다음과 같다. Jenkinsfile, frontend폴더, bacnekd폴더가 가장 최상단에 있고 그 밑에 Dockerfile이 있다.

2. Jenkinsfile

tools에서 이전에 설치한 메이븐 이름을 쓴다. M3로 설정했으므로 maven "M3"을 적는다. stages는 네 단계로 나눴는데, 다음과 같다.

1) Docker kill

이미 프론트엔드, 백엔드 돌아가고있는 도커가 있다면 멈추고 해당 컨테이너를 지웠다. 

만약 그 컨테이너가 없다면 오류가 나면서 빌드가 멈추기 때문에 || 연산을 사용해서 있든 없든 빌드가 계속되도록 했다.

2) Prepare

checkout scm 명령어로 깃 레파지토리를 가져온다.

성공한다면 prepare success, 실패한다면 prepare fail 메세지를 출력하도록 했다.

3) Frontend Build

프로젝트 최상단에서 frontend 폴더로 들어간다. 이 때, dir명령어를 사용한다. 

위치에 맞게 잘 들어갔는지 확인을 위해서 echo 명령어를 썼고, 그 다음 도커 이미지를 만들었다.

프론트엔드 도커파일은 내부적으로 nginx를 사용해 80포트를 쓴다. 따라서 8081:80 을 써서 내부 80포트를 외부 8081포트로 실행되게끔 한다.

이 때 컨테이너 이름은 fe로 했다.

4) Backend Build

위에서 frontend 폴더로 갔으므로 ./backend로 가야 정확한 위치에 접근할 수 있다. frontend 폴더와 backend 폴더는 같은 레벨에 위치해있기 때문이다. 

메이븐 clean package를 하고 dockerfile을 이용해 이미지를 생성한다. 스프링프로젝트는 3000포트를 사용하도록 했으므로 3000:3000을 썼다.

컨테이너 이름은 be로 했다.

pipeline {
    agent any

    tools {
      maven "M3"
    }

    stages {
      stage('Docker kill'){
        steps {
          sh 'docker stop fe || true && docker rm fe || true'
          sh 'docker stop be || true && docker rm be || true' 
        }
        post {
          success {
            echo "kill success"
          }
          failure {
            echo "kill fail"
          }
        }
      }
      stage('Prepare') {
        steps {
          checkout scm
        }
        post {
            success {
              echo " prepare success"
            }
            failure {
              echo "prepare fail"
            }
        }
      }
      stage('Frontend Build') {
        steps {
          dir('frontend'){
            echo "here is frontend dir"
            sh 'docker build -t frontend .'
            sh 'docker run -d --name fe -p 8081:80 frontend'
          }
        }
      }
      stage('Backend Build') {
        steps {
          dir('./backend'){
            echo "here is backend dir"
            sh "mvn -Dmaven.test.failure.ignore=true clean package"
            sh 'docker build -t backend .'
            sh 'docker run -d --name be -p 3000:3000 backend'
          }
        }
      }
    }
}

 

3. Frontend

1) Dockerfile

노드로 먼저 package를 다운로드 받은 뒤 build한다.

그 파일들을 nginx를 이용해 실행시킨다.

# build stage
FROM node:lts-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
RUN npm run build

# production stage
FROM nginx-alpine as production-stage
RUN mkdir /app
COPY --from=build-stage /app/dist /app
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

2) nginx.conf

https://cli.vuejs.org/guide/deployment.html#docker-nginx에서 복사해왔다. 프론트엔드폴더의 최상단에 넣으면 된다.

이 설정파일을 1)에서 copy시켜 사용한다.

user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
events {
  worker_connections  1024;
}
http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;
  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
  access_log  /var/log/nginx/access.log  main;
  sendfile        on;
  keepalive_timeout  65;
  server {
    listen       80;
    server_name  localhost;
    location / {
      root   /app;
      index  index.html;
      client_max_body_size 10M;
      try_files $uri $uri/ /index.html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   /usr/share/nginx/html;
    }
  }
}

 

4. Backend

1) Dockerfile

target 밑에 생성된 jar 파일을 app.jar로 copy한 후 실행시킨다. 

FROM openjdk:8-jdk-alpine
COPY target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
EXPOSE 3000

 

5. 주의할 점

dockerfile에서 alpine을 전부 붙여서 사용했다. node alpine, jdk alpine, nginx alpine.. 경량화된 버전이라 필요한 부분만 가져와서 속도가 빨라진다는 장점이 있지만 혹시 docker container 내부로 접속할 일이 생긴다면 alpine 버전말고 다른 버전을 사용해야 한다.

댓글