Tool/Docker

도커(Docker) 사용법 - 이미지 생성 방법 (feat. Dockerfile)

재은초 2024. 1. 18. 20:31
반응형

도커 이미지란?

  • Docker 이미지는 베이스 이미지에 필요한 프로그램과 라이브러리, 소스를 설치한 뒤 파일 하나로 만든 것을 말한다.
  • 베이스 이미지란 리눅스 배포판의 유저랜드만 설치된 파일을 뜻한다.
  • 유저랜드란 OS는 메모리 사용을 기준으로 커널 공간과 유저 공간으로 나눌 수 있는데, 유저 공간에서 실행되는 실행 파일과 라이브러리를 유저랜드라고 한다.

 

도커파일(Dockerfile)이란?

  • Dockerfile은 Docker 이미지 설정 파일로, Dockerfile에 설정된 내용대로 이미지를 생성한다.
  • Dockerfile은 <명령> <매개 변수> 형식으로 작성한다. 명령은 대소문자를 구분하지 않지만 보통 대문자로 작성한다.
# 우분투 22.04 기반 nginx 서버 설치한 Docker 이미지 생성 예제

FROM ubuntu:22.04                                    # FROM : 어떤 이미지를 기반으로 할지 설정
MAINTAINER Foo Bar <foo@bar.com>                     # MAINTAINER : 생성된 이미지의 개발자 정보

RUN apt update                                       # RUN : 셸 스크립트 혹은 명령을 실행
RUN apt install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
RUN chown -R www-data:www-data /var/lib/nginx

VOLUME ["/data", "/etc/nginx/site-enabled", "/var/log/nginx"] # VOLUME: 호스트와 공유할 디렉터리 목록

WORKDIR /etc/nginx                                   # WORKDIR: CMD에서 설정한 실행 파일이 실행될 디렉터리

CMD ["nginx"]                                        # CMD: 컨테이너가 시작되었을 때 실행할 실행 파일 또는 셸 스크립트

EXPOSE 80                                            # EXPOSE: 호스트와 연결할 포트 번호
EXPOSE 443

FROM

  • FROM은 어떤 이미지를 기반으로 이미지를 생성할지 설정한다.
  • Dockerfile로 이미지를 생성할 때는 항상 기존에 있는 이미지를 기반으로 생성하기 때문에 FROM은 반드시 설정해야 한다.
  • Dockerfile에서 명령은 항상 FROM으로 시작해야 하며, FROM이 없거나 FROM 앞에 다른 명령이 있으면 이미지가 생성되지 않는다.
FROM ubuntu                                        # latest 버전
FROM ubuntu:22.04

MAINTAINER

  • MAINTAINER는 이미지를 생성한 사람의 정보를 설정한다.
MAINTAINER <작성자 정보>
MAINTAINER Hong, Gildong <gd@yuldo.com>

RUN

  • RUN은 FROM에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행합니다.
  • RUN으로 실행한 결과가 새 이미지로 생성되고, 실행 내역은 이미지의 히스토리에 기록된다.
  • 셸 스크립트 구문을 사용할 수 있으며, FROM으로 설정한 이미지에 포함된 /bin/sh 실행 파일을 사용하게 되며 /bin/sh 실행 파일이 없으면 사용할 수 없다.
  • RUN으로 실행한 결과는 캐시되며 다음 빌드 때 재사용한다. 캐시된 결과를 사용하지 않으려면 docker build 명령에서 --no-cache 옵션을 사용하면 된다.
RUN <명령>
RUN apt install -y nginx                               # 셸 스크립트로 실행
RUN echo "Hello Docker" > /tmp/hello
RUN curl -sSL https://go.dev/dl/go1.19.2.src.tar.gz | tar -v -C /usr/local -xz
RUN git clone https://github.com/docker/docker.git
RUN ["<실행 파일>", "<매개 변수1>", "<매개 변수2>"]   # 셸 없이 바로 실행
RUN ["apt", "install", "-y", "nginx"]
RUN ["/user/local/bin/hello", "--help"]

CMD

  • CMD는 컨테이너가 시작되었을 때 스크립트 혹은 명령을 실행한다. 즉 docker run 명령으로 컨테이너를 생성하거나, docker start 명령으로 정지된 컨테이너를 시작할 때 실행된다.
  • CMD는 Dockerfile에서 한 번만 사용할 수 있다.
