오늘은 개발자들의 생산성을 확 높여주는 마법, CI/CD에 대해 이야기해보려고 합니다. 매번 코드를 수정하고, 빌드하고, 서버에 접속해서 파일을 올리는 반복 작업에 지치셨나요? CI/CD는 이런 과정을 자동화해서 우리가 더 중요한 일에 집중할 수 있게 도와줍니다.

 

🤔 CI/CD, 도대체 뭔가요?

CI/CD는 두 가지 개념의 조합입니다.

 

CI (Continuous Integration, 지속적 통합):

  • 핵심: 개발자들이 각자 작업한 코드를 자주 중앙 저장소(GitLab의 main, stage, prod 브랜치 같은 곳)에 합치는(merge) 것입니다.
  • 자동화: 코드가 합쳐질 때마다 자동으로 빌드되고 테스트됩니다.
  • 장점: 코드 충돌이나 숨어있는 버그를 조기에 발견하고 수정할 수 있어, 전체 프로젝트의 안정성이 높아집니다. "어? 내 컴퓨터에선 잘 됐는데!" 같은 상황이 줄어들죠.
  • YAML 파일에서: build-job, prod-build-job 부분이 바로 CI 단계입니다. 코드가 특정 브랜치로 푸시(push)되면, GitLab이 알아서 Node.js 환경을 만들고(image: node:18-alpine3.21), 필요한 라이브러리를 설치(npm install)한 뒤, 프론트엔드 코드를 웹 브라우저가 이해할 수 있는 파일들(HTML, CSS, JS)로 변환(npm run build...)합니다.

 

CD (Continuous Delivery/Deployment, 지속적 제공/배포):

  • 핵심: CI 단계를 성공적으로 통과한 결과물(빌드된 파일)을 자동으로 실제 사용자가 접속하는 서버 환경까지 전달하는 과정입니다.
  • 종류:
    • 지속적 제공(Delivery): 운영 서버 배포 직전까지만 자동화하고, 실제 배포는 사람이 버튼을 눌러 승인하는 방식입니다. (안정성이 중요할 때!)
    • 지속적 배포(Deployment): 모든 과정이 자동으로 진행되어, 코드가 합쳐지고 테스트를 통과하면 즉시 운영 서버에 반영되는 방식입니다. (빠른 업데이트가 중요할 때!)
  • YAML 파일에서: deploy-job, prod-deploy-job 부분이 CD 단계입니다. CI에서 만들어진 build 폴더 안의 파일들을 AWS S3라는 저장소로 복사(aws s3 sync)해서 웹사이트를 업데이트합니다.
    • prod-build-job과 prod-deploy-job에 when: manual 보이시죠? 이건 "운영(prod) 환경 빌드와 배포는 자동으로 하지 말고, 사람이 GitLab 화면에서 직접 실행 버튼을 눌러줘!"라는 뜻입니다. 즉, 지속적 제공(Delivery) 방식을 사용하고 있는 거죠.
    • main(개발)이나 stage(테스트) 브랜치는 when: manual이 없으니, 코드 변경 시 자동으로 빌드되고 배포될 가능성이 높습니다 (설정에 따라 **지속적 배포(Deployment)**에 가깝게 운영).

 

🧐 잠깐, image: docker:latest는 뭐죠?

파일 상단과 deploy-job 등에서 image: docker:latest를 사용하는 것을 볼 수 있습니다. 이는 해당 CI/CD 작업을 수행할 때 기본적으로 도커(Docker) 명령어를 사용할 수 있는 환경을 사용하겠다는 의미입니다. deploy-job에서는 이 도커 환경 안에서 apk add 명령어로 AWS CLI 도구를 설치하고 S3 및 CloudFront 명령어를 실행합니다.

 

 

✨ 캐시 무효화(Invalidation), 왜 필요할까요? (feat. CloudFront)

