Ssoon
1주 : Jenkins CI/CD + Docker : 4 본문
CloudNet@ 가시다님이 진행하는 CI/CD 맛보기 스터디
✅ 도커 기반 애플리케이션 CI/CD 구성
🧿 Gogs Webhooks 설정 : Jenkins Job Trigger
Webhooks는 시스템 간의 실시간 통신을 가능하게 해주는 HTTP 기반의 알림 시스템입니다. 한 시스템에서 특정 이벤트가 발생하면, 미리 지정된 다른 시스템으로 HTTP 요청(주로 POST 요청)을 보내는 방식입니다. 이를 통해 다른 시스템에서 해당 이벤트에 대해 자동으로 반응할 수 있습니다.
- gogs 에 app.ini 파일 수정
- 컨테이너 재기동
[ssoon@localhost cicd-labs]$ docker compose restart gogs
[+] Restarting 1/1
✔ Container gogs Started
- Settings > Webhooks
- Gogs는 발생한 이벤트에 대한 세부 정보와 함께 사용자가 지정한 URL로 POST 요청을 보냅니다. 또한 훅을 트리거할 때 어떤 종류의 데이터 형식(JSON, x-www-form-urlencoded, XML 등)을 가져올지 지정할 수도 있습니다.
- Payload URL : http://192.168.56.105:8080/gogs-webhook/?job=**SCM-Pipeline**/
- Content Type : application/json
- Secret : qwe123
- When should this webhook be triggered? : Just the push event
- Active : Check
- 웹훅은 기본 HTTP POST 이벤트 트리거와 매우 유사합니다. Gogs에서 어떤 일이 발생할 때마다 사용자가 지정한 대상 호스트에 알림을 처리합니다.
🧿 Jenkins Item 생성(Pipeline) : item name(SCM-Pipeline)
- 새로운 아이템을 생성합니다.
- GitHub project 을 설정합니다.
Jenkins의 GitHub Project는 Jenkins에서 GitHub 저장소를 연결하고, GitHub 이벤트에 따라 자동으로 빌드와 테스트를 실행할 수 있도록 설정하는 기능입니다. 이를 통해 GitHub에서 발생하는 이벤트(예: 코드 푸시, 풀 리퀘스트 생성 등)에 반응하여 Jenkins가 자동으로 작업을 처리하도록 할 수 있습니다.
GitHub Project의 주요 기능
- GitHub 저장소와 연동: Jenkins에서 GitHub 저장소를 지정하면, 해당 저장소의 변경 사항을 감지하고 자동으로 빌드를 트리거할 수 있습니다.
- GitHub 이벤트 트리거: GitHub에서 발생하는 다양한 이벤트(예: 커밋 푸시, 풀 리퀘스트 생성 등)에 반응하여 Jenkins 빌드를 자동으로 시작할 수 있습니다.
- GitHub Webhook을 통한 연동: GitHub에서는 Webhook을 설정하여 Jenkins 서버가 실시간으로 이벤트를 받아 처리하도록 할 수 있습니다. 예를 들어, 코드가 푸시되면 Jenkins가 자동으로 빌드를 실행하게 됩니다.
- Pull Request와 연동: Jenkins는 GitHub에서 풀 리퀘스트(PR) 이벤트를 처리할 수 있습니다. PR이 열리거나 변경되면 Jenkins는 자동으로 해당 PR에 대해 빌드를 수행하고 결과를 GitHub에 보고할 수 있습니다.
- Gogs Webhook 을 설정합니다.
Jenkins의 Gogs Webhook은 Gogs(Git 서버)와 Jenkins를 연결하여, Gogs에서 발생하는 이벤트(예: 코드 푸시, 풀 리퀘스트 등)에 자동으로 반응하여 Jenkins에서 빌드를 실행하는 방법입니다. Webhook을 사용하면 Gogs에서 특정 이벤트가 발생할 때마다 Jenkins에 알림을 보내어 자동화된 작업을 수행할 수 있습니다.
Gogs Webhook의 작동 방식
- Gogs에서 이벤트 발생:
Gogs에서 코드 푸시, 풀 리퀘스트 생성, 또는 다른 이벤트가 발생하면, 이 이벤트를 Jenkins에 알려주는 Webhook이 발동됩니다. - Jenkins에서 Webhook 수신:
Gogs가 이벤트를 발생시키면, 설정된 Webhook을 통해 Jenkins에 HTTP POST 요청을 보내게 됩니다. 이 요청을 받은 Jenkins는 자동으로 빌드를 실행하거나 다른 작업을 수행합니다.
- Build Triggers
Jenkins의 Build Triggers는 빌드를 자동으로 시작할 수 있는 여러 가지 방법을 제공합니다. 이 기능을 사용하면 수동으로 빌드를 실행하지 않고도 다양한 조건에서 자동으로 빌드를 실행할 수 있습니다. 빌드 트리거는 Jenkins Job의 설정에서 활성화할 수 있습니다.
Poll SCM | 정해진 주기로 SCM(버전 관리 시스템)을 폴링하여 변경 사항을 감지하고 빌드를 실행합니다. | H/15 * * * * (15분마다 SCM을 검사) |
GitHub hook trigger for GITScm polling | GitHub에서 푸시 이벤트가 발생할 때 Jenkins가 자동으로 빌드를 실행합니다. | GitHub Webhook을 통해 푸시 이벤트 발생 시 Jenkins 빌드 트리거 |
Build periodically | 지정된 시간에 정기적으로 빌드를 실행합니다. | H 0 * * * (매일 0시마다 실행) |
Trigger builds remotely | 외부 시스템에서 HTTP 요청을 통해 Jenkins 빌드를 트리거합니다. | http://<JENKINS_URL>/job/<JOB_NAME>/build?token=<TOKEN> |
Build after other projects are built | 다른 Jenkins Job이 완료된 후, 의존하는 Job을 자동으로 빌드합니다. | 예: Project A 완료 후 Project B 실행 |
GitHub Pull Request Builder | GitHub에서 풀 리퀘스트(PR) 생성 또는 업데이트 시 빌드를 트리거합니다. | PR 생성 시 Jenkins가 자동으로 빌드 실행 |
Build when a change is pushed to Gogs | Gogs 에서 푸시 이벤트가 발생할 때 Jenkins가 자동으로 빌드를 실행합니다. | Gogs Webhook을 통해 푸시 이벤트 발생 시 빌드 트리거 |
External Trigger | 외부 시스템에서 HTTP 요청을 통해 Jenkins 빌드를 트리거합니다. | 외부 시스템에서 Jenkins API 호출을 통해 빌드 실행 |
- Pipeline script from SCM 을 설정합니다.
Jenkins Pipeline에서 SCM 설정은 소스 코드 관리 시스템(Git, SVN 등)에서 코드를 가져와 빌드 과정에 사용할 수 있게 설정하는 부분입니다. Pipeline에서는 SCM을 사용해 저장소에서 코드를 가져오고, 빌드와 테스트를 자동화하는 작업을 할 수 있습니다.
- SCM : Git
- Repo URL(http://***<mac IP>***:3000/***<Gogs 계정명>***/dev-app)
- Credentials(devops/***)
- Branch(*/main)
- Script Path : Jenkinsfile
Jenkins Pipeline에서의 scriptPath는 Multibranch Pipeline 또는 Pipeline from SCM에서 Jenkinsfile의 위치를 지정하는 데 사용됩니다. Jenkins는 기본적으로 저장소의 루트 디렉토리에서 Jenkinsfile을 찾습니다. 그러나 프로젝트 구조에 따라 Jenkinsfile이 저장소의 서브디렉토리 안에 있을 수 있습니다. 이럴 때 scriptPath를 사용하여 정확한 경로를 지정할 수 있습니다.
🧿 Jenkinsfile 작성 후 Git push
- 버전 0.0.2 로 수정합니다.
- Jenkinsfile 작성합니다.
Jenkinsfile은 Jenkins Pipeline을 정의하는 스크립트 파일입니다. 이 파일은 Jenkins에서 CI/CD(지속적 통합 및 지속적 배포) 파이프라인을 자동화하고 관리하는 데 사용됩니다. Jenkinsfile은 파이프라인의 구성 요소, 즉 빌드, 테스트, 배포 등 여러 단계를 정의하고 조정하는 역할을 합니다.
Jenkinsfile의 기본 개념
- 스크립트 기반: Jenkinsfile은 Groovy 언어를 사용하여 작성됩니다. Groovy는 자바 기반의 스크립트 언어로, Jenkins Pipeline을 구성할 때 유용합니다.
- 버전 관리: Jenkinsfile은 소스 코드 저장소(예: Git, GitHub, Bitbucket)에 저장되어 코드와 함께 관리됩니다. 이를 통해 파이프라인 정의를 버전 관리할 수 있습니다.
작동 흐름
- Checkout: Git 저장소에서 코드를 가져옵니다.
- Read VERSION: 프로젝트 디렉토리 내 VERSION 파일을 읽고, 그 값을 사용해 Docker 이미지 태그를 설정합니다.
- Docker Build and Push: 설정된 태그를 사용하여 Docker 이미지를 빌드하고, Docker Hub로 이미지를 푸시합니다.
- Post Actions: 빌드 성공 또는 실패에 따라 메시지를 출력합니다.
pipeline {
agent any
environment {
DOCKER_IMAGE = '<자신의 도커 허브 계정>/dev-app' // Docker 이미지 이름
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'http://192.168.254.124:3000/devops/dev-app.git', // Git에서 코드 체크아웃
credentialsId: 'gogs-dev-app' // Credentials ID
}
}
stage('Read VERSION') {
steps {
script {
// VERSION 파일 읽기
def version = readFile('VERSION').trim()
echo "Version found: ${version}"
// 환경 변수 설정
env.DOCKER_TAG = version
}
}
}
stage('Docker Build and Push') {
steps {
script {
docker.withRegistry('https://index.docker.io/v1/', 'dockerhub-credentials') {
// DOCKER_TAG 사용
def appImage = docker.build("${DOCKER_IMAGE}:${DOCKER_TAG}")
appImage.push()
}
}
}
}
}
post {
success {
echo "Docker image ${DOCKER_IMAGE}:${DOCKER_TAG} has been built and pushed successfully!"
}
failure {
echo "Pipeline failed. Please check the logs."
}
}
}
- 수정된 파일(VERSION) 과 추가한 파일(Jenkinsfile) 을 push 합니다.
[ssoon@localhost dev-app]$ git add .
[ssoon@localhost dev-app]$ git status
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.
커밋할 변경 사항:
(use "git restore --staged <file>..." to unstage)
새 파일: Jenkinsfile
수정함: VERSION
[ssoon@localhost dev-app]$ git commit -m "Jenkinsfile add & VERSION 0.0.2 Changed"
[main 6abaf13] Jenkinsfile add & VERSION 0.0.2 Changed
2 files changed, 46 insertions(+), 1 deletion(-)
create mode 100644 Jenkinsfile
[ssoon@localhost dev-app]$ git status
현재 브랜치 main
브랜치가 'origin/main'보다 1개 커밋만큼 앞에 있습니다.
(로컬에 있는 커밋을 제출하려면 "git push"를 사용하십시오)
커밋할 사항 없음, 작업 폴더 깨끗함
[ssoon@localhost dev-app]$ git push -u origin main
Username for 'http://192.168.56.105:3000': devops
Password for 'http://devops@192.168.56.105:3000':
오브젝트 나열하는 중: 6, 완료.
오브젝트 개수 세는 중: 100% (6/6), 완료.
Delta compression using up to 4 threads
오브젝트 압축하는 중: 100% (3/3), 완료.
오브젝트 쓰는 중: 100% (4/4), 950 bytes | 950.00 KiB/s, 완료.
Total 4 (delta 1), reused 0 (delta 0), pack-reused 0
To http://192.168.56.105:3000/devops/dev-app.git
f180896..6abaf13 main -> main
branch 'main' set up to track 'origin/main'.
- Jenkins 트리거 빌드을 확인합니다.
- docker hub에 push 된 이미지를 확인합니다.
- Gogs WebHook 기록을 확인합니다.
🧿 도커 빌드 후 기존 컨테이너 중지/제거 후 신규 컨테이너 실행 Jenkinsfile pipeline 수정 후 빌드 (SCM-Pipeline)
- Jenkinsfile 수정 합니다.
작동 흐름
- Checkout: Git에서 코드를 가져옵니다.
- Read VERSION: VERSION 파일을 읽어 Docker 이미지 태그로 사용할 버전 정보를 설정합니다.
- Docker Build and Push: Docker 이미지를 빌드하고 Docker Hub에 푸시합니다.
- Check, Stop and Run Docker Container:
- 이미 실행 중인 컨테이너가 있으면 중지하고 제거합니다.
- 5초 대기 후 새로 빌드한 이미지를 기반으로 컨테이너를 실행합니다.
- Post Actions: 빌드 성공 또는 실패에 따라 후속 작업을 처리합니다.
주요 변수 및 설정
- DOCKER_IMAGE: Docker 이미지의 이름입니다.
- CONTAINER_NAME: Docker 컨테이너의 이름입니다.
- gogs-dev-app: Git 저장소 인증을 위한 Jenkins의 Credentials ID입니다.
- dockerhub-credentials: Docker Hub 인증을 위한 Jenkins의 Credentials ID입니다.
pipeline {
agent any
environment {
DOCKER_IMAGE = 'kschoi728/dev-app' // Docker 이미지 이름
CONTAINER_NAME = 'dev-app' // 컨테이너 이름
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'http://192.168.56.105:3000/devops/dev-app.git', // Git에서 코드 체크아웃
credentialsId: 'gogs-dev-app' // Credentials ID
}
}
stage('Read VERSION') {
steps {
script {
// VERSION 파일 읽기
def version = readFile('VERSION').trim()
echo "Version found: ${version}"
// 환경 변수 설정
env.DOCKER_TAG = version
}
}
}
stage('Docker Build and Push') {
steps {
script {
docker.withRegistry('https://index.docker.io/v1/', 'dockerhub-credentials') {
// DOCKER_TAG 사용
def appImage = docker.build("${DOCKER_IMAGE}:${DOCKER_TAG}")
appImage.push()
appImage.push("latest") // 빌드 이미지 push 할 때, 2개의 버전(현재 버전, latest 버전)을 업로드
}
}
}
}
stage('Check, Stop and Run Docker Container') {
steps {
script {
// 실행 중인 컨테이너 확인
def isRunning = sh(
script: "docker ps -q -f name=${CONTAINER_NAME}",
returnStdout: true
).trim()
if (isRunning) {
echo "Container '${CONTAINER_NAME}' is already running. Stopping it..."
// 실행 중인 컨테이너 중지
sh "docker stop ${CONTAINER_NAME}"
// 컨테이너 제거
sh "docker rm ${CONTAINER_NAME}"
echo "Container '${CONTAINER_NAME}' stopped and removed."
} else {
echo "Container '${CONTAINER_NAME}' is not running."
}
// 5초 대기
echo "Waiting for 5 seconds before starting the new container..."
sleep(5)
// 신규 컨테이너 실행
echo "Starting a new container '${CONTAINER_NAME}'..."
sh """
docker run -d --name ${CONTAINER_NAME} -p 4000:80 ${DOCKER_IMAGE}:${DOCKER_TAG}
"""
}
}
}
}
post {
success {
echo "Docker image ${DOCKER_IMAGE}:${DOCKER_TAG} has been built and pushed successfully!"
}
failure {
echo "Pipeline failed. Please check the logs."
}
}
}
- git push 합니다.
[ssoon@localhost dev-app]$ git add .
[ssoon@localhost dev-app]$ git status
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.
커밋할 변경 사항:
(use "git restore --staged <file>..." to unstage)
수정함: Jenkinsfile
[ssoon@localhost dev-app]$ git commit -m "Jenkinsfile Changed"
[main 5a94907] Jenkinsfile Changed
1 file changed, 34 insertions(+)
[ssoon@localhost dev-app]$ git status
현재 브랜치 main
브랜치가 'origin/main'보다 1개 커밋만큼 앞에 있습니다.
(로컬에 있는 커밋을 제출하려면 "git push"를 사용하십시오)
커밋할 사항 없음, 작업 폴더 깨끗함
[ssoon@localhost dev-app]$ git push -u origin main
Username for 'http://192.168.56.105:3000': devops
Password for 'http://devops@192.168.56.105:3000':
오브젝트 나열하는 중: 5, 완료.
오브젝트 개수 세는 중: 100% (5/5), 완료.
Delta compression using up to 4 threads
오브젝트 압축하는 중: 100% (3/3), 완료.
오브젝트 쓰는 중: 100% (3/3), 1.28 KiB | 1.28 MiB/s, 완료.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
To http://192.168.56.105:3000/devops/dev-app.git
6abaf13..5a94907 main -> main
branch 'main' set up to track 'origin/main'.
- Jenkins 트리거 빌드을 확인합니다.
- docker hub에 push 된 이미지를 확인합니다.
- 생성된 컨테이너를 확인합니다.
[ssoon@localhost dev-app]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2c627841ea90 kschoi728/dev-app:0.0.2 "python3 server.py" 2 minutes ago Up 2 minutes 0.0.0.0:4000->80/tcp, [::]:4000->80/tcp
[ssoon@localhost dev-app]$ curl http://127.0.0.1:4000
The time is 1:23:23 AM, CloudNeta Study.
- server.py 및 VERSION 을 수정 합니다.
response_string = now.strftime("The time is %-I:%M:%S %p, SSOON.\n")
0.0.3
- git push 합니다.
[ssoon@localhost dev-app]$ git status
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.
커밋하도록 정하지 않은 변경 사항:
(무엇을 커밋할지 바꾸려면 "git add <파일>..."을 사용하십시오)
(use "git restore <file>..." to discard changes in working directory)
수정함: VERSION
수정함: server.py
커밋할 변경 사항을 추가하지 않았습니다 ("git add" 및/또는 "git commit -a"를
사용하십시오)
[ssoon@localhost dev-app]$ git add .
[ssoon@localhost dev-app]$ git status
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.
커밋할 변경 사항:
(use "git restore --staged <file>..." to unstage)
수정함: VERSION
수정함: server.py
[ssoon@localhost dev-app]$ git commit -m "VERSION $(cat VERSION) Changed"
[main dc1a98e] VERSION 0.0.3 Changed
2 files changed, 2 insertions(+), 2 deletions(-)
[ssoon@localhost dev-app]$ git status
현재 브랜치 main
브랜치가 'origin/main'보다 1개 커밋만큼 앞에 있습니다.
(로컬에 있는 커밋을 제출하려면 "git push"를 사용하십시오)
커밋할 사항 없음, 작업 폴더 깨끗함
[ssoon@localhost dev-app]$ git push -u origin main
Username for 'http://192.168.56.105:3000': devops
Password for 'http://devops@192.168.56.105:3000':
오브젝트 나열하는 중: 7, 완료.
오브젝트 개수 세는 중: 100% (7/7), 완료.
Delta compression using up to 4 threads
오브젝트 압축하는 중: 100% (3/3), 완료.
오브젝트 쓰는 중: 100% (4/4), 354 bytes | 354.00 KiB/s, 완료.
Total 4 (delta 2), reused 0 (delta 0), pack-reused 0
To http://192.168.56.105:3000/devops/dev-app.git
5a94907..dc1a98e main -> main
branch 'main' set up to track 'origin/main'.
- Jenkins 트리거 빌드을 확인합니다.
- 서비스 중단 시간을 확인합니다.
'CICD 맛보기' 카테고리의 다른 글
1주 : Jenkins CI/CD + Docker : 3 (0) | 2024.12.04 |
---|---|
1주 : Jenkins CI/CD + Docker : 2 (0) | 2024.12.03 |
1주 : Jenkins CI/CD + Docker : 1 (0) | 2024.12.02 |