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

Docker와 가상머신(VM)의 차이

 

출처:  https://iancoding.tistory.com/184

 

아래 비교 표에 대한 자세한 설명은 아래에 작성하였습니다.

 

Docker 가상머신(VM)
Docker는 컨테이너화 된 애플리케이션을 실행합니다. 컨테이너는 호스트 OS의 커널을 공유하며 각 컨테이너는 시스템의 나머지 부분으로부터 격리된 환경에서 실행됩니다. VM은 물리적 하드웨어 위에 하이퍼바이저를 사용하여 별도의 전체 운영체제를 실행합니다. 완전히 독립된 가상의 컴퓨터를 의미합니다.
호스트 OS 커널을 공유하기 때문에 추가적인 운영체제를 로드할 필요가 없어 더 적은 리소스를 사용합니다. 각 VM은 전체 운영체제와 그 운영체제를 실행하는 데 필요한 리소스를 포함하므로 일반적으로 더 많은 리소스를 사용합니다.
컨테이너는 빠르게 시작될 수 있습니다. 전체 OS를 부팅해야 하기 때문에 시간이 좀 더 걸립니다.
컨테이너는 호스트 OS의 커널을 공유하기 때문에 VM에 비해 낮은 수준의 격리를 제공합니다. 각 VM은 독립적인 OS를 가지기 때문에 높은 수준의 격리를 제공합니다.
OS를 포함하지 않기 때문에 VM에 비해 이미지 크기가 일반적으로 작습니다. 전체 OS를 포함하기 때문에 디스크 이미지 크기는 대체로 큽니다.
Docker CLI, Docker Compose 등 다양한 도구와 플랫폼을 제공하여 컨테이너화된 애플리케이션의 배포 및 관리를 쉽게 합니다. VMware, VirtualBox, KVM 등 다양한 하이퍼바이저 및 관리 도구가 있습니다.

 

 

표에 대한 자세한 설명(표가 바로 이해되셨다면 넘어가셔도 됩니다)

 

컨테이너는 호스트 OS의 커널을 공유하며 각 컨테이너는 시스템의 나머지 부분으로부터 격리된 환경에서 실행됩니다

컨테이너와 호스트 OS의 관계를 이해하려면 먼저 컨테이너 기술의 핵심 요소와 원칙을 파악해야 합니다.

 

  1. 호스트 OS의 커널 공유

커널은 운영체제의 핵심 부분으로 하드웨어와 소프트웨어 간의 통신을 관리합니다.
이는 프로세스 관리, 메모리 관리, 디바이스 드라이버의 인터페이스 역할 등 다양한 핵심 기능을 포함합니다.

가상 머신(VM)
  • VM은 하이퍼바이저 위에 동작하며, 각 VM은 자체 운영체제(커널 포함)를 가집니다.
  • VM 내부의 애플리케이션은 해당 VM의 커널을 통해 하드웨어 리소스에 액세스합니다. 이 커널은 호스트 시스템의 실제 커널과 독립적입니다.
컨테이너
  • 컨테이너는 호스트 OS 위에서 동작하며, 호스트의 커널을 직접 사용합니다.
  • 컨테이너 내부의 애플리케이션은 호스트 OS의 커널을 통해 하드웨어 리소스에 액세스합니다.

"컨테이너는 호스트 OS의 커널을 직접 사용한다"는 것은, 컨테이너가 호스트 시스템의 실제 커널을 공유하고 이를 바탕으로 동작한다는 것을 의미합니다.

 

  1. 컨테이너의 격리

컨테이너는 '네임스페이스'라는 커널 기능을 사용하여 시스템의 다른 부분으로부터 격리됩니다.
네임스페이스는 프로세스, 네트워크, 사용자, 파일 시스템 등 다양한 리소스에 대한 격리를 제공합니다.

