Requests で Docker Remote API にアクセスする

Posted: , Modified:   Python Docker Requests Qiita

本稿は Qiita 投稿記事 のバックアップです.

概要

Python Requests から Docker Remote API を利用したい. 暗号化を行えば TCP からでも利用できるが,API を同じホストから利用することを考えているため unix ソケットを使う.

Unix ソケットの読み書き

Docker のソケットファイルは /var/run/docker.sock にある.ソケットファイルの読み書きは,次の通り.

import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/var/run/docker.sock")
# s.recv, s.send, etc.

Requests で独自ソケットを使う

こちらはかなり面倒で,Transport Adapterを実装する必要がある.そして,そのためには,PoolManager,HTTPConnectionPool,HTTPConnection も合わせて実装する必要がある.

import socket
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3 import PoolManager, HTTPConnectionPool
from httplib import HTTPConnection

class MyAdapter(HTTPAdapter):

    def __init__(self, sockfile, **kwargs):
        self._sockfile = sockfile
        super(MyAdapter, self).__init__(**kwargs)

    def init_poolmanager(self, connections, maxsize, **kwargs):
        self.poolmanager = MyPoolManager(self._sockfile,
                                         num_pools=connections, maxsize=maxsize)


class MyPoolManager(PoolManager):

    def __init__(self, sockfile, **kwargs):
        self._sockfile = sockfile
        super(MyPoolManager, self).__init__(**kwargs)

    def _new_pool(self, scheme, host, port):
        return MyConnectionPool(self._sockfile, host, port, **self.connection_pool_kw)


class MyConnectionPool(HTTPConnectionPool):

    def __init__(self, sockfile, host, port, **kwargs):
        self._sockfile = sockfile
        super(MyConnectionPool, self).__init__(host, port, **kwargs)

    def _new_conn(self):
        self.num_connections += 1
        return MyConnection(self._sockfile,
                            host=self.host, port=self.port, strict=self.strict)


class MyConnection(HTTPConnection):

    def __init__(self, sockfile, **kwargs):
        self._sockfile = sockfile
        HTTPConnection.__init__(self, **kwargs)

    def connect(self):
        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.sock.connect(self._sockfile)

        if self._tunnel_host:
            self._tunnel()

HTTPConnection は old-style クラスなので,初期化方法に注意.

API の利用

利用例は次の通り.

req = requests.Session()
req.mount("http://", MyAdapter("/var/run/docker.sock"))
print req.get("http://127.0.0.1/images/json?all=0").json()

http://127.0.0.1 と書いているところがダサい・・・.

参考