deploy-job과 prod-deploy-job을 보면 aws cloudfront create-invalidation이라는 명령어가 있습니다. 이게 바로 '무효화' 부분인데요, 왜 필요할까요?

  1. S3 + CloudFront = 빠른 웹사이트: 이 프로젝트는 빌드된 웹사이트 파일(HTML, CSS, JS 등)을 AWS S3라는 파일 저장소에 저장합니다. 그리고 AWS CloudFront라는 CDN(콘텐츠 전송 네트워크) 서비스를 이용해 사용자에게 파일을 더 빠르게 전달합니다.
  2. CDN의 똑똑한 캐싱: CloudFront는 전 세계 여러 지역에 있는 서버(엣지 로케이션)에 우리 웹사이트 파일의 복사본을 미리 저장(캐싱)해 둡니다. 사용자가 접속하면 가장 가까운 서버에서 파일을 받으니 로딩 속도가 빨라지는 원리죠.
  3. 캐시의 함정: 그런데 문제가 있습니다! S3에 새 버전의 파일을 업로드(배포)해도, CloudFront 서버에는 아직 이전 버전의 파일이 캐시되어 있을 수 있습니다. 그러면 사용자는 분명 배포가 끝났는데도 옛날 화면을 보게 되는 거죠. 😱
  4. 무효화 마법 주문!: aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths "/*" 명령어는 CloudFront에게 "야, $DISTRIBUTION_ID 배포판에 캐시된 모든 파일(/*) 이제 유효하지 않아! 새로 가져가!" 라고 알려주는 역할을 합니다.
  5. 결과: 이 명령어를 실행하면, CloudFront는 캐시된 옛날 파일 대신 원본 저장소(S3)에서 최신 파일을 가져와 사용자에게 보여주고, 그 최신 파일을 다시 캐싱합니다. 덕분에 사용자는 배포 즉시 최신 웹사이트를 볼 수 있게 됩니다!
  6. "완료될 때까지 기다려!" 루프: while true; do ... done 부분은 CloudFront가 무효화 작업을 완료할 때까지 (상태가 Completed가 될 때까지) 10초마다 확인하는 코드입니다. 무효화는 즉시 끝나지 않기 때문에, 완료를 확인하고 파이프라인을 성공적으로 마무리하기 위한 장치입니다.


정리: 이 YAML 파일은 무슨 일을 하나요?

이 .gitlab-ci.yml 파일은 GitLab CI/CD를 통해 다음과 같은 멋진 자동화 흐름을 만듭니다.

  1. 개발/테스트/운영 브랜치(main, stage, prod)에 코드 변경이 감지되면:
    • (CI) 자동으로 해당 환경에 맞는 프론트엔드 코드를 빌드합니다. (단, prod는 수동 실행)
    • (CD) 빌드된 결과물을 각 환경의 AWS S3 버킷으로 업로드(배포)합니다. (단, prod는 수동 실행)
    • (CD - 무효화) AWS CloudFront 캐시를 무효화하여 사용자가 즉시 최신 버전을 볼 수 있도록 합니다.
  2. 안정성 확보: 운영(prod) 환경 배포는 수동으로 실행하도록 하여(Continuous Delivery), 실수로 잘못된 코드가 배포되는 것을 방지합니다.

이제 CI/CD가 어떻게 돌아가는지, 그리고 왜 캐시 무효화가 중요한지 감이 오시나요? 이 자동화 파이프라인 덕분에 개발팀은 코드 작성에 더 집중하고, 사용자는 더 빠르고 안정적으로 새로운 기능을 만날 수 있게 됩니다! ✨

'GitHub' 카테고리의 다른 글

프론트엔드 Github Flow 관리  (3) 2024.09.04
깃허브 다운 후 브랜치 생성 및 다운  (0) 2023.08.08

프론트엔드 Github Flow 관리

Github Branch 용도

  1. 각 branch별 용도 설명
    1. release : 상용 배포용 브랜치. 사용시 release_frontend_20240813 등으로 별도 branch로 구분하여 사용
    2. develop : 개발 배포용 (현재 개인의 OCI) 브랜치
    3. feature : 로컬 작업용. 즉 로컬에서 작업하기 위한 환경 위주로 구성되어 있어야 함. 개인의 로컬 작업시에는 feature_dashboard , feature_publishing 등으로 별도 branch로 구분하여 사용
    4. 기타 feature_xxx : 로컬 작업이 끝난 개인의 feature branch

