본문 바로가기
Dev

Docker Jenkins 를 통한 CI/CD 자동화(React, Spring, Gitlab)

by IMSfromSeoul 2022. 5. 3.

환경설정

환경 및 목표

  • Jenkins와 Docker를 이용해서 배포 자동화 설정을 해준다.
  • 해당 프로젝트의 프론트는 React, 서버는 Spring을 이용해서 구축하였다.
  • 폴더구조
.
├── backend
│   ├── Dockerfile
│   ├── bin
│   ├── build
│   ├── build.gradle
│   ├── gradle
│   ├── gradlew
│   ├── gradlew.bat
│   ├── settings.gradle
│   └── src
├── docker-compose.yml
└── frontend
    ├── Dockerfile
    ├── README.md
    ├── nginx
    ├── node_modules
    ├── package-lock.json
    ├── package.json
    ├── public
    └── src

도커설치

sudo -i 입력 ( 관리자 권한 )

  • 저장소 설정
apt-get update
apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release 
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |  gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
  • 도커 설치 
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io
  • docker compose 설치
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Jenkins 설치 - with docker

 docker run -itd —name jenkins -p 9090:8080 jenkins/jenkins:lts
  • 도커를 이용해서 jenkins 설치를 해주자.

  • docker ps를 통해 jenkins 설치를 확인할 수 있다.

Jenkins 설치 - 내장 설치

  • docker를 이용해서 설치를 했는데 자꾸 ec2가 튕기면서 해당 docker image가 날라가는 현상이 2번이나 발생했다...
  • 나같은 현상이 있다면 내부 설치로 진행하자...

위 명령어를 입력해서 jenkins를 설치해준다.

Jenkins : 비밀번호

  • 초기 비밀번호를 입력하라고 뜬다.
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
  • 위 명령어를 통해 뜨는 비밀번호를 입력해주자.
sudo vi /var/lib/jenkins/secrets/initialAdminPassword
  • jenkins 내장설치의 경우 위 명령어를 통해 비밀번호를 확인해보자.

Jenkins - gitlab 연동 : gitlab acess token 발급

  • 내 프로필 > preferences > Access Tokens > Create personal access token > 복사를 해주자.
    • scope는 api만 체크해주면 된다.

Jenkins : 플러그인 설치

  • Jenkins 관리 > plugin 관리에 들어가서 plugin을 설치해주자.

  • Node.js, Blue Ocean, Gitlab 관련 설치를 진행해 줄 것이다.
  • 하나하나 찾고 넣어서 설치를 진행해주자.
Post build task
Bitbucket Pipeline for Blue Ocean
Dashboard for Blue Ocean
Personalization for Blue Ocean
Display URL for Blue Ocean
Server Sent Events (SSE) Gateway
Events API for Blue Ocean
Blue Ocean Pipeline Editor
i18n for Blue Ocean
Autofavorite for Blue Ocean
GitHub Pipeline for Blue Ocean
Git Pipeline for Blue Ocean
Config API for Blue Ocean
Blue Ocean
Jersey 2 API
GitLab
Generic Webhook Trigger
GitLab Authentication
Gitlab API
GitLab Branch Source
Gitlab API
Gitlab Merge Request Builder
Config File Provider
NodeJS
  • 위 플러그인들을 전부 설치해주면 된다.

gitlab - jenkins 연동

gitlab에서 발급된 키를 바탕으로 jenkins와 연동을 해주자.

  • Dashboard > Jenkins 관리 > 시스템 설정 > Gitlab > Add > Jenkins

  • 위에서 발급한 gitlab access token을 넣어주자.
  • Test Connection > Success 나오면 성공이다.

Jenkins - Docker

Pipeline 생성

  • pipeline의 흐름

  • Dashboard > 새로운 Item > Pipeline 클릭해주고 생성 클릭
  • Build Triggers > Build when a change is pushed to GitLab. GitLab webhook URL 클릭 

  • 밑에 고급이 있는데, 고급을 누르면 아래 칸들이 더 생성된다.

  • 위 generate 버튼을 클릭하면 secret token 생성된다.
  • 위 secret token을 gitlab에 등록해주자.

이제 gitlab에 들어가서 해당 secret key를 넣어주자.

  • gitlab > 해당 프로젝트 > settings > integeration에 들어가서 webhook 생성

  • URL에 사이트 주소/project/INVEW 입력
  • secret token에 아까 생성한 토큰값 집어넣으면 webhooks가 생성된다. ( 아래에 생성돼 있는 것을 확인할 수 있다 )
  • Test 해보면 

  • 위와 같이 성공적으로 연결된 것을 확인할 수 있다.
    • ( Docker를 이용해 9090포트를 사용했다면 위와 같이 뜰 것이고, 내장 설치를 이용해서 8080포트를 사용했다면 8080으로 뜰 것이다 )

Nodejs , Gradle 추가

  • React, Spring Boot를 띄울 것이므로 Node.js, Gradle을 추가해주자.
  • Jenkins 관리 > Global Tool Configuration

  • 이 때의 name은 script에 들어가는 이름이다.
