Study/seSAC 금천 4기

컨테이너 애플리케이션 개발_3일차_240920

지찬씌 2024. 9. 30. 09:09

Dockerfile 작성 시 유의사항 2 - 도커 이미지 크기가 커지지 않도록 유의

 

 

1. 레이어 최소화의 필요성

- Dockerfile의 각 라인은 레이어 형태로 이미지에 저장되므로, 지시문(명령문)을 결합해서 최적화하는 것이 필요하다.

 

  1) 명령어마다 RUN 지시문을 사용하는 경우 

 

  2) 여러 명령어를 하나의 RUN 지시문으로 묶어 기술

 

 

 

 

2. 불필요한 도구 설치 금지

- 앱 실행과 관련 없는 도구 (개발도구, 디버깅도구)와 패키지의 종속성을 제거한다.

 

  1) --no-install-recommends 플래스 사용

   - apt-get install 시 추천(recommended) 또는 제안(suggested) 패키지가 자동으로 설치되는 것을 방지하는 옵션이다.

 

  2) 이미지 빌드

 

 

 

 

3. 빌더 패턴과 다단계 도커 빌드

 

  1) 불필요한 아티팩트와 런타임을 포함하는 예

   - Go 컴파일러는 앱 빌드할 때는 필요하지만, 실행할 때는 필요하지 않음!

    => 단순하게 Hello World 를 출력하는 데 있어 image golang의 837MB라는 용량은 불필요한 것. 

 

 

  2) 소스코드 빌드를 위한 이미지와 실행을 위한 이미지를 따로 만들 것!

 

 

  3) 빌드 패턴을 사용한다.

 

 

  4) 다단계 도커 빌드를 사용한다.

   * 가독성 향상을 위해 AS 구문을 사용해 별칭을 부여할 수 있다.

 

 

 

 

 

 

Dockerfile 주요 명령어

 

1. RUN

: 이미지를 만들기 위해 컨테이너 내부에서 실행할 명령어

 

- 사용자 입력을 요구하는 명령어가 들어가면 docker image build 시 오류가 발생한다.

 

 

 

 

 

2. RUN, CMD, ENTRYPOINT 구문에서 명령어를 기술하는 방법

 

  1) shell Form

   예) CMD go run /myapp/main.go

   형식 : INSTRUCTION command param1 param2

   - 명령어(command)를 /bin/sh -c 구문을 통해서 실행한다.

     => 쉘이 먼저 실행되고, 해당 쉘에서 명령어가 실행됨을 의미한다.

 

   - 쉘을 기본적으로 사용학 때문에 쉘이 제공하는 파이프, 리다이렉션, 변수 사용 등이 가능하다.

 

   - CMD command_string 구문은 CMD ["/bin/sh", "-c", "command_string"] 구문과 동일하게 처리된다.

 

   - Shell 구문을 이용하면 다른 쉘도 사용이 가능하다.

     예) SHELL ["/bin/bash", "-c"]

          RUN     echo hello

          => /bin/sh 이 아닌 /bin/bash 을 통해서 실행

 

 

  2) exec Form (권장)

   예) CMD ["go", "run", "/myapp/main.go"]

   형식 : INSTRUCTION ["executable", "param1", "param2"]

             RUN, CMD, ENTRYPOINT

   - 쉘을 통하지 않고, 명령어가 직접 실행되도록 하는 방식으로,

     명령어와 인자를 JSON 배열 형식(단어를 반드시 쌍따옴표로 묶어서 표현)으로 전달한다.

 

   - 쉘을 통하지 않기 때문에, 쉘이 제공하는 부가 기능(파이프, 리다이렉션, 변수 사용 등)을 사용할 수 없다.

     => RUN ["echo", "$HOME"] = HOME이라는 실행파일을 열어라

 

   - 쉘을 이용해서 명령어를 실행하려고 하면, exec 형식으로 직접 쉘을 실행해야 한다!

     => RUN ["sh", "-c", "echo $HOME"] = 쉘의 HOME 환경 변수를 실행해라

 

 

 

 

 

3. COPY vs ADD

 

  1) COPY

   : 호스트의 로컬의 파일만 이미지에 추가할 수 있다.

 

  2) ADD

   : 외부 URL 및 tar 파일에서도 파일을 추출하여 이미지에 추가할 수 있다.

     (tar 파일의 경우 자동으로 묶음을 해제해서 추가한다.)

 

  - 의도하치 않은 파일의 추가를 방지하기 위해 COPY 사용을 권장한다.

 

 

 

 

 

4. WORKDIR

: 지정한 디렉터리로 전환(이동)하는 명령어이다.

 

- WORKDIR 명령문 이후에 등장하는 모든 RUN, CMD, ENTRYPOINT, COPY, ADD 명령문은 해당 디렉터리(WORKDIR)를 기준으로 실행한다.

 

 

 

 

 

 

5. EXPOSE (-P 옵션, 대/소문자 주의)

: 이미지에서 노출할 포트를 설정하는 명령어

 

예)

c:\docker\webserver> docker container run -p 9999:80 -d --name myweb2 --rm mywebserver                                                 

bbf5c12fac22308224d293983877e9de14584749881f1a130aa0e8e009416f1b

