본문 바로가기
카테고리 없음

Jenkins를 이용한 Docker 빌드/배포

by ^..^v 2022. 3. 27.
728x90
반응형

스프링 부트 기반의 애플리케이션을 도커 이미지화하여 도커 허브에 등록하고, 해당 이미지를 이용해서 EC2 인스턴스에서 컨테이너로 실행합니다. 

소스 코드 통합 및 배포를 위해 젠킨스를 이용하며 빌드 도구로 그레들을, 도커 이미지 생성 및 등록을 위해서 Jib 라이브러리를 사용합니다. 

 

 

 

프로젝트 생성

깃허브 레포지토리 생성




레포지토리 복사

C:\java> git clone https://github.com/naanjini/springboot-to-ec2.git
Cloning into 'springboot-to-ec2'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.




프로젝트 파일 생성




프로젝트 파일 임포트

 

 

 




애플리케이션 코드 작성

참고 

https://myanjini.tistory.com/entry/Jib%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9E%90%EB%B0%94-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EB%B9%8C%EB%93%9C

 

도커 이미지 생성 및 등록에 필요한 정보를 파라미터로 받아서 처리하도록 build.gradle 내용을 수정합니다.

plugins {
	id 'org.springframework.boot' version '2.6.5'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
	id 'com.google.cloud.tools.jib' version '3.1.4'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

jib {
    to {
        image = project.findProperty("docker.repository") + "/" + project.findProperty("docker.image.name")
        tags = [project.findProperty("docker.image.tag")]
        auth {
            username = project.findProperty("docker.repository.username")
            password = project.findProperty("docker.repository.password")
        }
    }
}





Jenkinsfile 생성

https://www.jenkins.io/doc/book/pipeline/jenkinsfile/

 

깃허브로부터 소스코드를 가져와서 빌드하고, jib를 이용해서 도커 이미지를 생성해서 도커 허브에 등록한 후 EC2 인스턴스로 SSH 접속해서 도커 컨테이너를 실행하는 동작을 기술한 Jenkinsfile을 생성합니다. 

dockerRepository 변수의 값으로는 본인의 도커 계정의 이름을, deployHost 변수의 값으로는 도커 컨테이너를 실행할 EC2 인스턴스의 퍼블릭 IP 주소를 입력합니다.

def dockerRepository = "myanjini"
def dockerImageName = "myspringbootapp"
def deployHost = "34.216.38.245"

pipeline {
    agent any
    
    stages {
        stage('Checkout'){
            steps {
                checkout scm
            }
        }
        stage('Build') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'dockerhub-key', 
                                 usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                    script {
                        sh """
                            chmod u+x ./gradlew
                            ./gradlew clean build -Pdocker.repository=${dockerRepository} \
                                                  -Pdocker.repository.username=${USERNAME} \
                                                  -Pdocker.repository.password=${PASSWORD} \
                                                  -Pdocker.image.name=${dockerImageName} \
                                                  -Pdocker.image.tag=${currentBuild.number}
                        """
                    }
                }
            }
        }    
        stage('Publish') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'dockerhub-key', 
                                 usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                    script {
                        sh """
                            ./gradlew jib -Pdocker.repository=${dockerRepository} \
                                          -Pdocker.repository.username=${USERNAME} \
                                          -Pdocker.repository.password=${PASSWORD} \
                                          -Pdocker.image.name=${dockerImageName} \
                                          -Pdocker.image.tag=${currentBuild.number}
                        """
                    }
                }
            }
        }
        stage('Deploy'){
            steps {
                sshagent(credentials: ["deploy-key"]) {
                    sh """
                        ssh -o StrictHostKeyChecking=no ec2-user@${deployHost} \
                        'docker container rm -f springbootapp &&  
                         docker container run -d -t -p 80:8080 --rm --name springbootapp ${dockerRepository}/${dockerImageName}:${currentBuild.number};'
                    """
                }
            }
        }
    }
}




변경 사항 커밋

C:\java\springboot-to-ec2> git add .
C:\java\springboot-to-ec2> git commit -m 'update'
C:\java\springboot-to-ec2> git push




젠킨스 실행 및 설정

젠킨스 컨테이너 실행

호스트 PC에서 컨테이너 내부로 접속할 수 있도록 -p 옵션을 이용해서 서비스 포트를 바인딩하고, 설정 정보를 저장할 수 있도록 -v 옵션을 이용해서 볼륨 바인딩을 생성합니다. 

