본문 바로가기
프로그래밍 놀이터/Settings

[Docker] Dockerfile 을 사용한 코드에 의한 서버 구축

by 돼지왕왕돼지 2020. 3. 24.

[Docker] Dockerfile 을 사용한 코드에 의한 서버 구축



-

Docker 에서는 인프라의 구성 관리를 Dockerfile 로 기술한다.

이 Dockerfile 에는 베이스가 되는 이미지에 각종 미들웨어를 설치 및 설정하고, 개발한 앱의 실행 모듈을 전개하기 위한 앱 실행 기반의 모든 구성 정보를 기술한다.





5.1. Dockerfile 을 사용한 구성 관리


* Dockerfile 이란?


-

Dockerfile 은 Docker 상에서 작동시킬 컨테이너의 구성 정보를 기술하기 위한 파이다.

docker build 명령은 Dockerfile 에 기술된 구성 정보를 바탕으로 Docker 이미지를 작성한다.




* Dockerfile 의 기본 구문


-

Dockerfile 은 텍스트 형식의 파일로 에디터 등을 사용하여 작성한다.

확장자는 필요 없으며, Dockerfile 이라는 이름의 파일에 인프라의 구성 정보를 기술한다.

Dockerfile 이외의 파일명으로도 작동하지만 그렇게 하면 이미지 빌드시 파일명을 명시적으로 지정해야 한다.



-

Dockerfile 의 기본 서식은 아래와 같다.

명령 인수


주요 명령은..

FROM : 베이스 이미지 지정

RUN : 명령 실행

CMD : 컨테이너 실행 명령

LABEL : 라벨 설정

EXPOSE : 포트 익스포즈

ENV : 환경변수

ADD : 파일/디렉토리 추가

COPY : 파일 복사

ENTRYPOINT : 컨테이너 실행 명령

VOLUME : 볼륨 마운트

USER : 사용자 지정

WORKDIR : 작업 디렉토리

ARG : Dockerfile 안의 변수

ONBUILD : 빌드 완료 후 실행되는 명령

STOPSIGNAL : 시스템 콜 시그널 설정

HEALTHCHECK : 컨테이너의 헬스 체크

SHELL : 기본 쉘 설정



-

Dockerfile 의 주석은 # 를 사용한다.




* Dockerfile 작성


-

Docker 컨테이너를 어떤 Docker 이미지로부터 생성할지라는 정보를 반드시 기술해야 한다.

이 이미지를 베이스 이미지라고 한다.


FROM [이미지명]

FROM [이미지명] : [태그명]

FROM [이미지명] @ [다이제스트]


ex) 

FROM centos:centos7

태그명을 생략하면 latest 가 적용된다.

이미지를 고유하게 특정할 때는 다이제스트를 이용한다.



-

Visual Studio Code 를 이용하면 더 쉽게 작성할 수 있다.





5.2. Dockerfile 의 빌드와 이미지 레이어


* Dockerfile 로부터 Docker 이미지 만들기


-

syntax)

$ docker build -t [생성할 이미지명]:[태그명] [Dockerfile의 위치]

-f 옵션으로 이름이 Dockerfile 이 아닌 Dockerfile 을 지정할 수 있다.

하지만 Dockerfile 이외의 이름인 경우 Docker Hub 에서 이미지의 자동 생성 기능을 사용할 수 없으므로 주의해야 한다.



-

ex)

$ docker build - < Dockerfile

표준 입력을 통해서도 빌드할 수 있다.

하지만 이 방법은 빌드에 필요한 파일을 포함시킬 수 없기 때문에, 예를 들면 ADD 명령으로 이미지 안에 파일을 추가할 수 없다.

그래서 Dockerfile 과 빌드에 필요한 파일을 tar 로 모아두고 표준 입력에서 지정한다.



-

Docker 는 이미지를 빌드할 때 자동으로 중간 이미지를 생성한다.

