Skip to content

spacedustz/Pipeline-CICD

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

87 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Auto-Deployment-Pipeline

  • Test Github Actions + AWS Code Deploy & S3 & EC2 [Done]
  • Test Jenkins + AWS Lightsail [Done]
  • Declarative Pipeline [Done]
  • Blue & Green Zero-Downtime Deployment [Done]

Jenkins Pipeline ๊ตฌ์ถ•

Jenkins์˜ Item์ค‘ ์„ ์–ธํ˜• Pipeline์œผ๋กœ ๊ตฌ์ถ•์„ ์™„๋ฃŒํ•ด์„œ ๊ธ€์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.


์ €๋ฒˆ์— Free Style Project๋กœ Jenkins CICD๋ฅผ ๊ตฌํ˜„ํ–ˆ์—ˆ๋Š”๋ฐ, ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ณ€๊ฒฝํ•จ์— ๋”ฐ๋ผ Declarative Pipeline Script๋ฅผ ์ด์šฉํ•œ Jenkins CICD๋ฅผ ๊ตฌ์ถ•ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•ด๋†“๊ณ  Pipeline์„ ๊ตฌ์ถ•ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!!


Jenkins Credential, JDK, Gradle, SSH, Token ๋“ฑ Jenkins Web์—์„œ์˜ ๋ชจ๋“  ์„ค์ •์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ๊ธ€์„ ์ผ์Šต๋‹ˆ๋‹ค.


๋‚ด์šฉ ์ถ”๊ฐ€ (Jenkins Git ๊ด€๋ จ ์ด์Šˆ ํ•ด๊ฒฐ)

  1. Jenkins Credentials์˜ SSH์™€ ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ์˜ SSH๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ์ฒดํฌ
  2. ๋งŒ์•ฝ SSH๋กœ Credentials๋ฅผ ๊ตฌ์„ฑํ–ˆ๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ์˜ ํ”„๋กœ์ ํŠธ URL๋„ ssh URL๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  3. Jenkins Server์˜ /var/lib/jenkins ๋””๋ ‰ํ„ฐ๋ฆฌ๋‚˜ ๊ทธ ํ•˜์œ„์˜ ํŒŒ์ผ๋“ค์˜ ๊ถŒํ•œ, ์†Œ์œ ์ž ํ™•์ธ ํ•„์ˆ˜ ( ์†Œ์œ ์ž: jenkins:jenkins ๋กœ ํ•ด์•ผํ•จ)
  4. EC2 jenkins user์˜ .ssh ํ•˜์œ„ ํŒŒ์ผ๋“ค์˜ ๊ถŒํ•œ, ์†Œ์œ ์ž ํ™•์ธ
  5. known_host์— EDSDA ํ‚ค ์ถ”๊ฐ€ ๋๋Š”์ง€ ํ™•์ธ

# Jenkins ๋””๋ ‰ํ„ฐ๋ฆฌ ํ•˜์œ„ ๋ชจ๋“  ํŒŒ์ผ๋“ค์˜ ์†Œ์œ ๊ถŒ ๋ณ€๊ฒฝ
chown -R jenkins:jenkins/var/lib/jenkin

# Jenkins User์˜ ssh ํŒŒ์ผ๋“ค ์†Œ์œ ์ž, ๊ถŒํ•œ ๋ณ€๊ฒฝ
chown -R jenkins:jenkins /var/lib/jenkins/.ssh
chmod 600 /var/lib/jenkins/.ssh/id_rsa
chmod 644 /var/lib/jenkins/.ssh/id_rsa.pub

Jenkins Server

EC2 m5a.large ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ์œผ๋ฉฐ AMI๋Š” Ubuntu 20.04 LTS์ž…๋‹ˆ๋‹ค.

root ๊ณ„์ •์œผ๋กœ ์ง„ํ–‰ํ–ˆ์œผ๋ฉฐ ๋ณด์•ˆ๊ทธ๋ฃน ํฌํŠธ๋Š” ์ด๋ฏธ ์—ด์–ด๋†“์€ ์ƒํƒœ์—์„œ ์„œ๋ฒ„ ์„ธํŒ… ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•ด ์„œ๋ฒ„๋ฅผ ์„ธํŒ…ํ•˜์˜€์Šต๋‹ˆ๋‹ค.


์„œ๋ฒ„ ์„ธํŒ… ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ

๊ธฐ๋ณธ์ ์ธ ํŒจํ‚ค์ง€๋“ค๊ณผ ๋ฐฉํ™”๋ฒฝ ์„ค์ •, Docker, Jenkins๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์Šคํ…์„ ์ง„ํ–‰ํ• ๋•Œ๋งˆ๋‹ค ๋กœ๊ทธ ํŒŒ์ผ์— ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

#!/bin/bash


# APT ์—…๋ฐ์ดํŠธ
apt-get -y update
ate-get -y upgrade
echo ----- APT Update ์ข…๋ฃŒ ---- | tee settinglogs


