🐳 Docker

EC2의 Docker 안에 Jenkins Container 올리기 (feat. Webhook CI/CD 구축 & DooD)

MNY 2024. 10. 11. 15:51
728x90
반응형
Keyword

1. DooD

2. docker network

 

Flow

1. 새로운 EC2 인스턴스 생성 -> 젠킨스만

2. docker 설치

3. docker 컨테이너 젠킨스 실행

4. 서브 도메인 세팅

5. 젠킨스 Webhook 연결

6. 파이프라인 작성 후 배포 확인

 

 EC2 인스턴스 설정 

EC2 인스턴스 설정

용량: 최소 100GB

EC2 인스턴스 생성:

  • AWS 콘솔에 로그인하고 EC2 서비스를 선택합니다.
  • "인스턴스 시작" 버튼을 클릭하여 새로운 인스턴스를 생성합니다.
  • Ubuntu AMI를 선택합니다.
  • 인스턴스 유형을 선택합니다 (t2.micro는 무료 티어로 사용할 수 있습니다). → t2.medium.
  • 키 페어를 설정하고 다운로드합니다.
  • 인스턴스를 시작합니다.

보안 그룹 설정:

  • SSH (포트 22), HTTP (포트 80), HTTPS (포트 443) 및 애플리케이션 포트 (예: 8080)를 허용합니다.

 

Docker 설치

* jenkins 실행을 위해 새로 만든 EC2 인스턴스에서 진행

시스템 업데이트 및 업그레이드:

sudo apt update -y
sudo apt upgrade -y

 

Docker 설치:

sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER

 

DooD를 이용한 Jenkins 실행 

* jenkins 실행을 위해 새로 만든 EC2 인스턴스에서 진행

Jenkins용 Dockerfile 만들기

Dockerfile 생성:

vi Dockerfile

 

작업 모드로 변경: i

Dockerfile 작성:

FROM jenkins/jenkins:2.452.3

USER root
RUN apt-get -y update && \
     apt-get -y install apt-transport-https ca-certificates curl gnupg-agent software-properties-common && \
     curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - && \
     add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
     apt-get -y update && \
     apt-get -y install docker-ce docker-ce-cli containerd.io
RUN usermod -u  1000 jenkins && \
    groupmod -g 113 docker && \
    usermod -aG docker jenkins

USER jenkins

 

저장하고 나가기: ECS + :wq

 

Jenkins docker 실행

Jenkins docker 이미지 빌드:

  • 앞서 작성한 Dockerfile이 있는 디렉토리에서 빌드
docker build -t jenkins .

 

jenkins 컨테이너 실행:

docker run -d --name jenkins -p 8080:8080 -p 5000:5000 jenkins/jenkins:2.452.3

 

 DNS 설정 (서브 도메인 설정) 

도메인 등록 기관의 DNS 관리 페이지로 이동합니다.

새 CNAME 레코드를 추가합니다:

  • 이름: 원하는 서브도메인 (예: jenkins)
  • 값: EC2 인스턴스의 퍼블릭 DNS (예: ec2-xx-xx-xx-xx.compute-1.amazonaws.com)

변경 사항이 적용되기까지 몇 분 정도 소요될 수 있습니다.

[ route 53 예시 ]

 

 Jenkins 접속 및 초기 세팅 

Jenkins 접속

Jenkins 메인 페이지 접근 확인:

 

초기 관리자 비밀번호 얻기:

* 해당 과정은 Jenkins의 EC2 인스턴스에서 진행

docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

 

초기 세팅

추천 플러그인 설치:

가장 간단한 방법은 "Install suggested plugins" 옵션을 선택하는 것입니다. 이는 Jenkins 커뮤니티가 유용하다고 여기는 플러그인을 자동으로 설치합니다.

  • "Install suggested plugins" 클릭

 

 Github Webhook 설정 

Jenkins 관리 페이지에서 플러그인 설치

플러그인 설치 페이지로 이동:

  • Jenkins 메인 페이지에서 "Manage Jenkins" -> "Manage Plugins"로 이동

플러그인 설치:

  • "Available" 탭에서 "GitHub Integration Plugin"을 검색하여 설치합니다.
  • "Available" 탭에서 "Docker Pipeline" 플러그인을 검색하여 설치합니다.
  • 설치 후 재시작 중요!
    • jenkins EC2 인스턴스에 들어가서 jenkins 컨테이너 재시작
jenkins restart

 

GitHub 저장소에 Webhook 추가

GitHub 저장소로 이동하여 "Settings" -> "Webhooks"로 이동합니다.

"Add webhook"을 클릭하고 다음과 같이 설정합니다:

 

사진은 아직 연결되지 않은 상태
→ 초록색 아이콘으로 변경되어야 연결 완료!

 

Jenkins Pipeline 생성 

Pipeline 생성

Jenkins 메인 페이지에서 "New Item"을 클릭하고 새 Job을 생성

 

 

