목차
- 개요
- 도커 이미지 다운로드 실패
- 필요한 의존성 찾을 수 없음 에러
- 파일 생성 오류
- nginx의 cache 권한 오류
- 포트 바인딩 오류
개요
폐쇄망 서버에서 수동 CI로 수동 배포 하던 것을 GitLab CI를 이용해서 소스 코드 변경시 자동 CI가 되도록 작업 수행필요.
gitlab과 gitlab-runner가 이미 설치되어있음을 가정함.
GitLab CI를 적용하는 과정에서 발생한 오류와 이슈 정리.
초기 설정 파일(참고용)
//dockerfile
FROM node:20 as builder
# 컨테이너 내부 작업 디렉토리 설정
WORKDIR /app
# app dependencies
# 컨테이너 내부로 package.json 파일들을 복사
COPY package*.json ./
# package.json 및 package-lock.json 파일에 명시된 의존성 패키지들을 설치
RUN npm install
# 호스트 머신의 현재 디렉토리 파일들을 컨테이너 내부로 전부 복사
COPY . .
# npm build
RUN npm run build
# prod environment
FROM nginx:stable-alpine
# 이전 빌드 단계에서 빌드한 결과물을 /usr/share/nginx/html 으로 복사한다.
COPY --from=build /app/dist /usr/share/nginx/html
# 기본 nginx 설정 파일을 삭제한다. (custom 설정과 충돌 방지)
RUN rm /etc/nginx/conf.d/default.conf
# custom 설정파일을 컨테이너 내부로 복사한다.
COPY nginx/nginx.conf /etc/nginx/conf.d
# 컨테이너의 80번 포트를 열어준다.
EXPOSE 80
# nginx 서버를 실행하고 백그라운드로 동작하도록 한다.
CMD ["nginx", "-g", "daemon off;"]
//nginx/nginx.conf
server {
listen 80;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
# root를 /usr/share/nginx/html 을 바라보게 했으므로(Dockerfile 참고)
# 해당 경로 아래에 배포해주면 됨
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
//gitlab_ci.yml
stages:
- build
variables:
COMMIT_TAG: ${CI_COMMIT_TAG}
COMMIT_BRANCH: ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
IMAGE_TAG: latest
HARBOR_URL1: https://10.10.5.66:444
HARBOR_USERNAME1: [계정]
HARBOR_PASSWORD1: [비번]
HARBOR_PROJECT: nextti
HARBOR_REPOSITORY_URI: 10.10.5.66:444/${HARBOR_PROJECT}
HARBOR_REPOSITORY_NAME: mobile_framework_react
build: # This job runs in the build stage, which runs first.
image: node:20
stage: build
tags:
- mobile_framework_react
services:
- name: docker:dind
before_script:
- echo ${HARBOR_PASSWORD1} | docker login ${HARBOR_URL1} --username ${HARBOR_USERNAME1} --password-stdin
script:
- docker build -t ${HARBOR_REPOSITORY_NAME}:${IMAGE_TAG} .
- docker tag ${HARBOR_REPOSITORY_NAME}:${IMAGE_TAG} ${HARBOR_REPOSITORY_URI}/${HARBOR_REPOSITORY_NAME}:${IMAGE_TAG}
- docker push ${HARBOR_REPOSITORY_URI}/${HARBOR_REPOSITORY_NAME}:${IMAGE_TAG}
after_script:
- docker logout
도커 이미지 다운로드 실패
ERROR: Job failed: failed to pull image "node:20" with specified policies [always]: error pulling image configuration: download failed after attempts=6: x509: certificate signed by unknown authority (manager.go:237:17s)
dockerfile 작업 환경을 node:20으로 설정했는데 이미지 다운에 실패.

기존에는 도커 허브에서 받아왔었는데 보안으로 인해 폐쇄망이 되버리면서 도커 허브 접근 제한으로 인한 오류 발생으로 보임.
팀에서 사용하는 개인 이미지 저장소인 harbor에 node:20을 직접 저장후 pull받도록 함


ERROR: failed to authorize: failed to fetch oauth token: Post "https://10.10.5.66:444/service/token": tls: failed to verify certificate: x509: certificate signed by unknown authority
dockerfile에서 nginx를 받으려고 하니까 https 인증서 오류 발생.

spring boot배포시 발생했던 인증서 오류를 참고해서 https 인증서가 있는 호스트 리눅스 서버에 위임시키려고함.

그런데 이미 volumes에 설정을 해놨었고 자세히 보니 이미 harbor에 로그인이 된거보면 https 인증서 문제는 아닌것 같음.
이것 저것 찾아봤지만 정말 모르겠었는데, 어쩌다가 호스트 리눅스 서버에서 직접 오류가 발생하는 nginx이미지를 다운 받고 실행해봤는데 문제가 해결됨.
어떤 문제였고 왜 되는지 모르겠음.
결과
성공?
필요한 의존성 찾을 수 없음 에러
vite not found
npm build시 vite를 찾을 수 없다는 오류 발생.

시도 1) 빌드 실행 환경 설정
dockerfile에서 실행되는 RUN npm run build에서 별도 설정이 없다면 실행 환경은 default로 prod로 실행된다고 함.