# ๊ธฐ๋ณธ ํŒจํ‚ค์ง€ ์„ค์น˜
apt install -y firewalld mysql-client net-tools curl wget gnupg lsb-release ca-certificates apt-transport-https software-properties-common gnupg-agent openjdk-11-jdk
echo ----- ๊ธฐ๋ณธ ํŒจํ‚ค์ง€ ์„ค์น˜ ์™„๋ฃŒ ----- >> settinglogs


# OpenJDK ์ „์—ญ๋ณ€์ˆ˜ ์„ค์ •
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
echo ----- $JAVA_HOME ----- >> settinglogs


# Firewalld ์‹œ์ž‘
systemctl start firewalld && systemctl enable firewalld
echo ----- Firewalld ์‹œ์ž‘ ----- >> settinglogs


# ํฌํŠธ ์˜คํ”ˆ
firewall-cmd --permanent --add-port=22/tcp
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=5000/tcp
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --add-port=18080/tcp
firewall-cmd --permanent --add-port=13306/tcp

# Jenkins < - > Github Webhook์„ ์œ„ํ•œ IP ํ—ˆ์šฉ
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address=192.30.252.0/22 port port="22" protocol="tcp" accept' && firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address=185.199.108.0/22 port port="22" protocol="tcp" accept' && firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address=140.82.112.0/20 port port="22" protocol="tcp" accept' && firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address=143.55.64.0/20 port port="22" protocol="tcp" accept' && firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address=2a0a:a440::/29 port port="22" protocol="tcp" accept' && firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address=2606:50c0::/32 port port="22" protocol="tcp" accept'


# Firewall Settings ์ €์žฅ
firewall-cmd --reload
echo ----- Firewalld ์„ค์ • ์™„๋ฃŒ ----- >> settinglogs


# ๋„์ปค ์„ค์น˜

## ๋„์ปค GPG Key ์ถ”๊ฐ€
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

## ๋„์ปค ์ €์žฅ์†Œ ์„ค์ •
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

## ๋„์ปค ์—”์ง„ ์„ค์น˜
apt install -y docker-ce docker-ce-cli containerd.io
echo ----- ๋„์ปค ์„ค์น˜ ์™„๋ฃŒ ----- >> settinglogs

## ๋„์ปค ์‹œ์ž‘
systemctl start docker && systemctl enable docker
echo ----- ๋„์ปค ์‹œ์ž‘ ----- >> settinglogs


# ์  ํ‚จ์Šค ์„ค์น˜
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -

curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
  /usr/share/keyrings/jenkins-keyring.asc > /dev/null

echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
  /etc/apt/sources.list.d/jenkins.list > /dev/null

apt -y update

apt install -y jenkins
echo ----- Jenkins ์„ค์น˜ ์™„๋ฃŒ ----- >> settinglogs

# ๋„์ปค, sudo ๊ถŒํ•œ ๋ถ€์—ฌ
usermod -aG docker jenkins
usermod -aG sudo jenkins
chmod 666 /var/run/docker.sock


# ์  ํ‚จ์Šค ํฌํŠธ ๋ณ€๊ฒฝ
sed -i 's/8080/18080/g' /usr/lib/systemd/system/jenkins.service


# ์  ํ‚จ์Šค ์‹œ์ž‘
systemctl start jenkins && systemctl enable jenkins
echo ----- Jenkins ์‹œ์ž‘ ์™„๋ฃŒ ----- >> settinglogs

์ƒํƒœ ํ™•์ธ์šฉ ์Šคํฌ๋ฆฝํŠธ

#!/bin/bash

echo -e "\033[31m"=== Firewalld Port Status ==="\033[0m"
firewall-cmd --list-all


echo -e "\033[31m"=== Docker Status ==="\033[0m"
systemctl status docker | grep active


echo -e "\033[31m"=== Jenkins Status ==="\033[0m"
systemctl status jenkins | grep active

script.sh

Jenkinsfile์˜ ์กฐ๊ฑด๋“ค์„ ํ†ต๊ณผํ•˜๊ณ , Build Stage์—์„œ ์‚ฌ์šฉ๋  ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ž‘์„ฑํ•œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์š”์•ฝํ•˜๋ฉด ์ด๋ ‡์Šต๋‹ˆ๋‹ค.

  1. gradlew ํŒŒ์ผ์— ์‹คํ–‰๊ถŒํ•œ ์ถ”๊ฐ€
  2. gradlew ๋นŒ๋“œ
  3. ์ „์— ๋นŒ๋“œํ•œ ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€ & ์‚ญ์ œ
  4. ๋นŒ๋“œํ–ˆ๋˜ ์ด๋ฏธ์ง€ ์‚ญ์ œ
  5. ๋„์ปค Hub ๋กœ๊ทธ์ธ
  6. ์ƒˆ๋กœ์šด ๋นŒ๋“œ์˜ Dockerfile ๋นŒ๋“œ
  7. ๊ตฌ์ถ•ํ•ด๋†“์€ Docker Container Registry์— ๋นŒ๋“œํ•œ ์ด๋ฏธ์ง€ Push
  8. Pushํ•œ ์ด๋ฏธ์ง€ ์‚ญ์ œ
  9. Pushํ–ˆ๋˜ ์ด๋ฏธ์ง€ Pull
  10. ๊ฐ€์ ธ์˜จ ์ด๋ฏธ์ง€๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰ + ๋ณผ๋ฅจ ๋งˆ์šดํŠธ + ํฌํŠธํฌ์›Œ๋”ฉ
  11. ์ค‘๋ณต๋œ ์ด๋ฏธ์ง€ ์‚ญ์ œ