"GitHub project" 옵션을 활성화하고 GitHub 저장소 URL을 입력

 

"Build Triggers" 섹션에서 "GitHub hook trigger for GITScm polling"을 선택

 

Pipeline 스크립트 작성 : 다음 단원에서 자세하게 다룰 예정

설정 저장:

  • 모든 설정이 완료되면 Save 버튼을 클릭하여 설정을 저장

 

 Pipeline script 작성 

전체적인 흐름도

  • 깃클론
  • gradle build
  • jar 파일과 dockerfile을 특정 경로로 이동
  • 환경변수 파일 작성
  • dockerfile을 이용해서 이미지 빌드(태그) → 현재 미적용된 내용
  • 빌드된 이미지 도커 허브에 push
  • ec2 인스턴스에 접속(제일 처음 만들었던 ec2)
  • 현재 동작 중인 docker-compose 중지
  • 도커 허브의 이미지 pull
  • 새로 받은 이미지로 docker-compose 시작
  • Jenkins의 메인화면에서 방금 만들었던 pipeline을 선택
  • 왼쪽 목록에서 “configure” 선택

 

Pipeline script 작성:

pipeline {
    agent any

    environment {
        // Docker Hub credentials
        DOCKER_HUB_CREDENTIALS = 'docker-hub-credentials'
        DOCKER_HUB_REPO = 'ysy561356/today-space-back'
        DOCKER_CONTAINER = 'today-space-back'
        
        // Github credentials
        GIT_CREDENTIALS_ID = 'github-token'
        GIT_BRANCH = 'release'
        GIT_URL = 'https://github.com/today-space/today-space-back.git'
        
        // EC2
        SSH_CREDENTIALS_ID = 'ec2-ssh-key'
        EC2_USER = 'ubuntu'
        EC2_DOMAIN = 'back.today-space.com'
        
        // DB
        DB_URL = 'jdbc:postgresql://postgresql.today-space.com:5432/space'
        DB_USERNAME = 'youngju'
        DB_PASSWORD = '4564'
        
        // JWT
        JWT_SECRET_KEY = '7Iqk7YyM66W07YOA7L2U65Sp7YG065+9c3ByaW5n7Ius7ZmU7KO87LCo7JWE7JuD7IaM7Iux7ZSE66Gc7KCd7Yq47YyM7J2067iM66CI7KCE65Oc7YyAand0c2VjcmV0a2V5'
        JWT_ACCESS_TOKEN_EXPIRATION = 1800000
        JWT_REFRESH_TOKEN_EXPIRATION = 1209600000
        
        // Social Login
        KAKAO_REST_API_KEY = '6cd61cbdb917a1046bf437980b1e2ac9'
        NAVER_REST_API_KEY = 'mgvICujU1zvQrtz_IQOA'
        NAVER_REST_API_SECRET_KEY = 'drUb2lRtGb'
        GOOGLE_REST_API_KEY = '878062679505-oh34mk7fm5mpipprk9o139i8if40b3qf.apps.googleusercontent.com'
        GOOGLE_REST_API_SECRET_KEY = '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'
        
    }

    stages {
	      stage('Clone Git Repository') {
            steps {
                script {
                    // GitHub 저장소에서 코드 클론
                    git credentialsId: "${GIT_CREDENTIALS_ID}", branch: "${GIT_BRANCH}", url: "${GIT_URL}"
                    
                    // gradlew 파일에 실행 권한 부여
                    sh 'chmod +x gradlew'
                    
                    // Gradle 빌드
                    sh './gradlew build'
                    
                    // destination 디렉토리 생성
                    sh 'mkdir -p ../destination'
                    sh 'mkdir -p ../destination/build/libs'
                    
                    // JAR 파일과 Dockerfile을 특정 경로로 이동
                    sh 'cp build/libs/*.jar ../destination/build/libs'
                    sh 'cp Dockerfile ../destination/'
                }
            }
        }
			  stage('Prepare .env') {
		        steps {
		            script {
		                sh '''
		                touch ../destination/back.env
		                echo DB_URL=$DB_URL > ../destination/back.env
				            echo DB_USERNAME=$DB_USERNAME >> ../destination/back.env
			              echo DB_PASSWORD=$DB_PASSWORD >> ../destination/back.env
			              echo JWT_SECRET_KEY=$JWT_SECRET_KEY >> ../destination/back.env
			              echo JWT_ACCESS_TOKEN_EXPIRATION=$JWT_ACCESS_TOKEN_EXPIRATION >> ../destination/back.env
			              echo JWT_REFRESH_TOKEN_EXPIRATION=$JWT_REFRESH_TOKEN_EXPIRATION >> ../destination/back.env
			              echo KAKAO_REST_API_KEY=$KAKAO_REST_API_KEY >> ../destination/back.env
			              echo NAVER_REST_API_KEY=$NAVER_REST_API_KEY >> ../destination/back.env
			              echo NAVER_REST_API_SECRET_KEY=$NAVER_REST_API_SECRET_KEY >> ../destination/back.env
			              echo GOOGLE_REST_API_KEY=$GOOGLE_REST_API_KEY >> ../destination/back.env
			              echo GOOGLE_REST_API_SECRET_KEY=$GOOGLE_REST_API_SECRET_KEY >> ../destination/back.env
			              echo FRONT_URL=$FRONT_URL >> ../destination/back.env
			              echo KAKAO_PAY_SECRET_KEY=$KAKAO_PAY_SECRET_KEY >> ../destination/back.env
			              echo KAKAO_PAY_URL=$KAKAO_PAY_URL >> ../destination/back.env
			              echo KAKAO_PAY_CID=$KAKAO_PAY_CID >> ../destination/back.env
			              '''
		            }
		        }
		    }
		    stage('Build and Push Docker Image') {
		        steps {
		            script {
		                dir('../destination') { // 특정 경로로 이동
				                // docker 이미지 빌드
				                def dockerImage = docker.build("${DOCKER_HUB_REPO}:latest", "./")
				                
		                    // Docker Hub에 로그인
		                    withCredentials([usernamePassword(credentialsId: DOCKER_HUB_CREDENTIALS, usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
		                        sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
		                    }
		                    
		                    // docker 이미지 push
		                    dockerImage.push("latest")
		                }
		            }
		        }
		    }
        stage('Deploy') {
            steps {
                script {
                    withCredentials([sshUserPrivateKey(credentialsId: "${SSH_CREDENTIALS_ID}", keyFileVariable: 'SSH_KEY')]) {
                        def sshKey = env.SSH_KEY
                        
                        // 권한 변경
                        sh 'chmod 400 ' + sshKey
                        
                        // docker-compose down
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker-compose down"'
                        
                        // docker image pull
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker pull ${DOCKER_HUB_REPO}:${DOCKER_IMAGE_TAG}"' // 이미지 명시

                        // 새로운 docker-compose 시작
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker-compose up -d"'

                    }
                }
            }
        }
    }
    post {
        always {
            cleanWs()
        }
        success {
            echo 'Deployment successful!'
        }
        failure {
            echo 'Deployment failed!'
        }
    }
}

 

Credentials 생성

Jenkins 메인 화면에서 “Manage Jenkins” > “Credentials” > “global” > “Add Credentials”

Docker Hub credentials:

  • Kind : Username with password
  • Username : Docker Hub ID
  • Password : Docker Hub Password
  • ID : Jenkins에서 변수로 사용할 ID (ex: docker-hub-credentials)

Github credentials:

  • Kind : Username with password
  • Username : GitHub ID
  • Password : GitHub Token
  • ID : Jenkins에서 변수로 사용할 ID (ex: github-token)

EC2 credentials:

  • Kind : SSH Username with private key
  • ID :
  • Username : ubuntu
    • EC2 인스턴스의 hostname(기본적으로 linux라면 기본적으로 ubuntu)
  • Pricate Key : EC2 인스턴스 생성하면서 .pem 파일을 다운 받았을텐데 해당 파일을 열어보면 사진과 같이 나오는 글자들을 전부 복사 붙여넣기
    • 단, 마지막에 잘못해서 공백이 들어가면 안된다.
    • Mac : 터미널에서 cat [.pem 파일 마우스로 끌어서 터미널에 넣기]
    • window : 메모장으로 확인하는 게 편하다

 

참고 자료 

  • Credentials 생성
 

Jenkins Pipeline을 이용한 Docker Image Push

지난 글에 이어서 빌드된 이미지를 Docker Hub로 Push 해보려고 합니다. 빌드까지 정상적으로 이루어졌다면, jenkinsfile-build를 수정해주어야 합니다. 하지만 해당 글은 가이드이기 때문에 jenkinsfile-push

teichae.tistory.com

 

[Jenkins]Git 연동하기(Git Token 발급 + Jenkins Credential 등록)

안녕하세요 오늘은 git 에서 Token을 발급받아 Jenkins Credential에 등록해보겠습니다!먼저 Github Settings -> Developer settings -> Personal access token 항목에 들어갑니다 이후 Generate new

velog.io

 

[Jenkins] SSH 사용 - pipeline SSH Agent

[Jenkins] SSH 사용 - pipeline SSH Agent 작업 순서 SSH Agent 플러그인 설치 SSH 인증서 생성 jenkins에 ssh 인증 정보 등록 pipeline에서 ssh 사용하기 Bad configuration option 에러 발생시 1. SSH Agent 플러그인 설치 Jenkin

royleej9.tistory.com

 

  • Jenkins 사용
 

NGINX 무중단 배포

지금까지의 서비스는 새로운 Jar가 실행되기 전까진 기존 Jar를 종료시켜 놓기 때문에 서비스가 중단된다. 이를 해결하기 위해 우리는 엔진엑스를 이용해 '무중단 배포' 를 해볼 것이다 엔진엑스

dallae7.tistory.com

 

 

 

728x90
반응형