Docker기반 Redis 구축하기 - (3) Dockerfile

Dockerfile 이란?

이전 예제에서는 Docker Hub에 등록된 이미지를 다운받아서 사용하였고, 이미지를 바탕으로 Container를 생성 할 수 있었습니다. Docker Hub에는 각 소프트웨어에 대한 공식이미지도 있지만, Docker Hub 사용자들이 공식이미지를 바탕으로 커스터마이징하여 배포한 이미지도 등록되어 있습니다.

어떻게 이미지를 빌드하고 배포 할 수 있었을까요? Dockerfile을 이용한 이미지 빌드를 이용하면 가능합니다.

Dockerfile은 이미지를 바탕으로 몇가지 명령을 실행 할 수 있는 로직을 담은 파일입니다. Dockerfile을 통해 더 유연하게 이미지에 대한 설정을 변경할 수 있고, 그 설정을 이미지에 담아 배포 할 수 있습니다.

물론 Docker run 구문에서 options을 사용하여 같은 기능을 하도록 구현 할 수 있지만, Dockerfile로 작성하게 되면 향후 유지보수가 쉬워지고 run 구문에 대한 options을 전부 기억하지 않아도 되는 장점이 있습니다.

이번 장에서는 Dockerfile을 작성하는 명령어를 위주로 알아보겠으며, 간단한 예제 Dockerfile을 보도록 하겠습니다.

Dockerfile 사용방법

Dockerfile을 이용한 docker build

1
2
#dockerfile이 위치한 directory의 dockerfile을 가지고 build합니다.
docker build -f /path/to/dockerfile

Dockerfile을 구성하는 핵심 명령어

From - Dockerfile의 시작

From 명령어는 어떤 이미지를 바탕으로 container를 빌드 할 것인지 명시합니다.

1
2
# redis:5.0-alpine 이미지를 바탕으로 빌드
From redis:5.0-alpine

CMD - Dockerfile의 끝

  • CMD명령은 Container가 docker run, docker start 명령을 실행 하였을 때 실행 됩니다.
  • 보통은 해당 프로그램을 실행시키는 명령을 사용합니다. ( ex> startup.sh)
  • CMD 명령은 Dockerfile에서 단 한번만 사용할 수 있습니다.

명령어 예제

1
2
3
4
5
6
7
8
# 일반적인 실행 방법
CMD ["execute.sh", "param1", "param2"]

# Entrypoint 실행을 위한 Default Parameter - Entrypoint를 위한 파라미터를 제공
CMD ["param1", "param2"]

# shell form
CMD execute.sh param1 param2

CMD 구문 사용 시, 주의사항!

1
2
3
4
> docker build -f ./dockerfile test
> # Container 생성 시, docker run [이미지] [실행파일 또는 명령] 입니다.
> docker run test echo "test!"
>

위 예시 처럼 run 명령 시, 이미지 명 뒤에 실행파일이나 명령어가 오게되면 CMD에 설정된 명령은 무시되고 docker run 구문에서 사용된 명령이 CMD 대신 실행됩니다.

ENTRYPOINT

  • ENTRYPOINT명령은 Container가 docker run, docker start 명령을 실행 하였을 때 실행 됩니다.
  • 보통 스크립트를 실행하거나, 실행명령을 수행하게 됩니다.
  • ENTRYPOINT명령은 Dockerfile에서 단 한번만 사용가능 합니다.
  • 기본적으로 FROM에서 설정한 이미지의 /bin/sh 파일을 기반으로 실행되며, 이미지에 /bin/sh 파일이 없는 경우 실행이 불가능 합니다.

ENTRYPOINT 사용 예시

1
2
ENTRYPOINT ["docker-entrypoint.sh"]
ENTRYPOINT ["docker-entrypoint.sh", "--param1=true", "--param2=1"]

1
2
3
#run 명령의 options으로 구현한 방식
#이러한 방식으로도 사용할 수 있지만, 추천하지 않는 안티패턴입니다.
docker run --entrypoint="docker-entrypoint.sh" test

Dockerfile에서 자주 사용하는 명령어

ADD - 파일을 Container에 추가

  • Container 내부에 Host OS의 파일을 추가하려고 할 때 사용합니다.
  • ADD <Host OS의 파일 경로> <Container의 파일 경로> 로 작성합니다.
  • <Container의 파일경로>란에 파일 경로만 적는 경우 파일 명은 Host OS의 파일명을 사용합니다.
  • <Host OS의 파일경로>는 현재 컨텍스트보다 상위 파일, 디렉터리나 절대경로는 사용 불가
  • <Container의 파일경로>는 반드시 절대경로로 사용합니다.
  • 와일드카드(*)를 이용하여 특정파일만 복사도 가능합니다.
  • Host OS에 있는 압축파일(tar.gz, tar.bz2, tar.xz)은 압축을 풀어서 Container에 추가됩니다. (Container에 압축 해제 된 파일들이 추가됨)
  • 인터넷에 있는 파일 URL은 압축만 해제된 뒤, tar파일만 추가됩니다.
  • Directory 전체를 추가 시, .dockerignore 파일에 설정한 파일과 디렉터리는 제외됩니다.
  • ADD로 추가되는 파일은 root root 기존 권한을 따릅니다 (단, URL로 추가된 파일의 경우 600)

