들어가면서(Intro)
CI/CD를 위해서 많은 사람들이 젠킨스를 활용한다. 젠킨스는 유저에게 강력한 GUI를 제공하여 편하게 설정을 추가하고 제거하는 것이 강점이다. 하지만 한번 설정한 후에는 거의 변경되지 않기 때문에 실수로 젠킨스 설정이 초기화되거나 하면 해당 설정이 기억나지 않아서 매우 난감한 상황이 벌어진다. 그래서 이런 상황을 피하기 위해서 세팅 방법을 따로 문서로 저장해 두거나 jenkins_home을 따로 저장해 두는 것도 방법이지만 이는 좋은 방법은 아닐 것이다. 좋은 방법은 초기 설정을 스크립트로 작성해서 관리하면 언제든지 도커로 매번 동일한 설정으로 젠킨스를 재설치할 수 있으며 해당 스크립트로 형상 관리 툴에 저장해서 이력을 관리하기 쉬울 것이다.
설정을 위해 Groovy 스크립트를 사용하는 이유(Why Groovy Scripts)
젠킨스는 Java로 작성되었으며, Groovy는 내부적으로 JVM 기반 스크립팅 언어로 Java와의 통합성이 뛰어나다. 그리고 안타깝게도 젠킨스 초기 설정 스크립트는 Groovy 언어만을 지원한다. 이는 젠킨스의 내부 API와 상호작용할 수 있는 기본 언어로 안타깝게도 Groovy가 선택되었기 때문이다.
Dockerfile에서 Groovy 초기화 스크립트 복사
로컬에서 나에게 맞는 내용으로 수정한 스크립트가 컨테이너 실행시 추가될 수 있도록 Dockerfile에서 추가해주도록 하자.
FROM jenkins/jenkins:lts
USER root
# Groovy 스크립트 복사
COPY init.groovy.d/ /usr/share/jenkins/ref/init.groovy.d/
USER jenkins
프로젝트 생성 스크립트(Project Add Scripts)
젠킨스 메뉴 '새로운 Item' 메뉴로 추가 가능한 항목을 '프로젝트'라고 한다. 프로젝트는 젠킨스가 제공하는 가장 기본적인 유형이며 단순한 빌드, 테스트, 배포 작업을 설정하는데 적합하다.
import jenkins.model.*
import hudson.model.*
// Jenkins 인스턴스 가져오기
def instance = Jenkins.getInstance()
// 프로젝트 이름 지정
def projectName = "MyFreestyleProject"
// Freestyle Project 생성
def freestyleProject = new FreeStyleProject(instance, projectName)
instance.add(freestyleProject)
println "Freestyle Project '${projectName}' has been created."
// 프로젝트 저장
freestyleProject.save()
println "Freestyle Project '${projectName}' has been saved."
Subversion & Credential 실행 스크립트(Subversion & Credential Setting Scripts)
형상 관리 툴인 Subversion을 실행해서 저장소에서 최신의 데이터를 가져와서 여러가지 작업이 가능하다.
import jenkins.model.*
import hudson.model.*
import hudson.scm.*
import hudson.scm.subversion.*
import com.cloudbees.plugins.credentials.CredentialsScope
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl
import com.cloudbees.plugins.credentials.domains.Domain
import org.jenkinsci.plugins.credentialsbinding.impl.*
// Subversion Credentials 추가
def svnUsername = "" // Subversion 사용자 이름
def svnPassword = "" // Subversion 비밀번호
def credentialsId = "" // Jenkins에서 참조할 ID
def svnCredentials = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL, // 범위
credentialsId, // ID
"", // 설명
svnUsername, // 사용자 이름
svnPassword // 비밀번호
)
// Credentials 저장
credentialsStore.addCredentials(Domain.global(), svnCredentials)
println("Subversion credentials added with ID '${credentialsId}'.")
// Jenkins 인스턴스 가져오기
def instance = Jenkins.getInstance()
def jobName = "job-name"
def job = instance.getItem(jobName)
if (job == null) {
println("Creating new Freestyle project: ${jobName}")
// Freestyle 프로젝트 생성
job = new FreeStyleProject(instance, jobName)
instance.add(job, jobName)
// Subversion 설정
def depthOption = "infinity"
// SubversionSCM.ModuleLocation 객체 생성
def moduleLocation = new SubversionSCM.ModuleLocation("http://svn.co.kr/svn", credentialsId, "./", depthOption, true, true)
// SubversionSCM 객체 생성
def svnSCM = new SubversionSCM(
[moduleLocation], // ModuleLocation 리스트
null, // workspaceUpdater
null, // browser
"", // excludedRegions
"", // excludedUsers
"", // excludedRevprop
"", // excludedCommitMessages
"", // includedRegions
false, // ignoreDirPropChanges
false, // filterChangelog
null, // additionalCredentials
true // quietOperation
)
job.setScm(svnSCM)
// 빌드 환경 설정: Use secret text(s) or file(s) - Username and Password (separated)
def usernamePasswordBinding = new UsernamePasswordMultiBinding(
"svn_username", // 사용자 이름이 바인딩될 환경 변수 이름
"svn_password", // 비밀번호가 바인딩될 환경 변수 이름
"credential_ID" // Jenkins Credentials ID
)
def buildWrapper = new SecretBuildWrapper([usernamePasswordBinding])
job.getBuildWrappersList().add(buildWrapper)
job.save()
println("Freestyle project '${jobName}' created with Subversion checkout configuration.")
} else {
println("Freestyle project '${jobName}' already exists.")
}
파워쉘 설정 및 실행 스크립트(PowerShell Execute Scripts)
import jenkins.model.*
import hudson.model.*
import hudson.plugins.powershell.PowerShell
def jobName = "powershell-job"
def job = instance.getItem(jobName)
if (job == null) {
println("Creating new Freestyle project: ${jobName}")
// Freestyle 프로젝트 생성
job = new FreeStyleProject(instance, jobName)
instance.add(job, jobName)
// PowerShell Build Step 추가
def powershellCommand = '''스크립트를 이곳에 추가'''.stripIndent()
def powershellStep = new PowerShell(powershellCommand, true, true, 0)
job.buildersList.add(powershellStep)
job.save()
println("Freestyle project '${jobName}' created with Subversion checkout configuration.")
} else {
println("Freestyle project '${jobName}' already exists.")
}
Publish Over SSH 설정 스크립트(Publish Over SSH Setting Scripts)
def jobName = "job-name"
def job = instance.getItem(jobName)
if (job == null) {
println "Creating project '${jobName}'"
job = new FreeStyleProject(instance, jobName)
instance.add(job, jobName)
def command = '''실행 커맨드 내용 추가'''.stripIndent()
// **Step 2: Configure SSH Publisher for file transfer**
def transferSet = new BapSshTransfer(
"", // sourceFiles
"", // excludes
"", // remoteDirectory
"", // removePrefix
false, // remoteDirectorySDF
false, // flatten
command, // execCommand
120000, // execTimeout
false, // usePty
false, // keepFilePermissions
false, // noDefaultExcludes
false, // makeEmptyDirs
"[, ]+" // patternSeparator
)
// SSH Publisher 설정
def sshPublisher = new BapSshPublisher(
"", // Jenkins에 등록된 SSH 서버 이름
true, // verbose
[transferSet], // Transfer Set
false,
false,
null,
null,
null
)
def sshPublisherPlugin = new BapSshPublisherPlugin(
[sshPublisher],
false,
false,
false,
"",
null
)
// 빌드 스텝에 추가
job.publishersList.add(sshPublisherPlugin)
job.save()
println "Project '${jobName}' created successfully with Copy Artifacts and SSH Execution steps."
} else {
println "Project '${jobName}' already exists."
}
.NET 빌드해서 빌드 결과물 아티팩트로 보관하기(Dotnet Build and Build Archive to Artifact)
def jobName = "project-build"
def job = instance.getItem(jobName)
if (job == null) {
println("Creating new Freestyle project: ${jobName}")
job = new FreeStyleProject(instance, jobName)
instance.add(job, jobName)
def credentialsId = "credential-id" // Jenkins Credentials ID
def depthOption = "infinity"
// SubversionSCM.ModuleLocation 객체 생성
def moduleLocation = new SubversionSCM.ModuleLocation("http://svn/svn/", credentialsId, ".", depthOption, true, true)
// SubversionSCM 객체 생성
def svnSCM = new SubversionSCM(
[moduleLocation], // ModuleLocation 리스트
null, // workspaceUpdater
null, // browser
"", // excludedRegions
"", // excludedUsers
"", // excludedRevprop
"", // excludedCommitMessages
"", // includedRegions
false, // ignoreDirPropChanges
false, // filterChangelog
null, // additionalCredentials
false // quietOperation
)
// Check-out Strategy 설정: Emulate Clean Checkout
svnSCM.setWorkspaceUpdater(new UpdateWithCleanUpdater())
job.setScm(svnSCM)
// .NET Publish Project 빌드 스텝 추가
def command = '''dotnet publish ./ `
--configuration Release `
--framework net8.0 `
--runtime linux-x64 `
--self-contained false `
--output ./Bin `
-p:PublishSingleFile=true'''.stripIndent()
def step = new PowerShell(command, true, true, 0)
job.buildersList.add(step)
// 빌드 후 조치: Archive the artifacts 설정 추가
def artifactArchiver = new ArtifactArchiver("") // 경로 추가
artifactArchiver.setExcludes("");
artifactArchiver.setOnlyIfSuccessful(true) // 빌드 성공 시에만 아카이브 수행 (옵션)
artifactArchiver.setDefaultExcludes(true)
artifactArchiver.setCaseSensitive(true)
artifactArchiver.setFollowSymlinks(false)
// 빌드 후 조치에 추가
job.getPublishersList().add(artifactArchiver)
job.save()
println("Freestyle project '${jobName}' created with Subversion checkout configuration.")
} else {
println("Freestyle project '${jobName}' already exists.")
}
다른 프로젝트에서 아티팩트 복사 허용하기(CopyArtifact Permission to Another Project)
job = new FreeStyleProject(instance, jobName1)
instance.add(job, jobName1)
// 아티팩트를 복사할 수 있는 프로젝트 이름 추가
def permissionProperty = new CopyArtifactPermissionProperty("target-project")
// 대상 프로젝트에 권한 속성 추가
job.addProperty(permissionProperty)
다른 프로젝트에서 아티팩트 복사하기(Copy Artifact From Another Project Scripts)
def jobName = "job-name"
def job = instance.getItem(jobName)
if (job == null) {
println "Creating project '${jobName}'"
job = new FreeStyleProject(instance, jobName)
instance.add(job, jobName)
// 빌드 환경 세팅
def preBuildCleanup = new PreBuildCleanup(null, false, "", "", false)
job.getBuildWrappersList().add(preBuildCleanup)
// **Step 1: Copy artifacts from another project**
def copyArtifactStep = new CopyArtifact("project-name")
// build selector 세팅
def buildselector = new StatusBuildSelector()
buildselector.setStable(false)
copyArtifactStep.setSelector(buildselector)
// 빌드 스텝에 추가
job.buildersList.add(copyArtifactStep)
job.save()
println "Project '${jobName}' created successfully with Copy Artifacts and SSH Execution steps."
} else {
println "Project '${jobName}' already exists."
}
반복적으로 빌드 유발 추가(Add Build Trigger)
import jenkins.model.*
import hudson.model.*
import hudson.triggers.*
// Jenkins 인스턴스 가져오기
def instance = Jenkins.getInstance()
// 프로젝트 이름
def projectName = "MyFreestyleProject"
// 기존 프로젝트 가져오기 또는 새로 생성
def project = instance.getItem(projectName)
if (project == null) {
project = new FreeStyleProject(instance, projectName)
instance.add(project)
println "Freestyle Project '${projectName}' has been created."
} else {
println "Freestyle Project '${projectName}' already exists."
}
// Build periodically 트리거 설정
def timerTrigger = new TimerTrigger("H/15 * * * *") // 매 15분마다 빌드
timerTrigger.start(project, true) // 트리거 초기화
project.addTrigger(timerTrigger)
// 프로젝트 저장
project.save()
println "Freestyle Project '${projectName}' has been saved with periodic build schedule."
참고하면 좋은 사이트
'프로그래밍 > 젠킨스(Jenkins)' 카테고리의 다른 글
젠킨스(Jenkins) 시간 설정 (3) | 2024.12.20 |
---|---|
젠킨스(Jenkins) Publish over SSH 사용하기 (0) | 2024.12.09 |
윈도우 재부팅시 젠킨스(Jenkins)가 자동 시작되지 않는 현상 해결하기 (0) | 2024.11.18 |
젠킨스(Jenkins) 접속 URL 변경하기 (2) | 2024.11.14 |
젠킨스(Jenkins) PowerShell SVN: E175013 Access to 'directory' forbidden 문제 해결하기 (0) | 2024.10.23 |
댓글