[24단계 실습으로 정복하는 쿠버네티스] 책으로 스터디를 진행하였다.
DevOps는 개발과 운영 사이에서 더 빠른 서비스를 제공할 수 있도록 하는 조직 문화, 개발 방법론이며,
GitOps는 DevOps에서 개발과 운영을 통합하여 애플리케이션 배포 및 관리를 자동화하기 위한 방법 중 하나라고 볼 수 있다.
이번 스터디에서는 GitOps에 대한 간단한 실습을 진행했다.
GitOps란?
GitOps는 Git을 중심으로 코드와 구성 요소를 관리하고, Git의 버전 관리 기능과 CI/CD 도구를 활용하여 배포를 자동화하는방법이다.
Weaveworks라는 업체에서 처음 언급되었다고 하는데, Weaveworks에서 설명하는 GitOps는 '클라우드 네이티브 어플리케이션 구축을 위한 운영 모델' 이다.
개인적으로 GitOps는 Infra를 코드 형태로 관리하고 자동으로 배포하는 방법이라고만 생각했으나,
Weaveworks에서는 아래와 같이 ' Kubernetes 및 기타 클라우드 네이티브 기술을 위한 운영 모델' 이라고 하며, Kubernetes 로 적용 대상을 한정하고 있었다.
GitOps can be summarized as these two things:
- It is an operating model for Kubernetes and other cloud-native technologies, that provides a set of best practices that bring together Git deployment, management, and monitoring for containerized clusters and applications.
- It offers a path towards a self-service developer experience for managing applications and automating CI/CD pipelines, unifying development and operations teams.
출처 : https://www.weave.works/technologies/gitops/
ChatGPT를 통해 확인해본 GitOps의 주요 원칙은 아래와 같았다.
1. Infrastructure as Code (IaC): 인프라를 코드화하여 버전 관리하고, 변경 사항을 추적하고, 코드 리뷰 및 테스트 등 소프트웨어 개발과 동일한 방식으로 관리합니다.
2. Declarative Configuration: 인프라 및 애플리케이션 구성을 선언적으로 정의하고, 변경 사항에 대해 자동으로 적용되도록 합니다.
3. Git as Single Source of Truth: Git 저장소가 모든 코드, 구성 요소 및 배포 상태의 단일 출처가 되도록 합니다.
4. Continuous Delivery: GitOps를 통해 지속적인 배포를 구현하고, 변경 사항이 Git 저장소에 푸시되면 자동으로 배포되도록 합니다.
5. Observability: 운영 환경에서 애플리케이션 및 인프라의 상태를 모니터링하고, 문제가 발생하면 빠르게 대응할 수 있도록 합니다.
6. Self-Healing: GitOps 시스템이 자동으로 문제를 감지하고, 자가 치유 (self-healing) 될 수 있도록 합니다.
이런 GitOps 모델은 크게 Push 기반과 Pull 기반 파이프라인으로 구분해서 구성할 수 있다고 한다.
Push 기반 파이프라인
코드 저장소 (GitLab, GitHub 등)의 변경이 발생할 경우 배포 파이프라인(Jenkins, CircleCI 등)을 동작시키는 방법이다.
코드화된 Kubernetes 환경 정보가 저장소에서 변경이 일어날 경우, Jenkins와 같은 CI/CD 도구를 통해 배포 파이프라인을 동작시켜 실제 환경에 반영한다. 이 경우 실제 환경과 코드화된 환경정보가 차이가 발생하는 상황이 자주 발생하는데 이를 감지할 수 있는 별도의 방안이 필요하다.
코드 상에서는 존재하지 않는 서비스였으나 실제 환경에는 서비스가 존재하는 경우 배포로 인해 이슈가 발생할 수 있다.
하지만 구조가 Pull 방식에 비해 간단하고, 배포 환경을 변경할 때 SSH 정보 등의 수정을 통해서 쉽게 추가/변경할 수 있다.
Pull 기반 파이프라인
코드 저장소 (GitLab, GitHub 등)의 변경이 발생할 경우 별도의 Operator(ArgoCD 등)가 해당 변경을 감지하고 배포 파이프라인을 수행하는 방법이다.
코드화된 Kubernetes 환경 정보가 저장소에서 변경이 일어날 경우, ArgoCD와 같은 Operator역할의 도구가 저장소를 주기적으로 모니터링하면서 변경이 감지되면 배포 파이프라인을 수행해 실제 환경에 반영한다. Operator가 코드 저장소와 실제 환경을 비교하면서 모니터링하기 때문에 환경정보의 차이를 자동으로 감지해주는 점이 굉장히 편리하다.
설정에 따라 배포 파이프라인을 자동으로 수행(Auto Sync)하기도 하고 별도의 승인 시스템을 추가해 승인 후 수행(Manual Sync)하는 방법을 구성할 수 있다.
스터디에서는 Pull 기반 파이프라인인 ArgoCD를 실습해봤기 때문에,
따로 정리하는 블로그에서는 Jenkins를 활용해서 Push기반 파이프라인을 구성해 테스트해보았다.
Push 기반 파이프라인 구성
이전 스터디에서 사용한 구성을 기반으로 GitOps 도구를 추가 배포하였다.
Harbor 구축
Harbor는 오픈소스인 컨테이너 이미지 저장소 및 관리 플랫폼으로,
AWS ECR을 써도 무방하나 스터디에서 사용한 Harbor를 이용해 로컬 이미지 저장소를 구축하였다.
Harbor 설치
// Harbor chart 저장소 추가 및 최신화
(ersia:default) [root@kops-ec2 ~]# helm repo add harbor https://helm.goharbor.io
"harbor" has been added to your repositories
(ersia:default) [root@kops-ec2 ~]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "harbor" chart repository
Update Complete. ⎈Happy Helming!⎈
// 추가 설정을 위해 로컬에 Harbor chart 다운로드
(ersia:default) [root@kops-ec2 ~]# helm fetch harbor/harbor --untar --version 1.11.0
(ersia:default) [root@kops-ec2 ~]# tree harbor -L 1
harbor
├── cert
├── Chart.yaml
├── conf
├── LICENSE
├── README.md
├── templates
└── values.yaml
// 아래의 내용을 수정
(ersia:default) [root@kops-ec2 ~]# vim harbor/values.yaml
---------------------------------------------------------
19 certSource: none ## auto/secret/none 옵션이 있으며, ingress controller에서 인증서를 설정하므로 none으로 수정)
36 core: core-harbor.ersia.net ## harbor core 서비스 ingress 규칙
37 notary: notary-harbor.ersia.net ## harbor notary 서비스 ingress 규칙
44 controller: alb ## gce/ncp(NSX-T Container Plugin)/alb/f5-bigip가 있으며 ingress controller 타입에 따라 설정
47 className: alb ## ingressClass 이름
48 annotations: ## 아래의 annotations 추가
49 alb.ingress.kubernetes.io/scheme: internet-facing
50 alb.ingress.kubernetes.io/target-type: ip
51 alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
52 alb.ingress.kubernetes.io/certificate-arn: 'ACM에서 생성한 인증서 ARN'
131 externalURL: https://core-harbor.ersia.net ## harbor 서비스에 대한 외부 도메인
---------------------------------------------------------
// harbor용 namespace 생성
(ersia:default) [root@kops-ec2 ~]# kubectl create ns harbor
namespace/harbor created
// 수정한 helm chart로 harbor 설치
k(ersia:default) [root@kops-ec2 ~]# helm install harbor harbor/harbor -f ~/harbor/values.yaml --namespace harbor --version 1.11.0
NAME: harbor
LAST DEPLOYED: Thu Mar 23 22:17:41 2023
NAMESPACE: harbor
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://core.harbor.ersia.net
For more details, please visit https://github.com/goharbor/harbor
// 설치 확인
(ersia:default) [root@kops-ec2 ~]# helm list -n harbor
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
harbor harbor 1 2023-03-23 22:17:41.479003234 +0900 KST deployed harbor-1.11.0 2.7.0
정상적으로 설치가 완료되면 Ingress Controller(ALB) 2개가 생성된 것을 확인할 수 있다.
각 ALB 규칙을 확인해보면 core 서비스용 ALB와 notary 서비스용 ALB가 각각 생성된 것을 확인할 수 있다.
Harbor 설치 후 웹페이지 접속
externalURL에 명시한 도메인으로 접속하면 로그인 가능한 웹페이지를 확인할 수 있다.
기본 사용자와 패스워드는 admin / Harbor12345 이며, 로그인 후 패스워드 변경이 가능하다.
// Harbor Helm Chart에서 설정한 기본 관리자 패스워드
(ersia:default) [root@kops-ec2 ~]# sed -n '386,387p' harbor/values.yaml
# The initial password of Harbor admin. Change it from portal after launching Harbor
harborAdminPassword: "Harbor12345"
Harbor 이미지 push 테스트
로그인한 웹페이지에서 New Project를 생성한다.
Project Name : 임의의 Harbor 프로젝트 이름을 입력한다. 해당 이름은 core 서비스의 URL Path로 활용된다.
Access Level
- Public으로 설정 시 별도의 docker login 없이 누구나 해당 저장소에서 이미지를 Pull할 수 있다.
- 테스트 시 docker login 없이 Push는 안되었는데, Harbor에서 생성한 권한이 있는 인증 사용자만 Push가 되었다.
- Private으로 설정 시 Pull도 권한이 있는 인증 사용자만 가능하다.
Storage Quota : Project에서 사용가능한 Disk 용량을 지정한다.
Proxy Cache : 생각보다 굉장히 좋은 기능인데, Harbor Project를 DockerHub의 Cache 서버로 사용하는 기능이다.
- DockerHub는 로그인 안한 익명 ip당 6시간에 100번, 로그인한 무료 계정 하나에 대해 6시간에 200번, 유료 구독 계정 하나당 하루에 5000번 제한이 존재한다.
- 생각없이 막 테스트하다보면 DockerHub에서 이미지 Pull이 제한되는데, Harbor의 Proxy Cache를 사용하면
DockerHub로부터 받아온 origin 이미지를 가지고 있다가 Pull 요청이 있을 경우 저장된 이미지를 제공한다.
1. DockerHub 이미지 변경없음 → Harbor에 저장된 이미지 제공
2. DockerHub 이미지가 바뀜 → Harbor에서 최신 이미지를 다운받아 제공
3. DockerHub origin에 연결안될 경우 → Harbor에 저장된 이미지 제공
4. DockerHub 이미지가 삭제됨 → Harbor에서 이미지 제공하지 않음
[참고] DockerHub Download rate limit : https://docs.docker.com/docker-hub/download-rate-limit/
[참고] 도커허브 이미지 풀 제약을 하버로 해결하기 : http://cwyang.github.io/2021/01/20/using-harbor-to-avoid-dockerhub-pull-ratelimit.html
아래의 과정을 따라 테스트용 이미지를 Push 하고 확인한다.
// dockerhub에서 busybox 이미지 가져오기
(ersia:default) [root@kops-ec2 ~]# docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
4b35f584bb4f: Pull complete
Digest: sha256:b5d6fe0712636ceb7430189de28819e195e8966372edfc2d9409d79402a0dc16
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest
// busybox 이미지에 tag를 달아 다른이름으로 저장
(ersia:default) [root@kops-ec2 ~]# docker tag busybox core-harbor.ersia.net/ersia-repo/busybox:0.1
(ersia:default) [root@kops-ec2 ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
core-harbor.ersia.net/ersia-repo/busybox 0.1 7cfbbec8963d 6 days ago 4.86MB
busybox latest 7cfbbec8963d 6 days ago 4.86MB
// docker login을 통해 구축한 harbor로 접근 가능하게 인증
(ersia:default) [root@kops-ec2 ~]# docker login core-harbor.ersia.net -u admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
// 구축한 harbor의 새로 생성한 Project에 이미지 Push
(ersia:default) [root@kops-ec2 ~]# docker push core-harbor.ersia.net/ersia-repo/busybox:0.1
The push refers to repository [core-harbor.ersia.net/ersia-repo/busybox]
baacf561cfff: Pushed
0.1: digest: sha256:acaddd9ed544f7baf3373064064a51250b14cfe3ec604d65765a53da5958e5f5 size: 528
[추가] Harbor의 컨테이너 이미지 취약점 진단
Harbor는 오픈소스 프로젝트인 Trivy와 Clair를 통해서 컨테이너 이미지 취약점 진단 기능을 제공한다.
- 참고 : https://goharbor.io/docs/2.0.0/administration/vulnerability-scanning/
Project에 저장된 이미지를 선택하면 Scan버튼이 활성화 되며, Vulnerabilities 컬럼에 취약점 결과를 제공한다.
테스트를 위해 nginx 이미지를 받아와 취약점을 진행해본다.
// DockerHub에서 nginx 이미지 가져오기
(ersia:default) [root@kops-ec2 ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
3f9582a2cbe7: Pull complete
9a8c6f286718: Pull complete
e81b85700bc2: Pull complete
73ae4d451120: Pull complete
6058e3569a68: Pull complete
3a1b8f201356: Pull complete
Digest: sha256:5bf62196c1ce39936ebdbce511127c57c06a944c51da2aef7fd27f4793cce239
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
// 가져온 nginx 이미지에 tag를 달아 다른이름으로 저장
(ersia:default) [root@kops-ec2 ~]# docker tag nginx core-harbor.ersia.net/ersia-repo/nginx:0.1
(ersia:default) [root@kops-ec2 ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 7cfbbec8963d 6 days ago 4.86MB
core-harbor.ersia.net/ersia-repo/nginx 0.1 904b8cb13b93 3 weeks ago 142MB
nginx latest 904b8cb13b93 3 weeks ago 142MB
// 구축한 Harbor에 로그인 인증 수행
(ersia:default) [root@kops-ec2 ~]# docker login core-harbor.ersia.net -u admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
// 이미지 Push
(ersia:default) [root@kops-ec2 ~]# docker push core-harbor.ersia.net/ersia-repo/nginx:0.1
The push refers to repository [core-harbor.ersia.net/ersia-repo/nginx]
101af4ba983b: Pushed
d8466e142d87: Pushed
83ba6d8ffb8c: Pushed
e161c82b34d2: Pushed
4dc5cd799a08: Pushed
650abce4b096: Pushed
0.1: digest: sha256:942ae2dfd73088b54d7151a3c3fd5af038a51c50029bfcfd21f1e650d9579967 size: 1570
Harbor Project에 이미지 저장 확인
이미지 Scan 수행 후 결과 확인
매번 수동으로 이미지 Scan을 수행하기 번거로우므로
이미지 Push 수행 시 취약점 검사를 자동으로 수행하는 설정을 활성화한다.
생성한 Project 클릭 -> Configuration -> Vulnerability scanning -> Automatically scan images on push 설정 체크
구축한 Harbor 삭제
Harbor 구축 시 values.yaml에서 persistentVolumeClaim 선언을 했기 때문에 PVC를 별도로 꼭 지워줘야 한다.
(ersia:default) [root@kops-ec2 ~]# helm uninstall -n harbor harbor
(ersia:default) [root@kops-ec2 ~]# kubectl delete pvc --all -n harbor
(ersia:default) [root@kops-ec2 ~]# kubectl delete ns harbor
참고자료
- Guide To GitOps : https://www.weave.works/technologies/gitops/
- What is GitOps? : https://www.gitops.tech/
- Architecture Overview of Harbor : https://github.com/goharbor/harbor/wiki/Architecture-Overview-of-Harbor
- 데브옵스의 확장 모델 – 깃옵스(GitOps) 이해하기 : https://s-core.co.kr/insight/view/데브옵스의-확장-모델-깃옵스gitops-이해하기-2/
- 도커허브 이미지 풀 제약을 하버로 해결하기 : http://cwyang.github.io/2021/01/20/using-harbor-to-avoid-dockerhub-pull-ratelimit.html