도커 엔진에 대해
업데이트:
카테고리: 도커
본 글은 책 시작하세요! 시작하세요! 도커/쿠버네티스 를 읽고 도커 엔진에 대한 내용들 및 간단하게 명령어를 정리한 글이다. 도커 및 쿠버네티스에 대해 더 자세히 알고 싶은 사람들은 책을 사거나 저자님의 블로그를 꼭 들어가보면 좋겠다!!
1. 도커 엔진에 대한 설명들
-
도커 이미지
컨테이너를 생성하고 실행할 때 읽기 전용으로 사용된다. 이미지의 이름은 [저장소의 이름]/[이미지의이름]:[태그] 형식으로 구성된다.
-
도커 컨테이너
이미지를 읽어와서 컨테이너 계층에 저장된다. 이미지를 읽어오는 것이므로, 컨테이너에서 변경사항이 있더라도 이미지는 영향을 받지 않는다. 그리고 중요한 점이 생성된 컨테이너들은 각각 독립적이므로 수정되어도 서로 영향을 받지 않으며, 호스트와도 분리되어 있기 때문에 호스트에도 영향을 미치지 않는다는 것이다.
-
도커 볼륨
도커 컨테이너는 각각 정보를 저장하고 보존한다. 그래서 컨테이너를 삭제하게되면 그대로 정보는 홀라당 날아가버린다. 이를 방지하기 위해, 도커 볼륨을 사용하자. 3가지의 방법이 있지만, 나는 docker volume을 사용해 데이터를 보존하는 것을 기억하려고 한다. (아래에 명령어가 있으니 ctrl+F로 [docker volume]을 찾을 것)
-
도커 네트워크
도커는 각각의 컨테이너마다 내부 IP를 순차적으로 할당하되, 매번 이것은 재시작할때마다 바뀐다. IP가 할당되면, 호스트에는 veth(virtual ethernet)이라는 네트워크 인터페이스가 생성된다.
도커 명령어들
- 도커 버전 확인
docker -v
- 기본적인 도커 run (컨테이너와 상호작용(interaction)이 되며 터미널을 사용할 수 있게 해주는)
docker run -i -t --name [컨테이너 이름] [이미지 이름]:[버젼]
- -i -t 옵션이 적혀 있어야 함.
- 이미지가 없을 경우, 도커 공식 이미지 저장소에서 이미지를 받아오는 pull이 자동으로 실행됨.
- docker start와 docker attach가 자동으로 실행됨.
- 도커 run 쪼개기 (create -> start -> attach)
docker create --name [컨테이너 이름] [이미지 이름]:[버젼] docker start [컨테이너 이름] docker attach [컨테이너 이름]
- 실행중인 컨테이너 종료하기
docker stop [컨테이너 이름]
- 컨테이너 목록 확인
docker ps
- 그냥 ps만 사용하면 실행중인 컨테이너들을 출력한다.
- 모든 컨테이너를 출력하기 위한 옵션 : -a
- 컨테이너의 ID만 출력하는 옵션 : -q
- 컨테이너 이름 재설정
docker rename [원래 이름] [바꿀 이름]
- 컨테이너 삭제
docker rm [컨테이너 이름]
- 단, 실행중인 컨테이너는 삭제가 불가능하다. 강제로 삭제하기 위해선 -f를 붙이자.
- 많은 컨테이너 삭제
docker container prune
- 도커 컨테이너를 외부와 연결하기
docker run -i -t --name [컨테이너 이름] -p [호스트의 포트]:[컨테이너의 포트] [이미지 이름]:[태그]
- -p 옵션을 사용함으로써 호스트의 포트와 컨테이너의 포트를 바인딩함.
- -p를 여러번 사용해서 다중 포트 개방 가능
내가 네트워크쪽 지식은 부족하지만.. 이해한 바를 기록하면, 위 방식대로 도커 컨테이너의 포트를 내 호스트의 포트와 바인딩해야 외부에서 [내 호스트 ip]:[바인딩된 포트]로 컨테이너의 웹 서버에 접근이 가능하다. 그리고 포트마다 설정을 줄 수 있는데, 기본으로 사용가능한 port가 80이다. 따라서 port 80에 연결했다면, 주소를 [호스트 ip]:[바인딩된 포트]를 적지 않고 [호스트 ip]만 입력하더라도 접속이 가능하다.
- 컨테이너를 foreground로 실행하기(detach)
docker run -d ...(other options)
- -d를 붙임으로써 컨테이너가 foreground로 실행된다.
- -i -t 와 다른 점은, -i -t는 우리가 terminal을 사용해 입출력을 컨테이너와 주고 받을 수 있게 해주었으나, -d는 컨테이너의 터미널이 프로그램을 foreground로 바로 작동되게 하기 때문에 입출력을 주고받을 수 없다.
- Detached 모드인 컨테이너는 반드시 프로그램과 같이 실행되고 따로 종료될 수 없다.
- 컨테이너 내부의 환경변수 설정
docker -e A=B
- 컨테이너 내부의 A라는 환경변수를 B로 설정하는 명령어
- 컨테이너간의 연결법
docker --link [연결할 컨테이너 이름]:[그 컨테이너의 별명] ...(other options)
- 컨테이너간의 연결을 NAT ip를 통해 할 수 있지만, 매번 컨테이너의 ip가 재설정되기 때문에 고정값을 쓰기 어렵다. 따라서 컨테이너의 별명(컨테이너의 호스트명)으로 접근 가능하게 해주는 명령어.
- 도커 볼륨 생성(create), 리스트(ls), 사용하지 않는 볼륨 삭제(prune)
docker volume create --name [볼륨 이름] docker volume ls docker volume prune
- 위 명령어를 이용해서 로컬 저장소에 도커 볼륨을 생성할 수 있다. 이는 도커 엔진에 의해 관리된다.
- 도커 볼륨을 쓰는 사용자는 볼륨이 어디에 저장되었는지 굳이 알 필요가 없다고 한다.
- 컨테이너를 삭제해도 볼륨은 삭제되지 않는다. 사용하지 않는 것을 전부 정리할꺼면, prune을 사용해 편하게 지우자.
- 도커 볼륨 사용법 예시
docker run -i -t --name [컨테이너 이름] -v [볼륨 이름]:[저장 디렉터리] [이미지 이름]:[태그]
- 위 디렉토리에 파일을 생성한 후, 다른 컨테이너를 해당 도커 볼륨을 사용하면 방금 생성한 파일을 새로운 컨테이너에서도 볼 수 있다.
- 굳이 [볼륨 이름]:[저장 디렉터리] 를 사용하지 않고, [저장 디렉터리]만을 써도 된다. 단, 매번 새로운 도커 볼륨이 생성되는 듯하다.
- 도커 네트워크 목록(ls), 도커 네트워크의 브릿지 생성(create)
docker network ls docker network create --driver [드라이버 타입] [네트워크 이름]
- 도커 네트워크 사용법 예시(브릿지,호스트,논)
docker run -i -t --name [컨테이너 이름] --net [네트워크 이름] [이미지 이름]:[태그] docker run -i -t --name [컨테이너 이름] --net host [이미지 이름]:[태그] docker run -i -t --name [컨테이너 이름] --net none [이미지 이름]:[태그]
- 호스트를 사용하면 별도의 포트 포워딩 없이 바로 컨테이너 내부의 어플리케이션에 접속가능하다.
- 논은 말그대로 네트워크를 사용하지 않음을 뜻한다.
- 다른 컨테이너의 네트워크 환경 가져오기
docker run -i -t --net container:[네트워크 환경을 가져올 다른 컨테이너 이름] ...(other options)
- 위 방식을 사용하면, 다른 컨테이너의 네트워크 환경과 같게 새로운 컨테이너를 설정할 수 있다.
- 도커 이미지 생성 과정 (컨테이너 생성 -> 이미지 커밋)
docker run -i -t --name [컨테이너 이름] [이미지 이름]:[태그] docker commit -a [작성자 이름] -m [커밋 메시지] [커밋할 컨테이너 이름] [커밋될 이미지 이름]:[태그]
- 위 과정을 거치면 docker images를 통해 내가 생성한 이미지를 볼 수 있다.
- 도커 조사법(inspect)
docker inspect [이름(컨테이너,이미지..)] --type [타입 명]
- inspect를 사용해 내가 갖고있는 도커 정보에 대해 알아볼 수 있다. 이 때, 이름이 중복될 경우가 있는데 그땐 컨테이너가 먼저 실행되므로 타입 명을 항상 기재하는 습관을 들이자.
- 도커 이미지의 commit들 보기
docker history [이미지 이름]:[태그]
- 도커 이미지는 레이어로 층층이 쌓여있는데, history를 사용하면 그동안 해당 이미지에 어떤 commit들이 들어가있는지 알 수 있다.
- 도커 이미지 저장 및 로드
docker save -o [저장할 파일명] [이미지 이름]:[태그] docker load -i [로드할 파일명]
- 도커 컨테이너 저장 및 이미지로 로드
docker export [저장할 컨테이너 이름] [저장할 tar 이름]:[태그] docker import [export로 저장된 tar을 로드할 파일명]:[태그]
- save/load는 이미지를 내보내고 로드하는 것이지만, export/import는 컨테이너를 내보내고 이미지로 로드하는 것의 차이이다.
- 도커 태그
docker tag [기존의 이미지 이름]:[태그] [새롭게 생성될 이미지 이름]:[태그]
- 도커 태그를 사용하면 같은 이미지를 가르키는 새로운 이미지를 만들 뿐이다.
- 도커 푸시 및 풀
docker push [저장소 이름]/[이미지 이름]:[태그] docker pull [저장소 이름]/[이미지 이름]:[태그]
- 도커 태그 혹은 이미지 커밋 과정에서 반드시 [저장소 이름]을 가진 이미지를 가져야한다. 그래야 도커 푸시를 이용해서 도커 허브에 있는 나의 레포지토리에 업로드가 가능하기 때문.
- 여기서 중요한 점은 내가 만약 이미 도커 허브에 올려진 이미지를 기반으로 새로운 레이어를 쌓아서 새로운 이미지를 만들었다면, 내가 쌓인 레이어만 푸쉬됨을 볼 수 있다는 것이다.
- 도커 빌드를 통한 이미지 생성
docker build -t [생성될 이미지 이름]:[태그] -f [Dockerfile의 이름] [Dockerfile이 있는 위치]
2. Dockerfile에 대한 설명들
-
도커 이미지를 만들때, 우리는 기본 베이스 이미지(ex:ubuntu)로 컨테이너를 생성하고 환경을 설치하고 프로젝트를 넣고 이미지를 커밋하는 방식을 사용할 수 있다. 그러나 이것은 애플리케이션을 컨테이너화하기 위한 장기적인 시점에서 본다면 좋지 않다고 한다. 그래서 나온 방법이 Dockerfile 이다.
-
Dockerfile은 이미지를 생성하기 위해서, 하나의 파일에 컨테이너에 설치해야할 패키지,소스코드,명령어 등을 적어 필요할 때 build를 통해 컨테이너에서 작업을 진행하게 해주는 파일이다. .dockerignore로 이미지를 생성할 때, 디렉터리 내의 무시하거나 무시하지 말아야할 파일들을 지정해줄 수 있다.
-
멀티 스테이지를 이용해서 빌드를하면, 반드시 필요한 실행 파일만 최종 이미지 결과물에 포함시킴으로써 이미지 크기를 줄일 때 유용하게 사용할 수 있다.
Dockerfile 명령어
- FROM [이미지 이름]: 생성할 이미지의 베이스가 될 이미지
- MAINTAINER [개발자 정보]: 이미지를 생성한 개발자의 정보
- LABEL [키]:[값]: 이미지에 메타데이터를 추가
- RUN [명령어]: 이미지를 만들기 위해 컨테이너 내부에서 명령어 실행 (명령어에 git clone [주소] 를 쓸 수도 있다.)
여기서 apt-get install로 패키지를 설치시 도중에 항목 선택을 하는 패키지가 존재할 수 있다. 그럴땐, ARG DEBIAN_FRONTEND=noninteractive 를 추가해주자.
- ADD [파일 이름] [이미지 내부 디렉터리]: 파일(로컬 폴더,웹사이트에서 다운로드 주소 등)을 이미지의 디렉터리에 저장
- COPY [로컬 폴더내의 파일 이름] [이미지 내부 디렉터리]: 로컬 폴더의 파일을 이미지의 디렉터리에 저장
ADD보다 COPY를 애용토록 하자.
- WORKDIR [명령어를 실행할 위치] : 명령어를 실행할 위치를 설정
- EXPOSE [포트] : 빌드로 생성된 이미지에서 노출할 포트를 설정
- CMD [명령어] : 컨테이너가 시작될 때마다 실행할 명령어를 설정함. Dockerfile에서 한 번만 사용 가능.
- ENV [환경변수 이름] [환경변수 값] : 이 명령어를 추가해서 빌드된 이미지는 컨테이너를 만들 때, [환경변수 이름]으로 [환경변수 값]을 생성
- VOLUME [호스트와 공유할 컨테이너 내부의 디렉터리] : 빌드된 이미지로 컨테이너를 생성했을 때, 호스트와 공유할 컨테이너 내부의 디렉터리를 설정
- ARG [환경 변수 이름][=초기 값] : 이건 파이썬의 argparse를 생각하면 됨. docker build 명령어를 실행할 때, –build-arg [환경변수 이름]=[변수 값]을 추가함으로써 환경변수 값을 바꿀 수 있음.
- USER [컨테이너 내에서 사용될 사용자 계정 이름] : 이것을 다른 명령어들보다 위에 적어둔다면, USER의 아래 명령어들은 사용자 계정 이름 권한으로 실행된다.
일반적으로 사용자의 그룹과 계정을 생성한 후, 사용한다. ex) RUN groupadd -r author && useradd -r -g author hyuntak \ USER hyuntak 이것은 꼭 의무화하자. 왜냐하면 루트가 권한을 갖는 호스트의 폴더를 컨테이너에 공유하게 되면, 컨테이너에서도 루트 권한이라면 그 폴더를 맘대로 갖고 놀 수 있기 때문. 보안에 문제가 생긴다.
- ONBUILD [명령어] : 이 명령어가 포함된 도커파일로 빌드된 이미지를 FROM을 통해 베이스로 사용하여 다른 이미지로 빌드되면, [명령어]가 실행 된다.
- ENTRYPOINT [명령어] : run의 CMD로 쓰이는 값들을 인자로 받아 스크립트의 역할을 할 수 있음 (아직 정확한 개념이 안잡힘)
3. 도커 데몬
도커 프로세스가 실행되어 서버로서 입력을 받을 준비가 된 상태를 도커 데몬이라고 한다. 도커 데몬은 API입력을 받아 도커 엔진의 기능을 수행한다.
음.. 나도 위에 말이 잘 이해가 안가서.. 이해한 바를 쉽게 풀어보면.. 우리가 여태까지 docker [명령어] 를 한 것은 도커의 클라이언트인 /usr/bin/docker 를 부른 것이라고 상상하면 된다. 그리고 클라이언트니까 서버에 물어보러 가야겠지? 그럼 서버는 누구인가? 바로 /usr/bin/dockerd인 도커 데몬인 것이다. 여기서 dockerd는 로컬 도커 데몬이라고 알면 된다. 이 둘 간의 소통은 /var/run/docker.sock을 이용해서 한다. dockerd는 도커를 설치하면 자동으로 리눅스 서비스로써 실행된다. 컴퓨터를 껐다 켜도 호스트에서 자동으로 실행된다. 그래서 여태까지 우리는 docker [명령어]를 쉽게 사용가능했던 것이다.
그러나 이건 어디까지나 내 컴퓨터(자신의 호스트)에서 클라이언트-서버로 왔다갔다한 것이고, 나는 아직 잘 모르지만, 저자님의 말에 따르면 우리가 연구실이나 회사에서 내 컴퓨터의 도커를 사용하고 싶을 지도 모른다. 아, 물론 내 컴퓨터가 항상 켜져있어서 서버의 노릇을 하고 있어야겠지. 그럼 외부에서 어떻게 접속을 할까? 그것은 Remote API를 이용하면 된다. 음.. API라는 개념에 대해 잘 알진 못하지만, 일종의 서로가 대화할 수 있게 해주는 메커니즘?이라고 보면 된다. 여태까지 우리가 사용해왔던 docker [명령어]는 사실 Local API라고 생각하면 된다.
그래서 외부에서 내 컴퓨터의 도커 서버(dockerd)에 접근하려면 tcp/ip 통신으로 직접 접속을 해야한다. 내 컴퓨터에서 dockerd -H tcp://{호스트 ip}:{포트 번호} 을 하게 되면, 내 컴퓨터에 있는 도커 데몬(도커 서버)이 {호스트 ip}:{포트 번호}에 바인딩되어 외부에서 {호스트 ip}:{포트 번호}로 접근이 가능하게 되는 것이다. 그래서 다른 컴퓨터에서 {호스트 ip}:{포트 번호}/[명령어]로 HTTP request를 보내게 되면 내 컴퓨터의 도커 서버가 docker [명령어]라는 것을 파싱한 다음에 다른 컴퓨터에 통신으로 쏴줘서 다른 컴퓨터의 터미널에 내 컴퓨터의 [명령어]로 인한 결과가 출력되는 것이다.
일단 이정도로만 이해했다..
도커 데몬 명령어
- 도커 데몬 시작/정지(도커 서비스 이용)
service docker start service docker stop
- 우분투에선 도커가 설치되면, 자동으로 서비스로 등록되므로 호스트가 재시작되더라도 자동으로 실행됨.
- 도커 데몬 시작(도커 서비스 없이)
dockerd
- 도커 프로세서인 dockerd는 /usr/bin/dockerd 로서 존재하기 때문에, 단독으로 도커 데몬을 실행할 수 있다.
- 그러나 dockerd를 실행하면 터미널에서 foreground로 실행되기 때문에, 실제 운영 환경에선 바람직하지 않다. 따라서 service 명령어를 사용해서 리눅스 서비스로서 관리하는게 좋다.
- 리눅스 서비스로서 관리하려면 /etc/default/docker 를 편집하면 된다.
- 도커 데몬 모니터링
- 도커 데몬 디버그 모드
dockerd -D
- Remote API의 입출력뿐만 아니라 로컬 도컬 클라이언트에서 오가는 모든 명령어를 로그로 출력함.
- 그러나 불필요한 정보들이 너무 많이 출력되고, 도커 데몬을 foreground로 작동해야하는 단점이 있음.
- docker events
docker events docker events --filter 'type=...'
- docker [명령어]로 실행되는 결과를 출력해준다. 이 때, 모든 명령어가 출력되는 것은 아니고 컨테이너,이미지,볼륨,네트워크,플러그인 등에 관한 명령어의 수행 결과만 출력된다.
- –filter 옵션으로 원하는 타입의 결과들만 볼 수도 있다.
- docker stats
docker stats docker stats --no-stream
- 실행중인 모든 컨테이너의 자원 사용량(CPU,메모리 제한 및 사용량, 네트워크 입출력(I/O), 블록 입출력)을 스트림으로 출력함.
- 한번만 출력하고 싶다면 –no-stream 옵션을 사용하자.
- docker system df
docker system df
- 도커가 사용하고 있는 이미지,컨테이너,로컬 볼륨의 총 개수 및 사용 중인 개수,크기,삭제함으로써 확보 가능한 공간을 출력함.
- CAdvisor
docker run \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:ro \ --volume=/sys:/sys:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ --volume=/dev/disk/:/dev/disk:ro \ --publish=8080:8080 --detach=true \ --name=cadvisor \ google/cadvisor:latest
- 구글이 만든 컨테이너 모니터링 도구로, 컨테이너로 간단히 설치할 수 있꼬, 컨테이너별 실시간 자우너 사용량 및 도커 모니터링 정보등을 시각화해서 보여준다.
- 깃허브 혹은 도커 허브에서 도커 이미지를 pull해서 얻을 수 있다.
- 도커 데몬 디버그 모드