참 오랜만에 포스팅을 쓴다.
현재 진행하고 있는 프로젝트의 배포를 하면서 동시에 자동화를 하기위해
제목과 같은 프로세스를 진행했고, 동시에 오랜시간 삽질했기 때문에 이 과정들을 잊지 않기 위해서
이 포스팅을 적는다.
** 생략하는 것
EC2 인스턴스 생성과정, Next.js 프로젝트 생성과정
** 이 포스팅에서 보여드릴 것
workflow 설정, ec2에 도커 설치 및 구동, 트러블 슈팅
github action을 사용해서 자동하를 해줄 것입니다
직접 레포지토리에 .github/workflow/[workflow이름].yml 이런식으로 만들어주셔도 되지만,
action 탭에 들어가서 flow를 정하고 수정하면 굳이 폴더를 만드는 작업을 안하실 수 있습니다.
저는 노드를 선택해서 수정하였습니다.
스크립트는 이렇습니다.
name: seoulful-client
on:
push:
branches: ['main']
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Docker 빌드 설정
uses: docker/setup-buildx-action@v3
- name: Docker Hub Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Docker Build & Push check
run: |
docker build -t ${{ secrets.DOCKERHUB_REPO }}/seoulful-client:latest .
docker push ${{ secrets.DOCKERHUB_REPO }}/seoulful-client:latest
스크립트에 대한 설명을 해보겠습니다.
이 워크플로우는 main 브랜치에 푸시가 발생할 때마다 실행됩니다.
build라는 작업이 정의되어 있으며, 이 작업은 최신 Ubuntu 환경(ubuntu-latest)에서 실행됩니다.
build 작업 안에 여러 단계가 정의되어 있습니다. 각 단계는 차례로 실행됩니다.
Step 1: Checkout Repository
name: Checkout Repository
uses: actions/checkout@v3
이 단계에서는 actions/checkout 액션을 사용하여 현재 리포지토리를 체크아웃합니다. 이로써 워크플로우가 리포지토리의 코드를 사용할 수 있게 됩니다.
Step 2: Set up Node.js
name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
이 단계에서는 actions/setup-node 액션을 사용하여 Node.js 버전 20을 설정합니다. 이를 통해 Node.js 환경에서 필요한 명령어들을 실행할 수 있습니다.
Step 3: Docker 빌드 설정
name: Docker 빌드 설정
uses: docker/setup-buildx-action@v3
이 단계에서는 docker/setup-buildx-action 액션을 사용하여 Docker 빌드를 설정합니다. Buildx는 Docker의 확장 빌드 기능을 제공합니다.
Step 4: Docker Hub Login
name: Docker Hub Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
이 단계에서는 docker/login-action 액션을 사용하여 Docker Hub에 로그인합니다. 로그인에 필요한 사용자 이름과 비밀번호는 GitHub Secrets에 저장된 값을 사용합니다.
Step 5: Docker Build & Push check
name: Docker Build & Push check
run: |
bash
docker build -t ${{ secrets.DOCKERHUB_REPO }}/seoulful-client:latest .
docker push ${{ secrets.DOCKERHUB_REPO }}/seoulful-client:latest
이 단계에서는 Docker 명령어를 직접 실행하여 Docker 이미지를 빌드하고, Docker Hub에 푸시합니다. 이미지 태그는 latest로 설정되며, 리포지토리 이름은 GitHub Secrets에 저장된 값을 사용합니다.
위의 시나리오들이 main 브랜치에 push 되었을 때 반영됩니다.
저는 docker를 통해서 build, push만하고, run은 ec2에서 환경변수와 함께 사용합니다
아래 명령어를 ec2에 접속해서 사용합니다!
이렇게 하는 이유는 도커 이미지에 있는 환경변수가 노출될 수 있기 때문에 그런 것입니다.
환경변수를 ec2에 등록하는 방법도 알려드리겠습니다.
docker run -d -p 3000:3000 --name seoulful-client \
-e NEXT_PUBLIC_NAVER_MAP_CLIENT_ID= NEXT_PUBLIC_NAVER_MAP_CLIENT_ID= 5sxg3hx97b \
-e NEXT_PUBLIC_NAVER_MAP_CLIENT_SECRET=NEXT_PUBLIC_NAVER_MAP_CLIENT_SECRET \
-e NEXT_PUBLIC_KAKAO_REST_API=$NEXT_PUBLIC_KAKAO_REST_API \
-e NEXT_PUBLIC_SERVER_URL=NEXT_PUBLIC_SERVER_URL \
[본인 도커 유저이름]/[이미지 이름]
1. 우분투 시스템 패키지 업데이트
sudo apt-get update
2. 필요한 패키지 설치
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
3. Docker의 공식 GPG키를 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
4. Docker의 공식 apt 저장소를 추가
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
5. 시스템 패키지 업데이트
sudo apt-get update
6. Docker 설치
sudo apt-get install docker-ce docker-ce-cli containerd.io
7. Docker가 설치 확인
7-1 도커 실행상태 확인
sudo systemctl status docker
7-2 도커 실행
sudo docker run [이미지 이름]
도커 실행 파트에서는 위에서 말했듯이 env랑 같이 주입한다!
정정하자면 env라기보다는 환경변수를 넣는 것이다.
아주 간단하다!
echo "export NEXT_PUBLIC_NAVER_MAP_CLIENT_ID=clientkey" >> ~/.bashrc
echo "export NEXT_PUBLIC_NAVER_MAP_CLIENT_SECRET=secret" >> ~/.bashrc
echo "export NEXT_PUBLIC_KAKAO_REST_API=your_kakao_rest_api" >> ~/.bashrc
echo "export NEXT_PUBLIC_SERVER_URL=your_server_url" >> ~/.bashrc
위와 같이 .bashrc 또는 .profile 파일 등에 환경변수를 추가하고,
source ~/.bashrc
source 명령어를 입력해준다!
만약 내 인스턴스 내에서 어떤 환경변수가 쓰이고 있는지 궁금하다면 그냥
$ubuntu@your-ip : env
env를 입력해보세요! 그러면 환경변수가 쫘라락 나올겁니다
도커가 빌드할 때 필요한 dockerfile과, .dockerignore, 작성하고 뜯어봅시다!
FROM node:20.11.0-alpine AS base
# From {baseImage명}:{version}
RUN apk add --no-cache 'libc6-compat'
WORKDIR /app
COPY package.json package-lock.json ./
RUN rm -rf ./.next/cache
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
ENTRYPOINT [ "npm", "run", "start" ]
베이스 이미지 설정
FROM node:20.11.0-alpine AS base
node:20.11.0-alpine
이미지를 사용하여 경량화된 Node.js 환경을 설정합니다.
alpine 버전은 크기가 작고 필요한 패키지만 포함하는 Linux 배포판입니다.
필요한 패키지 설치
RUN apk add --no-cache 'libc6-compat'
libc6-compat
패키지를 설치합니다. 이 패키지는 glibc 호환 라이브러리를 제공하여 애플리케이션의 호환성을 높입니다.
--no-cache 옵션은 빌드 캐시를 사용하지 않고 패키지를 설치하여 이미지를 더 작게 만듭니다.
작업 디렉토리 설정
WORKDIR /app
디렉토리를 작업 디렉토리로 설정합니다. 이후 명령어들은 이 디렉토리에서 실행됩니다.
패키지 매니저 파일 복사
COPY package.json package-lock.json ./
package.json 및 package-lock.json
파일을 컨테이너의 /app 디렉토리로 복사합니다.
이 파일들은 프로젝트의 의존성 정보를 포함합니다.
빌드 캐시 삭제
RUN rm -rf ./.next/cache
Next.js의 빌드 캐시를 삭제합니다. 이는 빌드 과정에서 불필요한 캐시를 제거하여 빌드를 깨끗하게 시작하기 위해 사용됩니다.
의존성 설치와 빌드
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
ENTRYPOINT [ "npm", "run", "start" ]
npm install 명령어를 실행하여 package.json 파일에 명시된 모든 의존성을 설치합니다.
현재 디렉토리의 모든 파일을 컨테이너의 작업 디렉토리 (/app)로 복사합니다.
npm run build 명령어를 실행하여 프로젝트를 빌드합니다
이 포트는 애플리케이션이 실행될 포트입니다.
npm run start 명령어를 실행하여 product version을 실행합니다.
위의 작업들을 docker build 명령어가 입력되었을 때 읽으면서 실행됩니다.
.dockerignoe
이미지 빌드시에 특정 파일이나 디렉토리를 제거하기 위해서 사용됩니다.
이미지 크기를 줄여서 빌드 속도를 향상시키고 보안을 높일 수 있습니다.
이와 같이 루트 폴더에 만들어주시고
Dockerfile
node_modules
dist
.eslintrc.js
.gitignore
.prettierrc
.env.local
.vscode
.next
.git
README.md
저는 이렇게 사용하였습니다.
자 다 마무리 하였습니다. 이제 인스턴스에서 돌려볼까요???!!
짜잔!! 아주 잘 나옵니다!!
고생하셨습니다...!! (물론 나 자신도..)
이렇게 시간이 오래 걸리는 작업인줄 몰랐는데 재밌었으면서 동시에 너무 힘든 작업이었습니다...
다음 게시물은 아마 빌드나 코드들 최적화를 하면서 그 결과를 포스팅하지 않을까합니다..
감사합니다..!!!
+++ yml 파일과 , docker file 수정했습니다!
on:
push:
branches: ['main']
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install Dependencies
run: npm install
- name: Generate Environment Variables File for Production
run: |
echo "NAVER_MAP_CLIENT_ID=${{ secrets.NAVER_MAP_CLIENT_ID }}" >> .env
echo "NAVER_MAP_CLIENT_SECRET=${{ secrets.NAVER_MAP_CLIENT_SECRET }}" >> .env
echo "KAKAO_REST_API=${{ secrets.KAKAO_REST_API }}" >> .env
echo "NEXT_PUBLIC_SERVER_URL=${{ secrets.NEXT_PUBLIC_SERVER_URL }}" >> .env
- name: Docker 빌드 설정
uses: docker/setup-buildx-action@v3
- name: Docker Hub Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Docker Build & Push
run: |
docker build --build-arg NAVER_MAP_CLIENT_ID=${{ secrets.NAVER_MAP_CLIENT_ID }} \
--build-arg NAVER_MAP_CLIENT_SECRET=${{ secrets.NAVER_MAP_CLIENT_SECRET }} \
--build-arg KAKAO_REST_API=${{ secrets.KAKAO_REST_API }} \
--build-arg NEXT_PUBLIC_SERVER_URL=${{ secrets.NEXT_PUBLIC_SERVER_URL }} \
-t ${{ secrets.DOCKERHUB_REPO }}/seoulful-client:latest .
docker push ${{ secrets.DOCKERHUB_REPO }}/seoulful-client:latest
# 베이스 이미지 설정
FROM node:20.11.0-alpine AS base
RUN apk add --no-cache 'libc6-compat'
WORKDIR /app
COPY package.json package-lock.json ./
RUN rm -rf ./.next/cache
RUN npm install
# 빌드
COPY . .
ARG NAVER_MAP_CLIENT_ID
ARG NAVER_MAP_CLIENT_SECRET
ARG NEXT_PUBLIC_SERVER_URL
ARG KAKAO_REST_API
ENV NAVER_MAP_CLIENT_ID=$NAVER_MAP_CLIENT_ID
ENV NAVER_MAP_CLIENT_SECRET=$NAVER_MAP_CLIENT_SECRET
ENV NEXT_PUBLIC_SERVER_URL=$NEXT_PUBLIC_SERVER_URL
ENV KAKAO_REST_API=$KAKAO_REST_API
RUN npm run build
EXPOSE 3000
ENTRYPOINT ["npm", "run", "start"]
어떻게 해도 naver map 이라던지 환경변수가 전부 주입이 안되는 문제가 발생했다.
그래서 map, marker 둘 다 표시가 안되었다..
그래서 문제는 뭐였냐?
서버쪽에서 사용하는 변수는 NAVER_MAP_CLIENT_ID 즉 NEXT_PUBLIC 이라는 접두사를 제거하고
클라이언트 쪽에서 사용하는 변수는 NEXT_PUBLIC을 붙여줘야 한다는 것!!!!
docker exec -it <컨테이너 id> /bin/sh
명령을 입력해 env를 확인했는데도 불구하고 왜 안됐을까 찾아보니
이런 이슈들이 있었다...
다음부턴 이런 실수 없도록 하자!!