일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Render Queue
- task queue
- Event Loop
- Headless 컴포넌트
- linux 배포판
- useEffect
- Compound Component
- type assertion
- JavaScript
- react
- 프로세스
- Custom Hook
- AJIT
- docker
- 암묵적 타입 변환
- Microtask Queue
- helm-chart
- useLayoutEffect
- CI/CD
- useCallback
- CS
- 타입 단언
- prettier-plugin-tailwindcss
- 주니어개발자
- useMemo
- React.memo
- 명시적 타입 변환
- TypeScript
- Sparkplug
- 좋은 PR
Archives
- Today
- Total
구리
Github Actions 관련 본문
회사에서 CI-CD 구축 업무을 위해 Github Actions에 대해 공부한 글로 React 기반 테스트용 프로젝트에 적용해보며 느낀 점을 작성했습니다. (Docker Image 파일 크기 : 18MB)
캐시 적용
Github Actions 캐시 사용
- repo별로 최대 10GB까지만 저장할 수 있고, 7일간 접근하지 않을 경우 삭제된다.
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
- 사용 action - https://github.com/docker/bake-action
- 다양한 플랫폼을 지원하는 이미지를 빌드할 수 있으며 기존 docker-compose.yml에 platform 설정(linux/amd64)을 했기에 사용했다.
- 해당 액션으로 다양한 Docker 이미지를 동시에 빌드할 수 있다.
- 깃헙 캐시 옵션 관련 - https://docs.docker.com/build/cache/backends/gha/
Github Actions 캐시 사용 결과
- 두번째 빌드 과정을 보면 코드 변경이 일어난 layer인 COPY . . 이전까지의 layer 생성에서는 캐시가 적용된 것을 확인할 수 있다.
첫 빌드 (캐시 적용 안된 상태) - 1m 13s
[stage-1 1/3] FROM docker.io/library/nginx:alpine@sha256:c04c18adc2a407740a397c8407c011fc6c90026a9b65cceddef7ae5484360158
#9 resolve docker.io/library/nginx:alpine@sha256:c04c18adc2a407740a397c8407c011fc6c90026a9b65cceddef7ae5484360158 0.0s done
#9 ...
#10 [internal] load build context
#10 transferring context: 735.56kB 0.0s done
#10 DONE 0.0s
#9 [stage-1 1/3] FROM docker.io/library/nginx:alpine@sha256:c04c18adc2a407740a397c8407c011fc6c90026a9b65cceddef7ae5484360158
#9 sha256:9da224fdd4124c20879a425f59ee3d7e9aeccf37356692f37cd7736e38c2efd2 1.40kB / 1.40kB 0.0s done
#9 sha256:41c49cbde6a69c2861d4443a90e47a59e906386088b706d32aba1091d0f262b0 1.21kB / 1.21kB 0.0s done
#9 sha256:532b9a30583c1bf82204f3cbc8054882bace1669cc85fdcb45b8f88b4db82833 393B / 393B 0.0s done
#9 sha256:35b039ba2bc54667ad0fdce04367ea93ed097b0506cda323e280e1ed31f29b31 13.19MB / 13.19MB 0.1s done
#9 sha256:62a896bb4a21c26afb24814d77cc345822fd8b03255bb9f940a0707daa9f2ff6 955B / 955B 0.1s done
#9 sha256:45f552c78c312f2b711135f5af71a2eb06e223246d13cae7bf3a15e447136045 629B / 629B 0.1s done
#9 sha256:7f5898476db744b7e3d5f25c7533b4285e21cf2025610f339cb32bf39bebcfe4 1.76MB / 1.76MB 0.1s done
#9 extracting sha256:7f5898476db744b7e3d5f25c7533b4285e21cf2025610f339cb32bf39bebcfe4
#9 extracting sha256:7f5898476db744b7e3d5f25c7533b4285e21cf2025610f339cb32bf39bebcfe4 0.2s done
#9 extracting sha256:45f552c78c312f2b711135f5af71a2eb06e223246d13cae7bf3a15e447136045
#9 extracting sha256:45f552c78c312f2b711135f5af71a2eb06e223246d13cae7bf3a15e447136045 done
#9 extracting sha256:62a896bb4a21c26afb24814d77cc345822fd8b03255bb9f940a0707daa9f2ff6 done
#9 extracting sha256:532b9a30583c1bf82204f3cbc8054882bace1669cc85fdcb45b8f88b4db82833 done
#9 extracting sha256:41c49cbde6a69c2861d4443a90e47a59e906386088b706d32aba1091d0f262b0 done
#9 extracting sha256:9da224fdd4124c20879a425f59ee3d7e9aeccf37356692f37cd7736e38c2efd2 done
#9 extracting sha256:35b039ba2bc54667ad0fdce04367ea93ed097b0506cda323e280e1ed31f29b31
#9 extracting sha256:35b039ba2bc54667ad0fdce04367ea93ed097b0506cda323e280e1ed31f29b31 0.7s done
#9 DONE 1.2s
#11 [react-build 1/6] FROM docker.io/library/node:18-alpine@sha256:17514b20acef0e79691285e7a59f3ae561f7a1702a9adc72a515aef23f326729
#11 resolve docker.io/library/node:18-alpine@sha256:17514b20acef0e79691285e7a59f3ae561f7a1702a9adc72a515aef23f326729 0.0s done
#11 sha256:62c7e5ec2b01a374e0ad0f2299c63d7940a5bdb466c580b243b9977dc12b8ecb 444B / 444B 0.0s done
#11 sha256:bc6e437c6fa911e43ef82fe79ec3cf94625557d8426639ee7758448b8a4fb464 1.38MB / 1.38MB 0.0s done
#11 sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 3.62MB / 3.62MB 0.1s done
#11 extracting sha256:c6a83fedfae6ed8a4f5f7cbb6a7b6f1c1ec3d86fea8cb9e5ba2e5e6673fde9f6 0.2s done
#11 sha256:1475bb19bdb76a034cba9b274ea9e4298897d6e108dbc81268740d70639f2b69 39.84MB / 39.84MB 0.3s done
#11 extracting sha256:1475bb19bdb76a034cba9b274ea9e4298897d6e108dbc81268740d70639f2b69
#11 ...
#12 [stage-1 2/3] COPY nginx.conf /etc/nginx/conf.d/default.conf
#12 DONE 0.6s
#11 [react-build 1/6] FROM docker.io/library/node:18-alpine@sha256:17514b20acef0e79691285e7a59f3ae561f7a1702a9adc72a515aef23f326729
#11 extracting sha256:1475bb19bdb76a034cba9b274ea9e4298897d6e108dbc81268740d70639f2b69 1.6s done
#11 extracting sha256:bc6e437c6fa911e43ef82fe79ec3cf94625557d8426639ee7758448b8a4fb464 0.0s done
#11 DONE 2.0s
#11 [react-build 1/6] FROM docker.io/library/node:18-alpine@sha256:17514b20acef0e79691285e7a59f3ae561f7a1702a9adc72a515aef23f326729
#11 extracting sha256:62c7e5ec2b01a374e0ad0f2299c63d7940a5bdb466c580b243b9977dc12b8ecb done
#11 DONE 2.0s
#13 [react-build 2/6] WORKDIR /app
#13 DONE 0.0s
#14 [react-build 3/6] COPY package*.json ./
#14 DONE 0.0s
#15 [react-build 4/6] RUN npm install
#15 7.414 npm warn deprecated w3c-hr-time@1.0.2: Use your platform's native performance.now() and performance.timeOrigin.
#15 DONE 21.6s
버전만 변경 후 build (캐시 생성된 상태) - 1m 1s
#10 [stage-1 1/3] FROM docker.io/library/nginx:alpine@sha256:c04c18adc2a407740a397c8407c011fc6c90026a9b65cceddef7ae5484360158
#10 resolve docker.io/library/nginx:alpine@sha256:c04c18adc2a407740a397c8407c011fc6c90026a9b65cceddef7ae5484360158 done
#10 DONE 0.0s
#11 importing cache manifest from gha:12972855224182164046
#11 DONE 0.6s
#8 [internal] load build context
#8 transferring context: 735.56kB 0.0s done
#8 DONE 0.0s
#12 [react-build 2/6] WORKDIR /app
#12 CACHED
#13 [react-build 3/6] COPY package*.json ./
#13 CACHED
#14 [react-build 4/6] RUN npm install
#14 CACHED
#14 [react-build 4/6] RUN npm install
#14 CACHED
#14 [react-build 4/6] RUN npm install
#14 sha256:16a24cffa87f8d63f3ffae1193a0f9a93015041fd4da993ecc42156747808189 0B / 98.52MB 0.2s
#14 sha256:9ce45f640f7831f89f81f3fc20f87cd8a91b6ad56bcf44a6d0ef6b5bd733b6d1 0B / 156.18kB 0.2s
#14 sha256:ff042a5863a401911d63533d1d29aa3cfc6230af13e43c2522b4a0013ed4e3bb 0B / 93B 0.2s
#14 sha256:62c7e5ec2b01a374e0ad0f2299c63d7940a5bdb466c580b243b9977dc12b8ecb 0B / 444B 0.2s
#14 sha256:ff042a5863a401911d63533d1d29aa3cfc6230af13e43c2522b4a0013ed4e3bb 93B / 93B 0.3s done
#14 sha256:62c7e5ec2b01a374e0ad0f2299c63d7940a5bdb466c580b243b9977dc12b8ecb 444B / 444B 0.3s done
#14 sha256:9ce45f640f7831f89f81f3fc20f87cd8a91b6ad56bcf44a6d0ef6b5bd733b6d1 156.18kB / 156.18kB 0.5s done
// 생략
#14 DONE 15.5s
#15 [react-build 5/6] COPY . .
#15 DONE 2.8s
#16 [react-build 6/6] RUN npm run build
#16 1.139
Github Actions 캐시 정리
- 테스트 프로젝트라 빌드 시간의 차이가 크지 않았지만 프로젝트 용량이 클수록 Github Actions 캐시 장점이 돋보일 것 같다.
- Github Actions 캐시를 사용해도 Docker 이미지 빌드 최적화를 진행하지 않으면 무용지물이므로… 최적화는 필수적인 것 같다.
- 자주 빌드하지 않거나 서비스가 크다면 Self hosted Runne에서 로컬 캐싱하는 방법도 좋을 것 같다.
Code Review
ChatGPT를 활용한 코드리뷰
- 만약 429 에러가 발생한다면 Open AI Billing 정보를 등록해야 한다.
- secrets.GITHUB_TOKEN 은 깃허브가 워크플로우 안에서 사용할 시크릿을 자동으로 생성하기에 별도로 repo secrets에 추가하지 않아도 된다.
- 입출력에 따른 1M 토큰마다 요금이 부과되는 방식이다 (https://openai.com/api/pricing/)
- 4bye가 평균 1토큰이다.
- 아래 결과를 보면 타이머를 구현한 간단한 코드 리뷰 진행시 $0.01 금액이 사용됨
코드리뷰 결과
리뷰 받은 코드 (타이머 구현 예시 코드)
더보기
리뷰 받은 코드 (타이머 구현 예시 코드)
import React, { useEffect, useState } from "react";
import styles from '../Auction/Timer.module.css';
export default function Timer() {
// 시간을 담을 변수
const [count, setCount] = useState(30);
useEffect(() => {
// 설정된 시간 간격마다 setInterval 콜백이 실행된다.
const id = setInterval(() => {
// 타이머 숫자가 하나씩 줄어들도록
setCount((count) => count - 1);
}, 1000);
// 0이 되면 카운트가 멈춤
if(count === 0) {
clearInterval(id);
}
return () => clearInterval(id);
// 카운트 변수가 바뀔때마다 useEffecct 실행
}, [count]);
return <div className={styles.timer}><span className={styles.count}>{count}</span></div>;
}
타이머 구현 코드에 대한 리뷰
더보기
코드 리뷰:
- useEffect 안에서 count 상태를 직접적으로 비교하여 0일 때 clearInterval을 호출하는 코드는 문제가 있습니다. count의 값이 변경될 때 해당 변화가 즉시 반영되지 않고, setCount가 비동기적으로 동작하기 때문입니다. 이로 인해 clearInterval 조건이 바로 반영되지 않을 수 있습니다.
개선 제안:
- setInterval 함수에서 현재 시간을 감소시킨 후, 결과가 0보다 작은지를 확인하여 clearInterval을 호출하도록 수정합니다.
- setCount((count) => count - 1) 대신에 setCount(count - 1)로 변경하여 불필요한 함수 호출을 줄입니다.
- 코드에 주석이 상대적으로 많이 사용되었으나, 설명보다는 코드 자체로 이해할 수 있도록 변수나 함수명 등을 더 명확한 이름으로 변경하는 것이 가독성을 높일 수 있습니다.
- 파일 끝에 \ No newline at end of file 메시지는 깃(Git)에서 생성된 diff 파일에 해당하는 내용이며, 실제 코드에 영향을 주지 않습니다.
- 모듈(css 파일)을 import 하는 부분과 컴포넌트 코드 사이에 한 줄 개행이 권장되며, 일관된 스타일에 따라 현재 코드와 다른 부분들을 고려해볼 수 있습니다.
개선 제안:
import React, { useEffect, useState } from "react";
import styles from '../Auction/Timer.module.css';
export default function Timer() {
const [count, setCount] = useState(30);
useEffect(() => {
const id = setInterval(() => {
setCount(count - 1);
}, 1000);
if (count <= 0) {
clearInterval(id);
}
return () => clearInterval(id);
}, [count]);
return (
<div className={styles.timer}>
<span className={styles.count}>{count}</span>
</div>
);
}
ChatGPT가 제안한 코드로 변경 후 코드 리뷰
더보기
이 코드는 기본적으로 정상적으로 작동할 수 있지만 몇 가지 개선점과 버그 가능성이 있습니다:
- 이벤트 처리 시 발생할 수 있는 문제: 현재 코드에서는 음수로 카운트가 내려갈 수 있습니다. 이에 대한 검증 또는 처리 방안이 필요할 수 있습니다.
- 시맨틱 요소 추가: <button> 태그에 aria-label을 추가하여 스크린 리더 사용자들에게 좀 더 이해하기 쉬운 정보를 제공할 수 있습니다.
- 코드 일관성 유지: 코드 가독성을 높이기 위해 변수나 함수명을 일관된 규칙에 따라 작성할 수 있습니다.
- 테스트 추가: 단위 테스트 또는 사용자 테스트를 추가하여 코드 변경에 대한 영향을 빠르게 파악할 수 있습니다.
- 상태 업데이트의 안정성 보장: useState에서 상태를 업데이트할 때 이전 상태를 기반으로 하는 경우, 함수형 업데이트를 사용하는 것이 좋습니다.
setCount(prevCount => prevCount + 1);
ChatGPT를 활용한 코드리뷰 정리
- 종종 ChatGPT를 이용해 코드 리뷰를 받아보곤 하는데 이보단 좀 더 디테일한 코드리뷰를 해주는 것 같다.
- 사소한 부분들도 짚어주며 버그 위험성과 그에 대한 개선점을 알려주기에 개인 프로젝트에 사용하면 좋을 것 같다.
- 코드리뷰가 완벽하진 않으며 삭제된 파일, 이름만 변경된 파일 전부 코드 리뷰가 진행되는 불필요한 작업이 발생한다.
- 무료가 아니기에 필요하다고 생각될때만 코드 리뷰를 받아보는 것도 좋을 것 같다.
'DevOps' 카테고리의 다른 글
[CI/CD] Github Actions을 통한 CI/CD 구축기 (0) | 2024.12.31 |
---|---|
[Github] 좋은 PR의 기준이 뭘까? (0) | 2023.12.29 |
[Docker] Docker Host OS와 Container OS가 다를 수 있는 이유 (0) | 2023.08.14 |