60/120

김건호·2022년 5월 10일
1

Docker 이미지 빌드

방법

  • docker commit
  • Dockerfile (보통 많이 사용)

docker commit

이미지를 만드려면 해당 이미지로 컨테이너 띄움

docker run -d httpd
docker exec -it id bash

웹컨텐츠는 /usr/local/apache2/htdocs 있음

echo "<h1>hello world!</h1>" > index.html

vagrant@docker  ~  docker commit --help
Usage:  docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

docker commit 을 이용한 이미지 생성

vagrant@docker  ~  docker commit 컨테이너이름 myhttpd(생성할 이미지이름)
sha256:59bbcc0fc00c7b1717c12298aa1279f883ade402322469e0bab192d8e0c41668

만든 이미지 생성 확인

vagrant@docker  ~  docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
myhttpd       latest    59bbcc0fc00c   3 seconds ago   144MB
...

이미지 작동 테스트

vagrant@docker  ~  docker run -d -p 80:80 myhttpd
76d3bc12e27541bada2ad47483131f067ef8920db75fed50b24fc6e20c57b068

docker diff

docker diff id 비교대상군은 이미지

 ✘ vagrant@docker  ~  docker diff 8f
C /root 
A /root/.bash_history  # bash의 명령어를 실행했기 때문에
C /usr
C /usr/local
C /usr/local/apache2
C /usr/local/apache2/logs
A /usr/local/apache2/logs/httpd.pid 
# 아파치 프로세스의 ID가 저장되는 파일, 커널이ㅣ 관리 프로세스 ID가 몇번이지 기록 -> 항상 바뀌거나 생성
C /usr/local/apache2/htdocs # 파일 속성바뀌면 위에위에 다 영향을 받음
C /usr/local/apache2/htdocs/index.html #변경한 내용, 파일 속성 바뀜

root@8fbaa302aea5:/usr/local/apache2# cd icons
root@8fbaa302aea5:/usr/local/apache2/icons# rm a.gif
root@8fbaa302aea5:/usr/local/apache2/icons# exit
exit
 vagrant@docker  ~  docker diff 8f
...
D /usr/local/apache2/icons/a.gif
...

A=add, C=change, D=delete

기준 이미지 <-> 컨테이너 차이

서비스포트를 80이 아니라 8080으로 바꿔서 만들어보기

  • sed 사용해서 Listen 바꾸기
  • docker cp를 활용하기

docker cp

vagrant@docker  ~  docker cp --help

Usage:  docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- # 컨테이너에서 호스트로 복사
        docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH # 호스트에서 컨테이너로
CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS          PORTS                                   NAMES
76d3bc12e275   myhttpd   "httpd-foreground"   18 minutes ago   Up 18 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp       peaceful_babbage

docker cp 76:/usr/local/apache2/conf/httpd.conf ./httpd.conf
# 파일의 Listen 80 -> Listen 8080
docker cp ./httpd.conf 76:/usr/local/apache2/conf/httpd.conf 
docker commit id myhttpd:p8080(tag)

docker run -d -p 80:8080 myhttpd:p8080

우분투 이미지로 httpd이미지 만들기

-c 옵션을 사용

docker commit -c "CMD=~~" id
docker run -itd ubuntu
docker exec -it NAME bash
# 아파치 설치
docker commit -c 'CMD /usr/sbin/apachectl -DFOREGROUND' [NAME] [images name you want]

https://docs.docker.com/engine/reference/commandline/commit/#commit-a-container-with-new-cmd-and-expose-instructions

systemctl이 없기 때문에 아파치를 실행하는 명령어를 직접 사용하여 실행
centos는 /usr/bin/httpd -DFOREGROUND

docker image inspect 로 확인 시 다른점

CMD의 항목이
/usr/sbin/apachectl -DFOREGROUND 만 있는게 아니라

/bin/sh # 셸로
-c # 뒤에 문자열을 셸이 실행하도록 하는 옵션
/usr/sbin/apachectl -DFOREGROUND # 를 실행하겠다

로 되어 있음

ExposedPorts가 없음

ExposedPorts 는 사용자에게 제공되는 정보로 실제 작동과는 연관이 없음
EX)

"ExposedPorts": {
                "80/tcp": {}
            },

이더라도 실제 서비스가 80포트에서 이뤄진다고 확신 할 수 없음 -> httpd.conf의 Listen의 영향을 받음

ExposedPorts는 필요하다면 설정가능
docker commit -c "CMD /usr/sbin/apachectl -DFOREGROUND" -c "EXPOSE 80/TCP" ID IMAGENAME:TAG

이미지 레이어

이미지는 전부 RO -> 이미지를 가지고 컨테이너를 생성하면 컨테이너는 레이어를 하나 더 얹음(RW) -> 컨테이너가 됨 -> 변경한 데이터는 이 새로만든 레이어에 저장 -> 명령어를 가지고 커밋
--> 결론은 이미지지를 사용해 컨테이너를 만들면 RW 레이어가 추가되어 컨테이너가 되고, commit으로 이미지를 생성하게 되면 RW 레이어가 RO 레이어로 변경되어 합쳐져 이미지가 됨

