소개
Jenkins 는 일반적으로 초기화되지 않은 상태의 컨트롤러로 시작됩니다. 첫 번째 관리자는 초기 비밀번호를 사용하여 컨트롤러 잠금을 해제하고, 영구적인 관리자 계정을 생성하며, Jenkins 가 작업 준비를 마쳤는지 확인합니다.
이번 실습에서는 이러한 첫 실행 워크플로우를 안전하게 연습해 봅니다. VM 의 메인 Jenkins 서비스는 이미 다른 실습을 위해 구성되어 있으므로, 포트 18080에서 두 번째 임시 Jenkins 컨트롤러를 시작할 것입니다. 해당 임시 컨트롤러만 초기화하고 결과를 확인한 뒤 삭제하는 과정을 진행합니다.
격리된 새로운 Jenkins 컨트롤러 시작
이 단계에서는 메인 Jenkins 서비스를 변경하지 않고 새로운 Jenkins 컨트롤러를 시작합니다. Jenkins 컨트롤러는 /var/jenkins_home 경로에 구성을 저장하므로, 이번 실습에서는 jenkins-init-lab-home이라는 별도의 Docker 볼륨을 사용합니다.
아래의 docker run 명령은 임시 컨트롤러를 백그라운드에서 시작합니다. -d 옵션은 분리 (detached) 모드를 의미하며, --name은 컨테이너에 고정된 이름을 부여하고, -p 18080:8080은 호스트의 18080 포트를 Jenkins 에 연결하며, -v는 격리된 Jenkins 홈 볼륨을 마운트합니다.
docker run -d \
--name jenkins-init-lab \
-p 18080:8080 \
-v jenkins-init-lab-home:/var/jenkins_home \
jenkins/jenkins:latest
Docker 가 새로운 컨테이너 ID 를 출력합니다. ID 는 실행할 때마다 다르므로 긴 16 진수 값이면 무엇이든 괜찮습니다.
다음으로, Jenkins 가 HTTP 요청에 응답할 때까지 기다립니다. 아래의 루프는 로컬 컨트롤러의 /login 경로에 HTTP 상태 코드가 반환될 때까지 요청을 보냅니다. 200 응답은 로그인 페이지를 사용할 수 있음을 의미합니다.
until [ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:18080/login)" = "200" ]; do
echo "Waiting for the temporary Jenkins controller..."
sleep 5
done
대기 메시지가 몇 번 출력된 후 프롬프트가 돌아올 것입니다. 컨테이너와 포트 매핑을 확인합니다:
docker ps --filter name=jenkins-init-lab --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
출력 결과에 컨테이너 이름과 포트 18080이 포함되어야 합니다:
NAMES STATUS PORTS
jenkins-init-lab Up ... 0.0.0.0:18080->8080/tcp, ...
초기 관리자 비밀번호 검색
이 단계에서는 Jenkins 가 첫 번째 관리자를 위해 생성한 일회용 비밀번호를 검색합니다. Jenkins 는 이 비밀번호를 컨트롤러 홈 디렉토리 내의 /var/jenkins_home/secrets/initialAdminPassword 파일에 저장합니다.
docker exec를 사용하여 임시 Jenkins 컨테이너 내부에서 cat 명령을 실행하고, 비밀번호를 프로젝트 디렉토리에 저장합니다:
docker exec jenkins-init-lab cat /var/jenkins_home/secrets/initialAdminPassword > /home/labex/project/jenkins-init-password.txt
이 명령은 > 리다이렉션을 사용하여 명령 출력을 파일에 기록합니다. 이렇게 하면 셸 변수에 의존하지 않고도 다음 단계에서 비밀번호를 사용할 수 있습니다.
터미널 기록에 전체 값이 노출되지 않도록 처음 몇 글자만 표시하여 파일이 비어 있지 않은지 확인합니다:
cut -c1-8 /home/labex/project/jenkins-init-password.txt
비밀번호의 앞 8 자리가 다음과 같이 표시되어야 합니다:
1a2b3c4d
영구 관리자 계정 생성
이 단계에서는 초기 비밀번호를 사용하여 lab-admin이라는 실제 Jenkins 관리자 계정을 생성합니다. 초기 비밀번호는 설정 용도로만 사용됩니다. 일반 관리자 계정은 컨트롤러 초기화가 완료된 후 팀에서 사용하는 계정입니다.
Jenkins 는 폼 제출을 보호하기 위해 크럼 (crumb) 토큰을 사용합니다. 크럼은 이를 요청한 브라우저나 HTTP 세션과 연결되어 있으므로, 아래 명령은 Jenkins 쿠키를 쿠키 저장 파일에 함께 저장합니다.
INIT_PASSWORD=$(tr -d '\r\n' < /home/labex/project/jenkins-init-password.txt)
COOKIE_JAR=/home/labex/project/jenkins-init-cookies.txt
curl -fsS -c "${COOKIE_JAR}" -u "admin:${INIT_PASSWORD}" \
http://localhost:18080/crumbIssuer/api/json \
> /home/labex/project/jenkins-init-crumb.json
다음 명령은 Jenkins 에 간단한 Groovy 스크립트를 전송합니다. 이 스크립트는 비공개 보안 영역을 생성하고, lab-admin 사용자를 추가하며, 로그인한 사용자에게 전체 권한을 부여하고, 설정 마법사를 완료 상태로 표시합니다.
CRUMB_FIELD=$(sed -n 's/.*"crumbRequestField":"\([^"]*\)".*/\1/p' /home/labex/project/jenkins-init-crumb.json)
CRUMB_VALUE=$(sed -n 's/.*"crumb":"\([^"]*\)".*/\1/p' /home/labex/project/jenkins-init-crumb.json)
cat > /home/labex/project/initialize-controller.groovy <<'GROOVY'
import jenkins.model.Jenkins
import jenkins.install.InstallState
import hudson.security.HudsonPrivateSecurityRealm
import hudson.security.FullControlOnceLoggedInAuthorizationStrategy
def jenkins = Jenkins.get()
def realm = new HudsonPrivateSecurityRealm(false)
realm.createAccount('lab-admin', 'LabEx-Admin-123')
jenkins.setSecurityRealm(realm)
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
jenkins.setAuthorizationStrategy(strategy)
jenkins.setInstallState(InstallState.INITIAL_SETUP_COMPLETED)
jenkins.save()
println('created lab-admin and completed setup')
GROOVY
curl -fsS -b "${COOKIE_JAR}" -u "admin:${INIT_PASSWORD}" \
-H "${CRUMB_FIELD}: ${CRUMB_VALUE}" \
--data-urlencode "script@/home/labex/project/initialize-controller.groovy" \
http://localhost:18080/scriptText \
> /home/labex/project/jenkins-init-result.txt
결과 파일을 읽어봅니다:
cat /home/labex/project/jenkins-init-result.txt
예상되는 메시지는 다음과 같습니다:
created lab-admin and completed setup
초기화된 컨트롤러 대시보드 확인
이 단계에서는 임시 컨트롤러가 더 이상 잠금 해제 화면만 표시하지 않는지 확인합니다. 정상적으로 초기화된 컨트롤러는 lab-admin 사용자를 인증하고 Jenkins 메인 페이지를 반환해야 합니다.
curl에 -u 옵션을 사용하여 인증합니다. -o 옵션은 HTML 을 파일로 기록하고, -w '%{http_code}'는 HTTP 상태 코드만 출력합니다.
curl -s -u 'lab-admin:LabEx-Admin-123' \
-o /home/labex/project/jenkins-init-dashboard.html \
-w '%{http_code}\n' \
http://localhost:18080/
상태 코드는 다음과 같아야 합니다:
200
이제 저장된 대시보드 페이지에서 Jenkins 관련 텍스트를 검색합니다:
grep -o -E 'Dashboard|Welcome to Jenkins|Jenkins' /home/labex/project/jenkins-init-dashboard.html | head
최소한 하나 이상의 일치하는 줄이 보여야 합니다. 정확한 HTML 은 Jenkins 버전에 따라 다를 수 있지만, 해당 페이지가 Jenkins 임을 식별할 수 있어야 합니다.
일회용 컨트롤러 중지 및 제거
이 단계에서는 임시 컨트롤러를 정리합니다. 메인 Jenkins 서비스는 다른 Jenkins 실습에서 사용되므로, 첫 실행 초기화 연습용으로만 사용했던 임시 컨트롤러를 정리하는 것이 중요합니다.
먼저 임시 컨테이너를 중지하고 제거합니다:
docker rm -f jenkins-init-lab
그런 다음 격리된 Jenkins 홈 볼륨을 제거합니다:
docker volume rm jenkins-init-lab-home
마지막으로 임시 컨트롤러가 제거되었는지 확인합니다:
docker ps -a --filter name=jenkins-init-lab --format '{{.Names}}'
이 명령은 아무것도 출력하지 않아야 합니다. 결과가 비어 있다는 것은 해당 이름을 가진 컨테이너가 남아 있지 않음을 의미합니다.
요약
격리된 Jenkins 컨트롤러를 시작하고, 일회용 초기 관리자 비밀번호를 검색하며, 영구 관리자 계정을 생성하고, 초기화된 대시보드에 접근할 수 있음을 확인한 뒤 임시 컨트롤러를 정리했습니다. 이것이 바로 사용 가능한 Jenkins 컨트롤러를 구축하기 위한 핵심 첫 실행 초기화 워크플로우입니다.