Ian's Archive 🏃🏻

thumbnail
Docker를 톺아보자
CI/CD
2023.08.21.

여러 기업들은 자사에서 데이터센터나 기계실을 보유하여 온프레미스 환경에서 가동시키던 부분을

효율적인 자원 활용을 위해 클라우드 상의 가상 인스턴스로 옮기고 시스템을 구축한다

또한 확장성을 고려해 MSA(Micro Service Architecture) 아키텍처를 적용하며

여러개의 나뉘어진 App을 하나의 Application 처럼 동작할 수 있게 시스템을 구축한다.

이와같은 분산환경을 적용하면 아래와 같은 장점이 있다.

  1. 개별 서비스가 다른 서비스에 영향을 주지 않으면서 작동 (높은 가용성)

  2. 향후 확장 및 새로운 기능 추가 용이 (높은 확장성)

  3. 개발자들이 각각의 서비스를 파악하고 개선하기에 용이해짐 (편리한 엑세스)

  4. 기존 모놀로식 방법에 비해 배포에 따른 우려사항들이 적어짐

기존 VM (Virtual Machine)으로도 MSA환경을 구축할 수 있지만

컴퓨터를 가상화하는 기술이 발전하고 점점 가벼워지면서 컨테이어 기술은 더욱더 인기가 많아지고 있다.

VM은 하이퍼바이저를 사용해 각 머신별로 독립적인 하드웨어 자원을 제공하고

그 자원위에 별도의 OS를 띄운다.

반면에 컨테이너의 경우 리눅스 OS내부에서 커널을 이용하여 리소스를 컨테이너 별로 나눠서 격리시키기

때문에 별도의 OS없이 구동이 된다.

그럼 효율적인 인프라 구성을 위해 컨테이너의 대표 기술인 도커에 대해 알아보자

Container

소프트웨어 서비스를 실행하는 데 필요한 1. 특정 버전의 프로그래밍 언어 런타임 및 2. 라이브러리와 같은 종속 항목과 3. 애플리케이션 코드를 함께 포함하는 경량 패키지

  • 이미지를 기반으로 하는 격리된 소프트웨어 유닛, 이미지를 실행중인 인스턴스
  • 중요한 특징으로 컨테이너는 서로 분리되어 있으며, 디폴트로 공유 데이터나 상태가 없다.

VMvsDocker

Container와 VM을 비교해보면 다음과 같은 특성이 있다.

  • 컨테이너는 VM보다 경량화 되어있다.
  • 컨테이너는 OS수준에서 가상화 되고, VM은 하드웨어 수준에서 가상화 된다.
    -> 메모리, CPU 등 효율적인 자원 사용
  • Linux커널과 Cgroups 및 네임스페이스 등 커널의 기능을 사용해 프로세스를
    분리함으로써 독립적으로 실행할 수 있다.
  • 컨테이너는 OS커널을 공유하며 VM에 필요한 것보다 적은 메모리 사용
  • 컨테이너는 무상태 (Volume에 할당되어 있으면 로컬 호스트 머신의 폴더로 미러링 하거나 복사 가능)

이러한 컨테이너의 장점 때문에 Linux Container기술이 발전 했지만

Linux Container 컨테이너 기술은 사용하기 어렵고 대중화하기에는 한계가 있었다.

이러한 기술을 도입하기 편리하게 개발된 기술이 **Docker**이다.

LXC vs Docker

LXCvsDocker

Linux Container(LXC)는 단일 컨트롤 호스트 상에서 여러개의 고립된 리눅스 시스템 (컨테이너)들을 실행하기 위한 OS 레벨 가상화 기술이다.

Docker는 단일 애플리케이션을 실행하는데 중점을 둔 컨테이너 기술이다.

세분화된 접근 방식에 의해 크게 2가지 차이점이 나타난다.

  • Docker는 네트워크, 스토리지, 로깅 등 머신별 설정에 대한 추상화 제공한다.
  • Docker 컨테이너는 컨테이너당 단일 프로세스를 실행하도록 만들어 졌다.

추가로 더 자세히 정리된 링크 남긴다.

Linex컨테이너란? - Red Hat
Table of contents LXC vs Docker: Which Container Platform Is Right for You?
Docker 그리고 Linux 컨테이너 기술들

Docker

그럼 이제부터 Docker에 대해 자세히 알아보자

