Docker

도커 엔진 기본 개념

25G 2023. 8. 7. 13:14

도커엔진

도커 이미지와 컨테이너

1. 도커 이미지

이미지는 컨테이너를 생성할 때 필요한 요소이며, 가상 머신을 생성할 때 사용하는 iso 파일과 비슷한 개념입니다. 여러개의 계층으로 된 바이너리 파일로 존재하고, 컨테이너를 생성하고 실행할 때 읽기 전용으로 사용됩니다.
도커에서 사용하는 이미지이름의 규칙은 저장소이름/이미지이름:태그 의 형태로 구성된다.

  • 저장소 : 도커허브 또는 개인 도커 레지스트리에 올라간 이미지
  • 이미지 이름 : 이미지의 역할 (우분투 이미지, mysql 이미지 등등)
  • 태그 : 이미지 버전 혹은 리버전 관리 사용

2. 도커 컨테이너

여러가지 이미지들로 컨테이너를 생성하면 해당 이미지의 목적에 맞는 파일이 들어 있는 파일시스템 격리된 시스템 자원 및 네트워크를 사용할 수 있는 독립된 공간이 생성되고, 이것이 바로 도커 컨테이너가 됩니다.
예를 들어 웹서버 도커 이미지로부터 여러개의 컨테이너를 생성하면 생성된 컨테이너의 개수만큼 웹서버가 생성되고 이 컨테이너들은 외부에 웹서비스를 제공하는데 사용될 것입니다.
그렇기 때문에 컨테이너에서 어떠한 변경이 생기더라도 그 컨테이너를 올리기위해 사용했던 이미지는 그대로 있습니다.

컨테이너 생성

docker run -it ubuntu:14.04

docker run 명령어를 입력하면 다음과 같은 내용이 출력됩니다. 이때 이미지가 로컬에 없으면 자동으로 도커허브에서 찾아서 다운받기 시작합니다.
그렇게 도커허브에서 이미지를 로컬에 받아서 컨테이너에 띄우게 됩니다.

컨테이너 목록 확인

docker ps 
or
docker ps -a (종료된 컨테이너 목록까지 확인)

위 이미지의 출력에 대한 설명

  • CONTAINER ID :컨테이너에게 자동으로 할당되는 고유 id
  • IMAGE : 컨테이너를 생성할때 사용된 이미지 이름
  • COMMAND : 컨테이너가 실작될 때 실행될 명령어 입니다. 커맨드는 대부분의 이미지에 미리 내장돼 있어 설정할 필요가 없습니다.
  • CREATED : 컨테이너가 생성되고 난 뒤 흐른시간
  • STATUS : 컨테이너 상태 실행시 UP 종료 Exited 일지중지 :Pause
  • PORTS : 컨테이너가 개방한 포트와 호스트에 연결한 포트
  • NAMES : 컨테이너의 고유한 이름

컨테이너 삭제

docker rm [컨테이너id]
  • -f 실행중인 컨테이너 삭제

컨테이너 외부 노출 시키기

컨테이너는 가상머신과 마찬가지로 가상 ip 주소를 할당 받습니다.
컨테이너를 생성할때 -p 옵션을 사용해서 호스트와 컨테이너를 연결해줄 포트를 개방합니다.

호스트의특정ip개방:호스트개방포트:컨테이너개방포트

위와같은 문법입니다.
호스트의 특정 ip 는 옵셔널하게 사용하면됩니다.
예시

 docker run - i - t -p 3306:3306 -p 192.168.0.100:7777:80 ubuntu:14.04

잘못된 예시

위와같이 입력했다면 외부에서 웹서버에 접근하지 못한다 왜냐하면 호스트의 80번 포트오 ㅏ연결된 컨테이너의 포트는 81번이 되고 81번 퐅는 어떠한 서비스도 제ㅗㅇ하도록 설정돼 있지 않기 때문입니다.

호스트와 바인딩된 포트만 확인하려면 docker port 명령어 사용

