안녕하세요. 이 글은 프로젝트를 진행하면서 github action과 argocd 연계한 과정을 정리한 글입니다. 쿠버네티스 시스템에서 빠르게 빌드/배포 시스템을 구축하고 싶다면 github action과 argocd사용 해보시면 좋을 것 같습니다.
1. 나의 역할
저의 역할은 4가지 였습니다. 그 중 이 글에서는 CI/CD를 어떻게 구축했는지 설명하려고 합니다.
github주소: https://github.com/INFP-Study/CIAT
- 스프링 시큐리티를 이용한 인증/인가 로직 개발
- 클라우드 인프라
- CI/CD 파이프라인
- 개발과 서비스 운영에 필요한 에코시스템 구축
2. 요약
애플리케이션은 쿠버네티스로 동작하게 인프라를 구축했습니다. AWS를 개인 돈으로 구매해서 사용했고 미니쿠버네티스를 사용했습니다. 외부 접속은 쿠버네티스 ingress 또는 nodeport를 활용했습니다. ingress는 nginx ingress controller를 사용했습니다. 이 글에서는 자세히 설명하지 않지만 로그시스템을 위해 Loki와 메트릭 수집은 프로메테우스를 사용했습니다.
형상관리는 github으로 관리했습니다. dev, prd 환경을 구분하기 위해 브랜치를 이용했습니다. develop브랜치는 dev namespace에 master브랜치는 prd namespace에 배포됩니다.
CI/CD 파이프라인 github action, argocd를 이용했습니다. 코드 리뷰, merge를 제외한 모든 과정이 자동화로 진행됩니다. github action의 수행결과는 디스코드로 알림을 가도록 설정했습니다.
3. github action을 선택한 이유?
처음에는 jenkins를 사용했었는데 3가지 이유로 github action을 최종적으로 선택하게 되었습니다. 3가지 이유라고 표현했지만 무료로 사용할 수 있는게 가장 큰 장점이라고 생각합니다.
① EC2사양때문에 jenkins를 사용하지 않기로 했습니다. jenkins는 설치가 필요하므로 EC2자원 일부(1core, 2GB)사용해야만 했습니다. 저의 EC2는 4core 16GB이여서 jenkins에 꽤 많은 CPU자원이 할당되었습니다. 해결책을 찾다가 설치가 필요없고 무료로 사용할 수 있는 github action을 선택하게 되었습니다. github action은 repo가 무료로 공개되어 있으면 일부 제한된 기능으로 무제한 사용할 수 있습니다. private은 구독하지 않으면 시간제한이 있습니다.
경험상 프론트엔드(react js, webpack 등)가 정말 많은 리소스를 요구합니다. 저의 경험에서 가장 많이 사양이 요구되었던 프론트엔드 빌드는 8core 16GB였습니다. 개발자 또는 프론트엔드 데브옵스(프론트엔드만 다루는 데브옵스직무가 존재)가 빌드 최적화를 해주지 않으면 자연스럽게 높은 하드웨어 사양을 요구합니다. 이 프로젝트의 프론트엔드는 높은 사양을 요구하지 않지만, 나중에 다른 프로젝트에 적용할 때 jenkins보다 유리한 점을 가지고 갈 수 있을거라 생각합니다.
② 개발자와 관리자의 편의성 위해 github action이 더 좋다고 느꼈습니다. 여러 편의성이 있는데요!. 가장 손에 꼽는 편의성은 가시성입니다.
첫번째 가시성은 빌드과정입니다. jenkins 또한 빌드과정을 볼수 있지만 아무나 접근할 수 없도록 로그인, 네트워크 보안 설정이 별도로 필요합니다. 하지만, github action은 설정없이 쉽게 github repo페이지에서 확인할 수 있습니다.
빌드과정의 오류도 파이프라인 구축 지식이 없이 쉽게 확인할 수 있습니다. 아래 예제에서는 argocd배포 과정이 오류가 생겼네요.
빌드 로그는 아쉽게도 무료버전은 90일까지 유료버전은 400일까지 보관할 수 있습니다.
출처: https://docs.github.com/en/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization
두 번째 가시성은, github pull requests연동입니다. 이것도 역시 jenkins에서 가능하지만, 별도의 플러그인 설치와 버전 업데이트 관리가 필요합니다. 하지만, github action은 기본으로 설정되어 있습니다. 예를 들어, pull request 이벤트가 감지될 때 테스트코드를 돌린다면, 테스트 코드 결과가 pull requests에 자동으로 보이게됩니다. 리뷰어 입장에서는 merge를 할지 안할지 결정할 때 테스트 코드를 쉽게 참고할 수 있습니다.
pull requests목록에서도 github action결과가 보입니다. github자체가 지원하는 기능이다보니 jenkins보다 훨씬 편의성이 좋습니다.
③ 손쉬운 민감정보 관리입니다. ①과 관련성이 있는데요!. jenkins는 직접 설치하고 직접 서버설정 페이지에 들어가서 credentials에 민감정보를 등록합니다. 예를 들어서 docker 아이디와 비밀번호같은 것을요.
github은 settings페이지에 들어가서 입력만 하면 됩니다. 이것만 봐서는 jenkins와 다를게 없어보이는데요. settings에 들어가기 위한 인증/인가를 별도로 설정하지 않아도 됩니다. github이 알아서 해줘요!.
민감정보는 jenkins와 github action 모두 로그에서 비식별로 보입니다.
4. github action 빌드 상세과정
4.1 pull request 이벤트
pull request 이벤트가 발생하고 백엔드 소스코드 업데이트(미구현) 백엔드 테스트코드가 실행됩니다. 아직 테스트코드는 백엔드밖에 없어 github action이 백엔드 테스트코드만 실행했습니다. 백엔드와 프론트엔드 프로젝트가 같이 있어서 백엔드 소스코드 업데이트만 github action이 실행되게 설정할 예정이었습니다.
참고자료: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-including-paths
name: backend-dev-junittest
on:
pull_request:
branches:
- "develop"
# paths:
# - backend/**
백엔드는 스프링부트를 사용했고 테스트는 junit프레임워크를 사용했습니다. github action에서 junittest 결과를 예쁘게 보여주는 플러그인을 사용했습니다.
테스트를 위한 스프링프로파일은 github submodule을 이용했습니다. 이 내용은 submodule[4.3]에서 자세히 설명합니다.
4.2 merge 이벤트
리뷰어가 merge를 수락하면 프로젝트 빌드가 수행됩니다.
빌드는 총 3단계로 진행됩니다. 프로젝트 빌드, 도커 이미지 빌드와 push, argocd 메타정보 업데이트입니다. 프로젝트 빌드와 도커 이미지 빌드는 한 step에 진행됩니다. 백엔드는 gradle, 프론트엔드는 yarn(미구현) 프로젝트를 빌드합니다. 빌드된 결과물을 도커이미지로 생성하고 도커 registry에 push합니다.
도커 이미지 생성과정에서 핵심은 tag관리입니다. v1, v2식으로 숫자관리로 tag를 관리하고 싶었지만 많은 시간이 소요될 것 같아서 git commit ID를 사용하기로 했습니다. 적어도 git commitID로 도커 이미지에 해당하는 히스토리를 추적할 수 있다고 생각했습니다.
그 다음 핵심과정은 argocd 메타정보 업데이트입니다. argocd가 자동으로 쿠버네티스에 베포하기 위해서는 git에 저장되어 있는 pod image를 변경해줘야 합니다. 이 부분은 argocd챕터[5.1]에서 자세히 설명합니다.
4.3 소스코드 민감정보 암호화 처리
소스코드 민감정보(데이터베이스 접속정보 등)는 백엔드 빌드과정에 헤당합니다. 빌드과정에 필요한 민감정보는 github action secret을 이용했습니다. 하지만, 소스코드의 민간정보는 별도의 암호화가 필요했습니다.
처음에는 jasypt를 사용했습니다. 하지만, 테스트코드를 돌리기 위한 오버헤드가 심하여 암호화는 없애고 스프링프로파일을 업로드하지 않는 방향으로 변경했습니다. 스프링프로파일은 private repo로 별도로 관리하고 git submodule을 이용해서 빌드단계에서 가져왔습니다. github action에서 submodule가져오는 옵션도 제공합니다.
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ssh-key: ${{ secrets.PRIVATEREPO_SSHKEY }}
submodules: 'recursive'
암호화를 하지 않았기 때문에 도커 이미지를 다운로드 받아 까보면 민감정보를 볼 수 있습니다. 그러므로, 공개 docker registry를 사용하지 못했습니다. ECR을 사용하고 싶었지만 비용상 dockerhub private registry를 사용했습니다.
4.4 알림
github이 이력이 업데이트 되거나 github action이 끝나면 webhook을 사용해서 디스코드에 알림을 가도록 설정했습니다. 아쉬운 점은 디스코드 webhook의 반응속도가 느려서 심하면 하루 이상 알림이 도착할 때가 있습니다.
4. argocd를 선택한 이유?
많은 이유가 있지만 보안과 가시성때문에 argocd를 선택했습니다. github action의 단점은 사용자에게 쿠버네티스 권한을 주게 되면 마음먹은 대로 쿠버네티스를 이용할 수 있습니다. 제한된 계정권한을 주면 쿠버네티스 배포(kubectl apply 등)가 불가하므로 별도의 솔루션을 써야하는 상황이었습니다.
솔루션 중에 argocd 저의 의도에 적합했습니다. 마치 객제지향 캡슐화처럼 사용자는 쿠버네티스 접속정보를 모르지만 merge만 하면 쿠버네티스에 자동으로 배포되는 시나리오에 argocd가 적합했습니다. 관리자인 제가 argocd에 수동으로 한번 등록해주면 개발자는 merge만 신경쓰면되죠.
그리고 argocd는 가시성이 매우 좋아서 쿠버네티스 지식 없어도 어디 과정에서 장애가 나는지 확인할 수 있습니다.
5. argocd 배포 상세과정
5.1 argocd를 위한 git branch
argocd는 charts라는 별도의 브랜치를 바라봅니다. charts의 내용이 업데이트 되면 argocd는 자동으로 쿠버네티스 리소스를 업데이트 합니다.
argocd와 github action 연동의 가장 큰 어려운 점은 새로운 도커 이미지가 push되면, argocd가 바라보는 git에 내용을 업데이트 할까였습니다. argocd는 git의 내용이 업데이트가 되야 쿠버네티스 배포를 시작합니다. 저의 의도는 도커 이미지가 push되면이여서 argocd전용 브랜치를 하나 생성했습니다.
챕터 [4.2]에서 설명한 것처럼 github action이 프로젝트 빌드, 도커 빌드와 push가 끝나면 argocd가 바라보는 브랜치 내용을 수정합니다. 단순히, pod의 도커 이미지 태그를 수정했습니다. docker commit에서 github action이 수정했다는 것을 표현하기 위해 config정보도 알맞게 수정했습니다.
steps:
- uses: actions/checkout@v2
with:
ref: "charts"
ssh-key: ${{ secrets.GITHUBACTION_KEY }}
submodules: 'recursive'
- name: change values-dev.yaml
run: |
cat <<EOF > values-dev.yaml
image:
tag: ${{ env.dockerimage_tag }}
EOF
- name: git push
run: |
git config --global user.email "GitHub Actions Bot@github.com"
git config --global user.name "GitHub Actions Bot"
git add values-dev.yaml
git commit -m "change dockertag"
git pull origin charts
git push origin charts
5.2 argocd private docker registry연동
챕터 [4.3]에서 언급한것처럼 private docker registry를 사용했기 때문에 argocd에 설정이 필요했습니다. 선택지는 2가지가 있었습니다. argocd 플러그인인 image updater를 사용 또는 쿠버네티스 imagePullSecret이용입니다. image update를 공부하는데 시간이 소요될것이라 생각하여 빨리 적용할 수 있는 imagePullSecret방법을 사용했습니다.
imagePullSecrets:
- name: regcred
5.3 github 프로젝트 생성과 권한 설정
개발자를 위한 읽기전용 argocd계정 생성이 필요했습니다. 공식문서(https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/#tying-it-all-together)를 참고하면서 계정 권한설정은 성공했습니다. 하지만, 계정 생성과 비밀번호 설정은 별도로 쉘로 해야되서 불편함이 있었습니다. 저는 argocd를 helm으로 설치했기 때문에 권한 관리도 helm으로 설정했습니다.
config:
accounts.guest: login
rbacConfig:
policy.default: role:readonly
policy.csv: |
p, role:guest, applications, get, ciat/*, allow
p, role:guest, repositories, get, *, allow
p, role:guest, projects, get, ciat/*, allow
g, guest, role:guest
5.4 argocd application등록
application 등록은 수동으로 웹 대시보드에서 진행했습니다.
6. 기타
스프링시큐리티를 이용한 인증/인가 백엔드 개발로도 참여했습니다. 주 언어가 자바도 아니고 업무로서 스프링부트를 사용해본적이 없어서 힘들었습니다. 하지만, 대표적인 인증, 인가 프레임워크를 공부하면서 어떻게 프로세스가 진행되는지 알게된 시간이었습니다. 시간이 될 때 블로그와 유투브(https://youtu.be/ewslpCROKXY)로 남기기도 했습니다
7. 마치며
7.1 AWS를 개인 돈으로 사용하면서 느낀점
저는 클라우드를 업무로서 다룬적이 약 한달이 안됩니다. 그 경험도 서비스 설계와 개발 담당이어서 인프라 경험이 거의 전무합니다. 업무로 다루지 않았더라도 데브옵스 엔지니어로서 나중에 부딪힐 경험이라 생각했습니다. 그래서, 큰 맘먹고 EC2 예약 인스턴스 를 약 130만원 주고 결재했습니다. 이 글을 쓰고 있는 오늘 요금이 도착했네요.
직접 돈을 주고 사용해보니 기술적인 것보다는 요금쪽에 시야가 확대되었습니다. 바보같이.. 처음에는 단순히 EC2만 사면 모든 돈 계산이 끝날 줄 알았습니다. 하지만... EC2를 사용하면서 생각하지도 못한 기타 요금이 너무 많이 나왔습니다. 네트워크 트래픽 비용, 저장장치 용량, ELB(Elastic Load Balancer)요금이 가장 눈에 띄었습니다. ELB는 서버에 직접 nginx를 설치해서 대체할 수 있다고 판단되어 중간에 사용중지 했습니다. 요금에 대한 느낀 사항은 유투브(https://youtu.be/Ff2Grehc7aI)에 짧게 올리기도 했었습니다.
제일 기억에 남는 요금계산은 EBS볼륨이었습니다. 매일 EBS요금이 늘어나고 원인을 못찾아서 페이스북 "AWS한국사용자모임"에도 질문을 하여 해결했습니다. EBS볼륨은 언제나 타입을 변경할 수 있고 용량도 변경할 수 있어서 핸드폰 요금처럼 일일사용량에 대해 계산이 됩니다!.
7.2 도구를 다루면서 느낀점
① github action이 너무 좋아져서 소규모 프로젝트에 사용하기에 너무 좋을 것 같다는 인상을 많이 받았습니다. 하지만, 대규모에서 사용하기에는 중앙집중 관리가 안되어 보완할 시스템이 필요하다고 느꼈습니다.
② argocd가 점점 발전하는게 보였습니다. 이 프로젝트에 사용한 argocd는 컨테이너 로그 뷰어와 다운로드기능이 추가되었습니다.
7.3 앞으로 공부할 방향
① argocd는 새로운 이미지를 배포는 쉽지만 rollback을 어떻게 해야할지 아직 감이 안옵니다. rollback을 하는 순간 git과 미스매칭이 생기는데 이 부분을 조금 더 살펴봐야겠습니다.
② argocd에서 image regiry를 쉽게 관리하기 위한 image updater 플러그인이 있습니다. 아직 사용해보지 않았는데 효율적으로 image registry를 관리하기 위해 필요해보였습니다.
③ SSO 솔루션 지금가지 별도로 공부하지 않았는데, 여러 솔루션을 공통된 계정으로 관리 필요성을 느꼈습니다. argocd도 sso연동을 지원하니 공부해야할 과제로 남았습니다.
④ 소스코드 보안을 어떻게 쿠버네티스와 엮을지 고민이 많이 됩니다. Valut를 사용해보지 않았는데 해결될지 내심 기대해봅니다. 또한, CKS를 공부하면서 새로 알게된 trivy 적용도 생각해봐야겠습니다.
⑤ 이 글에서는 크게 언급하지 않았지만 loki, prometheus를 어떻게 시스템과 연동을 잘할지 생각해봐야겠습니다.
⑥ 역시나 제일 아쉬운점은 프로젝트 공부했던 내용을 업무에 사용하지 못하는 점입니다 ㅜ.ㅜ
'연재 시리즈' 카테고리의 다른 글
쿠버네티스 네트워크 스터디 4주차 - service와 kube-proxy iptables모드 (0) | 2022.02.07 |
---|---|
쿠버네티스 네트워크 스터디 3주차 2편: Calico 모드 (0) | 2022.02.05 |
쿠버네티스 네트워크 스터디 3주차 1편: Calico 기본 통신 과정 (0) | 2022.01.24 |
쿠버네티스 네트워크 스터디 2주차 2편: pause컨테이너 (0) | 2022.01.19 |
쿠버네티스 네트워크 스터디 2주차 1편: Flannel CNI (2) | 2022.01.17 |