대표적인 파일 적재 형태

데이터를 적재하는 파일 형식은 대표적으로 2가지 방법이 있다.
Data in Row Format (행 기반), columnar file format (열 기반) 2가지 방법이 있다( 식견이 좁아 이 2개만 아는 것 일 수 있다.)

name email phoneNum
tom tom@gmail.com 010-0000-0001
justin justin@gmail.com 010-0000-0002
kim kim@gmail.com 010-0000-0003
  • 위와 같은 테이블이 존재한다 가정하고 아래 설명을 하겠습니다.

Data in Row Format (행 기반)

많은 사람들이 사용하는 Mysql 등 Row orented databased 에서 사용하는 파일 형태이다.

  • 간단하게 사진으로 보여주면 아래와 같은 형식으로 계속 옆으로 붙는다고 생각하면 된다.
    Pasted image 20231206140619.png
# CSV
name,email,phonNum
tom    , tom@gmail.com    , 010-0000-0001
justin , justin@gmail.com , 010-0000-0002
kim    , kim@gmail.com    , 010-0000-0003

# TSV
# 실제로는 tab으로 구분하지만, 보기 편하기 위해 줄을 맞 
name     email              phonNum
tom      tom@gmail.com      010-0000-0001
justin   justin@gmail.com   010-0000-0002
kim      kim@gmail.com      010-0000-0003

# JSON
{
	{name : tom    , email : tom@gmail.com    , phoneNum : 010-0000-0001} ,
	{name : justin , email : justin@gmail.com , phoneNum : 010-0000-0002} ,
	{name : kim    , email : kim@gmail.com    , phoneNum : 010-0000-0003}
}

위와 같이 본다면 CSV는 \n이 header가 되고, Json은 ,가 header가 된다고 봐도 될 것 같다.

  • 장점
    • 삽입 삭제에 용이하다
      • 그럼으로 쓰기 집약적인 작업에 적합하
      • 위에 코드와 같이 단순히 뒤에 붙여 넣으면 되기 때문 !
    • 모든 파일에 접근할 때 columnar보다 사용하기 좋다.
  • 단점
    • 데이터 집합 조회 시 성능 저하
      • 조회할 때 매번 모든 row를 읽어서 처리하기 때문

columnar file format (열 기반)

Spark ,Hive, 등에서 사용되는 파일 형식이다.
즉, 보통 대용량 데이터 처리할 때 많이 사용한다. (이때만 사용하는 것은 아니지만…?)
대표적으로 Parquet, ORC…등이 존재한다.
csv처럼 파일을 열어서 읽어서 보려고 했는데, 제대로 오지 않고, 검색하면 어떤 방식으로 적재가 되는 도식화된 사진만 있어
임의의 모양으로 예시를 들겠다.

name    |type-String|len-10 : tom          , justin          , kim
email   |type-String|len-10 : tom@gmail.com, justin@gmail.com, kim@gmail.com
phonNum |type-String|len-10 : 010-0000-0001, 010-0000-0002   , 010-0000-0003

대충 예시를 들면 위와 같다.
즉 열 기반이기 때문에 매번 Header를 추가하지 않고, 구분자만 추가하여 header에 사용되는 메모리를 절약할 수 있다.

  • 장점
    • 특정 칼럼만 읽어 처리하여 읽기 성능이 좋다
      • 예를 들어 select name,email from userTB where name = 'tom' 와 같은 조건의 쿼리문이 있다 예를 들면
      • where name = 'tom' 조건에 의해 name을 갖고 있는 칼럼만 읽어서 해당 인덱스를 가져온다
      • select name,email 이기 때문에 해당 name,email칼럼만 읽어서 조회하면 된다
      • 그로 인해 phonNum이라는 칼럼은 읽어드릴 필요가 없어진다. 그럼으로 보다 우수한 조회 성능을 갖을 수 있다
    • 압축 시 보다 좋은 성능을 보여준다
      • 100%는 아니지만, 같은 칼럼은 비슷한 값이 들어있기 때문에 보통은 최적화가 가능하다
      • 그럼으로 대용량 데이터 처리 할 때 용이하다
  • 단점
    • 데이터 삽입 시 데이터의 마지막 위치를 파악해야 한다.
    • 레코드 재 구성 시 느리다.
      • 각 행에서 세그먼트를 하나씩 읽어야 하기 때문
    • 파일을 읽기 전에 메타 정보를 읽고 행을 재 구성하기 때문에 CPU/ RAM등 리소스 소모가 더 크다