컨테이너 생성 옵션

  • -d : 백그라운드에서 실행
    • 위옵션은 컨테이너 내부에서 프로그램이 터미널을 차지하는 포그라운드로 실행돼 사용자의 입력을 받지 않습니다. -d 옵션을 사용한 컨테이너는 반드시 컨테이너에서 프로그램이 실행돼야합니다.
  • -e : 컨테이너 내부 환경변수 설정
  • exec : 실행중인 컨테이너 내부 쉘 사용
  • --link : A컨테이너에서 B컨테이너로 접근하는 방법중 가장 간단한 것은 NAT로 할당받은 내부 ip를 쓰는 것입니다. B컨테이너의 ip를 사용해 A컨테이너가 B컨테이너로 접근할 수 있습니다. 하지만 매번 할당되는 ip 가 다르기때문에 link옵션을 사용해서 컨테이너의 별명으로 접근하도록 설정할 수 있습니다.
  • -link 컨테이너명
    • 하지만 내부적으로 --link 옵션은 사라지는 추세이기때문에 도커 브리지 네트워크를 사용하는것을 권장도커 볼륨 (컨테이너 데이터를 영속적 저장)DB역할을 하는 컨테이너가 DB데이터를 적제하던 와중에 어떠한 이유로 도커엔진이 꺼진다면 대참사가 아닐수가 없다. 이를 해결하기위해서 호스트pc의 파일시스템과 도커 컨테이너의 파일시스템을 연결해 해당 공간에 파일들을 같은 공간에 두는고 데이터를 저장 시키는 방법이다.
  • (조심해야할 것은 동기화시키는 개념이아닌 그냥 완전히 같은 디렉터리를공유하는 개념)*

예시

# docker run -d \
- - name wordpressdb_hostvolume \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
-v /home/wordpress_db:/var/lib/mysql \ mysql:5.7

{호스트의공유디렉터리}: {컨테이너의 공유 디렉터리}
이때 미리 호스트에 해당 경로에 디렉터리가 없어도 자동생성됩니다.
(여러개 사용가능)

볼륨 컨테이너

볼륨을 사용하는 두번째 방법은 -v 옵션으로 볼륨을 사용하는 컨테이너를 다른 컨테이너와 공유하는 것입니다.
컨테이너 생성시 --volumes-from 옵션을 설정하면 -v 옵션을 적용한 실행중인 컨테이너의 볼륨 디렉터리를 공유할 수 있습니다. 하지만 이는 직접 볼륨을 공유하는 개념이 아닌 -v옵션을 적용한 컨테이너를 통해 공유하는 개념

docker run -i -t \
--name volumes_from_container \ volumes-from volume_overide \
이미지이름:태그

도커 볼륨

위 방법들은 호스트와 컨테이너 간에 볼륨을 공유하는 개념
도커 자체에서 볼륨 기능을 활용할 수 도 있습니다.

# docker volume create - - name myv이니me

...

docker volume Is

DRIVER VOLUME NAME 
local myvolume

위와같이 만들어진 볼륨을 공유하기 위해서는 컨테이너 생성시 다음과 같이 사용합니다.

볼륨의 이름 : 컨에티너의 공유 디렉터리

EX)

docker run -i -t name myv이니me_1 \ -v myvolume:/root/ \
ubuntu:14.04

docker inspect

위 명령어를 사용하면 도커의 모든 구성 단위의 정보를 확인할 수 있습니다. 정보를 확인할 종류를 명시하기 위해 --type 옵션에 image,volum 등을 입력하는것이 좋습니다.

tip

도커의 모든 명령어는 docker 접두어 다음에 container, image, volume 등을 명시함으로써 특정 구성 단 위를 제어하는 명령어를 사용할 수 있습니다. 예를 들어,docker container inspect는 컨테이너의 정보를, docker volume inspect는 볼륨의 정보를 출력합니다.

도커 네트워크

도커네트워크 구조

도커는 컨테이너 내부 ip를 순차적으로 할당하며 이ip 는 컨테이너를 재시작 할 때 마다 변경될 수 있습니다.
이 ip는 내부망이기때문에 호스트와만 통신할 수 있습니다. 이 과정은 컨테이너를 시작할때마다 veth--- 라는 네트워크 인터페이스를 생성함으로써 이뤄집니다.

  • veth에서 v는 virtual을 뜻합니다. 즉, virtual eth라는 의미입니다.

