Docker 이미지는 Dockerhub를 통해 다운받아서 사용할 수 있다. 이러한 도커 이미지들은 누군가 만들어서 올려놓은 것인데 이러한 이미지를 만드는 법에 대해서 알아보고자 한다.
Docker 이미지는 Dockerfile 이라는 것을 사용해서 만든다.
결국 Dockerfile이란 Docker 이미지를 만드는 파일이다.
FROM 은 베이스 이미지를 생성하는 역할을 한다.
Docker 컨테이너를 특정 초기 이미지를 기반으로 추가적인 설정을 할 수 있다.
특정 초기 이미지라는 것은 곧 베이스 이미지 를 의미한다.
베이스 이미지라는 것은 해당 컨테이너를 새로 띄울때 기본적으로 이정도는 있어야 한다고 말해주는 옵션이라고 생각하자.
FROM [IMAGE_NAME]
FROM [IMAGE_NAME]:[TAG_NAME]
어떠한 경로에 Dockerfile이라는 이름의 도커파일을 만들고
해당 Dockerfile에
FROM openjdk:17-jdk
라고 작성을 한다면 컨테이너가 띄워졌을 때 jdk 17버전이 깔려있어야 한다 라는 뜻의 베이스 이미지이다.
이 이미지를 바로 만들어보자.
해당 Dockerfile이 있는 경로에서
$ docker build -t [IMAGE_NAME] [상대경로]
를 써주면 된다.
그렇게 하면 아래 그림처럼 내가 지정한 이름의 docker 이미지가 생성되는 것을 볼 수 있다.

이렇게 생성된 이미지를 컨테이너에 올려보면

위 그림과 같이 Exited (0) 이라는 것을 볼 수 있는데 이 이유는 이미지에서 컨테이너가 실행 될 때 컨테이너가 내부적으로 해야 할 일이 끝이 나면 종료가 되게 되어 있는데 현재 Dockerfile에 따로 할 일이 없기 때문에 바로 종료가 되는 것이다.
이럴때는 아래와 같은 코드를 Dockerfile에 추가하면 종료된 컨테이너에서도 디버깅을 할 수 있다.
# 500초 동안 시스템을 일시정지 시키는 명령어
ENTRYPOINT ["/bin/bash", "-c", "sleep 500"]
이러한 코드를 Dockerfile에 작성하고 다시 빌드를 한다면 docker exec -it 로 해당 컨테이너에 접근하여 확인 할 수 있게 된다.
이런 식으로 Docker를 사용했을 때 컨테이너 내부에서 작동하기 때문에 어떤 과정으로 처리가 되는지, 잘 처리가 되었는지 확인 할 수 있는지 방법을 찾아봐야 한다.
COPY는 호스트 컴퓨터 에 있는 파일을 복사해서 컨테이너로 전달해주는 역할을 한다.
COPY [HOST_FILE_SRC_PATH] [CONTAINER_DEST_PATH]
위 코드에서 HOST_FILE_SRC_PATH는 호스트 컴퓨터에 있는 복사할 파일의 경로를 의미하고 CONTAINER_DEST_PATH는 컨테이너 내부에서 파일이 위치할 경로를 의미한다.
FROM ubuntu
COPY app.txt /app.txt
ENTRYPOINT ["/bin/bash", "-c", "sleep 500"]
만약 어떤 도커파일이 위와같이 작성되었다면 그 의미는 아래와 같다.
도커 이미지의 베이스 이미지는 ubuntu 이고 호스트의 현재 디렉토리의 app.txt 파일을 컨테이너 내부 최상위 경로에 복사하겠다.
따라서 위와 작성된 DockerFile을 기반으로 이미지를 생성하고 확인하면 아래와 같이 app.txt가 생긴 것을 볼 수 있다.