결론

결론적으로 Row Oriented와 Col Oriented는 아래와 같은 차이를 보인다.
어떤 것이 100%더 좋다는 없다고 생각한다.
단지 어떤 상황에 어떤 것이 더 적합한 것만 있는 것 같다.
Pasted image 20231206155149.png

[ Reference ]


개인적으로 공부한 내용 포스팅 중
잘못된 정보는 지적해주시면 좋겠습니다!

SparkSql?

Spark에서 RDD는 값은 표현하지만, Schema에 대한 방법이 없는데 이것을 대체하는 방법이라고 보면된다.
간단히 말하면 Spark에서 Hive 혹은 Mysql과 같은 RDB의 SQL을 사용할 수 있게 만들어 주는 것이라고 보면 쉽다

  • SQL작성시 ANSI-SQL 및 Hive-QL문법을 사용가능하다.
    • Hive-QL문법을 대다수 지원하지만, 모두 지원하는 것은 아니다 예외 항목이 있으니 홈페이지를 확인해보는 것이 좋다
    • 2.0버전부터 SQL:2003표준을 지원한다

방식

기본적으로 Spark에서 데이터를 다루는 방법은 SQL를 사용하는것 혹은 DataSet API을 사용하는 방법이 있다.

  • Dataset

주요 프로그래밍 구성요소

SparkSession

  • RDD 사용시 SparkContext를 사용한것 처럼 DataSet을 사용할 때 SparkSession을 사용한다
  • UDF를 등록하기 위한 목적으로 사용
  • 생성 기본 형태
    • val ss = SparkSession.builder().config(conf).getOrCreate()
  • Spark 2.0부터 사용됨 기존에는SQLContext, HiveContext를 구분하여 사용했다
    • 2.0버전부터는 Hive를 기본 지원하기 때문에 SparkSession을 사용하면 된다
      • 지원을 한다는 것 이지 필수적으로 hive를 필수로 사용해야 하는 것은 아니다
      • 만약 Hive를 사용하고 Hive를 사용하고 싶다면, hive-site.xml, core-site.xml, hdfs-site.xml을 spark의 conf 디렉토리에 추가하면 된다
        • 저게 싫다면 spark-submit의 경우 --file 에 추가해도 된다.
      • .enableHiveSupport() 를 추가해주면 된다.

DataSet

  • 분산 오브젝트 컬렉션에 대한 프로그래밍 모델
    - Transformation, Action 연산을 포함하고 있다.
    • Spark 1.6 버전부터 DataFrame이라는 API를 사용함
    • Spark 2.0 버전부터 Dataset이 Spark SQL의 Main API로 지정
      • 이때부터 DataFrame은 미지원
        • Scala에서는 Type Alias를 허용 하여 하위 호환 유지가 됨.
          • DataSet을 따라 들어가보면 아래와 같이 구성되어 있다.
          • def toDF(): DataFrame = new Dataset[Row](sparkSession, queryExecution, RowEncoder(schema))
          • 즉 DataFrame이 있긴 하지만, Dataset으로 대체 됐다고 보면 된다.

DataFrame

  1. DataSet이 나오기 전에 사용하던 DataSet
  2. 맞는 표현은 아니지만, 간단한 비유로는 Row 와 Column구조를 가진 RDD
    1. RDD와 같이 분산 데이터 처리를 위한것.
    2. RDD : value에 초점을 맞춤
    3. DataFrame : value + schema를 다룸
  3. Row타입을 사용한다

DataFrameReader / DataFrameWriter

  1. DataFrameReader
    1. SparkSession.read를 이용하여 메소드 접근
      1. 데이터 소스를 지정하여 데이터를 읽어 데이터 프레임을 생성해준다
  2. DataFrameWriter
    1. Dataset.write를 이용하여 특정 데이터 소스로 적재한다.