#!/bin/bash  
  
# Gradlew ๊ถŒํ•œ ๋ถ€์—ฌ  
chmod 500 ./gradlew  
  
# ๋นŒ๋“œ  
./gradlew build --exclude-task test  
  
# ๊ฐ€๋™์ค‘์ธ Spring Boot ์ปจํ…Œ์ด๋„ˆ ์ค‘ ์ด๋ฆ„์ด cosmic ์ธ ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€ & ์‚ญ์ œ  
if docker ps -a --filter "name=cosmic" | grep -q cosmic; then  
    docker stop cosmic  
    docker rm cosmic  
fi  
  
# ๊ธฐ์กด Spring Boot Image ์ค‘ ์ด๋ฏธ์ง€๊ฐ€ ๊ธฐ์กด๊ณผ ๋˜‘๊ฐ™์€๊ฒŒ ์žˆ์œผ๋ฉด ์ด๋ฏธ์ง€ ์‚ญ์ œ  
if docker images | awk '{print $1":"$2}' | grep -q "localhost:5000/cosmic:1.0"; then  
    docker rmi -f localhost:5000/cosmic:1.0  
fi  
  
# Docker Hub Login & ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์  ํ‚จ์Šค์—์„œ ์„ค์ •ํ•œ ์ „์—ญ๋ณ€์ˆ˜ ์‚ฌ์šฉ  
echo $PASSWORD | docker login -u $USERNAME --password-stdin  
  
# ๋„์ปคํŒŒ์ผ ๋นŒ๋“œ  
docker build --no-cache -t localhost:5000/cosmic:1.0 -f ./spacepet-deploy/test/cosmic .  
  
# Container Registry์— ์ด๋ฏธ์ง€ Push
docker push localhost:5000/cosmic:1.0  
  
# Pushํ•œ ์ด๋ฏธ์ง€ ์‚ญ์ œ  
docker rmi localhost:5000/cosmic:1.0  
  
# Container Registry์—์„œ ์ด๋ฏธ์ง€ Pull
docker pull localhost:5000/cosmic:1.0  
  
# Docker Container ์ƒ์„ฑ  
docker run -d -v /root/docker_volumn/cosmic:/app --privileged --name cosmic -p 8080:8080 localhost:5000/cosmic:1.0  
  
# ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ถˆํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ์‚ญ์ œ = ๊ฒน์น˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์กด์žฌํ•˜๋ฉด ์ด๋ฏธ์ง€๋ฅผ ์‚ญ์ œํ•œ๋‹ค  
dangling_images=$(docker images -f "dangling=true" -q)  
if [[ -n "$dangling_images" ]]; then  
    docker rmi -f $dangling_images || true  
fi

dangling Image๋ž€?

๋™์ผํ•œ ํƒœ๊ทธ๋ฅผ ๊ฐ€์ง„ Docker Image๊ฐ€ ๋นŒ๋“œ๋  ๊ฒฝ์šฐ, ๊ธฐ์กด์— ์žˆ๋Š” ์ด๋ฏธ์ง€๋Š” ์‚ญ์ œ๋˜์ง€๋„ ์•Š๊ณ ,

tag๊ฐ€ none์œผ๋กœ ๋ณ€๊ฒฝ๋œ ์ƒํƒœ๋กœ ๋‚จ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์žฌ ๋นŒ๋“œ์‹œ ์ด์ „ ์ด๋ฏธ์ง€๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€๋กœ ๋Œ€์ฒดํ•˜๊ฒ ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.


Dockerfile

๋„์ปคํŒŒ์ผ์€ ํ•ญ์ƒ ๋„์ปคํŒŒ์ผ์ด ์žˆ๋Š” ์œ„์น˜๊ฐ€ ๊ธฐ์ค€ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค.

spacepet-deploy/test/cosmic ์ด๋‹ˆ๊นŒ

COPY ๊ฒฝ๋กœ์— ../../ ๋ฅผ ํ•ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.

์ตœ๋Œ€ ํž™์‚ฌ์ด์ฆˆ๋ฅผ 6GB๋กœ ์ œํ•œํ•˜๋ฉด์„œ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.


Workdir์€ /app ์ธ๋ฐ JarํŒŒ์ผ์„ ์ปจํ…Œ์ด๋„ˆ ์ตœ์ƒ๋‹จ์— ๋‘๋Š” ์ด์œ ๋Š”