CMD <명령>                                     # 셸 명령어로 실행
CMD touch /home/hello/hello.txt
CMD ["<실행 파일>", "<매개 변수1>", "<매개 변수2>"]     # 셸 없이 바로 실행할 때 매개 변수 설정
CMD ["mysqld", "--datadir=/var/lib/mysql", "--user=mysql"]
  • ENTRYPOINT에 설정한 명령에 매개 변수를 전달하여 실행한다. Dockerfile에 ENTRYPOINT가 있으면 CMD는 ENTRYPOINT에 매개 변수만 전달하는 역할을 하므로, CMD 독자적으로 파일을 실행할 수 없게 된다.
CMD ["<매개 변수1>", "<매개 변수2>"]             # ENTRYPOINT를 사용할 때
ENTRYPOINT ["echo"]
CMD ["hello"]

ENTRYPOINT

  • ENTRYPOINT는 CMD와 같이 컨테이너가 시작되었을 때 스크립트 혹은 명령을 실행한다. 즉 docker run 명령으로 컨테이너를 생성하거나, docker start 명령으로 정지된 컨테이너를 시작할 때 실행된다.
  • ENTRYPOINT는 Dockerfile에서 단 한번만 사용할 수 있습니다.
ENTRYPOINT <명령>                    # 셸(/bin/sh)로 명령 실행
ENTRYPOINT touch /home/hello/hello.txt
ENTRYPOINT ["<실행 파일>", "<매개 변수1>", "<매개 변수2>"]     # 셸 없이 바로 실행
ENTRYPOINT ["/home/hello/hello.sh", "--hello=1", "--world=2"]
  • CMD와 ENTRYPOINT는 컨테이너가 생성될 때 명령이 실행되는 것은 동일하지만 docker run 명령에서 동작 방식이 다르다.
  • 컨테이너를 생성할 때 docker run <이미지> <실행할 파일> 형식인데, CMD로 설정시 docker run 명령에서 실행할 파일을 설정하면 CMD는 무시된다. ENTRYPOINT는 docker run 명령에서 실행할 파일을 설정하면 ENTRYPOINT 무시되지 않고, 실행할 파일 설정 자체를 매개 변수로 받아서 처리한다. 

EXPOSE

  • EXPOSE는 호스트와 연결할 포트 번호를 설정하며, docker run 명령의 --expose 옵션과 동일하다.
  • EXPOSE는 호스트와 연결만 할 뿐 외부에 노출은 되지 않는다. 포트를 외부에 노출하려면 docker run 명령의 -p, -P 옵션을 사용해야 한다.
EXPOSE <포트 번호>
EXPOSE 80 443

ENV

  • ENV는 환경 변수를 설정하며, ENV로 설정한 환경 변수는 RUN, CMD, ENTRYPOINT에 적용된다.
  • 환경 변수를 사용할 때는 $를 사용한다.
ENV <환경 변수> <값>
ENV HELLO 1234
CMD echo $HELLO
  • 환경 변수는 docker run 명령에서도 설정할 수 있으며, -e <환경 변수>=<값> 형식이다. -e 옵션은 여러 번 사용할 수 있고, --env 옵션과 같다.
$ sudo docker run -e HELLO=4321 example
4321

ADD

  • ADD는 파일을 이미지에 추가한다.
  • <복사할 파일 경로>는 컨텍스트 아래를 기준으로 하며 컨텍스트 바깥의 파일, 디렉터리나 절대 경로는 사용할 수 없다.
  • <복사할 파일 경로>는 파일뿐만 아니라 디렉터리도 설정할 수 있으며, 디렉터리를 지정하면 디렉터리의 모든 파일을 복사한다. 또한, 와일드카드를 사용하여 특정 파일만 복사할 수 있으며, 인터넷에 있는 파일의 URL을 설정할 수 있다.
  • <이미지에서 파일이 위치할 경로>의 마지막에 /가 있으면 디렉터리가 생성되고 파일은 그 아래에 복사된다.
  • <이미지에서 파일이 위치할 경로>는 항상 절대 경로로 설정해야 한다. 그리고 마지막이 /로 끝나면 디렉터리가 생성되고 파일은 그 아래에 복사된다.
ADD <복사할 파일 경로> <이미지에서 파일이 위치할 경로>
ADD hello-entrypoint.sh /entrypoint.sh
ADD hello-dir /hello-dir
ADD zlib-1.2.8.tar.gz /
ADD hello.zip /
ADD http://example.com/hello.txt /hello.txt
ADD *.txt /root/