Docker Inc.에 의해 개발 된 Go 언어로 작성된 소프트웨어로 컨테이너를 생성하고 관리하기 위한 도구이다.

Docker를 실행 하면 Docker Engine이라는

컨테이너를 구축 및 실행하는 오픈 소스 호스트 소프트웨어가 실행되며

이 위에 Libraries, Dependencies, Tools, App이 실행 된다.

도커를 사용하면 아래와 같은 장점을 가진다.

  • Docker Engine을 이용하기 때문에 호스트 운영체제의 영향을 받지 않음
  • 설정 파일(Dockerfile)로 동일한 환경을 가지기 때문에 공유, 재구축 및 배포가 매우 쉬움
  • 설정 파일을 통한 이미지 버전 관리
  • 이미지가 레이어 구조를 가지기 때문에 차분 빌드가 가능
  • 다양한 기능의 API (Docker API를 이용하여 관리 App 개발 가능)
  • Docker registry를 사용해 이미지 관리(저장, 배포) 가능 (public, private)

Images & Containers

Docker의 핵심 요소인 Image와 Container에 대해 정리해보자

Image

  1. 모든 설정 명령과 2. 모든 코드가 포함된 공유 가능한 패키지

docker의 이미지를 registry를 통해 검색할 수 있는데 default 주소는 dockerhub이다.
(docker search 명령어를 통해 검색)

copyButtonText
$ docker search {검색 할 레지스트리 명} --filter=stars=10

# --filter=stars=n : star 수가 n개 이상인 결과만 표시

Image는 name : tag로 나뉘어 있는데

name 부분은 image의 이름을 나타내고

tag는 이미지의 버전을 기록한다.

Container

이미지의 구체적인 실행 인스턴스

Container에서 구동시킬 Image는 Container Repository에서 docker pull로 다운로드 되거나

DockerFile을 참조해 docker build 명령어로 커스텀 이미지를 생성한다.

DockerFile엔 자체 이미지를 빌드할 때 실행하려는 도커에 대한 명령이 포함한다.

copyButtonText
FROM {image name} # 이름 지정

WORKDIR # 명령어를 수행 할 디렉토리 지정

COPY {이미지의 외부 경로} {이미지 내부 경로} # 어떤 파일이 이미지에 들어가는지 설정 (절대 경로가 좋다)

EXPOSE # 로컬 시스템에 노출 시킬 포트 설정

RUN # 실행 할 명령어

DockerFile에서 RUN, CMD 2가지 명령어가 비슷한 역할을 해 헷갈릴 수 있는데

RUN 명령어는 이미지 생성 시 실행 하고

CMD 명령어는 이미지 기반으로 컨테이너 시작 시 실행한다.

작성한 DOCKERFILE을 build 수행 하였다면 run명령어를 통해 Container를 실행 가능하다.

Docker는 모든 명령어를 기반으로 하는 이미지 레이어 생성 -> 모든 명령 결과를 캐시

다시 빌드할 때 변경사항이 없으면 캐시 된 내용을 사용해 실행한다.
-> 레이어 기반 아키텍처 라 한다.


레이어 기반 아키텍처를 자세히 이해하기 전에 UFS에 대해 잠깐 알아보고 가자

Union File System

Docker의 이미지는 Union File System기반으로 동작하는

**Storage Driver**에 의해 파일 시스템으로 복수의 Layer가 구현된다.
(Storage Driver가 파일 I/O 수행)

UFS란, 여러 개의 파일 시스템을 merge된 하나의 파일 시스템에 마운트 하는 기능이다.

OverlayDriver

각 layer 간의 파일들을 취합해서 하나의 파일시스템으로 만들고 중복되는 파일의 경우, “상위” layer 가 “하위” layer 의 있는 파일을 대체하는 방식이다

UFS 를 통해, Dockerfile 명령어를 실행한 결과 파일 시스템을 하나의 docker layer 로 만들고, 이 layer 들을 겹겹이 쌓아서 merge 된 최종 결과물이 docker 이미지가 된다.

inspectGraphDriver

추가로 inspect명령어로 GraphDriver부분을 살펴보면 위 그림처럼 각 레이어에 매칭되는 디렉토리 경로를 확인할 수 있다.
(jq 명령어는 JSON포맷 데이터를 다루는 커맨드라인 유틸리티)

docker diff 명령어를 통해 lowerdir을 기준으로 upperdir에서 변경된 사항을 확인 가능
(C : 변경, A : 추가, D : 삭제)