script.sh ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰ ์‹œ, ๋ณผ๋ฅจ ๋งˆ์šดํŠธ๋ฅผ /app์— ํ•˜๋Š”๋ฐ,

๊ทธ๋•Œ /app ํ•˜์œ„์— ์žˆ๋˜ jar๊ฐ€ ์‚ฌ๋ผ์ง€๋ฏ€๋กœ JarํŒŒ์ผ์„ ์ตœ์ƒ๋‹จ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

FROM openjdk:11  
RUN mkdir -p /app    
WORKDIR /app    
VOLUME /app    
EXPOSE 8080  ARG JAR=dangnyang-1.7.08-SNAPSHOT.jar    
COPY ../../build/libs/${JAR} /koboot.jar  
RUN chmod +x /koboot.jar  
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=test","-Xmx6144M","/koboot.jar"]

Jenkinsfile

Jenkinsfile์—์„œ Git repo์— ์ฒดํฌ์•„์›ƒ์„ ํ•˜๊ณ 

์›ํ•˜๋Š” ๋ธŒ๋žœ์น˜, ํƒœ๊ทธ ๋“ฑ ํ•„ํ„ฐ๋ง ์˜ต์…˜๋“ค์„ ๋„ฃ์–ด ๋นŒ๋“œ ์‹คํ–‰ ์ „ ์กฐ๊ฑด์„ ๊ฑธ์–ด๋‘ก๋‹ˆ๋‹ค.


Stage: Clean Workspace ํ•ญ๋ชฉ ๋นŒ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „ Workspace๋ฅผ ๋น„์›๋‹ˆ๋‹ค.


Stage: Checkout ํ•ญ๋ชฉ ๋“ฑ๋กํ•œ Jenkins Credential์„ ์ด์šฉํ•ด Git Repo์— Checkout์„ ํ•ฉ๋‹ˆ๋‹ค.


Stage: Build ํ•ญ๋ชฉ ์กฐ๊ฑด์ด ์ผ์น˜ํ•˜๋ฉด ๊ทธ๋•Œ ์œ„์— ์ž‘์„ฑํ•œ script.sh๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉฐ script.sh ์Šคํฌ๋ฆฝํŠธ ๋‚ด๋ถ€์—์„œ Dockerfile์„ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.

pipeline {  
  agent any  
  
  stages {  
  
    stage('Clean Workspace') {  
      steps {  
        deleteDir()  
      }  
    }  
  
    stage('Checkout') {  
      steps {  
        script {  
          checkout([$class: 'GitSCM',  
  
          branches: [[name: '<branch-name>']],  
          userRemoteConfigs: [[  
          url: 'git@github.com:<user-name>/<repo-name>.git',  
          branch: 'SPACEPET-TEST',  
          credentialsId: '<jenkins-credentials-id>']]])  
        }  
      }  
    }  
  
    stage('Build') {  
      steps {  
        script {  
          def gitTags = sh(returnStdout: true, script: 'git tag --contains HEAD')  
          if (gitTags.contains('cicd')) {  
            sh 'chmod 500 spacepet-deploy/test/script.sh'  
            sh './spacepet-deploy/test/script.sh'  
          } else {  
            echo 'No tag containing "cicd" found.'  
          }  
        }  
      }  
    }  
  }  
}

Pipeline (Item) ์ƒ์„ฑ


General

Github Project ์„ ํƒํ•˜๊ณ  Project URL์„ ์จ์ค๋‹ˆ๋‹ค. (.git ํฌํ•จ)

git@github.com:<user-name>/<repo-name>.git


Build Triggers

Github hook trigger for GITScm polling์„ ์„ ํƒํ•ด์ค๋‹ˆ๋‹ค.


Pipeline


Definition ํ•ญ๋ชฉ

Pipeline script from SCM ์œผ๋กœ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.


SCM ํ•ญ๋ชฉ

Git ์œผ๋กœ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.


Repository URL ํ•ญ๋ชฉ

git@github.com:<user-name>/<repo-name>.git ์˜ ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค.


Credentials ํ•ญ๋ชฉ

Jenkins Credential์— ๋“ฑ๋กํ•œ Jenkins Server์˜ Jenkins User SSH๋ฅผ ๋“ฑ๋กํ–ˆ๋˜ Credentials๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

์ด ํ›„ ๋ฐ‘์— ๊ณ ๊ธ‰ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ค๋‹ˆ๋‹ค.


RefSpec ํ•ญ๋ชฉ

Name์€ ์•„๋ฌด๋ ‡๊ฒŒ๋‚˜ ์ ๊ณ  Refspec์— ์›ํ•˜๋Š” ๋ธŒ๋žœ์น˜๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

+refs/heads/SPACEPET-TEST:refs/remotes/origin/SPACEPET-TEST


Branch Specifier ํ•ญ๋ชฉ

