본문 바로가기

DevOps

[AWS EKS] (22) EKS 스터디 8주차 ( jenkins + harbor+ agrocd - CICD )

 

CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.

Harbor Private Registry 사용 

 

왜 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

젠킨스 구성 ( 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 버전과 비교했을때 호환이 안되는 경우가 발생 가능.

 

(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)
  • 젠킨스 파일은 이렇게 작성

 

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 생성 화면 

6. 통합테스트

  ArgoCD가 모니터링 하고 있다가 Git의 태그가 변경되면 배포

 

JenkinsPipeline/test_koo.yaml at master · themapisto/JenkinsPipeline

Contribute to themapisto/JenkinsPipeline development by creating an account on GitHub.

github.com

  • 배포하려고 하는 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
 

ImagePullSecrets 없이 안전하게 Private Registry 사용하기!

ImagePullSecrets 없이 편리하고 안전하게 private registry를 사용 할 수 있도록 Kubelet Credential Provider 기능을 실험해보았습니다.

hyperconnect.github.io

  • 배포 완료