## Dockerfile 이란?
이미지가 어떤 단계를 걸쳐 빌드되는지 적힌 텍스트 파일. 프로젝트 최상위 디렉터리에 두는 것이 관례이다. `docker build`를 명령하면 이 파일에 나열된 명령문을 차례대로 수행하여 이미지가 생성된다.
## CLI 형식
```
docker build -t [생성할 이미지 이름] [Dockerfile 경로]
```
## Dockerfile 주요 명령
### 참고 : [Yaml 문법](https://lejewk.github.io/yaml-syntax/)
| 명령어 | 의미 | 예시 | | | | |
| ------------------------------------------ | -------------------------------- | ------------------------------------------------------------------------------ | ---------------- | ---------------------------- | --- | ----- |
| `FROM [이미지 이름]` | 베이스가 되는 이미지 지정 | `FROM nginx` | | | | |
| `MAINTAINER [작성자 정보]` | 이미지를 유지보수하는 사람 정보 지정 | `MAINTAINER John Doe` | | | | |
| `RUN [커맨드]` | 명령 실행 | `RUN apt-get update && apt-get install -y wget` | | | | |
| `COPY [소스] [타겟]` | 로컬 파일 복사 | `COPY ./app /usr/src/app` | | | | |
| `ADD [소스] [타겟]` | 로컬 파일 또는 URL 추가 (압축 파일 해제 가능) | `ADD http://example.com/file.tar.gz /tmp/` | | | | |
| `WORKDIR [작업 디렉터리]` | 작업 디렉터리 설정 | `WORKDIR /usr/src/app` | | | | |
| `ENV [환경 변수 이름] [값]` | 환경 변수 설정 | `ENV NODE_ENV production` | | | | |
| `EXPOSE [포트]` | 컨테이너가 사용하는 포트 공개 | `EXPOSE 80` | | | | |
| `CMD [실행 명령]` | 컨테이너가 시작될 때 실행할 명령 설정 | `CMD ["npm", "start"]` | | | | |
| `ENTRYPOINT [실행 명령]` | 컨테이너가 시작될 때 실행할 명령 설정 (CMD보다 우선) | `ENTRYPOINT ["nginx", "-g", "daemon off;"]` | | | | |
| `VOLUME [경로]` | 컨테이너와 호스트 간 데이터 공유를 위한 디렉터리 설정 | `VOLUME /var/log` | | | | |
| `USER [사용자]` | 실행할 사용자 지정 | `USER appuser` | | | | |
| `RUN apk --no-cache add [패키지]` | Alpine Linux에서 패키지 설치 | `RUN apk --no-cache add curl` | | | | |
| `ARG [인자]` | 빌드 중에 전달되는 인자 정의(= 이후는 기본값) | `ARG version=latest` | | | | |
| `LABEL [키=값]` | 이미지에 메타데이터 추가 | `LABEL version="1.0" description="My custom image"` | | | | |
| `COPY --from=[이미지] [소스] [타겟]` | 빌드 중 다른 이미지에서 파일 복사 | `COPY --from=builder /app/build /usr/share/nginx/html` | | | | |
| `RUN [커맨드] | | true` | 에러 발생해도 빌드 계속 진행 | `RUN command_that_might_fail | | true` |
| `HEALTHCHECK [옵션] CMD [명령]` | 컨테이너의 건강 상태를 확인하는 명령 설정 | `HEALTHCHECK --interval=5m CMD curl --fail http://localhost | | exit 1` | | |
| `RUN [커맨드] && rm -rf /var/lib/apt/lists/*` | 캐시 크기 줄이기 위해 패키지 설치 후 불필요한 파일 삭제 | `RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*` | | | | |
| `STOPSIGNAL [시그널]` | 컨테이너 중지 시 전송되는 시그널 설정 | `STOPSIGNAL SIGTERM` | | | | |
## 사용 예시
### Node JS 기반 서버 이미지 생성
```
# Node.js XX 버젼
FROM node:XX
# 작업 디렉터리 설정
WORKDIR /usr/src/app
# 소스 코드 복사
COPY . .
# 패키지 설치
RUN npm install
# 애플리케이션 실행 명령 설정
CMD ["npm", "start"]
```
### Spring Boot 서버 이미지 생성(Gradle 🐘)
```
# OpenJDK 17을 베이스 이미지로 선택
FROM adoptopenjdk:17-jdk-hotspot
# 볼륨 명시적으로 설정
VOLUME /data
# JAR 경로 받는 ARG 설정(기본값 포함)
ARG JAR=build/libs/my-spring-boot-app.jar
# JAR 파일을 컨테이너로 복사
# Gradle은 build/libs/ 여기에 jar을 생성함
COPY ${JAR} app.jar
# 빌드된 JAR 파일 실행
CMD ["java", "-jar", "app.jar"]
```
- build.gradle 에 아래의 설정을 추가하면 빌드 후 jar 파일의 이름이 고정됨.
```
bootjar {
archivesBaseName = 'my-spring-boot-app'
archiveFileName = 'my-spring-boot-app.jar'
}
```
### MySQL 서버 이미지 생성
```
FROM mysql:8.0
ENV MYSQL_ROOT_PASSWORD=[비밀번호]
ENV MYSQL_DATABASE=[DB 이름]
ENV MYSQL_USER=[유저 이름]
ENV MYSQL_PASSWORD=[비밀번호]
RUN { \
echo '[mysqld]'; \
echo 'character-set-server=utf8mb4'; \
echo 'collation-server=utf8mb4_unicode_ci'; \
echo 'skip-host-cache'; \
echo 'skip-name-resolve'; \
} > /etc/mysql/my.cnf
EXPOSE 3306
VOLUME /var/lib/mysql
```