*/SPACEPET-TEST <- ์ €๋Š” SPACEPET-TEST ๋ผ๋Š” ๋ธŒ๋žœ์น˜๋ฅผ ๋นŒ๋“œ ๋Œ€์ƒ์œผ๋กœ ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.


Script Path ํ•ญ๋ชฉ

๋นŒ๋“œ ๋Œ€์ƒ์— Jenkinsfile์ด ์œ„์น˜ํ•œ ๊ฒฝ๋กœ๋ฅผ ์ ์–ด์ค๋‹ˆ๋‹ค. (Pipeline Script ์œ„์น˜)

spacepet-deploy/test/Jenkinsfile


Pipeline Script ์ •์ƒ ๋™์ž‘

  1. Spring Boot์—์„œ ์„ค์ •ํ•œ ๋ธŒ๋žœ์น˜์—์„œ ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•œ Push
  2. Github Webhook Trigger ๋ฐœ๋™ -> Jenkins๋กœ Webhook ์ „์†ก
  3. Jenkins๊ฐ€ Webhook์„ ๋ฐ›๊ณ  Jenkinsfile์„ ์‹คํ–‰
  4. Jenkinsfile์— ๊ฑธ๋ฆฐ ์กฐ๊ฑด ํ•„ํ„ฐ๋ง (๋ธŒ๋žœ์น˜, ํƒœ๊ทธ)
  5. ๋ธŒ๋žœ์น˜์™€ ํƒœ๊ทธ๊ฐ€ ๋งž์œผ๋ฉด Jenkinsfile์˜ Build Stage์— script.sh ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ ๋ฐœ๋™
  6. script.sh ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰

100๋ฒˆ์˜ ์‚ฝ์งˆ๋์— ๊ฒจ์šฐ ์„ฑ๊ณต.. Jenkins ๋„ˆ๋ฌด ๋ถˆ์นœ์ ˆํ•œ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ใ… 

img



Jenkins Server์ธ EC2์— docker ps๋ฅผ ์ž…๋ ฅํ•ด๋ณด๋ฉด Springboot ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋„์›Œ์ง€๊ณ  ๋ณผ๋ฅจ ๋งˆ์šดํŠธ๋„ ์ž˜ ๋œ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋‹ค๋ฅธ ๋ฐฉ๋ฒ•

Dockerfile์ด๋‚˜ script.sh๋ฅผ ์ž‘์„ฑ ์•ˆํ•˜๊ณ  Pipeline์— ์ „๋ถ€ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ด ๋ฐฉ๋ฒ•์˜ ์žฅ์ ์€ Stage ๋ณ„๋กœ ๋‹จ๊ณ„๋ฅผ ๋ถ„๋ฅ˜ํ•จ์œผ๋กœ์จ Jenkins Web์—์„œ ์ง„ํ–‰ ์ƒํ™ฉ์„ GUI๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ˆˆ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทผ๋ฐ ์œ„์— ๋ฐฉ๋ฒ•์ด ๋” ์ต์ˆ™ํ•ด์„œ ์ด๊ฑด ๊ทธ๋ƒฅ ์—ฐ์Šต๋งŒ ํ•ด๋†“๊ณ  ์•ˆ์“ฐ๊ฒ ์Šต๋‹ˆ๋‹ค.

pipeline {  
  agent any  
  
  stages {  
  
    stage('Stop & Delete Container') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        sh '''  
          if docker ps -a --filter "name=cosmic" | grep -q cosmic; then              docker stop cosmic              docker rm cosmic          fi        '''      }  
    }  
  
    stage('Remove Image') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        sh '''  
          if docker images | awk '{print $1":"$2}' | grep -q "localhost:5000/cosmic:1.0"; then              docker rmi -f localhost:5000/cosmic:1.0          fi        '''      }  
    }  
  
    stage('Login Docker Hub') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        sh 'echo $PASSWORD | docker login -u $USERNAME --password-stdin'  
      }  
    }  
      
    stage('Git Clone') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        git branch: 'SPACEPET-TEST', url:'https://github.com/CosmicDangNyang/CosmicDangNyang-Server'  
      }  
    }  
  
    stage('Build') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        sh 'chmod 500 ./gradlew'  
        sh './gradlew build --exclude-task test'  
      }  
    }  
  
    stage ('Build Dockerfile') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        sh 'docker build --no-cache -t localhost:5000/cosmic:1.0 -f ./spacepet-deploy/test/cosmic .'  
      }  
    }  
  
    stage ('Container Registry - Push & Delete & Pull') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        script {  
          sh 'docker push localhost:5000/cosmic:1.0'  
          sh 'docker rmi localhost:5000/cosmic:1.0'  
          sh 'docker pull localhost:5000/cosmic:1.0'  
        }  
      }  
    }  
  
    stage ('Run Container') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        sh 'docker run -d -v /root/docker_volumn/cosmic:/ --privileged --name cosmic -p 8080:8080 localhost:5000/cosmic:1.0'  
      }  
    }  
  
    stage ('Delete Conflict Image') {  
      when {  
        allOf {  
          branch 'SPACEPET-TEST'  
          tag 'cicd*'  
        }  
      }  
      steps {  
        sh '''  
          dangling_images=$(docker images -f "dangling=true" -q)          if [[ -n "$dangling_images" ]]; then              docker rmi -f $dangling_images || true          fi        '''      }  
    }  
  
  }  
}