Docker는 UFS의 CoW(Copy on Write)전략을 활용해 레이어의 역할을 나눠

동일한 파일 시스템을 공유하며 독립적으로 실행한다

DockerLayer

도커의 컨테이너 레이어 구조는 컨테이너 레이어이미지 레이어로 분류한다.

각각의 특징을 살펴보면 아래와 같다.

컨테이너 레이어

  • 쓰기 가능한 레이어
  • 컨테이너가 생성된 후 변경작업은 이 레이어에서 이루어 진다.
  • 각 컨테이너마다 최상단 레이어에 생성되어 컨테이너마다 고유한 상태를 가진다.

이미지 레이어

  • 읽기 전용 레이어
  • 다른 컨테이너와 공유

DockerImageLayer

다시 Docker의 레이어 동작방식을 정리해보면

하위 레이어(base layer) 위에 새로운 Layer가 쌓일 경우, 하위 layer는 READ ONLY 상태로 변경되고

상위 layer에서 하위 layer를 복사하여 사용(CoW)하기 때문에, 상위 layer는 하위 layer에 아무런 영향을 주지 않는다.

이미지 레이어를 통해 동일한 이미지가 생성되고

컨테이너 레이어를 통해 이미지에 대한 생성을 공유 하면서도 고유한 데이터 상태를 가질 수 있다.


Docker에서 특정 iamge를 이용해 container를 기동하는 것은

모든 Layer를 결합하여 사용자에게 하나의 File system으로 제공하는 것이다

추가로

도커에서 관리되는 모든 레이어와 관련된 정보는 호스트 파일 시스템의 /var/lib/docker 폴더에 저장되며

이 영역을 Docker Area 또는 Backing Filesystem이라 부른다.

이러한 레이어 기반 아키텍처 덕분에 크게 2가지 이점이 생긴다.


첫번째는 빌드 시간 단축이다.

Dockerfile에 정의된 명령어 중

RUN, ADD, COPY 3단계가 레이어로 저장이 된다.
(CMD, LABEL, ENV, EXPOSE 등 메타 정보를 다루는 부분은 임시 레이어로 생성되지만 저장되지 않는다.)

레이어 기반 아키텍처를 이해하면 다음과 같은 최적화가 가능하다.

copyButtonText
# node가 설치된 docker 이미지를 가져온다.
From node

# /app 폴더 내부에서 실행될 것임을 설정
WORKDIR /app

# 현재 Dockerfile 경로에 있는 파일들 전부를 도커 이미지 내부 /app 경로에 복사
COPY . /app

# package.json 파일을 설치
RUN npm install

# 만약 node 앱에 80포트로 서버를 열어놨다면 container의 외부 포트를 설정
EXPOSE 80

# 마지막 server.js 파일을 실행
RUN node server.js

# CMD의 경우 이미지 기반으로 컨테이너가 실행 될 때 실행
# CMD ["node", "server.js"]

위의 설정파일의 경우엔 소스를 수정해 파일을 하나라도 변경 할 경우

npm install이 실행되어 종속된 파일을 전부 다시 받게되는데

copyButtonText
# node가 설치된 docker 이미지를 가져온다.
From node

# /app 폴더 내부에서 실행될 것임을 설정
WORKDIR /app

# 현재 package.json 파일만 /app 경로에 복사
COPY package.json /app

# package.json 파일을 설치
RUN npm install

# 현재 Dockerfile 경로에 있는 파일들 전부를 도커 이미지 내부 /app 경로에 복사
COPY . /app

# 만약 node 앱에 80포트로 서버를 열어놨다면 container의 외부 포트를 설정
EXPOSE 80

# 마지막 server.js 파일을 실행
RUN node server.js

package.json을 app경로에 복사 한 후 나머지 실행파일을 /app경로로 복사한다면

package.json파일이 바뀌지 않아서 package를 다시 받지 않고 실행된다.

즉, 이미지를 빌드할 때 필요한 부분만 다시 실행하여 이미지 생성 속도를 높일 수 있다
(빌드 시간 단축)


두번째는 이러한 레이어 기반 아키텍처 덕분에 롤백 기능을 활용할 수 있고

Layer를 활용해 **지속적 통합 및 배포(CI/CD)**를 수행하는 데 도움을 준다.

(CI/CD를 구축하는 부분은 다음 글에서 확인해보자)


