반응형
1. 작성 계기
- 백엔드 서버 개발을 진행하면서 젠킨스를 사용하긴 하지만 직접적인 구축에 대해서는 블랙 박스였기 때문에 장애 처리에 대한 미흡한 점이 많았다.
- 백엔드 개발자에 대한 내 개인적인 수준은 인프라적인 부분까지 어느정도 구축할줄 알아야한다고 생각했다.
- 기존에 Kubernetes & Jenkins 구축을 Vagrant 환경에서 해봤는데, 맥 & 로컬에서 스터디하기 너무 까다로워서 Docker Desctop 기반으로 쉽게 스터디할 수 있는 방안을 모색했었고, 이슈없이 한 번에 구축할 수 있도록 정리했다.
2. Kubernetes 환경 구성
- 로컬에서 개인저인 학습을 위해 Docker Desctop 위에 Kubernetes 환경을 구축했다.
- Docker Desctop의 설정 메뉴에서 아래 사진에 보이는 Kuberentes 메뉴를 통해 구축한다.
3. Helm Chart
- Kubernetes Deploy를 위해서는 Deployment / Statefulset / Demonset 등의 yaml 파일 통해 작성해야하는 번거로움이 있다.
- 이는 여러 환경을 구성해야 하는 Kuberentes 특성상 러닝커브에 대한 깊은 벽을 느끼게 된다 (처음 구축 시 막막했었다..)
- 단순 Kubernetes 학습을 위해서라면 위 배포 타입과 Servive / Namespace / Volume 등을 적절히 이용하여 구축해보는 것을 선호한다.
- 지금은 단순히 배포 프로세스에 대한 작성이기 때문에 간단한 방법을 소개하려 한다.
- Helm Chart는 복잡한 Kubernetes 설정 파일들을 하나의 이미지를 받아 사용하는 것처럼 간단하게 받아서 사용할 수 있는 Package Manager다
- Helm Chart Download (Mac Intel 기준)
brew install helm
4. Jenkins 환경 구축
- Helm을 통해 Jenkins 환경을 구축하기 위해서는 먼저 Helm Repository에 있는 Jenkins 정보를 로컬에 가져와야한다.
# 젠킨스 차트 정보를 추가한다.
helm repo add jenkins https://charts.jenkins.io
# 잘 받아졌는지 확인한다.
helm repo list
# 젠킨스를 구축하기 위한 정보를 담은 values.yaml 파일을 현재 디렉토리에 복사한다.
helm show values jenkins/jenkins > jenkins-values.yaml
# 젠킨스 statefulset 배포
helm install jenkins jenkins/jenkins
- 처음 Jenkins Install 시 아래와 같은 Log가 나오는데, 여기서 첫 번째와 두 번째 문구를 잘 봐야한다.
- 첫 번째 문구는 처음 생성 시 제공되는 비밀번호다.
- 사용자 이름: admin
- 비밀번호: 첫 번째 명령어 실행
- 두 번째 문구는 기본적으로 Kubernetes가 Docker 내부의 private 한 환경이기 때문에 외부에서 접속할 수 있도록 노출해주는 작업이 필요하다.
- 이 작업을 보통 Kubernetes에서는 ServiceType이 해주는데, 여기서는 그 중에 NodePort라는 것을 통해 외부로 노출시키도록했다.
- 두 번째 명령어를 실행하면 젠킨스가 외부로 노출된다.
- Jenkins가 성공적으로 구축되면 아래와 같은 사진이 뜬다.
4-1. 이대로 배포하게 된다면, 문제가 뭘까?
- Helm Chart에서 제공해주는 기본 Jenkins는 Built-in node 방식을 사용한다.
- 컨트롤러에서 job을 수행하는데, 이게 문제가 뭐냐면 Pod의 기본 사용 Memory가 512MB인데 Gradle 기본 프로젝트 Build 시 499MB를 소모하게 되는데 단순히 Gradle Job만 수행하는 것이 아니라, Controller 내부에서 Kubernete-plugin 운영하기 위해 사용하는 Memory가 먼저 점유하고있기 때문에 Gradle Job은 항상 실패하게 된다.
- 따라서 Built-in node 방식에서 Job을 수행하려면 node executor의 숫자를 0에서 1로 늘려줘야한다.(Jenkins 관리 -> Nodes 관리 -> 설정 버튼을 통해 조절할 수 있다.)
- 하지만, Built-in node 방식에서 executor의 수를 늘리는 것은 보안에 위협이 될 수 있다는 경고문이 뜨기 때문에 좋지 않은 방법이라 생각한다.
4-2. Master-Slave 구조로 변경
- Controller Node에서는 Job이 수행이 될 때, 특정 노드에서 agent pod를 실행시켜 Job을 수행하는 구조인 Master-slave 구조가 널리 사용된다고 하고 내 생각에도 좋은 방법인듯 하여 이를 통해 구축했다.
- 노드 구성 방법
- 우선 helm install 전에 jenkins-values.yaml 파일을 열어서runAsUser / fsGroup 가 1000으로 되어있는 부분을 0으로 고치자 => 노드 생성 시에 CLI 로 접속하여 명령어 수행 시, permission denied가 발생하기 때문에 권한을 미리 설정
- Helm을 통해 Jenkins를 구축하고, [Jenkins 관리] -> [Nodes 관리] -> [New Node]를 통해 젠킨스를 구축한다.
- 생성 후에는 다음과 같이 연결이 안 되어있는데, 연결하기 위해 안에 정보를 확인해보자
- 나의 Jenkins Controller는 리눅스 계열이기 때문에 첫 번째 항목을 통해 구성해주도록 하겠다.
- 위 명령은 kubectl get pod 명령어로 나오는 jenkins-0 pod로 접속하여 실행한다.
- kubectl exec -it ${POD_NAME} /bin/bash
- 접속 후 위 명령어 순차적으로 실행
- 다음과 같이 Node가 정상적으로 연결 된 것을 확인할 수 있다.
- Jenkins가 정상 구동되었을 때,
- 젠킨스가 구동이 되면 [Client] -> [NodePorter] -> [ClusterIp] -> [Pod] 로의 연결이 된다
- 젠킨스를 빌드하면, Master(built in node)에서 Slave 노드를 통해 agent pod를 생성하고, 이 안에서 build를 진행하기 때문에 해당 Pod의 Memory Usage만큼 사용할 수가 있다.
5. Jenkins Job을 통해 Gradle 배포하기
- Job을 실행하기 위한 방법을 여러가지가 있지만, 나는 가장 simple한 FreeStyle을 통해 진행했다.
- Job을 실행시킬 git repository 주소를 적는다. 이 때 단순 배포 학습이기 때문에 credential 정보는 적지않고, respository 또한 public을 유지한다.
- Build Step에서 [Execute Shell]을 클릭하여 실행할 명령어를 입력하고 저장한다.
- 저장 후에 이동한 화면에서 [지금 빌드]를 통해 Job을 시행한다.
반응형
LIST