- 이 글 목표 : ec2 인스턴스 젠킨스서버에 docker 설치, docker를 통해 jenkins 설치, jenkins pipeline을 통해 github webhook 설정, docker hub 자동 push,pull 하기 + 성공/실패시마다 slack 자동 알림 설정- 다음 글 목표 : ec2 인스턴스 스프링부트 서버에 NGINX 설치 및 blue/green 무중단 배포 구현 (젠킨스 파이프라인 이어서) |
1. 구성요소
- Jenkins Server : AWS EC2 Ubuntu ⇒ 이 글에선 편의상 A 서버라고 칭한다.
- Spring Boot Server : AWS EC2 Ubuntu ⇒ 이 글에선 편의상 B 서버라고 칭한다.
- Github Repository
- Docker Hub Repository
- 도커파일 예시 (파일명 Dockerfile)
# JDK11 이미지 사용
FROM openjdk:17-jdk
VOLUME /tmp
# JAR_FILE 변수에 값을 저장
ARG JAR_FILE=./build/libs/*.jar
# 변수에 저장된 것을 컨테이너 실행시 이름을 app.jar파일로 변경하여 컨테이너에 저장
COPY ${JAR_FILE} app.jar
# 빌드된 이미지가 run될 때 실행할 명령어
ENTRYPOINT ["java","-jar","app.jar"]
최종 구성요소 요약
|
2. ec2 인스턴스 2개 생성 후 접속 방법 (A서버 / B서버)
- ec2 스펙 선택 : Ubuntu , t2.micro , 키페어필수
- 보안 그룹 알맞게 설정하기
- ec2 인스턴스에 탄력적 IP 할당하기 (재시작 시에도 고정 ip를 가져가기 위함)
- pem 키 권한 설정
chmod 600 ~/.ssh/pem키파일명.pem
- ec2 접속
ssh -i pem키위치 탄력적IP주소
3. A서버에 Docker 설치
- A 서버 접속
- 패키지 업데이트
sudo apt update
- https 관련 패키지 설치
sudo apt install apt-transport-https ca-certificates curl software-properties-common
- 리눅스 배포판 종류를 자동으로 인식하여 Docker 패키지를 설치해주는 스크립트
sudo wget -qO- https://get.docker.com/ | sh
- 도커 설치 확인
docker --version
- 현재 사용자를 docker group에 포함 (루트 사용자 가 아닌 일반 사용자 가 docker 명령어를 사용하려고 하면, Permission Denied 에러가 발생한다. 따라서 sudo 없이 docker 명령어를 수행하기 위해 Docker group 에 현재 사용자 이름 을 등록한다.)
sudo usermod -aG docker ${USER}
- Docker 서비스 실행하기 및 부팅 시 자동 실행 설정
sudo systemctl start docker
sudo systemctl enable docker
- 다시 패키지 업데이트
sudo apt update
- A 서버 재접속
⇒ B서버에도 마찬가지로 Docker를 설치해줘야 추후 docker hub에서 pull 해올 수 있다.
4. A서버에 Jenkins 설치
- 도커 실행 (이미 도커 실행 중인 경우 제외)
sudo systemctl start docker
- 젠킨스 이미지 다운로드
docker pull jenkins/jenkins:lts
- 젠킨스 컨테이너 띄우기
sudo docker run -d -p 9090:8080 -p 50000:50000 -v /jenkins:/var/jenkins_home -v /home/ubuntu/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock --name jenkins -u root jenkins/jenkins:lts
↳ /home/ubuntu/.ssh 디렉토리와 /var/run/docker.sock 파일을 컨테이너 내부에 마운트하여 컨테이너 내부에서 호스트의 SSH 키와 Docker 데몬에 접근할 수 있도록 설정.
- 현재 실행중인 컨테이너 확인
docker ps
+) 출처 하단 기입.
EC2 프리티어 사용시 Jenkins가 죽어요 😂 현재 젠킨스 서버로 사용하는 프리티어 EC2는 젠킨스를 버틸 수 없습니다. 젠킨스를 도커로 띄우고 설정까지는 문제가 없으나 깃허브 웹훅으로 젠킨스를 이용해 spring을 빌드하는 과정에서 램을 1기가 이상(프리티어 EC2 램은 1기가) 사용하게 되면서 EC2가 먹통이 되어버립니다. 이 문제의 해결 방안으로는 리눅스의 하드디스크를 가상 메모리로 전환시켜 사용할 수 있다는 점을 이용하면 됩니다.
|
5. A서버의 Jenkins 접속 및 설정
- ip주소:9090 접속 후 초기 비밀번호 입력 (9090 포트 보안 접속 허용 필수)
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
↳ 초기 비밀번호를 얻을 수 있다.
- Install suggested plugins로 플러그인 설치
- Jenkins 계정 생성
- Jenkins 메인 대시보드 페이지가 나오면 성공
6. A서버의 Jenkins 와 github 연동
- ssh 키 생성
Jenkins Container를 생성할 때 "/home/ubuntu/.ssh:/root/.ssh"로 .ssh 디텍도리를 마운트 해놓았기 때문에 Container 밖에서 ssh 키를 생성하면 Jenkins Container와 연결된다.
// 그냥 전부 enter를 입력해 default로 만든다.
ssh-keygen
A 서버 EC2에 접속하면 /home/ubuntu/.ssh에 id_rsa와 id_rsa.pub이 생성되고,
A 서버 내 jenkins 컨테이너에 접속하면 /root/.ssh에 id_rsa와 id_rsa.pub이 생성된다.
(rsa 대신 영숫자가 나올수도 있음. 추후 rsa 관련 파일은 모두 본인에게 해당되는 이름으로 입력.)
- ssh 디렉토리 소유권한 변경
sudo chown ubuntu .ssh
//sudo chown [who am i치면 나오는 결과] [filename]
- Github Deploy Key 등록
만들어 놓은 Github Repository > Settings > Deploy Keys > Add deploy key로 접속한다.Title은 Jenkins로 지어 주고(마음대로 해도 된다), Key 부분에 id_rsa.pub에 들어있는 public key 값을 넣어준다. 아래 명령어로 확인 가능하다.
cat /home/ubuntu/.ssh/id_rsa.pub
- Jenkins Credentials 등록
Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다. Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다.왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다.
- Kind : SSH Username with private key
- ID : github -> 마음대로 지어도 된다. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자.
- Username : root (default)
- Private Key : Enter directly 체크 -> private key 입력 (여기서 private key는 Jenkins Server에서 생성한 id_rsa이다. 아래 명령어로 확인 가능하다.)
cat /home/ubuntu/.ssh/id_rsa
- BEGIN ~END까지 다 넣어 줘야한다.
- OK를 눌러 키를 생성
- A 서버 접속 ⇒ 키를 호스트 파일에 추가 (디렉토리경로는 본인 젠킨스 홈 경로 설정-일반에서 확인 후 해당 경로에 넣어줘야 함. 만약 해당 경로의 디렉토리가 없다고 나오면 mkdir해서 만들기)
ssh-keyscan github.com >> /var/jenkins_home/.ssh/known_hosts
sudo chmod 700 /var/jenkins_home/.ssh
sudo chmod 644 /var/jenkins_home/.ssh/known_hosts
- (이 단계는 불필요한 단계이지만, 혹시 마운트가 제대로 안 된 것 같아 오류가 난다면 해보세요. 정상적으로 잘 마운팅 된 경우에는, 이 과정을 하지 않아도 A서버에서 추가한 것이 젠킨스 컨테이너 내부 파일에도 똑같이 적용될 거에요. )
A 서버 내 jenkins 컨테이너 내부 접속 ⇒ 키를 호스트 파일에 추가
docker exec -it jenkins bash
ssh-keyscan github.com >> /var/jenkins_home/.ssh/known_hosts
7. A서버의 Jenkins 와 docker hub 연동
- Docker Plugin 설치
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Docker 검색 > Docker, Docker Pipeline 플러그인 설치 및 재실행
- Docker Hub Credentials 등록
Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다.Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다.왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다.
- Kind :Username with password
- Username : 본인의 Docker Hub ID
- Password : 본인의 Docker Hub Password
- ID : docker-hub -> 마음대로 지어도 된다. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자.
- OK 를 눌러 키를 생성
- Jenkins Container 내부에 Docker 설치 (필수)
Jenkins Pipeline에서 Docker 명령어를 사용할 수 있도록 Jenkins Container 내부에 Docker를 설치해야 한다.
- A 서버 접속 후 Jenkins 컨테이너 내부 접속
docker exec -it jenkins bash
- sudo 설치 (컨테이너 내부에서 도커를 설치하기 위해 필요함)
apt-get update && apt-get install -y sudo
- vi 설치 (컨테이너 내부에서 도커를 설치하기 위해 필요함)
apt-get update
apt-get install vim
- wget 설치 (컨테이너 내부에서 도커를 설치하기 위해 필요함)
apt-get install wget
- 패키지 업데이트
sudo apt update
- https 관련 패키지 설치
sudo apt install apt-transport-https ca-certificates curl software-properties-common
- 리눅스 배포판 종류를 자동으로 인식하여 Docker 패키지를 설치해주는 스크립트
sudo wget -qO- https://get.docker.com/ | sh
- 도커 설치 확인
docker --version
- 현재 사용자를 docker group에 포함 (루트 사용자 가 아닌 일반 사용자 가 docker 명령어를 사용하려고 하면, Permission Denied 에러가 발생한다. 따라서 sudo 없이 docker 명령어를 수행하기 위해 Docker group 에 현재 사용자 이름 을 등록한다.)
sudo usermod -aG docker ${USER}
- 다시 패키지 업데이트
sudo apt update
- jenkins 컨테이너에서 빠져나오기
exit
8. A 서버와 B 서버 의 SSH 연결 설정
Jenkins로 Gradle 빌드하고 Dockerfile로 도커 이미지를 빌드해서 Docker Hub에 Push하고 Spring Boot Server에서 도커 이미지를 Pull해서 실행하게 하기 위해 필요하다. Jenkins Pipeline Script에서 SSH를 사용하여 Spring Boot Server의 명령어 실행을 할 수 있도록 하는 것이다.
- SSH Agent Plugin 설치
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > SSH Agent 플러그인을 검색하고 설치 및 재실행
- A 서버 접속
public key 값을 복사해둔다.
cat /home/ubuntu/.ssh/id_rsa.pub
- A 서버에서 빠져나와 B 서버로 접속
B 서버의 .ssh/authorized_keys 파일에 A서버의 public key 추가해준다.
vi /home/ubuntu/.ssh/authorized_keys
// authorized_keys에 한줄 띄우고 public key 등록
- Jenkins Credentials 등록
Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다.Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다.왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다.
- Kind : SSH Username with private key
- ID : ssh -> 마음대로 지어도 된다. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자.
- Username : root (default)
- Private Key : Enter directly 체크 -> private key 입력 (여기서 private key는 Jenkins Server에서 생성한 id_rsa이다. 아래 명령어로 확인 가능하다.)
// 다시 A서버로 접속 후
cat /home/ubuntu/.ssh/id_rsa
- BEGIN ~END까지 다 넣어 줘야한다.
- OK를 눌러 키를 생성
(사실상 위의 Jenkins와 Github 연동 시 생성한 Jenkins Credentials과 동일하다. 하지만 ID를 구분하여 사용하고자 SSH Credentials을 별도로 생성하였다.)
9. Jenkins Pipeline 구성
Github Repository에 push event가 발생했을 때 자동으로 Build가 실행되게 하기 위해 Pipeline과 Github Webhook을 연동해야 한다.
- Github Integration Plugin 설치
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Github Integration 플러그인을 검색하고 설치 및 재실행
- Jenkins Pipeline 설정
- Github project 설정 Pipeline 구성 화면 > General 영역에서 Github project를 선택한다. > Project url에 본인의 Github Repository Url을 입력한다. 이 때 Repository Url은 Clone 시 사용하는 HTTPS Url(.git으로 끝남)을 입력한다.
- Build Triggers 설정Pipeline 구성 화면 > Build Triggers 영역에서 GitHub hook trigger for GITScm polling을 선택한다.
- Github Webhook 추가
- Github Repository에서 Settings > Webhooks > Add Webhook 을 눌러 Webhook을 추가한다.
- Payload URL[Jenkins Server URL]:[Jenkins Server 포트]/github-webhook/
- Content typeapplication/json
- 나머지는 모두 default 설정 유지Add webhook 버튼을 눌러 Webhook을 추가 -> 목록에서 녹색 체크 아이콘이 생성되면 성공
- Pipeline Script 작성 (본문에는 #이 전혀 들어가지 않는다. #~# 이 부분을 본인에 맞게 대치해서 적어주면 된다.)
pipeline {
agent any
environment {
imagename = "#도커허브아이디/도커허브레포명#"
registryCredential = '#도커허브크레덴셜아이디#'
dockerImage = ''
}
stages {
stage('Prepare') {
steps {
echo 'Clonning Repository'
git url: '#git@github.com:깃허브레포지토리.git#',
branch: 'main',
credentialsId: '#ssh크레덴셜아이디 - github#'
}
post {
success {
echo 'Successfully Cloned Repository'
}
failure {
error 'This pipeline stops here...'
}
}
}
stage('Unit test') {
steps {
withGradle {
sh'''
echo test start
./gradlew test
'''
}
}
post {
failure {
error 'Fail unit test'
}
}
}
stage('Bulid Gradle') {
steps {
echo 'Bulid Gradle'
dir('.'){
sh './gradlew clean build'
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Bulid Docker') {
steps {
echo 'Bulid Docker'
script {
dockerImage = docker.build imagename
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Push Docker') {
steps {
echo 'Push Docker'
script {
docker.withRegistry( 'https://index.docker.io/v1/', registryCredential) {
dockerImage.push("latest")
}
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Docker Run') {
steps {
echo 'Pull Docker Image & Docker Image Run'
withCredentials([usernamePassword(credentialsId: registryCredential , passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
sshagent (credentials: ['#ssh크레덴셜아이디 - ssh#']) {
sh "ssh -o StrictHostKeyChecking=no ubuntu@#B서버ip주소# 'echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin'"
sh "ssh -o StrictHostKeyChecking=no ubuntu@#B서버ip주소# 'docker pull #도커허브아이디/도커허브레포명#'"
sh "ssh -o StrictHostKeyChecking=no ubuntu@#B서버ip주소# 'docker ps -aqf name=#도커컨테이너명# | xargs -r docker rm -f'"
sh "ssh -o StrictHostKeyChecking=no ubuntu@#B서버ip주소# 'docker run -d --name #도커컨테이너명# -p 8080:8080 #도커허브아이디/도커허브레포명#'"
}
}
}
}
}
}
<추가 설정>
파이프라인 코드에 로그인 관련 정보를 위와 같이 직접 넣어줘도 되긴 하지만, 젠킨스 설정에서 로그인 정보를 등록해주면, 코드 상에 명시할 필요가 없어진다. 아래를 참고하자.
- Jenkins 관리 > System > 아래와 같이 레포지토리 주소와 크레덴셜 추가
pipeline {
agent any
environment {
imagename = "#도커허브아이디/도커허브레포명#"
registryCredential = '#도커허브크레덴셜아이디#'
dockerImage = ''
}
stages {
stage('Prepare') {
steps {
echo 'Clonning Repository'
git url: '#git@github.com:깃허브레포지토리.git#',
branch: 'main',
credentialsId: '#ssh크레덴셜아이디 - github#'
}
post {
success {
echo 'Successfully Cloned Repository'
}
failure {
error 'This pipeline stops here...'
}
}
}
stage('Unit test') {
steps {
withGradle {
sh'''
echo test start
./gradlew test
'''
}
}
post {
failure {
error 'Fail unit test'
}
}
}
stage('Bulid Gradle') {
steps {
echo 'Bulid Gradle'
dir('.'){
sh './gradlew clean build'
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Bulid Docker') {
steps {
echo 'Bulid Docker'
script {
dockerImage = docker.build imagename
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Push Docker') {
steps {
echo 'Push Docker'
script {
docker.withRegistry( 'https://index.docker.io/v1/', registryCredential) {
dockerImage.push("latest")
}
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Docker Run') {
steps {
echo 'Pull Docker Image & Docker Image Run'
sshagent (credentials: ['#ssh크레덴셜아이디 - ssh#']) {
sh "ssh -o StrictHostKeyChecking=no ubuntu@#B서버ip주소# 'docker pull #도커허브아이디/도커허브레포명#'"
sh "ssh -o StrictHostKeyChecking=no ubuntu@#B서버ip주소# 'docker ps -aqf name=#도커컨테이너명# | xargs -r docker rm -f'"
sh "ssh -o StrictHostKeyChecking=no ubuntu@#B서버ip주소# 'docker run -d --name #도커컨테이너명# -p 8080:8080 #도커허브아이디/도커허브레포명#'"
}
}
}
}
}
+) 슬랙 추가 (연동방법은 링크를 참고한다. 파이프라인 코드는 아래대로 원하는 각 stage마다 post를 넣어주면 된다.)
https://junhyunny.github.io/information/jenkins/jenkins-slack-notification/
https://velog.io/@mooh2jj/Jenkins-Slack-Notification-%EB%93%B1%EB%A1%9D
stage('Deploy') {
steps {
echo 'Pull Docker Image & Docker Image Run'
sshagent (credentials: ['ssh']) {
// ..
}
}
post {
success {
slackSend(channel: '#code', color: 'good', message: "Pipeline succeeded at stage: Deploy")
}
failure {
slackSend(channel: '#code', color: 'danger', message: "Pipeline failed at stage: Deploy")
}
}
}
참고 : https://velog.io/@wawakdev/DockerJenkins-CICD-이거보고-성공하세요
'[백엔드] 여러가지 정리' 카테고리의 다른 글
git commit 내역 삭제 (최초 커밋 / 최근 커밋) (0) | 2024.05.21 |
---|---|
ec2 인스턴스에 Docker 를 통해 Nginx 설치하기 (0) | 2024.05.08 |
[설치방법 총정리] EC2 인스턴스, Docker, Jenkins (0) | 2024.05.05 |
스프링 프로젝트 생성하기 (0) | 2023.11.05 |