pacakge.json의 설정을 보니까 devDependencies에만 vite가 적용되어있던데, 이런 경우 로컬 개발시에만 의존성에 추가되고 build시에 해당 의존성이 제외된다함. 실제 운영에 배포하는 것도 아니고 아직 개발단계에서 초기 배포 환경을 세팅하는 것이기 때문에 Dockerfile에 실행 환경을 dev로 변경하도록 추가 설정
ENV NODE_ENV=development
하지만 동일한 결과
시도 1. 결과
실패
시도 2) node 버전 변경
리액트 프로젝트 인수인계 해주신 분이 node버전 문제일 수도 있다고 node 22으로 버전 업그레이드를 권유.
node:22 버전을 사용해보니까 vite not found 오류는 발생하지 않음.
(vite 공홈에서는 node 20, 22 버전에서는 vite를 지원해준다고 했는데 왜 안되는지는 모르겠음)
시도 2. 결과
성공
의존성 다운 실패
계속해서 npm install에서 오류 발생.

폐쇄망이라 다운받지 못하는 의존성 다운이 정상적으로 이루어지지 않는것으로 예상함.
폐쇄망에서 의존성 패키지 사용하는 법을 사용.
error Can't make a request in offline mode ("https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz")
폐쇄망에서 의존성을 찾으려고 하는데 yarn install --offline 사용시 yarnrc 파일에 작성된 경로의 디렉터리에서 의존성을 다운 받는다.
.yarnrc.yml에 npm_pacakges를 미러링하도록 설정했는데 안되서 의아했었다.
하지만 --offline 옵션시 참고하는 .yarnc.yml이 yarn2 버전 때 인식하는 확장자이고 .yarnrc 파일이 yarn1 버전일때 읽는 차이가 있다고 한다.
내가 사용하는 yarn 버전을 확인해보니 1.22버전이었음.
결과
성공
빌드 중 파일 로드 오류
[vite:load-fallback] Could not load /src/utils/HeaderUtils (imported by src/pages/setting/HanaSetting.jsx): ENOENT: no such file or directory, open '/src/utils/HeaderUtils’
로컬에서 yarn build로 빌드파일 생성했을때는 정상적으로 동작을 했는데 gitlab ci에서 동일한 명령시 특정 파일을 로드 할수 없다는 오류 발생.