Row, Column

  1. SQL의 Row,Column과 같은 표현 모델이라고 생각하면 된다.

functions

  1. 데이터 처리시 사용하는 API
    1. select, sum, filter 등 여러가지 메소드들이 존재한다
      1. 공식 docs 에서 확인할 수 있다

StructType / StructField

  1. 스키마 정보를 정의하는 API
  2. StructType (List(StructField,StructField,StructField)) 와 같은 형식으로 생성한다(Scala)

GroupedData, GroupedDataSetP

  1. groupBy 메소드 등에 이해 군집 연산을 수행할 때 사용

개인적으로 공부한 내용 포스팅 중
잘못된 정보는 지적해주시면 좋겠습니다!

'프로그래밍 및 IT > Spark' 카테고리의 다른 글

spark-Setting  (0) 2023.11.28
spark-scheduling  (0) 2023.11.28
WordCount  (0) 2023.10.13
RDD Action  (0) 2023.10.13
RDD Transformation  (0) 2023.10.13

Spark Setting

Spark를 실행할 때 여러가지 설정을 할 수 있다.
상세한 정보들은 너무 많기 때문에 help 명령어를 사용하여 어떤 설정을 할 수 있는지 확인해 볼 수 있다.
Spark 공식홈페이지에서 본인이 사용하는 Spark 버전에 따라 확인해봐도 된다.

간단 예시 spark-submit 예시

spark-submit \
  --class {실행할 파일의 클래스} \
  --name {어블리케이션 명} \
  --master {클러스터 메니져 정보} \
  --deploy-mode {디플로이 모드} \
  --files {추가할 파일} \
  --jars {추가할 Jars 파일들} \
  --conf {추가할 설정} \  
  --driver-cores {드라이버 코어수} \
  --driver-memory {드라이버 메모리} \
  --executor-cores {익세큐터 코어수} \
  --executor-memory {익세큐터 메모리} \
  --num-executors {익세큐터 수} \
  {실행할 파일 경로}

위와 같이 Spark Submit할 때 해도 되지만, spark-defaults.conf에 미리 설정하여 사용해도 된다.
Spark Submit혹은 spark-defaults.conf에 추가한 값들이 모여 Spark Properties에 반영된다.
설정 우선순위 : code -> spark-submit -> spark-defaults.conf

[ Reference ]


개인적으로 공부한 내용 포스팅 중
잘못된 정보는 지적해주시면 좋겠습니다!

'프로그래밍 및 IT > Spark' 카테고리의 다른 글

SparkSql  (0) 2023.11.28
spark-scheduling  (0) 2023.11.28
WordCount  (0) 2023.10.13
RDD Action  (0) 2023.10.13
RDD Transformation  (0) 2023.10.13

Spark-Scheduling?

개인적으로 Spark를 사용하는 이유는 cluster-mode를 사용하기 위해라고 생각한다
Yarn등을 이용하여 각 Driver,Excutor에게 core,memory등을 할당 하는데, 많이 할당한다고 항상 좋은 결과를 보는 것은 아니다
어디서 본지 기억이 나지 않지만, core는 1~5개, memory는 4gb이상을 사용하는 것이 좋다고 봤었다.

Cluster Scheduling

Static resource allocation

정적(고정) 자원 할당

  • 명칭 그대로 최초 할당한 그대로 어플리케이션이 종료될 때 까지 자원을 점유하는 방식
  • Pipe line에 따라 데이터를 처리하여 필요한 자원 사전 계산 후 할당하면 좋은 방식이다.

Dynamic resource allocation

