Environment: Ubuntu 18.04
1. Docker daemon
docker 그 자체에 대해서 알아보는 시간입니다. Docker의 구조는 크게 2가지로 나뉩니다.
- Docker server
- /usr/bin/dockerd 파일로 실행
- container 생성 및 실행과 image 관리하는 주체
- 외부에서 API 입력을 받아 docker engine의 기능을 수행
- docker process가 실행되어 서버로서 API 입력을 받을 준비가 된 상태를 docker daemon
- Docker client
- /usr/bin/docker 에서 실행
- 외부에서 API를 사용할 수 있도록 CLI제공
- 외부에서 API요청을 해당 clinet가 사용되며 client는 docker daemon에게 API 전달
- Client는 /var/run/docker.sock에 위치한 unix socket을 통해 daemon API 호출
2. Docker daemon 실행 및 설정
docker daemon은 다음 명령어로 시작, 정지가 가능합니다. (start는 둘 중 아무 명령어를 사용해도 됩니다.)
#start
service docker start
dockerd
#stop
service docker stop
dockerd
명령어를 통해서도 daemon을 실행 가능합니다. 그리고 daemon에 적용할 수 있는 옵션에 대해 알아봅시다.
2.1 Docker daemon 제어 -H
아무런 옵션 없이 daemon을 실행시키면 default로 docker client인 /usr/bin/docker을 위한 unix socket인 /var/run/dokcer.sock을 사용하게 됩니다. 이를 -H옵션을 통해 나타내면 다음과 같고 두 명령어는 같은 명령어입니다.
dockerd
dockerd -H unix:///var/run/docker.sock
즉, -H옵션을 통해서 dameon의 API를 사용할 방법을 추가할 수 있다는 것이고 예를 들어 -H뒤에 IP주소와 port번호를 입력하면 원격 API인 Docker remote API로 docker를 제어 가능합니다.
(Remote API는 RESTful API형식을 띄고 있으므로 HTTP 요청으로 docker를 제어 가능) 다음과 같이 docker daemon을 실행하면 host에 존재하는 모든 네트워크 인터페이스의 IP주소와 2375번 포트를 바인딩해 입력을 받습니다.
dockerd -H tcp://0.0.0.0:2375
하지만 이렇게 할 경우 Remote API만을 위한 바인딩 주소를 입력했으므로 unix socket은 비활성화되고 docker client를 사용 못하게 됩니다. 즉, 위와 같이 docker ps
와 같이 docker로 시작하는 명령어 사용 이 불가합니다. 그러므로 이를 해결하기 위해 Remote API를 위한 바인딩 주소와 unix socket을 같이 설정해 줍니다.
dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
위와 같이 하면 docker client가 docker daemon에게 명령 수행 요청뿐만 아니라 Remote API 또한 사용 가능합니다. 0.0.0.0은 localhost주소이며 이는 실제 localhost주소(private ip)인 192.168.26.129를 가리킵니다. 또 하나의 terminal을 켜서 curl을 통해 Http요청을 보내 Remote API가 작동 가능한 지 확인해봅니다. Host ip(192.168.26.129), port(2375)를 가지는 docker daemon으로 http 요청을 보내는 것이고 192.168.26.129:2375/version은 docker version
명령어와 같습니다.
그리고 다음과 같이 docker client에 -H옵션을 설정해 제어할 원격 docker daemon을 설정하고 해당 daemon에 명령 수행 요청 가능합니다.
2.2 Docker daemon 보안 적용 --tlsverify
Docker는 기본적으로 보안 연결 설정이 안 되어있기 때문에 docker client, remote API 사용할 때 위험성이 있다는 것을 의미합니다. 특히나 보안이 없다면 ip, port만 안다면 remote API를 통해 docker를 제어 가능해져 버립니다.
그래서 docker daemon에 TLS 보안을 적용하고 docker client가 인증하지 않으면 docker를 제어할 수 없도록 설정해봅시다.
서버 측 파일 생성
- 인증서에 사용할 key 생성 (ca-key.pem)
RSA 4096 키 생성 및 개인키를 AES256으로 암호화하여 ca-key.pem 파일을 만듭니다.
- Public key를 생성 (ca.pem)
입력하는 모든 항목은 공백으로 둬도 상관없으므로 공백으로 둔다.
- 서버에서 사용할 key 생성 (server-key.pem)
- 서버에서 사용될 인증서를 위한 인증 요청서 파일 생성 (server.csr)
192.168.29.129은 docker host의 IP주소 또는 domain이름이고 이는 외부에서 접근 가능해야 합니다.
- 서버 측의 인증서 파일을 생성합니다. (server-cert.pem)
접속에 사용될 IP주소를 extfile.cnf로 저장하고 192.168.29.129으로 연결이 사용되도록 인증서 파일을 생성한다.
클라이언트 측 파일 생성
- 클라이언트 측의 key 파일 (key.pem)과 인증 요청 파일을 생성 (client.csr), extfile.cnt 파일에 extendedKeyUsage항목 추가
- 클라이언트 측의 인증서 생성 (cert.pem)
- 서버, 클라이언트 측에서 사용할 인증서들에 대한 쓰기 권한 삭제
TLS 보안 적용
TLS 보안 적용을 위해 --tlsverify 옵션과 보안을 위해 필요한 옵션들을 더하여 docker daemon을 실행한다. (밑의 맨위 그림)
dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376 -H unix:///var/run/docker.sock
그리고 client 측에서 TLS 연결 설정을 하지 않고 Remote API로 접근했을 때와(밑의 중간 그림) TLS 연결 설정을 하고 접근했을 때의 원격 제어 시(밑의 맨 아래 그림)의 결과 차이를 볼 수 있다.
# No TLS
docker -H 192.168.26.129:2376 version
# TLS
docker -H 192.168.26.129:2376 --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem --tlsverify version
docker의 remote API를 사용하는 포트는 보안이 적용되어 있지 않으면 2375, 되어 있으면 2376을 사용하는 것이 docker 커뮤니티의 관례
2.3 Docker daemon 모니터링
다음과 같은 이유로 docker daemon 자체에 대한 모니터링이 필요합니다.
- 많은 수의 docker server 관리
- container 어플리케이션 개발 중 오류 디버깅
- docker를 Paas로써 제공하기 위해 실시간으로 상태 체크
Docker daemon 디버그 모드
다음과 Docker daemon을 디버그 옵션으로 실행하면 Remote API뿐만 아니라 로컬 docker client에서 오가는 명령어도 로그로 출력하게 됩니다. 하지만 원치 않는 정보도 출력되고 해당 daemon을 foreground 상태로 실행해야 한다는 단점이 있다.
dockerd -D
events, stats, system df 명령어
events는 docker daemon에서 일어나는 일을 실시간 stream log로 보여줍니다.
docker events
위의 명령어를 실행시키고 docker pull ubuntu:14.04
을 해보면 다음과 같이 docker events 명령어 밑으로 logging이 됩니다. events는 attach, commit, copy, create와 같은 container관련 명령어, delete, import, pull, push등의 image 관련 명령어, 볼륨, 네트워크, 플러그인 명령어의 수행 결과만을 출력합니다.
stats은 실행 중인 모든 container의 자원 사용량을 stream으로 출력한다.
docker stats
system df은 docker에서 사용하고 있는 이미지, 컨테이너, 로컬 볼륨의 총 개수 및 사용 중인 개수, 크기 등을 출력합니다.
docker system df
CAdvisor
구글이 만든 컨테이너 모니터링 도구로 실시간 자원 사용량 및 docker 모니터링 정보 등을 시각화해서 보여줍니다. 다음과 같이 docker hub에서 docker image로 사용 가능하며 container agent형태로 docker 모니터링에 필요한 자료를 수집합니다.
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
Host에서 127.0.0.1:8080에 접속하면 CAdvisor 대시보드에 접근할 수 있고 해당 웹에서 말한 다양한 정보를 볼 수 있다.
[Subcontainers]항목의 [/docker]를 클릭하면 docker daemon의 정보, 컨테이너의 목록을 보여주는 페이지로 이동한다. CAdvisor의 container는 위의 옵션에서 많은 --volume옵션을 통해 docker의 정보를 담고 있는 파일들을 마운트했기때문에 CAdvisor에서 다양한 모니터링이 가능함을 알아둡시다. 예를 들어 /var/lib/docker에는 도커 컨테이너, 이미지 등이 파일로 존재합니다.
하지만 CAdvisor는 단일 docker host만을 모니터링 가능하므로 여러 개의 호스트로 docker를 사용하고 있다면 Kubernetes나 swarm mode 등과 같은 오케스트레이션 툴을 설치한 뒤에 프로메테우스(Prometheus), InfluxDB 등을 이용해 여러 host의 데이터를 수집해야 한다. (이후 글에서 더 자세히!!)
2.4 Remote API라이브러리를 이용한 docker 사용
docker daemon을 제어하기 위해 -H옵션을 통해 진행했었는데 container application이 수행해야 할 작업이 많거나 초기 화등 복잡한 과정이 포함되어 있을 경우 docker를 제어하는 라이브러리를 사용한다. 즉, Remote API를 wrapping해서 사용하기 쉽게 만들어 놓은 라이브러리를 쓰면 docker 사용이 편해진다.
파이썬 라이브러리
파이썬 라이브러리를 사용하기 위한 환경은 python 3.6입니다. docker library를 설치하려면 pip3가 필요하기 때문에 pip3가 설치되어 있지 않으시면 다음과 같이 설치하고 docker library를 설치합시다.
# if you don't installed pip3 before
apt install python3-pip -y
# install docker library
pip3 install docker
라이브러리가 정상적으로 설치되어있는지 확인하기 위해 unix socket에 연결해 docker engine의 정보를 출력해봅니다.
좀 더 심화 과정으로 다음과 같은 시나리오를 진행해보죠.
- Remote API를 사용할 수 있게 0.0.0.0:2376을 바인딩 주소로 해놓고 TLS보안이 적용되도록 docker daemon실행
- 파이썬 라이브러리를 통해 해당 docker daemon에 연결 후 ubuntu:16.04 image로 container실행
위에서 TLS적용을 위해 진행한 key들이 있는 directory에서 tls_docker_run.py이라는 python 파일을 만들어 실행해보았습니다.
#ls_docker_run.py
import docker
import requests.packages.urllib3 as urllib3
urllib3.disable_warnings() # disable to print warning
tls_config = docker.tls.TLSConfig(client_cert=('./cert.pem', './key.pem'))
client= docker.DockerClient(base_url='tcp://192.168.26.129:2376', tls=tls_config)
container = client.containers.run('ubuntu:16.04', name='python_ubuntu', detach=True)
print(f'Created container is : {container.name}, {container.id}')
'AI Engineering > MLOps' 카테고리의 다른 글
Docker/Kubernetes - (8) Docker Compose (0) | 2022.03.15 |
---|---|
Docker/Kubernetes - (7) Docker Swarm (0) | 2022.03.15 |
Docker/Kubernetes - (5) Dockerfile (0) | 2022.03.14 |
Docker/Kubernetes - (4) docker image 이해 및 배포 (0) | 2022.03.14 |
Docker/Kubernetes - (3) docker container 네트워크/로깅/제한 (0) | 2022.03.13 |