Dockerfile & Image

lamPolar·2023년 4월 5일
0

42seoul

목록 보기
5/5
post-thumbnail

지금까지 배운거

image를 pull받아서 container run시키기
근데 나의 이미지로 container를 만들 수는 없을까?

나의 도커 이미지 만들기

방법은 2개

1. container를 수정하고, commit하기

2. 원하는 방식으로 dockerfile을 작성하고 build하기

Q. commit과 build의 차이는?
둘다 결과적으로 이미지를 만드는 명령어이다.
commit : 이미 사용하고 있는 컨테이너가 있을 때 이미지로 만드는 것 ( 백업 느낌)
build : 도커 파일을 바탕으로 구체적으로 시간순서에 따라서 새로 이미지를 생성하는 것

도커파일을 이용하면 어떤 과정을 통해서 이미지가 만들어졌는지 분명하게 이해할 수 있다.
나뿐만 아니라 남들도 마찬가지!

이번 수업은 빌드가 위주이지만, commit도 보긴해야지

웹서버 이미지를 만들고 싶다.

진짜요? 그래요.그럼 만듭시다.
같은 이미지를 commit 방식과 build방식 두가지로 만들어보아요

vscode기능중에 docker확장기능 추천

commit 방식

  • ubuntu 20.04 이미지 다운로드 후 컨테이너 생성
    docker run -p 8888:8000 --name web-server -it ubuntu:20.04
  • web-server컨테이너를 web-server-commit 이름으로 이미지 생성
    docker commit web-server web-server-commit
  • 이미지 생성확인
    docker images
  • 컨테이너 안으로 이동
  • 파이썬3 다운로드
    apt update
    apt install python3
  • 이순간에 커밋하면 이미지 생성가능
  • 사용자 요청을 저장할 디렉토리 생성하기
    mkdir -p /var/www/html
    cd /var/www/html
  • index.html 파일 생성
    echo "Hello, <strong>Docker</strong>" > index.html
    ls
  • python3에 내장된 웹서버를 실행하고, 8000번 포트를 리스닝
    python3 -m http.server
  • http://0.0.0.0:8888 로 접속하면 작성한 index.html이 보인다.

build 방식

  • docker file 생성
FROM ubuntu:20.04 //기본 이미지를 ubuntu로 설정
RUN apt update && apt install -y python3 //파이썬 3 다운로드
WORKDIR /var/www/html //directory가 없다면 만들고, 그 위치로 이동시킴
//이제부터 실행하는 run, entrypoint, cmd같은 명령어가 실행될때는 저 디렉토리 위치에서 실행됨.
COPY ["index.html", "."] //host에 있는 index.html을 WORKDIR로 복사하기
==== 이미지 생성 끝
CMD ["python3", "-u", "-m", "http.server"] //-u 옵션을 포함시켜야만 실행중인 현재 상태의 로그가 화면으로 출력됨
==== 컨테이너 실행 후 실행

  • 이미지의 이름을 -t(tag)로 설정후 pwd에 위치시키기
    docker build -t web-server-build .
  • build 후 container 실행
    docker rm --force web-server;
    docker run -p 8888:8000 --name web-server web-server-build;
  • http://0.0.0.0:8888 로 접속하면 host디렉토리에 작성한 index.html이 보인다.
  • 컨테이너 실행시 CMD를 실행하고 싶지 않다면 pwd를 쓰기
    pwd가 cmd대신에 실행되어서, 시작명령을 변경할 수 있음 (overriding)
    docker run -p 8888:8000 --name web-server web-server-build pwd;

RUN 명령어는 실행될 때마다 layer가 생성된다. 따라서 가급적 하나의 명령어로 연결실행하는게 유리하다.
RUN apt update;
RUN apt install python3;보다
RUN apt update && apt install python3으로 실행시키는 걸 추천