동적 자원 할당

  • 자원을 필요에 따라 동적으로 할당하는 방식

    • Spark-Shell , 혹은 web기반으로 동작하면 항상 많은 자원을 할당받아 자원 낭비가 발생할 수 있는 상황에 합리적인 선택
  • 공통

    • spark.dynamicAllocation.enabled true 설정을 해야한다
  • Standalone

    • spark.shuffle.service.enabled true
  • Yarn

    • 모든 node manager에 spark-{version}-yarn-shuffle.jar를 class path등록해야 한다
    • yarn-site.xml에 아래와 같은 설정이 있어야 한다.(안 되어 있으면 설정 후 재시작)
    	<property>
            <name>yarn.nodemanager.aux-services</name>
            <value>mapreduce_shuffle,spark_shuffle</value>
        </property>
        <property>
            <name>yarn.nodemanager.aux-services.spark_shuffle.class</name>
            <value>org.apache.spark.network.yarn.YarnShuffleService</value>
        </property>
        <property>
            <name>spark.shuffle.service.enabled</name>
            <value>true</value>
        </property>
    
  • yarn에서 별도 Shuffle Service를 실행시킨 이유는 동작 도중 Executor가 제거될 수 있기 때문

    • Mapper에 저장된 데이터Reducer단계에 Network를 통해 데이터를 읽어 가는데 이때 Executor가 삭제되면 해당 데이터는 삭제
    • 그러한 문제가 발생하지 않기 위해 Shuffle data를 따로 관리 할 수 있는 Shuffle Process를 설정하는 것

Application Scheduling

Spark Context는 기본적으로 Multi-Thread 방식으로 실행된다.
그로인하여 N+1개의 Action Function을 동시 실행해도 문제가 발생하지 않는다.

  • Scheduling으로 FIFO방식으로 구동 된다
    • 후속 작업은 이전 작업이 끝날 때 까지 대기해야한다
    • Fair scheduler 방식도 가능하다
      • Round robin
    • 설정
      • Code 단 : conf.set("spark.scheduler.mode", "Fair")
      • spark-default.conf에서 설정해도 된다.

fairscheduler.xml에 poll 설정을 하여 원하는 Pool이용하는 코드를 작성할 수 있다

<allocations>
  <pool name="production">
    <schedulingMode>FAIR</schedulingMode>
    <weight>1</weight>
    <minShare>2</minShare>
  </pool>
  <pool name="test">
    <schedulingMode>FIFO</schedulingMode>
    <weight>2</weight>
    <minShare>3</minShare>
  </pool>
</allocations>
  • fairscheduler.xml에 기본적으로 작성되어있는 것을 가져왔다.
    • weight : 우선순위
    • minShare : Pool의 최초 CPU Core
val conf = new SparkConf()  
  .setAppName("application_name")  
  .setMaster("local[*]")  
  .set("spark.local.ip", "localhost")  
  .set("spark.driver.host", "localhost")  
  // .set("spark.scheduler.mode", "Fair")  //이와 같이 특정 scheduler 사용가능
  .set("spark.scheduler.allocation.file" ,"file path") // 
val sc = new SparkContext(conf)
sc.setLocalProperty("spark.scheduler.pool", "production") // pool설정  
sc.setLocalProperty("spark.scheduler.pool", null) // 기본 pool설정
  • 위와 같이 사용하면 scheduler mode : FAIR , 최소 CPU core : 2
  • 이와 같이 N+1명의 사용자가 접근하면 사용자에 따른 자원 할당을 할 수 있다

[ Reference ]


개인적으로 공부한 내용 포스팅 중
잘못된 정보는 지적해주시면 좋겠습니다!

'프로그래밍 및 IT > Spark' 카테고리의 다른 글

SparkSql  (0) 2023.11.28
spark-Setting  (0) 2023.11.28
WordCount  (0) 2023.10.13
RDD Action  (0) 2023.10.13
RDD Transformation  (0) 2023.10.13

Docker Compose?

간단히 말하면 Dockerfile을 이용하여 생성한 Docker Image를 Services로 묶어 구성을 작성한 Yaml파일을 관리 도구
추가적으로 작성하자면, Dockerfile를 이용하여 구축 시 Docker Run에 상당히 많은 옵션값들을 작성해야 한다
Docker Compose를 이용하면 해당 옵션들을 작성 후 간단한 명령줄로 Docker Container를 생성 할 수 있다

요소들