ex

# ifconfig
...

veth05O0ea3:flags=4163<UP,BROADCAST,RUNNING, MULTICAST) mtu 1500
inet6 fe80::c4e4:80ff:fe9f:a131 prefixlen 64 scopeid 0x20<link> ether c6:e4:80:9 f:a1:31 txqueuelen 0 (Ethernet)

출력 결과에서 eth0은 공인ip 또는 내부 ip 가 할당되어 실제로 외부와 통신할 수 있는 호스트의 네트워크 인터페이스 입니다.
그리고 docker() 브리지도 있는데 브리지는 각 veth인터페이스와 바인딩돼 호스트의 eth() 인터페이스와 이어주는 역할을 합니다.

정리하면 컨테이너의 ethO 인터페이스는 호스트의 veth...라는 인터페이스와 연결됐으며 veth 인 터페이스는 dockerO 브리지와 바인딩돼 외부와 통신할 수 있습니다.

도커 네트워크 기능

도커가 자체적으로 제공하는 대표적인 네트워크 드라이버로는 브리지(bridge), 호스트(host), 논(none), 컨테이너(container), 오버레이(overlay)가 있습니다. 서드파티(third-party) 플러그인 솔루션으로는 weave, flannel, openvswitch 등이 있으며,더 확장된 네트워크 구성을 위해 활용됩니다.

도커 네트워크 리스트 보기 멸영어

  • docker network ls

브리지 네트워크는 컨테이너를 생성할때 자동으로 연결되는 docker() 브리지를 활용하도록 설정돼 있습니다.

브리지 네트워크

브리지 네트워크는 docker()이 아닌 사용자 정의 브리지를 새로 생성해 각 컨테이너에 연결하는 네트워크 구조 이비다. 컨테이너는 연결된 브리지를 통해 외부와 통신할 수 있습니다.

새로운 브리지 생성 명령어

# docker network create --driver bridge mybridge

이렇게 만든 브리지를 다음 예시와 같이 사용해 활용할 수 있습니다.

# docker run - i - t name mynetwork_container \
ᅳnet mybridge/image:tag

이렇게 생성된 사용자 정의 네트워크는 docker network disconnect, connect를 통해 컨테이 너에 유동적으로 붙이고 뗄 수 있습니다.

브리지 네트워크와 --net-alias

--net-alias 옵션을 통해 특정 호스트 이름으로 컨테이너 여러개에 접근할 수 있습니다.
이렇게 할때 매번 달라지는 Ip를 결정하는 것은 별도의 알고리즘이 아닌 라운드 로빈 방식입니다. 이것이 가능한 이유는 내장된 dns가 호스트 이름을 --net-alias 옵션으로 호스트를 설정한 컨테이너로 변환하기 때문입니다.

호스트 네트워크

위 브리지와 달리 기존에 host라는 이름의 네트워크를 사용하면 됩니다.
네트워크를 호스트로 사용하면 호스트의 네트워크 환경을 그대로 쓸 수 있습니다.

# docker run - i - t — name network_host \
--net host image/tag

논 네트워크

말그대로 아무런 네트워크를 쓰지 않는 것을 뜻하고 외부와 연결이 단절됩니다.

컨테이너 네트워크

--net 옵션으로 container를 입력하면 다른 컨테이너의 네트워크 네임스페이스 환경을 공유할 수 있습니다.
공유되는 속성은 내부 IP,네트워크 인터페이스의 맥(MAC) 주소 등입니다. — net 옵션 의 값으로 container:다른 컨테이너의 ID 와같이 입력합니다.

위와 같이 다른 컨테이너의 네트워크 환경을 공유하면 내부 IP를 새로 할당받지 않으며 호스트에 veth로 시작하는 가상 네트워크 인터페이스도 생성되지 않습니다.

macVLAN 네트워크

