Next.js프로젝트를 Docker에 올리라는 미션을 받았다.

요들레이후·2023년 11월 11일
5

Devops

목록 보기
1/1
post-thumbnail

am I..? 제가 할 수 있을까요? Docker가 뭐죠? 이름만 들어봤는데..

리눅스 서버에 제 이름 이니셜로 디렉토리를 생성 후 해당 디렉토리 하위에 git 클론 받아서 도커 이미지를 빌드하고 8089:80로 서버를 띄우라는 미션을 받았었습니다.

당시 저는 프론트엔드 직무로 입사한 지 3주차였고, 도커는 만져본 적도 깔아본 적도 없었습니다.. 프로젝트를 할 때는 백엔드 개발자분들도 docker 사용했던 분들이 안계셨어서 기회가 없었죠..

리눅스 명령어도 익숙치 않은 저는 얼레벌레 vscode로 ssh 연결하고 도커 이미지를 빌드하는 과정을 서칭했고 결과적으로 도커 띄우는 것에 성공..! 했었습니다. 그 과정을 한 번 기록해보고자 합니다.. 총총

1. vscode Remote SSH 설치하기


vscode extension에 Remote - SSH라는 것이 있습니다. 요놈을 설치해줍니다.
이제 끝입니다. 거의 다했습니다.

2. SSH 연결하기


Remote - SSH를 설치하면 왼쪽 사이드바로 저 아이콘이 생깁니다. 저 아이콘을 누르면 사이드바가 열리는데, 제일 상단에 셀렉트를 원격(터널/SSH)로 설정해주시면 됩니다.

그리고 톱니바퀴를 누르면 업데이트 할 SSH 구성 파일 선택하는 부분이 나옵니다. ssh 구성 파일을 선택해주면 config파일 내에 접근할 수 있습니다. 이 중 맨 첫번째 Users/{유저명}/.ssh/config 를 눌러줍니다.

원격 탐색기에 이제 host 설정을 넣어주면 됩니다. 아마 다 전달해주실거라 생각합니다.
예시로 다음과 같이 작성하면 됩니다.

Host 0.0.0.0
  HostName 0.0.0.0
  User shy
  IdentityFile C:\Users\_pem\shy.pem
  Port 22
  • Host : 서버 호스트
  • User : 유저 이름
  • IdentityFile : 발급받은 pem키가 있는 파일 경로(파일명 포함)
    - 호스트에 접속하려면 암호화된 키가 필요합니다. 그게 바로 pem키라는 것!
  • Port : 포트 번호


호스트를 추가 누르면 해당 호스트로 연결이 됩니다. 새창 버튼 누르시면 vscode 새 창이 열리면서 ssh 접속이 완료됩니다!

3. Next.js Dokerfile 작성하기

도커 명령어를 작성해서 이제 컨테이너를 만들고 이미지를 빌드해야겠죠. 그런데 그 전에 중요한 게 있어요. 바로 Dockerfile을 프로젝트 최상단에 작성하는 것입니다. Dockerfile은 Image를 만드는 스크립트이고 그걸 우리 입맛대로 만드는 것이라고 생각하면 됩니다.

Dockerfile은 명령어가 Layer 형식으로 실행됩니다. 그래서 소스코드인 src ./가 수정될 경우 이후 레이어만 다시 빌드 후 나머지 Layer는 재사용할 수 있어 이미지 제작 시간 단축할 수 있다는 장점이 있습니다!

뭐 어떻게 작성해야할지 모른다고요? 여기 vercel/next.js/Dockerfile 예시가 있습니다. 저도 Dockerfile 작성법을 몰라 이것을 기준으로 정리해보고자 합니다.

1. Base Image 설정

FROM node:18-alpine AS base
# From {baseImage명}:{version}
  • node:18-alpine는 Docker가 사용할 기본 이미지를 설정합니다. 여기서는 Node.js 18 버전을 실행하는 Alpine Linux를 사용합니다.
  • Alpine은 linux 배포판으로 docker이미지의 크기를 최소화하는데 유용하다고 합니다.
  • As base는 이미지 레이어의 이름을 base로 별칭 지정합니다. 이 이름은 다음 스크립트들에서 참조할 때 사용합니다.

2. 의존성 설치

