> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cloudtype.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Dockerfile

> Dockerfile 관련 문제 해결 가이드

## 준비 및 확인사항

<AccordionGroup>
  <Accordion title="Docker 이미지 확인 사항" defaultOpen={true}>
    * 단일 Docker 이미지의 크기는 2GB(유료 구독 시 5GB)까지 지원합니다. 큰 용량의 이미지를 활용해야 하는 경우, 컨테이너보다는 VM이나 온프레미스 방식의 인프라 사용이 적합할 수 있습니다.
  </Accordion>
</AccordionGroup>

<Warning>
  Windows Server나 ARM 아키텍처 기반의 Docker 이미지 런타임은 지원하지 않습니다.
</Warning>

## 공통

### Dockerfile 작성 시 root 권한으로 스크립트 작성

> 클라우드타입에서 Dockerfile을 이용하여 배포를 진행하시는 경우 UID 및 GID를 설정하는 스크립트를 작성해야 합니다. 배포되는 서비스는 보안 및 서비스 안정성을 위해 non-root 권한으로 실행하도록 권장하고 있어, Dockerfile로 배포 시 정상적으로 작동하지 않는 경우 아래의 예시를 참고하여 스크립트 수정 후 재배포해주세요.

* **Java Spring Boot(Gradle)**
  ```dockerfile theme={null}
  # jar 파일 빌드
  FROM eclipse-temurin:11 as builder

  COPY gradlew .
  COPY gradle gradle
  COPY build.gradle .
  COPY settings.gradle .
  COPY src src
  RUN chmod +x ./gradlew
  RUN ./gradlew bootjar

  # jar 실행
  FROM eclipse-temurin:11 as runtime

  RUN addgroup --system --gid 1000 worker
  RUN adduser --system --uid 1000 --ingroup worker --disabled-password worker
  USER worker:worker

  COPY --from=builder build/libs/*.jar app.jar

  EXPOSE 8080

  ENTRYPOINT ["java", "-Dspring.profiles.active=${PROFILE}", "-jar", "/app.jar"]
  ```

* **Java Spring Boot(Maven)**
  ```dockerfile theme={null}
  # jar 파일 빌드
  FROM eclipse-temurin:11 as builder

  WORKDIR /opt/app
  COPY .mvn/ .mvn
  COPY mvnw pom.xml ./
  RUN ./mvnw dependency:go-offline
  COPY ./src ./src
  # -Dmaven.test.skip=true 이 mvn install 단계에 설정되지 않으면
  # 환경변수가 주입되지 않은 상태에서 어플리케이션이 실행되어 에러 발생
  RUN ./mvnw clean install -Dmaven.test.skip=true

  # jar 실행
  FROM eclipse-temurin:11 as runtime

  RUN addgroup --system --gid 1000 worker
  RUN adduser --system --uid 1000 --ingroup worker --disabled-password worker
  USER worker:worker

  WORKDIR /opt/app
  EXPOSE 8080
  COPY --from=builder /opt/app/target/*.jar /opt/app/*.jar

  ENTRYPOINT ["java", "-Dspring.profiles.active=${PROFILE}", "-jar", "/opt/app/*.jar"]
  ```

* **Python Flask**
  ```dockerfile theme={null}
  FROM python:3.9-slim-buster

  ENV PYTHONDONTWRITEBYTECODE=1
  ENV PYTHONUNBUFFERED 1

  ARG UID=1000
  ARG GID=1000

  RUN groupadd -g "${GID}" python \
    && useradd --create-home --no-log-init -u "${UID}" -g "${GID}" python
  WORKDIR /home/python

  COPY --chown=python:python requirements.txt requirements.txt
  RUN pip3 install -r requirements.txt

  # USER 변경은 반드시 pip 패키지 설치 스크립트 이후에 작성되어야 함
  USER python:python
  ENV PATH="/home/${USER}/.local/bin:${PATH}"
  COPY --chown=python:python . .

  ARG FLASK_ENV
  ARG DB_USERNAME
  ARG DB_PASSWORD
  ARG DB_URL

  ENV FLASK_ENV=${FLASK_ENV}
  ENV DB_USERNAME=${DB_USERNAME}
  ENV DB_PASSWORD=${DB_PASSWORD}
  ENV DB_URL=${DB_URL}

  EXPOSE 5000

  CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]
  ```

* **Node.js**
  ```dockerfile theme={null}
  # 의존성 설치
  FROM node:16-buster
  WORKDIR /app
  COPY package*.json ./ 
  RUN npm ci --only=production

  ENV NODE_ENV production

  COPY . .

  # node 이미지에 이미 "node"라는 사용자가 uid/gid 1000번으로 생성되어 있음
  USER node

  EXPOSE 3000
  CMD ["npm", "start"]
  ```

* **React**
  ```dockerfile theme={null}
  # 프로젝트 빌드
  FROM node:16-buster AS builder
  WORKDIR /app
  COPY package*.json .
  RUN npm ci
  COPY . .
  RUN npm run build

  # Production 런타임
  FROM nginxinc/nginx-unprivileged:1.23 AS runner
  WORKDIR /usr/share/nginx/html
  COPY --from=builder /app/build .

  EXPOSE 3000
  CMD ["nginx", "-g", "daemon off;"]
  ```

### Dockerfile 내부에서 ARG 와 ENV 로 선언된 값 활용

> Dockerfile을 활용하여 배포하는 경우 다음과 같이 변수를 넘기는 두 가지의 방법이 있습니다.

* **빌드 인자(Build Arguments): 빌드 시점에 주입**
  ```bash theme={null}
  docker build -t app:latest . --build-arg ARG1="VAL1" --build-arg ARG2="VAL2"
  ```
* **환경 변수(Environment Variables): 런타임 시점에 주입**
  ```bash theme={null}
  docker run -d -p 8080:8080 --name app -e ENV1="VAL1" -e ENV2="VAL2" app:latest
  ```

***

## 참고

### 공식문서

* [Docker Docs](https://docs.docker.com/)
