Image 를 만드는 법 (2가지)
- 컨테이너를 commit 하기
- 이미지로 back-up 해두는 느낌이다
- Dockerfile을 build 하기
- 이미지를 생성하는 느낌이다
1. 컨테이너를 commit 해서 이미지 생성하기
먼저 ubuntu:20.04를 가져와서 컨테이너 생성하기
PS C:\Users> docker run --name web-server -it ubuntu:20.04
도커 이미지를 commit으로 만들기
PS C:\Users> docker commit
"docker commit" requires at least 1 and at most 2 arguments.
See 'docker commit --help'.
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Create a new image from a container's changes
PS C:\Users> docker commit web-server web-server-commit
sha256:022cb7cfedf7a298c20955dfdfc30ebf4175a0ba136fcf3f37c38377ddc21e88
이미지가 만들어졌는지 확인하기
PS C:\Users> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web-server-commit latest 022cb7cfedf7 6 seconds ago 72.8MB
이미지를 생성한 것을 확인 할 수 있었다
위의 방법과 같이 Dockerfile 파일을 통해 이미지를 생성하고 싶다
2. Dockerfile 파일을 build 해서 이미지 생성하기
아주 간단한 Dockerfile 파일을 만들기
FROM이라는 명령문만 있는 Dockerfile
FROM ubuntu:20.04
Dockerfile 파일 build 하기
PS C:\Users\Desktop> docker build -t web-server-build .
이미지 생성 된거 확인 완료
PS C:\Users\JibinKim\Desktop> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web-server-commit latest 022cb7cfedf7 31 minutes ago 72.8MB
web-server-build latest 3c97ce3e1958 5 weeks ago 72.8MB
Dockerfile 명령문
Dockerfile은 다음과 같은 형식으로 여러 개의 명령문으로 구성되어 있다.
# 주석(Comment)
명령어(INSTRUCTION) 인자(arguments)
명령어 종류
FROM | base 이미지 설정 |
WORKDIR | 작업 디렉터리 설정 |
RUN | 이미지 빌드 시 커맨드 실행 |
ENTRYPOINT | 이미지 실행 시 항상 실행되야 하는 커맨드 설정 |
CMD | 이미지 실행 시 디폴트 커맨드 또는 파라미터 설정 |
EXPOSE | 컨테이너가 리스닝할 포트 및 프로토콜 설정 |
COPY/ADD | 이미지의 파일 시스템으로 파일 또는 디렉터리 복사 |
ENV | 환경 변수 설정 |
ARG | 빌드 시 넘어올 수 있는 인자 설정 |
Dockerfile 파일 작성법
- 베이스가 되는 이미지(image) 선택하기
- 작업 디렉토리(working directory) 지정하기
- Host에서 컨테이너로 파일 복사하기
- 의존성(dependencies) 설치하기
- 포트를 Expose 하기
- 환경변수 설정하기
- 실행 할 명령어 지정하기
예시
# Step 1 : Ubuntu (베이스 이미지)
FROM ubuntu:latest
# Step 2 : 작업 디렉토리(working directory) 지정하기
WORKDIR /app
# Step 3 : Host에서 컨테이너로 파일 복사하기
COPY app.py /app/
# Step 4 : Python3 설치
RUN apt-get update && apt-get install -y python3
# STEP 5 : 포트를 Expose 하기
EXPOSE 8080
# STEP 6 : Python3 시작
CMD ["python3", "app.py"]
실전
좀 더 복잡한 Dockerfile 파일
아래와 같이 적기
FROM ubuntu:20.04
# 파이썬3 설치, -y 자동으로 예스 눌러줌
RUN apt update && apt install -y python3
WORKDIR /var/www/html
RUN echo "Hello, Docker" index.html
# Hello docker을 index.html에 넣기
CMD ["python3", "-u", "-m", "http.server"]
Build 후에 Run 해보기
PS C:\Users\Desktop> docker build -t web-server-build .
[+] Building 40.5s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 299B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:20.04 0.0s
=> [2/4] RUN apt update && apt install -y python3 38.9s
=> [3/4] WORKDIR /var/www/html 0.1s
=> [4/4] RUN echo "Hello, Docker" index.html 0.5s
=> exporting to image 0.9s
=> => exporting layers 0.9s
=> => writing image sha256:9924bd9be6182cd898f6573927b71c7603d78e537f3f40a163c019d07be63a9c 0.0s
=> => naming to docker.io/library/web-server-build
PS C:\Users\Desktop> docker run -p 8888:8000 --name web-server web-server-build
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Dockerfile Best Practice
- 인증 안된 컨테이너 이미지는 사용하지 않기
→ Docker Official Images 가 비교적 안전햐다
- 컨테이너(이미지) 는 최대한 작게 만들기
- Command과 Tag 를 적절하게 잘 사용하기
- Lint 툴을 사용하기
컨테이너의 용량 작게 사용하는 방법
- 작은 컨테이너(이미지)를 사용하기
- 레이어(Layer) 를 의식하기
- Multi-stage build 를 사용하기
레이어(Layer) 란??
도커 이미지는 레이어(layer)와 메타정보라는 것으로 구성된다
뭐 이런 구조라는걸 알면 된다
실전
이미지 하나를 다운로드해서 레이어를 확인해보자
busybox라는 이미지 다운로드
PS C:\Users\testforLayer> docker pull busybox:1.34.1
1.34.1: Pulling from library/busybox
2123501b93d4: Pull complete
Digest: sha256:05a79c7279f71f86a2a0d05eb72fcb56ea36139150f0a75cd87e80a4272e4e39
Status: Downloaded newer image for busybox:1.34.1
docker.io/library/busybox:1.34.1
docker inspect busybox:1.34.1 라는 명령어를 통해 레이어 확인하기
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:d6a7fc1fb44b63324d3fc67f016e1ef7ecc1a5ae6668ae3072d2e17230e3cfbc"
]
},
sha256 라는 레이어가 추가된걸 확인완료!
뭐.... 이런게 레이어구나라고 이해 할 수 있다!!
레이어(Layer)란 구체적으로
도커 이미지는 컨테이너를 만드는 '압축 파일' 이라고 생각하면 이해하기 쉽다
도커 이미지는 컨테이너를 실행하기 위한 모든 정보를 가지고 있기 때문에 용량이 크다 (수백 MB이다)
도커 이미지를 한번 다운로드 하고 끝인거면 용량이 커도 딱히 문제 없을 것이다
근데 기존의 도커 이미지에 파일 하나를 추가했을 경우
또 다시 다운로드 해야할 때 처음부터 다시 수백MB를 다시 다운받아야 한다면 매우 비효율적이다
도커는 이런 문제를 레이어(layer)라는 개념을 도입하여 해결했다
압축파일과 이미지는 비슷한데 차이점은 아래의 그림과 같다.
압축파일과 다른점은 이미지가 레이어를 공유한다는 점이다!
실전
nginx:1.15.1을 다운로드 해보기
PS C:\Users\testforLayer> docker pull nginx:1.15.1
1.15.1: Pulling from library/nginx
be8881be8156: Pull complete
f2f27ed9664f: Pull complete
54ff137eb1b2: Pull complete
Digest: sha256:4a5573037f358b6cdfa2f3e8a9c33a5cf11bcd1675ca72ca76fbe5bd77d0d682
Status: Downloaded newer image for nginx:1.15.1
docker.io/library/nginx:1.15.1
그리고 nginx:1.15.2를 또 다운로드 해보기
PS C:\Users\testforLayer> docker pull nginx:1.15.2
1.15.2: Pulling from library/nginx
be8881be8156: Already exists
32d9726baeef: Pull complete
87e5e6f71297: Pull complete
Digest: sha256:d85914d547a6c92faa39ce7058bd7529baacab7e0cd4255442b04577c4d1f424
Status: Downloaded newer image for nginx:1.15.2
docker.io/library/nginx:1.15.2
be8881be8156: Already exists 라는 안내문이 나온다
be8881be8156 이라는 레이어가 이미 존재하기 때문에 다운로드 하지않고 넘어간 것이다
따라서 nginx:1.15.1 과 nginx:1.15.2는 서로 같은 레이어(be8881be8156)를 공유한다는 것을 알 수 있다.
Dockerfile을 build 할 경우
Dockerfile의 명령어 한줄마다 이미지(layer)가 작성된다.
작성된 여러개의 이미지는 레이어 구조로 되어 있다
실전
Dockerfile 작성 & index.html 생성
같은 폴더 내에 Dockerfile과 index.html 만들기
Dockerfile
# STEP: 1 Ubuntu (베이스 이미지)
FROM ubuntu:latest
# STEP: 2 Nginx 설치
RUN apt-get update && apt-get intstall -y -q nginx
# STEP: 3 파일복사
COPY index.html /usr/share/nginx/html/
# STEP: 4 Nginx 시작
CMD ["nginx", "-g", "daemon off;"]
index.html
$ cat > index.html
Hello World Dockerfile!
Dockerfile build 하기
PS C:\Users\JibinKim\study\docker\testforLayer> docker build -t webap .
[+] Building 87.2s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 302B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:latest 2.9s
=> [internal] load build context 0.0s
=> => transferring context: 29B 0.0s
=> CACHED [1/3] FROM docker.io/library/ubuntu:latest@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 0.0s
=> [2/3] RUN apt-get update && apt-get install -y -q nginx 83.4s
=> [3/3] COPY index.html /usr/share/nginx/html/ 0.0s
=> exporting to image 0.7s
=> => exporting layers 0.7s
=> => writing image sha256:f176f7bca7171ae6af31621cc52e298e4a4767e10d06a301cbbe3ea7c4f0bbb8 0.0s
=> => naming to docker.io/library/webap 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Docker inspect를 통해 레이어(layer) 확인하기
FROM, RUN, COPY 명령문으로인해 레이어 3개 작성되었다!
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:b93c1bd012ab8fda60f5b4f5906bf244586e0e3292d84571d3abb56472248466",
"sha256:3d9a7922fd9742fa619d261d8b6ade9c04457e98ead64f54ef9d1c9bc96b1556",
"sha256:aa27044af1e0b80cfcca5e83cd8c5da8cfe790b73a9148f2798f9f7070d6bf7d"
]
},
Read-Only layer / Runtime Read-Write layer
Read-Write layer (Container layer)
- 컨테이너가 생성될 때 Read-Write 속성의 layer가 생성된다 (container layer) 라고 부른다.
- 컨테이너에서 작업한 데이터는 Container layer에 저장된다.
- Container layer는 컨테이너가 사라지면 삭제된다
Read-Only layer (Image layers)
- 이 레이어들은 각각 독립적으로 저장되며 읽기 전용(read-only)이기 때문에 임의로 수정할 수 없다
- RUN이나 COPY 명령문을 실행할때마다 read-only의 레이어가 계속 쌓인다
레이어를 최대한 적게 만들어라!
안 좋은 예시 ❌
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y -q nginx \
curl automake \
build-essential
RUN rm -rf /cmd/*
좋은 예시 👌
FROM ubuntu:latest
RUN apt-get update \
apt-get install -y -q nginx \
curl automake \
build-essential \
rm -rf /cmd/*
Cache를 생각하여 레이어를 분할하라!
- docker build를 할 때 변경이 필요 없는 레이어는 cache가 사용된다
- cache를 의식함으로 인해 docker build 시작은 줄일 수 있다
안 좋은 예시 ❌
FROM ubuntu:latest
COPY myapp ./
RUN apt-get update &&\
apt-get install -y \
build-essential &&\
rm -rf /cmd/* &&\make
좋은 예시 👌
FROM ubuntu:latest
RUN apt-get update &&\
apt-get install -y \
build-essential &&\
rm -rf /cmd/*
COPY myapp ./
RUN make
Multi-stage build
- 하나의 Dockerfile을 여러개의 스테이지로 나눠서 적을 수 있다.
- 이용 예시
- Build 용 implement 용 스테이지를 나누기
- Build 용 컨테이너로 실행 파일을 build하기
- 실행파일을 실행용 컨테이너
참고자료)
'Docker' 카테고리의 다른 글
Docker의 네트워크 방식 (0) | 2023.02.08 |
---|---|
[Docker] 도커의 기본적인 명령어 (알아두면 좋은 것들 정리) (0) | 2023.02.06 |
[Docker] 도커와 컨테이너란? 아주 쉽게 설명!! (Container, Image) (0) | 2023.02.04 |