도커 컴포즈 파일

도커 컴포즈 파일은 애플리케이션의 '원하는 상태', 즉, 모든 컴포넌트가 실행 중일 때 어떤 상태여야 하는지를 기술하는 파일이다. 그리고 docker container run 명령으로 컨테이너를 실행할 때 지정하는 모든 옵션을 한 곳에 모아 놓은 단순한 형식의 파일이다. 도커 컴포즈 파일을 작성한 뒤, 도커 컴포즈 도구를 사용해 애플리케이션을 실행하면 도커 컴포즈가 컨테이너, 네트워크, 볼륨 등 필요한 모든 도커 객체를 만들도록 도커 API에 명령을 내린다.

도커 컴포즈 파일의 스크립트

 

위 스크립트의 내용은 도커 네트워크에 도커 컨테이너 하나가 연결된 간단한 애플리케이션을 기술한 것이다.

위 도커 컴포즈 파일은 다음과 같은 세 개의 최상위 statement로 구성된다.

  • version: 파일에 사용된 도커 컴포즈 파일 형식의 버전을 나타냄.
  • service: 애플리케이션을 구성하는 모든 컴포넌트를 열거하는 부분. *도커 컴포즈에서는 실제 컨테이너 대신 서비스 개념을 단위로 삼는다. 하나의 서비스를 같은 이미지로 여러 컨테이너에서 실행 가능하기 때문이다.
  • networks: 서비스 컨테이너가 연결될 모든 도커 네트워크를 열거하는 부분

도커 컴포즈를 통해 애플리케이션을 실행하면 컨테이너 하나가 실행돼 스크립트에 정의된 구성을 갖추게 된다.


도커 네트워크 생성

컴포즈 스크립트의 external 필드에 정의된 네트워크는 애플리케이션 실행 전에 생성돼 있어야 한다.

애플리케이션을 실행시킨다. 도커 컴포즈는 현재 있는 리소스와 애플리케이션을 구성하는 리소스를 비교해 더 필요한 요소를 생성한다.

웹 사이(localhost:8020) 접속 확인

 

위와 같이 도커 컴포즈를 이용하면 간단하고 안정적으로 애플리케이션 실행이 가능하다. 도커 컴포즈 파일은 애플리케이션 소스 코드, Dockerfile 스크립트와 함께 형상 관리 도구로 관리된다. 이 파일에 애플리케이션의 모든 실행 옵션이 기술되므로 README 파일에 애플리케이션 이미지 이름이나 공개해야 할 포트 번호를 문서화할 필요가 없다.


도커 컴포즈로 여러 컨테이너로 구성된 애플리케이션 실행

여러 개의 컨테이너로 구성된 이미지 갤러리를 기술한 컴포즈 스크립트

 

accesslog 서비스는 이미지 이름만 적혀있고 iotd 서비스는 REST API다. 스크립트에 이미지 이름과 함께 80번 포트를 호스트 컴퓨터의 무작위 포트를 통해 공개하도록 작성됐다. image-gallery 서비스는 이미지 이름과 함께 8010번 포트를 호스트 컴퓨터의 8010번 포트를 통해 공개한다. 또한 depends_on 항목은 이 서비스가 다른 두 서비스에 의존한다는 사실을 기술한다.

도커 컴포즈는 의존 관계를 준수해 세 개의 컨테이너를 만들고, image-gallery 컨테이너는 accesslog와 iotd 서비스가 실행된 다음에 실행된다.

 

도커 컴포즈는 컨테이너를 관리해주고 도커 컴포즈를 통해 전체 애플리케이션을 관리할 수 있다.

도커 컴포즈는 컨테이너를 관리하는 별도의 명령이지만 내부적으로는 마찬가지로 도커 API를 사용한다. 따라서 도커 컴포즈를 실행한 컨테이너라도 똑같이 도커 명령행으로 관리할 수 있다.

컴포즈로 애플리케이션을 중지하면 모든 컨테이너가 중지된다. 중지된 컨테이너는 CPU나 메모리를 점유하지는 않지만, 컨테이너 파일 시스템은 그대로 유지한다. 이후 다시 애플리케이션을 시작하면 기존 컨테이너가 재시작된다.

 

