이번 파트에서는 이미지가 어떻게 저장되는지에 대해서 알아보고 이미지를 효율적으로 저장하는 레이어드 구조에 대해서 배운다.
그리고 이미지가 저장되는 원리를 알아보고 이미지를 만드는 방법인 커밋과 빌드 두 가지 방식에 대해서 알아보자
이미지와 레이어
이미지는 컨테이너를 실행하기 위한 읽기 전용 파일이다.
도커 이미지는 저장소를 효율적으로 사용하기 위해서 레이어드 파일 시스템으로 구성되어 있다.
레이어라는 것은 하나의 층을 의미한다. 여러 개의 층으로 구성되어 있는 것에서 하나의 층을 레이어라고 표현한다.
이미지는 여러 개의 레이어로 구성되어 있다.
오른쪽 이미지는 NGINX를 실행했을 때 나오는 출력이다.
먼저 로컬 저장소에 이미지가 없는 것을 확인하고 도커 허브에서 이미지를 다운받는다.
nginx라는 하나의 이미지를 다운받는 과정에서 pull이 여러 단계에 걸쳐서 실행된다.
여기서 한 줄이 하나의 레이어를 의미한다. 이 레이어들이 모여서 하나의 이미지로 구성된다.
각각의 레이어는 이미지의 일부분을 나타낸다.
그러면 굳이 하나의 이미지를 왜 여러 개의 레이어로 구성했을까?
레이어드 구조가 재사용하기 유리한 구조이기 때문이다.
레이어드 파일 시스템을 사용하면 공간을 효율적으로 사용할 수 있어서 이미지를 저장하고 전송할 때 스토리지와 네트워크 사용량을 절약할 수 있다.
설계도를 예시로 들어보겠다.
구조, 토목, 전기, 조경으로 구성된 건축 설계도가 있다고 하자.
각각의 레이어들을 하나로 합치면 완성된 설계도 A가 될 거다.
만약 설계도에서 조경 부분을 수정해야 한다고 했을 때 설계도 A가 한 장의 도면으로 되어 있었다면 조경 부분을 수정하면 전체 도면이 영향을 받는다. 하지만 여러 장의 도면으로 나눠지면 조경 부분 수정 시 다른 부분에는 영향을 끼치지 않는다. 즉 변경 사항에 있어서 재활용이 유리한 구조다.
그리고 설계도 B가 설계도 A와 비교해서 전기 부분만 다르면 나머지 조경, 토목, 구조 부분은 재사용이 가능하다.
이처럼 겹치는 레이어를 재사용하면 사용량도 줄이고 보관하기에도 효율적이다.
그리고 이렇게 겹치는 레이어를 재사용한 상태에서 왼쪽 순서대로 읽으면 설계도 A, 오른쪽 순서로 읽으면 설계도 B로 읽을 수 있다.
설계도 A를 이미 가지고 있는 사람한테 설계도 B를 전달해줘야 한다고 생각해 보자.
설계도 A와 설계도 B는 조경, 토목, 구조 부분이 겹치기 때문에 전기 한 장만 받으면 설계도 B를 만들 수 있다.
레이어드 구조가 아니었다면 전기 하나만 달라서 완전히 새로운 설계도를 만들어야 했다.
즉 레이어 구조는 데이터 전송에 있어서도 더 유리한 구조이다.
이미지의 레이어는 건축 도면과 비슷하지만 조금 다른 방식으로 구성된다.
이미지의 레이어는 바로 직전 단계의 레이어에서 변경된 내용들만 저장된다.
서버에 간단한 페이지를 출력하는 NGINX를 설치한다고 생각해 보자.
이 NGINX를 구성하는 단계는 먼저 OS를 설치하고 NGINX 소프트웨어를 설치한 다음에 NGINX 설정 파일을 수정하고 브라우저에서 표시되는 index.html 파일을 사용자에게 응답할 내용으로 수정해야 한다.
이제 이 순서대로 이미지의 레이어를 구성한다고 생각해 보면 먼저 OS를 준비한 다음에 이 OS 위에서 NGINX 소프트웨어를 설치한다.
소프트웨어를 설치하면 이 OS의 특정 폴더에 NGINX 소프트웨어와 관련된 파일들이 추가된다. 그래서 이 NGINX를 설치한다는 것은 기존 OS 파일 시스템에서 추가되는 부분이 있는 거다. 이렇게 기존 레이어에서 변경되는 것들은 이 기존의 레이어를 수정하는 것이 아니라 기존 레이어 위에 변경된 내용들이 새로운 레이어로 저장된다.
그래서 두 번째 NGINX 설치 레이어에는 이전 레이어인 OS 레이어에서 NGINX 소프트웨어가 추가된 부분만 따로 가지고 있는 거다. 이전 레이어와 비교해서 추가되거나 변경된 파일들이 다음 레이어로 저장되는 것이다. 이미지에서 한 번 저장된 레이어는 변경할 수 없다. 변경 사항이 있으면 새로운 레이어로 저장해야 한다. 마치 소스코드에서 한번 push 한 내용은 되돌릴 수 없는 것과 같다.
nginx 설정 파일인 nginx.conf 파일을 작성하거나 index.html 파일의 내용을 hello nginx로 수정하는 것도 각각 새로운 레이어로 만들어진다. 이렇게 이미지 A를 완성한 다음에 이미지 B를 새로 만드는데 이미지 B는 이전과 똑같은 순서이지만 마지막 단계에서 index.html 파일의 내용을 다른 내용인 커스텀 인덱스로 작성한다고 가정하면 이미지 B를 만들 때 Nginx의 소프트 버전과 NGINX 설정을 이미지 A와 모두 동일하게 설정하면 이 세 번째 NGINX 설정까지는 같은 레이어를 재사용하게 된다.
정리하면 이미지의 레이어는 순차적으로 쌓이고 각각의 레이어는 이전 레이어에서 변경된 부분을 저장하고 있다.
그리고 같은 변경이 일어난 레이어는 공유해서 재사용할 수 있다.
도커 run 명령으로 컨테이너를 실행하면 이미지의 가장 마지막 레이어 위에서 새로운 읽기/쓰기 전용 레이어가 추가된다.
그리고 이 추가된 레이어는 컨테이너 레이너라고 부른다.
애플리케이션에서 로그가 쌓이거나 컨테이너가 실행 중에 생기는 모든 변경 사항들 이 새로운 레이어에 저장된다.
이미지 레이어는 수정이 불가능한 읽기 전용 레이어이다. 이미지의 레이어와 컨테이너의 레이어는 역할이 완전히 다르다.
이미지의 레이어는 컨테이너를 실행하기 위한 세이브 포인트 역할을 하고 컨테이너의 레이어는 실제로 이 이미지를 컨테이너로 실행한 다음에 프로세스가 변경하는 내용을 기록하는 레이어다. 컨테이너 레이어는 쓰기가 가능한 읽기/쓰기 레이어이기 때문에 컨테이너 레이어 한 장이 읽기 전용 레이어들인 이미지의 상단에 추가돼서 컨테이너 실행 중에 변경되는 내용만 기록한다.
정리하면 모든 컨테이너는 각자 자기만의 읽기/쓰기 레이어 한 장을 가진다.
그리고 컨테이너를 만들 때 사용된 이미지에 따라서 이미지의 읽기 전용 레이어 전체를 공유할 수도 있고 일부만 공유할 수도 있다.
이렇게 이미지의 읽기 전용 레이어를 활용하면 컨테이너를 실행할 때 전체 공간을 복사하지 않아도 되기 때문에 컨테이너를 빠르게 실행할 수 있다 그리고 컨테이너가 늘어나면서 사용하는 공간을 최대한 작게 관리할 수 있다.
하나의 이미지로 컨테이너를 수십 개 실행해도 이 컨테이너가 수행하는 근본적인 기능은 동일하다.
docker image history 이미지명
이미지의 레이어 이력 조회
도커 이미지 히스토리 뒤에 이미지 이름을 입력하면 해당하는 이미지의 레이어가 어떻게 구성되어 있는지 확인할 수 있다.
첫 번째로 hello-nginx를 pull 하면 각각의 레이어들을 pull 하는 걸 볼 수 있다.
두 번째로 config-nginx를 pull 하면 각각의 레이어들을 pull 하고 있지 않다.
이미 존재하는 레이어들은 Already exists라고 뜨고 새로 추가된 레이어 부분만 pull 하는 것을 확인할 수 있다.
이미지 레이어 실습 명령어
1. 실습용 이미지 다운로드
docker image pull devwikirepo/hello-nginx
docker image pull devwikirepo/config-nginx
docker image pull devwikirepo/pre-config-nginx
2. 실습용 이미지 히스토리 조회
docker image history devwikirepo/hello-nginx
docker image history devwikirepo/config-nginx
docker image history devwikirepo/pre-config-nginx
3. 실습용 이미지 레이어 조회
docker image inspect devwikirepo/hello-nginx
docker image inspect devwikirepo/config-nginx
docker image inspect devwikirepo/pre-config-nginx
docker image inspect 사용해서 각각의 이미지 레이어의 고유 해시값을 확인해 보자.
이 이미지의 해시값은 SHA256 알고리즘으로 생성되고 각각의 레이어의 변경 사항을 암호화한 값이다.
이미지 레이어의 고유한 해시 값을 통해서 다른 레이어와 구분할 수 있다.
중요한 것은 이미지의 레이어가 고유한 ID가 있다는 걸 이해하면 된다.
정리
Layering
각 레이어는 이전 레이어 위에 쌓이며, 여러 이미지 간에 공유될 수 있다.
레이어 방식은 중복 데이터를 최소화하고, 빌드 속도를 높이며, 저장소를 효율적으로 사용할 수 있게 해 준다.
Copy-on-Write (CoW) 전략
다음 레이어에서 이전 레이어의 특정파일을 수정할 때, 해당 파일의 복사본을 만들어서 변경사항을 적용한다.
이렇게 함으로써 원래 레이어는 수정되지 않고 그대로 유지된다.
읽기/쓰기 레이어인 컨테이너 레이어를 생각하면 된다.
실행된 컨테이너에서 변경된 모든 것들은 이미지가 아닌 컨테이너 레이어에 저장된다.
예를 들어서 nginx 컨테이너를 실행한 다음에 이 실행 중인 컨테이너 안에서 index.html 파일의 내용을 다시 바꾼다고 생각해 보자.
그러면 이미지의 레이어에 있는 index.html 파일의 내용을 수정하는 것이 아니라 컨테이너 레이어에 수정할 index.html 파일을 copy 해 온 다음에 이 파일을 수정 후 write 한다. 그러면 레이어에서 index.html 파일은 총 3개가 되고 이 중에서 가장 최근에 변경한 파일인 컨테이너 레이어에 있는 index.html 파일이 실제 파일의 내용으로 사용된다. 새로운 레이어는 이전 레이어에 영향을 주지 않고 자신의 레이어에 수정할 내용을 카피하고 수정해서 사용하는 거다. Copy-on-Write 전략을 사용하는 목적은 Immutable Layers를 위해서다.
Immutable Layers (불변 레이어) :이미지의 각 레이어는 불변으로, 한번 생성되면 변경되지 않는다.
이렇게 함으로써 이미지의 일관성을 유지하고, 여러 컨테이너에서 안전하게 공유할 수 있다.
Caching (캐싱) : 레이어를 캐시 하여, 이미 빌드된 레이어를 재사용할 수 있다.
이는 이미지 빌드시간을 크게 줄여주며, 같은 레이어를 사용하는 여러 이미지에서 효율적으로 작동한다.
이미지 커밋
이미지를 만드는 방법은 크게 2가지가 있다.
- 실행 중인 컨테이너를 그 상태 그대로 이미지로 만들어내는 커밋 방식
- Dockerfile이라는 명세서를 통해서 이미지를 만드는 빌드 방식
대부분 빌드 방식을 사용하지만 이 빌드 방식이 커밋을 기반으로 동작하기 때문에 커밋 방식도 알아둬야 한다.
- 이미지 커밋 방식은 현재 실행 중인 컨테이너의 상태를 그대로 새로운 이미지로 저장하는 것을 의미한다. 현재 실행 중인 컨테이너는 이미지의 읽기 전용 레이어 위에 컨테이너의 읽기/쓰기 전용 레이어가 올라가 있다.
- 이미지의 읽기 전용 레이어는 nginx의 레이어이고 이 위에서 수정한 사항들은 컨테이너의 읽기 쓰기 레이어에 저장되어 있다.
- 그리고 이 상태를 커밋 명령을 사용해서 새로운 이미지로 만든 것이다. 이렇게 커밋으로 만든 이미지로 새로운 컨테이너를 실행하면 이제 이 컨테이너에서 제공하는 응답은 hello-my-nginx라는 페이지가 된다.
이 커밋 방식을 사용하면 기존 레이어에 새로운 레이어를 한 장 더 추가할 수 있다.
이런 식으로 컨테이너의 이미지는 기존 이미지의 레이어에 새로운 레이어를 쌓아가면서 이미지를 만드는 것이라고 볼 수 있다.
docker run -it —name 컨테이너명 이미지명 bin/bash
컨테이너 실행과 동시에 터미널 접속
docker commit -m 커밋명 실행중인컨테이너명 생성할이미지명
실행 중인 컨테이너를 이미지로 생성
이미지 빌드
이미지 빌드 방식에 대해 알기 전에 IaC의 개념에 대해 알아보자
현대의 인프라 구성에서 가장 중요한 개념 중 하나가 IaC라는 방법론이다.
IaC는 인프라를 코드를 통해서 관리한다는 의미이다.
도커에서도 이 IaC 방법을 활용해서 코드로 이미지를 관리하는 방식이 이미지 빌드이다.
IaC 방법론을 활용하는 많은 소프트웨어들이 시중에 있다.
Docker도 그중 하나이다. Docker는 Dockerfile이라는 소스코드를 사용해서 인프라의 상태를 저장하는 이미지를 만들 수 있다.
Dockerfile: 이미지를 만드는 단계를 기재한 명세서
빌드 방식은 컨테이너를 생성하고 커밋하는 것을 도커가 대신 수행해 준다.
도커에게 어떤 작업을 수행할지를 코드로 작성하는 것이 바로 이 Dockerfile이다.
이미지 제작자가 도커가 이해할 수 있는 문법에 따라서 Dockerfile을 작성하면 도커는 임시로 컨테이너를 실행하고 사용자가 정의한 작업을 수행한 뒤에 커밋을 실행한다. 그래서 도커 빌드를 활용하면 여러 개의 레이어도 쉽게 추가할 수 있다.
레이어를 한 장 추가한 다음에 다시 그 레이어로 만든 이미지를 컨테이너로 만들고 그 컨테이너 위에서 변경 작업을 한 다음에 추가로 커밋하는 것을 도커가 알아서 반복해 준다.
정리하면 도커는 IaC 방식에 따라서 이미지를 Dockerfile이라는 소스 코드로 관리할 수 있다.
코드이기 때문에 애플리케이션 소스 코드와도 함께 관리할 수 있고 버전 관리도 할 수 있다.
Dockerfile에는 이미지를 어떻게 만드는지에 대한 세부 내용이 기재되어 있다.
도커는 이 Dockerfile을 해석해서 이미지를 제작해 준다.
docker build -t 이미지명 Dockerfile경로
Dockerfile을 통해 이미지 빌드
-t 옵션 뒤에 빌드할 이미지의 이름을 입력
Dockerfile이 저장되어 있는 경로를 지정해서 이미지를 빌드할 수 있다.
도커 build 명령어는 Dockerfile이 있는 경로에서 실행해야 한다.
명령어
Dockerfile의 문법은 지시어와 지시어의 옵션으로 구성된다.
그래서 Dockerfile을 작성하려면 각각의 지시어들이 어떤 역할을 하는지, 어떤 옵션 값을 어떻게 넣어야 하는지에 대해서 학습해야 한다.
FROM 이미지명
from은 새롭게 빌드할 이미지에 기반이 되는 베이스 이미지를 지정한다.
from에는 도커가 이미지를 빌드할 때 처음 시작할 베이스 이미지의 이름을 지정하면 된다.
그래서 from 지시어는 Dockerfile에서 필수로 표시해야 한다.
COPY 파일경로 복사할경로
원하는 파일을 레이어에 복사할 수 있다.
CMD [“명령어”]
CMD 지시어는 이미지를 컨테이너로 실행할 때 이 컨테이너 안에서 프로그램을 실행할 명령어를 지정한다.
CMD 지시어에 작성한 명령어는 메타데이터의 CMD 필드에 저장된다.
CMD ["nginx" "-g" "daemon off;"]
foreground로 실행되게 변경하는 것, 초기 프로세스가 종료되지 않고 컨테이너가 계속 실행된다
foreground로 실행하는 것은 nginx 프로그램을 프로세스로 실행한다는 말과 동일하다
컨테이너의 라이프사이클 부분에서 컨테이너는 생성(Created) 단계와 실행(Running) 단계로 구분된다
docker create 이미지명 명령으로 컨테이너를 생성할 수 있었고, docker start 컨테이너명 명령으로 컨테이너를 실행할 수 있었다.
그리고 docker run 명령은 create와 start를 한 번에 실행하는 명령이다.
여기서 중요한 부분은 docker start 또는 docker run 명령으로 컨테이너를 실행하는 시점에서 메타데이터의 Cmd 필드에 있는 명령어를 통해 프로그램을 실행하는 것이다
정리하면 nginx 이미지의 CMD필드에 지정하는 nginx -g daemon off; 라는 명령은, nginx 이미지를 컨테이너로 실행하는 시점에서 컨테이너 내부의 nginx 소프트웨어를 실행하는 명령어로 이해하면 된다.
FROM nginx:1.23
COPY index.html /usr/share/nginx/html/index.html
CMD ["nginx", "-g", "daemon off;"]
COPY 부분에 있는 index.html은 Dockerfile과 함께 있는 경로의 index.html 파일이다.
CMD 부분은 NGINX가 컨테이너를 실행할 때 NGINX 웹서버를 실행하도록 지정하는 부분이다.
커밋은 사용자가 직접 새로운 이미지를 만드는 방법이고 빌드는 도커 데몬이 Dockerfile에 적힌 지시어를 사용해서 이미지를 자동으로 만들어주는 방법이다. 도커 빌드는 IaC 개념으로 인프라의 상태를 Dockerfile이라는 코드로 관리할 수 있다.
커밋 빌드에서 사용자가 직접 수행했던 일들을 Dockerfile의 지시어로 기록해 놓고 필요할 때마다 도커 데몬에게 이미지 빌드를 맡기는 것이다. 하나의 커밋은 기존 레이어에 하나의 새로운 레이어를 추가합니다. 그래서 여러 레이어를 쌓으려면 커밋을 완료한 이미지를 새로운 컨테이너로 만들고 다시 두 번째 레이어를 커밋하는 순서대로 여러 차례 커밋을 수행해야 합니다. 하지만 Dockerfile을 사용하면 도커가 직접 이 작업들을 반복해 주기 때문에 여러 개의 레이어 구조를 편리하게 활용할 수 있다.
빌드 컨텍스트
빌드 컨텍스트는 이미지를 빌드할 때 사용되는 폴더입니다.
이미지 빌드 방식은 도커 데몬이 임시 컨테이너를 실행시키면서 레이어드를 하나씩 추가한다.
그래서 도커 데몬에게 Dockerfile과 빌드에 사용되는 파일들을 전달해 주어야 한다.
이렇게 도커 데몬에게 전달해 주는 폴더가 바로 빌드 콘텍스트입니다.
도커 빌드 명령을 사용하면 빌드 컨텍스트가 도커 데몬에게 통째로 전달된다.
그래서 이 컨텍스트 안에 있는 Dockerfile로 도커 데몬이 이미지를 빌드하는 것이다.
그리고 Dockerfile에서 COPY 지시어를 사용하면 빌드 컨텍스트에 있는 파일이 빌드에 사용되는 컨테이너로 복사된다.
그리고 도커 데몬은 빌드 컨텍스트에 있는 파일만 COPY 명령으로 복사할 수 있다.
아래 명령어 중에서 맨 뒤에 . 이 빌드 컨텍스트를 지정한다.
. 은 명령어를 실행하는 현재 디렉터리 경로를 의미한다.
정리하면 빌드 컨텍스트는 도커 데몬이 이미지를 빌드할 때 전달되는 폴더이고 이 폴더 안에 Dockerfile과 카피에 사용할 파일들이 모두 들어있어야 한다.
그리고 빌드 컨텍스트의 .dockerignore라는 파일을 통해서 빌드 컨텍스트로 전달될 파일을 관리할 수 있다.
Dockerfile이 C 드라이브의 최상단 폴더에 있게 되면 이 Dockerfile이 포함된 C 드라이브 전체가 빌드 컨텍스트가 되어버린다.
그래서 Dockerfile과 빌드에 사용되는 파일만 별도의 폴더로 관리해야 한다.
Dockerfile 지시어
애플리케이션 빌드
애플리케이션의 빌드는 소스 코드를 실행 가능한 상태로 만드는 것을 의미한다.
소스 코드만 가지고 있는 상태로는 프로그램이라고 부를 수 없다.
소스 코드가 실행되기 위해 필요한 라이브러리를 설치하거나 소스 코드를 실행 가능한 프로그램으로 만드는 과정이 필요하다.
이러한 과정들을 통 들어서 애플리케이션 빌드라고 부른다.
즉 애플리케이션 빌드는 소스 코드를 실행 가능한 상태로 만드는 작업을 의미한다.
이 애플리케이션 빌드를 통해서 만들어낸 결과물을 애플리케이션, 프로그램 또는 아티팩트라고 부른다.
도커 이미지를 빌드하는 것은 컨테이너로 바로 실행할 수 있는 이미지를 만드는 것이다.
컨테이너로 실행하는 소프트웨어 중에서는 사용자가 개발한 애플리케이션을 실행할 수도 있지만 데이터베이스 같은 일반적인 소프트웨어를 실행시키는 경우도 많이 있다. 그런데 이런 프로그램을 실행시키는 컨테이너는 별도의 소스 코드가 필요하지 않기 때문에 이미지를 빌드하는 과정에서 애플리케이션 빌드 과정이 포함되어 있지 않다.
정리하면 도커 이미지를 빌드할 때 일반적인 소프트웨어만 실행할 때는 실행 환경을 준비하고 실행할 프로그램만 준비하면 된다. 하지만 개발한 소스 코드를 이미지로 빌드하려면 먼저 소스 코드를 애플리케이션으로 빌드하고 그 애플리케이션을 실행할 수 있는 환경을 준비하면 된다. 그래서 이 경우에는 컨테이너 이미지를 빌드하는 과정 안에서 애플리케이션 빌드 과정이 포함되어 있다.
jar파일이나 애플리케이션의 소스 코드들을 빌드하는 단계와 같은 사전작업은 RUN 명령어
실제 이미지에 빌드된 프로그램을 CMD명령을 통해 실행된다
아래 명령어를 보면 새로운 레이어를 추가하는 명령어가 있고 추가하지 않는 명령어가 있다.
파일 시스템의 내용을 변경하는 부분이 있으면 일반적으로 레이어를 추가한다.
그리고 메타데이터에만 영향을 주는 부분은 레이어가 추가되지 않는다.
그래서 지시어들을 잘 활용해서 레이어들의 개수를 관리할 수 있다.
FROM 이미지명
베이스이미지를 지정
COPY 빌드컨텍스트경로 레이어경로
빌드 컨텍스트의 파일을 레이어에 복사
(cp) (새로운 레이어추가)
RUN 명령어
명령어 실행
(새로운 레이어추가)
CMD [“명령어”]
컨테이너 실행 시 명령어 지정
CMD vs RUN
RUN 지시어 같은 경우는 이미지를 빌드하는 시점에서 실행되는 명령어이다
그래서 컨테이너로 실행하는 시점에는 이미 RUN 지시어의 결과로 만들어진 레이어가 이미지에 포함되어 있다.
예를 들어 RUN npm install이라는 지시어를 dockerfile의 지시어로 추가하실 경우, docker build 명령을 사용해서 이미지를 제작하는 시점에 이미 npm install명령이 실행되고, 결과가 레이어로 추가된다다.
CMD 지시어의 경우 이미지를 컨테이너로 실행하는 시점에 실행되는 명령어이다.
그래서 레이어가 별도로 추가되지 않고 메타데이터에만 저장되어 있다가, docker run 명령을 사용해서 컨테이너 레이어가 추가되는 시점에 명령어로 실행된다.
CMD 지시어를 덮어씌우는 부분
$ docker run -it --name officialNginx nginx bin/bash
이렇게 명령어를 실행하면, nginx의 메타데이터에는 "nginx -g daemon off;"라는 CMD가 사전에 입력되어 있기 때문에 그대로 실행할 경우 nginx 웹서버가 실행된다.
CMD지시어는 docker run으로 컨테이너를 실행하는 시점에서 실행되기 때문에, docker run 명령을 사용해서 덮어씌울 수 있다.
하지만 RUN 지시어는 이미 이미지의 일부가 되어있기 때문에, 컨테이너를 실행하는 시점에서는 이미 실행이 된 상태이다.
docker build -f 도커파일명 -t 이미지명 Dockerfile경로
Dockerfile명이 Dockerfile이 아닌 경우 별도 지정
일반적으로는 Dockerfile의 이름을 Dockerfile이라고 그대로 저장을 한다.
그런데 이 파일의 이름을 다르게 저장하는 경우도 있다.
그래서 Dockerfile의 이름이 Dockerfile 아닌 경우에는 -f 옵션을 줘서 실제로 빌드에 사용할 Dockerfile의 이름을 지정해 주면 된다.
WORKDIR 폴더명
작업 디렉터리를 지정(cd) (새로운 레이어추가)
WORKDIR 지시어는 다음 명령어들이 작업할 디렉터리를 지정할 수 있습니다.
WORKDIR 다음에 나오는 지시어들은 이 WORKDIR에서 지정한 디렉터리를 기준으로 명령어를 수행한다.
WORKDIR 지시어는 리눅스나 윈도우의 CD 명령과 비슷하다.
WORKDIR 지시어는 이후에 사용되는 지시어들에게 영향을 줄 수 있기 때문에 가능한 from 다음에 바로 작성하는 게 좋다.
USER 유저명
명령을실행할사용자변경(su) (새로운 레이어추가)
USER 지시어는 명령어를 실행할 때 이 명령어를 사용할 기본 사용자를 지정합니다.
도커 컨테이너가 실행될 때는 기본적으로 명령어들이 루트 사용자로 실행되기 때문에 실행된 프로세스가 굉장히 많은 권한을 가질 수 있다.
그리고 이 점은 보안에 취약할 수 있기 때문에 컨테이너가 필요 이상의 권한을 가지지 않도록 유저 지시어로 조절할 수 있다.
EXPOSE 포트번호
컨테이너가 사용할 포트를 명시
EXPOSE 지시어는 컨테이너가 실행될 때 사용할 네트워크의 포트를 기재한다.
EXPOSE를 사용하지 않아도 기본적으로는 컨테이너가 모든 포트를 사용할 수 있다.
그럼에도 굳이 EXPOSE 지시어를 사용하는 이유는 이 Dockerfile을 읽는 다른 사람에게 애플리케이션이 사용하는 포트를 문서처럼 기재하기 위해서이다. 보통은 애플리케이션 소드 코드 안에 애플리케이션이 사용할 포트를 지정한다. 이렇게 Dockerfile 안에도 Expose로 애플리케이션이 사용할 포트를 명시해 놓으면 굳이 소스 코드를 보지 않아도 Dockerfile만 가지고도 포트를 확인할 수 있다.
환경변수설정: ARG와 ENV
도커에서 환경 변수는 arg나 env로 지정할 수 있다.
시스템 환경 변수는 다양한 방법으로 활용할 수 있다.
ENV color app에서 환경변수에 따라서 다른 색깔의 웹 페이지를 응답할 수도 있다.
애플리케이션이 DB에 접속하기 위해서 데이터베이스 접속 정보를 환경 변수에 저장하는 경우도 있다.
여기서 ARG와 ENV의 차이는 컨테이너를 실행할 때 환경 변수가 유지되는지에 대한 여부이다.
ARG로 지정한 환경변수는 도커 build 명령으로 이미지를 빌드할 때만 사용된다.
ENV 명령으로 지정한 환경 변수는 도커 build뿐만 아니라 이 이미지를 컨테이너로 실행할 때까지 지속적으로 유지된다.
ARG 변수명 변수값
이미지 빌드 시점의 환경변수 설정 docker build --build-arg 변수명=변숫값으로 덮어쓰기 가능
ENV 변수명 변수값
이미지 빌드 및 컨테이너 실행 시점의 환경변수 설정 (새로운 레이어추가) docker run -e 변수명=변수값 으로 덮어쓰기 가능
정리하면 ARG는 빌드에만 사용할 환경 변수를 지정할 때 사용한다. ENV는 애플리케이션이 실행할 때 참고할 용도로 사용한다.
그리고 기본적으로 특수한 경우를 제외하고는 ENV를 사용하면 된다.
프로세스실행: ENTRYPOINT와 CMD
CMD에 들어가는 명령어는 띄어쓰기를 기준으로 여러 개를 넣을 수 있다.
그런데 이 CMD로 지정하는 명령어 중에서 일반적으로는 고정되는 값들이 많이 있다.
예를 들어 Node.js 환경에서는 npm start, npm install처럼 npm이라는 부분이 계속 중복된다.
그래서 이 중복되는 명령어는 Dockerfile의 ENTRYPOINT로 지정해서 관리할 수 있다.
ENTRYPOINT[”npm]
CMD[”statrt”]
로 되어 있는 경우 실제 실행 명령은 npm start가 된다.
ENTRYPOINT를 활용하면 사용자가 CMD를 bash로 덮어쓰기 해서 터미널로 들어오는 것도 관리할 수 있다.
ENTRYPOINT [“명령어”]
고정된 명령어를 지정
CMD [“명령어”]
컨테이너 실행 시 실행 명령어 지정
멀티 스테이징 빌드
멀티 스테이징 빌드는 Dockerfile에서 두 개의 베이스 이미지를 활용하는 방법이다.
보통 애플리케이션을 빌드하는 과정에서 만들어지는 파일들이 용량을 많이 차지한다.
자바로 개발된 소프트웨어는 jar나 war라는 파일로 소스 코드를 실행 가능한 아티팩트로 build 할 수 있다.
이 jar 파일을 실행시키기 위해서는 OS에 Java Runtime이 설치되어 있어야 한다.
그리고 이 소스 코드를 애플리케이션으로 build 하려면 maven이나 gradle이라는 build 도구가 필요하다.
JavaHelloApp에서는 maven을 활용했다.
이제 자바 애플리케이션을 실행할 수 있는 환경을 만드는 것을 순서대로 정리해 보자.
먼저 OS 위에 자바 런타임과 메이븐을 설치한다.
그리고 git clone을 통해 소스코드를 다운 받고 mvn clean package라는 maven 명령을 사용해서 애플리케이션 build를 실행한다.
build를 하고 나면 애플리케이션 artifact 파일인 app.jar 파일이 만들어진다.
이 애플리케이션을 실행하려면 이미지에 보이는 java -jar 명령을 수행하면 jar 파일을 실행할 수 있다.
그리고 실행된 애플리케이션에 접속하면 이렇게 헬로월드라는 문자열을 출력하는 웹 애플리케이션이 실행된다.
참고
인프런의 개발자를 위한 쉬운 도커 강의를 보고 정리한 글입니다.
'Docker' 카테고리의 다른 글
7. 도커 볼륨 (0) | 2024.08.16 |
---|---|
6. 네트워크 (0) | 2024.08.15 |
5. 컨테이너 애플리케이션 구성 (0) | 2024.08.15 |
3. 이미지 레지스트리 (0) | 2024.06.29 |
2.이미지와 컨테이너 (0) | 2024.06.29 |