포트폴리오 프로젝트에서 Jenkins와 Docker를 활용한 CI/CD 구축하기

Mini_me·2023년 8월 16일
0

공부 [Spring]

목록 보기
25/27
post-thumbnail

이번 포스트에서는 제 포트폴리오 프로젝트에서 Jenkins와 Docker를 사용하여 어떻게 CI/CD를 구축한지, 그 과정에서 겪은 여러 문제들과 그 해결 과정에 대해 이야기해보려고 합니다.

그전에 제가 왜 Jenkins와 Docker을 통해서 CI/CD를 구축하게 되었는지에 대해 말씀드리겠습니다.
Jenkins와 Docker을 도입한 이유는 간단합니다.
"번거로웠고, 귀찮은" 작업이였습니다.

매번 브랜치에서 작업한 내용들을 main 브랜치로 merge하고, main 브랜치로 merge 한 이후에는 서버에 접속하여 쉘 스크립트를 실행시켜 빌드 하고 배포하는 과정이 반복되다 보니깐 귀찮고, 번거롭다는 생각이 들었습니다.
그래서 Jenkins와 Docker을 도입하여 이 과정을 자동화하자라는 생각이 들어, 공부하게 되었고, 프로젝트에도 적용하게 되었습니다.

이 포스팅은 jenkins 서버와 운영서버를 구축하며 발생한 오류에 대해서 다루고, 서버를 어떻게 설치하고, 서버내에 docker 설치, jenkins설치, jenkins 기본설정 등에 대해서는 다른 블로그들에 정보가 많기 때문에 약소하게 다룰 예정입니다.

먼저, CI/CD란 무엇인지 간략하게 설명하겠습니다.

CI/CD는 지속적 통합(Continuous Integration)과 지속적 배포(Continuous Deployment)를 의미하는데, 이는 개발자들이 작업한 코드를 지속적으로 통합하면서 빠르고 효율적으로 어플리케이션을 빌드, 테스트, 배포할 수 있는 프로세스입니다.

  1. 프로젝트의 기본 구조
  • 백엔드: Spring Boot
  • 데이터베이스: MySQL
  • 버전 관리: Git
  • CI/CD: Jenkins
  • 컨테이너화: Docker
  1. Jenkins와 Docker를 활용한 CI/CD 구성

Jenkins와 Docker를 사용해 CI/CD를 구성하는 주요 단계는 다음과 같습니다.

  1. Jenkins 서버 구축
  2. 소스코드 변경 감지를 위한 Webhook 설정
  3. 컨테이너 이미지 빌드 및 배포 자동화

그러면 이제 구체적인 과정을 조금 더 디테일하게 살펴보겠습니다.

사진으로만 생략한 단계의 경우, 다른 블로그들에도 많이 나와있는 경우이기 때문에, 이 글은 현재 프로젝트의 CI,CD 구성을 어떻게 했고, 구성을 할때 만난 오류들을 기록하기 위해 작성하였습니다.

cloud.png

  1. github로 push
  2. github webhooks 이용하여 jenkins server에 변화를 전달
  3. jenkins에서 아래 단계들 실행
    1. 소스코드 clone
    2. 테스트 및 빌드 실행
    3. Dockerfile 이용해서 Docker 이미지 만들고 Docker hub에 push
    4. CD 를 위해 운영 서버로 도커 이미지 pull 받아오고 run 함
    5. 운영용 서버에서 docker로 스프링 부트 실행

I. Jenkins 서버 구축

우선, Jenkins 서버를 셋팅하기 위해서는 Jenkins가 설치된 도커 이미지를 사용하거나 직접 호스팅한 서버에 설치하여 구축해야 합니다. 이 작업을 통해 Jenkins를 통해 코드를 빌드하고, 테스트하며, 배포할 수 있는 환경을 마련합니다.

Oracle Cloud 서버 두개를 활용하여 구성하였습니다

Oracle linux server로 구성

  1. Server에 java 및 docker 설치
    1. 도커 설치
//패키지 업데이트
sudo yum -y upgrade

//도커 설치
sudo yum -y install docker

//도커 설치 작업이 잘 되었는지 버전 확인
docker -v

//도커 시작
sudo service docker start

//도커 그룹에 사용자 추가 -> docker가 그룹명, opc가 사용자명
sudo usermod -aG docker jenkins

Docker in Docker 방식으로 진행하였다.

😵‍💫 트러블 슈팅

1. 젠킨스 플러그인 설치 오류

도커에서 jenkins 이미지를 pull 받아와 run 한 후, 플러그인을 설치할려했는데

자꾸만 거의 모든 플러그인이 설치가 되지않는 오류를 겪었습니다.