macVLAN 은 호스트 네트워크 인터페이스 카드를 가상화해 물리 네트워크 환경을 컨테이너에게 동일하게 제공합니다. 따라서 MacVLAN을 사용하면 컨테이너는 물리 네트워크상에서 가상의 맥 주소를 가지며 해당 네트워크에 연결된 다른 장치와의 통신이 가능해 집니다. MacVlAN에 연결된 컨테이너는 기본적으로 할당되는 IP대역인 172.17.x.x 대신 네트워크 장비의 ip를 할당받기 때문입니다.

MacVLAN은 여기서 설명하는 것보다 더 복잡한 네트워크 개념을 포함하고 있습니다. MacVLAN에는 여러 종류가 있으며 그중에서 bridge 모드를 사용한다는 것, 그리고 MacVLAN을 사용하기 위해서는 부모 네트워크 인터페이스를 지정할 필요가 있다는 것만 알아두면 됩니다.

짤막 네트워크 지식

  1. 물리계층
  2. 데이터 링크계층
    • 허브 : 동일한 네트워크 대역 연결
    • 리피터 : 신호증폭
  3. 네트워크 계층
    • 라우터 : 서로다른 네트워크를 연결
    • 스위치 : 포괄적.

공인아이피를 하나 할당받으면 내부적으로 private ip 대역을 만드는 것이 핫스팟이다.
라우터도 이와 닮아 있다. 그리고 이 가상화 기술이 vlan 이라고 한다. 사실 핸드폰에서 private ip 라고 할 수 없고 가상의 랜을 만들어주는 개념이다. 버추얼 랜
이 역할을 랜카드가 수행한다.
랜카드에서 외부 public ip 를 받으면 가상으로 인터넷 대역망을 만든다.
이때 이 public ip를 통해서 내부망을 만들 수 있다 172.30.1.x 보통 이런 형식의 ip가 생성된다.

서브네팅?

서브네팅은 ip 주소가 뒤에서 부터 찬다고 생각하면 쉽다.
0.0.0.0 / 24
는 서브네팅이 24이란 뜻이고
8.8.8.0 이니 24로 해놨다는 뜻은 마지막 자리말고는 고정이라는 뜻이다.
그럼 8.8.8.x에 x 주소들은 사설망에 있는 네트워크들이기 때문에 허브만으로 통신이 가능하다.

서브네팅을 설정해놔도 마지막 아이피에 첫번째와 마지막은 사용하면 안된다.
첫번째는 게이트웨이 주소
마지막번째는 브로드캐스트 주소

공인ip 는 네가지로 나눠져있고 첫번째는 나라에서 지역정보. 두번째가 국가, 이런식의 규칙들이 존재한다.
이는 ip에는 규칙이 존재한다라는 뜻이고 대략적인 얘기이다.
MacVlan은 이러한 과정을 장비를 통해서 해야하는데 가상화해서 할 수 있게 해주는 기술이라는뜻

컨테이너 로깅

json-file 로그 사용하기

컨테이너 내부에서 어떤일이 일어나는지 알고 디버깅하기위애선 로깅 시스템이 필요합니다 도커는 컨테이너의 표준 출력과 에러 로그를 별도으 메타데이터 파일로 저장하여 이를 확인하는 명령어를 제공합니다.

docker logs 컨테이너 이름

--tail (줄수) = 끝에서부터 입력된 줄 수 만큼만 출력

--since = 유닉스 시간을 입력해 특정시간 이후의 로그를 확인할 수 있다.
-t = 타임스탬프 출력
-f = 로그를 스트림으로 확인할 수 있다. (개발에 유용)

기본적으로 컨테이너로그는 json 형태로 도커 내부에 저장됩니다. 이 파일은 다음 경로에 컨테이너의 id로 시작하는 파일명으로 저장됩니다. 아래의 log 파일의 내용을 car, vi 등으로 확인하려면 Logs 명령으로 정제되지 않은 json 데이터를 볼 수 있습니다.

아마존 클라우드워치 로그

AWS 에서 로그 및 이벤트 등을 수집하고 저장해 시각적으로 보여주는 클라우드 워치를 제공합니다. 도커를 aws ec2에서 사용하고 있다면 다른 도구를 별도로 설치할 필요없이 컨테이너에서 드라이버 옵션을 설정하는 것만으로 클라우드워치 로깅 드라이버를 사용할 수 있습니다.