docker: Error response from daemon: driver failed programming external connectivity on endpoint myweb2 (bd1d11840fc43632dc63b3d1360bb1e0787630bb42e781320a1b827815cce4c3): Bind for 0.0.0.0:9999 failed: port is already allocated.

  => 해당 오류는 호스트 포트가 충돌해서 컨테이너가 실행되지 않음을 의미한다.

 

 

- 호스트 포트의 충돌을 방지하기 위해 호스트 포트를 지정하지 않는다.

  => 이 때 가용한 임의의 포트가 할당된다.

예)

c:\docker\webserver> docker container run -p 80 -d --name myweb2 --rm mywebserver

387c6203b1af4b1490aca6b6195192ab232f20abccd1a07506807708dd55f4e7

 

c:\docker\webserver> docker container ls

CONTAINER ID   IMAGE         COMMAND                   CREATED          STATUS          PORTS                   NAMES

387c6203b1af   mywebserver   "/bin/sh -c 'apachec…"   4 seconds ago    Up 3 seconds    0.0.0.0:58317->80/tcp   myweb2

e6b1be0d9511   mywebserver   "/bin/sh -c 'apachec…"   38 minutes ago   Up 38 minutes   0.0.0.0:9999->80/tcp    myweb

 

 

- 컨테이너 실행 시 -P 옵션을 사용하면 호스트의 가용한 포트와 컨테이너 내부에 EXPOSE된 포트를 자동으로 매핑한다.

 

- 포트 맵핑 정보를 확인할 때는 docker container port 명령어를 사용하면 된다.

 

 

 

 

 

 

6. CMD vs ENTRYPOINT

 

- ENTRYPOINT가 설정되지 않았다면 CMD에 설정된 명령어를 그대로 실행하지만,

  ENTRYPOINT가 설정되어 있다면 CMD는 단지 ENTRYPOINT에 대한 인자의 기능을 수행할 뿐이다.

 

- ENTRYPOINT를 사용하는 이유는 명령어로 입력한 값의 내용이 변경되는 것을 희망하지 않을 때 사용한다.

 

 

 

 

 

 

7. ENV

: Dockerfile에서 사용할 환경 변수를 지정하는데 사용한다.

 

- 형식 : ENV 환경변수이름=환경변수값. 설정한 환경변수는 ${환경변수이름} 또는 $환경변수이름 형태로, Dockerfile, 이미지, 이미지로 생성한 컨테이너에서 사용이 가능하다.

 

- docker container run 명령의 -e 옵션을 이용해서 같은 이름의 환경변수 값을 덮어 쓸 수 있다.

 

 

 

 

 

 

8. VOLUME

: Union File System을 사용하지 않고 호스트에 저장하는 명령어이다.

 

 

 

 

 

 

- -v 옵션을 이용해서 데이터 볼륨을 맵핑하면 persistant 하게 볼륨을 유지할 수 있다.

  => 컨테이너와 컨테이너 간의 데이터 공유 및 유지가 가능해진다.

 

 

 

 

 

 

Dockerfile 모범 사례

: 도커 이미지 빌드 시간 단축, 이미지 크기 감소, 보안 강화 및 유지 관리 가능성 보장하는 Dockerfile이 권장된다.

 

 

1. 적절한 베이스 이미지 사용

 

  1) 도커 허브 공식 이미지 사용

   : 도커 허브의 공식 이미지는 모범 사례를 따르고 문서화되어 있으며 보안 패치가 적용되어 있다.

 

 

  2) 특정 버전의 태그 사용

   : 프로덕션 환경을 위한 도커 이미지를 빌드할 때 베이스 이미지에 latest 태그를 사용하면,

     하위 호환성을 제공하지 않을 경우 문제가 될 수 있다.

 

 

  3) 최소 크기의 이미지를 사용

   : 최소 크기 버전의 부모 이미지를 사용해야 한다. (= 최소 크기의 도커 이미지를 생성)

 

   - Alpine Linux 이미지를 중심으로 빌드된 최소 크기 이미지 또는 빌드 도구가 포함된

    JDK 대신 JRE를 사용하여 앱을 실행한다.

 

 

 

 

2. 루트가 아닌 사용자로 컨테이너 실행

: 도커 컨테이너는 기본적으로 루트(id=0) 사용자로 실행된다.

  이는 해커가 도커 컨테이너 내부에서 실행되는 앱을 해킹 후 도커 호스트에 대한 루트 액세스 권한을 획득할 수 있다.

  프로덕션 환경에서 루트 사용자로 도커 컨테이너를 실행하는 것은 나쁜 보안 관행으로 간주된다.

  따라서 응용 프로그램 실행에 필요한 최소한의 권한만 갖도록 최소 권한의 원직을 준수해야 한다.

 

  1) --user(또는 -u) 플래그 사용

 

 

  2) USER 지시문 사용

 

 

 

 

빌드 컨텍스트 (Build Context)

: 도커 이미지를 생성하는데 필요한 각종 파일, 소스 코드, 메타 데이터 등을 담고 있는 디렉터리이다.

                                                                                           Dockerfile, dockerignore

                                                                                                             ignore 파일 : 해당 파일에 명시된 이름의 파일을 

                                                                                                            빌드할 때 컨테스트에서 제외

 

 

 

 

 


빌드패턴?

 

 

*alpine : 경량 리눅스 배포판