FROM base AS deps
RUN apk add --no-cache 'libc6-compat'
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN rm -rf ./.next/cache
  • 'libc6-compat'라이브러리를 설치 후 패키지 관리자에 따라 의존성을 설치해주는 명령어입니다.
    - 경량화를 위해 최소한의 라이브러리를 가지고 있다보니, process.dlopen을 수행하기 위해서는 추가 설치해야 한다고 합니다.
  • From base As deps는 새로운 빌드 스테이지를 시작하며, 이전에 정의한 base이미지를 기반으로 합니다.
  • Run apk add --no-cache libc6-compat는 Alpine 리눅스에서 특정 C 라이브러리(libc6-compat)를 설치합니다. 특정 Node.js 패키지가 시스템 레벨의 라이브러리에 의존할 때 필요할 수 있습니다.
    - Run: 새로운 레이어에서 명령어를 실행하고 새로운 이미지를 생성합니다. Run 명령을 실행할 때마다 레이어가 생성되고 캐시됩니다.
  • WORKDIR /app은 작업 디렉토리를 /app으로 설정합니다.
    - WORKDIR : 이제 명령어는 이 디렉토리를 기준으로 동작합니다. cd명령어와 동일합니다.
  • COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./는 프로젝트의 의존성 파일을 컨테이너 내 /app 디렉토리로 복사합니다.
  • 마지막 RUN 명령은 yarn, npm, pnpm 중 어떤 패키지 관리자를 사용하는지에 따라 의존성을 설치합니다.npm을 사용하면 RUN npm run dev처럼 작성하시면 됩니다.
  • cache에 저장된 것들을 1차적으로 삭제해서 이미지를 경량화 시켜줍니다.

3. 애플리케이션 빌드

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
  • FROM base AS builder는 빌드 스테이지를 시작합니다.
  • deps 스테이지에서 설치한 node_modules를 현재 스테이지로 복사합니다.
  • 현재 디렉토리의 모든 파일을 Docker 컨테이너의 /app 디렉토리로 복사합니다.
  • 애플리케이션을 빌드합니다.

4. 프로젝트 실행

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /usr/src/app