클라우드 워치 사용 단계

  • 클라우드워치에 해당하는 iam 권한 생성
  • 로그 그룹 생성
  • 로그 그룹에 로그 스트림 생성
  • 클라우드워치의 iam 권한을 사용할 수 있는 ec2 인스턴스 생성과 로그 전송

IAM 권한 설정

  1. iam 권한 생성
    관리콘솔 메뉴에서 "보안,자격증명 및 규정 준수" 에서 IAM에 들어갑니다.

  1. 역할 탭 클릭후 역할 만들기


3. ec2 선택

  1. 권한 정책 연결 학목의 정책 필터에서 CloudWatchFullAccess를 입력한 뒤 체크하고 다음 클릭

  1. IAM 역할 이름입력후 새로운 권한 생성

로그 그룹 생성

  1. 관리 콘솔 페이지에서 관리및 거버넌스 항목의 CloudWatch를 클릭합니다.
  2. 왼쪽 사이드 바에서 로그 항목을 클릭한 뒤 로그 그룹 생성을 클릭해 로그가 저장될 새로운 그룹을 생성합니다.

3.로그 그룹에 로그 스트림 생성

  1. 클라우드 워치의 IAM 권한을 사용할 수 있는 EC2 인스턴스 생성과 로그 전송
    EC2 인스턴스에서 위에서 만든 iam 권한 을 사용하도록 권한을 추가 해야합니다. 이때 ec2 인스턴스를 생성시 단계 3: 인스턴스 세부 정보 구성 의 iam 역할 에서 해당 iam을 선택해 이를 설정 할 수 있습니다.

이렇게 인스턴스가 생성됏다면 해당 서버에 접속해 도커 엔진을 설치한 뒤 클라우드워치를 로긴 드라이버로 사용할 수 있습니다.

IAM 권한을 사용하도록 설정한 EC2 인스턴스의 도커 엔진에서 다음 명령어를 입력해 컨테이너를 생성합니다. 로깅 드라이버로 awslogs(클라우드워치)를 사용할 수 있게 설정하고 로그 그룹과 스 트림은 mylogs와 mylogstream을 시용합니다. 리전으로는 EC2 인스턴스가 아닌 로그 그룹 및 스 트림이 생성된 리전을 입력해야 합니다. ap-northeast-2는 아시아 태평양(서울) 리전의코드입 니다.

컨테이너 설정 예시 명령어

# docker run -i -t \
—log-driver=awslogs \
--log-opt awslogs-region=ap-northeast-2 \
—log-opt awslogs-group=mylogs \ 
—log-opt awslogs-stream=mylogstream \
ubuntu:14.04

root@5e95f239e6f0:/# echo test! 
test!

컨테이너 자원 할당 제한

컨테이너를 생성하는 run, create 명령어에서 컨테이너의 자원 할당량을 조정하도록 옵션을 입력 할 수 있습니다. 아무런 옵션을 입력하지 않으면 컨테이너는 호스트의 자원을 제한 없이 쓸 수 있게 설정되므로 제품 단계의 컨테이너를 고려한다면 컨테이너의 자원 할당을 제한해 호스트와 다른 컨테이너의 동작을 방해하지 않게 설정하는 것이 좋습니다.
컨테이너에 자원할당 옵션을 설정하지 않으면 호스트의 자원을 전부 점유해 다른 컨테이너들 뿐 아니라 호스트 자체의 동작이 멈출 수도 있습니다.
현재 컨테이너에 설정된 자원 제한을 확인하는 가장 쉬운 방법은 docker inspect 명령어를 입력하는 것입니다.

이때 run 명령어에서 설정된 컨테이너의 자원제한을 변경하려면 update 명령어를 사용합니다.

docker update (변경할 자원 제한) (컨테이너 이름)

컨테이너 메모리 제한

docker run 명령어에 --memory를 지정해 컨테이너의 메모리를 제한할 수 있습니다. 제한할 수 있는 최소 메모리는 4MB 입니다.

docker run --memory=4m //4mb로 설정

