์ฝ์ง์์๋ Docker&Jenkins์ด์์ต๋๋ค... ๊ทธ๋ ์ง๋ง 4๋ฒ์ ์คํจ ๋์ ์ฑ๊ณตํด๋์ต๋๋ค!!!(์ ์ ํจ์ค ๋ก๊ณ ๊ฐ ํ๋ชจ์ธ์ง ์๊ฒ๋๋...ใ
)
์ ๊ฐ ๊ฒช์๋ ๋์ค์ ์๋ฌ๋ค๊ณผ ํ์ํ๋ ๊ณผ์ ์ ์ถ๊ฐํ๊ธฐ ์ํด ๋ธ๋ก๊ทธ์ ๊ธ์ ์์ฑํ๊ฒ ๋์์ต๋๋ค. ๋ถ์กฑํ ๋ถ๋ถ์ด ๋ง์ ๊ธ์ด ๋๊ฒ ์ง๋ง... ์กฐ๊ธ์ด๋ผ๋ ๋์์ด ๋์์ผ๋ฉด ํ๋ ๋ง์์ ์์ฑํด๋ด
๋๋ค!
์์น๋ bulid.gradle๊ณผ ๊ฐ์์์น์ ๋ก๋๋ค.
# JDK11 ์ด๋ฏธ์ง ์ฌ์ฉ
FROM openjdk:11-jdk
VOLUME /tmp
# JAR_FILE ๋ณ์์ ๊ฐ์ ์ ์ฅ
ARG JAR_FILE=./build/libs/*.jar
# ๋ณ์์ ์ ์ฅ๋ ๊ฒ์ ์ปจํ
์ด๋ ์คํ์ ์ด๋ฆ์ app.jarํ์ผ๋ก ๋ณ๊ฒฝํ์ฌ ์ปจํ
์ด๋์ ์ ์ฅ
COPY ${JAR_FILE} app.jar
# ๋น๋๋ ์ด๋ฏธ์ง๊ฐ run๋ ๋ ์คํํ ๋ช
๋ น์ด
ENTRYPOINT ["java","-jar","app.jar"]
plugins {
id 'org.springframework.boot' version '2.7.3'
id 'io.spring.dependency-management' version '1.0.13.RELEASE'
id 'java'
}
jar {
enabled = false
}
bootJar{
archivesBaseName = 'app'
archiveFileName = 'app.jar'
archiveVersion = "0.0.0"
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
ssh -i pemํค์์น ํ๋ ฅ์ IP์ฃผ์
//pemํ์ผ์ ~/.ssh/๋ก ๋ณต์ฌ
cp pemํค์์์น ~/.ssh/
// pemํค์ ๊ถํ์ ๋ณ๊ฒฝ
chmod 600 ~/.ssh/pemํคํ์ผ๋ช
.pem
// ~/.ssh๋๋ ํ ๋ฆฌ์ config ํ์ผ์ ์์ฑํฉ๋๋ค.
vim ~/.ssh/config
config ํ์ผ ์์ฑ
Host springBoot
HostName [ํด๋น ํ๋ ฅ์ IP์ฃผ์]
User ubuntu
IdentityFile ~/.ssh/[ํด๋น ํคํ์ด.pem]
Host jenkins
HostName [ํด๋น ํ๋ จ์ IP์ฃผ์]
User ubuntu
IdentityFile ~/.ssh/[ํด๋น ํคํ์ด.pem]
์์ ๊ฐ์ด ์์ฑ์ ๋ง์น๋ฉด :wq๋ช ๋ น์ด๋ก ์ ์ฅํ๊ณ ์ข ๋ฃํฉ๋๋ค.
์์ฑ๋ configํ์ผ์ ์คํ ๊ถํ ์ค์
chmod 700 ~/.ssh/config
์ด์ ์ ์์ ssh Host ๋ช
์ผ๋ก ์ ์ํ๋ฉด ๋ฉ๋๋ค.
ex:) ssh springBoot
jenkins server์ ์ ์ํฉ๋๋ค.
ํด๋น ์ฝ๋๋ฅผ ์ ๋ ฅํด EC2 ์ด๊ธฐ์ค์ ์ ๋ง๋ฌด๋ฆฌํฉ๋๋ค
sudo apt update
sudo apt upgrade
sudo apt install build-essential
$ sudo apt update
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common
๋ฆฌ๋ ์ค ๋ฐฐํฌํ ์ข ๋ฅ๋ฅผ ์๋์ผ๋ก ์ธ์ํ์ฌ Docker ํจํค์ง๋ฅผ ์ค์นํด์ฃผ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ ๊ณต
$ sudo wget -qO- https://get.docker.com/ | sh
$ sudo systemctl start docker
$ sudo systemctl enable docker
$ sudo usermod -aG docker ${USER}
$ sudo systemctl restart docker
$ docker -v
$ docker pull jenkins/jenkins:lts
$ docker images
$ docker run -d -p 8080:8080 -p 50000:50000 -v /jenkins:/var/jenkins -v /home/ubuntu/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock --name jenkins -u root jenkins/jenkins:lts
$ docker ps
๐ก EC2 ํ๋ฆฌํฐ์ด ์ฌ์ฉ์ Jenkins๊ฐ ์ฃฝ์ด์ ๐
ํ์ฌ ์ ํจ์ค ์๋ฒ๋ก ์ฌ์ฉํ๋ ํ๋ฆฌํฐ์ด EC2๋ ์ ํจ์ค๋ฅผ ๋ฒํธ ์ ์์ต๋๋ค. ์ ํจ์ค๋ฅผ ๋์ปค๋ก ๋์ฐ๊ณ ์ค์ ๊น์ง๋ ๋ฌธ์ ๊ฐ ์์ผ๋ ๊นํ๋ธ ์นํ ์ผ๋ก ์ ํจ์ค๋ฅผ ์ด์ฉํด spring์ ๋น๋ํ๋ ๊ณผ์ ์์ ๋จ์ 1๊ธฐ๊ฐ ์ด์(ํ๋ฆฌํฐ์ด EC2 ๋จ์ 1๊ธฐ๊ฐ) ์ฌ์ฉํ๊ฒ ๋๋ฉด์ EC2๊ฐ ๋จนํต์ด ๋์ด๋ฒ๋ฆฝ๋๋ค. ์ด ๋ฌธ์ ์ ํด๊ฒฐ ๋ฐฉ์์ผ๋ก๋ ๋ฆฌ๋ ์ค์ ํ๋๋์คํฌ๋ฅผ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ๋ก ์ ํ์์ผ ์ฌ์ฉํ ์ ์๋ค๋ ์ ์ ์ด์ฉํ๋ฉด ๋ฉ๋๋ค.
sudo dd if=/dev/zero of=/swapfile bs=128M count=16
dd ๋ฉธ๋ น์ ์ฌ์ฉํ์ฌ ๋ฃจํธ ํ์ผ ์์คํ ์ ์ค์ ํ์ผ์ ์์ฑํฉ๋๋ค.
๋ช ๋ น์์ dd๋ ๋ธ๋ก ํฌ๊ธฐ์ด๊ณ count๋ ๋ธ๋ก ์ ์ ๋๋ค.
์ง์ ํ ๋ธ๋ก ํฌ๊ธฐ๋ ์ธ์คํด์ค์์ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฉ๋ชจ๋ฆฌ๋ณด๋ค ์์์ผํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด memory exhauted ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
ํ๋ฆฌํฐ์ด์ ๋ฉ๋ชจ๋ฆฌ๋ 1GB์ด๋ฏ๋ก ๊ถ์ฅ์ฌํญ๋๋ก 2GB๋ฅผ ์ฆ์ค์์ผ์ผ ํฉ๋๋ค.
ํ์ฌ ์ ์ฝ๋๋๋ก๋ผ๋ฉด 2GB(128MB * 16 = 2,048MB) ์ ๋๋ค
2. ์ค์ ํ์ผ์ ๋ํ ์ฝ๊ธฐ ์ฐ๊ธฐ ๊ถํ ์ ๋ฐ์ดํธํ๊ธฐ
sudo chmod 600 /swapfile
3. Linux ์ค์ ์์ญ ์ค์ ํ๊ธฐ
sudo mkswap /swapfile
4. ์ค์ ๊ณต๊ฐ์ ์ค์ ํ์ผ์ ์ถ๊ฐํ์ฌ ์ค์ ํ์ผ์ ์ฆ์ ์ฌ์ฉํ ์ ์๋๋ก ํ๊ธฐ
sudo swapon /swapfile
5. ์ ์ฐจ๊ฐ ์ฑ๊ณตํ๋์ง ํ์ธํ๊ธฐ
sudo swapon -s
6. /etc/fstab ํ์ผ์ ํธ์งํ์ฌ ๋ถํ ์ ์ค์ ํ์ผ์ ํ์ฑํํ๊ธฐ
ํ์ผ ์ด๊ธฐ
sudo vi /etc/fstab
ํ์ผ ๊ฐ์ฅ ๋ง์ง๋ง์ ๋ค์์ ์ถ๊ฐํ๊ณ :wq๋ก ์ ์ฅํ๊ณ ์ข
๋ฃ
/swapfile swap swap defaults 0 0
7. free ๋ช ๋ น์ด๋ก ๋ฉ๋ชจ๋ฆฌ ํ์ธํ๊ธฐ
free
๋ณด์๊ทธ๋ฃน์์ 8080 - > ๋ดIP๋ฅผ ์ถ๊ฐํด์ค์ผํ๋ค.
/var/lib/jenkins/secrets/initialAdminPassword๋ฅผ ํ์ธํด์ผ ํ๋๋ฐ Jenkins Container์ ์ ์ํ์ฌ ์ป์ด์ค๊ฑฐ๋ "docker logs jenkins" ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
// Container ์ ์
$ docker exec -it jenkins bash
// ์ํธ ํ์ผ ํ์ธ
$ cat /var/lib/jenkins/secrets/initialAdminPassword
Jenkins ๋ฉ์ธ ๋์๋ณด๋ ํ์ด์ง๊ฐ ๋์ค๋ฉด ์ฑ๊ณต
Jenkins Container๋ฅผ ์์ฑํ ๋ "/home/ubuntu/.ssh:/root/.ssh"๋ก .ssh ๋ํ ๋๋ฆฌ๋ฅผ ๋ง์ดํธ ํด๋์๊ธฐ ๋๋ฌธ์ Container ๋ฐ์์ ssh ํค๋ฅผ ์์ฑํ๋ฉด Jenkins Container์ ์ฐ๊ฒฐ๋๋ค.
// ๊ทธ๋ฅ ์ ๋ถ enter๋ฅผ ์
๋ ฅํดdefault๋ก ๋ง๋ ๋ค.
$ ssh-keygen
EC2์ ์ ์ํ๋ฉด ๊ธฐ๋ณธ ์ ์ ๊ฐ ubuntu์ด๊ธฐ ๋๋ฌธ์ /home/ubuntu/.ssh์ id_rsa์ id_rsa.pub์ด ์์ฑ๋๋ค.
๋ง๋ค์ด ๋์ Github Repository > Settings > Deploy Keys > Add deploy key๋ก ์ ์ํ๋ค.Title์ Jenkins๋ก ์ง์ด ์ฃผ๊ณ (๋ง์๋๋ก ํด๋ ๋๋ค), Key ๋ถ๋ถ์ id_rsa.pub์ ๋ค์ด์๋ public key ๊ฐ์ ๋ฃ์ด์ค๋ค. ์๋ ๋ช ๋ น์ด๋ก ํ์ธ ๊ฐ๋ฅํ๋ค.
$ cd /home/ubuntu/.ssh
$ cat id_rsa.pub
Jenkins ๋์๋ณด๋ > Jenkins ๊ด๋ฆฌ > Manage Credentials > Credentials์ ์ ์ํ๋ค.Store Jenkins์ Domain์ด (global)์ธ ํ์ดํ๋ฅผ ๋๋ฌ Global credentials (unrestricted)๋ก ์ด๋ํ๋ค.์ผ์ชฝ ๋ฉ๋ด์ Add credentials๋ฅผ ๋๋ฌ credentials๋ฅผ ์ถ๊ฐํ๋ค.
$ cd /home/ubuntu/.ssh
$ cat id_rsa
-----BEGIN OPENSSHPRIVATEKEY-----
...
... ์ด์ ๊ฐ์ ํํ์key๊ฐprivatekey ์
๋๋ค ...
...
-----END OPENSSHPRIVATEKEY-----
Jenkins ๋์๋ณด๋ > Jenkins ๊ด๋ฆฌ > ํ๋ฌ๊ทธ์ธ ๊ด๋ฆฌ > ์ค์น ๊ฐ๋ฅ > Docker ๊ฒ์ > Docker, Docker Pipeline ํ๋ฌ๊ทธ์ธ ์ค์น ๋ฐ ์ฌ์คํ
Jenkins ๋์๋ณด๋ > Jenkins ๊ด๋ฆฌ > Manage Credentials > Credentials์ ์ ์ํ๋ค.Store Jenkins์ Domain์ด (global)์ธ ํ์ดํ๋ฅผ ๋๋ฌ Global credentials (unrestricted)๋ก ์ด๋ํ๋ค.์ผ์ชฝ ๋ฉ๋ด์ Add credentials๋ฅผ ๋๋ฌ credentials๋ฅผ ์ถ๊ฐํ๋ค.
Jenkins Pipeline์์ Docker ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก Jenkins Container ๋ด๋ถ์ Docker๋ฅผ ์ค์นํด์ผ ํ๋ค.
$ docker exec -it jenkins bash
sudo ์ค์น
$ apt-get update && apt-get install -y sudo
vi ์ค์น
apt-get update
apt-get install vim
wget ์ค์น
apt-get install wget
Jenkins๋ก Gradle ๋น๋ํ๊ณ Dockerfile๋ก ๋์ปค ์ด๋ฏธ์ง๋ฅผ ๋น๋ํด์ Docker Hub์ Pushํ๊ณ Spring Boot Server์์ ๋์ปค ์ด๋ฏธ์ง๋ฅผ Pullํด์ ์คํํ๊ฒ ํ๊ธฐ ์ํด ํ์ํ๋ค. Jenkins Pipeline Script์์ SSH๋ฅผ ์ฌ์ฉํ์ฌ Spring Boot Server์ ๋ช ๋ น์ด ์คํ์ ํ ์ ์๋๋ก ํ๋ ๊ฒ์ ๋๋ค.
Jenkins ๋์๋ณด๋ > Jenkins ๊ด๋ฆฌ > ํ๋ฌ๊ทธ์ธ ๊ด๋ฆฌ > ์ค์น ๊ฐ๋ฅ > SSH Agent ํ๋ฌ๊ทธ์ธ์ ๊ฒ์ํ๊ณ ์ค์น ๋ฐ ์ฌ์คํ
// Jenkins Server์์ public key ํ์ธ
$ cat /home/ubuntu/.ssh/id_rsa.pub// Spring Boot Server์ Jenkins Server public key ์ถ๊ฐ
$ vi /home/ubuntu/.ssh/authorized_keys
// authorized_keys์ ํ์ค ๋์ฐ๊ณ public key ๋ฑ๋ก
Jenkins ๋์๋ณด๋ > Jenkins ๊ด๋ฆฌ > Manage Credentials > Credentials์ ์ ์ํ๋ค.Store Jenkins์ Domain์ด (global)์ธ ํ์ดํ๋ฅผ ๋๋ฌ Global credentials (unrestricted)๋ก ์ด๋ํ๋ค.์ผ์ชฝ ๋ฉ๋ด์ Add credentials๋ฅผ ๋๋ฌ credentials๋ฅผ ์ถ๊ฐํ๋ค.
$ cd /home/ubuntu/.ssh
$ cat id_rsa
-----BEGIN OPENSSHPRIVATEKEY-----
...
... ์ด์ ๊ฐ์ ํํ์key๊ฐprivatekey ์
๋๋ค ...
...
-----END OPENSSHPRIVATEKEY-----
Github Repository์ push event๊ฐ ๋ฐ์ํ์ ๋ ์๋์ผ๋ก Build๊ฐ ์คํ๋๊ฒ ํ๊ธฐ ์ํด Pipeline๊ณผ Github Webhook์ ์ฐ๋ํด์ผ ํ๋ค.
Jenkins ๋์๋ณด๋ > Jenkins ๊ด๋ฆฌ > ํ๋ฌ๊ทธ์ธ ๊ด๋ฆฌ > ์ค์น ๊ฐ๋ฅ > Github Integration ํ๋ฌ๊ทธ์ธ์ ๊ฒ์ํ๊ณ ์ค์น ๋ฐ ์ฌ์คํ
Github Repository์์ Settings > Webhooks > Add Webhook ์ ๋๋ฌ Webhook์ ์ถ๊ฐํ๋ค.
pipeline {
agent any
environment {
imagename = "docker build๋ก ๋ง๋ค ์ด๋ฏธ์ง ์ด๋ฆ"
registryCredential = 'Docker Hub Credential ID'
dockerImage = ''
}
stages {
stage('Prepare') {
steps {
echo 'Clonning Repository'
git url: 'Github Repository SSH Url(git@github.com๋ก ์์)',
branch: 'Clone ๋ฐ์์ฌ Branch ์ด๋ฆ',
credentialsId: 'Github Credential ID -> github'
}
post {
success {
echo 'Successfully Cloned Repository'
}
failure {
error 'This pipeline stops here...'
}
}
}
stage('Bulid Gradle') {
steps {
echo 'Bulid Gradle'
dir('.'){
sh 'chmod +x ./gradlew'
sh './gradlew clean build'
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Bulid Docker') {
steps {
echo 'Bulid Docker'
script {
dockerImage = docker.build imagename
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Push Docker') {
steps {
echo 'Push Docker'
script {
docker.withRegistry( '', registryCredential) {
dockerImage.push()
}
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Docker Run') {
steps {
echo 'Pull Docker Image & Docker Image Run'
sshagent (credentials: ['SSH Credential ID -> ssh']) {
sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP ์ฃผ์] 'docker pull [๋์ปค์ด๋ฏธ์ง ์ด๋ฆ]'"
sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP ์ฃผ์] 'docker ps -q --filter name=[์ปจํ
์ด๋ ์ด๋ฆ] | grep -q . && docker rm -f \$(docker ps -aq --filter name=[์ปจํ
์ด๋ ์ด๋ฆ])'"
sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP ์ฃผ์] 'docker run -d --name [์ปจํ
์ด๋ ์ด๋ฆ] -p 8080:8080 [๋์ปค์ด๋ฏธ์ง ์ด๋ฆ]'"
}
}
}
}
}
Stage ๋ก ๋์ด์ prepare ์ gradle ๋ง ์ค๋ช ํ๊ฒ ๋ค.
stage('Prepare') {
steps {
echo 'Clonning Repository'
git url: 'Github Repository SSH Url(git@github.com๋ก ์์)',
branch: 'Clone ๋ฐ์์ฌ Branch ์ด๋ฆ',
credentialsId: 'Github Credential ID -> github'
}
post {
success {
echo 'Successfully Cloned Repository'
}
failure {
error 'This pipeline stops here...'
}
}
}
sh 'chmod +x ./gradlew'
: gradlew ์คํ๊ถํ ์ ์ฉ
sh './gradlew clean build'
: grdlew cleanํ bulid
stage('Bulid Gradle') {
steps {
echo 'Bulid Gradle'
dir('.'){
sh 'chmod +x ./gradlew'
sh './gradlew clean build'
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
$ docker ps
๋์์ ์ฃผ์ ๋ธ๋ก๊ทธ๋ค ๐
https://hyeinisfree.tistory.com/23
https://backtony.github.io/spring/aws/2021-08-08-spring-cicd-1/#๋์ปค-์ธํ