๋ฌด์ค‘๋‹จ ๋ฐฐํฌ - Blue Green Deployment

์ง€๋‚œ๋ฒˆ์— ๊ตฌ์ถ•ํ•œ Jenkins + Github Webhook Trigger + AWS EC2, RDS ELB๋ฅผ ์—ฐ๋™ํ•ด์„œ ๊ฐ„๋‹จํ•œ CICD ๋ฐฐํฌ ์„ฑ๊ณต์„ ํ•˜๊ณ ,

์‚ฌ๋‚ด ์š”๊ตฌ์‚ฌํ•ญ ๋ณ€๊ฒฝ์œผ๋กœ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ(zero-downtime)๋ฅผ ๊ตฌ์ถ•ํ•œ ๊ธฐ๋ก์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.



์„ค๊ณ„ํ•  ๋ฐฐํฌ ๊ตฌ์กฐ

  1. ์ƒˆ๋กœ์šด ๋ฒ„์ „์ด Git์— ๋ณ‘ํ•ฉ๋˜๋ฉด,ย Github Webhook์„ ํ†ตํ•ด Jenkins์— ์‹ ํ˜ธ๊ฐ€ ๋“ค์–ด์˜ค๊ณ , ์  ํ‚จ์Šค๋Š”ย ์ตœ์‹  ๋ฒ„์ „์˜ Jar ํŒŒ์ผ์„ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.
  2. ์  ํ‚จ์Šค๋Š”ย Blue์— Health check๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. Blue๊ฐ€ ์‚ด์•„์žˆ๋‹ค๋ฉด ์‹ ๋ฒ„์ „์„ Green์— ๋ฐฐํฌํ•˜๋ฉด ๋˜๊ณ , ์‚ด์•„์žˆ์ง€ ์•Š๋‹ค๋ฉด Blue์— ๋ฐฐํฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  3. ๊ทธ๋ฆผ์ƒ Blue๊ฐ€ ์‚ด์•„์žˆ๋Š” ๊ฒƒ์œผ๋กœ ํŒ๋‹จ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์  ํ‚จ์Šค๋Š” Green์— ๋ฐฐํฌ๋ฅผ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
  4. ์  ํ‚จ์Šค๋Š”ย Green์— ๋งจ ์ฒ˜์Œ ๋นŒ๋“œํ•ด๋‘” Jar ํŒŒ์ผ์„ ์ „์†กํ•˜๊ณ , ์›๊ฒฉ์ง€์—์„œย ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  5. Green์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๊ตฌ๋™๋˜์—ˆ๋Š”์ง€ย 10์ดˆ ์ฃผ๊ธฐ๋กœ Health Check๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. Green ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๊ธฐ๋™๋จ์„ ํ™•์ธํ•˜๋ฉด (6)์œผ๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค.
  6. Nginx์˜ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ๋ฐฉํ–ฅ์„ Blue์—์„œ Green์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ํด๋ผ์ด์–ธํŠธ์˜ ๋ชจ๋“  ํŠธ๋ž˜ํ”ฝ์ด ์‹ ๋ฒ„์ „ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ํ–ฅํ•ฉ๋‹ˆ๋‹ค.
  7. Blue ์ธ์Šคํ„ด์Šค์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฃฝ์ž…๋‹ˆ๋‹ค.

Nginx Reverse Proxy ์„ค์ •

๊ฐ€์šฉ์„ฑ์„ ์œ„ํ•ด Nginx์˜ ํฌํŠธ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋ฅผ 8080 ์‹คํŒจ ์‹œ 8081๋กœ ํฌํŠธ 2๊ฐœ๋ฅผ ์„ค์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Nginx Logging์„ ์œ„ํ•ด ๋กœ๊ทธ ์„ค์ •๋„ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.


nginx.conf

upstream docker-spring {  
      server localhost:8080 weight=10 max_fails=3 fail_timeout=10s;  
      server localhost:8081 weight=5 max_fails=3 fail_timeout=10s;  
}

server {
    listen 80;
    server_name localhost;

    include /etc/nginx/conf.d/service-url.inc;

    location / {
        proxy_pass $service_url;
        proxy_redirect     off;
        proxy_http_version 1.1;
        proxy_set_header   Host $http_host;
        proxy_set_header   Connection "";
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }

		client_max_body_size 100M;

		access_log /var/log/nginx/access.log;
		error_log /var/log/nginx/error.log;
}

์œ„ ์„ค์ •์„ ๋ณด๋ฉดย includeย ๋ผ๋Š” ์ง€์‹œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Š” ์™ธ๋ถ€์—์„œ ์„ค์ • ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋Š” Nginx ์˜ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

