Docker

VueJs Docker를 이용해서 node 20.12.2 버전 빌드하기(with jenkins,ssh)

hwanguu 2024. 5. 7. 10:45

나는 node 16.12 버전을 사용중이다.

새로운 프로젝트에서는 node 20.12.2 버전이 필요해서 nvm으로 설치후 빌드를 하려 했다.

nvm use 20.12.2를 하는 순간!

node: /lib64/libm.so.6: version GLIBC_2.27' not found (required by node)
node: /lib64/libc.so.6: versionGLIBC_2.28' not found (required by node)
nvm is not compatible with the npm config "prefix" option: currently set to ""
Run nvm use --delete-prefix v20.12.2 to unset it.

두둥쓰!

 

GLIBC_2.27, 2.28을 찾을수 없다고 한다..

나는 Amazone Linux2를 사용중인데, Centos 7을 기반으로 만들어진 배포판이라고 한다.

위 에러에 대해서 확인해보니 Centos 7.X에서는 아래 방법을 통해서 GLIBC버전을 업그레이드 해야한다고 한다.

 

1. GLIBC 를 업그레이드 한다.

2. OS를 업그레이드 한다.

 

위 둘중에 하나를 택해야 했다.

1번같은 경우 구글링 해보니 GLIBC 변경은 OS자체에 심각한 문제가 발생할 수도 있으므로 주의해야 한다는 글을 많이 봐서 패쓰하기로 했다. 참고로 해당 서버는 모든 프로젝트의 빌드를 담당하는 젠킨스 서버이다(잘못해서 다른 프로젝트에 문제가 생기면 대참사가 발생한다..)

 

2번도 사실 OS를 업그레이드 한다는게 1번과 같은 맥락의 이유로 패쓰하기로 했다.

 

다른 방법이 뭐가 있을까 고민하다가 생각해낸것은 node 20.12.2버전이 설치된 Docker Image를 통해서 빌드를 하자 였다!

 

 

VueJs Docker를 이용해서 node 20.12.2 버전 빌드하기

DockerFile

FROM alpine:3.19

ENV NODE_VERSION 20.12.2


RUN addgroup -g 1000 node \
    && adduser -u 1000 -G node -s /bin/sh -D node \
    && apk add --no-cache \
        libstdc++ \
    && apk add --no-cache --virtual .build-deps \
        curl \
    && ARCH= OPENSSL_ARCH='linux*' && alpineArch="$(apk --print-arch)" \
      && case "${alpineArch##*-}" in \
        x86_64) ARCH='x64' CHECKSUM="61729a4b4adfefb48ed87034dbaff9129e1fd5b9396434708b0897217a6bf302" OPENSSL_ARCH=linux-x86_64;; \
        x86) OPENSSL_ARCH=linux-elf;; \
        aarch64) OPENSSL_ARCH=linux-aarch64;; \
        arm*) OPENSSL_ARCH=linux-armv4;; \
        ppc64le) OPENSSL_ARCH=linux-ppc64le;; \
        s390x) OPENSSL_ARCH=linux-s390x;; \
        *) ;; \
      esac \
  && if [ -n "${CHECKSUM}" ]; then \
    set -eu; \
    curl -fsSLO --compressed "https://unofficial-builds.nodejs.org/download/release/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz"; \
    echo "$CHECKSUM  node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" | sha256sum -c - \
      && tar -xJf "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
      && ln -s /usr/local/bin/node /usr/local/bin/nodejs; \
  else \
    echo "Building from source" \
    # backup build
    && apk add --no-cache --virtual .build-deps-full \
        binutils-gold \
        g++ \
        gcc \
        gnupg \
        libgcc \
        linux-headers \
        make \
        python3 \
    # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150
    && export GNUPGHOME="$(mktemp -d)" \
    # gpg keys listed at https://github.com/nodejs/node#release-keys
    && for key in \
      4ED778F539E3634C779C87C6D7062848A1AB005C \
      141F07595B7B3FFE74309A937405533BE57C7D57 \
      74F12602B6F1C4E913FAA37AD3A89613643B6201 \
      DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \
      61FC681DFB92A079F1685E77973F295594EC4689 \
      8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \
      C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
      890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \
      C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \
      108F52B48DB57BB0CC439B2997B01419BD92F80A \
      A363A499291CBBC940DD62E41F10027AF002F8B0 \
      CC68F5A3106FF448322E48ED27F5E38D5B0A215F \
    ; do \
      gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \
      gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \
    done \
    && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION.tar.xz" \
    && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
    && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
    && gpgconf --kill all \
    && rm -rf "$GNUPGHOME" \
    && grep " node-v$NODE_VERSION.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
    && tar -xf "node-v$NODE_VERSION.tar.xz" \
    && cd "node-v$NODE_VERSION" \
    && ./configure \
    && make -j$(getconf _NPROCESSORS_ONLN) V= \
    && make install \
    && apk del .build-deps-full \
    && cd .. \
    && rm -Rf "node-v$NODE_VERSION" \
    && rm "node-v$NODE_VERSION.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt; \
  fi \
  && rm -f "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" \
  # Remove unused OpenSSL headers to save ~34MB. See this NodeJS issue: https://github.com/nodejs/node/issues/46451
  && find /usr/local/include/node/openssl/archs -mindepth 1 -maxdepth 1 ! -name "$OPENSSL_ARCH" -exec rm -rf {} \; \
  && apk del .build-deps \
  # smoke tests
  && node --version \
  && npm --version