Git Action 관련 용어 설명

  1. 내려받기 Action
    1. fetch : 대상 git의 모든 branch의 Log와 상태를 내려받습니다. Log와 상태만 내려받을 뿐 실제로 소스가 병합되지는 않으니 안심하셔도 됩니다.
    2. pull : 대상 git의 대상 branch를 설정하여 소스의 변경사항을 처리합니다. 충돌나는 파일이 없다면 smooth하게 변경사항이 로컬 소스에 적용됩니다.
  2. 저장 및 올리기 Action
    1. commit : 현재 Local 소스를 자신의 feature branch에 저장합니다. Git의 장점으로, SVN에서는 오로지 서버 commit만 되었습니다. 때문에 서버가 날아가면 소스의 복구가 불가능했는데 Git을 사용함으로서 로컬이 괜찮다면 소스의 복구가 가능해진 면이 있습니다. 이렇게 상황에 맞춰 유동적으로 소스를 관리할 수 있어 Git의 사용이 일반화되었습니다.
    2. push : 현재 저장된 feature branch의 소스를 Git서버쪽으로 올립니다. 같은 이름의 branch로 올릴수도 있고 변경할 수도 있습니다.
  3. 병합과 충돌 Action
    1. merge : 여러 branch에 따로 떨어져 있는 소스를 병합합니다. 보통 master가 되는 branch를 따로 두고 master에 각 feature의 변경 사항이 반영되는 것으로 처리를 합니다. 그러므로 관리자가 필요하며 보통 전담할 수 있는 한 명의 개발자가 관리하는 것이 일반적입니다.
    2. conflict : 소스를 병합하는 위 merge 과정이나 소스를 내려받는 pull 과정에서 같은 소스에 서로의 차이점이 동시에 병합 처리되면 충돌이 발생합니다. 이를 conflict라 하며 처리하기 위해서는 작업자 각자의 Log를 재확인해야 하고 어느 부분에서 충돌이 났는지, 그리고 최선의 처리 방법은 무엇인지가 고민되어야 합니다. 보통 위 merge에서 설명한 바와 같이 단일 관리자로 관리합니다.
    3. 즉 merge와 conflict는 휴먼 에러의 종류로서, 처리해본 경험이 충분해야 처리할 수 있는 사안들로 팀 내에서 관리에 대한 협의가 잘 되어야 합니다.

Github Flow (Merge, Pull, Push 등)

  1. 개인의 로컬 작업이 완료되어 feature (이하 origin )에 병합이 필요할 경우
    1. 로컬 작업을 자신의 feature에 commit
    2. origin 과의 충돌 방지를 위해 fetch, pull - origin 에서 개인 feature branch로 향하도록 설정하시고 fetch, pull 을 실행하면 됩니다.
    3. Already Update (이미 업데이트 되었음) 이 뜨면 충돌이 날 염려가 없는 것이므로, 자신의 feature명과 같은 github branch에 push
    4. origin 과의 Merge(병합) 수행 - 작업 담당자 : 박정환 (고정)
    5. 병합 완료 후 전체 메세지로 완료 안내 및 pull 요청
    6. origin 병합 버전과 Sync하기 : 위의 b 작업을 한번 더 수행 (origin 과의 충돌 방지를 위한 fetch, pull 하면 됩니다.
    7. 로컬 정상 반영, 작업 지속
  2. conflict (충돌) 발생할 경우
    1. 바로 호출해 주시기 바랍니다. 충돌 난 파일은 보통 revert처리를 하거나, 작업자 별로 확인해서 최신의 Log를 확인해 덮어쓰는 것으로 해결할 수 있으나 우선은 전후상황 대처를 위해 확인이 필요합니다.
  3. 기타 평상시
    1. 출근 후 항상 origin 에 대해 개인 feature branch에 fetch, pull 을 실행하시는 것을 권장합니다.

Fetch와 Pull을 왜 같이 사용해야 하는가?

  • Fetch, Pull을 항상 세트로 사용하시는걸 권장드립니다. 이유는 아래와 같습니다.
    1. Fetch를 먼저 수행하면 리모트 저장소의 최신 변경 사항을 로컬로 가져오지만, 로컬 작업 브랜치에는 바로 적용되지 않습니다. 이렇게 하면 변경 사항을 미리 확인하고 분석할 수 있습니다. (Log를 가져오는 것이라고 생각하시면 됩니다.)
    2. Fetch를 통해 최신 상태를 확인한 후, 문제가 없다고 판단되면 그때 Pull을 수행합니다. 이 방식은 예상치 못한 충돌을 최소화하며, 작업의 안정성을 높입니다.
    3. Fetch 없이 바로 Pull을 하면 리모트 변경 사항이 즉시 로컬에 적용되기 때문에, 예상치 못한 충돌이 발생할 수 있습니다. 이러한 충돌은 작업 흐름을 방해할 수 있으며, 예기치 않은 Merge Log가 생성될 가능성도 있습니다.

git branch dev -- 내 우분투에서 브랜치 생성

git pull origin dev -- 깃허브 클라우드 dev를 내 우분투 안의 dev로 복사해 옴

git branch nuri --  우분투에서 내 브랜치 생성

git checkout nuri -- 우분투 브랜치를 nuri로 변경

git pull origin dev -- nuri 브랜치에  깃허브 클라우드 dev를 복사해 옴

git push origin nuri -- nuri 브랜치를 깃허브 클라우드에 올림 (nuri 클라우드가 생성 됌)

 

다운 후에는 npm i 한 번 해서 라이브러리 다운받기 

 

 

[업데이트 된 코드 반영할 때 (git merge 할 때)]

 

git pull -- 우분투 안의 모든 클라우드 업데이트

git merge origin/dev -- 업데이트한 dev 클라우드를 내 브랜치에 합침 (nuri인지 확인하기)

 

+ Recent posts