Jenkins

1️⃣ EC2 서버 준비 & RDS 준비

  • 두 개의 EC2 인스턴스를 t3.medium 타입 이상으로 생성합니다.

    • Jenkins 서버 (EC2 #1): t3.medium

    • 개발 서버 (EC2 #2): t3.medium

    • RDS 생성

📚 t3.medium 타입 이상이 필요한 이유
- 지금 여기서는 Jenkins 와 Java 를 Docker Continer 로 띄우는 것이 목적입니다.
- 일단 Docker 를 설치하고 실행하게 되면, 1GB 의 메모리는 부족합니다.
- t3.micro 또는 t3.small 타입의 메모리는 1GB 입니다.
- t3.micro 와 t3.small 타입은, Jenkins UI 가 매우 느렸으며, 수시로 서버가 죽는 현상을
  경험하였습니다. 특히 Jenkins 의 경우 컨테이너로 띄우는 경우, 최소 4기가의 램이 있어야 합니다.

보안 그룹 설정

  • Jenkins 와 개발서버에 대해서 동일한 보안 그룹을 사용하였습니다.

  • 필요에 따라서 보안 그룹을 나누어서 설정할 수 있습니다.

  • 사용자 지정 TCP 8080 port *Jenkins 는 일반적으로 8080 포트 샤용

  • SSH 22 port * SSH 접속을 위해서

  • RDS 에 대한 보안 그룹 생성 후, Inbound 규칙에서 개발 서버의 보안 그룹 허용

개발 서버 보안그룹
RDS 보안그룹

개발 서버와 Jenkins 서버에 대해서 탄력적 IP(EIP) 적용하기

서버 접속 및 코드 상에서 IP 입력 부분에서 매번 변경하지 않도록, 고정 IPv4 를 생성하여, 각 인스턴스에 연결해줍니다.

📚 EIP 는 인스턴스와 연결 중일 때는 한 개 까지 무료이며, 연결되지 않은 상태로 두면 요금 부과

2️⃣ Jenkins 서버에 기본 환경 설치 (EC2 #1)

Jenkins 와 개발 서버에 대한 EC2는 Ubuntu 24 버전 이미지를 사용하여 생성하였습니다.

SSH 접속 후 Docker & Compose 설치:


3️⃣ Jenkins Dockerfile / Docker Compose 세팅

Dockerfile

jenkins-plugin.txt:

jenkins-plugin.txt 를 통해서, Java Springboot 앱의 CI/CD 에 필요한 플러그인을, 미리 설치해줍니다.

Docker compose 파일

네임드 볼륨 jenkins_home 를 생성하여 관리합니다.

📦 네임드 볼륨(named volume)을 사용하는 이유

Docker 가 직접 관리 → 성능 최적화

  • 네임드 볼륨은 Docker 엔진이 /var/lib/docker/volumes/ 아래에서 직접 관리합니다.

  • 로컬 디스크와 달리 OverlayFS 최적화가 적용되어 입출력(I/O) 속도가 더 빠릅니다.

  • Jenkins처럼 수많은 작은 파일(플러그인 캐시, 빌드 로그 등)을 다루는 경우 성능 차이가 큽니다.

    • 로컬 바인드 마운트는 호스트 파일시스템과 Docker OverlayFS 사이에서 I/O overhead가 발생합니다.

    • Jenkins는 수천 개의 작은 파일을 다루므로 속도 저하가 심각해집니다.

    • macOS/Windows에서는 Hypervisor를 거치기 때문에 더 느려집니다.

데이터 영속성 보장

  • 컨테이너가 삭제되어도 네임드 볼륨은 남아있습니다.

  • docker compose down -v로 명시적으로 삭제하기 전까지는 안전하게 보관됩니다.

  • Jenkins 서버를 재배포해도 설정, 플러그인, 빌드 히스토리가 그대로 유지됩니다.

호스트 경로 독립성

  • 특정 경로(./jenkins_home)에 의존하지 않고, 어떤 서버/환경에서도 동일하게 동작합니다.

  • 여러 개발자/운영자가 같은 compose 파일을 써도 로컬 파일 경로 충돌이 없습니다.

실행

처음 실행하면 Jenkins 관리자 비밀번호를 로그에서 확인:

  • 브라우저에서 http://<JENKINS_EC2_PUBLIC_IP>:8080 접속 →

  • Unlock Jenkins (로그에서 비밀번호 확인)

  • 관리자 계정 생성

  • 플러그인 설치

    • 위의 jenkins_plugin.txt 를 사용하지 않고, 직접 설치하는 경우

    • Github, SSH Agent, Pipeline 등 설치

4️⃣ 배포 서버 (EC2 #2) 설정

배포 서버에도 Docker & Docker Compose 설치 (Spring Boot 배포용):

위의, 2️⃣ Jenkins 서버에 기본 환경 설치 (EC2 #1) 참조

5️⃣ Jenkins → 배포 서버 SSH 연결

Jenkinsfile 을 프로젝트 루트에 생성하여, Jenkins 에서 해당 파일의 스크립트를 실행할 예정입니다. 그렇게 하기 위해서는, Jenkins 서버에서 개발 서버로의 ssh 접속이 가능해야 합니다.

  • Jenkins 서버에서 ssh-keygen 을 사용하여, 키 파일을 만들어줍니다.

  • 생성된 rsa 퍼블릭키를, 개발 서버에 등록해줍니다.

  • 개발 서버의 ~/.ssh/authrized_keys 에 추가합니다.

젠킨스 서버에서 cat 으로 .pub 파일 출력 후 복사 -> 개발서버에 붙여넣기

젠킨스 서버:

Jenkins 서버

개발 서버:

개발 서버

젠킨스 서버 -> 개발 서버 ssh 접속 테스트:

6️⃣ Jenkins Job (Pipeline) 구성

Jenkins UI에서 새로운 Item → Pipeline 생성. GitHub 연동 후 아래 예시 파이프라인 스크립트 (Jenkinsfile) 작성:

Jenkinsfile-dev

위의 credential 설정에 대해서는, 아래의 [7️⃣ Jenkins Credential 설정] 에서 설명한다.

  • credentialsId: 'my-jenkins-credentials'

  • sshagent (credentials: ['deploy-server-ssh'])

📚 TIPs - pipeline 아래의 tools java 등을 설정하지 않은 이유

  • 지금 설치된 Jenkins dockerfile 은 이미 Java 21 버전이 설치되어 있기 때문에, 별도의 tools 설정이 필요 없습니다.

7️⃣ Jenkins Credential 설정

여기서는 아래의 credentialsId 와 sshagent 의 credentials 에 들어가는 값에 대해서 설명합니다.

🔑 credentialsId 가 필요한 이유

GitHub 인증 문제 해결

  • Jenkins에서 git 플러그인을 통해 private repo를 clone/pull 하려면 인증이 필요합니다.

  • 예전에는 GitHub username/password를 썼지만, 지금은 Personal Access Token (PAT) 또는 SSH key만 지원합니다.

  • credentialsId는 Jenkins 내부 Credentials Store에 저장된 인증 정보를 참조하기 위한 키입니다.

보안 유지

  • Jenkinsfile에 직접 토큰이나 비밀번호를 적으면 보안상 위험합니다. (GitHub에 노출될 수 있음)

  • 대신 Jenkins Credentials Store에 안전하게 저장하고, Jenkinsfile에서는 credentialsId 만 명시합니다.

  • 실제 비밀값은 빌드 실행 시점에만 주입됩니다.

유연한 관리

  • 같은 Jenkinsfile을 쓰더라도 Jenkins 서버마다 다른 인증정보를 연결할 수 있습니다.

  • 예: 로컬 Jenkins는 개인 GitHub 토큰, 회사 Jenkins는 조직 계정 토큰 → 코드 수정 없이 가능.

credentialsId 설정 방법

Github 접속

  • 오른쪽 상단 profile -> settings

  • 왼쪽 하단 <> Developer settings

  • Personal access tokens -> Tokens (classic)

  • Generate new token

  • Token name, Expiration, Repository access 설정

  • 최소한 repo, workflow, write:packages 선택

  • 생성되는 키 복사 (다시 볼 수 없음)

Jenkins 에서 Credential 설정

  • 상단 프로필 -> Credentials 클릭 jenkins-credentials

  • Stores from partent 의 (global) 클릭 jenkins-credentials

  • Add Credentials 클릭 jenkins-credentials

  • Username with password 로 설정

    • Username 은 Github Id 로 설정

    • Password 는 Github 에서 생성한 키 붙여넣기

    • ID 는 커스텀하게 설정하되, 해당 ID 를 Jenkinsfile 에서 사용함

    • jenkins-credentials

deploy-server-ssh 설정 방법

  • 위와 동일한 방법으로 Add Credentials 클릭

  • SSH Username with private key 선택

  • ID: deploy-server-ssh *Jenkinsfile 에서 sshagent 에 들어가는 값

  • Username: ubuntu

  • Private Key 에 AWS .pem 키의 내용 붙여넣기

    • 아래와 같이 했을 때, terminal 에 출력되는 값의 마지막에 % 는 제외하고 복붙 하도록 한다

jenkins credential

8️⃣ GitHub → Jenkins Webhook 연결

  • GitHub repo → Settings → Webhooks

    • Payload URL: http://<JENKINS_EC2_PUBLIC_IP>:8080/github-webhook/

    • Content type: application/json

github webhook

9️⃣ Jenkins pipeline 설정

pipeline
pipeline
pipeline
pipeline
pipeline
pipeline
pipeline
pipeline
pipeline

✅ 완료


Trouble Shooting

젠킨스 CI/CD 연동 작업에서 발생한 모든 트러블 슈팅을 기록합니다.

ssh 접속 불가

✅ pem 키 파일 권한 확인

EC2 접속할 때 pem 키 권한이 잘못되면 바로 거절됩니다.

정상 권한은 아래 중 하나여야 합니다:

  • -r-------- (chmod 400)

  • -rw------- (chmod 600)

✅ 2. EC2 보안 그룹 (Security Group) 설정

AWS 콘솔 → EC2 → 인스턴스 선택 → 보안 그룹 확인

  • Inbound 규칙에 아래가 있어야 함:

    • SSH (TCP) / 포트 22 / 소스: 내 IP (또는 0.0.0.0/0 테스트용)

✅ 3. 올바른 유저명 확인

AMI 종류에 따라 접속 계정이 달라집니다.

  • Amazon Linux 2 / Amazon Linux 2023 → ec2-user

  • Ubuntu → ubuntu

  • CentOS → centos

  • RHEL → ec2-user 또는 root

즉, AMI가 Ubuntu라면 아래처럼 시도해야 합니다:

✅ 4. 퍼블릭 IP / Elastic IP 확인

  • EC2에 퍼블릭 IPv4 주소가 할당돼 있는지 (또는 Elastic IP 연결했는지) 확인

  • 프라이빗 서브넷에만 있으면 외부에서 접근 불가

✅ 5. 네트워크 ACL / VPC 라우팅 확인

  • 퍼블릭 서브넷에 있어야 외부 접근 가능

  • 인터넷 게이트웨이(IGW)가 VPC에 연결돼 있어야 함

✅ 6. SSH 로그 확인 (EC2 내부)

혹시 이미 내부 콘솔로 들어갈 수 있다면 (AWS Systems Manager Session Manager 같은 것)

  • /var/log/secure 또는 /var/log/auth.log 확인해서 SSH 거절 이유 확인 가능

docker compose up 명령어를 수행할 때 permission denided

에러 메세지의 핵심은 아래의 메세지이다.

위에서 현재 유저를 docker group 에 추가하는 명령어를 실행하였는데, 그룹 변경은 즉시 반영이 아니기 때문에, 세션을 새로 열어야 한다. 따라서, 로그아웃 후 다시 ec2 에 접속한다.

그룹 확인하여, docker 가 포함되어 있어야 한다.

Last updated