설치한 Jenkins에서 명령 한 줄을 실행하는 것과 팀이 다시 사용할 자동화를 만드는 것은 조금 다릅니다. 첫 작업에서는 실행 위치부터 확인하고, 그다음에는 명령의 순서를 Git에 남겨 보겠습니다. 예제는 외부 Python 패키지가 필요 없는 덧셈 함수와 테스트 두 개입니다.
Jenkins 시작하기 · 01 Ubuntu 설치 · 02 Rocky Linux 9 설치 · 03 첫 작업과 Pipeline · 04 자동화 활용
이 글의 목차
컨트롤러는 관리하고 에이전트가 실행한다

컨트롤러는 작업 설정·실행 대기열·자격 증명을 관리합니다. 에이전트는 실제로 셸 명령을 실행하는 머신입니다. 실행기(executor)는 동시에 실행할 수 있는 작업 슬롯이고, 워크스페이스(workspace)는 그 작업이 파일을 체크아웃하고 처리하는 작업 디렉터리예요.
컨트롤러에서 빌드를 실행하면 빌드가 읽을 수 있는 파일과 컨트롤러의 민감한 파일이 같은 머신에 놓입니다. 그래서 이 실습은 별도 에이전트를 연결한 뒤 내장 노드의 실행기 수를 0으로 바꿉니다. 컨트롤러 격리 권고와 에이전트 사용 안내를 함께 참고할 수 있습니다.
1. 학습용 Linux 에이전트를 준비한다
에이전트는 컨트롤러와 다른 VM이며, 주소는 예시로 192.168.56.31을 사용합니다. VM에 SSH 서버가 준비되어 있어야 합니다. Ubuntu 또는 Rocky Linux 중 해당하는 패키지 명령 한 가지만 실행하세요.
Ubuntu 에이전트
sudo apt update
sudo apt install -y openjdk-21-jre-headless git python3
Rocky Linux 9 에이전트
sudo dnf install -y java-21-openjdk-headless git python3
sudo useradd --create-home --shell /bin/bash ciagent
sudo install -d -o ciagent -g ciagent -m 0750 /home/ciagent/work
sudo install -d -o ciagent -g ciagent -m 0700 /home/ciagent/.ssh
java -version
git --version
python3 --version
ciagent는 새 실습 계정 예시입니다. 이미 같은 이름이 있으면 계정을 다시 만들지 말고 용도와 권한을 먼저 확인합니다. 이 계정에 sudo 권한을 줄 필요는 없습니다. 컨트롤러가 사용할 SSH 키의 공개키를 이 계정의 ~/.ssh/authorized_keys에 등록하고, 파일 소유자를 ciagent, 권한을 0600으로 설정합니다.
관리 PC에서 전용 키를 만들고 공개키 파일만 에이전트로 보냅니다. 아래는 새 키 파일 이름을 jenkins-ciagent로 정한 예시입니다. 기존에 같은 파일이 있으면 덮어쓰지 말고 다른 이름을 사용하세요. 생성 도중 설정한 passphrase는 나중에 Jenkins 자격 증명에도 입력합니다.
ssh-keygen -t ed25519 -f ./jenkins-ciagent -C jenkins-ciagent
scp ./jenkins-ciagent.pub labadmin@192.168.56.31:/tmp/jenkins-ciagent.pub
에이전트 VM의 관리자 터미널에서 공개키를 등록합니다. labadmin과 IP는 자신이 SSH로 관리할 수 있는 VM의 값으로 바꿉니다.
sudo tee -a /home/ciagent/.ssh/authorized_keys < /tmp/jenkins-ciagent.pub >/dev/null
sudo chown ciagent:ciagent /home/ciagent/.ssh/authorized_keys
sudo chmod 0600 /home/ciagent/.ssh/authorized_keys
rm -f /tmp/jenkins-ciagent.pub
개인키는 Jenkins의 Credentials → SSH Username with private key에 Username ciagent, ID linux-ci-ssh로 등록합니다. Private Key의 Enter directly에 개인키 파일 내용을 입력하고, 키를 만들 때 설정한 passphrase도 함께 넣습니다. System 범위는 Jenkins 자체의 에이전트 연결에 사용할 때 적합합니다. 키와 암호를 Git에 넣지 않습니다. Jenkins 자격 증명 안내에서 종류와 사용 범위를 확인하세요.
2. SSH 에이전트를 등록한다
- Manage Jenkins → Plugins에서 SSH Build Agents가 설치되어 있는지 확인합니다.
- Manage Jenkins → Nodes → New Node에서
linux-ci-01이라는 Permanent Agent를 만듭니다. - Remote root directory는
/home/ciagent/work, Labels는linux-ci, 실행기는 학습 시작값으로 1을 지정합니다. - Usage는 라벨 표현식과 일치하는 작업만 실행하는 방식으로 지정합니다.
- Launch method는 Launch agents via SSH, Host는 실제 에이전트 IP, Credentials는
linux-ci-ssh로 선택합니다. - SSH 호스트 키 검증은 Known hosts file Verification Strategy를 사용합니다. 아래 절차로 컨트롤러의 jenkins 계정에 호스트 키를 등록한 후 연결합니다.
- 에이전트가 Online이 되면 내장 노드(Built-In Node)의 실행기를 0으로 설정합니다.
호스트 키는 연결 상대 서버의 신원을 확인하는 값입니다. 에이전트 콘솔에서 아래 명령으로 지문을 확인합니다.
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
컨트롤러에서 다음 명령으로 수집한 지문이 에이전트 콘솔의 값과 같은지 대조합니다. 일치할 때만 마지막 두 줄로 known_hosts에 등록하세요. ssh-keyscan 결과를 받았다는 사실만으로 상대를 신뢰하지는 않습니다.
CI_HOSTKEY_FILE=$(mktemp)
ssh-keyscan -t ed25519 192.168.56.31 > "$CI_HOSTKEY_FILE"
ssh-keygen -lf "$CI_HOSTKEY_FILE"
# 에이전트 콘솔의 지문과 대조해 일치한 경우에만 진행
sudo install -d -o jenkins -g jenkins -m 0700 /var/lib/jenkins/.ssh
sudo tee -a /var/lib/jenkins/.ssh/known_hosts < "$CI_HOSTKEY_FILE" >/dev/null
sudo chown jenkins:jenkins /var/lib/jenkins/.ssh/known_hosts
sudo chmod 0600 /var/lib/jenkins/.ssh/known_hosts
rm -f "$CI_HOSTKEY_FILE"
SSH 방식은 컨트롤러에서 에이전트의 SSH 포트로 연결합니다. 이 예제 때문에 컨트롤러에 50000번 인바운드 포트를 따로 열 필요는 없습니다. 플러그인의 연결 방식과 검증 옵션은 SSH Build Agents 문서를 기준으로 확인했습니다.
3. Freestyle 작업으로 실행 위치를 확인한다
- 대시보드에서 New Item → Freestyle project로
first-agent-check를 만듭니다. - 작업의 실행 위치 제한(Restrict where this project can be run)에
linux-ci를 입력합니다. - Build Steps에서 Execute shell을 추가하고 아래 명령을 저장합니다.
- Build Now → 해당 빌드 → Console Output에서 사용자·경로·도구 버전을 확인합니다.
set -eu
whoami
hostname
pwd
java -version
python3 --version
git --version
사용자가 ciagent이고 경로가 에이전트의 work 하위라면 의도한 곳에서 실행된 것입니다. 콘솔의 성공 표시보다 먼저 이 두 값을 보세요. PC에서 되는 명령이 Jenkins에서 안 될 때는 실행 계정·PATH·현재 디렉터리가 달라진 경우가 많습니다.
4. 테스트할 작은 Git 저장소를 만든다
자신이 관리하는 Git 저장소에 다음 세 파일을 저장합니다. 테스트는 Python 표준 라이브러리 unittest만 사용하므로 pip 설치가 필요 없습니다.
jenkins-demo/
├── app.py
├── tests/
│ └── test_app.py
└── Jenkinsfile
app.py
def add(a, b):
return a + b
tests/test_app.py
import unittest
from app import add
class AddTest(unittest.TestCase):
def test_positive_numbers(self):
self.assertEqual(add(2, 3), 5)
def test_negative_numbers(self):
self.assertEqual(add(-2, -3), -5)
if __name__ == "__main__":
unittest.main()
저장소 루트에서 python3 -m unittest discover -s tests -v를 실행해 두 테스트가 통과하는지 먼저 확인합니다. 이 예제의 Python 파일과 패키지 생성 명령은 별도 작업 디렉터리에서 실행해 확인했습니다. Jenkins 안의 연결·권한·플러그인 조합은 자신의 VM에서 아래 절차로 확인해야 합니다.
5. Jenkinsfile에 실행 순서를 적는다
pipeline {
agent { label 'linux-ci' }
options {
skipDefaultCheckout(true)
disableConcurrentBuilds()
timeout(time: 10, unit: 'MINUTES')
buildDiscarder(logRotator(numToKeepStr: '20'))
}
stages {
stage('Checkout') {
steps {
deleteDir()
checkout scm
}
}
stage('Test') {
steps {
sh 'python3 -m unittest discover -s tests -v'
}
}
stage('Package') {
steps {
sh 'mkdir -p dist && tar -czf dist/app.tgz app.py'
}
}
stage('Archive') {
steps {
archiveArtifacts artifacts: 'dist/app.tgz', fingerprint: true
}
}
}
post {
success { echo 'Tests passed; artifact archived.' }
failure { echo 'Build failed. Check the first failing stage.' }
cleanup { deleteDir() }
}
}
skipDefaultCheckout(true)로 자동 체크아웃을 생략하고, Checkout 단계에서 checkout scm을 한 번 명시적으로 실행합니다. SCM은 소스 관리 저장소를 뜻해요. 이 예제는 다음 단계에서 만드는 Pipeline script from SCM 작업을 전제로 합니다. Jenkins 화면에 스크립트만 붙여 넣는 작업에서는 scm 정보가 없어 그대로 동작하지 않을 수 있습니다. Jenkinsfile 사용 문서를 함께 확인하세요.
| 설정 | 이 예제에서 필요한 이유 |
|---|---|
| linux-ci 라벨 | 실행할 도구와 계정이 준비된 에이전트 선택 |
| disableConcurrentBuilds | 같은 작업의 동시 실행을 제한. 서로 다른 배포 작업까지 잠그는 설정은 아님 |
| timeout | 할당된 에이전트에서 실행이 무한히 이어지지 않게 제한. 최상위 timeout은 에이전트 대기까지 포함하지 않음 |
| buildDiscarder | 빌드 기록·산출물이 끝없이 누적되지 않도록 보관 개수 제한 |
| deleteDir | 현재 워크스페이스를 정리. Git과 보관된 산출물을 삭제하는 명령은 아님 |
| fingerprint | 보관한 산출물 추적용 지문 기록. 보안 서명이나 SBOM을 대신하지 않음 |
옵션의 적용 위치와 문법은 Declarative Pipeline 문법에서 확인할 수 있습니다. 위 예제는 체크아웃·테스트·패키징·보관의 순서만 담았으며, 서버 배포는 포함하지 않습니다.
6. Git에서 Pipeline을 읽고 한 번 실패시켜 본다
- 세 파일을 Git에 커밋하고 원격 저장소에 push합니다.
- New Item → Pipeline으로 새 작업을 만들고 Definition을 Pipeline script from SCM으로 지정합니다.
- SCM에서 Git을 선택하고 자신의 저장소 URL과 브랜치를 입력합니다. 예를 들어 main 브랜치라면
*/main을 사용합니다. - 비공개 저장소라면 읽기 전용으로 접근할 자격 증명을 선택합니다. URL에 토큰을 직접 적지 않습니다.
- Script Path는
Jenkinsfile로 두고 저장한 뒤 Build Now를 실행합니다. - 성공하면 빌드 페이지에서
dist/app.tgz산출물을 확인합니다. - 테스트의 기대값을 의도적으로 5에서 6으로 바꿔 커밋합니다. 다시 실행했을 때 Test에서 실패하고 새 Package·Archive 단계가 실행되지 않는지 봅니다.
- 기대값을 5로 되돌린 커밋을 올립니다. 이전 성공 빌드의 산출물과 현재 실패 빌드를 구분해 확인합니다.
처음에는 버튼으로 실행해 흐름을 확인하는 편이 편합니다. 자동 실행은 이 수동 실행이 통과한 뒤 붙여도 늦지 않아요. 04 자동화 활용에서는 Git 변경 감지, 컨테이너 이미지, Kubernetes 배포, 운영 점검으로 범위를 넓혀 봅니다.

![[Jenkins 시작하기 04] 활용 사례 6가지: 이미지 빌드·Kubernetes 배포·운영 점검](https://blog.maruops.com/wp-content/uploads/2026/10/maruops-jenkins-use-cases-768x512.webp)
![[Jenkins 시작하기 02] Rocky Linux 9에 Jenkins 설치하기: DNF·SELinux·방화벽](https://blog.maruops.com/wp-content/uploads/2026/10/maruops-jenkins-rocky-install-768x512.webp)
![[Jenkins 시작하기 01] Ubuntu에 Jenkins LTS 설치하기: Java·초기 설정·접속](https://blog.maruops.com/wp-content/uploads/2026/10/maruops-jenkins-ubuntu-install-768x512.webp)
답글 남기기