Docker&Container

Docker&Container - 성능을 위한 Dockerfile 작성법

hminor 2024. 11. 29. 01:11
반응형

성능을 위한 Dockerfile 작성법

  • 이전 작성한 Dockerfile의 경우엔 아주 기초적인 코드를 작성했기에
  • 성능 최적화를 위한 추가적인 코드를 작성할 예정
    • docker build 시간을 단축
      • 변동 사항이 많은 부분은 밑에 작성하기.
      • 이유는 기존 실행한 코드를 캐싱하게 되는데
      • 저번이랑 차이가 없다면 캐싱해둔 결과를 사용하기에.
        • ex) COPY . . RUN [”npm”, “install”]
      • 그래서 package.json, 라이브러리 파일은 변동사항이 별로 없기에 위에 작성하여 캐싱된 데이터를 사용하는 것으로 시간을 단축하기
      • 순서
        1. package.json 파일 먼저 옮기기
        2. npm install 실행
        3. 소스 코드 옮기고 실행
      • 기존
      • FROM node:20-slim
        WORKDIR /app
        COPY . .
        RUN ["npm", "install" ]
        EXPOSE 8080
        CMD ["node", "server.js" ]
      • 수정 후
        • COPY . . 이전까진 변동이 많이 없기에 캐싱된 데이터를 사용할 것.
        FROM node:20-slim
        WORKDIR /app
        COPY package*.json .
        RUN ["npm", "install" ]
        
        COPY . .
        EXPOSE 8080
        CMD ["node", "server.js" ]
        
      • 여기서 npm install 보다 더 좋은 명령어는
        • npm ci → npm clean install
        • 이유는 그냥 npm install하게 되면 package.json에서 보이는 ^4.21.0 과 같이 4로 시작하는 것을 의미하는 것으로
        • 4.22 버전이 나오게 된다면 해당 버전을 설치할 수 도 있기에
        • package-lock.json 파일 바탕으로 설치하는 것이 좋기에 해당 명령어를 추천.
        FROM node:20-slim
        WORKDIR /app
        COPY package*.json .
        RUN ["npm", "ci" ]
        
        COPY . .
        EXPOSE 8080
        CMD ["node", "server.js" ]
        
      • 그리고 ENV 코드가 있는데
        • React에서 사용하는 것처럼 환경 변수를 넣을 수 있음
        • ENV 이름=값
        • 그리고 엄청 예전부터 존재하던 nodejs 라이브러리는 아래 코드를 작성해야 출력되는 로그를 줄여 성능을 향상할 수 있다고 함.
        FROM node:20-slim
        WORKDIR /app
        COPY package*.json .
        RUN ["npm", "ci" ]
        
        ENV NODE_ENV=production
        
        COPY . .
        EXPOSE 8080
        CMD ["node", "server.js" ]
        
    • image 용량을 줄이기
  • 코드 실행 전 유저 권한 낮추기
    • 기본적으로 실행하게 되면 root 권한으로 실행하게 됨
    • 좀 더 안전하게 실행하고자 한다면 권한을 낮춰서 실행하면 좋다고 함.
    • 그래서 우선 유저를 생성하는 코드를 작성해야 함.
      • 여기서 새로운 그룹을 추가하고자 한다면
      RUN groupadd -r 그룹명
      
    • RUN useradd -m 유저명
    • 이후 해당 유저로 변경하는 코드를 작성해야 함.
    • USER 변경할유저명
    • 여기서 docker hub에 올라온 공식 코드의 경우
      • node 라는 이름의 유저가 만들어져 있음.

Spring Boot로 만든 웹서버를 Dockerfile로 작성하기

  • 해당 프로젝트에서 터미널 열기
    • .jar 파일 생성하기
    ./gradlew build // gradle
    
    ./mvnw package// maven
    // mvnw는 Maven Wrapper를 의미
    
    • .jar 파일 실행
    java -jar .jar
    
  • 위 과정을 Dockerfile 생성 후 파일 안에서 명령하기
    • FROM 에 어떤 OS와 자바 버전을 사용할 것인지 작성하며 아래와 같이 작성
    • 아마 ./jar 파일의 경로는
      • /build/libs 안에 있을 것임.
    FROM AMAZONCORRETTO:21.0.4
    WORKDIR /app
    COPY . .
    RUN ./mvnw package
    CMD ["java", "-jar", "./jar파일경로"]
    
    • 이를 최적화 하기 위하고자
      • 우선 .jar 파일만 있다면 서버를 실행할 수 있기에, 다른 코드가 필요 없음
      • 그래서 코드 순서를 조금 변경하고자 한다면
      • 순서
        1. ./mvnw package 입력해서 .jar 파일 생성
        2. 새롭게 OS 다시 설치
        3. 거기에 .jar 파일만 옮김
        4. java -jar .jar 파일 실행
      FROM AMAZONCORRETTO:21.0.4 AS build
      WORKDIR /app
      COPY . .
      RUN ./mvnw package
      
      # 새롭게 FROM을 작성하면 기존것과 별개로 독립적으로 새로운 스테이지가 시작
      FROM AMAZONCORRETTO:21.0.4 AS runtime  
      # /app 폴더를 생성 후 이동
      WORKDIR /app  
      # build 이미지에서 만든 .jar 파일을 새롭게 만든 /app 폴더에 server.jar 이름으로 이동
      COPY --from=build /app/build/libs/*.jar /app/server.jar 
      CMD ["java", "-jar", "/app/server.jar"]
      
      #단 gradle의 경우엔 위 코드와 같은 /app/build/libs 경로에 *.jar 파일이 있지만
      # maven의 경우엔 /app/target 폴더 안에 생성됨
      
      
    • 위 코드 작성이 멀티 스테이지 식으로 작성한 것.
      • 이를 통해 용량을 줄일 수 있음.
      • 참고로 Spring boot에서 이미지를 생성할 때 따로 코드가 있긴 함.
      # gradle
      ./gradlew bootBuildImage
      
      # maven
      ./mvnw spring-boot:build-image
      
  • Spring Boot와 React를 함께 Docker에 올리는 방법이 궁금해서 찾아보니
    • 멀티 스테이지 빌드를 사용해서 아래와 같이 코드를 작성할 수 있다고 함.
    • 추후에 해볼 예정
    # Stage 1: Build React application
    FROM node:18 AS react-build
    
    WORKDIR /app
    COPY ./frontend/package.json ./frontend/package-lock.json ./
    RUN npm install
    COPY ./frontend ./
    RUN npm run build   # React 빌드 (생성된 빌드 파일은 /app/build에 위치)
    
    # Stage 2: Build Spring Boot application
    FROM maven:3.8.6-openjdk-17 AS spring-build
    
    WORKDIR /app
    COPY ./backend/pom.xml ./backend
    RUN mvn -f /app/pom.xml clean package -DskipTests  # Spring Boot 애플리케이션 빌드
    
    # Stage 3: Create the final image with both React and Spring Boot
    FROM openjdk:17-jdk-slim AS runtime
    
    WORKDIR /app
    
    # React의 빌드된 파일을 Spring Boot의 static 디렉토리로 복사
    COPY --from=react-build /app/build /app/backend/src/main/resources/static
    
    # Spring Boot .jar 파일 복사
    COPY --from=spring-build /app/target/backend-*.jar /app/server.jar
    
    # Spring Boot 실행
    CMD ["java", "-jar", "/app/server.jar"]