Jenkins ⇒ GitHub Actions

이건선·2023년 5월 13일
0

해결

목록 보기
33/48

CI/CD Jenkins ⇒ GitHub Actions

  1. Jenkins vs GitHub Actions?

    1. express sequelize를 CI/CD하기 위해서 Jenkins vs GitHub Actions 중에서 선택해야했다.

    2. 쉬운 방법으로 GitHub Actions를 선택 할 수있었지만 현재 디펙토에 가까운 프로그램이 Jenkins 라는 의견이 모아졌기 때문에 Jenkins를 채택했다. 호스트 서버에 Jenkins를 설치하는 방법은 두가지 있었는데

      1. 호스트 서버에 직접 설치하는 방법

      2. Docker를 설치하고 image를 이용하는 방법

        두 가지 다 해본결과 Docker의 image를 이용하는 편이 편리 했다. 그러나 Jenkins 플러그인 설치할 때 문제가 있었다.

        플러그인 설치 후 적용을 위해서 Jenkins 컨테이너를 재부팅하면 Jenkins 컨테이너가 초기화 되는 문제가 발생했다.

        조사해본 결과 Docker image로 Jenkins container구성시에 -v 볼륨 옵션으로 호스트 서버의 파일에 마운트함으로써 Jenkins 컨테이너가 재부팅 해도 데이터가 보존 될 수 있도록 설정해야 한다는 사실을 알았다. 그리고 Jenkins 컨테이너 내부에서 호스트의 Docker 데몬과 통신 할 수 있도록 -v /var/run/docker.sock:/var/run/docker.sock 옵션을 추가해야했다. 이 옵션은 컨테이너 안에서 도커 명령어를 실행할 수 있게 해준다.

  2. [ CI/CD 전략 Jenkins.Ver ] Jenkins선언적 파이프라인을 이용한 **CI/CD 플랜

    1. Git main repo에 merge 발생한다.

    2. Jenkins**web 후크로 이를 감지하고 repo의 main을 클론한다.

    3. Jenkins서버에서 클론을 바탕으로 Docker 이미지를 만들고 Jenkins의 빌드 환경변수를 Docker image에 입력해서 버전을 관리한다.

        IMAGE_TAG = "gunsun/realjeans:1.0.${env.BUILD_NUMBER}"
    4. 생성한 이미지를 Docker hub에 올린다.

    5. 각 서버는 프리티어로 만들어졌기 때문에 절대적으로 용량이 부족하다. 따라서 배포 서버에 존재하는 기존 Docker container를 stop하고 삭제하며 구버전 이미지도 삭제한다. 버전 관리는 Docker hub가 담당한다.

    6. EC2서버는 총 4개로 Nginx 서버, Jenkins 서버, 배포서버 2대이다.

    7. Nginx EC2서버에서 라운드로빈 방식을 취하고 있다.

    8. 서버가 2개 밖에 없기 때문에 롤링 방식으로 진행한다.

    9. 배포 서버는 각각 1번서버 2번서버로 분리되어있고 Nginx에서 각 서버를 10초마다 테스트 하고 서버가 살아있는 유무에 따라서 배포 순차적으로 진행 할 것이다.

    10. 일련의 과정을 Jenkins선언적 파이프라인 stage로 분할하고 성공하거나 실패하면 슬랙으로 팀원에게 알람이 전달된다.

    • 슬랙 알림 일부
    • 선언적 파이프라인 일부
    1. [문제점] Nest.js build를 못버티는 Jenkins EC2 프리티어 서버
      1. node.js express를 사용할 때는 문제가 없었다.

      2. 하지만 Nest.js로 마이그레이션을 마치고 테스트하자 CI/CD가 이루어지지 않았다.

      3. Nest.js의 빌드 과정에서 멈추는 문제가 발생했다. EC2 서버를 살펴보니 cpu 사용량 99.7%에 달했다.

      4. Docker의 이미지를 만들때 node 알파인 버전을 사용하면 빌드시에 필요한 메모리가 조금이라도 줄어들지 않을까 생각했는데 효과가 없었다.

      5. 왜 빌드 과정에서만 멈추는지 궁금해서 조사해봤다.

      6. NestJS는 TypeScript를 기반으로 하는 프레임워크다. TypeScript는 JavaScript의 상위 집합이며, 브라우저와 Node.js에서 기본적으로 이해할 수 없는 구문을 사용하기 때문에 NestJS 애플리케이션을 실행하기 전에는 TypeScript 코드를 JavaScript로 변환하는 빌드 과정이 필요하다는 것을 깨달았다.

      7. 이때문에 node.js express에서는 문제가 없었지만 Nest.js에서는 빌드 과정에 문제가 발생했던것

      8. 결국 TypeScript의 JavaScript 컴파일시에 근본적인 해결법은 램을 늘리는 것이었고 1GB를 제공하는 t2에서 2GB를 제공하는 t3.small로 티어를 올렸다.

      9. 그리고 Dockerfile에서 멀티 스테이지 빌드를 사용했다. 젠킨스 서버에서 빌드를 마친 이미지를 올림으로써 다른 서버에서는 빌드를 할 필요가 없게 만들었다.

      10. 성공은 했지만 프로젝트의 크기에 비해서 CI/CD에 소모되는 시간값이 컸다. 그리고 이것마저도 빌드의 안정성이 보장되지 않았고 빌드에 실패하는 경우가 대부분이었다.

    1. [해결 방법] 돌고 돌아 GitHub Actions 써야한다. 그리고 **버리기 아까운 Jenkins EC2서버

      1. 멘토님과 상담에서 이러한 고민을 질문했고, 근본적인 해결법은 EC2 서버의 사양을 늘리는 것이었다.
      2. 만약에 Jenkins EC2서버가 터지면 어떻게 해결할 것이냐는 질문을 던지셨다.
      3. Unstable Program을 신용 할 수 없었고 기존의 Jenkins 에서 GitHub Actions으로 CI/CD를 옮기기로 결정했다.
      4. GitHub Actions에서 제공하는 컴퓨터 스펙은 2-core CPU, 7 GB of RAM memory, 14 GB of SSD disk space로 기존의 Jenkins EC2서버를 상회했다. 비용적인 측면에서도 공개 repo의 경우 무료다.
      5. 이미 구성이 끝나있는 Jenkins 서버를 버리기는 아까워서 Jenkins에 헬스 체크 기능을 부여했다.
      6. Jenkins EC2서버의 선언적 파이프 라인 코드를 변경해서 main에 merge가 발생할 때, 각각 배포서버의 저장공간, docker image, docker container 상태를 확인하고 슬랙으로 정보를 보내는 임무로 변경했다.
      • Jenkins 선언적 파이프라인을 변경한 코드 일부
      • 서버의 health를 확인하는 Jenkins
    2. [ CI/CD 전략 GitHub_Actions.Ver ] GitHub Actions을 이용한 **CI/CD 플랜

      1. Git main repo에 merge 발생한다.

      2. Jenkins EC2서버는 main에 merge가 발생할 때, 각각 배포서버의 저장공간, docker image, docker container 상태를 확인하고 슬랙으로 정보를 보낸다.

      3. Git Hub Actions이 merge를 감지하고 이미지를 빌드해서 Docker hub에 올린다.

      4. 각 서버는 프리티어로 만들어졌기 때문에 절대적으로 용량이 부족하다. 따라서 기존의 docker container를 stop하고 삭제하며 기존의 구버전 이미지도 삭제한다. 버전 관리는 Docker hub가 담당한다.

      5. 서버가 2개 밖에 없기 때문에 롤링 방식으로 진행한다.

        run: |
                  docker stop realjeans;docker rm realjeans;docker rmi ${{ secrets.DOCKERHUB_USERNAME }}/realjeans:realjeans
        
                  docker pull ${{ secrets.DOCKERHUB_USERNAME }}/realjeans:realjeans
        
                  docker run -i -t --env-file /home/ubuntu/newJeans.env -d -p 3000:3000 --name realjeans ${{ secrets.DOCKERHUB_USERNAME }}/realjeans:realjeans
    3. [결과] GitHub Actions을 이용한 **CI/CD결과

      1. 압도적인 성능개선 효과가 있었다. build 발생시 메모리 부족으로 build가 되지 않던 불안정한 배포 상태가 해결되었고 배포 시간도 5배 이상 줄어들었다.

    4. [결론] Jenkins vs GitHub Actions!

      1. Jenkins
        1. 장점
          1. 무료로 이용이 가능하다.
          2. 선언적 파이프라인이나 Groove문법을 이용한 파이프라인의 작성으로 세밀한 조정이 가능하다.
          3. Blue Ocean Plugin , Git Parameter Plug-In, Slack Notification Plugin같은 ****다양한 플러그인으로 유용하게 커스텀 할 수있다.
          4. 서버의 사양에 따라서 성능이 증가 할 수있다.
        2. 단점
          1. 스타팅이 굉장히 어렵고 난이도가 높다.
          2. 호스트 서버에 어떻게 어떤식으로 설치할것인가 부터 시작한다. 그리고 배포하는 서버에 PUB KEY를 넘겨주고 SSH키를 가져와서 Jenkins서버에 등록하고, Git Web후크를 위한 토큰 준비해야하며 배포 서버에 선언적 파이프라인을 사용해서 배포 서버에 접속하기 위해서 SSH 플러그인도 설치해야 한다. 그리고 선언적 파이프라인을 사용하기 위해 sh지식도 약간이나마 있어야한다.
          3. Jenkins를 사용하기 위해서 호스트 서버가 필요하고 이 호스트 서버의 사양이 낮다면 배포에 실패 할 수 있다.
      2. GitHub Actions
        1. 장점
          1. GitHub Actions에서 서버를 제공하고 EC2 프리티어에 비해서 성능이 압도적으로 뛰어나다. 쓰고있는 서버가 좋지않다면 GitHub Actions은 좋은 선택이다.
          2. 여러 설정과 설치법이 필요한 Jenkins에 비해서 상대적으로 쉽게 사용할 수 있고 배포 서버에 연결하는 방법이 간단하다.
          3. workflows를 IDE에서 작성 할 수 있다. 따라서 Jenkins 서버에서 작성해야하는 pipeline script에 비해 상대적으로 친숙하다.
        2. 단점
          1. 프로젝트가 큰 규모의 프로젝트라면 GitHub Actions의 사양으로는 감당하기 어려워진다.
          2. repo가 퍼블릭이 아니라면 시간과 용량제한이 있고 비용을 지불해야 한다.
profile
멋지게 기록하자

0개의 댓글