COPY

  • COPY는 파일을 이미지에 추가한다. ADD와는 달리 COPY는 압축 파일을 추가할 때 압축을 해제하지 않고, 파일 URL도 사용할 수 없다.
COPY <복사할 파일 경로> <이미지에서 파일이 위치할 경로>
COPY hello-entrypoint.sh /entrypoint.sh
COPY hello-dir /hello-dir
COPY zlib-1.2.8.tar.gz /zlib-1.2.8.tar.gz
COPY *.txt /root/

VOLUME

  • VOLUME은 디렉터리의 내용을 컨테이너에 저장하지 않고 호스트에 저장하도록 설정한다.
VOLUME <컨테이너 디렉터리> 또는 VOLUME ["컨테이너 디렉터리 1", "컨테이너 디렉터리2"]
VOLUME /data
VOLUME ["/data", "/var/log/hello"]
  • VOLUME으로 /data처럼 바로 경로를 설정할 수도 있고, ["/data", "/var/log/hello"]처럼 배열 형태로 설정할 수도 있지만, 호스트의 특정 디렉터리와 연결할 수는 없다. 데이터 볼륨을 호스트의 특정 디렉터리와 연결하려면 docker run 명령에서 -v 옵션을 사용해야 한다.
-v <호스트 디렉터리>:<컨테이너 디렉터리>
$ sudo docker run -v /root/data:/data example

USER

  • USER는 명령을 실행할 사용자 계정을 설정하며, RUN, CMD, ENTRYPOINT에 적용된다.
  • 중간에 USER를 설정하면 중간에 사용자를 바꿀 수 있다.
USER <계정 사용자명>
USER nobody
RUN touch /tmp/hello.txt

USER root
RUN touch /hello.txt
ENTRYPOINT /hello-entrypoint.sh

WORKDIR

  • WORKDIR은 RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리를 설정한다.
  • 중간에 다른 디렉터리를 설정하여 실행 디렉터리를 다시 바꿀 수 있다.
WORKDIR <경로>
WORKDIR /root
RUN touch hello.txt

WORKDIR /tmp
RUN touch hello.txt
  • WORKDIR은 절대 경로 대신 상대 경로도 사용할 수 있다. 상대 경로를 사용하면 먼저 설정한 WORKDIR의 경로를 기준으로 디렉터리를 변경하며, 최초 기준은 / 다.
WORKDIR /root
RUN touch hello.txt

WORKDIR /tmp
RUN touch hello.txt

ONBUILD

  • ONBUILD는 생성한 이미지를 기반으로 다른 이미지가 생성될 때 명령을 실행한다.
  • 최초에 ONBUILD를 사용한 상태에서는 아무 명령도 실행하지 않지만, 다음 번에 이미지가 FROM으로 사용될 때 실행할 명령을 예약하는 기능이라 할 수 있다.
ONBUILD <Dockerfile 명령> <Dockerfile 명령의 매개 변수>
ONBUILD RUN touch /hello.txt
ONBUILD ADD world.txt /world.txt

 

이미지 생성하기

  • Dockerfile을 작성했으면, Dockerfile이 저장된 디렉터리에서 아래 명령을 실행 해이미지를 생성할 수 있다.
  • --tag 옵션으로 이미지 이름과 태그를 설정할 수 있는데, 이미지 이름만 설정하면 태그는 latest로 설정된다.
$ docker build <옵션> <Dockerfile 경로>
$ docker build --tag hello:0.1 .

 

이미지 실행하기

  • -d 옵션은 컨테이너를 백그라운드로 실행한다.
  • -p 80:80 옵션으로 호스트의 80번 포트와 컨테이너의 80번 포트를 연결하고 외부에 노출한다. 이렇게 설정한 뒤 http://<호스트 IP>:80에 접속하면 컨테이너의 80번 포트로 접속된다.
  • -v /root/data:/data 옵션으로 호스트의 /root/data 디렉터리를 컨테이너의 /data 디렉터리에 연결한다. /root/data 디렉터리에 파일을 넣으면 컨테이너에서 해당 파일을 읽을 수 있다.
$ docker run <옵션> <이미지 이름/아이디> <실행할 파일>
$ docker run --name hello-nginx -d -p 80:80 -v /root/data:/data hello:0.1

 

필요 없는 파일 제외하기

  • 컨텍스트에서 특정 파일이나 디렉터리를 제외하고 싶을 때는 .dockerignore 파일을 사용하면 된다.
example/hello.txt
example/*.cpp
wo*
*.cpp
.git
.svn

 

Reference

반응형