그리고 다른 이미지를 빌드할 때 중간 이미지를 내부적으로 재이용해서 빌드를 고속으로 수행한다.

이미지를 재이용하고 있을 때는 빌드로그에 Using cache 가 표시된다.

캐시를 이용하고 싶지 않다면 build 명령에서 --no-cache 옵션을 지정한다.




* Docker 이미지의 레이어 구조


-

FROM ubuntu:latest

RUN apt-get update && apt-get install -y- q nginx

COPY index.html /usr/share/nginx/html/ # Dockerfile 과 동일한 dir 에 index.html 이 있어야 한다.

CMD ["nginx", "-g", "daemon offl"]

위 4가지 명령을 수행하면서 중간중간 이미지를 만든다. (위에서는 4개의 중간이미지를 만듬)



-

Docker 이미지를 공유하는 서비스인 Docker Hub 는 전 세계의 엔지니어가 작성한 이미지를 공개하고 있다.

이미지는 OS 파일을 포함하고 있어 용량이 크다.

그래서 이미지를 레이어로 겹쳐서 작성함으로써 공통되는 이미지를 공유하여 관리한다.

Docker Hub 에서 이미지 ID 가 같은 것은 하나의 실체를 공유하여 사용한다.





5.3. 멀티스테이지 빌드를 사용한 앱 개발


-

앱 개발 시 개발 환경에서 사용한 라이브러리나 개발 지원 툴이 제품 환경에서 반드시 사용되는 것은 아니다.

제품 환경에는 앱을 실행하기 위해 최소한으로 필요한 실행 모듈만 배치하는 것이 좋다.

멀티스테이지 빌드 기능을 사용하면 하나의 Dockerfile 로 빌드 환경에 사용된 image 가 포함되지 않은 사용환경 image 를 만들 수 있다.




* Dockerfile 만들기


-

# 1. Build Image

FROM buildConfig


# Build

RUN build operation


# 2. Production Image. FROM 이 두번 나오는데, 이곳이 최종 빌드 포인트가 되어, build 과정의 이미지는 사용되지 않고 결과만 사용한다.

FROM mandatoryConfig


# Apply Build Result.

ENTRYPOINT ["./buildResult"]




* Docker 이미지의 빌드


-

일반 빌드 방식으로 빌드하면 된다. (docker build -t ... )




* Docker 컨테이너의 시작








5.4. 명령 및 데몬 실행


-

Docker 이미지를 만들려면 필요한 미들웨어를 설치하고 사용자 계정이나 디렉토리를 작성하는 등의 명령을 실행할 필요가 있다.

또한 이미지로부터 컨테이너를 생성했을 때 서버 프로세스 등을 데몬으로서 작동시킬 필요도 있다.




* 명령 실행(RUN 명령)


-

RUN 명령을 이용해 앱/미들웨어를 설치 및 설정하고, 환경 구축을 위한 명령을 실행한다.


syntax)

RUN [실행하고 싶은 명령]



-

RUN 명령은 shell 형식과 exec 형식으로 기술할 수 있다.


Shell 형식은 아래와 같다. 이렇게 하면 /bin/sh -c 를 사용하여 명령을 실행했을 때와 똑같이 작동한다.

Shell 형식 ex)

RUN apt-get install -y nginx


Exec 형식은 아래와 같다. /bin/sh 에서 실행되지만 쉘을 경유하지 않고 직접 실행한다. 따라서 $HOME 과 같은 환경변수를 지정할 수 없다. Exec 형식에서는 실행하고 싶은 명령을 JSON 배열로 지정한다.

다른 쉘을 이용하고 싶을 때는 RUN 명령에 쉘의 경로를 지정한 후 실행하고 싶은 명령을 지정한다.

Exec 형식 ex)

RUN ["bin/bash", "-c", "apt-get install -y nginx"]



-

RUN 명령은 Dockerfile 에 여러 개 기술할 수 있다.