ENV YARN_VERSION 1.22.19

RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \
  # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150
  && export GNUPGHOME="$(mktemp -d)" \
  && for key in \
    6A010C5166006599AA17F08146C2130DFD2497F5 \
  ; do \
    gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \
    gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \
  done \
  && curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
  && curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz.asc" \
  && gpg --batch --verify yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \
  && gpgconf --kill all \
  && rm -rf "$GNUPGHOME" \
  && mkdir -p /opt \
  && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
  && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
  && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
  && rm yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \
  && apk del .build-deps-yarn \
  # smoke test
  && yarn --version \
  && rm -rf /tmp/*

WORKDIR /app

COPY ./start.sh .
RUN chmod 755 /app/start.sh

ENTRYPOINT ["/app/start.sh"]

 

위 도커 파일은 Docker Hub에서 node 20.12.2버전 Image Dockerfile을 참고 하였다. (아래 링크 참고)

https://github.com/nodejs/docker-node/blob/17bf0838eaf9d32ba6280599e51fac5269d0dfb4/20/bookworm/Dockerfile

 

docker-node/20/bookworm/Dockerfile at 17bf0838eaf9d32ba6280599e51fac5269d0dfb4 · nodejs/docker-node

Official Docker Image for Node.js :whale: :turtle: :rocket: - nodejs/docker-node

github.com

 

 

위 Dockerfile에서 내가 추가한것은 단 4줄이다.

 

WORKDIR /app

COPY ./start.sh .
RUN chmod 755 /app/start.sh

ENTRYPOINT ["/app/start.sh"]

하나씩 확인해보자

 

WORKDIR : 기본 작업 위치를 /app으로 변경하겠다는 의미이다. 아래 COPY, RUN도 모두 $ /app에서 이뤄지게 된다.

 

COPY ./start.sh . : 내 PC(호스트 PC)의 현재 디렉터리의 start.sh를 WORKDIR(/app)로 옮기겠다는 의미 이다.

주의!
반드시 start.sh가 현재 dockerfile 빌드 하는 위치에 있어야 할것!
ex). windows :
    Dockerfile 의 위치가 : C:\study\docker 인경우 docker build를 해당 위치에서 하게 될텐데 이때 C:\study\docker        위치에 start.sh가 존재해야 정상적으로 COPY명령이 성공된다. (없으면 실패함)
      mac :
    Dockerfile 의 위치가 : /home/user/docker 인경우 docker build를 해당 위치에서 하게 될텐데 이때
    /home/user/docker  위치에 start.sh가 존재해야 정상적으로 COPY명령이 성공된다. (없으면 실패함)
   

 

RUN chmod 755 /app/start.sh : 위에서 COPY 명령어로 start.sh 파일을 옮겼기 때문에 실행 권한을 줘야 한다. 그렇기 때문에 RUN 명령어를 사용하여 start.sh의 실행 권한을 부여한다.

 

ENTRYPOINT ["/app/start.sh"] : COPY 명령어로 내 PC 현재 디렉터리의 start.sh 파일을 /app 으로 옮겼고, RUN chmod 755 /app/start.sh를 통해서 실행 권한을 부여 했다. ENTRYPOINT를 사용하여 Docker를 run 하는 시점에 start.sh를 실행시킨다.

 

 

start.sh

#!/bin/sh
node --version
npm install
npm run build

 

start.sh는 간단하다.

일단 node의 버전을 출력하게 하였고.

npm install로 종속된 패키지를 설치한 후 빌드를 진행한다.

 

Dockerfile Build

자 이제 위의 Dockerfile을 가지고 빌드를 해보자!

docker build --no-cache -t node:20.18.2 .

 

위 명령어를 사용하였다.

--no-cache : 기존 캐시를 사용하지 않고 모두 새로 다운받아서 빌드하는 속성

-t : 태그 지정 속성 (버전을 명시하지 않는다면 latest가 된다).

 

 

위와 같이 생성되면 성공!!

 

 

Jenkin 설정 (SSH Publishers)

나는 SSH Publishers를 통해서 설정을 하겠다.

 

기본적인 Git 연동, 파라미터 설정 등은 스킵하겠다.

 

 

빌드 환경에서 Execute shell을 추가한다.

docker run -v /jenkins_root/workspace/new_project_front:/app --rm node:20.12.2

 

젠킨스를 통해서 빌드를 할 경우 위의 명령을 실행시켜준다.

여기서 중요 한 부분이 있다. 

 

docker run -v /jenkins_root/workspace/new_project_front:/app --rm node:20.12.2

 

위의 부분이 가장 중요하다.

-v 옵션의 경우 호스트PC:원격PC 간의 디렉터리를 공유할수 있게 해준다.

-v /jenkins_root/workspace/new_project_front:/app 의 경우 내 PC /jenkins_root/workspace/new_project_front 파일을 원격 PC(Docker)의 /app과 공유하여 사용할수 있도록 해준다.

--rm 옵션은 빌드가 끝나면 docker ps -a에 남지 않도록 종료시켜준다.

 

위의 사진과 같이 -v 옵션은 내가 Docker run 한 Docker PC와 내 PC의 디렉터리를 연결할 수있다. (공유 디렉터리)

내 PC 에서는 /jenkins_root/workspace/new_project_front 폴더 이고 Docker PC에서는 /app이다.

 

 

 

빌드 후 조치는 위와 같이 설정한다.

 

Source Files

dist/**

 

Docker에서 npm run build를 하게 되면 WORKDIR(/app)에 dist폴더가 생성이 될것이다(-v 옵션을 통해서 디렉터리를 공유 하였기 때문). 반드시 dist/** 로 해줘야 정상적으로 SSH를 통해서 전송이 된다.

그리고 Remote Directory를 설정하지 않으면 SSH로 파일 전송 하였을때 Target PC에 /home/user 에 파일이 옮겨진다.(user로 로그인 한경우)

 

 

Exec command

mv /new_project/source/front/dist /new_project/source/front/dist_back
mv /home/user/dist /new_project/source/front/dist
rm -rf /new_project/source/front/dist_back

 

SSH로 배포할 PC에서 실행시킬 명령어 이다.

1. mv 명령어를 통해서 기존의 dist 폴더를 dist_back으로 이름을 변경한다.

2. 젠킨스 서버에서 빌드가 완료되서 SSH로 dist 파일이 옮겨진 기본 위치 /home/user 에서 dist 파일을 옮긴다.

3. dist_back 파일을 삭제한다.

 

 

과정

간단하게 빌드 과정을 설명하겠다.

 

1. Jenkins Web Page에서 빌드 시작.

2. Jenkins 서버에서 빌드하려는 Git Branch Pull 진행

3. Docker run 을 통해서 node 20.12.2가 설치된 이미지를 통해서 빌드를 진행(start.sh)

4. 빌드 결과(dist 파일)은 -v 옵션을 통해서 디렉터리를 공유한 폴더에 생성

5. SSH를 통해서 dist파일을 Target PC에 전송

 

잘못되거나 궁금한점이 있다면 댓글로 남겨주시면 감사하겠습니다.