C:\java\springboot-to-ec2> docker run --name jenkins -d -p 8080:8080 -v c:/docker/jenkins:/var/jenkins_home -u root jenkins/jenkins:latest
90e218dc446e3aaa0ad3211b368e305b0a12afb07948f88b26152d2d329d363b

C:\java\springboot-to-ec2> docker container ls
CONTAINER ID   IMAGE                    COMMAND                  CREATED          STATUS          PORTS                               NAMES
90e218dc446e   jenkins/jenkins:latest   "/sbin/tini -- /usr/…"   16 seconds ago   Up 15 seconds   0.0.0.0:8080->8080/tcp, 50000/tcp   jenkins




admin 계정의 초기 패스워드 확인

C:\java\springboot-to-ec2> dir jenkins
 C 드라이브의 볼륨에는 이름이 없습니다.
 볼륨 일련 번호: 4A25-B901

 c:\docker\jenkins 디렉터리

2022-03-24  오전 11:01    <DIR>          .
2022-03-24  오전 10:53    <DIR>          ..
2022-03-24  오전 11:00    <DIR>          .cache
2022-03-24  오전 11:00    <DIR>          .java
2022-03-24  오전 11:01             1,659 config.xml
2022-03-24  오전 11:01               100 copy_reference_file.log
2022-03-24  오전 11:01                58 failed-boot-attempts.txt
2022-03-24  오전 11:01               156 hudson.model.UpdateCenter.xml
2022-03-24  오전 11:00             1,712 identity.key.enc
2022-03-24  오전 11:00               171 jenkins.telemetry.Correlator.xml
2022-03-24  오전 11:00    <DIR>          jobs
2022-03-24  오전 11:01               907 nodeMonitors.xml
2022-03-24  오전 11:00    <DIR>          nodes
2022-03-24  오전 11:00    <DIR>          plugins
2022-03-24  오전 11:00                64 secret.key
2022-03-24  오전 11:00                 0 secret.key.not-so-secret
2022-03-24  오전 11:00    <DIR>          secrets
2022-03-24  오전 11:00    <DIR>          userContent
2022-03-24  오전 11:00    <DIR>          users
2022-03-24  오전 10:59    <DIR>          war
               9개 파일               4,827 바이트
              11개 디렉터리  168,639,078,400 바이트 남음

C:\java\springboot-to-ec2> type c:\docker\jenkins\secrets\initialAdminPassword
617dd6b4c91f45b0b2f68e9355288063




젠킨스 로그인 > 기본 플러그인 설치 > 관리자 계정 생성 > 설정 마무리

http://localhost:8080

 

 

 

 

 




tester 사용자 계정 생성

젠킨스 대시보드 > Jenkins 관리 > Security > Manage Users > 사용자 생성

 




User Defined Time Zone을 Asia/Seoul로 변경 

 




로그아웃 후 tester 사용자로 로그인




플러그인 추가 설치

DSL, Pipeline, Github, Docker, AWS, SSH 관련 플러그인을 추가로 설치

 

Dashboard > Jenkins 관리 > System Configuration > 플러그인 관리

 

 

설치할 플러그인 목록

  • Amazon Web Services SDK :: All
  • AWS Global ConfigurationVersion
  • Build Pipeline
  • CloudBees AWS Credentials
  • CloudBees Docker Build and Publish
  • CloudBees Docker Custom Build Environment
  • Docker
  • Docker Commons
  • Docker Pipeline
  • docker-build-step
  • Git Parameter
  • GitHub Authentication
  • GitHub Integration
  • Job DSL
  • Pipeline: AWS Steps
  • Pipeline: Declarative Agent API
  • Pipeline: GitHub
  • PipelineUtility Steps
  • Simple Build DSL for Pipeline
  • SSH Agent
  • SSH Pipeline Steps
  • SSH

 




EC2 인스턴스 생성

스프링 부트 어플리케이션을 배포한 EC2 인스턴스를 생성합니다. 외부에서 EC2 인스턴스로 접속할 수 있도록 퍼블릭 IP 자동 할당을 활성화하고, 보안 그룹에 80 포트를 추가해 줍니다.

 

 

 

 

 

 

 




EC2 인스턴스 도커 설치

컨테이너 이미지로 배포한 스프링 부트 어플리케이션을 도커 레포지터리로 부터 가져와서 실행할 수 있도록 EC2 인스턴스에 Docker를 설치합니다. 

도커 설치
[ec2-user@ip-172-31-3-193 ~]$ sudo yum -y upgrade
[ec2-user@ip-172-31-3-193 ~]$ sudo yum -y install docker

설치 확인
[ec2-user@ip-172-31-3-193 ~]$ docker -v
Docker version 20.10.7, build f0df350