그리고 그 명령은 기술된 내용에 따라 순서대로 실행된다.



-

이미지를 생성할 때 어떤 명령이 실행되는지를 확인하기 위해 docker history 를 사용할 수 있다.

syntax)

$ docker history <imageName>



-

Dockerfile 을 빌드하면 기술된 명령마다 내부 이미지가 하나씩 작성된다.

그래서 Dockerfile 의 명령을 줄이는 방법이 몇 가지 고안되어 있다.

# 이미지 2개

RUM yum -y install httpd 

RUM yum -y install php


# 이미지 1개

RUM yum -y install httpd php


RUN 명령은 \ 로 줄바꿈을 넣을 수 있다.




* 데몬 실행(CMD 명령)


-

RUN 명령은 이미지를 작성하기 위해 실행하는 명령을 기술하지만, 이미지를 바탕으로 생성된 컨테이너 안에서 명령을 실행하려면 CMD 명령을 사용한다.

Dockerfile 에는 하나의 CMD 명령을 기술할 수 있다.

만일 여러 개 지정하면 마지막 명령만 유효하다.


syntax)

CMD [실행하고 싶은 명령]



-

CMD 명령은 세 가지 기술 방법이 있다.


Exec 형식으로 기술한다.

Exec 형식 ex)

CMD ["nginx", "-g", "daemon off;"]


Shell 형식으로 기술한다.

Shell 형식 ex)

CMD nginx -g 'daemon off;'


ENTRYPOINT 명령의 파라미터로 기술 (다음 chap 에서 다룸)



-

패키지 관리 시스템은 앱 설치 시 발생하는 의존 관계를 모아서 관리하는 시스템이다.

Linux 에는 대표적인 몇 가지 패키지 관리 시스템이 있다.


YUM (Yellowdog Updater Modified) 

    CentOS 나 Fedora 같은 Red Hat 계열에서 사용하는 녀석

    OS 표준 저장소 외에 EPEL 이나 Remi 같은 외부 저장소도 이용할 수 있다.

    최근 버전에서는 DNF(Dandified Yum)도 사용되고 있다.


APT(Advanced Packaging Tool)

    Debian 이나 Ubuntu 같은 Debian 계열에서 사용하는 녀석.

    apt 또는 apt-get 을 사용하여 패키지를 조작한다.




* 데몬 실행 (ENTRYPOINT 명령)


-

ENTRYPOINT 명령에서 지정한 명령은 docker container run 명령을 실행했을 때 실행된다.


syntax)

ENTRYPOINT [명령]


Exec 형식으로 기술

Exec 형식 ex)

ENTRYPOINT ["nginx", "-g", "daemon off;"]


Shell 형식으로 기술

Shell 형식 ex)

ENTRYPOINT nginx -g 'daemon off;'



-

ENTRYPOINT 와 CMD 의 차이는 docker container run 명령 실행 시의 동작에 있다.

CMD 의 경우 컨테이너 시작 시에 실행하고 싶은 명령을 정의해도 docker container run 명령 실행 시에 인수로 새로운 명령을 지정한 경우 이것을 우선 실행한다.


ENTRYPOINT 명령에서 지정한 명령은 반드시 컨테이너에서 실행되는데, 실행 시에 명령 인수를 지정하고 싶을 때는 CMD 명령과 조합하여 사용한다.

ENTRYPOINT 명령으로 실행하고 싶은 명령 자체를 지정하고 CMD 명령으로는 그 명령의 인수를 지정하면, 컨테이너를 실행했을 때의 기본 작동을 결정할 수 있다.



-

# DockerFile

ENTRYPOINT ["top"]

CMD ["-d", "10"]


$ docker container run -it sample # top -d 10 이 실행된다.

$ docker container run -it sample -d 2 # top -d 2 가 실행된다.




* 빌드 완료 후에 실행되는 명령 (ONBUILD 명령)


-

