새로 시작한 개인 프로젝트는 python기반인데 docker를 이용한 sandbox 아키텍쳐가 필요해졌습니다. 때문에 python으로 작성된 docker client가 필요해서 찾아보니 docker-py를 발견하게 되었습니다. 일반적인 docker 쉘 커맨드와 동일한 기능을 docker-py를 이용해서 거의 모두 사용할 수 있는데 이를 이용해서 python으로는 어떻게 작성하는 지 정리해보겠습니다.

초기화

제일 처음 해야 할 것은 로컬에 있는 docker daemon과 연동해야 하는데 docker-py에서는 Client라는 인스턴스를 생성하고 이에 내재된 다양한 API를 통해 컨트롤이 가능합니다.

from docker import Client
cli = Client()

인자를 주지 않고 인스턴스를 생성하면 기본적으로 로컬로 접근하게 됩니다. base_url이라는 인자로 외부 daemon과 연동도 가능한 듯 하네요.

docker pull

docker hub에서 이미지를 다운로드합니다.

cli = Client(base_url='tcp://127.0.0.1:2375')
for line in cli.pull('busybox', stream=True):
    print(json.dumps(json.loads(line), indent=4))
# { "status": "Pulling image (latest) from busybox", "progressDetail": {}, "id": "e72ac664f4f0" }
# { "status": "Pulling image (latest) from busybox, endpoint: ...", "progressDetail": {}, "id": "e72ac664f4f0" }

인자에 stream=True로 설정하면 string generator로 리턴되고 False로 설정하거나 설정하지 않으면 string으로 리턴됩니다.

docker run

docker를 사용하면서 가장 쓰는 명령어가 컨테이너를 기동하는 명령어인 run일텐데요. docker-py에서는  컨테이너를 생성하고(.create_container()) 시작하는(.start()) 절차로 진행할 수 있습니다.

container = cli.create_container(image='busybox:latest', command='/bin/sleep 30')
print(container) # {'Id': '8a61192da2b3bb2d922875585e29b74ec0dc4e0117fcbf84c962204e97564cd7', 'Warnings': None}

response = cli.start(container=container.get('Id'))
print(response)  # None

command line에서 컨테이너를 기동할 때 다양한 옵션을 줄 수 있는데 자주 쓰는 옵션들만 소개해보겠습니다.

docker run -p

-p, -publish=[] : 호스트에 연결된 컨테이너의 특정 포트를 외부에 노출합니다. 보통 웹 서버의 포트를 노출할 때 주로 사용합니다.

  • <호스트 포트>:<컨테이너 포트> 예) -p 80:80
  • <IP 주소>:<호스트 포트>:<컨테이너 포트> 호스트에 네트워크 인터페이스가 여러 개이거나 IP 주소가 여러 개 일 때 사용합니다. 예) -p 192.168.0.10:80:80
  • <IP 주소>::<컨테이너 포트> 호스트 포트를 설정하지 않으면 호스트의 포트 번호가 무작위로 설정됩니다. 예) -p 192.168.0.10::80
  • <컨테이너 포트> 컨테이너 포트만 설정하면 호스트의 포트 번호가 무작위로 설정됩니다. 예) -p 80

docker-py에서는 host_config를 생성해서 포트 바인딩해줍니다.

container = cli.create_container(
    'busybox', 'ls', ports=[1111, 2222],
    host_config=cli.create_host_config(port_bindings={
        1111: 4567,
        2222: None,
        3333: [1234, 5678],
    })
)

위 코드는 다음과 같이 네트워크 설정을 하게 됩니다.

  • 컨테이너 1111번 포트를 호스트 4567번 포트로 bind
  • 컨테이너 2222번 포트는 개방하지 않음
  • 컨테이너 3333번 포트를 호스트 1234번 포트와 5678번 포트로 bind

포트 바인딩에 대해서 더 자세한 설정은 여기를 참고해주세요.

--link=[] : 컨테이너끼리 연결합니다. <컨테이너 이름>:<별칭> 형식입니다.

  • --link="db:db"

포트 바인딩에서 했던 것처럼 host_config를 생성해서 링크를 설정합니다. 다음 예를 보시죠.

container = cli.create_container(
    'busybox', 'ls', ports=[1111, 2222],
    host_config=cli.create_host_config(links=[(db_container['Id'], 'db')])
)

이제  busybox 컨테이너 안에서 데이터베이스 컨테이너를 접근할 때 db라는 URL로 접근이 가능합니다. (예: mongo://db:27017 )

docker ps

컨테이너 목록을 출력합니다.

cli.containers()
# [{'Command': '/bin/sleep 30',
#  'Created': 1412574844,
#  'Id': '6e276c9e6e5759e12a6a9214efec6439f80b4f37618e1a6547f28a3da34db07a',
#  'Image': 'busybox:buildroot-2014.02',
#  'Names': ['/grave_mayer'],
#  'Ports': [],
#  'Status': 'Up 1 seconds'}]

docker stop

기동된 컨테이너를 중지합니다.

cli.stop(container.get('id'))

프로젝트를 진행하며 계속 추가하도록 하겠습니다~~ 🙂

프로젝트에서 사용한 것을 위주로 작성하였고, 이 밖에 전체 기능에 대해서는 공식 문서를 참고해주세요.


Reference