GitHub Actions를 먼저 알아보기전 GitHub을 먼저 알아보자면, GitHub(깃허브)이란 소프트웨어 버전 관리와 협업을 위한 Git 플랫폼 입니다. 별도로 서버를 구성하지 않고도 GitHub 계정을 생성하여 소스 코드를 관리할 수 있습니다.
GitHub Actions이란 GitHub에서 공식적으로 제공하는 CI/CD 툴로써, 빌드, 테스트 및 배포 등의 파이프라인을 자동화할 수 있습니다. 또한 다양한 이벤트와 검색, 생성 및 공유 등 다양한 워크플로 및 사용자 정의된 워크플로를 사용할 수 있습니다. GitHub Actions의 특징 및 비용, 사용, 사례에 대한 기본적인 정보를 알아보겠습니다.
특징
GitHub Actions은 GitHub 저장소와 긴밀하게 통합되어 있어, 저장소 내에서 워크플로우를 설정하고 관리할 수 있습니다. 또한 코드, 이슈, 워크플로우 등 GitHub의 다양한 기능과 함께 통합되어 효과적인 협업과 개발이 가능합니다. 저장소 내에서 워크플로우를 설정하고 관리할 수 있다는 점이 큰 특징입니다.
GitHub에서 제공하는 Runner를 통해 별도의 서버(Runner)를 구성하지 않고 CI/CD Job을 실행할 수 있습니다. Runner는 Windows, MacOS, Linux와 같은 다양한 운영체제에서 동작하며, 다양한 환경에서 실행할 수 있습니다.
병렬로 여러 워크플로우 작업을 처리할 수 있어, 대규모 프로젝트에서도 효율적으로 사용할 수 있습니다.
비용
기본적으로 한 달에 Job 실행에 대한 시간을 3,000분을 무료로 제공해줍니다.
운영 체제 및 CPU에 따른 분당 요금은 다르며 가장 기본적인 요금은 분당 $0.008 입니다. 대략적으로 하루에 1분이 소요되는 Job을 100번 실행한다면 한 달 요금이 $24정도 발생됩니다.
Job 실행 시간이 길거나 많은 수를 실행한다면 생각보다 높은 비용이 발생될 수 있습니다.
Jenkins에서는 도커 컨테이너를 통해 다양한 환경에서의 빌드 및 배포 작업을 진핼할 수 있습니다. 하지만 Host OS가 Linux인 Jenkins 서버에서는 Window OS에서만 할 수 있는 작업에는 제한이 있는데요. Host OS가 Linux인 Jenkins 서버에서 Window 관련 작업을 진행하기 위한 Window Nodes 추가 및 연동하는 작업을 진행해 보겠습니다.
Nodes 설정 추가
Dashboard -> Jenkins 관리 -> Nodes 메뉴에서 Nodes 관련 설정을 관리할 수 있습니다.
기본적으로 Jenkins 서버를 설치하면 Host OS에 맞는 기본 Nodes가 Built-In Node 이름으로 생성되어 있습니다. Window Nodes를 신규 추가할 것이므로 New Node를 클릭하여 Nodes 설정을 추가합니다.
Nodes Name을 입력 후 Type은 Permanent Agent를 선택합니다.
Permanent Agent는 Jenkins 마스터 서버와 연결되어 지속적으로 사용 가능한 에이전트(또는 슬레이브)를 할당하는 것을 의미합니다.
Number of executors 값은 Nodes에서 수행할 수 있는 동시 빌드 작업 수를 정의합니다.
Remote root directory 값은 Nodes에서 사용할 작업 디렉토리를 지정하며, 작업 디렉토리는 설정한 값과 동일하게 Window Nodes에 추가해야됩니다.
Labels 값은 여러 에이전트를 그룹화하고 Pipeline에서 에이전트를 선택 시 사용하는 값입니다.
Usage 값은 빌드 작업에 대한 방법을 제어하며 Only build jobs with label expressions matching this node 값을 선택합니다. 레이블 표현식이 있는 작업만 빌드 시 사용하겠다는 것을 의미합니다.
Nodes 설정 추가 작업을 완료하면 아래와 같이 추가된 Nodes 정보를 확인하실 수 있습니다.
Nodes 연결
Nodes 설정을 추가하였으니 이제 Window에서 Nodes를 연결하도록 설정해보겠습니다. Nodes 이름을 클릭하면 아래와 같이 Nodes 연결을 위한 agent.jar 파일 다운로드와 연결 명령어가 정리되어 있습니다.
이제 Window OS에 접속하여 해당 명령어를 입력하여 agent.jar 파일 다운로드 후 jenkins의 Nodes로 연결합니다.
연결이 완료되면 Nodes 관리 페이지에서도 해당 Nodes의 상태에 X 표시가 사라지고 정상적으로 연결됨을 확인하실 수 있습니다.
Nodes 사용
이제 Jenkins Pipeline에서 설정한 Nodes를 사용하도록 설정해보겠습니다.
Pipeline에서는 Nodes 생성 시 설정한 Labels 값을 통해 Nodes를 지정하고 빌드 시 사용할 수 있습니다.
stage('window-agent-stage') {
agent {
// Nodes 생성 시 설정한 label 값
label 'windows'
}
steps {
// 명령어 입력
bat '''
bat 'dir /b
'''
}
}
agent { label 'windows' } agent 옵션을 사용하여 Nodes 생성 시 설정한 Labels 값을 지정하였습니다. 이제 Jenkins의 Pipeline이 동작할 경우 해당 Stage에서는 Nodes를 통해 연결된 Window OS 환경에서 명령어를 실행하여 빌드 시 사용할 수 있게 되었습니다.
Jenkins를 Window OS 환경에서 설치하여 사용할 경우 위와 같은 작업은 필요 없지만,
Linux OS 환경에 설치된 Jenkins에서 Window OS 환경 작업이 필요한 경우,
Window OS 환경에 설치된 Jenkins에서 Linux OS 환경 작업이 필요한 경우,
Nodes 추가 작업으로 작업을 구분하여 빌드 및 배포 작업을 구현할 수 있습니다.
지금까지 Jenkins에서 Window Nodes 추가 및 연동하는 작업을 알아보는 시간이었습니다....! 끝...!
Jenkins에서 빌드한 컨테이너 이미지를 EC2에 배포하는 작업을 진행해보겠습니다. 사전에 컨테이너 빌드 작업 완료 후 AWS ECR(Elastic Container Registry)에 업로드하는 작업을 생성해둔 상태입니다.
플러그인 설치
우선 Jenkins에서 빌드한 컨테이너 이미지를 EC2에 배포하기 위해서는 SSH 접속을 통한 접근이 필요한데요. Jenkins에서 EC2에 SSH 접속을 하기 위해서는 플러그인을 설치해야됩니다.
설치해야되는 플러그인은 SSH Agent Plugin 입니다.
SSH Key 발급 및 적용
SSH 접속은 Key를 통해 접속하므로 Key 발급 및 적용 작업을 진행합니다.
SSH Key 발급
ssh-keygen 명령어를 통해 개인키(id_rsa)와 공개키(id_rsa.pub)를 발급합니다.
EC2 공개키(id_rsa.pub) 적용
발급한 키 중 공개키(id_rsa.pub)를 배포하고자 하는 EC2에 적용합니다. 적용하고자 하는 접속 계정의 ~/.ssh/authorized_keys 파일에 공개키를 복사합니다.
### ssh-copy-id 명령어로 복사
ssh-copy-id {HOSTNAME}@{IP}
EX) ssh-copy-id ec2-user@10.1.1,1
### cat 명령어로 복사
cat .ssh/id_rsa.pub >> .ssh/authorized_keys
### vi로 파일 내용 추가
vi .ssh/authorized_keys
key 값 복사
EC2 서버로 직접 접속하여 공개키(id_rsa.pub)가 정상적으로 적용되었는지 확인합니다.
SSH Agent를 통해 EC2를 접속하기 위해 사전에 발급한 SSH Key 중 개인키(id_rsa)를 Credentials로 등록합니다.
개인키(id_rsa)는 Dashboard -> Jenkins 관리 -> Credentials 메뉴에서 등록합니다.
Credentials 발급 시 Kind는 SSH Username with private key를 선택합니다. 사용하고자 하는 ID와 Username을 지정합니다.
Private Key 값은 Enter directly 버튼을 클릭하여 직접 개인키(id_rsa)를 입력할 수 있도록 합니다. 개인키(id_rsa)를 Key에 입력 후 Create 버튼을 클릭하여 Credentials 등록을 완료합니다.
Jenkins Pipeline 설정
SSH Agent 플러그인을 사용하여 사전에 등록한 Credentials을 통해 EC2 접속 및 배포 작업을 진행해보도록 하겠습니다.
stage('deploy-EC2') {
steps {
//SSH Agent 플러그인을 사용하여 사전에 등록한 Credentials 지정
sshagent (credentials: ['EC2_ACCESS_KEY_ID']) {
sh """
### ssh 명령어로 EC2 서버 지정
ssh -o StrictHostKeyChecking=no ${EC2_USER}@${EC2_IP} '
### 실행할 명령어 입력
cd ${WORK_DIR}
docker compose down
docker pull ${AWS_ECR}/${IMAGE_NAME}:${IMAGE_TAG}
docker compose up -d
exit
'
"""
}
}
}
sshagent() 구분을 통해 SSH Agent 플러그인을 사용할 수 있도록 지정합니다.
credentials:[] 값에는 사전에 등록한 Credentials을 지정합니다.
ssh 명령어로 접속 및 배포하고자 하는 EC2 서버를 지정합니다.
실행할 명령어를 입력합니다.
작업 디렉토리 이동
도커 컨테이너 종료
도커 컨테이너 이미지 다운로드
도커 컨테이너 시작
위 작업을 통해 Jenkins에서 EC2 접속 및 배포 작업을 진행할 수 있습니다.
실행할 명령어에 따라 배포 작업을 진행하거나, 테스트, 모니터링 등 다양한 작업을 할 수도 있습니다.
지금까지 Jenkins에서 빌드한 컨테이너 이미지를 EC2에 배포하는 작업을 알아보는 시간이었습니다....! 끝...!
Jenkins에서 빌드한 컨테이너 이미지를 AWS ECR(Elastic Container Registry)에 업로드하는 작업을 진행해보겠습니다. 사전에 AWS ECR(Elastic Container Registry)은 생성해둔 상태입니다.
간단히 ECR 알아보기
사전에 간단히 ECR이 무엇인지 알아보겠습니다.
AWS ECR (Amazon Elastic Container Registry)은 Amazon에서 제공하는 Docker 컨테이너 이미지를 저장하고 관리하기 위한 완전관리형 Docker 이미지 저장소입니다. ECR을 사용하면 보안 및 확장성이 뛰어난 프라이빗 이미지 저장소를 손쉽게 생성하고 Docker 컨테이너를 배포할 수 있으며, Amazon ECS (Elastic Container Service) 및 Amazon EKS (Elastic Kubernetes Service)와 통합되어 원활한 컨테이너 관리를 제공할 수 있습니다.
플러그인 설치
우선 Jenkins에서 AWS ECR에 컨테이너 이미지를 업로드하기 위해서는 플러그인을 설치해야됩니다. 설치해야되는 플러그인은 Amazon ECR plugin 입니다.
AWS Credentials 등록
AWS ECR(Elastic Container Registry)의 Private Repositories를 접근하기 위해서는 Access Key와 Secret Key를 통한 인증이 필요합니다.
플러그인 설치 완료 후 Jenkins 관리 탭을 확인하면 AWS 메뉴가 추가되어 있습니다.
AWS 메뉴를 통해 AWS Credentials을 등록합니다.
Kind는 AWS Credentials를 선택합니다.
이후 설정하고자 하는 Access Key와 Secret Key를 설정하고 저장합니다.
마지막으로 Region을 선택하고 저장하면 AWS Credentials 등록은 완료됩니다.
Pipeline 설정
Pipeline script에서 제공하는 docker.build 와 docker.withRegistry 기능을 통해 Jenkins에서 빌드한 컨테이너 이미지를 AWS ECR(Elastic Container Registry)에 업로드 할 수 있습니다.
사전에 Build 환경이 구성되어야 하며 Dockerfile이 작성되어 docker build 명령어로 바로 도커 컨테이너 빌드가 가능한 상태로 세팅되어야 합니다.
stage('build_and_upload_docker') {
steps {
script {
// 도커 컨테이너 이미지 빌드
build_data = docker.build("${ECR_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/${IMAGE_NAME}:latest")
// 도커 컨테이너 이미지 업로드
// `AWS_CREDENTIALS_ID` 값은 사전에 등록한 AWS Credentials 정보
docker.withRegistry("https://${ECR_ID}.dkr.ecr.ap-northeast-2.amazonaws.com", "ecr:ap-northeast-2:${AWS_CREDENTIALS_ID}") {
build_data.push("${TAG_NAME}")
}
)
}
}
위 작업의 내용은 아래와 같습니다.
docker.build를 통해 도커 컨테이너 이미지 빌드 작업을 진행합니다.
빌드 작업을 완료하면 완료한 정보는 build_data에 저장합니다.
docker.withRegistry를 통해 AWS ECR에 접근합니다.
build_data의 push를 통해 저장하고자 하는 TAG 이름으로 AWS ECR에 빌드한 도커 컨테이너 이미지를 업로드 합니다.
${ECR_ID}, ${IMAGE_NAME}, ${AWS_CREDENTIALS_ID}, ${TAG_NAME} 값은 자신에 환경에 맞는 값을 설정하시면 됩니다.
성공적으로 Jenkins에서 빌드한 컨테이너 이미지를 AWS ECR(Elastic Container Registry)에 업로드 완료하면 아래와 같이 AWS ECR(Elastic Container Registry) 관리 페이지에서 업로드된 도커 컨테이너 이미지를 확인하실 수 있습니다.
활용
위에 작성한 Pipeline 설정 부분은 기본적인 방법으로 Jenkins에서 빌드한 컨테이너 이미지를 AWS ECR(Elastic Container Registry)에 업로드하는 작업입니다.
옵션 등을 사용하여 실제 업무에서 활용했던 부분을 간략히 추려보았습니다.
pipeline {
agent any
// 환경 변수 세팅
environment {
AWS_ECR = '123456789.dkr.ecr.ap-northeast-2.amazonaws.com'
AWS_IMAGE_NAME= 'test'
AWS_REGION = 'ap-northeast-2'
AWS_CREDENTIALS_ID = 'AWS_CREDENTIALS_ID_VALUE'
}
stage('build_and_upload_docker') {
steps {
script {
// 도커 컨테이너 이미지 빌드
// -f 등 추가적인 옵션 추가
build_data = docker.build(
"${AWS_ECR}/${AWS_IMAGE_NAME}:latest",
". -f Dockerfile.patch +@ ETC OPTION"
)
// 도커 컨테이너 이미지 업로드
// Branch 이름 및 기타 정보 등으로 TAG 생성
docker.withRegistry("https://${AWS_ECR}", "ecr:${AWS_REGION}:${AWS_CREDENTIALS_ID}") {
build_data.push("${env.gitlabBranch}")
build_data.push("${env.gitlabBranch}-${env.BUILD_NUMBER}")
build_data.push("${env.gitlabBranch}-${env.GIT_COMMIT}")
build_data.push("${env.gitlabBranch}-latest")
}
)
}
}
}
지금까지 Jenkins에서 빌드한 컨테이너 이미지를 AWS ECR(Elastic Container Registry)에 업로드하는 작업을 알아보는 시간이었습니다....! 끝...!
Jenkins 에서는 Artifact 플러그인 기능을 사용하여 생성된 Artifact를 저장하거나 복사하여 필요한 프로젝트 및 빌드에서 사용할 수 있습니다. Jenkins Pipeline에서 Artifacts 기능을 활용하는 방법을 알아봅시다.
Artifacts 정의
우선 Artifacts 기능을 활용하기 전에 Artifacts에 대한 정의를 알아봅시다.
위키백과에서는 Artifacts를 소프트웨어 개발 과정에서 생성되는 다양한 유형의 부산물 중 하나라고 설명하고 있습니다. 일부 Artifacts(예: 사용 사례, 클래스 다이어그램 및 기타 UML(Unified Modeling Language) 모델, 요구 사항 및 디자인 문서)는 소프트웨어의 기능, 아키텍처 및 디자인을 설명하는 데 도움이 되고, 다른 Artifacts는 프로젝트 계획, 비즈니스 사례 및 위험 평가와 같은 개발 프로세스 자체와 관련이 있다고 설명하고 있습니다.
artifacts로 파일 및 디렉토리 지정 시 glob 형식의 패턴을 통해 아래와 같이 사용할 수 있습니다.
### target 디렉토리에 있는 main.jar 파일 지정
archiveArtifacts artifacts: 'target/main.jar'
### target 디렉토리에 있는 *.jar 파일 지정
archiveArtifacts artifacts: 'target/*.jar'
### target 디렉토리에 있는 *.jar 파일과 *.war 파일 지정
archiveArtifacts artifacts: 'target/*.jar, target/*.war'
### 모든 디렉토리에 있는 *.jar 파일 지정
archiveArtifacts artifacts: '**/*.jar'
여러 옵션을 사용하여 아래와 같이 사용할 수도 있습니다.
excludes: 디렉토리 경로 및 파일의 패턴을 지정하여 제외할 수 있습니다. 설정 패턴은 artifacts와 동일하게 사용 가능합니다.
allowEmptyArchive: 빌드 아티팩트가 없는 경우도 아카이브에 추가할지 여부를 결정합니다. 기본값은 false이며, true로 설정하면 아카이브가 빈 상태가 될 수 있습니다.
caseSensitive: 아카이브 내 파일 이름 검색시 대소문자를 구분할지 여부를 결정합니다. 기본값은 false이며, true로 설정하면 대소문자를 구분합니다.
defaultExcludes: 아카이브에서 기본적으로 제외할 파일을 결정합니다. 기본값은 true이며, false로 설정하면 Ant 파일 패턴을 사용하여 제외할 파일을 지정할 수 있습니다.
fingerprint: 빌드 아티팩트의 지문(fingerprint)을 생성하여 추적할지 여부를 결정합니다. 기본값은 false이며, true로 설정하면 빌드 아티팩트가 변경될 때마다 새로운 지문이 생성됩니다.
followSymlinks: 심볼릭 링크를 따라가서 링크가 가리키는 실제 파일을 아카이브할지 여부를 결정합니다. 기본값은 false이며, true로 설정하면 심볼릭 링크가 아닌 실제 파일이 아카이브됩니다.
onlyIfSuccessful: 빌드가 성공했을 때만 아카이브를 생성할지 여부를 결정합니다. 기본값은 false이며, true로 설정하면 빌드가 실패했을 때는 아카이브를 생성하지 않습니다.
Artifact 복사 (copyArtifacts)
archiveArtifacts{} 구문을 통해 저장된 파일을 copyArtifacts{} 구문을 통해 복사할 수 있습니다. 기본적인 구문은 아래와 같이 사용됩니다. projectName 필드 설정으로 가져올 빌드의 이름을 지정하여 파일을 복사하는 설정입니다. 다른 프로젝트 빌드에 저장되어 있는 Artifact를 복사하여 사용할 수도 있습니다.
이제 저장된 Artifact를 복사하여 사용하기 위해 아래와 같이 코드를 구성하였습니다. pipeline-project-name 이름으로 저장된 빌드의 Artifact를 설정하고, 동일하게 'vendor/**, bin/**' 디렉토리를 지정하였습니다. 복사하는 Artifact는 build/ 디렉토리에 저장되도록 구성하였으며 복사할 Artifact가 없더라도 빌드가 실패하지 않도록 설정하였습니다.
Window 환경의 Jenkins에서 Cannot run program git.exe 에러 발생 시 해결하는 방법입니다.
Jenkins에서 Pipeline 실행 시 git.exe를 실행하지 못할 경우 아래와 같이 에러가 발생합니다.
git.exe 파일의 경로를 찾지 못하는 것으로 Jenkins 웹 관리자 페이지에서 Jenkins 관리 -> Global Tool Configuration 설정을 통해 git.exe 경로를 추가해줍니다. Git installations 설정 중 Path to Git executable 설정을 Window 환경에 맞는 값으로 설정합니다.
설정 저장 후 다시 Pipeline 실행 시 정상적으로 git.exe를 실행하는 것을 확인하실 수 있습니다.
지금까지 Cannot run program git.exe 에러 발생 시 해결하는 방법을 알아보았습니다...! 끝...!
GitLab 프로젝트 연동과 간단히 Pipeline을 동작하는 설정을 완료하였고, 이제 WebHook을 연동하여 Commit 등의 Event 시 자동으로 Jenkins Pipeline이 동작되도록 설정해봅시다.
WebHook 설정
설정하고자하는 Pipeline의 상세 설정의 Build Triggers 설정합니다.
Trigger 받고자하는 Event를 선택하고 자동으로 생성되는 WebHook URL을 복사해둡니다.
하단의 고급 버튼을 클릭하여 상세 설정을 확인합니다.
Secret token 항목에서 Generate 버튼을 클릭하여 GitLab WebHook과 연동할 token 값을 생성합니다. 해당 token 값은 이후에 사용해야하므로 복사해둡니다.
설정을 완료하면 Pipeline 설정을 저장합니다.
이제 GitLab 프로젝트에서 WebHook 설정을 추가해봅시다. GitLab 프로젝트 Settings -> Webhooks 메뉴를 클릭합니다.
아까 복사해둔 WebHook URL 값과 Secret token 값을 URL, Secret token 항목에 붙여 넣습니다.
그리고 사용하고자 하는 Trigger Event를 선택해주시면 됩니다.
WebHook 설정을 추가하면 아래와 같이 추가된 설정을 확인하실 수 있습니다.
Test를 통해 WebHook이 정상적으로 연결되었는지 확인합니다.
정상적으로 WebHook 설정이 완료되었으면 상단에 "Hook executed successfully: HTTP 200" 메시지가 출력된 것을 확인하실 수 있습니다.
WebHook 테스트
WebHook 연동 설정이 완료되었으므로 해당 프로젝트에서 소스 코드 수정 및 Commit 후 자동으로 Pipeline이 동작하는지 확인합니다. Pipeline 관리 페이지를 열어둔 상태에서 프로젝트에 Commit을 해봅니다. WebHook 연동 설정을 통해 자동으로 Pipeline 빌드가 실행됩니다.
Pipeline 빌드가 완료되면 해당하는 Build ID 클릭 후 아래와 같이 빌드 상태를 확인할 수 있습니다.
지금까지 Jenkins에서 GitLab 프로젝트와의 연동과 WebHook을 통한 Pipeline 자동화 구축 작업을 완료하였습니다...! 끝...!