syntax)

ONBUILD [명령]



-

syntax)

$ docker image inspect --format="{{ .Config.OnBuild }}" <containerName>

위 명령을 통해 OnBuild 값을 볼 수도 있다.




* 시스템 콜 시그널의 설정 (STOPSIGNAL 명령)


-

컨테이너를 종료할 때에 송신하는 시그널을 설정할 수 있다.

syntax)

STOPSIGNAL [시그널]




* 컨테이너의 헬스 체크 명령 (HEALTHCHECK 명령)


-

컨테이너 안의 프로세스가 정상적으로 작동하고 있는지를 체크하고 싶을 때는 HEALTHCHECK 명령을 사용한다.

syntax)

HEALTHCHECK [옵션] CMD 실행할 명령


옵션

--internal=n : 헬스체크 간격, 기본 30s

--timeout=n : 헬스 체크 타임아웃, 기본 30s

--retries=N : 타임아웃 횟수, 기본 3



-

예를 들어 5분마다 가동 중인 웹 서버의 메인 페이지를 3초 안에 표시할 수 있는지 없는지를 확인하려면

ex)

HEALTHCHECK --internal=5m --timeout=3s CMD curl -f http://localhost/ || exit 1



-

헬스 체크의 결과는 docker container inspect 명령으로 확인할 수 있다.








5.5. 환경 및 네트워크 설정


* 환경변수 설정 (ENV 명령)


-

syntax)

ENV [key] [value]

ENV [key]=[value]

key value 의 경우 첫 번째 공백 이후는 모두 value 로 문자열 취급한다.

key=value 의 경우 \ 로 줄바꿈 할 수 있으며, ENV 를 한번만 사용하여 이미지를 하나만 만들 수 있다.



-

env 값은 docker container run 의 --env 옵션을 사용하여 변경할 수 있다.




* 작업 디렉토리 지정 (WORKDIR 명령)


-

syntax)

WORKDIR [경로]


WORKDIR 명령은 RUN, CMD, ENTRYPOINT, COPY, ADD 명령을 실행하기 위한 작업용 디렉토리를 지정한다.

만약 존재하지 않으면 새로 만든다.


WORKDIR 명령은 Dockerfile 안에서 여러 번 사용할 수 있다.

상대 경로로 사용된다면 WORKDIR 기준이다.

cd 와 같은 기능이라고 보면 된다.


ex)

WORKDIR /first

WORKDIR second

WORKDIR thrid

RUN ["pwd"] # /first/second/thrid 가 출력



-

WORKDIR 에는 ENV 에서 정의한 값을 사용할 수도 있다.

ex)

WORKDIR $DIRPATH/$DIRNAME




* 사용자 지정 (USER 명령)


-

USER 는 RUN, CMD, ENTRYPOINT 명령을 수행하기 위한 사용자를 지정한다.

syntax)

USER [사용자명/UID]



-

USER 명령에서 지정하는 사용자는 RUN 명령으로 미리 작성해 놓아야 한다.

ex)

RUN ["adduser", "asa"]

RUN ["whoami"] # root

USER asa

RUN ["whoami"] # asa




* 라벨 지정(LABEL 명령)


-

이미지에 버전 정보나 작성자 정보, 코멘트 등의 정보를 제공할 때 LABEL 을 사용한다.

syntax)

LABEL key=value

LABEL 은 여러 번 기술할 수 있다.



-

docker image inspect 를 통해 Config.Labels 의 label 값들을 확인할 수 있다.




* 포트 설정(EXPOSE 명령)


-

컨테이너의 공개 포트 번호를 지정할 때 사용한다.

syntax)

EXPOSE <port num>

이는 docker 에게 실행 중인 컨테이너가 listen 하고 있는 네트워크를 알려준다.

docker container run 의 -p 옵션을 사용할 때 어떤 포트를 호스트에 공개할지를 정의한다.




