EC2의 Docker 안에 Jenkins Container 올리기 (feat. Webhook CI/CD 구축 & DooD)
Keyword
1. DooD
2. docker network
Flow
1. 새로운 EC2 인스턴스 생성 -> 젠킨스만
2. docker 설치
3. docker 컨테이너 젠킨스 실행
4. 서브 도메인 세팅
5. 젠킨스 Webhook 연결
6. 파이프라인 작성 후 배포 확인
EC2 인스턴스 설정
EC2 인스턴스 설정
용량: 최소 100GB
EC2 인스턴스 생성:
- AWS 콘솔에 로그인하고 EC2 서비스를 선택합니다.
- "인스턴스 시작" 버튼을 클릭하여 새로운 인스턴스를 생성합니다.
- Ubuntu AMI를 선택합니다.
- 인스턴스 유형을 선택합니다 (t2.micro는 무료 티어로 사용할 수 있습니다). → t2.medium.
- 키 페어를 설정하고 다운로드합니다.
- 인스턴스를 시작합니다.
보안 그룹 설정:
- SSH (포트 22), HTTP (포트 80), HTTPS (포트 443) 및 애플리케이션 포트 (예: 8080)를 허용합니다.
Docker 설치
* jenkins 실행을 위해 새로 만든 EC2 인스턴스에서 진행
시스템 업데이트 및 업그레이드:
sudo apt update -y
sudo apt upgrade -y
Docker 설치:
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
DooD를 이용한 Jenkins 실행
* jenkins 실행을 위해 새로 만든 EC2 인스턴스에서 진행
Jenkins용 Dockerfile 만들기
Dockerfile 생성:
vi Dockerfile
작업 모드로 변경: i
Dockerfile 작성:
FROM jenkins/jenkins:2.452.3
USER root
RUN apt-get -y update && \
apt-get -y install apt-transport-https ca-certificates curl gnupg-agent software-properties-common && \
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - && \
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
apt-get -y update && \
apt-get -y install docker-ce docker-ce-cli containerd.io
RUN usermod -u 1000 jenkins && \
groupmod -g 113 docker && \
usermod -aG docker jenkins
USER jenkins
저장하고 나가기: ECS + :wq
Jenkins docker 실행
Jenkins docker 이미지 빌드:
- 앞서 작성한 Dockerfile이 있는 디렉토리에서 빌드
docker build -t jenkins .
jenkins 컨테이너 실행:
docker run -d --name jenkins -p 8080:8080 -p 5000:5000 jenkins/jenkins:2.452.3
DNS 설정 (서브 도메인 설정)
도메인 등록 기관의 DNS 관리 페이지로 이동합니다.
새 CNAME 레코드를 추가합니다:
- 이름: 원하는 서브도메인 (예: jenkins)
- 값: EC2 인스턴스의 퍼블릭 DNS (예: ec2-xx-xx-xx-xx.compute-1.amazonaws.com)
변경 사항이 적용되기까지 몇 분 정도 소요될 수 있습니다.
Jenkins 접속 및 초기 세팅
Jenkins 접속
Jenkins 메인 페이지 접근 확인:
- 브라우저에서 서브 도메인 주소를 입력하여 Jenkins에 접근
- ex) http://jenkins.yourdomain.com:8080
초기 관리자 비밀번호 얻기:
* 해당 과정은 Jenkins의 EC2 인스턴스에서 진행
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
초기 세팅
추천 플러그인 설치:
가장 간단한 방법은 "Install suggested plugins" 옵션을 선택하는 것입니다. 이는 Jenkins 커뮤니티가 유용하다고 여기는 플러그인을 자동으로 설치합니다.
- "Install suggested plugins" 클릭
Github Webhook 설정
Jenkins 관리 페이지에서 플러그인 설치
플러그인 설치 페이지로 이동:
- Jenkins 메인 페이지에서 "Manage Jenkins" -> "Manage Plugins"로 이동
플러그인 설치:
- "Available" 탭에서 "GitHub Integration Plugin"을 검색하여 설치합니다.
- "Available" 탭에서 "Docker Pipeline" 플러그인을 검색하여 설치합니다.
- 설치 후 재시작 중요!
- jenkins EC2 인스턴스에 들어가서 jenkins 컨테이너 재시작
jenkins restart
GitHub 저장소에 Webhook 추가
GitHub 저장소로 이동하여 "Settings" -> "Webhooks"로 이동합니다.
"Add webhook"을 클릭하고 다음과 같이 설정합니다:
- Payload URL: http://<YOUR_JENKINS_URL>/github-webhook/
- Content type: application/json
- 이벤트: Just the push event
사진은 아직 연결되지 않은 상태
→ 초록색 아이콘으로 변경되어야 연결 완료!
Jenkins Pipeline 생성
Pipeline 생성
Jenkins 메인 페이지에서 "New Item"을 클릭하고 새 Job을 생성
"GitHub project" 옵션을 활성화하고 GitHub 저장소 URL을 입력
"Build Triggers" 섹션에서 "GitHub hook trigger for GITScm polling"을 선택
Pipeline 스크립트 작성 : 다음 단원에서 자세하게 다룰 예정
설정 저장:
- 모든 설정이 완료되면 Save 버튼을 클릭하여 설정을 저장
Pipeline script 작성
전체적인 흐름도
- 깃클론
- gradle build
- jar 파일과 dockerfile을 특정 경로로 이동
- 환경변수 파일 작성
- dockerfile을 이용해서 이미지 빌드(태그) → 현재 미적용된 내용
- 빌드된 이미지 도커 허브에 push
- ec2 인스턴스에 접속(제일 처음 만들었던 ec2)
- 현재 동작 중인 docker-compose 중지
- 도커 허브의 이미지 pull
- 새로 받은 이미지로 docker-compose 시작
- Jenkins의 메인화면에서 방금 만들었던 pipeline을 선택
- 왼쪽 목록에서 “configure” 선택
Pipeline script 작성:
pipeline {
agent any
environment {
// Docker Hub credentials
DOCKER_HUB_CREDENTIALS = 'docker-hub-credentials'
DOCKER_HUB_REPO = 'ysy561356/today-space-back'
DOCKER_CONTAINER = 'today-space-back'
// Github credentials
GIT_CREDENTIALS_ID = 'github-token'
GIT_BRANCH = 'release'
GIT_URL = 'https://github.com/today-space/today-space-back.git'
// EC2
SSH_CREDENTIALS_ID = 'ec2-ssh-key'
EC2_USER = 'ubuntu'
EC2_DOMAIN = 'back.today-space.com'
// DB
DB_URL = 'jdbc:postgresql://postgresql.today-space.com:5432/space'
DB_USERNAME = 'youngju'
DB_PASSWORD = '4564'
// JWT
JWT_SECRET_KEY = '7Iqk7YyM66W07YOA7L2U65Sp7YG065+9c3ByaW5n7Ius7ZmU7KO87LCo7JWE7JuD7IaM7Iux7ZSE66Gc7KCd7Yq47YyM7J2067iM66CI7KCE65Oc7YyAand0c2VjcmV0a2V5'
JWT_ACCESS_TOKEN_EXPIRATION = 1800000
JWT_REFRESH_TOKEN_EXPIRATION = 1209600000
// Social Login
KAKAO_REST_API_KEY = '6cd61cbdb917a1046bf437980b1e2ac9'
NAVER_REST_API_KEY = 'mgvICujU1zvQrtz_IQOA'
NAVER_REST_API_SECRET_KEY = 'drUb2lRtGb'
GOOGLE_REST_API_KEY = '878062679505-oh34mk7fm5mpipprk9o139i8if40b3qf.apps.googleusercontent.com'
GOOGLE_REST_API_SECRET_KEY = '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'
}
stages {
stage('Clone Git Repository') {
steps {
script {
// GitHub 저장소에서 코드 클론
git credentialsId: "${GIT_CREDENTIALS_ID}", branch: "${GIT_BRANCH}", url: "${GIT_URL}"
// gradlew 파일에 실행 권한 부여
sh 'chmod +x gradlew'
// Gradle 빌드
sh './gradlew build'
// destination 디렉토리 생성
sh 'mkdir -p ../destination'
sh 'mkdir -p ../destination/build/libs'
// JAR 파일과 Dockerfile을 특정 경로로 이동
sh 'cp build/libs/*.jar ../destination/build/libs'
sh 'cp Dockerfile ../destination/'
}
}
}
stage('Prepare .env') {
steps {
script {
sh '''
touch ../destination/back.env
echo DB_URL=$DB_URL > ../destination/back.env
echo DB_USERNAME=$DB_USERNAME >> ../destination/back.env
echo DB_PASSWORD=$DB_PASSWORD >> ../destination/back.env
echo JWT_SECRET_KEY=$JWT_SECRET_KEY >> ../destination/back.env
echo JWT_ACCESS_TOKEN_EXPIRATION=$JWT_ACCESS_TOKEN_EXPIRATION >> ../destination/back.env
echo JWT_REFRESH_TOKEN_EXPIRATION=$JWT_REFRESH_TOKEN_EXPIRATION >> ../destination/back.env
echo KAKAO_REST_API_KEY=$KAKAO_REST_API_KEY >> ../destination/back.env
echo NAVER_REST_API_KEY=$NAVER_REST_API_KEY >> ../destination/back.env
echo NAVER_REST_API_SECRET_KEY=$NAVER_REST_API_SECRET_KEY >> ../destination/back.env
echo GOOGLE_REST_API_KEY=$GOOGLE_REST_API_KEY >> ../destination/back.env
echo GOOGLE_REST_API_SECRET_KEY=$GOOGLE_REST_API_SECRET_KEY >> ../destination/back.env
echo FRONT_URL=$FRONT_URL >> ../destination/back.env
echo KAKAO_PAY_SECRET_KEY=$KAKAO_PAY_SECRET_KEY >> ../destination/back.env
echo KAKAO_PAY_URL=$KAKAO_PAY_URL >> ../destination/back.env
echo KAKAO_PAY_CID=$KAKAO_PAY_CID >> ../destination/back.env
'''
}
}
}
stage('Build and Push Docker Image') {
steps {
script {
dir('../destination') { // 특정 경로로 이동
// docker 이미지 빌드
def dockerImage = docker.build("${DOCKER_HUB_REPO}:latest", "./")
// Docker Hub에 로그인
withCredentials([usernamePassword(credentialsId: DOCKER_HUB_CREDENTIALS, usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
}
// docker 이미지 push
dockerImage.push("latest")
}
}
}
}
stage('Deploy') {
steps {
script {
withCredentials([sshUserPrivateKey(credentialsId: "${SSH_CREDENTIALS_ID}", keyFileVariable: 'SSH_KEY')]) {
def sshKey = env.SSH_KEY
// 권한 변경
sh 'chmod 400 ' + sshKey
// docker-compose down
sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker-compose down"'
// docker image pull
sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker pull ${DOCKER_HUB_REPO}:${DOCKER_IMAGE_TAG}"' // 이미지 명시
// 새로운 docker-compose 시작
sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker-compose up -d"'
}
}
}
}
}
post {
always {
cleanWs()
}
success {
echo 'Deployment successful!'
}
failure {
echo 'Deployment failed!'
}
}
}
Credentials 생성
Jenkins 메인 화면에서 “Manage Jenkins” > “Credentials” > “global” > “Add Credentials”
Docker Hub credentials:
- Kind : Username with password
- Username : Docker Hub ID
- Password : Docker Hub Password
- ID : Jenkins에서 변수로 사용할 ID (ex: docker-hub-credentials)
Github credentials:
- Kind : Username with password
- Username : GitHub ID
- Password : GitHub Token
- ID : Jenkins에서 변수로 사용할 ID (ex: github-token)
EC2 credentials:
- Kind : SSH Username with private key
- ID :
- Username : ubuntu
- EC2 인스턴스의 hostname(기본적으로 linux라면 기본적으로 ubuntu)
- Pricate Key : EC2 인스턴스 생성하면서 .pem 파일을 다운 받았을텐데 해당 파일을 열어보면 사진과 같이 나오는 글자들을 전부 복사 붙여넣기
- 단, 마지막에 잘못해서 공백이 들어가면 안된다.
- Mac : 터미널에서 cat [.pem 파일 마우스로 끌어서 터미널에 넣기]
- window : 메모장으로 확인하는 게 편하다
참고 자료
- Credentials 생성
Jenkins Pipeline을 이용한 Docker Image Push
지난 글에 이어서 빌드된 이미지를 Docker Hub로 Push 해보려고 합니다. 빌드까지 정상적으로 이루어졌다면, jenkinsfile-build를 수정해주어야 합니다. 하지만 해당 글은 가이드이기 때문에 jenkinsfile-push
teichae.tistory.com
[Jenkins]Git 연동하기(Git Token 발급 + Jenkins Credential 등록)
안녕하세요 오늘은 git 에서 Token을 발급받아 Jenkins Credential에 등록해보겠습니다!먼저 Github Settings -> Developer settings -> Personal access token 항목에 들어갑니다 이후 Generate new
velog.io
[Jenkins] SSH 사용 - pipeline SSH Agent
[Jenkins] SSH 사용 - pipeline SSH Agent 작업 순서 SSH Agent 플러그인 설치 SSH 인증서 생성 jenkins에 ssh 인증 정보 등록 pipeline에서 ssh 사용하기 Bad configuration option 에러 발생시 1. SSH Agent 플러그인 설치 Jenkin
royleej9.tistory.com
- Jenkins 사용
NGINX 무중단 배포
지금까지의 서비스는 새로운 Jar가 실행되기 전까진 기존 Jar를 종료시켜 놓기 때문에 서비스가 중단된다. 이를 해결하기 위해 우리는 엔진엑스를 이용해 '무중단 배포' 를 해볼 것이다 엔진엑스
dallae7.tistory.com