location์˜ย proxy_passย ๋ฅผ ๋ณด๋ฉด,ย $service_urlย ๋กœ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋Š”๋ฐ,

service-url.incย ์—์„œ ์ดย $service_urlย ๋ณ€์ˆ˜ ๊ฐ’์„ ์ฑ„์›Œ์ค๋‹ˆ๋‹ค.

service-url.inc

set $service_url http://XXX.XXX.XXX.XXX:8080;

location

  • proxy_pass : ์‚ฌ์šฉ์ค‘์ธ ํ”„๋ก์‹œ URL์„ ์ž…๋ ฅ ํ•ด์ค๋‹ˆ๋‹ค.
  • proxy_redirect : ํ”„๋ก์‹œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋Š” ์‚ฌ์šฉ์„ ํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค.
  • proxy_http_version : HTTP 1.1์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Jenkins ์„ค์ •

ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •

  • nginx_ip, blue_ip, green_ip 3๊ฐœ์˜ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ๊ฐ ์ธ์Šคํ„ด์Šค IP ์ฃผ์†Œ๋ฅผ ๊ฐ’์œผ๋กœ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

๋„์ปค ๋„คํŠธ์›Œํฌ ์ƒ์„ฑ

์ œ ๊ฒฝ์šฐ์—๋Š” ๊ฐ๊ฐ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹Œ ์ปจํ…Œ์ด๋„ˆ ๋ผ๋ฆฌ Blue, Green ๋ฐฐํฌ๋ฅผ ํ• ๊ฒƒ์ด๊ณ  Jenkins์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜์— IP๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋„์ปค ๋„คํŠธ์›Œํฌ๋ฅผ ๋งŒ๋“ค์–ด ์คŒ์œผ๋กœ์จ, Container์˜ IP๋ฅผ ๊ณ ์ •์‹œ์ผœ์„œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ bridge0์— ํ• ๋‹น๋˜์–ด ์žˆ์œผ๋ฉด ์ปจํ…Œ์ด๋„ˆ๋Š” ์žฌ์‹œ์ž‘ ํ• ๋•Œ๋งˆ๋‹ค IP๊ฐ€ ๋ฐ”๋€Œ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์ƒˆ๋กœ์šด Docker Bridge๋ฅผ ๋งŒ๋“ค๊ณ  ์ปจํ…Œ์ด๋„ˆ๋“ค์„ ๊ธฐ๋ณธ bridge0์ด ์•„๋‹Œ Custom Bridge์— ํ• ๋‹น์‹œํ‚ต๋‹ˆ๋‹ค.


docker network create --gateway 172.20.0.1 --subnet 172.20.0.0/16 deploy

์ด ํ›„, docker run์„ ํ•  ๋•Œ --network deploy ์˜ต์…˜๊ณผ --ip 172.20.0.X ๋กœ ์•„์ดํ”ผ๋ฅผ ํ• ๋‹นํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.


์Šคํฌ๋ฆฝํŠธ ์ˆ˜์ •

#!/bin/bash  

# Blue & Green ํƒ€๊ฒŸ ์ง€์ • ๋ณ€์ˆ˜
target=2
deployment_target_ip=""

# Gradlew ๊ถŒํ•œ ๋ถ€์—ฌ  
chmod 500 ./gradlew  
  
# ๋นŒ๋“œ  
#./gradlew clean build --exclude-task test

# ํ…Œ์ŠคํŠธ์šฉ ๋น ๋ฅธ ๋นŒ๋“œ
./gradlew bootJar

# Blue Health Check
if curl -s "http://$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' blue):8080" > /dev/null 
then
	deployment_target_ip=$green_ip
	target=0
else
	deployment_target_ip=$blue_ip
	target=1
fi
  
# Target๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฐ€๋™์ค‘์ธ Spring Boot ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€ & ์‚ญ์ œ  
if [ "$target" -eq 1 ]; then
	if docker ps -a --filter "name=green" | grep -q green; then  
		docker stop green
		docker rm green 
		fuser -s -k 8080/tcp
	fi

	# ๊ธฐ์กด Spring Boot Image ์ค‘ ์ด๋ฏธ์ง€๊ฐ€ ๊ธฐ์กด๊ณผ ๋˜‘๊ฐ™์€๊ฒŒ ์žˆ์œผ๋ฉด ์ด๋ฏธ์ง€ ์‚ญ์ œ  
	if docker images | awk '{print $1":"$2}' | grep -q "localhost:5000/green:1.0"; then  
	  docker rmi -f localhost:5000/green:1.0  
  fi
  