도커 컴포즈는 클라이언트 측에서 동작하는 도구이다. 도커 컴포즈 명령을 실행하면 컴포즈 파일에 따라 도커 API로 지시를 보내고, 이는 도커 엔진 자체는 컨테이너를 실행할 뿐, 여러 컨테이너가 하나의 애플리케이션으로 동작하는지 여부는 알지 못한다. 그러므로 컴포즈를 사용해 애플리케이션을 관리하려면 컴포즈 파일을 작성하고 이 파일을 읽을 수 있게 해야 한다.


도커 컨테이너 간 통신

컨테이너는 도커 엔진으로부터 부여받은 자신만의 가상 IP 주소를 가지며 모두 같은 도커 네트워크로 연결돼 IP 주소를 통해 서로 통신이 가능하다. 그러나 애플리케이션 생애주기동안에 컨테이너가 교체되면 IP 주소가 변경되기 때문에 IP 주소가 변경돼도 문제가 없도록 도커에서 DNS를 이용해 서비스 디스커버리 기능을 제공한다.

accesslog의 IP 주소는 168.126.63.1임을 알 수 있다. 도커 네트워크에 연결된 모든 컨테이너는 이 네트워크의 범위에 포함되는 IP 주소를 부여받는다. 그리고 이 네트워크를 통해 컨테이너 간 통신이 가능하다. DNS 조회를 사용하면 컨테이너가 교체돼 IP 주소가 변경되더라도 항상 새로 만들어진 컨테이너에 접근이 가능하다.

 

<ref>

https://github.com/gilbutITbook

모든 컨테이너는 독립된 파일 시스템을 갖는다. 같은 이미지에서 실행한 여러 개의 컨테이너는 처음에는 디스크의 내용이 모두 같지만, 그중 한 컨테이너에서 애플리케이션이 파일을 수정해도 다른 컨테이너나 이미지는 영향을 받지 않는다.

같은 이미지로부터 두 개의 컨테이너 실행. 위 이미지에 담긴 애플리케이션은 컨테이너 속 파일에 무작위 숫자를 쓰는기능

 

이 두 컨테이너는 같은 이미지로부터 실행됐으나 파일 시스템의 내용이 서로 다르다.

컨테이너를 종료해도 파일 시스템은 삭제되지 않기 때문에 컨테이너의 파일과 디렉터리는 그대로 남아 있을 것이다.

 

"docker container cp" 명령으로 컨테이너와 로컬 컴퓨터 간에 파일을 복사할 수 있다.

위 파일을 로컬 컴퓨터로 복사해서 내용을 확인했을 때, 두 파일이 서로 다른 것을 확인할 수 있다.

즉, 컨테이너의 파일 시스템이 서로 독립적임을 알 수 있다.


도커 볼륨을 통한 컨테이너 실행

도커 볼륨은 도커에서 스토리지를 다루는 단위이다. 볼륨은 컨테이너와는 독립적으로 존재하며 별도의 생명주기를 갖으며, 컨테이너에 연결이 가능하다. 퍼시스턴시가 필요한 stateful 애플리케이션을 컨테이너로 실행하려면 볼륨을 사용해야 한다. 볼륨을 생성해 애플리케이션 컨테이너에 연결하면 컨테이너 파일 시스템의 한 디렉터리가 되고 애플리케이션을 업데이트하더라도 새로운 컨테이너에 다시 볼륨을 연결하면 데이터가 그대로 유지된다.

 

컨테이너에서 볼륨을 사용하는 방법

1. 수동으로 볼륨을 생성해 컨테이너에 연결

2. Dockerfile 스크립트에서 VOLUME 인스트럭션 사용

-> 이 인스트럭션을 사용해 만든 이미지로 컨테이너를 실행하면 자동으로 볼륨을 생성

-> VOLUME 인스트럭션 문법은 VOLUME <target-directory> 형식

# 볼륨이 사용된 멀티 스테이지 빌드 Dockerfile 스크립트 일부
FROM diamol/dotnet-aspnet
WORKDIR /app
ENTRYPOINT ["dotnet", "ToDoList.dll"]

VOLUME /data
COPY --from=builder /out/ .

 

이 이미지로부터 컨테이너를 실행하면 자동으로 볼륨을 생성해 컨테이너에 연결해 준다. 실행된 컨테이너에는 /data 디렉터리가 있고 다른 디렉터리와 똑같이 사용할 수 있지만 이 디렉터리의 내용은 볼륨에 영구적으로 저장된다.

 

