문제상황
저희 팀의 프론트엔드 배포 과정에는,
'깃허브액션에서 도커 이미지 빌드 > 도커허브에 push > ec2서버에서 해당 이미지를 Pull 받아서 도커 컨테이너를 생성'하는 단계가 있습니다.
그런데 도커 컨테이너를 생성하는 과정에서 스토리북 빌드를 실행할 때 문제가 있었어요.(아래 주석처리한 부분)FROM --platform=linux/arm64 node:18.16.1-alpine as builder WORKDIR /app # build COPY . /app RUN yarn build:prod #RUN yarn build:sb # nginx FROM nginx:latest RUN rm -rf /etc/nginx/conf.d COPY conf /etc/nginx COPY --from=builder /app/dist >/usr/share/nginx/html #COPY --from=builder /app/storybook-static /usr/share/nginx/html/storybook EXPOSE 3000 CMD ["nginx", "-g", "daemon off;"]
시도한 다른 방법
배포 자동화를 젠킨스에서 깃허브액션으로 마이그레이션하면서부터 이 과정이 잘 작동하지 않았는데 추측하기로는 깃허브 액션에서의 환경(amd64)과 도커 컨테이너 내부 환경(arm64)이 다르기 때문에 제대로 패키지가 설치되지 않아서 생기는 문제라고 생각했기 때문에...
도커 베이스 이미지를node:18.16.1-alpine
에서 두 환경 모두 지원하는node
로 바꿔보았으나 해결 되지 않았습니다.또 다른 문제
깃허브액션에서 바로 s3로 파일을 업로드하기 위해서는 aws key가 필요했지만 보안상의 이유로 사용할 수 없었습니다. 하지만 ec2에서 s3에 접근할 수 있는 IAM 권한이 있었기 때문에 아래와 같은 방법으로 다시 도전해보았어요!그래서
기존의 ec2서버에서 nginx를 통해 스토리북을 배포하는 방식 대신,
깃허브액션 ci환경에서 스토리북 빌드 파일을 ec2를 거쳐 s3에 전달해 s3 + CloudFront로 배포하는 방법을 시도해보게되었습니다.
이 게시글은 프로젝트에 적용하기 전 연습했던 내용을 정리한 글입니다.
EC2 인스턴스 생성하는 방법을 정리한 블로그를 참고하여 인스턴스를 생성해줍니다.
~/.ssh
경로에 키페어를 저장합니다.
ls *.pem
sudo mv chex-ec2-webserver-keypair.pem ~/.ssh
소유자만 읽기/쓰기할 수 있도록 권한을 설정합니다.
chmod 600 chex-ec2-webserver-keypair.pem
config 설정을 하지 않을 경우 아래와 같이 입력해야하는 번거로움이 있습니다.
ssh -i chex-ec2-webserver-keypair.pem ubuntu@<ec2_ip_public_dns>
vi config // config 파일을 엽니다.
i
(insert)→ 위 내용 입력 → esc
→ :wq
위와 같이 config파일 내용을 수정해줍니다.
ssh [HostName]
으로 실행할 수 있습니다.
인스턴스 아키텍처에 맞게 설치해주세요
(아래 명령어는 Linux ARM 기준입니다.)
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
$ unzip awscliv2.zip
$ sudo ./aws/install
$ aws --version
aws-cli/2.13.22 Python/3.11.5 Linux/5.19.0-1025-aws exe/aarch64.ubuntu.22 prompt/off
$ rm -f awscliv2.zip # 설치 되었으니 zip은 삭제합니다.
AWS - S3 버킷 생성 및 파일 업로드 하기글을 참고해 버킷을 생성합니다.
{
"Id": "Policy1696247568640",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1696246121541",
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::chex-bucket/*",
"Principal": "*"
}
]
}
위와 같이 버킷정책을 설정해주었습니다.
-> 이 부분은 CloudFront 배포 생성 시 바뀌는 부분이기 때문에 생략하셔도 됩니다.
역할 만들기 글을 참고해 역할을 생성해줍니다.
사용자 및 사용자그룹은 생성하지 않고 ec2-chex-role
이라는 역할만 생성 후 AmazonEC2FullAccess
, AmazonS3FullAccess
권한을 주었습니다.
EC2 인스턴스 선택 > 작업 > 보안 > IAM 역할 수정에서
위와 같이 ec2-chex-role
이라는 역할을 인스턴스에 연결합니다.
이제 터미널에서 $ aws s3 ls
명령어를 통해 버킷 목록을 확인할 수 있습니다.
$ mkdir actions-runner && cd actions-runner // 호스트 서버에서 디렉토리 생성
$ curl -o actions-runner-linux-arm64-2.309.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.309.0/actions-runner-linux-arm64-2.309.0.tar.gz // 가장 최신의 Runner 패키지 다운로드
$ tar xzf ./actions-runner-linux-arm64-2.309.0.tar.gz // 다운로드 받은 파일 압축해제
$ ./config.sh --url https://github.com/[저장소주소] --token [토큰값] // 저장소 연결
$ nohup ./run.sh // 등록한 Self-hosted Runner 활성화(세션이 종료되어도 실행이 유지되도록 함)
nohup(no hang up)
name: Storybook Deploy To S3
on:
push:
branches:
- hyeryongchoi
jobs:
build:
runs-on: ubuntu-22.04
defaults:
run:
working-directory: ./
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
steps:
- name: Use repository source
uses: actions/checkout@v3
- name: Use node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
- name: Cache Yarn global cache
uses: actions/cache@v3
with:
path: '**/.yarn'
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Cache Yarn project cache
uses: actions/cache@v3
with:
path: '**/.yarn/cache'
key: ${{ runner.os }}-yarn-project-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-project-
- name: Install dependencies
run: yarn install --immutable
- name: Build Storybook
run: yarn build-storybook
- name: Upload storybook build files to temp artifact
uses: actions/upload-artifact@v3
with:
name: Storybook
path: ./storybook-static
deploy:
needs: build
runs-on: [self-hosted, Linux, ARM64]
steps:
- name: Remove previous version app
working-directory: .
run: rm -rf frontend/storybook
- name: Download the built file to AWS EC2
uses: actions/download-artifact@v3
with:
name: Storybook
path: frontend/storybook
- name: Upload to S3
run: |
aws s3 sync frontend/storybook s3://chex-bucket/storybook --delete
#- name: Cloudfront invalidation # 클라우드 프론트 연결 후 주석 제거
# run: |
# aws cloudfront create-invalidation \
# --distribution-id ${{ secrets.AWS_DISTRIBUTION_ID }} \
# --paths "/storybook/*"
워크플로우 실행 후 S3 버킷으로 들어가보면 위와 같이 스토리북 빌드 파일들이 잘 들어가있는 것을 확인할 수 있습니다.
CloudFront 배포 생성 글을 참고하여 클라우드 프론트 배포를 생성합니다.
버킷 내의 storybook디렉토리 안에 index.html이 있기 때문에 원본 경로에 /storybook
을 추가합니다.
CloudFront 배포 ID(distribution id)를 GitHub Secrets에 등록해줍니다.
- name: Cloudfront invalidation
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.AWS_DISTRIBUTION_ID }} \
--paths "/storybook/*"
파일 업데이트 시 캐시 무효화를 해야 최신버전을 바라볼 수 있기 때문에 클라우드프론트 권한을 추가한 후 워크플로우 마지막 단계에 캐시 무효화를 추가해주었습니다.
EC2 생성 및 접속하기
S3+Cloudfront를 활용한 정적 웹 배포
AWS - S3 버킷 생성 및 파일 업로드 하기
AWS IAM 계정 생성
EC2에 GitHub Actions self-hosted runner를 띄우는 방법
GitHub Actions에 Self-hosted Runner 등록하기
t4g 인스턴스와 ARM 아키텍처
뱅크샐러드 Web chapter에서 GitHub Action 기반의 CI 속도를 개선한 방법
[AWS] Cloudfront 캐시 무효화
AWS S3로 이미지 배포하기