elif [ "$target" -eq 2 ]; then
  if docker ps -a --filter "name=blue" | grep -q blue; then  
		docker stop blue
		docker rm blue
		fuser -s -k 8080/tcp
	fi

	# ๊ธฐ์กด Spring Boot Image ์ค‘ ์ด๋ฏธ์ง€๊ฐ€ ๊ธฐ์กด๊ณผ ๋˜‘๊ฐ™์€๊ฒŒ ์žˆ์œผ๋ฉด ์ด๋ฏธ์ง€ ์‚ญ์ œ  
	if docker images | awk '{print $1":"$2}' | grep -q "localhost:5000/blue:1.0"; then  
	  docker rmi -f localhost:5000/blue:1.0  
  fi
else
	echo "Invalid target Value"
fi
  
# Docker Hub Login & ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์  ํ‚จ์Šค์—์„œ ์„ค์ •ํ•œ ์ „์—ญ๋ณ€์ˆ˜ ์‚ฌ์šฉ  
echo $PASSWORD | docker login -u $USERNAME --password-stdin  

# ๋„์ปคํŒŒ์ผ ๋นŒ๋“œ
if [ "${deployment_target_ip}" == "${blue_ip}" ]; then
	docker build --no-cache -t localhost:5000/blue:1.0 -f ./spacepet-deploy/test/blue .
	
	# Container Registry์— ์ด๋ฏธ์ง€ Push
	docker push localhost:5000/blue:1.0  
  
	# Pushํ•œ ์ด๋ฏธ์ง€ ์‚ญ์ œ  
	docker rmi localhost:5000/blue:1.0  
  
	# Container Registry์—์„œ ์ด๋ฏธ์ง€ Pull
	docker pull localhost:5000/blue:1.0

	# Docker Container ์ƒ์„ฑ  
	docker run -d -v /root/docker_volumn/blue:/app --network deploy --ip 172.20.0.2 --privileged --name blue -p 8080:8080 localhost:5000/blue:1.0  
	
elif [ "${deployment_target_ip}" == "${green_ip}" ]; then
	docker build --no-cache -t localhost:5000/green:1.0 -f ./spacepet-deploy/test/green .
	
	# Container Registry์— ์ด๋ฏธ์ง€ Push
	docker push localhost:5000/green:1.0  
  
	# Pushํ•œ ์ด๋ฏธ์ง€ ์‚ญ์ œ  
	docker rmi localhost:5000/green:1.0  
  
	# Container Registry์—์„œ ์ด๋ฏธ์ง€ Pull
	docker pull localhost:5000/green:1.0

	# Docker Container ์ƒ์„ฑ  
	docker run -d -v /root/docker_volumn/green:/app --network deploy --ip 172.20.0.3 --privileged --name green -p 8080:8080 localhost:5000/green:1.0 
else
	echo "Invalid target Value"
fi
  
# ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ถˆํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ์‚ญ์ œ = ๊ฒน์น˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์กด์žฌํ•˜๋ฉด ์ด๋ฏธ์ง€๋ฅผ ์‚ญ์ œํ•œ๋‹ค  
dangling_images=$(docker images -f "dangling=true" -q)  
if [[ -n "$dangling_images" ]]; then  
    docker rmi -f $dangling_images || true  
fi

# Nginx Reverse Proxy ๋ฐฉํ–ฅ (ํƒ€๊ฒŸ ์ปจํ…Œ์ด๋„ˆ) ๋ณ€๊ฒฝ
ssh root@${nginx_ip} "echo 'set \\\$service_url http://${deployment_target_ip}:8080;' > /etc/nginx/conf.d/service-url.inc && service nginx reload"
echo "Switch the reverse proxy direction of nginx to ${deployment_target_ip} ๐Ÿ”„"

Jenkinsfile

pipeline {  
  agent any  
  
  stages {  
  
    stage('Clean Workspace') {  
      steps {  
        deleteDir()  
      }  
    }  
  
    stage('Checkout') {  
      steps {  
        script {  
          checkout([$class: 'GitSCM',  
  
          branches: [[name: '<branch-name>']],  
          userRemoteConfigs: [[  
          url: 'git@github.com:<user-name>/<repo-name>.git',  
          branch: 'SPACEPET-TEST',  
          credentialsId: '<jenkins-credentials-id>']]])  
        }  
      }  
    }  
  
    stage('Build') {  
      steps {  
        script {  
          def gitTags = sh(returnStdout: true, script: 'git tag --contains HEAD')  
          if (gitTags.contains('cicd')) {  
            sh 'chmod 500 spacepet-deploy/test/script.sh'  
            sh './spacepet-deploy/test/script.sh'  
          } else {  
            echo 'No tag containing "cicd" found.'  
          }  
        }  
      }  
    }  
  }  
}

Dockerfile

FROM openjdk:11  
RUN mkdir -p /app    
WORKDIR /app    
VOLUME /app    
EXPOSE 8080  
ARG JAR=dangnyang-1.7.08-SNAPSHOT.jar    
COPY ../../build/libs/${JAR} /koboot.jar  
RUN chmod +x /koboot.jar  
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=test","-Xmx6144M","/koboot.jar"]

About

๐Ÿ’ป Test CICD - Github Actions & Jenkins

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published