추가로 base가 되는 image layer(read-only layer)에 있는 내용을 변경하고 싶을 땐

해당 data 를 Writable layer 로 먼저 Copy 한 후 이를 변경하는 기법을 사용해야 한다.

CoW기법은 동작 구조 상 다음과 같은 단점을 가질 수 있다는 부분을 알고있어야 한다.

  • data 를 먼저 복제(Copy)한 후 변경을 수행해야 하므로 성능 하락(Performance Overhead)이 존재한다.
  • 하위 layer 에 있는 원본 data와 상위 layer 에 변경된 data 도 유지해야 하므로 disk space를 많이 사용할 수 있다.

Docker Command

Docker의 동작방식을 살펴봤으니 다시 돌아와 사용하기 위한 명령어를 살펴보자

리눅스에서 도커 엔진을 제어하기 위한 명령어는 아래와 같다.

copyButtonText
# Docker 데몬 상태 확인
$ sudo systemctl status docker

# Docker demon 시작/중지
$ sudo systemctl start/stop docker

# Docker 데몬 사용/미사용 설정
$ sudo systemctl enabloe/disable docker

Docker 명령어의 기본적인 형태는 아래와 같다.

copyButtonText
$ docker [command] (option) [target] (arguments)
  • target : container (생략 가능), image, volume, network 등
  • command : ls, inspect, start, run 등

start vs run -> attached 모드 vs Detached 모드

1. build

Dockerfile로 부터 image 생성

copyButtonText
$ docker build [options] . -t "app/container_name"    # name

2. run

image를 기반으로 컨테이너를 만들어 실행 (생성, 실행)

copyButtonText
$ docker run {options} {이미지 명}

  # -a, --attach               # attach stdout/err
  # -i, --interactive          # attach stdin (interactive)
  # -t, --tty                  # pseudo-tty
  #     --name NAME            # name your image
  # -p, --publish 5000:5000    # port map
  #     --expose 5432          # expose a port to linked containers
  # -P, --publish-all          # publish all ports
  #     --link container:alias # linking
  # -v, --volume `pwd`:/app    # mount (absolute paths needed)
  # -e, --env NAME=hello       # env vars

3. start

컨테이너 실행

copyButtonText
$ docker start [options] CONTAINER
  # -a, --attach        # attach stdout/err
  # -i, --interactive   # attach stdin

4. create

컨테이너 생성

copyButtonText
$ docker create [options] IMAGE

# ex
$ docker create --name app_redis_1 \
  --expose 6379 \
  redis:3.0.2

# -d : detached mode (백그라운드 모드)
# -p : 포트 연결
# -v : volume 설정
# -e : 컨테이너 내에서 사용할 환경변수 설정
# --name : 컨테이너 이름 설정
# --it : 터미널 입력 옵션 (컨테이너의 표준 입력과 로컬 컴퓨터 입력 연결)
# --rm : 프로세스 종료 시 컨테이너 자동 제거
# --restart : docker desktop 실행 시 container 자동 실행 여부 (default : no)

5. attach

이미 실행 중인 컨테이너에 연결

copyButtonText
$ docker attach {이미지}:{태그}

6. ps / kill

실행중인 모든 container 노출

copyButtonText
$ docker ps -a
$ docker kill $ID

# -a : 현재 존재하는 모든 컨테이너의 목록 출력

7. cp

copyButtonText
$ docker cp

복사 명령어, 도커 내부의 로그 파일을 꺼내올 때 유용

8. stop

컨테이너 종료

copyButtonText
$ docker stop {Container ID}

9. rm

도커 컨테이너 삭제

copyButtonText
$ docker rm {컨테이너 명}

10. rmi

도커 이미지 삭제

copyButtonText
$ docker rmi {이미지 명}
# -f : 컨테이너도 강제 삭제

10. push / pull

레지스트리에 push / pull

copyButtonText
$ docker pull {이미지 이름}:{태그}
$ docker

11. rename

컨테이너 이름 변경

copyButtonText
$ docker rename {기존 이름} {변경하고자 하는 이름}

12. log

컨테이너 로그 조회

copyButtonText
$ docker container logs -t {컨테이너 식별자}

13. prune

사용하지 않는 Docker 오브젝트 삭제

Prune unused Docker objects

