AWS EC2 Jenkins를 통한 CI 환경 구축
서론
이전 글을 통해 Docker-compose 구성을 통한 각 서버별 Docker Container들을 구성하였는데, 진행하다 보니 CI 자동화도 알아보고 싶어 이에 대해 다루고자 한다. 본 글에서는 AWS EC2 인스턴스 내 Jenkins를 통해 CI 자동화에 대해 다루고자 한다. 현재 회사 특성상 CD 까지 진행하는데 어려움이 있을 듯 해 ‘CI/CD’가 아닌, CI만을 다루고자 한다.
본론
CI/CD 란?
CI = 지속적인 통합(Continuous Integration)을 의미하는 단어로 ‘빌드와 테스트’를 자동화한 것이다.
CD = 지속적인 전달(Continuous Delivery) or 지속적인 배포(Continuous Deployment)를 의미하는 단어로 CI가 완료된 이후 사용자에게 전달하는 배포 과정을 자동화한 것이다.
즉, CI는 개발 과정에서 필요한 빌드 및 테스트 단계를 자동화한 것이고 CD는 테스트가 완료된 코드를 사용자에게 전달하기 위한 도구이다.
프로젝트 구성
전체 프로젝트 구성은 위 사진과 같다. 사용자가 코드를 깃 저장소에 올릴 경우 Github Webhook을 통해 해당 코드 내용을 Jenkins Docker Container에 반영한다. 이후 Jenkins가 Migration, Test를 비롯한 일련의 작업들을 수행하는 구조이다.
위에서 언급했듯이 본 프로젝트에서는 CI 환경 구축만을 목표로 하였기 때문에 별도의 Docker Hub와의 연결 없이 테스트 단계에서 마무리하도록 하겠다.
AWS EC2 인스턴스 생성
EC2에 대해 보다 자세히 다룬 글들이 존재하기에 참조할만한 링크만 추가한 뒤 본 글에서는 EC2 인스턴스를 통해 자동화하는 과정에 대해 집중적으로 다루고자 한다.
기존 활용하던 인스턴스가 아닌 새로 인스턴스를 생성하여 설명하도록 하겠다. 추가로 본 글에서는 ‘프리 티어’를 기준으로 설명하므로 이를 인지하고 살펴볼 필요가 있다.
신규 인스턴스 생성
상단 레드박스 내 버튼을 통해 신규 인스턴스를 생성할 수 있다
Application and OS Images
AMI(Amazon Machine Image)는 해당 EC2 인스턴스의 베이스가 될 OS를 선택하는 것인데, 본 글에서는 Amazon Linux 2
를 기준으로 설명하고자 한다. Ubuntu
를 기준으로 하고자 할 경우 다른 AMI를 선택하면 된다.
인스턴스 유형 및 키 페어
인스턴스도 마찬가지로 기본 인스턴스인 t2.micro를 활용할 예정이다. 다음으로 중요한 부분은 키페어에 관련된 부분인데, 추후 해당 키 페어를 통해 SSH 접속에 활용할 예정이니 주의깊게 살펴야 한다.
키페어 이름을 설정한 뒤 생성을 하면 로컬에 키페어가 다운로드 된다. 추후 해당 키페어가 위치한 디렉토리에서 SSH 접속을 해야하므로 안전한 곳에 보관하면 된다.
네트워크 구성
네트워크 구성의 경우 외부에서 Jenkins 접근을 허용하기 위해 8080
포트를 추가로 개방해주었다. 특정 포트에 대해 외부로부터의 접근을 허용하는 것을 ‘인바운드 규칙’이라 하는데, 본 글에서는 8080
포트만 활용할 예정이므로 추가적으로 이에 대해 다루진 않겠다.
인스턴스 생성 완료
상기 과정을 완료했다면 아래 이미지처럼 인스턴스가 성공적으로 생성되었음을 확인할 수 있다
인스턴스 접근
정상적으로 인스턴스 생성이 완료되었다면 이전 과정에서 생성한 키 페어를 통해 인스턴스 내부에 접근할 수 있다. 본인의 키 페어가 위치한 디렉토리에서 ssh -i <키페어 이름>.pem ec2-user@<퍼블릭 IP>
를 통해 인스턴스 내부로 접근할 수 있다.
그런데 접근을 시도할 경우 위 이미지처럼 에러가 발생함을 확인할 수 있다. 이는 최초 다운로드된 키 페어의 경우 접근 권한이 외부인에게도 허용된 상태이기 때문인데, sudo chmod 400 test.pem
명령어를 통해 해당 키 페어의 권한을 변경해주면 정상적으로 인스턴스에 접근할 수 있다.
Jenkins 설치 & 설정
본 글에서는 EC2 인스턴스 내 도커를 설치한 뒤, Jenkins Container를 띄울 예정이다. Docker 내부에 Jenkins를 설치하지 않고 EC2 자체에 Jenkins를 설치하는 방법도 존재하나, 설치 및 관리의 편의성으로 인해 이러한 방법을 채택하였다.
아래 일련의 명령어를 수행함으로써 필수 패키지 및 Docker를 설치할 수 있다.
1 | # 패키지 업데이트 |
위 과정을 완료하였다면 아래 명령어들을 통해 정상적으로 설치 및 실행이 완료되었음을 확인할 수 있다
1 | # Docker 설치 확인 |
이후 docker-compose.yml
파일을 통해 Jenkins Container를 구성해보겠다.
1 | # pwd : /home/ec2-user/docker-compsoe.yml |
아래 명령어들을 통해 도커 생성 및 확인을 할 수 있다
1 | # pwd : /home/ec2-user |
상기 과정을 모두 정상적으로 수행하였다면 브라우저 상에서 <퍼블릭 IP>:8080
을 통해 Jenkins를 사용할 수 있다.
Jenkins를 활성화하기 위한 비밀번호는 docker logs <container 이름>
명령어를 통해 확인할 수 있다.
이후 패키지를 설치할 수 있는데, 대부분 좌측 기본 패키지 설치하는 것을 권장한다
패키지 설치를 완료한 뒤 로그인에 사용할 관리자 계정을 생성해주면 Jenkins 설정은 끝이다.
Github Webhook 연결
Github Webhook을 통해 Github 저장소에 코드가 변경될 경우(push, merge request, …) 자동적으로 빌드를 수행하게끔 하고자 한다. Github 저장소와의 연결을 위해 Credential을 만들어야 한다.
아래 페이지에서 username
: Github ID, Password
: Github Access Token 를 입력한 뒤 ID
는 자유롭게 입력하면 된다. ID
를 입력하지 않을 경우 자동으로 생성되나 구분을 위해 별도로 선언하는 편이 좋다.
이후 연결하고자 하는 저장소에 들어간 뒤 Webhook을 설정할 수 있다.
Payload URL에 http://<퍼블릭 IP>:8080/github-webhook/
로 설정하면 된다.
Github와 연결을 완료하였으니 코드가 수정될 경우 수행할 작업들을 정의하도록 하겠다.
아래 이미지와 마찬가지로 ‘소스 코드 관리’ 탭에서 연결하고자 하는 Git 주소, Credential, Branch를 설정해주었다. 필자는 main
branch 기준이므로 수정하였다.
이후 ‘빌드 유발’ 탭에서 Github Webhook과 관련된 GitHub hook trigger for GITScm polling
옵션을 활성화해준 뒤, ‘Build Steps’에서 Execute Shell
탭을 선택한 뒤 수행할 일련의 명령어들을 정의하였다.
참고로 필자의 경우 실제론 Postgresql, Django, Nginx 3개의 Docker-compose로 구성된 환경이나 Jenkins 내부에서는 Django에 대한 테스트를 수행할 것이므로 위와 같이 빌드 명령어를 작성하였다.
또한 위 명령어는 Jenkins Docker Container 내부에서 수행되는데, 현재 해당 Conatiner 내부에는 파이썬을 비롯한 별도의 패키지들이 설치되어 있지 않다. 따라서 아래 명령어를 통해 이를 설치하고자 한다.
1 | # Container 진입을 위한 명령어 |
이후 연결한 Github 저장소에 들어가 코드를 수정하면 아래와 같이 Jenkins에서 빌드가 수행됨을 확인할 수 있다.
참고 문헌
젠킨스란 무엇인가, CI(Continuous Integration) 서버의 이해)
Django + jenkins + docker CI/CD 구축기)
젠킨스(Jenkins) Github Webhooks 연결)
비공개 도커 레지스트리(private docker registry) 만들기)
End to End Project: Deployed Django Application with Jenkins CI/CD Pipeline)
Springboot Gradle + AWS EC2 + Jenkins + Docker로 배포까지)