회사에서 도커로 이미지를 빌드하고 그 이미지를 도커허브에 올린 후 누구나(권한을 부여할시) 도커허브에 올린 이미지를 통해
k8s 에서 실행시킬 수 있도록 작업하기를 원해서 관련 내용 공부를 하며 작업을 진행했었다.
처음엔 막막하고 어려웠는데 공부도 하고 찾아가면서 작업을 진행하다보니 예상치 못하게 재밌었고 나중에 많은 도움이 될 거 같아
공부 했던 내용을 다시 상기하고 기록하고 싶어서 포스팅을 하려고 한다.
Docker 파일
# build stage
FROM node:14-alpine as build-stage
# ARG ENV
WORKDIR /app
COPY package*.json ./
# COPY yarn.lock ./
RUN yarn install
COPY . .
RUN yarn run build-dev
# production stage
FROM nginx:stable-alpine as production-stage
RUN apk add --no-cache tzdata && apk add vim
ENV LANG ko_KR.UTF-8
ENV LANGUAGE ko_KR:en
ENV LC_ALL ko_KR.UTF-8
# Set Timezone
ENV TZ=Asia/Seoul
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
## COPY nginx config
COPY custom-nginx.conf /etc/nginx/
RUN cat /etc/nginx/custom-nginx.conf > /etc/nginx/conf.d/default.conf
## log
RUN mkdir /logs
RUN chmod 777 /logs
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
FROM node:14-alpine as build-stage
- FROM : 베이스이미지 , 간단하게 말해 OS라고 생각하면됨
- Alpine은 매우 작은 Linux 배포판인 Alpine Linux 를 기반으로 하는 기본 이미지
- node:14-alpine 의 의미는 노드 12에 설치된 알파인 기반 이미지를 의미
- node:alpine 사용 시 최신 버전의 Alpine을 사용할 수 있다.
- build-stage는 이미지 빌드 단계에서 생성된 이미지의 이름이며, 이 이미지는 다른 이미지 빌드 단계에서 사용
- as키워드를 사용하여 현재 단계에 대한 이름을 정의하고 다음 단계에서 해당 이름을 참조할 수 있다
FROM node:14-alpine as build-stage 구문은 node:14-alpine이라는 베이스 이미지에서 새 이미지를 빌드하기 시작하는 것을 의미. 이 단계에서 생성된 이미지는 build-stage라는 이름으로 지정됨. 이후에 다른 Dockerfile 단계에서 build-stage 이미지를 참조하여 해당 이미지를 기반으로 새로운 이미지를 생성할 수 있음.
WORKDIR /app
- WORKDIR지시자는 도커 파일에서 리눅스 명령어의 cd와 유사하게 뒤에 오는 모든 지시자(RUN, CMD, COPY , ADD 등)에 대한 작업 디렉토리를 설정한다.
- WORKDIR /app는 Dockerfile에서 사용되는 명령어로, 컨테이너 내부에서 작업 디렉토리를 설정하는 역할을 한다.
- 원래 최상위 파일이나 폴더에 있던 이름과 COPY해오는 파일이나 폴더의 이름이 같은게 있다면, 기존에 파일을 덮어쓰게되어 문제가 생길 수 있으며, 최상위 폴더에 모두 있을 경우 가독성 또한 좋지 않다.
- /app 은 컨테이너 내부에서 작업할 디렉토리를 의미. 즉, WORKDIR /app 명령어를 사용하면 이후의 명령어들은 모두 /app디렉토리 내에서 실행
- 예를 들어, COPY명령어로 로컬 파일을 컨테이너 내부의 /app디렉토리로 복사하려면, WORKDIR /app 로 작업 디렉토리를 /app으로 설정한 후, COPY 명령어에서 소스 경로를 로컬 파일 경로에서 /app 으로 변경해야 한다.
WORKDIR /app은 Dockerfile에서 작업 디렉토리를 설정하는 중요한 명령어 중 하나이며, 이후의 명령어들이 /app 디렉토리 내에서 실행되도록 한다.
COPY package*.json ./
- Docker클라이언트의 현재 디렉토리에서 파일을 추가한다.
- WORKDIR를 별도로 지정했다면 로컬에 있는 파일들이 도커 컨테이너로 복사될때 WORKDIR 에 정의한 디렉토리로 복사된다.
- 로컬 파일 시스템에 있는 package.json 파일을 Docker 이미지 내부로 복사하는 역할을 한다
- package*.json은 현재 디렉토리에서 package.json으로 시작하는 모든 파일을 매칭하며, ./ 은 현재 Dockerfile이 있는 디렉토리를 나타낸다.
COPY package*.json ./명령어는 Dockerfile이 있는 디렉토리에서 package.json으로 시작하는 파일을 모두 Docker 이미지 내부의 현재 작업 디렉토리에 복사한다.
이 명령어를 사용하면, Node.js 애플리케이션을 Docker 이미지로 패키징할 때 package.json 파일과 yarn.lock파일 등의 의존성 파일을 Docker 이미지 내부로 복사하여 yarn install 명령어에서 이를 활용할 수 있도록 한다.
따라서, COPY package*.json ./은 Node.js 애플리케이션을 Docker 이미지로 패키징할 때 필요한 명령어 중 하나이며, package.json과 같은 의존성 파일을 Docker 이미지 내부로 복사하여 이후의 명령어에서 활용할 수 있도록 한다.
✔ COPY . . 의 의미 ✔
- Dockerfile에서 사용되는 명령어로, 현재 Dockerfile이 있는 디렉토리의 모든 파일을 Docker 이미지 내부의 현재 작업 디렉토리로 복사하는 역할을 한다.
- 첫 번째 .은 현재 로컬 파일 시스템에서 Dockerfile이 있는 디렉토리를 나타내고, 두 번째 . 은 Docker 이미지 내부의 현재 작업 디렉토리를 나타낸다.
- 이 명령어를 사용하면, Node.js 애플리케이션을 Docker 이미지로 패키징할 때 필요한 파일들을 Docker 이미지 내부로 복사하여 애플리케이션 실행에 필요한 파일들을 모두 포함시킬 수 있다.
- 따라서, COPY . .은 Node.js 애플리케이션을 Docker 이미지로 패키징할 때 필요한 명령어 중 하나이며, 현재 Dockerfile이 있는 디렉토리의 모든 파일을 Docker 이미지 내부로 복사하여 이후의 명령어에서 활용할 수 있도록 한다.
RUN yarn install
- 도커 이미지가 생성되기 전에 수행할 쉘 명령어이다.
- Dockerfile에서 사용되는 명령어로, 컨테이너 내부에서 Node.js 애플리케이션을 실행하기 위해 필요한 의존성 패키지를 설치하는 역할을 한다.
- yarn은 Node.js 패키지 매니저 중 하나로, yarn install 명령어는 package.json 파일에 명시된 의존성 패키지를 설치하고, 이를 node_modules ****디렉토리에 저장한다.
RUN yarn install명령어를 Dockerfile에서 사용하면, Docker 이미지를 빌드할 때 의존성 패키지를 미리 설치하여 컨테이너를 실행할 때 불필요한 다운로드와 설치 시간을 줄일 수 있다.
따라서, RUN yarn install은 Node.js 애플리케이션을 Docker 이미지로 패키징할 때 필요한 명령어 중 하나이며, 의존성 패키지를 미리 설치하여 컨테이너 내부에서 빠르고 안정적인 애플리케이션 실행을 가능하게 한다.
FROM nginx:stable-alpine as production-stage
- Dockerfile 명령어 중 하나로, 프로덕션 환경에서 사용될 Docker 컨테이너의 기본 이미지를 지정
- 기본 이미지는 "nginx:stable-alpine"이며, 경량화된 Alpine Linux 배포판 기반의 Nginx 웹 서버의 안정적인 버전
- as production-stage 부분은 명명된 빌드 스테이지를 정의하는 데 사용되며, Docker의 멀티 스테이지 빌드를 가능하게 하며 이것은 빌드 환경과 최종 프로덕션 환경을 분리하여 더 작고 효율적인 이미지를 만드는데 유용하다.
즉 안정적인 Alpine 기반 Nginx 웹 서버를 기반 이미지로 사용하는 Docker 컨테이너를 지정하며, 동시에 빌드 스테이지의 이름을 "production-stage"로 설정한다.
** Nginx 웹 서버란?
- Nginx는 오픈 소스로 개발된 고성능 웹 서버 소프트웨어
- 기본적으로 정적 콘텐츠를 처리하며, 동적 콘텐츠를 처리하기 위해 다양한 백엔드 서버와 연동 가능
- 다양한 기능과 모듈을 제공하며, 프록시, 부하 분산, SSL 인증서 지원, URL 리다이렉션, 보안 기능 등 다양한 웹 서버 기능을 제공
- 가벼우면서도 처리 속도가 빠르고 안정성이 높아 많은 사용자들이 선호하는 웹 서버 중 하나
- 또한 Reverse Proxy 서버로 사용될 수도 있음, Reverse Proxy는 클라이언트의 요청을 받아서 백엔드 서버로 전달하는 역할을 수행, 이는 보안성을 높이거나, 부하 분산을 위한 클러스터링 등의 목적으로 사용
- Nginx는 대규모 웹 서비스에서 많이 사용되며, Facebook, Netflix, Dropbox, GitHub 등 많은 인터넷 기업들이 사용하고 있음
RUN apk add --no-cache tzdata && apk add vim
- Docker 이미지 내부에서 실행되며, Alpine 리눅스 배포판에서 "apk" 패키지 매니저를 사용하여 "tzdata" 패키지와 "vim" 패키지를 설치
- tzdata 패키지는 타임존 데이터를 포함하며, 이를 설치하여 시스템의 시간대를 설정 할 수 있음
- vim 패키지는 Vim 텍스트 에디터를 설치
- --no-cache 옵션은 apk 패키지 매니저가 인덱스를 캐시하지 않도록 함, 이 옵션을 사용하면 이미지 크기를 줄일 수 있음
이 명령어는 Dockerfile에서 이미지 빌드 과정에서 사용되며, 이미지를 생성하는 데 필요한 의존성 패키지를 설치하는 역할을 한다. 따라서, 이 명령어를 사용하여 필요한 패키지를 미리 설치해 두면, 나중에 이미지를 실행할 때 패키지를 추가로 설치할 필요가 없어지므로, 이미지 실행 시간을 단축시킬 수 있다.
** —no-cache ?
- apk 패키지 매니저에서 사용되는 옵션 중 하나
- 이 옵션을 사용하면 apk 패키지 매니저가 패키지 인덱스를 캐시하지 않고, 항상 최신 버전의 패키지 인덱스를 다운로드하여 사용
( 패키지 인덱스는 패키지 매니저가 사용하는 메타데이터로, 설치하려는 패키지의 정보와 패키지가 어디에 위치하는지 등을 담고있다. 패키지 인덱스를 캐시한다는 것은 패키지 매니저가 인덱스를 한번 다운로드를 하고 캐시해 두면, 이후에 패키지를 설치할 때 매번 인덱스를 다시 다운로드하지 않아도 된다는 의미다. 대부분의 패키지 매니저는 이와 같은 방식으로 패키지 인덱스를 관리한다)
- 그러나, 패키지 인덱스가 캐시되면 패키지 매니저가 최신 버전의 패키지를 사용하지 않을 수 있다. 따라서 --no-cache 옵션을 사용하여 항상 최신 버전의 패키지 인덱스를 사용하도록 설정할 수 있다.
- 이 옵션을 사용하면 패키지 인덱스를 다운로드해야 하기 때문에, 패키지 설치 속도가 느려질 수 있지만, 항상 최신 버전의 패키지를 사용할 수 있기 때문에 보안상 이점이 있다. 또한, Docker 이미지 크기를 줄일 수 있어 이미지 빌드 시간을 단축시킬 수도 있다.
** Vim 텍스트에디터란
- 터미널에서 사용하는 텍스트 에디터 중 하나
- Vim은 다양한 기능을 제공하는데 예를 들어 검색 기능, 복사/붙여넣기 기능, 키 매핑 등이 있다.
- 또한 다양한 플러그인을 사용하여 Vim의 기능을 확장할 수 있다.
ENV TZ=Asia/Seoul
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
- $TZ 환경 변수에 저장된 값을 읽어와서 시간대를 설정한다. $TZ환경 변수는 이미지를 빌드할 때 --build-arg 플래그로 전달되는 값으로, Dockerfile 내에서 $TZ 환경 변수를 사용하면 빌드할 때 전달한 시간대 값이 설정된다.
- 다음으로 /usr/share/zoneinfo/$TZ 파일을 /etc/localtime파일로 심볼릭 링크를 걸어서 시간대 설정을 한다. 이를 통해 호스트 컴퓨터의 시간대를 쉽게 컨테이너 내부로 가져올 수 있다.
- 마지막으로, $TZ값을 /etc/timezone 파일에 저장한다. 이를 통해 컨테이너 내부의 시간대 설정이 영구적으로 유지되도록 한다.
ENV TZ=Asia/Seoul은 TZ라는 이름의 환경 변수를 "Asia/Seoul"로 설정하는 역할
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone은 "/usr/share/zoneinfo/Asia/Seoul" 시간대의 심볼릭 링크를 "/etc/localtime"에 생성하고, "/etc/timezone"에 "Asia/Seoul"을 기록
✔ ln -snf ?
- ln 은 link의 약어로 파일이나 디렉토리를 다른 이름으로 링크하는 명령어다.
- -s 옵션은 symbolic link를 생성하도록 한다. 즉 링크된 파일이나 디렉토리를 가리키는 심볼릭 링크를 생성한다.
- -n 옵션은 이미 링크된 대상이 있을 경우, 새로운 링크를 생성하지 않도록 한다.
- -f 옵션은 강제로 링크를 생성하도록 한다.
→ 따라서 ln -snf 명령어는 강제로 이미 존재하는 심볼릭 링크를 생성하도록 하는것을 의미한다.
✔ Symbolic Link
파일 시스템에서 사용되는 개념으로, 하나의 파일이나 디렉토리를 다른 경로에서도 참조할 수 있도록 해주는 링크
- 심볼릭 링크는 원본 파일이나 디렉토리에 대한 참조를 담고 있는 작은 파일이 생성되는데 다른 경로에서도 마치 원본 파일인 것처럼 사용할 수 있음. 즉 원본 파일이나 디렉토리의 변경 사항이 심볼릭 링크에도 반영됨
- 심볼릭 링크는 하드 링크(Hard Link)와 대조되는데 하드 링크는 원본 파일과 완전히 동일한 새로운 파일을 생성하는 것이며, 원본 파일이나 하드 링크 중 어느 하나를 삭제하더라도 나머지 파일은 남아있다. 반면 심볼릭 링크는 원본 파일에 대한 참조만을 담고 있기 때문에 원본 파일이 삭제되면 심볼릭 링크도 더 이상 유효하지 않게 된다.
COPY custom-nginx.conf /etc/nginx/
RUN cat /etc/nginx/custom-nginx.conf > /etc/nginx/conf.d/default.conf
이 코드는 custom-nginx.conf 파일을 Docker 이미지 내부의 /etc/nginx/ 디렉토리에 복사하고, 이후 cat명령어를 사용하여 custom-nginx.conf파일의 내용을 /etc/nginx/conf.d/default.conf 파일에 덮어쓰는 역할을 한다.
**** ‘cat [옵션] 파일명’ 명령어**
cat명령어는 파일의 내용을 터미널에 출력하는 역할을 하기 때문에, 특정 파일의 내용을 확인하거나 파일을 이어붙이는 등의 용도로 사용됨
ex) cat example.txt명령어는 example.txt 파일의 내용을 터미널에 출력
cat file1.txt file2.txt > combined.txt명령어는 file1.txt와 file2.txt ****파일의 내용을 이어붙여서 combined.txt ****파일에 저장
RUN mkdir /logs
RUN chmod 777 /logs
→ /logs 디렉토리를 생성하고, 이 디렉토리의 권한을 chmod 명령어를 사용하여 777 으로 변경하는 역할
- mkdir명령어는 디렉토리를 생성하는 명령어다.
- chmod명령어는 파일이나 디렉토리의 권한을 변경하는 명령어다.
- chmod 777은 해당 디렉토리나 파일에 대한 모든 권한을 부여하는 것으로, 다음과 같은 의미를 갖는다.
- 7: 해당 파일의 소유자(user)에 대한 권한을 rwx (읽기, 쓰기, 실행) 로 부여
- 7: 해당 파일의 그룹(group)에 대한 권한을 rwx (읽기, 쓰기, 실행) 로 부여
- 7: 다른 사용자(other)에 대한 권한을 rwx ****(읽기, 쓰기, 실행) 로 부여
⇒/logs디렉토리를 생성하고, 이 디렉토리의 권한을 모든 사용자에게 부여하는 것으로, 이후에 이 디렉토리를 사용하는 애플리케이션이나 서비스에서 로그 파일을 쓰고 읽을 수 있도록 하는 것
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
→ build-stage단계에서 생성한 /app/dist 디렉토리의 파일을 nginx서버의 /usr/share/nginx/html 디렉토리로 복사하고, 이후에 nginx서버를 실행하여 포트 80 으로 노출하는 역할을 한다.
- COPY 명령어는 호스트 머신에서 Docker 이미지로 파일을 복사하는 명령어. 위의 코드에서는 build-stage 단계에서 생성한 /app/dist 디렉토리의 파일을 **nginx** 서버의 /usr/share/nginx/html 디렉토리로 복사하는 역할을 한다.
- EXPOSE 명령어는 Docker 컨테이너가 사용할 포트를 지정하는 명령어. 위의 코드에서는 nginx 서버가 사용하는 기본 포트인 80을 노출하는 역할을 한다.
- CMD 명령어는 컨테이너가 실행될 때 실행할 명령어를 지정하는 명령어입니다. 위의 코드에서는 nginx 서버를 실행하고, g 옵션으로 설정 파일 내에서 사용할 전역 지시문을 지정하고, daemon off;로 백그라운드에서 실행되지 않도록 설정하는 명령어를 실행합니다.
⇒ 즉, 위의 코드는 nginx서버를 실행하고, build-stage 단계에서 생성한 /app/dist 디렉토리의 파일을 nginx서버의 /usr/share/nginx/html디렉토리로 복사하여 서비스를 제공하는 역할을 한다. 이후에 docker build명령어를 사용하여 Docker 이미지를 빌드하고, docker run명령어를 사용하여 컨테이너를 실행하면 nginx서버가 실행되고, http://localhost와 같은 URL을 사용하여 웹 페이지를 확인 할 수 있다.