설정할 수 있는 것들이 너무 많아 모든 것을 정리하지는 않음.
e.g blkio_config, cpu, mem

Expose

컨테이너 간 Port 노출
Host에게 노출되는 것은 아님

port

Host에게 Port 노출

Network

Container 에서 사용할 Docker Networks 지정

Network_mode

Container의 Network 모드 설정

None : Network 미사용
Host : Host의 Network 사용
service:{Name} : 특정 Service에만 접근 허용

CheatSheet


version: "3.7" # compose file format설정.

servies : # services 정의, 클러스터 정의라고 봐도 무관할듯
	container_name : # 생성할 container 명
		image : Image_Name #사용할 Image
        attach : true # 서비스 로그 수집 여부 
		build  :  # 아래 옵션을안 쓰고 경로를 작성해도 무관
		  context: . # Docker file 경로
	      dockerfile : Dockerfile # Docker file 명
		container_name: my-web-container # 컨테이너에 부여할 이름
		labels:
	      # 방식 1
		  com.example.description: "Accounting webapp"
		  # 방식 2
		  - "com.example.description=Accounting webapp"
		# 환경 변수
		env_file: # 환경 변수 파일 추가
			- a.env
			- b.env
		environment: #환경변수 추가
			# 방식 1
			EVN_VAL1: VAL1
			EVN_VAL2: VAL2
			EVN_VAL3
			# 방식 2
			- EVN_VAL1=VAL1
			- EVN_VAL2=VAL2
			- EVN_VAL3
		restart : unless-stop # 재시작 여부
		
		# 실행
		command : # dockerfile CMD Overrides 
			# 방법 1
			sh -c "/script1.sh &&/script2.sh"
			
			# 방법 2
			sh -c "
			/script1.sh &&
			/script2.sh
			"
			
			# 방법 3
			- sh
		    - -c
			- |
			  /script1.sh
			  /script2.sh
		entrypoint : # dockerfile entrypoint Overrides 
  
		# 종속
		depends_on : # 종속관계 추가
			containerName : # 종속될 컨테이너
				restart : true/false # 종속된 컨테이너 업데이트 시 재 시작
				condition : service_healthy # 상태
		healthcheck:
		  test: ["CMD", "curl", "-f", "http://localhost"]
		  interval: 1m30s
		  timeout: 10s
		  retries: 3
		  start_period: 40s
		  start_interval: 5s
		# 네트워크
		expose :
			"8080"
		port :
			8080:8080
		network_mode : "host"
		networks:
	      - bapa-network
	      - bapa2-network

Network

Host 에서 생성한 네트워크 혹은 Docker 내부의 네트워크를 사용하기 위해 사용

services :
	....

networks :
	networName : 
		driver : driver Name
		driver_opts:
			driver_val : driver_val # Driver의 옵션 추가
		external : true #외부 네트워크 사용
		internal : false # 외부와 격리된 독립 네트워크
		label : metadata # 해당 네트워크의 메타 정보 저장
		name : network name # 특수 문자를 포함한 네트워크 잠조 시 사용
		ipam :
			driver : ipam DriverName
			config :
			  - subnet: 172.28.0.0/16
	          ip_range: 172.28.5.0/24
	          gateway: 172.28.5.254
	          aux_addresses:
	            host1: 172.28.1.5
		    options :
			    driver_val1: driver_val

Volumes

docker에 추가 volumes을 사용하고 싶으면 아래와 같이 정의하여 사용할 수 있다.

services :
	....
volumes:
	volumes_name : # 볼륨 명
		name : "volumes_name" # volume의 다른 이름을 붙여 사용하고 싶다면 사
		driver : drive_name # 사용할 docker volume driver
		driver_opts :  # docker volume driver 설정, key-value 로 사
			key : value
		    ...
			
	    external: true/false # 외부 volume 여무, 즉 기존에 생성한 volumes를 사용 할 것인가 ?
	    labels : # key-values로 구성된 volume의 메타데이터 설정
		    key : value
		    ...

그 외