이때 주의할점은 컨테이너 내에 프로세스가 컨테이너에 할당된 메모리를 초과하면 컨테이너는 자동으로 종료되므로 애플리케이션에 따라 메모리를 적절하게 할당하는 것이 좋습니다.

컨테이너 CPU 제한

  • --cpu-shares

--cpu-shares 옵션은 컨테이너에 가중치를 설정해 해당 컨테이너가 CPU를 상대적으로 얼마나 사용할 수 있는지를 나타냅니다. 즉 컨테이너에 CPU를 한개 씩 할당하는 방식이 아닌, 시스템에 존재하는 CPU를 어느 비중만큼 나눠 쓸것인지를 명시하는 옵션입니다. 디폴트 값은 1024로 CPU 할당에서 1의 비중을 뜻합니다.
이는 비중이므로 양을 할당하는 개념이 아니라는것이 포인트

  • --cpuset-cpu

호스트에 CPU가 여려 개 있을 때 --cpuset-cpus 옵션을 지정해 컨테이너가 특정 CPU만 사용하도록 설정할 수 있습니다. CPU 집중적인 작업이 필요하다면 여러 개의 CPU를 사용하도록 서정해 작업을 적절하게 분배하는 것이 좋습니다.

  • --cpu-period, --cpu-quota
    컨테이너의 CFS(Completely Fair Scheduler) 주기는 기본적으로 100ms로 설정되지만 run 명령 어의 옵션 중 一 cpu-period와 一 cpu-quota로 이 주기를 변경할 수 있습니다. 다음 명령어를 입력해 컨테이너를 생성합니다.

책에서는 다음과 같은 tip 이 적혀 있습니다.
병렬 처리를 위해 CPU를 많이 소모하는 워크로드를 수행해야 한다면 — cpu-share, — cpus, — cpu- period, cpu-quota 옵션보다는 一 cpuset-cpu 옵션을 사용하는 것이 좋습니다. 一 cpuset-cpu 옵 션을 사용하면 특정 컨테이너가 특정 CPU에서만 동작하는 CPU 친화성(Affinity)을 보장할 수 있고,CPU 캐시미스 또는 컨텍스트 스위칭과 같이 성능을 하락시키는 요인을 최소화할 가능성이 높아지기 때문입니다.

Block I/O 제한

컨테이너를 생성 할 때 아무런 옵션도 설정하지 않으면 컨테이너 내부에서 파일을 읽고 쓰는 대역폭에 제한이 설정 되지 않습니다. 하나의 컨테이너가 블록 입출력을 과도하게 사용하지 않게 설정하려면 run 명령어에서
— device-write-bps, — device—read—bps, — device-write—iops, --device-read-iops 옵션을 지정해 블록 입출력을 제한할 수 있습니다. 단,Direct I/O의 경우 에만 블록 입출력이 제한되며, Buffered I/O는 제한되지 않습니다.

스토리지 드라이버와 컨테이너 저장 공간 제한

토커 엔진은 컨테이너 내부의 저장 공간을 제한하는 기능을 보편적으로 제공하지는 않지만, 도커의 스토리지 드라이버나 파일 시스템 등이 특정 조건을 만족하는 경우에만 이 기능을 제한적으로 사용할 수 있습니다.
단 모든 스토리지 드라이버에서 컨테이너의 저장 공간을 제한할 수 있는 것은 아닙니다. 따라서 컨테이너 애플리케이션이 해당 스토리지 드라이버에 적합하지 않다면 이 기능을 사용하지 않은 것이 좋을 수도 있습니다.
특별한 상황이 아니라면 컨테이너 자체가 상태를 가지는 것은 그다지 바람직하지 않습니다. 때문에 저장공간을 제한하지 않는 선택지를 고려해 볼 수 있습니다.

이 글은 제가 해당 책을 공부하며 정리한 글입니다.
출처 : 시작하세요 도커 쿠버네틱스

'Docker' 카테고리의 다른 글

Dockerfile 기본 문법  (0) 2023.08.07
docker 컨테이너와 이미지 조사하는법  (0) 2023.08.07
도커 이미지 기본개념  (0) 2023.08.07
Dockerfile 기본개념  (0) 2023.08.07
도커 데몬  (0) 2023.05.31