docker inspect id 해서 보면 아래와 같은 항목에서
LowerDir의 첫 번째줄은 RO 레이어
두 번째 줄은 RW 레이어

"GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/~~~~:
                /var/lib/docker/overlay2/~~",

            }

레이어에서 파일을 삭제하면❓

레이어에서 파일 하나 지우면 레이어를 지웠다는 정보를 가진 레이어를 만들어서 결합 -> 지워진 파일이 보이지 않게 됨

docker history, docker image history

이미지 레이어를 상세하기 보기 위한 명령어

docker history, docker image history

 vagrant@docker  ~  docker history httpd
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
c30a46771695   2 weeks ago   /bin/sh -c #(nop)  CMD ["httpd-foreground"]     0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  EXPOSE 80                    0B
<missing>      2 weeks ago   /bin/sh -c #(nop) COPY file:c432ff61c4993ecd…   138B
<missing>      2 weeks ago   /bin/sh -c #(nop)  STOPSIGNAL SIGWINCH          0B
<missing>      2 weeks ago   /bin/sh -c set -eux;   savedAptMark="$(apt-m…   60.6MB
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV HTTPD_PATCHES=           0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV HTTPD_SHA256=d0bbd112…   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV HTTPD_VERSION=2.4.53     0B
<missing>      2 weeks ago   /bin/sh -c set -eux;  apt-get update;  apt-g…   2.63MB
<missing>      2 weeks ago   /bin/sh -c #(nop) WORKDIR /usr/local/apache2    0B
<missing>      2 weeks ago   /bin/sh -c mkdir -p "$HTTPD_PREFIX"  && chow…   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV PATH=/usr/local/apach…   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV HTTPD_PREFIX=/usr/loc…   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      2 weeks ago   /bin/sh -c #(nop) ADD file:8b1e79f91081eb527…   80.4MB

missing -> 로컬 저장소에 없다
사용했던 명령어들이 적혀져있음

레이어 사용의 장점

저장소 및 네트워크 전송 효율성 높임

  1. 레이어를 분리 시키면 동일한 레이어가 있는경우는 해당되는 레이어를 받지 않아도 됨 -> 중복된 레이어는 별도로 저장할 필요가 없음

  2. 파일을 분리하여 저장할 수 있음
    변경될일이 없을거 같으면 한번에 파일을 저장하는게 효율적
    변경이 될거같으면 면 레이어 분리시키는게 효율적
    커밋한번당 레이어 한번

docker export

컨테이너 -> 아카이브

docker export <CONTAINER> -o <TARFILE>

docker save와의 차이

docker save는 이미지를 아카이브 하는 명령어

docker import

아카이브 -> 이미지

docker import <TARFILE> <IMAGE>:<TAG>

TIP! 1개의 레이어로 가져오기
하나의 레이어로 만들고싶으면 export하고 import하면 하나의 레이어로 가지고 올 수 있음

docker load와의 차이

docker load는 docker save에 의해 생성된 아카이브를 이미지로 가져오는 명령어
docker import 는 docker export에 의해 생성된 아카이브를 이미지로 가져오는 명령어

Dockerfile 이미지 생성

https://docs.docker.com/engine/reference/builder/
파일명은 Dockerfile로 정해져 있음

docker build .

docker build . 를 통해 도커파일에 정의 된대로 이미지를 빌드하게 됨
.은 경로 현재디렉토리

❗❗ 도커파일을 /에 만들지 않기->현재 디렉토리 밑에 전부 이미지로 만들어서 루트에 하면 루트시스템을 전부 다 만들어버림

-t 옵션으로 태그를 지정할 수 있음
이름이 여러개라면 -t 를 여러개 만들면 됨

지시어

# Comment
INSTRUCTION arguments

FROM

새로 빌드할 이미지의 베이스 이미지 지정, 컨테이너를 띄울 베이스 이미지를 지정

FROM <image>
FROM <image>[:<tag>]
FROM <image>[@<digest>]

플랫폼은 x86 x86장비인데 amd 용 이미지는 불가
latest는 안써야함
AS name 별칭 -> 따로 상황이 있음

shell form과 exec form

이미지를 만들때 이미지를 빌드할때 FROM에서 베이스이미지를 지정할때, 베이스이미지를 지정하고 이미지를 빌드할때 실행할 명령어

shell form

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
docker run -d httpd
docker stop ~~ -> 금방 종료가 돔
docker start ~~ 
docker stop ~~
time docker stop ~~ -> 1.5 초 정도걸림
docker inspect ~~ 보면 State라는 항목 status exited, ExitCode 0 정상종료
컨테이너 중지 -> 프로세스 종료 프로세스를 정상적으로 종료시켜야 리턴코드가 0