index.html을 생성하는, 다른 방법이 있다. (commit과 유사)
RUN echo "Hello, <strong>Docker</strong>" > index.html
이렇게 작성하면 WORKDIR로 설정한 디렉토리 아래에 생성이 된다.
하지만, dockerfile이 있는 같은 디렉토리에 index.html 파일을 만들어서, 도커파일이 build될 때 index.html파일을 host에서 image로 복사할 수 있으면 더 좋겠죠? 왜죠?
이전에 도커 볼륨에서 학습했음

dockerfile에 의해서 만들어진 image를 container로 생성할 때 명령어를 실행해서 바로 웹서버를 사용할 수 있는 상태가 되길 바란다면, 도커파일에 CMD명령어를 이용

이제 도커 이미지를 생산하는 생산자가 되었음 와우아

🤦‍♂️찾아봅시다

Q. python3 -u -m http.server 명령어의 뜻은?
원래 http.server는 파이썬이 일반적으로 제공하는 모듈중 하나인데, -m 옵션과 함께 실행하면, 직접실행이 가능하다. 평소엔 확장자가 py인 파일에 import해서 사용해야함.
python3 -m http.server 의 기본 포트는 8000 이고, 만약 변경하고 싶으면 뒤에 포트번호를 써주면 된다. ex) python3 -m http.server 9000

Q. 포트포워딩을 하지 않고 run 했을 때 http://0.0.0.0:8000은 왜 접속이 안되는지?
왜냐면 컨테이너의 포트와 호스트의 포트가 연결되지 않았기 때문! 이해가 되지 않는다면 도커 입문으로 가시죠

Q. 왜 run명령어 뒤에 pwd를 붙이면 CMD명령이 있는데도 일회성으로 실행이 되는지?
Q. CMD명령을 여러개를 쓸수 있나?
Q. 만약 CMD명령이 여러개였다면 모두 실행이 안되고 pwd가 실행이 되는걸까?
세 개의 질문을 묶어서 설명해보자.
CMD명령은 컨테이너가 생성될 때 단 하나의 유효한 값을 갖는다.
그래서 이미 CMD명령이 있었더라도, 이후에 다른 CMD명령어가 입력된다면 이전의 값 대신에 실행된다.
따라서 가장 마지막에 입력된 CMD명령인 pwd가 실행되는 것이다.
원한다면, dockerfile내부에 CMD명령을 여러 개 쓸 수 있다! 그러나 여러 줄을 쓸 경우, 가장 마지막 명령만 유효하게 실행된다.
어떻게든 여러개를 한번에 실행하고 싶다면 > 여기를 참고하자.
CMD명령에 대한 doc페이지

  • 추가로 알게 된 지식 : CMD echo "This is a test." | wc - 이렇게 명령어 형식으로도 쓸 수 있다. 명령어 형식으로 쓸 경우 /bin/sh -c 상황에서 실행되게 된다. json array형식으로 작성하면 shell없이 실행된다.

Q. build로 생성한 이미지로 실행중인 컨테이너도 commit이 가능한지?
논리적으로 생각해보면, build로 생성한 이미지나 commit으로 생성한 이미지나 같은 이미지 타입일 것 같다. 따라서 가능하지 않을까?
=> 가능합니다!
빌드된 이미지 파일로 실행한 컨테이너 파일시스템에서 새로운 파일을 생성하고 commit하니, 이미지 레이어가 하나 더 생기고, 새로운 이미지로 commit됩니다 :)

Q. mkdir -p /var/www/html에서 -p옵션의 의미는?
필요하다면 경로 중간의 디렉토리를 rwxrwxrwx 권한으로 생성한다.
만약 -p 옵션이 주어지지 않았을 때는 경로에 쓰여진 모든 디렉토리가 존재해야만 에러가 발생하지 않는다.

Q. commit 은 어느범위까지 저장(백업)이 되는지? 파일? 실행중인 프로세스?
변경된 컨테이너의 file 혹은 settings 에 대해서 저장된다.