파일을 확인해보니 HeaderUtils를 import하고 있는데 실제 파일은 headerUtils였음.
잉? 로컬에서는 어떻게 오류가 안났지 싶었는데.. 리눅스는 대소문자를 구분하고 윈도우는 대소문자 구분을 못한다고 한다. 오류가 안났던 로컬 환경은 윈도우 os, 오류가 발생한 gitlab ci 환경은 리눅스였다.
결과
성공
nginx의 cache 권한 오류
react 프로젝트 이미지는 생성을 했고 배포 환경인 okd에 올렸는데 nginx관련해서 오류 발생.
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf is not a file or does not exist
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/10/29 15:43:42 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2025/10/29 15:43:42 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
nginx에서 cache를 사용하는데 docker가 관련 디렉터리에 대한 접근 권한 오류가 발생한 것으로 보인다.
//dockerfile에서 nginx 설정 부분
FROM 10.10.5.66:444/library/nginx:1.29
COPY --from=builder /app/dist /usr/share/nginx/html
#권한추가
RUN chmod -R 777 /var/cache/nginx && \
chmod -R 777 /var/log/nginx && \
chmod -R 777 /var/run
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
cache와 log등 nginx에서 주로 사용하는 디렉터리에 대해 권한 변경 명령어를 dockerfile에 추가해줌.
결과
성공
포트 바인딩 오류
okd에서 이미지 실행을 했을때 nginx에서 바인딩 관련된 오류 발생.
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf is not a file or does not exist
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/10/29 16:20:15 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2025/10/29 16:20:15 [emerg] 1#1: bind() to 0.0.0.0:80 failed (13: Permission denied)
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
gpt가 말하길 okd, kubernates 컨테이너에서 내부적으로 80번 포트를 쓰고 있을 수 있기 때문에 1024포트 이상을 사용하는 것이 권장되는 방법이라고 합니다.
nginx와 react의 포트를 변경 시켜줍니다.
먼저 dockerfile에서 컨테이너에서 nginx가 외부 통신할 포트를 80에서 21000으로 변경해줍니다.
//Dockerfile
# 컨테이너의 80번 포트를 열어준다.
EXPOSE 21000
그런 다음 nginx가 실제로 리스닝하는 포트를 21000으로 변경해줍니다.
//nginx.conf
server {
listen 21000; //80 > 21000으로 변경
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
# root를 /usr/share/nginx/html 을 바라보게 했으므로(Dockerfile 참고)
# 해당 경로 아래에 배포해주면 됨
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
이렇게 하면 외부에서 21000포트로 okd 컨테이너로 요청을 보내면 내부적으로 nginx은 21000포트로 요청을 받아 동작을 하게 됩니다.
결과
성공
참고
https://ko.vite.dev/guide/migration
Vite
Vite, 프런트엔드 개발의 새로운 기준
ko.vite.dev
리눅스는 대소문자 구분하고 윈도우는 대소문자 구분 못한다
결론 - 리눅스는 대소문자 구분하고 윈도우는 대소문자 구분 못한다 윈도우는 case sensitive가 없다, 하지만 리눅스는 case sensitive가 있다. 예를 들어 cd abcd란 명령이 있다고 할때, 윈도우 : cd abcd (O)
lemeraldl.tistory.com
https://velog.io/@_gyullbb/OKD-%EA%B0%9C%EC%9A%94
OKD 개요
Kubernetes 배포판 중의 하나인 OKD를 운영하는 입장에서 OKD에 대해 소개를 해보고자 해당 글을 작성한다.
velog.io
'develop > server' 카테고리의 다른 글
| [GitLab CI] Spring Boot 배포 과정 (삽질) (1) | 2025.11.11 |
|---|---|
| [npm] 폐쇄망 환경에서 배포시 의존성 문제 해결하기 (0) | 2025.11.10 |
| [ERROR] GitLab pipeline pending (Job is stuck. Check runners.) (0) | 2025.11.09 |
| [Docker] 폐쇄망 React + Nginx 도커 이미지로 배포 (1) | 2025.11.07 |
| [GitLab] GitLab Runner 등록 (0) | 2025.11.06 |