Docker File 이란?
- Docker 컨테이너를 생성하기 위한 구성 파일입니다.
- Dokcer 이미지를 만들기 위한 명령어와 설정을 포함하고 있습니다.
- Docker File을 사용하면 애플리케이션과 종속성을 코드 형태로 정의할 수 있으며, 이를 통해 일관된 환경에서 애플리케이션을 배포하고 실행할 수 있습니다.
Docker File 기본적인 구성
FROM #운영체제 이미지
RUN #실행할 명령어
CMD #컨테이너 명령 실행
DockerFile 문법
명령어 | 설명 | 명령어 | 설명 |
---|---|---|---|
FROM | 베이스 이미지 지정 | RUN | 명령어 실행 |
CMD | 컨테이너 실행 명령 | EXPOSE | 포트 노출 |
ENV | 환경 변수 | ADD | 파일 / 디렉토리 추가 |
COPY | 파일 복사 | ENTRYPOINT | 컨테이너 실행 명령 |
VOLUME | 볼륨 마운트 | USER | 사용자 지정 |
WORKDIR | 작업 디렉토리 | ARG | Dockerfile 안의 변수 |
ONBUILD | 빌드 완료 후 실행되는 명령 | LABEL | 라벨 설정 |
STOPSIGNAL | 종료 시그널 설정 | HEALTHCHECK | 컨테이너 상태 체크 |
SHELL | 기본 쉘 설정 |
- 대다수의 Dockerfile을 보면 FROM 부터 시작합니다.
- 운영체제를 지정하는데 메모리 기반으로 돌아가기 때문에 용량을 적게 설정하는 것이 필요합니다.
명령어 상세 설명
1. RUN
- 이미지 생성과정에서 애플리케이션 / 미들 웨어 설치, 환경 설정을 위한 명령 등을 정의합니다.
1) Shell 형식
- 쉘 프롬프트에 명령을 기술하는 방식입니다.
- 베이스 이미지 위에서
/bin/sh -c
를 사용해서 명령을 수행하는 것과 동일합니다.
RUN apt-get update && apt-get install -y nginx
2) exec 형식
- 쉘을 경유하지 않습니다.
- 직접 실행이 아니라 $HOME 같은 쉘 환경 변수를 사용할 수 없습니다.
- 명령어가 단독적으로 실행되는 것이 아니기 때문에 JSON 배열 형식으로 정의합니다.
RUN ["/bin/bash", "apt-get install -y nginx" ]
2. CMD
- 생성된 이미지를 바탕으로 컨테이너 내부에서 수행될 작업이나 명령을 실행합니다.
- Dockerfile에 하나의 CMD 명령만 기술 가능하기 때문에, 여러개를 기록한다면 마지막 명령만 유효합니다.
ex) Nginx 이미지를 생성할 때 Nginx를 설치하는 것은 RUN 명령이지만, Nginx Daemon을 실행하는 것은 CMD 명령어 입니다.
- shell, exec 형식을 지원합니다.
#shell
CMD nginx -g 'daemon o ff;'
#exec
CMD ["nginx", "-g", "daemon o ff;" ]
3. ONBUILD
- 해당 이미지를 import 하는 곳에서 사용하기 위한 명령어 입니다.
- Dockerfile 에 ONBUILD 명령을 사용하여 어떤 명령을 실행하도록 설정하여 빌드하고 이미지를 작성하게 되면, 그 이미지를 다른 Dockerfile 에서 베이스 이미지로 설정하여 빌드했을 때 ONBUILD 명령에서 지정한 명령이 실행됩니다.
4. ENV, ARG
- 둘 모두 환경 변수를 지정해 줍니다.
- ENV는 컨테이너 내부에서 사용하는 환경 변수, ARG는 빌드 되는 과정에서만 사용하는 환경 변수 입니다.
FROM nginx
ENV FOOD "Chicken" \
Summer Cola Sea Vacation \
ENV Time 1116
CMD ["/bin/bash"]
5. EXPOSE
- 컨테이너의 공개포트를 지정하고 컨테이너가 대기하고 있는 포트를 알려줍니다.
docker run -p
옵션을 통해 호스트의 포트 번호와 매핑할 수 있습니다.
예를 들면-p 8080:443
처럼 사용할 수 있습니다.
FROM nginx
EXPOSE 443
Image Layer
- Image layer는 햄버거와 유사합니다. 햄버거가 빵 -> 야채 -> 패티 -> 야채 -> 소스 -> 빵 순서로 하나씩 쌓아가듯 컨테이너도 레이어를 쌓아서 Image Layer를 이룬다고 생각하시면 됩니다.
- 이미지 전송시간을 줄이기 위해 Read-only image layer 를 공유합니다.
위 그림에서 첫번째 그림의 Container에서 Image 1.0은 Read only 입니다. 여기에 Apache를 추가하여 레이어를 쌓았습니다.
두번째 그림은 첫번째 그림의 Container(Image 1.0, Iamge 1.1) 위에 Git을 추가하여 레이어를 쌓았습니다.
세번째 그림은 두번째 그림의 Container(Image1.0, 1.1, 1.2) 위에 Source를 추가하여 레이어를 쌓았습니다.
이렇게 명령어가 하나씩 실행될 때마다 upper layer(프로그램 설치)가 반복이 됩니다.
이런식으로 끊임없이 레이어가 쌓이게 되면 메모리는 점점 많아져 무거워 질겁니다.
예를 들어 보겠습니다.
1) dockerfile은 아래와 같습니다.
FROM ubuntu
RUN apt-get update && apt-get install -y -q nginx
RUN rm -rf /var/lib/apt/lists/***
COPY index.html /var/www/html
CMD ["nginx", "-g", "daemon off; " ]
2) dockerfile을 실행 후 모습
180MB의 메모리를 지니고 있는 것을 확인할 수 있습니다.
3) dockerfile 내의 RUN 명령어를 한줄로 변경하기
FROM ubuntu
RUN apt-get update && \
apt-get install -y -q nginx && \
rm -rf /var/lib/apt/lists/***
COPY index.html /var/www/html
CMD ["nginx", "-g", "daemon off; " ]
4) dockerfile 실행 후 모습
134MB 메모리로 줄어든 것을 확인할 수 있습니다!
java 파일을 Dockerfile을 이용한 예시 입니다.
- 환경으로는 Springboot 2.5.2, java 11, gradle 6.8.2 에서 실행하였습니다.
build.gradle 파일
buildscript {
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE"
}
}
plugins {
id 'org.springframework.boot'
id 'java'
id 'com.palantir.docker' version '0.25.0'
}
compileJava{
sourceCompatibility = 11
targetCompatibility = 11
}
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.pay.membership'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
testImplementation 'com.tngtech.archunit:archunit:1.0.1'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.jetbrains:annotations:23.0.0'
testImplementation 'junit:junit:4.13.1'
runtimeOnly 'mysql:mysql-connector-java'
implementation project(path: ':common')
}
test {
useJUnitPlatform()
}
docker{
println(tasks.bootJar.outputs.files)
// 이미지 이름
name rootProject.name+'-'+project.name + ":" + version
// 어떤 Dockerfile을 사용 할 거냐
dockerfile file('../Dockerfile')
// 어떤 파일들을 Dockerfile 에 복사하여 image에 넣을 것이냐
files tasks.bootJar.outputs.files
// Dockerfile 에 전달할 인자
buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name])
}
Docker File
FROM openjdk:11-slim-stretch
EXPOSE 8080
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
docker 실행
- dockerfile 경로에서 아래 명령어를 실행합니다.
./gradlew docker
결과
Docker Compose(도커 컴포즈)
- Docker Compose는 여러 개의 컨테이너(Container)로 구성된 애플리케이션을 관리하기 위한 간단한 오케스트레이션(Orchestration) 도구 입니다.
- 또한 여러 개의 컨테이너를 yaml 파일의 코드를 통해 통합 관리하기 위한 툴입니다.
yaml
- 구조화 데이터나 오브젝트를 문자열로 변환하기 위한 데이터 형식의 한 종류입니다.
- Space를 사용한 들여쓰기를 통해 데이터 계층을 표시합니다.
Docker Compose 파일의 구조
version: ()
services: (docker container)
volumes: (docker volume)
networks: (docker network)
- version: 지원 버전
- services: 컨테이너 설정
- volumes: 도커 볼륨에 대한 설정
- networks: 도커 네트워크에 대한 설정
예시
version: '3'
services:
mysql:
image: mysql:8.0
networks:
- pay_network
volumes:
- ./db/conf.d:/etc/mysql/conf.d
- ./db/data:/var/lib/mysql
- ./db/initdb.d:/docker-entrypoint-initdb.d
env_file: .env
ports:
- "3307:3306"
environment:
- TZ=Asia/Seoul
- MYSQL_ROOT_PASSWORD=root@@
- MYSQL_USER=shbae
- MYSQL_PASSWORD=shbae@@
membership-service:
image: msapay-membership-service:1.0.0
networks:
- pay_network
ports:
- "8081:8080" # 외부에서 8081 port를 통해서 내부의 8080 port로 통할거야. 8080은 실제 어플리케이션 port
depends_on:
- mysql
environment:
- AXON_AXONSERVER_SERVERS=axon-server:8124
- AXON_SERIALIZER_EVENTS=jackson
- AXON_SERIALIZER_MESSAGES=jackson
- AXON_SERIALIZER_GENERAL=xstream
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/msa_pay?useSSL=false&allowPublicKeyRetrieval=true
- SPRING_DATASOURCE_USERNAME=shbae
- SPRING_DATASOURCE_PASSWORD=shbae@@
- SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect
- SPRING_JPA_HIBERNATE_DDL_AUTO=update
banking-service:
image: msapay-banking-service:1.0.0
networks:
- pay_network
ports:
- "8082:8080" # 외부에서 8081 port를 통해서 내부의 8080 port로 통할거야. 8080은 실제 어플리케이션 port
depends_on:
- mysql
environment:
- AXON_AXONSERVER_SERVERS=axon-server:8124
- AXON_SERIALIZER_EVENTS=jackson
- AXON_SERIALIZER_MESSAGES=jackson
- AXON_SERIALIZER_GENERAL=xstream
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/msa_pay?useSSL=false&allowPublicKeyRetrieval=true
- SPRING_DATASOURCE_USERNAME=shbae
- SPRING_DATASOURCE_PASSWORD=shbae@@
- SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect
- SPRING_JPA_HIBERNATE_DDL_AUTO=update
networks:
pay_network:
driver: bridge
Docker Compose Commands
- docker-compose.yaml 파일이 위치한 디렉토리에서 실행
docker-compose up -d # background에서 서비스와 관련된 컨테이너 생성 및 시작
docker-compose down # 서비스와 관련된 컨테이너 종료 후 제거
docker-compose start/stop/restart # 서비스 관련 컨테이너 시작 / 종료 / 재시작
docker-compose kill # 실행 중인 컨테이너에 SIGKH 시그널을 통해서 강제 종료
docker-compose pause / unpause # 컨테이너 정지 / 재가동
'개발 > Docker' 카테고리의 다른 글
Docker vs 가상머신(Docker와 가상머신의 차이) (0) | 2023.09.27 |
---|