ENV NODE_ENV=production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# builder된 곳에서 만들어진 public을 해당 runner 이미지에 추가해주기 위함
COPY --from=builder /usr/src/app/public ./public
COPY --from=builder --chown=nextjs:nodejs /usr/src/app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /usr/src/app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]
  • FROM base AS runner는 최종 실행 스테이지를 정의합니다.
  • 이 단계에서는 빌드된 애플리케이션 파일만 복사하고, 필요한 환경변수를 설정하며, 애플리케이션을 실행합니다.
  • standalone 디렉토리의 파일을 사용하여 프로젝트를 실행하고 있습니다. Next.js는 node_modules의 선택 파일을 포함하여 프로덕션 배포에 필요한 파일만 복사하는 독립 실행형 폴더를 자동으로 생성할 수 있습니다. 이 자동복사를 활용하기 위해선 다음과 같이 next.config.js파일에 추가해주면 됩니다.
    - next.config.js에 다음과 같이 설정을 추가하면 standlone에 파일들이 생성됩니다.
    			module.exports = {
    			 output: 'standalone',
    			}
    		```
    - 이렇게 할 경우 next.js에서 자동으로 프로덕션 배포에 필요한 파일들만 추출해서 독립 실행 가능한 .next/standalone 폴더를 만들어줍니다. 그러면 **node_modules를 설치하지 않고도 자체적으로 배포**할 수 있습니다. 이때 **프로젝트를 실행할 수 있는 server.js파일을 만들어 주기 때문에 이걸로 프로젝트를 실행**하면 됩니다. 
    - public폴터와 같이 static폴더 하위에 있는 내용은 standalone에 포함되지 않으므로, 따로 가지고 와야 합니다.
  • 나머지는 사용자 설정, 포트 사용 및 환경변수 설정, 마지막 최종 실행 스크립트입니다.

이제 진짜 끝입니다. 이제 드디어 도커 이미지 생성할 수 있습니다.

4. 도커 이미지 생성하기

도커 명령어는 Dockerfile이 있는 곳에서 명령어를 쳐야 작동됩니다. 왜냐면 당연히 Docker가 빌드 과정에서 Dockerfile과 해당 디렉토리의 파일 및 폴더를 참조하기 때문입니다.

그리고 사수분께서 도커 명령어를 작성할 때는 계정을 관리자로 전환한 뒤에 실행해야한다고 하셨었습니다. 시스템 리소스를 직접적으로 접근하고 제어하기 위해서, 보안 문제로 인해, Docker Daemon과 통신하며 동작하기때문에, 권한 부족으로 인한 에러 방지 등의 이유가 있다고 합니다.

1. 권한 스위칭 리눅스 명령어

  • 관리자 계정 전환
sudo su -
  • 유저 계정 전환
su - shy

2. 도커 명령어

  • 이미지 빌드
docker build -t [image_name] [path_to_dockerfile]
docker build -t frontend .
- -`t` : tag옵션 의미, 이미지 별칭을 지정해줍니다.
  • dockerfile로 빌드한 이미지 실행
docker run --name [실행image명] -v $(pwd):[workdir] -p [입력포트]:[컨테이너내부포트] [컨테이너명]
docker run --name front         -v $(pwd):/home/app -p 8089:8089  front-container
  • 생성된 이미지 확인
docker images

여기까지 하면 도커 이미지를 빌드하고 실행한 것입니다.
하지만 host 안에 있는 코드의 경로와 docker 컨테이너 안에 있는 코드의 경로는 다르며, 코드를 수정한 것을 반영하려면 docker 이미지를 재빌드 해야합니다. 도커 안에서 vi 편집기로 수정하거나 이미지를 재빌드 하는 것 보다는 코드를 마운트 시켜 바로 수정사항이 반영되게 하는게 더 좋겠죠? 따라서 도커 볼륨을 사용해 도커 컨테이너에서 해당 파일에 접근해서 사용하는 방법으로 동기화 할 것 입니다.

  • 도커 볼륨
docker run -d **-v [리눅스 서버 안에 있는 코드의 경로]:[docker 컨테이너 안에 있는 코드의 경로]** -p [입력포트]:[컨테이너내부포트] [컨테이너 명]:[컨테이너 버전]
docker run -d -v /home/ubuntu/.docker/front-container/app:/var/www/html/app -p 8089:8089 front-container:v0.1

이렇게 하면 컨테이너 생성 시 도커 볼륨을 통해 host와 도커 컨테이너의 html 폴더를 동기화 할 수 있습니다.
- -d : 백그라운드모드로 실행
- -p : [호스트포트][컨테이너포트] 포트 연결
- -v : 로컬과 컨테이너 파일 연동

  • 도커 강제 종료(바로 꺼짐)
docker kill [컨테이너 id || 컨테이너 이름]
  • 도커 종료(작업 마무리 후 꺼짐)
docker stop [컨테이너 id || 컨테이너 이름]
  • 도커 이미지 삭제
docker rmi [이미지 id || 이미지 이름]
  • 도커 특정 요소 삭제
docker builder prune # 빌드 캐시 삭제
docker system prune  # 이밈지, 정지 중 컨테이너, 네트워크 다 지우고 싶을 때
  • 도커 시작
docker start [OPTIONS] CONTAINER [CONTAINER...]

일단 여기까지 제가 직접 써봤던 도커 명령어들입니다. 추후 여러개의 도커 컨테이너를 띄울 수 있는 도구인 도커 컴포즈라든지 사용해 볼 수 있을 기회가 있으면 좋을 것 같습니다. 후후
혹시나 틀린 부분이 있다면 언제든지 댓글로 올려주세요!

자료 출처
next.js Dockerfile
Next.js 도커 이미지를 만들어서 CI/CD를 통해 NCloud 배포(1)
docker 기본 명령어

profile
💩 잘㈛는건 ㅇr닌데, 포ブl㈛ズl 않을꺼○F. ㄴr는 별로 코딩을 잘㈛ズl는 않ズl口ざ, ㄱH발ㅈr를 포ブl㈛ズl 않을꺼○F. ュ 정도로 포ブl를 먼저 んı작ㅎŁ⊂ト면, ㅇr무것도 도전㈛ヱ 싶ズl 않을 꺼○F. 💩

0개의 댓글