exec form

RUN ["/bin/bash", "-c", "echo hello"]
docker run -d myweb
docker stop ~~
docker start ~~
time docker stop ~~ 10초가 걸림
docker inspect ~~ 상태를 보면 ExitCode 137

쌍따음표만 가능❗

차이는❓

프로세스의 정상종료는
X창누르면 15번 시그널이 전송 됨 SIGTERM (kill -l 로 확인) = 정상 종료 시그널
15번 시그널을 보냈을때 정상종료 -> 부모프로세스에 리턴코드를 보냄
stop 은 15번 시그널 전송 시키는 것

httpd-fore~ httpd가 직접받음 httpd가 제대로 받고 정상 종료
/bin/sh ~~ 은 셸이 직접받음 -> 15번 시그널 무시 -> apache에 보내야하는데 무시해서 아무작업을 안함
도커는 10초동안 응답이 안오면 9번시그널을 보냄 -> 어떤 프로세스도 무시 불가 137-128=9
9번으로 종료시킨 것

결론은❓

RUN은 shell form, CMD, ENTRYPOINT는 exec form
shell form은 하위 프로세스에게 시그널을 전달하지 않기 때문에

RUN

빌드시 실행할 명령

Shell Form

RUN yum install httpd

=> /bin/sh -c yum install httpd

Exec Form

RUN ["yum", "install", "httpd"]

=> exec yum install httpd

exec는 명령 X

CMD

기본 실행 어플리케이션

Shell Form

CMD /usr/sbin/httpd -DFOREGROUND

=> /bin/sh -c yum install httpd

Exec Form(선호)

CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

EXPOSE

외부에 노출할 포트 및 프로토콜

EXPOSE <PORT>/<PROTOCOL>

ENV

쉘 환경 변수

ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy

ADD/COPY

도커 호스트 -> 컨테이너 파일 복사

ADD <SRC> <DEST>
COPY <SRC> <DEST>

호스트에 있는 게 소스 -> 컨테이너로 복사

ADD는 SRC로 URL 지정 가능

ENTRYPOINT

CMD의 명령으로 사용

ENTRYPOINTCMDResult
XX허용X
Xabcabc
xyzXxyz
xyzabcxyz abc

결론은❓

ENTRYPOINT가 CMD보다 먼저❗

사용방법

ls -l을 사용할 때 ENTRYPOINT를 ls로 설정하고 CMD를 -l로 설정하면 옵션을 바꾸고 싶을 때 CMD의 내용만 변경하기

VOLUME

자동으로 마운트할 볼륨 마운트 포인트 지정

VOLUME /myvol

WORKDIR

작업 디렉토리
RUN, CMD, ENTRYPOINT, ADD, COPY에 영향을 미침

WORKDIR /usr/local

레이어

RUN, ADD, COPY 레이어를 만듦

예제

mkdir -p ~/image-build/myweb
cd ~/image-build/myweb

Dockerfile

FROM centos:7
RUN yum install -y httpd
ADD index.html /var/www/html/index.html
CMD ["/usr/sbin/httpd", "-DFOREGROUND" ]
EXPOSE 80/tcp

index.html

hello dockerfile
docker build -t myweb:centos .

Linux Timezone 설정

/etc/localtime 파일이 가리키고 있는 파일이 시간대

시간대
/usr/share/zoneinfo/*

sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
sudo timedatectl

ubuntu 20.04/focal 이미지 부터 시간대가 설정되어 있지 않음
우회: ENV DEBIAN_FRONTEND=noninteractive

tzdata

timezone을 세팅하는 패키지
도커파일 빌드 시 타임존 설정을 미리 하는 방법

DEBIAN_FRONTEND=noninteractive apt install tzdata
이렇게하면 넘어가짐
ls -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
apt install -y apache2


FROM ubuntu:focal
RUN apt update
RUN DEBIAN_FRONTEND-noninteractive apt install tzdata
RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /ect/localtime
RUN apt install -y apache2
ADD index.html /var/www/html/index.html
EXPOSE 80/tcp

진행하게 되면 경고가 나옴

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
apt는 안정적인 CLI 인터페이스가 아니다 스크립트 사용시 주의해라

apt, apt-get 차이

처음부터 apt존재하진 않았음
apt-get은 처음부터 존재한 명령어

apt-get install 하고 검색할때는
apt0cache search 명령어가 다 다름
apt-~~~ 명령어 분리되어 있어서 귀찮음 -> 그래서 만든게 apt 명령어
자주쓰는 명령어만 뽑아온거
apt 다른거의 100 가져온거아니고 일부 주요한 기능들만 가져왔고
일부기능만 있을수있으니까 경고를 주는것


도커파일 베스트 프렉티스
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

profile
Ken, 🔽🔽 거노밥 유튜브(house icon) 🔽🔽

0개의 댓글