copyButtonText
$ docker container prune # 사용하지 않는 컨테이너 삭제
$ docker image prune # 사용하지 않는 이미지 삭제
$ docker volume prune # 컨테이너와 연결되어 있지 않은 모든 볼륨 삭제
$ docker system prune # 컨테이너, 이미지, 볼륨, 네트워크 전부 삭제

14. image / container

image 관련

command descriptioin
docker image build Dockerfile에서 이미지 빌드
docker image history 이미지의 history 표시
docker image ls 이미지 나열
docker image prune 사용하지 않는 이미지 제거
docker image pull 레지스트리에서 이미지 또는 저장소 가져오기
docker image push 이미지 또는 저장소를 레지스트리에 푸시
docker image rm 하나 이상의 이미지 제거
docker image tag SOURCE_IMAGE를 참조하는 TARGET_IMAGE 태그 생성

command 관련

Command description
docker container attach 실행 중인 컨테이너에 로컬 표준 입력, 출력 및 오류 스트림 연결
docker container commit 컨테이너의 변경 사항에서 새 이미지 만들기
docker container cp 컨테이너와 로컬 파일 시스템 간에 파일/폴더 복사
docker container create 새 컨테이너 만들기
docker container exec 실행 중인 컨테이너에서 명령 실행
docker container inspect 하나 이상의 컨테이너에 대한 자세한 정보 표시
docker container kill 하나 이상의 실행 중인 컨테이너 종료
docker container logs 컨테이너의 로그 가져오기
docker container ls 컨테이너 나열
docker container pause 하나 이상의 컨테이너 내 모든 프로세스 일시 중지
docker container port 컨테이너에 대한 포트 매핑 또는 특정 매핑 나열
docker container prune 중지된 모든 컨테이너 제거
docker container rename 컨테이너 이름 바꾸기
docker container restart 하나 이상의 컨테이너 다시 시작
docker container rm 하나 이상의 컨테이너 제거
docker container run 새 컨테이너에서 명령 실행
docker container start 하나 이상의 중지된 컨테이너 시작
docker container stop 하나 이상의 실행 중인 컨테이너 중지
docker container top 컨테이너의 실행 중인 프로세스 표시
docker container unpause 하나 이상의 컨테이너 내의 모든 프로세스 일시 중지 해제

dockerCheet


Docker의 컨테이너에 쓰여진 데이터는 기본적으로 컨테이너가 삭제될 때 함께 사라진다.

그렇기 때문에 호스트 컴퓨터와 연결하기 위해 Docker는 3가지 마운트 방법을 제공한다.

dockerMount

Volume, Bind Mount, thmpfs Mount

마운트 방식을 항목별로 살펴보자

Volumes

Volume은 Docker에서 관리하는 호스트 파일 시스템과 컨테이너와 매핑해 데이터를 영구적으로 사용하는 방법이다.
-> 볼륨은 Docker에 의해 생성되고 관리되며, 호스트 컴퓨터에서 편집은 불가능하다.

Volume은 Named Volume, Anonymous Volume 두가지 방법으로 지정 가능 하다.

-v <volumeName>:<mount dir>[:rw | ro]

명령어는 다음과 같이 -v or --volume으로 사용하고 :로 3개의 필드를 구분한다.

  • 마지막 rw, ro는 선택사항이며 read only옵션을 설정할 수 있다.

Named Volume

Volume에 이름을 지정해 사용하는 방법은 DockerFile에 명시하거나 명령어를 통해 지정해주는 방식이 있다.

Named Volume은 제거되지 않기 때문에 수동으로 제거시켜 줘야한다.

copyButtonText
# DockerFile 내부

VOLUME [ "/app/log" ]

명령어를 통해 Volume을 생성하고 확인하기 위해선 아래 명령어들을 사용한다

copyButtonText
$ docker volume create app_vol
$ docker volume ls

상세한 Volume 정보를 확인하기 위해선 inspect명령어를 사용하는데

Mountpoint 항목을 보면 해당 볼륨이 컴퓨터의 어느 경로에 생성 하였는지 확인 가능하다.

copyButtonText
$ docker volume inspect app_log

volumeInspect

Docker 실행 시 volume지정은 -v 옵션으로 volume의 이름과 경로를 지정한다

copyButtonText
$ docker run -d -p 3000:80 --rm --name exampleApp -v app_log:/app/log first:latest

위의 명령어로 container를 실행 후 inspect 명령어를 통해 container정보를 확인해보면 아래와 같이
mount된 정보를 확인할 수 있다.