# Extension
# 간단히 생각하면 변수 선언이라고 보면된다.
# x-{name} : &{name}
# Superset 예시
x-superset-image: &superset-image apachesuperset.docker.scarf.sh/apache/superset:${TAG:-latest-dev}
x-superset-common: &superset-common
  image: apachesuperset.docker.scarf.sh/apache/superset:${TAG:-latest-dev}
  depends_on:
    - db
    - redis

# Fragments
# 간단히 말하면 Extension을 사용하는 것.
# $를 이용하여 생성, *를 이용하여 사용
services :
  superset :
    <<: *superset-common # superset-common에 선언된것을 모두 사용하겠다는 의미
    image: *superset-image # 이와같이 1개만 가져와서 사용할 수 있다.

# interpolation
# 변수를 사용할 대 Default값을 설정하는 느낌이다.
# Trino 이미지 가져오는 예시
# TRINO_IMAGE_NAME 이 변수에 값이있으면 TRINO_IMAGE_NAME를 사용하고 없으면 trinodb/trino:433를 사용하겠다
image: ${TRINO_IMAGE_NAME:-trinodb/trino:433}

# 아래와 같이 작성하면 TRINO_IMAGE_NAME값이 없으면 Compose가 실패한다
image: $$TRINO_IMAGE_NAME

[ Reference ]


개인적으로 공부한 내용 포스팅 중
잘못된 정보는 지적해주시면 좋겠습니다!

'프로그래밍 및 IT > docker' 카테고리의 다른 글

docker  (0) 2023.11.22

DockerFile?

docker에서 사용하는 Vagrant 파일이라고 생각하면 편하다.
미리 어떤 이미지를 이용하여 어떤 로직을 이용해 환경을 구축 할 것다! 라는 것을 구성한다
사용할 이미지, 파일 실행, 네트워크 등등을 작성 할 수 있다.
실제 이해한게 맞는지 모르겠지만, Dockerfile은 기본적으로 Image파일을 생성하기 위해 사용하는 것으로 이해했다.
물론 그것에 CLI명령어를 합쳐서 사용할 수 있지만, 다중 컨테이너를 사용하려면 docker-compose를 사용하는 것이 좋아보인다.

작성 방법

DockerFile에 작성된 주석은 실제 실행 시에는 제거되고 실행된다.

FROM

Docker Image 가져오기

  • Docker hub에 존재하는 Image를 다운로드 받아서 사용 혹은 생성한 Local Image를 사용한다
    • build 전에 docker pull을 이용하여 미리 다운 받아 사용 가능하다
  • 형식은 보통 서비스명:버전 형식으로 구성이 되는 것으로 보인다.
  • 만약 build 시 예외시키고 싶은 디렉토리, 파일 등이 존재한다면, .dockerignore File을 생성하면 된다.
# .dockerignore 예시
**/__pycache__/
tests/
docs/
# FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
# FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
# 아래 2가지 방법은 동일한 결과를 보여준다.
ARG AIRFLOW_IMAGE:apache/airflow:2.6.3-python3.7
FROM ${AIRFLOW_IMAGE}

FROM apache/airflow:2.6.3-python3.7

실행

크게는 RUN과 CMD가 존재한다

  • RUN
    • 용도
      • Docker Image를 Build 시 실행할 명령어
      • mount , network, security 설정을 할 수 있다.
        • mount : FS 를 추가하는 것.
          • 간단히 말하면 HDD/SSD같은 Disk 혹은 usb등을 PC에 삽입하고 인식시키는 것
        • 상세 설정이 필요하면 위 링크로 들어가서 확인해보자
    • \ 을 마지막에 붙여서 여러 개행하여 사용 할 수 있다.
  • CMD
    • 용도
      • Container 최초 실행 시 실행할 명령어
  • ENTRYPOINT
    • 용도
      • Container 실행 시 실행할 명령어
        • 어플리케이션 실행 명령어과 같은 것들을 주로 사용하는 것으로 보임.
