EKS 란?
EKS란 Elastic Kubernetes Service의 약자로 AWS의 쿠버네티스 서비스입니다. Master Node가 따로 필요한 기존의 쿠버네티스와는 다르게
EKS의 마스터 노드 (컨트롤 플레인) 는 AWS에서 관리해 주어 따로 구성 및 관리할 필요가 없다는 장점이 있습니다.
자세한 내용은 아래의 문서[1]를 참고 해 주세요.
[1] https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/what-is-eks.html
이번 장은 저희 최종 목표인 EKS 클러스터 내에 Pod를 배포하기 위해 앞장에서 다뤘던 Jenkins Pipeline에 추가 구성을 해보도록 하겠습니다.
kubectl 설치 및 설정
CI/CD로 Pod 배포를 하려면 jenkins 서버에서 해당 EKS 클러스터에 접근 할 수 있도록 kubectl이 설정되어 있어야합니다.
일단, jenkins 서버의 jenkins 유저로 접속 해 봅시다.
kubectl 설치
$ curl -o kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.14.6/2019-08-22/bin/linux/amd64/kubectl
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 41.0M 100 41.0M 0 0 8835k 0 0:00:04 0:00:04 --:--:-- 9304k
$ chmod +x ./kubectl
$ mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
$ echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc
$ kubectl version --short --client
Client Version: v1.14.7-eks-1861c5
IAM AccessKey/ SecretAccessKey 설정
IAM 엔티티가 EKS 클러스터의 RBAC에 제어받기 때문에, Jenkins 서버에 클러스터를 생성한 IAM 계정의
Access Key를 설정 해 줍니다.
물론, Jenkins 서버에서만 사용하는 계정을 생성하여 최소한의 권한만 부여하는 것이 Best Practice입니다.
다른 IAM 사용자에 클러스터 액세스 권한을 주기 위해서는 아래 문서[2]를 참고 하시면 됩니다.
[2] https://aws.amazon.com/ko/premiumsupport/knowledge-center/amazon-eks-cluster-access/
aws configure 커맨드로 설정 가능하며, 파일 저장 위치는 .aws/credentials 입니다.
$ aws configure
AWS Access Key ID [****************IWTW]:
AWS Secret Access Key [****************5CIJ]:
Default region name [ap-northeast-2]:
Default output format [None]:
$ aws sts get-caller-identity
{
"UserId": "*******************",
"Account": "************",
"Arn": "arn:aws:iam::************:user/sanghyeon.park"
}
aws eks 커맨드로 kubeconfig 파일을 자동으로 생성합니다.
$ aws eks update-kubeconfig --region ap-northeast-2 --name srebgk_cluster
Added new context arn:aws:eks:ap-northeast-2:************:cluster/srebgk_cluster to /home/jenkins/.kube/config
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
여기 까지 잘 따라 오셨다면, kubectl 설정은 끝이납니다.
Jenkins Pipeline 추가 구성
다시 Jenkins 대시보드로 돌아갑니다.
구성에 해당 Job에 들어가 Pipeline에 아래와 같이 Deployment를 배포하는 Step을 추가 해 줍니다.
[Stage: Deploy pod]
stage('Deploy pods'){
when {
expression {
return env.dockerBuildResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/
}
}
steps{
script{
try{
sh """
sudo rm -rf deployfiles
mkdir deployfiles && cd deployfiles
#!/bin/bash
cat>monthly_deploy.yaml<
apiVersion: apps/v1
kind: Deployment
metadata:
name: monthly-deployment
labels:
app: monthly
spec:
replicas: 3
selector:
matchLabels:
app: monthly
template:
metadata:
labels:
app: monthly
spec:
containers:
- name: monthly-cont
image: ${ECR_TASK_URI}:ver${env.BUILD_NUMBER}
ports:
- containerPort: 5000
EOF"""
sh "pwd"
sh "/home/jenkins/bin/kubectl apply -f /var/lib/jenkins/workspace/Deploy_SREBGK_MonthlyReport/deployfiles/monthly_deploy.yaml"
env.deployPodsResult=true
}catch(error){
print(error)
env.deployPodsResult=false
currnetBuild.result='FAILURE'
}
}
}
}
전체 Script
pipeline {
agent any
stages {
stage('Git Clone') {
steps {
script {
try{
git url: "https://$GIT_URL", branch: "master", credentialsId: "$GIT_CREDENTIALS_ID"
env.cloneResult=true
}catch(error){
print(error)
env.cloneResult=false
currentBuild.result='FAILURE'
}
}
}
}
stage('Docker Build'){
when{
expression {
return env.cloneResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/
}
}
steps {
script{
try{
sh"""
#!/bin/bash
cat>Dockerfile<
# build stage
FROM ${ECR_BASE_URI}:init as build-stage
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "flasktest:app", "-w", "2", "--timeout=300", "-k", "gevent"]
EOF"""
sh"""
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${ECR_URI}
docker build -t ${env.JOB_NAME.toLowerCase()} .
docker tag ${env.JOB_NAME.toLowerCase()}:latest ${ECR_TASK_URI}:ver${env.BUILD_NUMBER}
docker push ${ECR_TASK_URI}:ver${env.BUILD_NUMBER}
"""
env.dockerBuildResult=true
}catch(error){
print(error)
env.dockerBuildResult=false
currentBuild.result='FAILURE'
}
}
}
}
stage('Deploy pods'){
when {
expression {
return env.dockerBuildResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/
}
}
steps{
script{
try{
sh """
sudo rm -rf deployfiles
mkdir deployfiles && cd deployfiles
#!/bin/bash
cat>monthly_deploy.yaml<
apiVersion: apps/v1
kind: Deployment
metadata:
name: monthly-deployment
labels:
app: monthly
spec:
replicas: 3
selector:
matchLabels:
app: monthly
template:
metadata:
labels:
app: monthly
spec:
containers:
- name: monthly-cont
image: ${ECR_TASK_URI}:ver${env.BUILD_NUMBER}
ports:
- containerPort: 5000
EOF"""
sh "pwd"
sh "/home/jenkins/bin/kubectl apply -f /var/lib/jenkins/workspace/Deploy_SREBGK_MonthlyReport/deployfiles/monthly_deploy.yaml"
env.deployPodsResult=true
}catch(error){
print(error)
env.deployPodsResult=false
currnetBuild.result='FAILURE'
}
}
}
}
}
}
최종 결과
코드에서 master 브랜치로의 git push를 진행하고 pod가 잘 배포되는 지 확인 해 보자.
% git push
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/Monthly_Report
8bc8c23..9d1c9c3 master -> master
마지막으로 추가한 Deploy pods stg가 View에 추가된 것을 확인 할 수 있습니다.
클러스터에 Deployment 까지 확인 할 수있습니다.
이렇게 해서, EKS 환경에서 CI/CD 구축이 완료되었습니다.
개발자 분들은 코드 배포 과정에서 더이상 고통 받지 마시고 개발에만 집중하시는게 어떨까요!
감사합니다.