copyButtonText
$ docker inspect exampleApp | grep -A 12 "Mounts"

containerVolumeMount

Anonymous Volume

아무 설정없이 컨테이너를 시작하면 자동으로 Anonymous Volume이 생성되는데

–rm 옵션을 넣어 컨테이너 시작하면 종료 시 자동으로 익명 Volume 제거 된다.
(옵션 없이 시작하면 제거되지 않는다.)

–rm 옵션 없이 컨테이너를 재시작 할 경우 새로운 익명 볼륨이 계속 생성된다.

아래 두 명령어를 통해 볼륨 삭제 가능하다

copyButtonText
$ docker volume rm VOL_NAME
$ docker volume prune

주의할 점으로 Volume을 삭제 시 Volume이 마운트 되어있으면 삭제가 되지 않으니
연결된 container를 모두 삭제 하고 제거해야 한다.

docker volume prune 커맨드는 마운트되어 있지 않은 모든 볼륨을 한번에 제거한다.

  • 익명 볼륨은 일부 컨테이너 내부 폴더를 덮어쓰지 않도록

Bind Mount

Volume은 도커에 의해 지정된 위치와 마운트하는 방법이지만

Bind Mount호스트 머신상에 디렉토리를 선언해 매핑할 컨테이너 경로를 마운트한다.
-> 호스트 머신의 어떤 폴더에 연결
-> 항상 최신 코드에 액세스 가능
-> 즉, 바인드 마운트는 컨테이너가 실행되는 동안 변경될 수 있는 데이터를 컨테이너와 공유하는데 사용한다.

Bind Mount는 개발 중에는 유용한 옵션이지만 프로덕션에서는 사용x
(컨테이너는 호스트시스템에서 격리되어 실행하는게 좋은 방향)

바인드 마운트를 사용하는 방법은 docker run 커맨드를 실행할 때

  • -v 옵션의 콜론(:) 앞 부분에 마운트명 대신에 호스트의 경로를 지정한다
  • -v 옵션으로 사용이 가능하지만 --mount도 동일한 기능을 하기 때문에 직관적인 --mount 사용이 좋음.
  • -v--mount의 차이점은 -v옵션은 존재하지 않는 파일 또는 디렉토리를 실행시 파일 존재여부와 상관 없이 생성되는데 --mount는 오류 생성
  • 경로는 절대 경로로 지정해 줘야 한다.
  • 폴더간 마운트를 주로 사용하지만 파일 간 마운트도 가능
  • bind mount는 docker volume ls로 노출되지 않는다.
copyButtonText
$ docker run -d -p 3000:80 --rm --name exampleApp --mount {절대 경로}:/app/log first:latest

-v $(pwd):/app 명령어로 현재 위치에 Bind 가능

docker inspect 커맨드로 컨테이너의 상세 정보를 확인해보면

현재 경로(/root)가 bind 타입으로 마운트되어 있는 것을 확인할 수 있다.


실제로 Node환경 Application의 소스를 bind mount를 활용해 받아올 수 있는데

실행 시 npm install을 받아오게 dockerfile을 구성했으면 에러가 난다.

bind 1

해당 원인은 컨테이너에서 npm install 시 호스트 컴퓨터 파일에 node_modules이 없기 때문인데

이와 같은 상황에선 volume을 추가로 생성해야 한다.
(Bind Mount된 볼륨의 내용을 덮어쓴다.)

volume을 설정하면 도커는 호스트 파일(원본)에 덮어쓰지 않고, 충돌이 있는 경우 긴 경로를 우선시 한다.

이렇게 재 생성하는 경우 Anonymous Volume를 사용하는 것이 유용

Volume vs Bind Mount

한줄정리 해보면

Container 데이터를 호스트 컴퓨터로 꺼내오기 위해 Volumes 사용

심볼릭 링크처럼 호스트 데이터를 읽을 때 사용 (호스트 폴더를 복사) 하기 위한 Bind Mount.

name example
Volume - 호스트 컴퓨터와 Docker 구성을 분리 할 경우
- 컨테이너의 데이터를 로컬이 아닌 원격 호스트 또는 클라우드에 저장하는 경우
- Docker 컨테이너 간 데이터를 백업, 복원, 마이그레이션 해야 하는 경우 (중지 후 백업 가능)
- 고성능 I/O가 필요한 경우
- Docker에서 App이 완전한 기본 파일 시스템 동작을 요구하는 경우 (ex - DB)
Bind Mount - 호스트 머신의 구성파일을 컨테이너로 공유 할 경우 (ex - DNS확인 시 /etc/resolv.conf 설정)
- 소스 코드 또는 빌드 아티팩트 공유 시
- Docker의 호스트 파일 or 디렉토리 구조를 일치시킬 때