계속 다시 시도해봐도 똑같이 플러그인이 설치가 안되서 해당 방법은 포기했으나

해결책을 찾았습니다.

서버에서는 자바 17버전을 설치햇는데, pull받아온 jenkins는 기본적으로 자바 11버전이기 떄문에

sudo docker run -d --name jenkins -p 8080:8080 jenkins/jenkins:jdk17

자바 17버전을 pull 받아와 실행했더니 해결되었습니다..

2. 오류: Exception in thread "main" java.lang.RuntimeException: Wrapper properties file '/var/jenkins_home/workspace/PortfoGram/gradle/wrapper/gradle-wrapper.properties' does not exist.

해결책: gradle-wrapper.properties 파일이 존재하지 않는 문제입니다.

해당 파일이 있는지 확인하고, 없다면 프로젝트 구성 시 Gradle Wrapper를 생성해야 합니다.

gradle wrapper

저의 경우에는,. 기존 로컬 스프링 프로젝트의 gradle-wrapper.properties 파일을 복사하여

젠킨스 서버에 복붙하여 해결했습니다.

cd ./wrapper

touch gradle-wrapper.properties

sudo vi gradle-wrapper.properties

3. 오류: ERROR: JAVA_HOME is set to an invalid directory: /usr/lib/jvm/java-17-openjdk-amd64 Please set the JAVA_HOME variable in your environment to match the location of your Java installation.

해결책: JAVA_HOME 환경 변수가 잘못 설정된 것입니다. 올바른 Java 설치 경로로 환경 변수를 변경하여 해결했습니다.

export JAVA_HOME=/usr/lib/jvm/java-<version>-<vendor>

4. 오류: chown: changing ownership of './build/classes/java/main/com/api/PortfoGram/Image/dto/Image$ImageBuilder.class': Operation not permitted

해결책: 권한 문제입니다.

Jenkins 사용자에게 충분한 권한을 부여하거나 루트 권한으로 해당 명령어를 실행하여 해결했습니.

sudo chown -R jenkins:jenkins ./build

5. 오류: docker build -t minimeisme/porfogram:0.1.0 ERROR: "docker buildx build" requires exactly 1 argument. See 'docker buildx build --help'.

해결책: 이 오류는 빌드 명령어의 오타 때문입니다. docker 사용할 때마다 자주 저지르는 실수인데,

docker build 마지막에 마침표를 찍어야합니다.

docker build -t minimeisme/porfogram:0.1.0 .

6. 오류: ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? Build step 'Execute shell' marked build as failure

해결책: Docker 데몬이 실행 중인지 확인하고, 실행되지 않았다면 다음 명령어로 Docker 데몬을 시작해야 합니다.

sudo systemctl stop docker
sudo systemctl start docker

II. 소스코드 변경 감지를 위한 Webhook 설정

Git 저장소에 Webhook을 설정하여 소스코드에 변동 사항이 있을 경우, 이를 Jenkins 서버에 알려주도록 합니다. 이를 통해 변경 사항을 자동으로 감지하고 빌드 및 배포 프로세스를 자동으로 실행하게 됩니다.

III. 코드 통합 및 테스트 자동화

Jenkins에서 코드를 빌드하고 테스트하기 위한 파이프라인 스크립트를 작성합니다.
이번 프로젝트의 경우 Jenkins를 처음 도입해봐서, 파이프라인 스크립트가 아닌 FreeStyle로 구성하여 Execute shell을 사용하였습니다.

IV. 컨테이너 이미지 빌드 및 배포 자동화

Docker를 사용해 프로젝트를 컨테이너화합니다. 이를 통해 프로젝트의 전체 환경을 효과적으로 관리할 수 있게 됩니다. 빌드된 이미지에 대해 이미지를 배포할 수 있도록 설계합니다.

마치며

이제는 더이상 귀찮게 제가 main에 merge될때마다 직접 쉘 스크립트를 실행시키고, 빌드하고, 배포할 필요가 없어졌습니다.
이 과정을 통해서, main에 merge할 경우, 자동으로 build 하고, 자동으로 도커 이미지를 생성하고, 자동으로 도커 허브에 pull하고 운영서버에서는 도커 허브에서 pull 받아와 자동으로 docker을 실행시킬수 있게 되었습니다.

귀찮음과 번거로웠던 작업이 자동화가 되어버리니, 본질적인 개발 및 모니터링 등 다른 반복적이지 않은 작업에 대해 집중할 수 있는 효율성을 얻을 수 있었던 경험이였습니다.

1개의 댓글

comment-user-thumbnail
2023년 8월 16일

이렇게 유용한 정보를 공유해주셔서 감사합니다.

답글 달기