이후 웹 브라우저에서 http://localhost:8010에 접근하면 to-do 애플리케이션의 화면을 볼 수 있는데 웹에서 to-do 리스트를 추가하면 데이터는 도커 볼륨에 저장된다.

 

같은 데이터를 공유하는 to-do 애플리케이션 컨테이너 두 개를 만들 것이다.

위 코드에서 확인해봤을 때, 두 번째 컨테이너는 새로운 볼륨을 생성해 연결하기 때문에 /data 디렉터리가 비어 있지만, 세 번째 컨테이너는 첫 번째 컨테이너와 볼륨을 공유하므로 애플리케이션의 데이터를 세 번째 컨테이너의 디렉터리에서도 볼 수 있다.

 

하지만 볼륨은 컨테이너 간 파일 공유보다는 업데이트 간 상태를 보존하기 위한 용도로 사용해야 하며, 이미지에서 정의하는 것보다는 명시적으로 관리하는 것이 더 좋다. 그렇기때문에 볼륨에 이름을 붙여 생성하고 업데이트 시 다른 컨테이너로 옮겨 연결하면 된다.

# 복사 대상 경로를 환경 변수로 정의

# 볼륨을 연결해 v1 애플리케이션 실행

# v1 애플리케이션이 실행 중인 컨테이너 삭제

# 그 다음에는 같은 볼륨을 사용하도록 v2 애플리케이션 실행

 

<ref>

https://github.com/gilbutITbook

'DevOps > DOCKER' 카테고리의 다른 글

[Docker] 도커 컴포즈  (0) 2024.03.14
[Docker] 이미지 생성  (0) 2024.03.13
[Docker] 컨테이너를 이용해 웹 사이트 호스팅  (0) 2024.03.11

Dockerfile

Dockerfile은 애플리케이션을 패키징 하기 위한 간단한 스크립트로 일련의 인스트럭션으로 구성돼 있다.

이 인스트럭션을 실행한 결과로 도커 이미지가 생성이 된다.

FROM diamol/node

ENV TARGET="blog.sixeyed.com"
ENV METHOD="HEAD"
ENV INTERVAL="3000"

WORKDIR /web-ping
COPY app.js .

CMD ["node", "/web-ping/app.js"]

 

위 스크립트를 통해 인스트럭션에 대해 간단하게 설명을 해보려고 한다.

FROM, ENV, WORKDIR, COPY, CMD 이렇게 총 5가지 인스트럭션이 사용되었다.

  • FROM: 모든 이미지는 다른 이미지로부터 출발한다. 위 스크립트는 diamo/node 이미지를 시작 지점으로 지정하였고 위 이미지에는 web-ping 애플리케이션을 실행하는 데 필요한 런타임인 Node.js가 설치돼 있다.
  • ENV: 환경 변수 값을 지정하기 위한 인스트럭션이다. 값을 지정하기 위해서는 [key]="[value]" 형식을 따른다.
  • WORKDIR: 컨테이너 이미지 파일 시스템에 디렉터리를 만들고, 해당 디렉터리를 작업 디렉터리로 지정하는 익스트럭션이다. 리눅스와 윈도우 컨테이너 모두 구분자로 '/'를 사용한다. 위 스크립트에서는 /web-ping 디렉터리를 만드는 것을 알 수 있다. (*윈도우는 C:\web-ping dir 생성)
  • COPY: 로컬 파일 시스템의 파일 혹은 디렉터리를 컨테이너 이미지로 복사하는 익스트럭션이다. [원본 경로] [복사 경로] 형식으로 지정한다.
  • CMD: 도커가 이미지로부터 컨테이너를 실행했을 때 실행할 명령을 지정하는 인스트럭션이다.

컨테이너 이미지 빌드

이미지를 빌드하기 위해서는 Dockerfile 스크립트 외에도 이미지의 이름, 패키징에 필요한 파일의 경로를 추가로 지정해주어야 한다.

docker image build 명령어로 Dockerfile 스크립트 이미지 빌드

 

--tag의 인자 값(web-ping)은 이미지의 이름이고, 이어지는 인자는 Dockerfile 및 이미지에 포함시킬 파일이 위치한 경로

build 명령을 입력하면 Dockerfile 스크립트에 포함된 인스트럭션이 차례로 실행되며 그 결과가 출력된다.

이미지 생성 확인
새로 빌드한 이미지로부터 컨테이너를 실행해 도커 웹 사이트에 5초마다 ping