Q. 이미지는 어떤 위치에 주로 저장하는지? (docker build시)
docker가 설치된 가상환경에서, 기본 Docker 경로 /var/lib/docker에 저장된다.

Q. ENTRYPOINT는 무엇인가?
CMD명령문과 같이 컨테이너가 실행하게 될때 수행하게 되는 명령을 정의하는 명령문이다.
CMD와 다르게, 컨테이너 시작시 실행명령에 대한 Default값을 지정하게 되는데, 그래서 변경이 CMD보다 어렵고, 해당 컨테이너가 실행될 때 반드시 ENTRYPOINT에서 지정한 명령을 수행한다.
만약 ENTRYPOINT가 지정되었다면, CMD는 추가 인자값으로 활용된다. 예를 들어, df -h가 entrypoint로 지정되고, ps -aef가 CMD값으로 지정되었다면, 컨테이너가 실행될 때 df -h ps -aef로 실행된다.
따라서, 메인 프로세스인 ENTRYPOINT에서 실행한 명령어에 대한 옵션값을 CMD로 정의해주면 좋다. > 참고

Q. RUN명령어 실행시에 만들어진다는 layer는 무엇일까?
이미지는 레이어로 구성되어있고, 파일이 추가되거나 수정되면 새로운 레이어가 생성된다.
그래서 pull받을 때 여러줄로 분리된 것처럼 받아지는데, 여기서 한 줄씩 분리된 데이터를 Layer라고 한다.
layer는 이미지에 따라 구성이 다른데, 예를 들어 ubuntu 이미지는 1개의 레이어가 있고, nginx 이미지는 5개의 레이어가 있다

Dockerfile에 정의된 명령문 중에 (RUN, ADD, COPY) 3가지 단계만이 레이어로 저장된다.
(CMD, LABEL, ENV, EXPOSE) 등 메타정보를 다루는 명령문은 임시레이어로 생성은 되지만 저장되지 않아서 도커 이미지 사이즈에 영향을 주지 않는다.
레이어를 pull 이후에 확인해보고 싶다면 docker inspect [image 이름]을 실행하면 layer, env등의 정보를 볼 수 있고 docker history [image 이름]을 실행하면 이미지에 포함된 layer들에 대해서 자세히 보여준다.
이미지를 생성할 때 Layer가 쌓이게 되면 파일을 삭제해도 이미지 사이즈는 줄어들지 않는다. 따라서 layer수를 줄이는 것은 이미지를 가볍게 만들 수 있는 가장 핵심적인 방법중 하나다.

  • 컨테이너를 생성할 때도 기존의 이미지 레이어 위에 쓰기가 가능한 레이어를 추가 하는데, 이부분에 대한 추가 설명이 필요하다면 > 여기

Q. ubuntu:20.04 에서 20.04는 태그다. 태그는 무엇일까?
도커에서 이미지의 버전을 관리하기 위해서 사용하는 이미지에 부여되는 별칭이다.
일반적으로 버전 관리를 위해 latest태그보다는 patch numbergit commit을 활용한다.
따라서, 여기서 20.04는 우분투 이미지의 버전을 의미한다.
image생성시 tag명 지정을 생략하면 default값으로 마지막에 build/tag된 이미지라는 뜻의 latest태그가 붙는다.

  • 주의사항 latest 태그가 언제나 가장 최신 버전을 의미하지는 않는다. (tag가 없는 image에 디폴트로 주어진 값일 수도 있으므로)

push

원하는 이미지를 바탕으로 컨테이너가 잘 생성된다면, docker hub 에 push 명령어를 통해서 이미지를 레지스트리에 공유해봅시다.

  • 주의사항 : docker hub는 github와 유사합니다. 미리 가입을 해야합니다.

참조

생활코딩 도커파일
생활코딩 도커 commit
읽어볼거리

profile
불안을 안고 구르는 작은 모난 돌

0개의 댓글