Jenkins Pipeline 구성
DevOps & 클라우드 환경을 구성한 프로세스의 구성도이다.
우선 CI(Continous Integration) 작업은 다음과 같다.
개발자가 깃허브로 커밋을 하게 되면 Jenkins에서 변경사항을 감지하여 소스코드를 pull 받아 gradle로 빌드한다.
빌드한 파일을 openSSH를 이용하여 Ansible 서버로 전달하게 되면 Ansible에서 jar 파일을 도커 컨테이너로 빌드하여 업로드 하고, 이미지화하여 도커 허브에 업로드한다.
CD(Continous Deployment)작업은 다음과 같다.
쿠버네티스 클러스터를 실행하고 있는 환경에서 도커 허브에 업로드했던 이미지를 pull 받아 파드로 실행한다. 로드밸런서를 연결하여 외부에서 접근할 수 있는 주소를 연결한다.
pipeline 구성에서 각 서버의 역할은 다음과 같다.
jenkins서버에서는 깃 변경사항 감지부터 ansible playbook을 실행하여 전체적인 흐름을 관리한다.
ansible 서버는 jenkins 서버에서 명령을 받아 도커에 이미지를 업로드하고, kubernetes에서 파드생성과 로드밸런서 연결을 위한 명령어를 실행한다.
eks 서버는 AWS 서비스의 EKS를 사용하기 때문에 쿠버네티스의 클러스터를 생성 및 관리하고, 파드를 실행하여 외부에서 접근할 수 있는 주소인 ELB의 DNS로 접근할 수 있다.
프로젝트 환경으로 AWS의 EC2의 인스턴스를 이용하여 서버를 구성하고, 각 서버는 같은 VPC로 연결되어있어 내부 IP 로 접근이 가능하다.
EC2 인스턴스 3개 구성
Jenkins, Ansible, eks
인스턴스 유형으로는 메모리 1GB, CPU 1개인 인스턴스 생성
인스턴스 이미지 : Linux
인스턴스 유형 : t2.micro
Jenkins 설치 및 실행
각 운영체제마다 jenkins 설치 방법은 링크에서 확인할 수 있다.
https://www.jenkins.io/doc/book/installing/linux/#red-hat-centos(Long Term Support release)
sudo wget -O /etc/yum.repos.d/jenkins.repo \
https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
sudo yum upgrade
# Add required dependencies for the jenkins package
sudo amazon-linux-extras install java-openjdk11
sudo yum -y install java-11-openjdk
sudo yum -y install jenkins
sudo systemctl daemon-reload
sudo systemctl enable jenkins
sudo systemctl start jenkins
sudo systemctl status jenkins
설치 후에 public ip 주소의 8080포트로 접근하면 다음과 같은 화면을 볼 수 있다.
jenkins password는 /var/lib/jenkins/secrets/initialAdminPassword
경로에서 확인할 수 있다.
접속후 볼 수 있는 화면
jenkins 설치 후 처음 접속하는 경우 admin 비밀번호를 재설정한다.
jenkins에서는 생성한 item이 하나의 파이프라인이 된다.
인스턴스의 서버가 혼동되지 않도록 hostname을 설정하자
hostnamectl set-hostname jenkins
exec bash
jenkins와 github 연동하기
jenkins CLI에서 git 패키지를 먼저 설치한다.
yum install git
git --version
jenkins 페이지에서 Dashboard → 구성 → Plugins → Available Plugin 으로 들어가서 git을 설치한다.
(git 설치 완료 페이지 넣기)
Jenkins Gradle 설정
Gradle은 Groovy를 기반으로 한 빌드 도구이다.
Ant와 Maven과 같은 이전 세대 빌드 도구의 단점을 보완하고 장점을 취합하여 만든 오픈소스로 공개된 빌드 도구이다.
Gradle은 의존성 관리를 위한 다양한 방법을 제공하고 빌드 스크립트를 Groovy 기반의 DSL을 사용한다.
Grooby는 자바 문법과 유사하여 자바 개발자가 쉽게 익힐 수 있고, Gradle Wrapper를 이용하면 Gradle이 설치되지 않은 시스템에서도 프로젝트를 빌드할 수 있다.
springboot 프로젝트를 빌드하기 위한 도구로 gradle을 사용했기 때문에 jenkins에서 gradle설정을 해준다.
jenkins 관리 → plugin → gradle plugins 설치
gradle환경 설정
jenkins 관리 → tool
→ install from Gradle.org 에는 gradle이 없다면 자동 설치하도록 버전을 설정해준다.
→ 빌드하려는 자바 프로젝트가 gradle 7.6.1 버전이기 때문에 상위 버전인 Gradle 8.0 을 설치한다.
트러블 슈팅
EC2의 t2.micro 유형으로 gradle프로젝트 빌드시 메모리 사용률 과다 문제
jenkins 서버에서 gradle로 프로젝트 빌드 중에 EC2가 멈추는 현상이 있었다.
EC2 FreeTier로 t2.micro 유형의 인스턴스의 경우 1GB의 RAM이 부여되는데, 서버 내부에서 프로젝트를 빌드하면서 메모리 사용률 과다로 인해 알 수 없는 문제가 발생해 cpu 사용률이 100%가 된 것으로 생각된다.
EC2 서버에 스왑영역을 생성하여 해결할 수 있었다.
참고 블로그 : https://sundries-in-myidea.tistory.com/102
- 일단 dd 명령어를 통해 swap 메모리를 할당한다.
sudo dd if=/dev/zero of=/swapfile bs=128M count=16
128씩 16개의 공간을 만드는 것이여서 우리의 경우 count를 16으로 할당하는 것이 좋다. 즉, 2GB정도 차지하는 것이다.
$ sudo chmod 600 /swapfile # 스왑 파일에 대한 읽기 및 쓰기 권한을 업데이트합니다.
$ sudo mkswap /swapfile # Linux 스왑 영역을 설정합니다.
$ sudo swapon /swapfile # 스왑 공간에 스왑 파일을 추가하여 스왑 파일을 즉시 사용할 수 있도록 만듭니다.
$ sudo swapon -s # 절차가 성공했는지 확인합니다.
# **/etc/fstab** 파일을 편집하여 부팅 시 스왑 파일을 활성화합니다.
$ sudo vi /etc/fstab
/swapfile swap swap defaults 0 0
EKS 란?
EKS는 AWS에서 제공하는 Amazon Elastic Kubernetes Service의 약자이다. EKS는 관리형 Kubernetes 서비스로, 사용자가 Kubernetes 클러스터를 프로비저닝하고 관리하는 데 도움을 준다.
EKS를 사용하면 사용자는 클러스터의 인프라 관리에 신경 쓰지 않고 애플리케이션에 집중할 수 있다.
EKS는 AWS에서 Kubernetes 마스터 컨트롤 플레인을 완전히 관리하므로 사용자는 클러스터의 설치, 업그레이드, 확장 등과 같은 복잡한 작업을 처리할 필요가 없다.
대신, 사용자는 간단한 명령을 사용하여 원하는 수의 워커 노드를 프로비저닝하고 관리할 수 있다.
즉, EKS를 사용하게 되면 마스터 컨트롤 플레인이 해당 쿠버네티스 서버가 아닌 EKS에서 관리하기 때문에 쿠버네티스를 설치한 서버가 다운되더라도 배포한 서비스에는 영향이 없다는 장점이 있다.
EKS 설치하기
eks의 이름으로 설정한 인스턴스에 접속하여 root 로 전환하여 작업한다.
콘솔의 hostname 바꾸기
hostnamectl set-hostname eks
exec bash
awscli 2 linux 버전으로 설치
https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/getting-started-install.html
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version
eksctl install
docs : https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/eksctl.html
github install 경로 : https://github.com/weaveworks/eksctl/blob/main/README.md#installation
# for ARM systems, set ARCH to: `arm64`, `armv6` or `armv7`
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH
curl -sLO "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
# (Optional) Verify checksum
curl -sL "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_checksums.txt" | grep $PLATFORM | sha256sum --check
tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz
sudo mv /tmp/eksctl /usr/local/bin
# version 확인
eksctl version
kubectl install
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
# (Optional) checksum
curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256"
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check
# kubectl: OK
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# version 확인
kubectl version --client --output=yaml
이후 eks인스턴스에 정책 부여 후 다른 인스턴스를 좌우할 수 있게 정책 설정
AWS - IAM - 역할 - 역할 만들기 (역할을 정책에서 가져와 부여한다.)
다음 페이지에서 정책 부여
- AmazonEC2FullAccess
- CloudFormationFullAccess //쿠버네티스 클러스터
- IAMFullAccess
- AdministratorAccess
완료 후에 화면은 다음과 같다.
AWS의 EKS가 EC2 인스턴스의 kubernetes를 제어할 수 있도록 설정
인스턴스 → EKS인스턴스 → 작업 → 보안 → IAM 역할 수정 → eks 역할 배정
eks cluster 생성 후 VPC 확인
EKS를 통해 생성된 VPC 구성도는 다음과 같다.
VPC 서비스 구성도
VPC 내에 생성된 private subnet은 외부 접근이 막혀있기 때문에 NAT Gateway를 통해 public subnet에서 접근할 수 있다. public subnet에서는 Internet Gateway를 통해 인터넷을 연결하고, ALB를 통해 외부에서 접근할 수 있는 주소를 연결한다.
EKS에서 생성한 클러스터와 워커 노드들은 위와 같은 방식으로 구성되어 EKS에서 관리하게 된다.
이렇게 설정 후 eks 인스턴스 콘솔로 다시 돌아오자
쿠버네티스 클러스터 만들기
eksctl create cluster --name 4glcluster --region ap-northeast-2 --node-type t2.small
—name : 이름은 클라우드 내에서 겹치면 안된다.
—region : 서울 리전
—node-type : 인스턴스 타입
→ 노드 갯수를 지정하지 않았지만 워커노드가 2개 만들어진다.
생성하는데 20분 정도가 걸린다.
생성 완료 후 워커 노드로 사용할 EC2 인스턴스가 두개가 생긴것을 확인할 수 있다.
Ansible이란?
Ansible은 IT 자동화 및 구성 관리 도구로써 서버, 네트워크 장비, 클라우드 리소스 등 다양한 IT 인프라를 자동화하고 관리하기 위해 설계되었다.
Ansible은 서버 프로비저닝, 구성 관리, 애플리케이션 배포, 오케스트레이션 등 다양한 작업에 사용될 수 있다.
Ansible은 Playbook이라고 불리는 yml 기반의 선언적인 구성 관리 파일을 작성하여 시스템을 원하는 상태로 구성할 수 있다. Playbook은 호스트 그룹, 모듈, 변수, 조건 등의 요소로 구성되며, 시스템 구성 및 관리 작업을 자동화하기 위해 사용ehlsek.
사용자는 Ansible을 통해 인프라스트럭처를 일관되고 반복 가능한 방식으로 관리하고, 자동화된 작업 흐름을 구축하며, 시스템의 상태를 모니터링하고 제어할 수 있다.
Ansible / docker 설치
ansible과 docker 통합 서버로 구축
ansible이 playbook을 참조하여 코드 자동화를 해준다.
hostname 설정
hostnamectl set-hostname ansible
exec bash
ansible 설치
yum -y install ansible // deprecated
sudo amazon-linux-extras install ansible2
docker 설치
yum -y install docker
systemctl --now enable docker
systemctl status docker
Ansible & kubernetes 서버 설정
앤서블 서버 → 쿠버네티스 부트 서버로 키 배포(SSH)
인스턴스 생성시 같은 VPC로 설정했기 때문에 내부 IP 로 통신이 된다.
Ansible / eks ****서버에서 유저를 생성 후 ssh 로그인 활성화
useradd ansadmin
passwd ansadmin
visudo해서 111행에 작성
ansadmin ALL=(ALL) NOPASSWD: ALL
유저 패스워드 ssh 로그인 활성화
vi /etc/ssh/sshd_config
61행 주석 해제 → 63행 주석 처리
service sshd reload
ansible의 ansadmin유저로 접근 후 키 배포를 한다.
su - ansadmin
ssh-keygen
이후 ansible 서버에서 eks서버로 public key를 전송한다.
ssh-copy-id <eks 서버 내부 id>
이제 ansible 서버에서 eks서버로 비밀번호 없이 접속이 가능하다.
ssh <eks 서버 내부 ip>
또한 ansible 서버를 타겟 서버로 접근하는 경우가 있기 때문에
ansible서버의 ansadmin에서 본인에게 ssh 전송을 한다.
ssh-copy-id <ansible 서버 내부 id> //ansadmin 유저로 진행
앤서블 서버에서 쿠버네티스 부트 서버로의 root 권한 또한 필요하므로
ssh-copy-id root@<eks 내부 ip>
이제 Ansible 서버에서 host파일에 작성
vi /etc/ansible/hosts
[kubernetes]
eks 서버 내부 IP
[ansible]
ansible 서버 내부 IP (나 자신의 IP)
이후 ssh ping 보내기
ansible all -m ping
docker 설정
docker 설치
앤서블 서버의 /opt/dockker 디렉터리를 도커 이미지 빌드 경로로 이용할 것이므로 디렉터리 생성과 권한을 부여한다.
mkdir /opt/docker
chown ansadmin.ansadmin /opt/docker
ansible에서 만든 이미지를 docker hub에 업로드 하기 위해 로그인을 한다.
docker login
Ansible을 jenkins와 연동
jenkins SSH 설정
jenkins의 plugin에서 publish over SSH 플러그인 다운로드 하기
대시보드 → jenkins관리 → system → publish over SSH
하단의 메뉴 중 SSH Server 추가하기
hostname은 ansible 서버의 내부 IP (jenkins와 같은 대역의 VPN으로 연결되어 있기 때문에 내부 IP 사용 가능)
username은 ansible 서버의 유저인 ansadmin
고급 - Use password authentication, or use a different key 체크 - Passphrase / Password에 dockeradmin 유저 패스워드 기입 - 맨 마지막 test configuration 으로 확인 - success
이렇게 jenkins 기본 설정을 마친 후 jenkins 프로젝트를 생성해보자
jenkins 프로젝트 생성
CI-Project : git repository로 부터 소스코드를 풀받아 Jenkins 서버에서 gradle로 빌드 후 ansible-playbook을 이용하여 프로젝트를 컨테이너화 시켜 도커 허브에 이미지로 저장
CD-Project : ansible서버에서 kubernetes 서버로 실행 관련 명령어를 전달하는 파일
Jenkins 구성관리에서 CI / CD 프로젝트를 각각 생성
→ 매 분마다 깃의 변경사항을 검사하여 빌드 실행하기 위해 crontab과 같은 문법으로 작성
→ 프로젝트의 gradle 버전인 7.4 보다 상위버전인 8.0으로 빌드 설정
Send build artifacts over SSH
Source files : build/libs/*.jar → gradle 빌드시 jar파일이 위치하는 기본경로 설정
Remove prefix : build/libs → 앞의 경로 지우가
Remote directory : //opt//docker → artifact를 받아서 빌드할 디렉터리 지정
jenkins에서 gradle 빌드가 완료된 후에는 다음의 명령어가 수행된다.ansible-playbook /opt/docker/create_image_regapp.yml
CI-Gradle 프로젝트에서 작업이 종료되면 CD-Gradle로 다음 작업을 트리거한다.
CD-Gradle 프로젝트는 다음의 명령어를 수행하기 위한 프로젝트이다.ansible-playbook /opt/docker/kube_deploy.yml
위의 파일에 관한 설명을 해보자
yml파일
ansible server 측 구성 → /opt/docker 디렉터리에 위치
# create_image_regapp.yml
# CI-Gradle 프로젝트에서 실행되는 파일, 이미지를 빌드하여 도커 허브에 push 한다.
---
- hosts: ansible
tasks:
- name: create docker image
command: docker build -t regapp:latest . #같은 경로에 있는 도커파일을 이용하여 컨테이너화 시킨다.
args:
chdir: /opt/docker
- name: create tag to push image onto dockerhub
command: docker tag regapp:latest os2018706072/regapp:latest #위의 name으로 생성된 컨테이너를 이미지화 시킨다.
- name: push docker image
command: docker push os2018706072/regapp:latest #도커 허브에 이미지를 push 한다.
# Dockerfile
FROM openjdk:11-jre
RUN mkdir /opt/app
COPY cloudProject.jar /opt/app/4glCloud.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/opt/app/4glCloud.jar"]
#openjdk11를 베이스 이미지로 설정하여 컨테이너 내부의 /opt/app 경로에 jenkins에서 빌드한 jar 파일을 복사한다.
#컨테이너 실행시 java -jar /opt/app/4glCloud.jar 명령어가 한번 실행되고, 매핑되는 내부 포트는 8080번이다.
# kube_deploy.yml
# CD-Gradle에서 실행하는 파일, kubernetes 서버에 명령을 전달한다.
---
- hosts: kubernetes
user: root
tasks:
- name: deploy regapp on kubernetes
command: kubectl apply -f /root/regapp-deployment.yml
- name: create service for regapp
command: kubectl apply -f /root/regapp-service.yml
- name: update deployment with new pods if image updated in docker hub
command: kubectl rollout restart deployment.apps/regapp4gl #생성한 deployment를 rollout 방식으로 재시작한다.
eks 서버측 구성
#regapp-deployment.yml
#쿠버네티스 파드 생성을 위한 파일
apiVersion: apps/v1
kind: Deployment #Deployment 생성
metadata:
name: regapp4gl
labels:
app: regapp
spec:
replicas: 3 #Deployment에 3개의 레플리카셋을 생성하여 포함시킨다.
selector:
matchLabels:
app: regapp
template:
metadata:
labels:
app: regapp
spec:
containers:
- name: regapp
image: os2018706072/regapp #dockerhub에 올렸던 이미지를 pull 받아 8080포트로 파드를 실행시킨다.
imagePullPolicy: Always
ports:
- containerPort: 8080
strategy:
type: RollingUpdate #rollout -> 변경사항이 있어 파드를 다시 올릴 때 레플리카셋에 있는 파드를 순차적으로 업데이트한다.
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
#regapp-service.yml
#쿠버네티스 로드밸런서 연결을 위한 파일, host의 80포트와 컨테이너 내부의 8080포트로 연결하여 ELB를 생성해준다.
apiVersion: v1
kind: Service
metadata:
name: service4gl
labels:
app: regapp
spec:
selector:
app: regapp
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
결과화면
jenkins pipeline으로 구성한 파드와 로드밸런서 확인
EC2 서버 & 워커노드 생성 확인
웹 브라우저에서 로드밸런서의 80 주소로 접근하면 springboot로 만든 화면을 확인할 수 있다.
github repository : https://github.com/hweyoung/jenkins-gradle.git
'프로젝트 > 클라우드' 카테고리의 다른 글
클라우드 리소스 관리를 위한 모니터링 시스템 구축, Prometheus와 Grafana (0) | 2023.06.25 |
---|---|
가상화 / 자동화 / 클라우드 기반 보안 네트워크 및 인프라 구현 (0) | 2023.06.24 |