CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.
Devops 문화가 자리잡으며, 어플리케이션의 수명 주기가 짧아졌습니다.
이러한 환경적 변화에 적응 하기 위하여 어플리케이션 주기를 관리하기 위한 시스템이 필요 해졌는데요, 이러한 시스템을
CICD Tool이라고 부릅니다.
▶ CI CD가 뭐에요 ?
CI CD는 지속적 통합과 지속적 배포라는 뜻의 용어입니다.
Git과 같은 SCM Tool을 사용할때 코드 푸시와 병합, 컴파일이라는 용어를 자주 볼것입니다. 개발자들에게 코드를 작성하는것 만큼이나 해당 코드를 공통 레포지토리에 푸시하고 병합(Merge)하며 컴파일을 함으로써 인간이 이해 할수 있는 언어로 작성된 소스 코드를 CPU가 이해할수 있는 기계어로 컴파일하는 과정이 필요하며 중요합니다.
✅ 전반적인 과정을 지속적 통합, 지속적 배포라고 부르죠. (CICD)
✅ 통상적으로 통합과 배포 관련 과정들을 전부 자동화 하여 처리해주는 시스템을 CICD 툴이라고 부릅니다.
▶ CI영역과 CD영역을 구분해서 사용하는 이유?
아래 그림과 같이 코드를 작성하고 어플리케이션 빌드와 테스트 등을 자동화 한 부분을 CI 영역이라고 부르고,
이를 Deploy하고 Operate 하는 부분을 CD 영역이라 부릅니다.
사실상 이렇게 구분해서 이해하는것이 CICD Tool이 어떻게 동작하는지에 대해 정확히 이해하기 편리하기 때문에 편의상
CI와 CD를 구분해서 이야기 하기도 합니다.
또한, CI툴과 CD툴을 다른 솔루션으로 처리하는것도 빈번하게 보이는 추세입니다.
실 습 내 용
ci는 젠킨스를 통해 Harbor 레지스토리에 이미지 푸시
왜 harbor을 사용할까?
Harbor는 private Registry로 오픈소스 레지스트리 입니다.
컨테이너 레지스트리를 public으로 docker hub 또는 ECR을 사용하는 경우도 있지만, 비용상의 문제와 보안상의 문제로 오픈소스 컨테이너 레지스트리를쓰는 기업도 많습니다.
harbor SSL 을 적용? 미적용?
Harbor을 http로 insecure 형태로 사용하는 경우와 https 인증서를 직접 노드에 적용시켜 사용하는 경우가 있습니다.
해당 인증서를 설치하고 사용하는데 있어서 이번 시간에 가이드를 제공 드리려고 합니다.
- CI: 코드 작성 / Build / TEST - CI 툴은 전통적인 강호 Jenkins를 사용하는것이 많은 레퍼런스와 편리한 코드작성에 유리합니다.
- CD: 배포,운영 - 또한, CD 툴은 가시성이 뚜렷한 ArgoCD 와 같은 솔루션을 오픈소스로 사용하는 것이 적합하다는 평이 많습니다.
필요사항
- 젠킨스 설치 및 설정
- Harbor Registry 설치 및 설정 - private Registry를 사용해보려고 한다.
- argocd 사용함으로써 Git을 활용한 (gitops) 쿠버네티스 클러스터에 어플리케이션을 배포.
1. 젠킨스 설치
# 실습 편리를 위해서 root 계정 전환
sudo su -
# Add required dependencies for the jenkins package
# https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/amazon-linux-install.html
sudo yum install fontconfig java-17-amazon-corretto -y
java -version
alternatives --display java
JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto.x86_64
echo $JAVA_HOME
# 젠킨스 설치
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
sudo yum install jenkins -y
sudo systemctl daemon-reload
sudo systemctl enable jenkins && sudo systemctl start jenkins # 다소 시간 걸림
sudo systemctl status jenkins
# 초기 암호 확인
sudo systemctl status jenkins
cat /var/lib/jenkins/secrets/initialAdminPassword
# 접속 주소 확인
curl -s ipinfo.io/ip | awk '{ print "Jenkins = http://"$1":8080" }'
- 제안된 플러그인 설치 시 Docker 플러그인 추가 설치 필요함
- 관리자 계정 설정 : admin/qwe123, 이름(koo)
- 설정완료 후 젠킨스 접속 -> 젠킨스 관리 -> Tools
- JDK installations: jdk-17 , /usr/lib/jvm/java-17-amazon-corretto.x86_64 → Save
- 첫번째 Item(Project) 생성 -> 새로운 Item 클릭 → Name : First-Project , Freestyle project ⇒ 하단 OK 클릭
- Build Steps → Add build step ⇒ Execute shell 클릭
- 간단한 문장 출력 될 수 있게 입력 : echo "Aws Workshop Study" → 하단 Apply 후 저장
- docker 사용 - 플러그인 추가 설치 필요 / docker 설치 필요
- 젠킨스 유저로 docker 사용 가능 해야 함
# jenkins 유저로 docker 사용 가능하게 설정
grep -i jenkins /etc/passwd
usermod -s /bin/bash jenkins
grep -i jenkins /etc/passwd
# jenkins 유저 전환
su - jenkins
whoami
pwd
docker info
exit
#
chmod 666 /var/run/docker.sock
usermod -aG docker jenkins
# Jeknins 유저로 확인
su - jenkins
docker info
# Dockerhub로 로그인 하기
docker login
Username: <자신의 계정명>
Password: <자신의 암호>
# myweb:v2.0.0 컨테이너 이미지 생성을 위한 Dockerfile 준비
# 실습을 위한 디렉터리 생성 및 이동
mkdir -p ~/myweb2 && cd ~/myweb2
# Dockerfile 파일 생성
vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.0.0 NICK=<자신의 닉네임>
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apache2 figlet && \
echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
echo "<pre>" >> /var/www/html/index.html && \
figlet AEWS Study >> /var/www/html/index.html && \
echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]
vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.0.0 NICK=gasida
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apache2 figlet && \
echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
echo "<pre>" >> /var/www/html/index.html && \
figlet AEWS Study >> /var/www/html/index.html && \
echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]
# 모니터링
watch -d 'docker images; echo; docker ps'
-----------
# (참고) 이미지 빌드
docker build -t myweb:v2.0.0 -f /var/lib/jenkins/myweb2/Dockerfile
# (참고) 컨테이너 실행
docker run -d -p 80:80 --rm --name myweb myweb:v2.0.0
- item: docker-project, freestyle
- Build steps: Execute Shell
2. Harbor 설치
- harbor Route53 등록 (eip A record 등록 -> harbor.taskoo.net)
- docker-compose 설치
# Compose Plugin
sudo mkdir -p /usr/local/lib/docker/cli-plugins/
sudo curl -SL "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m)" -o /usr/local/lib/docker/cli-plugins/docker-compose
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
docker compose version
- harbor 설치
mkdir harbor
cd harbor
wget https://github.com/goharbor/harbor/releases/download/v1.9.4/harbor-online-installer-v1.9.4.tgz
tar xvfz harbor-online-installer-v1.9.4.tgz
cd harbor
vim harbor.yml
# 특정 설정을 변경해야 한다.
# hostname : 52.78.159.169
# https 인증서를 사용할 예정
###
https:
port: 443
certificate: /etc/docker/certs.d/harbor.taskoo.net/ncc.cert
private_key: /etc/docker/certs.d/harbor.taskoo.net/ncc.key
###
(koo@myeks:default) [root@myeks-bastion docker]# tree -h
├── [ 31] certs.d
│ └── [ 70] harbor.taskoo.net
│ ├── [1.2K] ca-git.crt
│ ├── [1.3K] ncc.cert
│ ├── [1.3K] ncc.crt
│ └── [1.6K] ncc.key
sudo ./install.sh
# 설치 이전에 https 인증서를 먼저 준비해야한다.
- 보안그룹 추가 후 docker 로그인
- 프로젝트 생성(koomzc)
- docker push 명령어 정상확인
(koo@myeks:default) [root@myeks-bastion certification]# docker push harbor.taskoo.net/koomzc/ubuntu:20.04
The push refers to repository [harbor.taskoo.net/koomzc/ubuntu]
5faf9c0a9efe: Pushed
20.04: digest: sha256:56cc2e49f02bdbe2dd6f8ae107d9c6a2a7f5435d8c8ed4a7c481593eccc8b70e size: 529
3. 젠킨스 구성 ( git, maven 빌드)
- 젠킨스 Pipeline 작성
- Harbor Credential 젠킨스에 생성
- harbor 계정 (admin/Harbor12345) - Username: admin 넣어줘야함 / ID는 젠킨스파일에서 호출시 사용할 변수명
- Git 사용
- MVN plugin 설치 & tools에서 Maven 특정 버전 선택 해서 변수화
바이너리 설치해서 환경변수 설정까지 os 단계에서 적용해도 되지만, 여러가지 메이븐 버전과 java 버전을 사용할수 있기 때문에
각 jenkinsfile과 Global Tools 설정파일에서 변수설정 해주는것이 재사용간에 용이하다.
또한 yum 설치시 3.0.5버전이 기본으로 설치되어서, 현재 spring 버전과 비교했을때 호환이 안되는 경우가 발생 가능.
- mvn 버전 설치 확인
(koo@myeks:default) [root@myeks-bastion mvnHome]# pwd
/var/lib/jenkins/tools/hudson.tasks.Maven_MavenInstallation/mvnHome
(koo@myeks:default) [root@myeks-bastion mvnHome]# ls
bin boot conf lib LICENSE NOTICE README.txt
(koo@myeks:default) [root@myeks-bastion bin]# ./mvn --version
Apache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-05T04:00:29+09:00)
- 젠킨스 파일은 이렇게 작성
node {
stage('========== Clone repository ==========') {
checkout scm
}
stage('Ready'){
sh "echo 'Ready to build'"
mvnHome = tool 'mvnHome'
}
// mvn 빌드로 jar파일을 생성하는 stage
// tools로 설치한 mvn 버전과 경로 확인 선행
stage('Build'){
sh "echo 'Build Spring Boot Jar'"
sh "pwd"
sh "cd demo && /var/lib/jenkins/tools/hudson.tasks.Maven_MavenInstallation/mvnHome/bin/mvn clean package"
}
4. 도커를 Jenkins에서 사용
- 필요 플러그인 설치 (Docker API / Docker / docker-build-step /Docker Pipeline )
- Dockerfile 만들기
FROM openjdk:11
CMD ["sudo","./mvnw", "clean", "package"]
ARG JAR_FILE=demo/target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
- 젠킨스 파일 추가(stage- 도커이미지 빌드, 도커 이미지 푸시)
node
{
stage('========== Clone repository ==========') {
checkout scm
}
stage('Ready'){
sh "echo 'Ready to build'"
mvnHome = tool 'mvnHome'
}
// mvn 빌드로 jar파일을 생성하는 stage
stage('Build'){
sh "echo 'Build Spring Boot Jar'"
sh "pwd"
sh "cd demo && /var/lib/jenkins/tools/hudson.tasks.Maven_MavenInstallation/mvnHome/bin/mvn clean package"
}
stage('========== Build image ==========') {
app = docker.build("koomzc/${env.IMAGE_NAME}")
}
stage('========== Push image ==========') {
docker.withRegistry('https://harbor.taskoo.net', 'Harbor') {
app.push("${env.BUILD_NUMBER}")
app.push("latest")
}
}
}
- 동작 완료
5. ArgoCD 설치 - 기본 테스트
- GitOps는 Git과 Operations의 합성어
- 쿠버네티스 상태를 git으로 관리하는 개념을 gitops 라고 합니다. 쿠버네티스에 배포하려고 하는 상태를 Git에 저장하면 ArgoCD가 git에 있는 내용을 쿠버네티스 배포합니다.
- Desired State로 유지한다는 관점에서 Declarative와 유사
- 최대 단점은 쿠버네티스에서만 ArgoCD를 사용할 수 있습니다. 쿠버네티스가 아닌 다른 환경에서는 사용하지 못합니다. 혼합환경을 사용하고 있는 곳이라면 Argo CD는 적절하지 않습니다. Jenkins, CircleCI등을 고려해야 합니다.
- Argo CD가 많은 사랑을 받는 것은 SSO, helm, kustomize 등과 호환성, 멀티 쿠버네티스 클러스터 관리, 사용자(또는 그룹)별 권한관리, WEB UI 제공
- argocd는 application이라는 단위로 배포할 리소스를 관리합니다. application은 쿠버네티스 CRD로서 argocd를 설치하면 자동으로 CRD가 생성됩니다.
- 설치 ( 헬름 통해서 설치 - 사전작업: CERT_ARN 및 ExternalDNS 필요 )
# 간단 설치
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# helm 설치
cat <<EOT > argocd-values.yaml
global:
domain: argocd.$MyDomain
configs:
params:
server.insecure: true
controller:
metrics:
enabled: true
serviceMonitor:
enabled: true
server:
ingress:
enabled: true
controller: aws
ingressClassName: alb
hostname: "argocd.$MyDomain"
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/ssl-redirect: '443'
aws:
serviceType: ClusterIP
backendProtocolVersion: GRPC
metrics:
enabled: true
serviceMonitor:
enabled: true
repoServer:
metrics:
enabled: true
serviceMonitor:
enabled: true
applicationSet:
metrics:
enabled: true
serviceMonitor:
enabled: true
notifications:
metrics:
enabled: true
serviceMonitor:
enabled: true
EOT
kubectl create ns argocd
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 6.7.11 -f argocd-values.yaml --namespace argocd
# 확인
kubectl get ingress,pod,svc -n argocd
kubectl get crd | grep argo
applications.argoproj.io 2024-04-14T08:12:16Z
applicationsets.argoproj.io 2024-04-14T08:12:17Z
appprojects.argoproj.io 2024-04-14T08:12:16Z
# 최초 접속 암호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
MC3y8rzzECTIAHSB
- Applications > NEW APP 생성 화면
- SOURCE
- Repository URL : https://github.com/gasida/aews-cicd.git
- Revision : main
- Path : 3/deploy
- DESTINATION
- Cluster URL : https://kubernetes.default.svc
- Namespace : first
- [선택] Directory ← 소스를 보고 자동으로 유형 선택됨
6. 통합테스트
ArgoCD가 모니터링 하고 있다가 Git의 태그가 변경되면 배포
- 배포하려고 하는 private Repo에 있는 이미지를 배포하려고 하면 ?
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-pod
image: harbor.taskoo.net/koo/1.0.0
- 다음과 같이 Error가 발생한다
- x509에러가 발생
- docker config.json 확인
- .docker 디렉토리에 docker login 할때 쓰이는 비밀번호가 저장되어있음
cd .docker
# .docker 디렉토리에 docker login 할때 쓰이는 비밀번호가 저장되어있음
(koo@myeks:default) [root@myeks-bastion .docker]# cat config.json
{
"auths": {
"harbor.taskoo.net": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
},
"https://index.docker.io/v1/": {
"auth": "a29vbXpjOm1lZ2F6b25lMDAhIQ=="
}
}
- 이와 같은 형태로 시큐릿으로 만들어야함 ( kubernetes.io 참고 )
- 쿠버네티스의 secret에 dockerconfig.json을 통해 x509 인증을 받는 방식 이외에도 운영 시 containerd config에서 insecure 형태로 https를 적용 안하고 사용하는 경우도 있다.
- 사실 쿠버네티스 워커노드의 접근과 권한 사용이 용이 한경우 ssl 인증서를 /etc/docker/certs.d 아래에 복사해 놓고 사용하는 것도 한가지 방법.
(koo@myeks:default) [root@myeks-bastion ~]# k describe secret regcred
Name: regcred
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/dockerconfigjson
Data
====
.dockerconfigjson: 167 bytes
(koo@myeks:default) [root@myeks-bastion ~]# kubectl get secret regcred --output=yaml
apiVersion: v1
data:
.dockerconfigjson: ewoJImF1dGhzIjogewoJCSJoYXJib3IudGFza29vLm5ldCI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0sCgkJImh0dHBzOi8vaW5kZXguZG9ja2VyLmlvL3YxLyI6IHsKCQkJImF1dGgiOiAiYTI5dmJYcGpPbTFsWjJGNmIyNWxNREFoSVE9PSIKCQl9Cgl9Cn0=
kind: Secret
metadata:
creationTimestamp: "2024-04-20T13:39:25Z"
name: regcred
namespace: default
resourceVersion: "2302635"
uid: 9fced9a7-132a-43f5-af01-53cca2cf351b
type: kubernetes.io/dockerconfigjson
(koo@myeks:default) [root@myeks-bastion ~]#
(koo@myeks:default) [root@myeks-bastion ~]# kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
{
"auths": {
"harbor.taskoo.net": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
},
"https://index.docker.io/v1/": {
"auth": "a29vbXpjOm1lZ2F6b25lMDAhIQ=="
}
}
}(koo@myeks:default) [root@myeks-bastion ~]#
(koo@myeks:default) [root@myeks-bastion ~]# echo "YWRtaW46SGFyYm9yMTIzNDU=" | base64 --decode
admin:Harbor12345(koo@myeks:default) [root@myeks-bastion ~]#
- 다음과 같이 pod도 imagepullsecrets 적용
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-pod
image: harbor.taskoo.net/koo/1.0.0
imagePullSecrets:
- name: regcred
- 이 방법보다는 최근에 https://hyperconnect.github.io/2022/02/21/no-more-image-pull-secrets.html 하이퍼 커넥트에서는 Kubelet Credential Provider을 사용한답니다.
- 하이퍼 커넥트에서는 Kubernetes 1.20부터 alpha feature로 추가된 Kubelet Credential Provider - KEP 2133를 소개하고 있습니다.
- 배포 완료
많은 회사들이 AWS의 서비스들을 편리하게 사용하고 있습니다만, 저희 회사에서는 온프레미스의 k8s 활용 방법과
다양한 클라우드에서의 컨테이너 서비스의 사용방안에 대해서 많은 고려를 하고 있습니다.
해당 블로그 포스팅은 S사의 AIML 쿠버네티스 환경 구축간 진행한 내용을 바탕으로 작성했습니다. 감사합니다.
'DevOps' 카테고리의 다른 글
[AWS EKS] EKS IaC with Terraform (2) (0) | 2024.04.23 |
---|---|
[AWS EKS] EKS IaC with Terraform (1) (0) | 2024.04.23 |
[AWS EKS] EKS Security (Kyverno) (0) | 2024.04.13 |
[AWS EKS] EKS Security (IRSA) (0) | 2024.04.11 |
[AWS EKS] EKS Security ( IAM Authenticator) (0) | 2024.04.08 |