스프링 부트 기반의 애플리케이션을 도커 이미지화하여 도커 허브에 등록하고, 해당 이미지를 이용해서 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.
프로젝트 파일 생성
프로젝트 파일 임포트
애플리케이션 코드 작성
참고
도커 이미지 생성 및 등록에 필요한 정보를 파라미터로 받아서 처리하도록 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 크리덴션 설정
Jenkins 파이프라인 생성
배포 및 동작확인
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 인스턴스 삭제
젠킨스 컨테이너 삭제
댓글