Etc

Gitlab + Docker + Jenkins 이용한 스프링부트, 리액트 프로젝트 CI/CD

sssbin 2024. 2. 25. 18:20

EC2 접속

ssh -i ./pem키 ubuntu@ec2주소
  • 권한 오류가 뜬다면? Permission denied (publickey)

      chmod 400 pem키

Docker 설치

오래된 버전 삭제

sudo apt-get remove docker docker-engine docker.io containerd runc

Repository 설정

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo 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" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Docker Engine 설치

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

설치 완료

docker --version


Docker Compose 설치

최신 버전 설정 후 다운로드

sudo apt install jq
VERSION=$(curl --silent https://api.github.com/repos/docker/compose/releases/latest | jq .name -r)
DESTINATION=/usr/local/bin/docker-compose
sudo curl -L https://github.com/docker/compose/releases/download/${VERSION}/docker-compose-$(uname -s)-$(uname -m) -o $DESTINATION
sudo chmod 755 $DESTINATION

버전 정보 확인

docker-compose -v


OpenVidu 서버 배포

포트 열어주기

# 포트 열기
sudo ufw allow 포트번호/tcp
sudo ufw allow 포트번호/udp

# 포트 상태 확인
sudo ufw status

OpenVidu 설치

cd /opt
sudo su
curl https://s3-eu-west-1.amazonaws.com/aws.openvidu.io/install_openvidu_latest.sh | bash

설정 파일 수정

cd /opt/openvidu
sudo vim .env
# /opt/openvidu/.env

DOMAIN_OR_PUBLIC_IP=<Linux 서버의 public ip 주소 또는 도메인>
OPENVIDU_SECRET=<사용할 비밀번호 입력>
CERTIFICATE_TYPE=letsencrypt 
LETSENCRYPT_EMAIL=<이메일>
HTTP_PORT=80
HTTPS_PORT=443
# HTTP_PORT와 HTTPS_PORT는 letsencrypt 방식의 키를 발급 받기 전까진 기본 포트인 80, 443을 사용해야 함.

OpenVidu 서버 실행

sudo ./openvidu start

적어준 도메인으로 들어가보면..!

Username: admin

Password: 비밀번호

** 실행 후 기본 포트

HTTP : 8880

HTTPS: 8443

으로 변경해줬다.


NGINX

설치

sudo apt install nginx

certbot 설치

sudo add-apt-repository ppa:certbot/certbot # certbot을 위한 저장소 추가
sudo apt install python3-certbot-nginx      # certbot nginx 패키지 설치

certbot 이용해 SSL 인증서 발급

sudo certbot certonly --nginx -d <도메인 주소>

요청이 너무 많아서 캘리포니아 시간 기준으로 저 시간 지나서 다시 하라고 함..^^;

~ 2월 5일 오전 8시가 된 후 ~

설정 파일 생성

sudo vim /etc/nginx/sites-available/nginx-settings.conf
# /etc/nginx/sites-available/nginx-settings.conf

server {
    location / {
        proxy_pass http://localhost:3000;
    }

    location /api {
        proxy_pass http://localhost:8081/api;
    }

    location /ws-stomp {
        proxy_pass http://localhost:8081/api/ws-stomp;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }

    location /oauth2 {
        proxy_pass http://localhost:8081/oauth2;
    }

    location /login {
        proxy_pass http://localhost:8081/login;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/<도메인>/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/<도메인>/privkey.pem; # managed by Certbot
    # include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    # ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = <도메인>) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name <도메인>;
    return 404; # managed by Certbot
}

sites-enabled에 심볼릭 링크 생성

sudo ln -s /etc/nginx/sites-available/nginx-settings.conf /etc/nginx/sites-enabled
  • 심볼릭 링크 제거

      cd /etc/nginx/sites-enabled
      sudo rm <제거할 파일>

NGINX 실행 테스트

sudo nginx -t

NGINX 실행, 중지, 상태

sudo systemctl start nginx
sudo systemctl restart nginx # 설정 파일 변경 후엔 restart를 해줘야 한다.
sudo systemctl stop nginx
sudo systemctl status nginx

Docker에 React 프로젝트 이미지 올리기

리액트 프로젝트 루트 디렉토리에 Dockerfile 생성

# nginx 이미지를 사용. 뒤에 tag가 없으면 latest 를 사용.
FROM nginx

# root 에 app 폴더를 생성
RUN mkdir /app

# work dir 고정
WORKDIR /app

# work dir 에 build 폴더 생성 /app/build
RUN mkdir ./build

# host pc의 현재경로의 build 폴더를 workdir 의 build 폴더로 복사
ADD ./build ./build

# nginx 의 default.conf 를 삭제
RUN rm /etc/nginx/conf.d/default.conf

# host pc 의 nginx.conf 를 아래 경로에 복사
COPY ./nginx.conf /etc/nginx/conf.d/nginx.conf

# 80 포트 오픈
EXPOSE 80

# container 실행 시 자동으로 실행할 command. nginx 시작함
CMD ["nginx", "-g", "daemon off;"]

React 프로젝트 루트 디렉토리에 nginx.conf 파일 생성

server {
    listen 80;
    location / {
        root    /app/build;
        index   index.html;
        try_files $uri $uri/ /index.html;
    }
}

Docker에 Springboot 프로젝트 이미지 올리기

Springboot 프로젝트 루트 디렉토리에 Dockerfile 생성

# 베이스 이미지
FROM openjdk:17

# 컨테이너 외부와 컨테이너 내부를 연결시켜 저장된 데이터의 수명과 데이터를 생성한 컨테이너의 수명을 분리
VOLUME /tmp

# 외부 호스트 8081 포트로 노출
EXPOSE 8081

# 이미지 생성 시 파일 복사
COPY build/libs/*.jar application.jar

# 컨테이너의 어플 지정
CMD ["java", "-jar", "application.jar"]

Jenkins 설치

자바 설치

sudo apt-get update
sudo apt-get install openjdk-17-jre

젠킨스 설치

  • 8080 포트 열기

  • Jenkins Debian Packages

      sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
          https://pkg.jenkins.io/debian/jenkins.io-2023.key
    
      echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
          https://pkg.jenkins.io/debian binary/ | sudo tee \
          /etc/apt/sources.list.d/jenkins.list > /dev/null
    
      sudo apt-get update
    
      sudo apt-get install fontconfig openjdk-17-jre
    
      sudo apt-get install jenkins

    [참고] https://pkg.jenkins.io/debian/

  • Jenkins 설치 확인

      sudo systemctl status jenkins

젠킨스 실행

  • http://도메인:8080 접속

    • 접속이 안 된다면? 주소가 https로 리다이렉트 되었는지 확인해보자..
    • 크롬 시크릿 모드로 접속하기…
  • 초기 비밀번호

      sudo cat ~/my-jenkins/jenkins_home/secrets/initialAdminPassword
  • 추천 플러그인 설치

  • 계정 만들기

젠킨스 플러그인

  • Jenkins 관리 - 플러그인 설치

    • GitLab, Publish Over SSH, NodeJS, Mattermost Notification, SSH Agent, Docker
  • Jenkins 관리 - Tools - Gradle, NodeJS Install (프로젝트 버전에 맞게)

    gradle 8.5

    nodejs 20.11.0


Jenkins GitLab 연결하고 웹훅 설정하기

토큰 생성

  • GitLab - Repository - Settings - Access Tokens

  • GitLab - 프로필 - Preferences - Access Tokens - Add new token

젠킨스 설정

  • Jenkins 관리 - 시스템 설정 - Gitlab

    • GitLab connections

      • GitLab host URL: 깃랩 메인 주소?
    • Add Credentials

      위에서 발급 받았던 토큰 넣어주기!

    • Test Connection

      성공!

젠킨스 Webhook 설정

  • 젠킨스 - 새로운 item - PipeLine

  • Configure - Build Triggers

    • Build when a change is pushed to GitLab.

      여기서 GitLab Webhook URL 기억해두기.

    • 고급 - Secret Token 생성

깃랩 Webhook 설정

  • Repository - Settings - Webhooks

    위에서 생성된 URL, Secret Token 입력

  • Test

    Push events 발생시켜보자.

    성공하면 저렇게 뜬다.


파이프라인 스크립트 작성

키 추가

  • item - Pipeline

  • Pipeline Syntax

    • Sample Step: git
    • Repository URL 입력
    • Branch 입력
    • Add
      • Kind: Username with password
      • Username: 깃랩 아이디 (이메일)
      • Password: 깃랩 개인 토큰
  • Generate Pipeline Script

  • 만들어진 credentialsId 복사해두기 (나는 직접 지정해줬다.)

스크립트 작성

pipeline {
    agent any

    tools {
        gradle "gradle"
        nodejs "nodejs"
    }

    stages {
        stage('clone'){
            steps{
                git branch: '-', credentialsId: '-', 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'
            }
        }
    }
}
  • push 이벤트 발생 → git clone → front & back build → deploy

docker-compose.yml

# /var/lib/jenkins/workspace/crazy-alcade/docker-compose.yml

version: "3"
services:
  nginx:
    build:
      context: ./frontend
    ports:
      - 3000:80 # 로컬포트:컨테이너포트
    depends_on:
      - spring

  spring:
    build:
      context: ./backend
    environment:
      - 환경변수=값
    ports:
      - 8081:8081 # 로컬포트:컨테이너포트

프론트 환경변수는 프론트 폴더 안에 파일 하나 만들어서 넣어줬다.

결과

웹훅을 걸어준 브랜치에 push 이벤트를 날리면 젠킨스가 자동 빌드 & 배포를 시작한다.

  • 트러블 슈팅

      + sudo docker-compose up -d --build
      validating /var/lib/jenkins/workspace/crazy-alcade/docker-compose.yml: services.nginx.environment must be a mapping

    중간에 계속 이런 오류가 뜨면서 deploy 단계에서 막혔다.

    docker-compose.yml 파일을 열어보니 프론트 부분에 환경변수를 설정해줬다가 지웠는데, environment: 가 지워지지 않아서 생긴 오류였다. 🧐

Mattermost 알림 보내기

배포 결과를 mm으로 알림을 보내보자.

  • mattermost - 통합 - imcoming webhook - 추가

  • Jenkins 관리 - 시스템

    채널명은 잘못 적음.

  • 파이프라인 스크립트 deploy 단계에 메시지 알림을 추가해준다.

      stage('deploy'){
          steps{
              sh 'sudo docker-compose up -d --build'
              mattermostSend color: '#32a852', message: "Deploy End! (${env.JOB_NAME}) #(${env.BUILD_NUMBER}) (<${env.BUILD_URL}|Open>) \n See the (<${env.BUILD_URL}console|console>)"
          }
      }
  • Deploy에 성공하면 알림이 온다. ^_^