[INFRA] Jenkins로 배포 자동화

양시온·2023년 10월 29일
0
post-thumbnail
post-custom-banner

Jenkis Pipeline을 활용한 배포 자동화 후기

EC2서버에 Nginx+SSL로 https, Docker를 활용해 수동 배포가 완료된 시점부터 시작하겠습니다.


1. Jenkins 이미지 다운로드

Docker환경에서 Jenkins를 활용할것이기 때문에 Docker Image를 받아 줍니다.
프로젝트가 Java17버전을 활용했기에 다음과 명령어 입력

docker pull jenkins/jenkins:jdk17

2. Jenkins 컨테이너 실행

  • 가독성을 위해 줄바꿈했는데, 줄바꾸지 말고 사용할 것
  • 각 옵션은 상황에 맞게 변경하세요
docker run -d --env JENKINS_OPTS=--httpPort=8080 -v 
/etc/localtime:/etc/localtime:ro -e TZ=Asia/Seoul -p 8080:8080 -v 
/jenkins:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v 
/usr/local/bin/docker-compose:/usr/local/bin/docker-compose
--name jenkins -u root jenkins/jenkins:jdk17

3. Jenkins접속

  • 8080포트로 열어줬기 때문에, 주소 뒤에 :8080으로 jenkins로 접속
  • 접속을 하면 비밀번호를 치라고 나오는데 다음과 같이 비밀번호를 확인할 수 있다.
docker exec -it jenkins /bin/bash
cd /var/jenkins_home/secrets
cat initialAdminPassword
  • 로그인을 완료했다면 왼쪽(Install suggested plugins)을 클릭해서 Install한다.
  • 모든 사항이 이상이 없는 초록색이 나와야 한다. 하나라도 빨간색이 나온다면 뭔가 잘못됐다는것이니 처음부터 다시 해보길 추천 드립니다.

4. Jenkins 내부 docker설치

docker exec -it jenkins /bin/bash

# Docker Repository 등록 및 docker-ce 패키지 설치
docker exec -it jenkins /bin/bash

apt-get update && apt-get -y install apt-transport-https ca-certificates curl gnupg2
software-properties-common && curl -fsSL
https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey;
apt-key add /tmp/dkey && add-apt-repository "deb [arch=amd64]
https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")
$(lsb_release -cs) stable" && apt-get update && apt-get -y install docker-ce

5. Docker Jenkins에서 HOST docker 접근권한 부여

groupadd -f docker
usermod -aG docker jenkins
chown root:docker /var/run/docker.sock

6. Jenkins 플러그인 설치

  • 다음 플러그인을 Jenkins관리 - plugins에서 설치한다.
# ssh 커맨드 입력에 사용
SSH Agent

# docker 이미지 생성에 사용
Docker
Docker Commons
Docker Pipeline
Docker API

# 웹훅을 통해 브랜치 merge request 이벤트 발생시 Jenkins 자동 빌드에 사용
Generic Webhook Trigger

# 타사 레포지토리 이용시 사용 (GitLab, Github 등)
GitLab
GitLab API
GitLab Authentication
GitHub Authentication

7. Gitlab Credential 등록

  • Jenkins관리 - Credentials - Add Credentials
kind: Username with password
Username : Gitlab ID
Password : Gitlab Token
ID : 내 마음대로 정하기(나는GitLab이라고 설정)

8. Gitlab 커넥션 추가

  • Jenkins관리 - System - Enable authentication for ‘/project’ end-point
Connection name : Gitlab 커넥션 이름 지정
Gitlab host URL : Gitlab 시스템의 Host 주소 입력
Credentials : 조금 전 등록한 Jenkins Credential을 선택
Test Connection을 눌러 Success가 뜨면 저장

9. 파이프라인 생성

  • 파이프라인을 생성하고 토큰을 발행해서 이 토큰으로 GitLab 웹훅을 감지한다.
생성시 다음 체크(상황에 맞게 변경)
General - Build Triggers
        - Build when a change is pushed to Gitlab 체크
        - Push Events 체크
        - Opened Merge Request Events 체크
        - Approved Merge Request (EE-only) 체크
        - Comments 체크
        
고급 - Generate 클릭
Secret Token복하해두고 저장하면 파이프라인이 생성 된다.

10. Gitlab Webhook 지정

  • Gitlab 프로젝트로 들어가서 왼쪽 아래 Webhook 클릭
  • Settings - Webhook - Add new webhook
- URL : Jenkins의 Item URL 입력
  양식 : `http://[Jenkins Host]:[Jenkins Port]/project/[파이프라인 아이템명]`