# RUN은 기본적으로 /bin/bash -c를 기본값으로 실행시킨다.
# RUN 명령어
# RUN ["명령어", "param1", "param2"]
# 아래 3개는 동일하게 echo 'hello'를 출력한다.
RUN echo 'hello'
RUN /bin/bash -c echo 'hello'
RUN ["/bin/bash", "-c", "echo hello"]
# Mount 
RUN --mount=[type=<TYPE>][,option=<value>[,option=<value>]...]
# Network
RUN --network=<Type>
# Security
RUN --security=<Type>

# CMD
# 형식, 사용 방법은 RUN과 동일하다.
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2

# ENTRYPOINT
ENTRYPOINT ["executable", "param1", "param2"]
# 실제로 가장 많이 본 형식은 아래와 같이 sh 파일을 copy하여 사용하는 것을 많이 봤다.
ENTRYPOINT ["filePath/entrypoint.sh"]

MetaConfig

  1. LABEL
    1. key=value 형식으로 image에 Meta정보를 삽입하는 것
# 공백으로 구분하여 여러 LABLE을 추가 가능
LABEL version="0.0.1" createBy="bapa"
LABEL description="\
이렇게 이미지에 대한 정보를 작성할 수 있습니다.
This is how you can write information about an image.
"

변수

  1. ENV
    1. 환경 변수 등록
  2. ARG
    1. 임시 변수로써 dockerfile 내부에서만 사용되는 변수
# =은 생략 가능하
ENV key1=val1 key2=val2
ARG key=val

Network

  1. EXPOSE
    1. 외부로 노출시킬 Port 설정
# 형식
EXPOSE [<external port>]:<internal port>/[<Protocol>]
# 아래 3개는 동일
EXPOSE 80 
EXPOSE 80:80
EXPOSE 80:80/tcp
# 만약 내부 외부 포트를 다르게 하고 싶다면 아래와 같이 변경시킬 수 있다.
EXPOSE 81:80/udp 

마운트

  1. VOLUME
    • docker 영역에서 생성한 Volume과 마운트 하는 것
  2. Bind-Mount
    • Host영역에서 관리 가능한 Volume과 마운트 하는 것
    • RUN 명령어를 이용하여 마운트
    • docker doc 이곳에 적혀있는 것을 보면 Volume과 차이를 볼 수 있다.
      • the first field is the path to the file or directory on the host machine.
# 형식
VOLUME ["/data"]
VOLUME /data

# 형식
RUN --mount=[type=<TYPE>][,option=<value>[,option=<value>]...]

WORKDIR

RUN,COPY 등 이 실행될 경로
간단히 말하면 Linux의 CD명령어를 이용하여 디렉토리 변경하는 것 이라고 보면된다.
그럼으로 WORKDIR를 이용하여 명령어 실행 위치를 변경 할 수 있다.

# 형식
WORKDIR /path/to/workdir

파일 복사

  1. ADD
    1. 압축된 파일을 풀어서 복사한다.
    2. URL 혹은 local path를 이용하여 복사
  2. COPY
    1. 파일 복사
    2. Local path만 지원
    3. –parents 옵션 추가 시 src의 디렉토리 경로까지 같이 복사 됨
ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src> <src> <src>... <dest>
ADD [--chown=<user>:<group>] [--chmod=<perms>] ["<src>","<src>","<src>"... "<dest>"]

COPY [--chown=<user>:<group>] [--chmod=<perms>] <src> <src> <src>... <dest>
COPY [--chown=<user>:<group>] [--chmod=<perms>] ["<src>","<src>","<src>"... "<dest>"]

# --parents 추가시 아래와 같이 복사됨/
COPY ./y/a.txt /no_parents/
# /no_parents/a.txt
COPY --parents./y/a.txt /parents/
# /parents/y/a.txt

사용자 권한

  1. USER
    1. 실행 권한을 적용
# 형식
# USER <user>[:<group>]
# USER <UID>[:<GID>]

USER root
# root 권한으로 실행
USER shb
# shb 권한으로 실행

개인적으로 이해한 그림

Pasted image 20231123112207.png**

[ Reference ]


개인적으로 공부한 내용 포스팅 중
잘못된 정보는 지적해주시면 좋겠습니다!

+ Recent posts