서비스 추가
[ec2-user@ip-172-31-3-193 ~]$ sudo service docker start

그룹에 사용자 추가
[ec2-user@ip-172-31-3-193 ~]$ sudo usermod -aG docker ec2-user

로그아웃 후 다시 로그인 후 명령어 실행 확인
[ec2-user@ip-172-31-3-193 ~]$ docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[ec2-user@ip-172-31-3-193 ~]$ docker image ls
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE




인증 정보 설정

git private access token 생성

 

 

 




SSH 키 생성

c:\docker> ssh-keygen -b 2048 -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (C:\Users\myanj/.ssh/id_rsa):	⇐ 키 저장 위치 → 엔터(기본 위치 사용)
Enter passphrase (empty for no passphrase):					⇐ 개인키 암호화에 사용할 패스워드 
Enter same passphrase again:							   → 엔터(패스워드 사용하지 않음)
Your identification has been saved in C:\Users\myanj/.ssh/id_rsa.	⇐ 개인키 → 젠키스에 등록
Your public key has been saved in C:\Users\myanj/.ssh/id_rsa.pub.	⇐ 공개키 → 깃허브에 등록
The key fingerprint is:
SHA256:KRd5wJhUBHVruKWaM6/NeNx66pwxA4vu4IGWTKK3hPU myanj@sbook
The key's randomart image is:
+---[RSA 2048]----+
|     .oO= .      |
|      o .= .     |
|        + =      |
|         O       |
|...   o S        |
|=+.. . B         |
|++= E *.+.       |
|.+ =   Oo=o      |
|  o.o o+X+       |
+----[SHA256]-----+




깃허브에 공개키 등록

 




Jenkins 크리덴션 설정

 

 

 

개인키(id_rsa) 내용을 포함하고 있는 SSH Username with private key 타입의 github-key를 생성

 

EC2 인스턴스의 키페이(perm 파일) 내용을 포함하고 있는 SSH username with private key 타입의 deploy-key를 생성

 

도커 허브 아이디와 패스워드 내용을 포함하고 있는 Username with password 타입의 dockerhub-key를 생성

 




Jenkins 파이프라인 생성

 

 

GitHub project를 선택하고 Project url 입력창에 소스 코드가 저장된 깃허브 주소를 입력
Pipeline script from SCM > SCM으로 Git을 선택 > Repository URL로 깃허브 주소를 입력하고 Credentials로 github-key를 선택




배포 및 동작확인

 




EC2 인스턴스의 퍼블릭 IP로 요청




젠킨스 컨테이너에 소스 코드 체크 아웃 확인

c:\> docker container exec -it jenkins /bin/bash
root@6710bb680522:/# cd /var/jenkins_home/workspace/		⇐ 젠킨스 작업 디렉터리
root@6710bb680522:/var/jenkins_home/workspace# ls -al
total 0
drwxr-xr-x 1 root root 4096 Mar 27 04:44 .
drwxrwxrwx 1 root root 4096 Mar 27 04:48 ..
drwxr-xr-x 1 root root 4096 Mar 27 04:47 springboot-deploy-pipeline
drwxr-xr-x 1 root root 4096 Mar 27 04:48 springboot-deploy-pipeline@tmp
root@6710bb680522:/var/jenkins_home/workspace# ls springboot-deploy-pipeline
Jenkinsfile  README.md  build  build.gradle  gradle  gradlew  gradlew.bat  settings.gradle  src




도커 허브에 이미지 등록 확인




EC2 인스턴스에 도커 컨테이너 동작 확인

[ec2-user@ip-172-31-3-193 ~]$ docker container ls
CONTAINER ID   IMAGE                         COMMAND                  CREATED          STATUS          PORTS                                   NAMES
e678a108e0a1   myanjini/myspringbootapp:36   "java -cp @/app/jib-…"   27 minutes ago   Up 27 minutes   0.0.0.0:80->8080/tcp, :::80->8080/tcp   springbootapp
[ec2-user@ip-172-31-3-193 ~]$ docker image ls
REPOSITORY                 TAG       IMAGE ID       CREATED        SIZE
myanjini/myspringbootapp   33        29dbe8bc2777   52 years ago   261MB
myanjini/myspringbootapp   34        29dbe8bc2777   52 years ago   261MB
myanjini/myspringbootapp   35        29dbe8bc2777   52 years ago   261MB
myanjini/myspringbootapp   36        29dbe8bc2777   52 years ago   261MB




리소스 정리

EC2 인스턴스 삭제

젠킨스 컨테이너 삭제

 

728x90
반응형

댓글