이미지 히스토리 확인

 

위 명령을 입력하면 한 줄마다 한 레이어에 대한 정보가 출력된다.

CREATED BY 항목은 해당 레이어를 구성한 Dockerfile 스크립트의 인스트럭션이다.

도커 이미지는 이미지 레이어가 모인 논리적 대상으로 레이어는 도커 엔진의 캐시에 물리적으로 저장된 파일이다.

 

<ref>

https://github.com/gilbutITbook

intro.

도커를 사용하는 주목적은 웹 사이트, 배치 프로세스, 데이터베이스 같은 서버 애플리케이션을 백그라운드에서 계속 동작하게 하는 형태일 것이다.

docker container ls

현재 실행 중인 컨테이너가 없는 것을 확인할 수 있다.


컨테이너 생성

docker container run --detach --publish 8088:80 (docker image)

github에서 가져온 도커 이미지를 통해 컨테이너를 생성
사용된 이미지에는 아파치 웹 서버와 간단한 HTML 페이지를 담고 있다.

 

컨테이너가 백그라운드에서 동작하면서 네트워크를 listen 하게 하기 위해서는 docker container run 명령에 다음과 같은 플래그들을 적용해주어야 한다.

  • --detach : 컨테이너를 백그라운드에서 실행하며 컨테이너의 ID를 출력한다.
  • --publish : 컨테이너의 포트를 호스트 컴퓨터에게 공개한다.

컨테이너의 포트를 호스트 컴퓨터에 공개하는 원리

도커를 다운로드하면 호스트 컴퓨터의 네트워크 계층에 도커가 끼어들게 된다. 그러면 호스트 컴퓨터에 지나가는 네트워크 트래픽을 모두 도커가 가로채 그중 필요한 것만 컨테이너에 전달할 수가 있다.

컨테이너는 기본적으로 외부 환경에 노출되지 않기 때문에, 각 컨테이너가 고유의 IP 주소를 가져도, 이 IP가 호스트 컴퓨터에 연결된 물리 네트워크를 의미하는 것이 아닌, 도커가 관리하는 내부 가상 네트워크의 주소이다.

컨테이너의 포트를 공개한다는 것은 도커가 호스트 컴퓨터의 포트를 해당 포트로 들어오는 트래픽을 컨테이너로 전달해 주는 것이다. 위 컨테이너 포트에서는 8080번 포트로 들어오는 트래픽을 컨테이너의 80번 포트로 전달하는 것을 확인할 수 있다.

 

위 그림에서 172.0.5.1은 도커가 부여한 도커 가상 네트워크의 주소다. 이 주소는 도커 내부에만 존재하는 주소이기 때문에 호스트 컴퓨터가 연결된 물리 네트워크의 컴퓨터는 컨테이너의 IP 주소에 접근할 수 없다. 그러나 컨테이너의 포트가 공개되어 컨테이너로 트래픽을 전달할 수는 있다.


웹 사이트 접속

브라우저에서 http://localhost:8080 페이지에 접근한 이미지다. HTTP 요청은 로컬 컴퓨터에서 보낸 것인데, HTTP 응답은 컨테이너로부터 나온 것

 

이 웹 페이지는 웹 서버와 함께 이미지로 패키징 되는 것으로 도커의 이식성과 효율성을 보여준다.

컨테이너 하나만 실행함으로써 전체 애플리케이션 스택이 실행되는 것이다.

이 컨테이너의 애플리케이션은 계속 실행된 상태이므로 컨테이너 또한 계속 실행 상태가 된다.

docker container stats # 실행중인 컨테이너의 상태 확인 가능.
#위 명령어로 실시간으로 컨테이너의 CPU, 메모리, 네트워크, 디스크 사용량을 볼 수 있다.

 

 

docker container rm --force $(docker container ls --all --quiet) # 위 명령어로 모든 컨테이너를 삭제할 수 있다.

 

모든 컨테이너가 삭제되는 것을 확인

 

<ref>

https://github.com/gilbutITbook

'DevOps > DOCKER' 카테고리의 다른 글

[Docker] 도커 컴포즈  (0) 2024.03.14
[Docker] 도커 볼륨을 이용한 퍼시스턴트 스토리지  (0) 2024.03.14
[Docker] 이미지 생성  (0) 2024.03.13

+ Recent posts