안녕하세요, 주니어 개발자 Eon입니다.
이번엔 Docker image 빌드에 관한 포스팅입니다.
이전 포스트에서 Docker image를 pull해서 사용하는 방법까지 알아봤습니다.
이번 포스트에서는 직접 image를 만들어서 사용하려고 합니다.
이전 포스트에서 Docker image를 pull해서 사용했습니다.
다른 누군가, 다른 단체가 빌드해서 public repository 저장소에 push해서 올린 image를 pull해서 다운로드 받은 것입니다.
이처럼 Docker image를 다른 사람이 사용할 수 있게 하려면 image를 Docker hub에 올려야 합니다.
검색을 통해 image를 찾고, 사용할 수 있게 됩니다.
그럼 일단 계정이 있어야 합니다.
그건 이전 포스트에서 Docker hub 가입도 마쳤으니 이번엔 개인 repository를 생성합니다.
여기 Repositories로 들어가서
Create Repository를 누르면 repo를 생성할 수 있습니다.
생성할 때, public이나 private로 생성할 수 있습니다.
Docker hub subscribe를 하지 않은 상태라면 private repository는 계정당 1개만 생성할 수 있습니다.
public repo는 모두에게 오픈되어 있으며, 아무나 사용이 가능합니다.
private repo는 나를 제외한 모두에게 열람 권한이 없습니다.
image 여러 개를 나만 쓰고 싶은데 private repo를 1개만 생성 가능해서 불편하다고 느끼신다면 아래에서 소개할 image 빌드를 통해 어느 정도 불편함을 해소할 수 있습니다. (사실 해소라기 보다 다른 불편함으로 대체되는 것입니다..)
저는 repository 이름을 c-project라고 지었습니다.
제 계정이 eon이라고 한다면 제 repository path는 eon/c-project 입니다.
repo path라고 말씀드렸지만 사실은 이 자체가 image의 이름입니다.
아직 image 빌드를 하지 않은 상태라 repository에 올릴 image가 없습니다.
그래도 일단 repository를 만들었으니 push하는 방법을 알아보겠습니다.
docker push <Image_Name>:<TAG>
image는 기본적으로 image 이름과 태그로 구성되어 있습니다.
TAG는 버전을 기입하는 용도로 쓰입니다.
TAG는 image를 빌드할 때 붙일 수 있으며, 빌드 이후에도 수정이 가능합니다.
위에서 언급한 제 repository path인 eon/c-project 가 image 이름이라고 했습니다.
그래서 push를 할 때는 아래와 같이 됩니다.
docker push eon/c-project:<TAG>
첫 이미지가 될 테니 TAG는 0.0.1로 하겠습니다.
docker push eon/c-project:0.0.1
이렇게 명령어를 실행하면 제가 생성한 repository에 빌드한 이미지가 올라옵니다.
Docker image에 TAG를 부여함으로써 image의 버전을 표기했습니다.
TAG를 붙여서 push를 함으로써, push되는 모든 image에는 버전이 붙게 됩니다.
그리고 그 버전들은 각각 별개의 image가 됩니다.
TAG에 따라 발생할 문제가 다 다를 테니, 문제가 있는 버전은 repo에서 제거함으로써 안전한 사용을 위한 관리도 할 수 있습니다.
Docker image를 빌드하려면 Dockerfile을 작성해야 합니다.
Dockerfile의 작성법은 단순하면서도 복잡합니다.
단순히 OS를 처음 설치하고, 내가 원하는 서비스를 설치하는 과정을 그대로 텍스트로 작성하면 되는 것입니다.
# Dockerfile # The base image (OS) is ubuntu bionic.. FROM ubuntu:bionic # RUN set -x is as same as to run these commands after '\'.. RUN set -x \ # Update apt package list as latest.. && apt-get update \ # Install gcc and gdb.. gcc for compile c language, gdb for debugger.. && apt-get install -y gcc gdb RUN set -x \ && mkdir -p ~/cproject/helloworldDir # In dockerfile, '#'is for comment.. so if the line including '#' right below, it would be ignored by dockerfile syntax.. # To resolve this problem, separate the lines like below.. RUN echo "#include <stdio.h>" > ~/cproject/helloworldDir/helloworld.c RUN echo '\ int main(void){\n \ printf("helloworld!\\n");\n \ return 0;\n \ }' >> ~/cproject/helloworldDir/helloworld.c RUN set -x \ && cat ~/cproject/helloworldDir/helloworld.c RUN set -x \ && gcc -o ~/cproject/helloworldDir/helloworld ~/cproject/helloworldDir/helloworld.c # You may choose one below.. #CMD ["/root/cproject/helloworldDir/helloworld"] CMD ["/bin/bash"]
Dockerfile 작성 시, 위의 내용의 경우, 개행하는 방법을 알아두어야 합니다.
개행할 때는 "\"로 하고, 이어지는 명령어 작성은 "&&"로 이어갈 수 있습니다.
FROM, RUN , CMD와 같은 명령어 블럭은 각각 한 step을 의미합니다.
(step을 구성할 수 있는 명령어는 Dockerfile reference docs에 소개돼 있습니다.)
Dockerfile을 빌드하다가 error를 만나서 빌드가 중단되는 경우가 종종 있습니다.
때문에 step을 적절하게 나눠주는 것이 중요합니다.
이미 앞에서 성공한 step은 Docker가 caching하기 때문에, 성공한 step을 다시 빌드하지는 않습니다.
단, 성공한 step 1과 step 2 사이에 step을 하나 추가하게 되면 추가한 step부터 다시 빌드를 합니다.
Dockerfile 빌드에 시간이 꽤나 소요되기 때문에 효율적으로 step을 나누는 것이 좋습니다.
추가로, step은 image layer로 등록돼서 push할 때 조각 조각으로 나눠서 push하게 됩니다.
step 하나가 굉장히 길어지게 되면 해당 image layer만 엄청 커져서 push할 때 시간이 오래 걸릴 수도 있고 리소스를 많이 사용하게 돼, 다른 실행 중인 프로세스에 좋지 않은 영향을 줄 수 있습니다.
추가 +) 위와 같이 소스 코드를 echo를 활용해서 작성하는 방법은 당연히 좋지 않은 방법입니다. 그냥 이런 것도 가능하다는 걸 보여드리기 위함입니다. ubuntu 위에 C언어 환경이 구성된 container를 만들기 위함이라면 apt 패키지 설치까지와 최하단 CMD만 남겨두시면 됩니다.
이렇게 환경을 구성하고, 설치하고 즉시 실행까지 가능합니다.
위의 주석처리된 CMD 파트를 실행하면 컴파일된 바이너리 파일이 실행됩니다.
출력 결과는 당연하게도 "helloworld!"입니다.
위의 내용을 Dockerfile이라는 파일명으로 저장하시면 됩니다.
물론 다른 이름으로 저장하셔도 상관없으나, vscode 등의 IDE를 사용할 때에 파일명을 Dockerfile로 사용하시면 가독성이나 syntax 체크가 훨씬 편할 수 있습니다. (IDE가 제공하는 font 색상 등으로 line이나 주석 구분이 쉬워짐)
Dockerfile 빌드를 해보겠습니다.
아래와 같이 명령어 입력 후 실행합니다.
docker build -t ${IMAGE_NAME:TAG} -f ./Dockerfile .
-t : 태그 옵션입니다.
-f : 빌드할 Dockerfile의 path를 지정합니다. (Default is 'PATH/Dockerfile')
-. : PATH | URL 입력하는 부분입니다. build 후에 이미지를 전송합니다.
마지막에 '.'은 다른 PATH를 참조하지 않을 때 사용합니다.
Docker hub repository를 참조할 경우, '.'을 default로 사용합니다.
외에 -t나 -f 옵션은 말 그대로 옵션입니다.
하지만 image를 쉽게 재사용이나 버전 관리를 하기 위해 -t 옵션을 사용해서 태그를 붙입니다.
-f 옵션은 Dockerfile이 있는 디렉터리에서 빌드할 경우엔 필요없는 옵션입니다.
저는 태그를 지정해서 image를 빌드했습니다.
eon/c-project:0.0.1
이제, 포스트 초반에 설명한 push를 할 수 있습니다.
docker push eon/c-project:0.0.1
이제 eon/c-project repository에 0.0.1 태그가 달린 eon/c-project:0.0.1 image가 push됐습니다.
image의 사용은 꼭 pull을 하고 써야 하는가?
아닙니다. 위와 같이 로컬에서 빌드하고 바로 사용할 수 있습니다.
때문에 repo path나 TAG 등은 무시하고 빌드해도 image의 사용에는 문제가 없습니다.
이번 포스트에서는 Dockerfile로 image를 빌드하는 방법과 image를 repo에 push하는 방법을 소개했습니다.
위에 예시로 만든 image는 ubuntu bionic 기반, gcc와 gdb도 설치하니 해당 image로 container를 생성해서 구동시키면 그 안에서 c언어 컴파일과 실행 및 디버깅이 가능합니다.
이것으로 오늘 포스팅을 마치겠습니다.
감사합니다.👍