Make my Docker Image

나만의 콘테이너가 필요한 경우 콘테이너가 사용할 이미지를 만들어야 되는데 간단하게 만들어보자.

Hello World

모든 언어의 시작이 ‘Hello World’ 로 시작하듯 간단하게 프로그램을 작성하자.

파일명은 ‘hello.c’ 로 할 것이다.

#include <stdio.h>

int main() {
    printf("hello from docker container\n");
    return 0;
}

컴파일을 위한 ‘Makefile’ 을 만들어야 하는데 이는 콘테이너가 실행하면서 ‘hello.c’ 를 컴파일하기 때문이다.

중요한 점은 ‘hello.c’ 코드를 static 하고 실행단계에서 C library 에 의존하지 않도록 컴파일 하여야 한다.

CC	= gcc
CFLAGS	= -static -Wall

hello: hello.c
    $(CC) $(CFLAGS) $< -o $@

c 코드이며 Makefile 을 사용하였기에 호스트에서 컴파일 하기 위해서는 ‘gcc’ 와 ‘make’ 가 필요하다.

$ sudo apt install -y gcc make

준비가 되었으면 컴파일 한다.

$ make
gcc -static -Wall hello.c -o hello

정상적으로 파일이 컴파일 되었는지 확인한다.

$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=05cb203367c91510838cd5c808889cf528026a5d, not stripped

확인 결과 ..., statically linked, ... 를 확인하였다면 의존성 문제는 없는 것이다.

Make Docker Image

위 예에서 사용한 make 는 복잡한 의존성 관계를 지닌 프로그램을 컴파일 할 때 Makefile 에 포함된 내용에 의해 단순화 된다.

즉, 개발자가 1) 길고 복잡한 명령을 외우지 않도록 명령어 집합을 포함하고, 2) 여러 명령이 순서에 맞도록 나열되어 있고, 3) 의존성에 따라 구조적인 절차가 포함되어 있다.

Docker 에서는 Dockerfile 이 같은 역할을 담당한다.

위에서 예를 든 ‘hello.c’ 를 포함한 Container Image 를 만드는 과정이 포함된 절차를 적어둔 파일이다.

FROM scratch
COPY hello /
CMD ["/hello"]

각 절차의 의미는 다음과 같다.

  1. FROM scratch: 비어있는 이미지 (스크레치)
  2. COPY hello /: hello 파일을 / 에 복사
  3. CMD ["/hello"]: 실행할 명령은 /hello

생성한 Dockerfile 을 사용하여 docker build 를 한다. (docker builder 명령어 끝에 . 이 포함됨에 주의)

$ docker build -t hello .
Sending build context to Docker daemon  849.4kB
Step 1/3 : FROM scratch
 --->
Step 2/3 : COPY hello /
 ---> fa32a7a28dc7
Step 3/3 : CMD ["/hello"]
 ---> Running in b28638619810
Removing intermediate container b28638619810
 ---> 8dfc72a052e2
Successfully built 8dfc72a052e2
Successfully tagged hello:latest

docker build 명령은 Dockerfile 을 사용하여 이미지를 만드는 것이다. 작성한 3 줄의 Dockerfile 명령을 하나씩 실행하면서 이미지를 만들어가는 것이 로그에 남는다.

Removing intermediate container b28638619810 라는 구문을 보니 intermediate container 를 삭제하는 것을 볼 수 있다.

Check First Docker Image

만들어진 Image 가 정상동작하는지 확인하기 위해 다음을 실행한다.

$ docker run hello
hello from docker container

hello.c 에서 출력하고자 하는 결과가 나타나는 것을 확인할 수 있다.

작성한 image 정보를 확인해보면 다음과 같다.

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              8dfc72a052e2        6 minutes ago       845kB

$ docker container ls -al
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
44f26bfbac29        hello               "/hello"            2 minutes ago       Exited (0) 2 minutes ago                       lucid_kalam

REPOSITORY 는 hello, TAG 는 latest, IMAGE ID 는 8dfc72a052e2 인 image 가 생성되었음을 확인할 수 있다.

또한, 이 image 를 사용한 Container 는 2 분 전에 만들어져 /hello 명령을 실행하고, 2 분 전에 종료되었음을 확인할 수 있다.