tmpfs Mount

Volume과 bind Mount와 달리 일시적이며 호스트 메모리에 저장된다.

호스트나 컨테이너 쓰기 가능 계층에 유지하고 싶지 않은 민감한 파일을 임시로 저장하는데 유용

  • Linux에서 Docker를 실행하는 경우에만 사용 가능

Docker Setting

.dockerignore

.dockerignre은 Docker CLI가 Docker demon으로 보내기 전에 지정된 파일 및 디렉토리를 제외하도록 컨텍스트를 수정

gitignore와 같이 COPY명령으로 복사하면 안되는 폴더와 파일 지정가능

.dockerignore 파일 - Docker document

.env 설정

Dockerfile 내부의 ENV옵션으로 설정하여 환경변수가 존재함을 Docker에 알린다음
docker run에서 --env옵션을 사용해 구체적인 값 제공

  • key-value 형태로 환경변수 지정 가능
  • ${VAR+} 표현식을 지원하여 매개변수 확장 가능
  • docker run 시에 –e 옵션을 활용하여 오버라이딩 가능
copyButtonText
ENV abc=hello

ENV FOO=/bar
WORKDIR ${FOO}

ARG 설정

Build시에만 사용 인수 지정

  • key-value 형태로 환경변수 지정 가능
  • ${VAR+} 표현식을 지원하여 매개변수 확장 가능
  • 빌드 시 특정값 잠금, 변경하지 않고 유연하게 빌드
  • ARG명령어는 FROM는 에서 앞에 올 수 있는 유일한 명령
  • docker build 시에 –build-arg 옵션을 활용하여 오버라이딩 가능
copyButtonText
ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}

argEnv

Networking

host Computer와 연결하기 위해선 host.docker.internal도메인을 사용해 http통신한다

도커 컨테이너 내부에서 호스트 머신의 IP주소로 변환된다.

내부 Container간 통신하기 위해서는 IP 주소를 수동으로 찾거나 network를 사용해 통신한다.

docker run 명령에 --netrork 옵션을 추가하면 모든 컨테이너를 하나의 동일한 네트워크에 넣을 수 있다.
-> IP조회 및 해결 작업을 자동으로 수행
-> 컨테이너 격리에 용이

docker는 network경우 자동으로 생성하지 않기 때문에 사용하기 전 docker network create명령어로 생성이 필요

docker network ls를 사용해 네트워크 확인

네트워크로 연결 시 url을 컨테이너 이름으로 지정 가능

ex) mongodb://mongodb:27017/sw

도커 컨테이너 이름또한 도커에 의해 IP주소로 변환된다.

컨테이너 간 통신을 위해선 포트 게시 필요x
-> 로컬 호스트 머신이나 컨테이너 네트워크 외부에서 연결 할 경우만 필요

IP Resolving

컨테이너에서 요청을 전송할 때만 자동 IP 변환

즉, 사용자가 웹 앱 방문하여 Javascript 코드가 브라우저에서 실행 중이고 브라우저에서 요청이 전송되면 도커는 아무 작업도 수행하지 않는다.
(소스 코드 대체x)

Docker-Compose

Utility Container

Multi-Container Project example

Deploy

Summary

추가로 더 알아 볼 내용

  • Docker registry를 사용해 이미지 관리

Reference

Storage drivers - Docker docs
Multi-stage builds - Docker docs
도커 컨테이너 까보기(1) - Protocol, Registry
도커 컨테이너 까보기(2) – Container Size, UFS
What are Containers? - Google Cloud
What’s a Linux container? - Red Hat
Docker 그리고 Linux 컨테이너 기술들
Table of contents LXC vs Docker: Which Container Platform Is Right for You?
Docker란? - Red Hat
Docker란 무엇인가? - OCI
What is a hypervisor? - Red Hat
What is a virtual machine (VM)? - Red Hat
Containers vs VMs
Docker Cheatsheet [2023 Updated] - Collabnix Docker ARG vs ENV - vsupalov blog

Thank You for Visiting My Blog, I hope you have an amazing day 😆
© 2023 Ian, Powered By Gatsby.