pipeline {
    agent any
    
    tools {
        nodejs "nodejs" ** <-- 이 부분
        gradle 'gradle' ** <-- 이 부분
        
    }
    
    stages {
        stage('clean'){
            steps{
                sh 'docker-compose down'
                step([$class: 'WsCleanup'])
                
            }
        }
        ...

젠킨스 파이프라인 구성

Script 생성 ( git )

  • script를 생성해보자.
  • 내가 script 구문을 하나하나 외우고 있을 필요 없다.
  • 아래와 같이 pipeline syntax를 이용해서 script를 생성해보자.

  • 구성 > pipeline > pipeline syntax 클릭

  • Snippet Generator > Sample step : git 클릭

키 추가

  • username : id
  • password, id -> token 값 입력

  • generate pipeline script를 누르면 script가 생성된다.

 

  • 생성된 해당 script를 credentialsId 자리에 넣어주자.
    • clone으로 정상적으로 gitlab repository에 있는 소스코드를 가져와보자. 
    • git branch를 기본으로 'develop'을 가져올 것이면 위처럼 명시해주면 된다.

  • 성공이면 위처럼 체크표시가 뜬다.
  • 즉, 성공적으로 gitlab소스를 가져왔다고 보면 된다.

Jenkins 스크립트 , Docker 작성

  • 이제 거의 다 왔다. Jenkins를 통해 npm build, gradle build를 유발하고 해당 build된 파일을 docker container환경에서 실행시켜보자.

폴더 구조

.
├── backend
│   ├── Dockerfile
│   ├── bin
│   ├── build
│   ├── build.gradle
│   ├── gradle
│   ├── gradlew
│   ├── gradlew.bat
│   ├── settings.gradle
│   └── src
├── docker-compose.yml
└── frontend
    ├── Dockerfile
    ├── README.md
    ├── nginx
    ├── node_modules
    ├── package-lock.json
    ├── package.json
    ├── public
    └── src

Jenkins 파이프라인 스크립트

pipeline {
    agent any
    
    tools {
        gradle "gradle"
        nodejs "nodejs"
    }

    stages {
        stage('clone'){
            steps{
                git branch: '브랜치명', credentialsId: '아이디', url: 'URL(주소)'
            }
        }
        stage('front_build'){
            steps{
                dir('frontend'){
                    sh 'npm install'
                    sh 'npm run build'
                }
            }
        }
        stage('back_build'){
            steps{
                dir('backend'){
                    sh 'gradle clean build'
                }
            }
        }
        stage('deploy'){
            steps{
                sh 'sudo docker-compose up -d --build'
            }
        }
    }
}
  • npm install -> npm run build
    • build 파일을 생성해준다.
  • gradle clean build
    • .jar 파일을 생성해준다.

nginx : frontend/nginx/default.conf

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name ssayeon.co.kr;

        large_client_header_buffers 4 32k;
        root /usr/share/nginx/html;

        location / {   
                try_files $uri $uri/ /index.html;
        }

        location /api {
                proxy_pass http://spring:8081;
                proxy_redirect off;
                charset utf-8;

                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_set_header X-NginX-Proxy true;

                client_max_body_size 500M;
        
                # 502 에러를 없애기 위한...
                proxy_buffer_size          128k;
                proxy_buffers              4 256k;
                proxy_busy_buffers_size    256k;

                proxy_connect_timeout 300s; 
                proxy_read_timeout 600s;
                proxy_send_timeout 600s;
        }
}
  • 먼저 nginx 설정을 해주자.
    • server_name
      • 현재 나의 프로젝트 DNS이다.
    • location / { ... }
      • 진입하면 해당 index.html을 띄워준다.
      • 해당 index.html은 build된 react파일에 의해 실행된다.
    • location /api
      • spring 서버 요청을 /api로 mapping한다.

nginx + react dockerfile

FROM nginx:alpine
RUN rm -rf /etc/nginx/conf.d/default.conf
COPY /nginx/default.conf /etc/nginx/conf.d/default.conf

RUN rm -rf /usr/share/nginx/html/*
COPY /build /usr/share/nginx/html

EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
  • 기본 nginx default 설정을 지워주고, 우리가 작성한 nginx 파일을 default.conf 로 넣어주자.
  • jenkins script에 의해 build된 파일을 /usr/share/nginx/html 로 옮겨주어서 nginx로 접근 시 해당 build 파일이 실행되도록 해주자.

spring dockerfile

FROM openjdk:11-jdk

WORKDIR /app

COPY build/libs/*.jar application.jar

EXPOSE 8081

CMD ["java", "-jar", "application.jar"]
  • Spring 포트를 mapping 한다.
  • 현재 프로젝트에서의 port는 8081로 설정돼있다.

Docker Compose : docker-compose.yml

version: "3"
services:
  nginx:
    build: 
      context: ./frontend
    ports:
      - 80:80
    depends_on:
      - spring

  spring:
    build: 
      context: ./backend
    ports:
      - 8082:8081 #로컬포트:컨테이너포트
  • 8082:8081
    • 8082는 무작위 포트로 설정한 값이다.
    • 어차피 /api를 통해 요청이 들어오기 때문에 해당 포트값은 어떤 값을 쓰더라도 상관없다.

결과

 


REF

https://jktech.tistory.com/41

 

 

 

 

'Dev' 카테고리의 다른 글

golang 기초 #1 - 도입  (0) 2021.12.07

댓글