또한 같은 확장자를 가진 모든 파일을 복사 할 수 있는데 그때는 *.확장자 를 사용하면 된다.
만약에 directory 를 통째로 복사하고 싶으면 컨테이너 내부의 파일 위치 경로 뒤에 / 를 꼭 붙여줘야 한다.
FROM ubuntu
COPY myFolder /myFolder/
ENTRYPOINT ["/bin/bash", "-c", "sleep 500"]
🚨 복사를 하고 싶지 않은 파일들은 .dockerignore 파일에 작성하여 복사를 하지 않을 수도 있다.
ENTRYPOINT는 컨테이너가 생성되고 최초로 실행할 때 수행되는 명령어 를 뜻한다.
ENTRYPOINT [명령문...]
만약에 아래와 같은 Dockerfile을 작성하고 실행한다고 생각을 해보자.
FROM ubuntu
ENTRYPOINT ["/bin/bash", "-c", "echo hello"]
이렇게 된다면 ubuntu를 베이스이미지로 하는 이미지가 생기고 이 이미지를 빌드하는 순간 "hello"라는 단어가 나오게 될 것이다.
이번엔 위와 같이 시스템을 일시정지 시키지 않았기 때문에 바로 종료가 될것이고 docker logs를 사용해서 로그를 확인해보자.

그러면 위 그림과 같이 hello라는 글자가 나오는 것을 볼 수 있다.
RUN 은 이미지 생성 과정에서 명령어를 실행시켜야 할 때 사용한다.
RUN [명령문]
#예시
RUN npm install
RUN과 ENTRYPOINT 는 둘 다 명령어를 실행 시키지만 RUN은 이미지 생성 과정에서 필요한 명령어를 실행시킬 때 사용하고, ENTRYPOINT는 생성된 이미지를 기반으로 컨테이너를 생성한 직후에 명령어를 실행시킬 때 사용한다.
만약 환경이 ubuntu로 구성되고 git이 깔려있었으면 좋겠다고 한다면 다음과 같이 Dockerfile을 작성하면 된다.
FROM ubuntu
RUN apt update && apt install -y git
ENTRYPOINT ["/bin/bash", "-c", "sleep 500"]


위와 같이 git 이 설치되어 git의 버전을 확인 할 수 있다.
WORKDIR 로 작업디렉토리를 전환하면 그 이후에 등장하는 모든 RUN, ENTRYPOINT, COPY, ADD, EMD 명령문은 해당 디렉토리를 기준으로 실행된다.
작업 디렉토리를 지정해주는 이유는 컨테이너 내부의 폴더를 관리하기 위함이다.
컨테이너도 컴퓨터와 같다고 생각하면 내부의 폴더가 깔끔한게 좋지 않을까 라고 생각하면 된다.
그래야 Dockerfile을 통해 생성되는 파일들을 특정 폴더에 정리해두는 것이 나중에 쉽다.
만약 WORKDIR을 사용하지 않으면 컨테이너 내부에 존재하는 기존 파일들과 뒤섞여버린다.
WORKDIR [작업 디렉토리 절대 경로]
##예시
WORKDIR /usr/src/app
먄약에 호스트의 디렉토리에 src 라는 폴더 하나와 app.txt, config.json 등의 파일이 존재한다고 하자. 만약 이 모든 파일들을 컨테이너에 옮기고 싶다면 Dockerfile을 아래와 같이 작성하면 된다.
FROM ubuntu
COPY ./ ./
ENTRYPOINT ["/bin/bash", "-c", "sleep 500"]
WORKDIR을 사용하지 않을 경우 이 파일들은 그냥 컨테이너의 최상위 경로에 다 들어가게 된다.
이렇게 할 경우 나중에 알아보기가 힘들기 때문에 아래와 같이 작성하면 my-dir 이라는 디렉토리에 다 들어가게 된다.
FROM ubuntu
WORKDIR /my-dir
COPY ./ ./
ENTRYPOINT ["/bin/bash", "-c", "sleep 500"]
EXPOSE 는 컨테이너 내부에서 어떤 포트에서 프로그램이 실행되는지를 문서화하는 역할만 한다.
docker -p 8080:8080 과 같은 명령어의 -p 같은 역할은 아니고 작동하는 방식에는 영향을 미치지 않는다.
즉 있든 없든 상관이 없다.
EXPOSE [PORT_NUM]
##예시
WORKDIR 3000