예를 들어, 네트워크 네임스페이스를 사용하면 각 컨테이너는 자체 IP 주소, 포트 번호, 라우트 테이블 등을 가질 수 있습니다.
PID(프로세스 ID) 네임스페이스를 사용하면 컨테이너 내부의 프로세스는 컨테이너 외부에서는 보이지 않습니다.

 

  1. 컨테이너의 이미지 및 파일 시스템

컨테이너는 '이미지'를 기반으로 실행됩니다.
이미지는 응용 프로그램, 라이브러리, 종속성 및 실행에 필요한 다른 모든 파일을 포함합니다.

'오버레이 파일 시스템'을 사용하여 이미지는 여러 계층으로 구성될 수 있습니다.
이를 통해 여러 컨테이너가 동일한 이미지 계층을 공유하면서 독립적인 변경을 수행할 수 있습니다.

VM은 물리적 하드웨어 위에 하이퍼바이저를 사용하여 별도의 전체 운영체제를 실행합니다. 이것은 완전히 독립된 가상의 컴퓨터를 의미합니다.

 

  1. 물리적 하드웨어
  • 컴퓨터의 실제 구성 요소를 의미합니다.
  • 예를 들어, CPU, RAM, 저장 장치(SSD, HDD), 네트워크 카드 등입니다.

 

  1. 하이퍼바이저
  • 하이퍼바이저는 가상화를 가능하게 하는 소프트웨어 또는 펌웨어 컴포넌트입니다.
  • 이를 통해 단일 물리적 하드웨어 위에서 여러 운영체제를 동시에 실행할 수 있습니다.

 

  1. 별도의 전체 운영 체제
  • VM은 자체적인, 독립된 운영체제를 실행합니다. 이 운영체제는 "게스트 운영체제"라고도 불립니다.
  • 게스트 운영체제는 물리적 하드웨어가 아닌, 하이퍼바이저에 의해 제공되는 가상의 하드웨어 위에서 동작합니다. 가상의 CPU, RAM, 디스크 등의 자원을 사용합니다.
  • 각 VM은 다른 VM과 완전히 독립적입니다. 따라서 한 VM에서 발생하는 문제가 다른 VM에 영향을 미치지 않습니다.

 

요약하면, VM 기술은 하이퍼바이저를 사용하여 물리적 하드웨어를 추상화하고, 이 추상화된 환경 위에서 여러 개의 독립적인 운영체제(게스트 OS)를 동시에 실행할 수 있게 해줍니다.
각 운영체제는 자신만의 가상의 자원과 환경을 가지며, 실제 물리적 자원을 하이퍼바이저를 통해 공유합니다.

 

컨테이너는 거의 즉시 시작될 수 있습니다.

  1. 가벼운 구조
  • 컨테이너는 전체 운영체제를 포함하지 않습니다. 대신 호스트 OS의 커널을 공유합니다. 따라서 컨테이너 이미지는 애플리케이션과 그 종속성만을 ㅗ함하게 되므로 사이즈가 작습니다.

 

  1. 직접적인 커널 액세스
  • 컨테이너는 호스트의 커널을 직접 사용하기 때문에 추가적인 추상화 계층이 없습니다. 이로 인해 컨테이너는 자원에 대한 접근이 빠르고 효율적입니다.

 

  1. 최소한의 부팅 프로세스
  • 전통적인 운영체제나 가상 머신은 시작할 때 많은 초기화 과정과 프로세스를 거쳐야 합니다.
  • 반면, 컨테이너는 애플리케이션 실행을 위한 최소한의 프로세스만 시작하므로 시작 시간이 크게 단축됩니다.

 

  1. 이미지 기반의 구조
  • 컨테이너는 미리 준비된 이미지를 바탕으로 실행됩니다.
  • 이 이미지에는 실행에 필요한 모든 파일과 설정이 포함되어 있기 때문에 추가적인 설정 또는 초기화 과정이 필요 없습니다.
반응형

'개발 > Docker' 카테고리의 다른 글

Docker File, Docker Compose 정의 및 사용 방법  (1) 2023.12.28

+ Recent posts