1
2
3
4
5
6
7
8
ADD ../file.sh /home/file.sh (x) #상위 디렉터리 사용x
ADD /home/user/file.sh /home/file.sh(x) #절대경로 사용x
ADD file.sh ../../file.sh (x) #<Container 파일경로>는 상대경로 사용x

ADD file.sh /home/file.sh (O) #가급적이면 Dockerfile과 같은 경로상에 두는 것이 좋다.
ADD *.sh /home (O) # 와일드카드를 이용하여 복사 가능
ADD compress.tar.gz / # Container / 경로에 compress.tar파일의 풀어진 형태로 파일 추가
ADD http://file.co.kr/file/1234.tar.gz / # Container 내부의 / 경로에 1234.tar.gz 파일 추가

COPY - 파일을 Container로 복사

  • ADD의 기능과 거의 유사합니다.
  • COPY <Host OS의 파일 경로> <Container의 파일 경로> 로 작성합니다.
  • <Container의 파일경로>란에 파일 경로만 적는 경우 파일 명은 Host OS의 파일명을 사용합니다.
  • <Host OS의 파일경로>는 현재 컨텍스트보다 상위 파일, 디렉터리나 절대경로는 사용 불가
  • <Container의 파일경로>는 반드시 절대경로로 사용합니다.
  • 와일드카드(*)를 이용하여 특정파일만 복사도 가능합니다.
  • Host OS에 있는 압축파일(tar.gz, tar.bz2, tar.xz)은 압축을 풀지않고 그대로 복사됩니다. (ADD와 차이점)
  • 인터넷에 있는 파일 URL은 사용 불가. (ADD와 차이점)
  • Directory 전체를 추가 시, .dockerignore 파일에 설정한 파일과 디렉터리는 제외됩니다.
  • COPY로 추가되는 파일은 root root 기존 권한을 따릅니다

1
2
3
4
5
6
7
8
COPY ../file.sh /home/file.sh (x) #상위 디렉터리 사용x
COPY /home/user/file.sh /home/file.sh(x) #절대경로 사용x
COPY file.sh ../../file.sh (x) #<Container 파일경로>는 상대경로 사용x

COPY file.sh /home/file.sh (O) #가급적이면 Dockerfile과 같은 경로상에 두는 것이 좋다.
COPY *.sh /home (O) # 와일드카드를 이용하여 복사 가능
COPY compress.tar.gz / (O)# Container / 경로에 compress.tar파일이 복사
COPY http://file.co.kr/file/1234.tar.gz / (X) # COPY는 인터넷 파일URL 사용 불가

RUN - Container 내부에서 명령 실행

  • 기본적으로 /bin/sh 파일로 실행됩니다.
  • Window의 경우 cmd 기반 명령을 수행합니다.

Dockerfile 내 RUN 명령어 사용법

1
2
3
4
5
6
# software 설치 명령 실행 (예시의 경우 yum이 Container내부에 설치되어야 합니다.)
RUN yum -y install software
# /usr/local/redis directory 생성
RUN mkdir -p /usr/local/redis
# execute.sh 파일 실행
RUN ["execute.sh", "param1", "param2"]

명령어의 길이가 긴 경우 \ 문자를 사용하여 append 가능합니다

1
2
3
RUN yum -y install software \
echo "install software" \
mkdir -p /usr/local/redis

ENV - Container 내부에서 사용할 환경 변수 추가

Container는 Host OS와 독립된 공간이기 때문에 Container 내부에서 사용 할 환경변수를 추가할 수 있습니다.

1
2
ENV LOCAL_PORT 80
ENV REDIS_HOME /usr/local/bin/redis

EXPOSE - Container의 Port 설정

  • Host OS - Container와 통신할 포트를 설정
  • EXPOSE는 Host OS와 연결만 할 뿐 외부에 노출 되지는 않습니다.
  • 포트를 노출 하기 위해서는 docker run -p 또는 -P 옵션 사용해야 합니다.

1
2
3
4
EXPOSE 80   #Container 내의 Web Server Port 노출
EXPOSE 6379 #Container 내의 Redis Server Port 노출

EXPOSE 80 6379 #포트 여러개 노출

VOLUME - 외부 볼륨 설정

  • Container 내부의 Directory와 Host OS의 Directory를 동기화 시키는 설정
  • log파일이나 설정파일은 보통 Container 내부에만 있는데 이를 Host OS에 동기화 하여 파일에 대한 접근이 가능하게 한다.

1
2
3
4
5
6
# Dockerfile volume 설정
VOLUME ["/data", "/var/log"]

# docker run 사용 시, volumn 설정
# -v 옵션을 사용하여 설정 -v <host 디렉터리>:<컨테이너 디렉터리>
docker run -v /host/os/data:/container/data app

WORKDIR - Container의 Work Directory 설정

  • RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리
  • 중간에 Directory가 변경되는 경우 바꿀수 있다.
  • 리눅스의 cd 명령어와 비슷하다.

1
2
3
4
5
6
7
8
9
WORKDIR /usr/local/bin
ADD redis.conf /usr/local/bin/redis.conf

WORKDIR /usr/local
ADD redis.log /usr/local/redis.log

WORKDIR var
WORKDIR lib
RUN touch file.sh # /var/lib/file.sh 생성

참고

  • http://pyrasis.com/book/DockerForTheReallyImpatient
  • https://docs.docker.com/engine/reference/builder