* Dockerfile 내 변수의 설정 (ARG 설정)


-

환경변수인 ENV 와 달리 이 변수는 Dockerfile 안에서만 사용할 수 있다.

syntax)

ARG key=value

docker build 시 --build-arg 를 통해 값을 바꿔치기 할 수도 있다.




* 기본 쉘 설정 (SHELL 명령)


-

지정하지 않았을 때 기본 쉘은 ["/bin/sh", "-c"], 윈도우는 ["cmd", "\S", "\C"] 이다.

syntax)

SHELL ["쉘 경로", "파라미터"]





5.6. 파일 설정


* 파일 및 디렉토리 추가 (ADD 명령)


-

ADD 명령은 호스트상의 파일이나 디렉토리, 원격 파일을 docker 이미지 안으로 복사한다.

syntax)

ADD <host file path> <docker file path>

ADD ["<host file path>" "<docker file path>"]



-

추가하고 싶은 파일 경로에는 와일드카드와 Go 언어의 filepath.Match 룰과 일치하는 패턴을 사용할 수 있다.

Docker 이미지 안의 파일은 절대 경로로 지정하거나 WORKDIR 명령에서 지정한 디렉토리를 기점으로 한 경로를 지정한다.



-

이미지에 추가하고 싶은 파일이 원격 파일 url 인 경우, 추가한 파일은 퍼미션이 600(사용자만 읽기 쓰기 가능)이 된다.

만일 취득한 원격 파일이 HTTP Last-Modified 헤더를 갖고 있다면 추가된 파일에서 mtime 의 값으로 사용된다.

또한 ADD 명령은 인증을 지원하지 않기 때문에 원격 파일의 다운로드에 인증이 필요한 경우는 RUN 명령에서 wget 이나 curl 명령을 사용하는 것이 좋다.



-

호스트의 파일이 tar 아카이브거나 압축 포맷(gzip, bzip2 등)일 때는 디렉토리로 압축을 푼다.

단 원격 URL 로부터 다운로드한 리소스는 압축이 풀리지 않으므로 주의한다.



-

Docker 에서 빌드하면 빌드를 실행한 디렉토리 아래에 있는 모든 파일이 Docker 데몬으로 전송된다!!!

그래서 빌드에서 제외하고 싶은 파일이 있는 경우 .dockerignore 라는 이름의 파일 안에 해당 파일명을 기술하면 된다.

여러 개의 파일을 지정할 때는 줄 바꿈을 해서 파일명을 나열한다.




* 파일 복사 (COPY 명령)


-

이미지에 호스트상의 파일이나 디렉토리를 복사할 때는 COPY 명령을 사용한다.

syntax)

COPY <host file path> <docker file path>

COPY ["<host file path>" "<docker file path<"]



-

ADD 와 COPY 는 매우 비슷하다.

ADD 명령은 원격파일의 다운로드나 아카이브의 압축 해제 등과 같은 기능을 갖고 있지만, COPY 명령은 호스트상의 파일을 이미지 안으로 복사하는 처리만 한다.




* 볼륨 마운트(VOLUME 명령)


-

이미지에 볼륨을 할당한다.

syntax)

VOLUME ["\마운트 포인트"]

지정한 이름의 마운트 포인트를 작성하고, 호스트나 그 외 다른 컨테이너로부터 볼륨의 외부 마운트를 수행한다.

설정할 수 있는 값은 아래와 같은 두가지 형태가 있다.

ex)

VOLUME["/var/log"] # JSON 배열

VOLUME /var/log /var/db



-

컨테이너는 영구 데이터를 저장하는 데는 적합하지 않다.

그래서 영구 저장이 필요한 데이터는 컨테이너 밖의 스토리지에 저장하는 것이 좋다.

영구 데이터는 docker 호스트 머신상의 볼륨에 마운트하거나 공유 스토리지를 볼륨으로 마운트 하는 것이 가능하다.    




댓글0