- Secret token : 방금 전 파이프라인의 토큰
- Trigger : Push events(나는 push될때마다 빌드했는데, 알아서)
  그리고 Regular expression를 활용해서 브랜치 구분을 해준다.
  • 완료 후 Gitlab에서 Test해보고, Jenkins에서도 잘 됐나 확인을 꼭 해줘야 한다.

11. DockerHub 토큰 생성

  • 여기서 끝이 아니라 DockerHub를 위해 토큰도 만들어줘야 한다...
  • 로그인 - Account Settings - Security - New Access Token
  • 알다시피 토큰발행후 꼭 복사 해 놓아야 한다.

12. Docker Hub 레포지토리 생성

  • Repositories - Public

13. Docker Hub Credential 추가

  • Jenkins관리 - Credentials
  • 7번의 과정과 동일하게 작성(DockerHub ID 기준)

14. Ubuntu Credential 추가

  • 여기서 끝이 아니다... Ubuntu Credential도 추가해줘야 한다.
  • Jenkins관리 - Credentials
이번엔 kind: Username with password가 아닌
kind : SSH Username with private key
ID : 내맘대로
Username : SSH 원격 서버 호스트에서 사용하는 계정명 입력

Enter directly - Add 클릭
AWS *.pem 키값 그대로 복사 붙여넣기

15. 드디어 Pipeline Script

  • 아까 파이프라인 생성해둔 것 - 왼쪽 구성 클릭
  • 맨아래로 내리면 Pipeline Script를 작성할 수 있다.
  • 나는 다음과 같이 Pipeline Script를 작성했다.
  • 아래 Pipeline Script를 천천히 확인해보면 앞선 과정이 왜 필요한지 알 수 있게 된다.
  • 아래는 백엔드 파이프라인인데, 각 상황에 맞게 잘 변경해서 쓰면 된다.
  • 시도 -> 실패 -> Console확인 반복반복하면 꼭 성공할 수 있습니다. 화이팅!!
pipeline {
    agent any 

    // 환경 변수 설정
    environment {
        registryCredential = 'DockerCredential을 적어준다'
        dockerImage = '도커이미지를 적어준다'
        releaseServerAccount = 'ubuntu'
        releaseServerUri = '배포주소를 넣어준다(http빼고)'
    }

    stages {
        stage('Git Clone') {
            steps {
                git branch: 'BE-api/develop',
                # 각 브랜치에 맞게 수정
                    credentialsId: 'Gitlab Credential넣기', 
                    url: 'https://lab.ssafy.com/s09-final/S000000000'
            }
            post {
                failure {
                    echo '=============\n Git Clone 실패\n============='
                }
            }
        }

        stage('Jar Build') {
            steps {
                dir ('Gradlew파일 있는 곳으로 이동') {
                    sh 'chmod +x ./gradlew'
                    sh './gradlew clean bootJar'
                }
            }
            post {
                failure {
                    echo '=============\n Jar Build 실패\n============='
                }
            }
        }

        stage('Build Docker image') {
            steps {
                script {
                    dir('apiService') {
                        sh "docker build -t $dockerImage ."
                    }
                }
            }
            post {
                failure {
                    echo '=============\n Docker 이미지 빌드 실패\n============='
                }
            }
        }

        stage('Push Image to DockerHub') {
            steps {
                script {
                    docker.withRegistry('', registryCredential) {
                        sh "docker push $dockerImage"
                    }
                }
            }
            post {
                failure {
                    echo '=============\n DockerHub 푸시 실패\n============='
                }
            }
        }

        stage('Deploy to EC2') {
            steps {
                sshagent(credentials: ['우분투credential넣기']) {
                    sh """
                    ssh -o StrictHostKeyChecking=no $releaseServerAccount@$releaseServerUri 'docker stop 도커이미지|| true && docker rm 도커이미지|| true'
                    """
                    sh """
                    ssh -o StrictHostKeyChecking=no $releaseServerAccount@$releaseServerUri 'docker pull $dockerImage && docker run -d -p 포트:번호 --name 도커이미지 $dockerImage'
                    """
                }
            }
            post {
                failure {
                    echo '=============\n EC2 배포 실패\n============='
                }
            }
        }
    }

    post {
        success {
            echo '=============\n 성공성공성공성공\n============='
        }
        failure {
            echo '=============\n 실패실패실패실패\n============='
        }
    }
}
profile
병아리개발자🐤
post-custom-banner

0개의 댓글