文档章节

Docker Remote API如何在开发中使用

clearraining
 clearraining
发布于 2015/01/22 18:47
字数 2196
阅读 120
收藏 2

初学docker,了解docker remote API的时候根本不知道怎么使用在开发中,通过DockerClient这个项目能很好的认识到API在开发过程中的使用,如何建立连接等。也希望像我一样的初学者能通过这个项目了解docker API的使用。

一.   基本配置

访问docker远程API有两种方法,使用Unix套接字和HTTP端口。

Unix套接字:docker监听unix:///var/run/docker.sock这个unix套接字。

HTTP远程访问:需要修改配置使能支持远程访问,在ubuntu环境下找到/etc/init/docker.conf文件,找到 DOCKER_OPTS并修改,接着重启docker后台进程。

DOCKER_OPTS="-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock"
$sudo service docker restart
验证
$netstat -ant  |grep 4243
tcp6       0      0 :::4243                 :::*                    LISTEN

然后就可以访问了。

举例如下:

$curl http://127.0.0.1:4243/info
{"Containers":4,"Debug":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Dirs","63"]],"ExecutionDriver":"native-0.2","IPv4Forwarding":1,"Images":55,"IndexServerAddress":"https://index.docker.io/v1/","InitPath":"/usr/bin/docker","InitSha1":"","KernelVersion":"3.13.0-32-generic","MemoryLimit":1,"NEventsListener":0,"NFd":16,"NGoroutines":15,"OperatingSystem":"Ubuntu precise (12.04.5 LTS)","SwapLimit":0}

$curl GET http://127.0.0.1:4243/containers/json
[{"Command":"crate -Des.cluster.name=cratecluster -Des.node.name=crate1 -Des.transport.publish_port=4300 -Des.network.publish_host=115.159.76.38 -Des.multicast.enabled=false -Des.discovery.zen.ping.unicast.hosts=115.159.76.38:4300,115.159.26.242:4300 -Des.discovery.zen.minimum_master_nodes=2","Created":1418829276,"Id":"dfd58a62a7c941218088f6e43d8dc17ecfb8cd0783e6c4e338c321d6d39c4bbd","Image":"docker.cn/docker/crate:0.45","Names":["/node1"],"Ports":[{"IP":"0.0.0.0","PrivatePort":4200,"PublicPort":4200,"Type":"tcp"},{"IP":"0.0.0.0","PrivatePort":4300,"PublicPort":4300,"Type":"tcp"}],"Status":"Up 2 weeks"}]


如果想要了解完整的docker API可以访问官网:https://docs.docker.com/reference/api/docker_remote_api/ 。

二.  DockerClient  

下面开始进入dockerClient这个项目,dockerclient.go中实现了对docker remote API的封装。

dockerClient项目:https://github.com/samalba/dockerclient

1.创建DockerClient

a. NewDockerClient()

func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) {
	return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout))
}

使用NewDockerClient方法新建一个dockerclient,需要传入daemonUrl和tlsConfig两个参数,创建成功会返回一个DockerClient。其中两个参数具体含义如下:

daemonUrl: 需要传入一个后台docker进程的Url,比如unix:///var/run/docker.sock。

tlsConfig: tlsConfig是cropto/tls包中的Config结构类型,Config结构类型用于配置TLS客户端或服务端,具体参阅cropto/tls包。

TLS:Transport Layer Security(安全传输层协议)

TLS用于在两个通信应用程序之间提供保密性和数据完整性。

使用举例:

docker, _ := dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)

在NewDockerClient方法中调用NewDockerClientTimeout方法实现具体的DockerClient的创建。


b.NewDockerClientTimeout()

func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration) (*DockerClient, error) {
	u, err := url.Parse(daemonUrl)
	if err != nil {
		return nil, err
	}
	if u.Scheme == "tcp" {
		if tlsConfig == nil {
			u.Scheme = "http"
		} else {
			u.Scheme = "https"
		}
	}
	httpClient := newHTTPClient(u, tlsConfig, timeout)
	return &DockerClient{u, httpClient, tlsConfig, 0}, nil
}

需要向NewDockerClientTimeout方法传入三个参数,分别是daemonUrl、tlsConfig和timeout。在此方法中会先解析daemonUrl,net/url包中的Parse方法解析daemonUrl,返回一个URL结构类型。

URL结构类型:

type URL struct {    
    Scheme   string
    Opaque   string    // 编码后的不透明数据
    User     *Userinfo // 用户名和密码信息
    Host     string    // host或host:port
    Path     string
    RawQuery string    // 编码后的查询字符串,没有'?'
    Fragment string    // 引用的片段(文档位置),没有'#'}

URL基本格式如下:

scheme://[userinfo@]host/path[?query][#fragment]

timeout:timeout是time包中的Duration类型,代表两个时间点之间经过的时间,以纳秒为单位。timeout默认为30s(defaultTimeout)

解析完daemonUrl后,对返回的URL的scheme进行判断,tcp协议并且有安全传输协议的设置scheme为https,否则设为http。当然scheme也有可能是unix。接着需要新建一个HTTPClient,通过向newHTTPClient方法传入三个参数,包括解析后的URL、tlsConfig和timeout。


c. newHTTPClient()

func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *http.Client {
	httpTransport := &http.Transport{
		TLSClientConfig: tlsConfig,
	}
	switch u.Scheme {
	default:
		httpTransport.Dial = func(proto, addr string) (net.Conn, error) {
			return net.DialTimeout(proto, addr, timeout)
		}
	case "unix":
		socketPath := u.Path
		unixDial := func(proto, addr string) (net.Conn, error) {
			return net.DialTimeout("unix", socketPath, timeout)
		}
		httpTransport.Dial = unixDial
		// Override the main URL object so the HTTP lib won't complain
		u.Scheme = "http"
		u.Host = "unix.sock"
		u.Path = ""
	}
	return &http.Client{Transport: httpTransport}
}

newHTTPClient主要是新建一个HTTPClient(就是建立一个网络连接),在方法中先新建一个Transport结构类型的httpTransport实例。

Transport结构类型:

type Transport struct {    
    Proxy func(*Request) (*url.URL, error)              // Proxy指定一个对给定请求返回代理的函数。  
    Dial func(network, addr string) (net.Conn, error)   // Dial指定创建TCP连接的拨号函数。如果Dial为nil,                                                         // 会使用net.Dial。
    TLSClientConfig *tls.Config                         // TLSClientConfig指定用于tls.Client的TLS配置信息                                                        // 如果该字段为nil,会使用默认的配置信息。  
    TLSHandshakeTimeout time.Duration                    
    DisableKeepAlives bool                              
    DisableCompression bool                             
    MaxIdleConnsPerHost int                             
    ResponseHeaderTimeout time.Duration                 
}

接着对URL的scheme进行判断,如果是unix(也就是访问由docker监听的unix套接字),那么进入case "unix",否则进入默认的default。(能传输到这里的一般是unix、http和https)

Example: unix:///var/run/docker.sock

case "unix": 先新建一个socketPath为URL中Path的内容(如上例子中u.path=/var/run/docker.sock), 接着新建网络连接的拨号方法unixDial,即要赋值给httpTransport实例中的Dial方法。在unixDial方法中调用net包中的DialTimeout方法实现采用超时的网络连接。

func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
即
net.DialTimeout("unix", "/var/run/docker.sock", timeout)
举例
conn, err := net.DialTimeout("tcp", "google.com:80", timeout)

最后返回一个Client结构类型实例表示HTTP客户端。

Client结构类型:

type Client struct {    
    Transport RoundTripper     // Transport指定执行独立、单次HTTP请求的机制。
    CheckRedirect func(req *Request, via []*Request) error
    Jar CookieJar             // Jar指定cookie管理器。
    Timeout time.Duration}

最后返回NewDockerClientTimeout方法中,httpClient建立完成,接着返回一个建立完成的DockerClient结构类型实例。

DockerClient结构类型:

type DockerClient struct {
	URL           *url.URL
	HTTPClient    *http.Client
	TLSConfig     *tls.Config
	monitorEvents int32
}

至此DockerClient创建完成。

2. 发送请求处理

a. doRequest()

func (client *DockerClient) doRequest(method string, path string, body []byte, headers map[string]string) ([]byte, error) {
	b := bytes.NewBuffer(body)
	req, err := http.NewRequest(method, client.URL.String()+path, b)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")
	if headers != nil {
		for header, value := range headers {
			req.Header.Add(header, value)
		}
	}
	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		if !strings.Contains(err.Error(), "connection refused") && client.TLSConfig == nil {
			return nil, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
		}
		return nil, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode == 404 {
		return nil, ErrNotFound
	}
	if resp.StatusCode >= 400 {
		return nil, Error{StatusCode: resp.StatusCode, Status: resp.Status, msg: string(data)}
	}
	return data, nil
}

doRequest方法完成发送请求的工作,比如你想获得docker的信息,那么可以通过doRequest方法发送“GET”请求。下面介绍doRequest方法的具体实现。

b := bytes.NewBuffer(body)
方法原型:
func NewBuffer(buf []byte) *Buffer

NewBuffer使用buf(即body)作为初始内容创建并初始化一个Buffer,本方法用于创建一个用于读取已存在数据的buffer(即b)。

req, err := http.NewRequest(method, client.URL.String()+path, b)
方法原型:
func NewRequest(method, urlStr string, body io.Reader) (*Request, error)

NewRequest使用指定的方法、网址和可选的主题创建并返回一个新的*Request(即req)。Request类型代表一个服务端接收到的或者客户端发送出去的HTTP请求。比如上面所说的一个例子:

curl GET http://127.0.0.1:4243/containers/json

那么method=GET, urlStr=http://127.0.0.1:4243/containers/json , body=nil。

Request结构类型:

type Request struct {
    Method   string    //Method指定HTTP方法(GET,POST,PUT等)。对客户端,""代表GET。
    URL   *url.URL     //URL在服务器端表示被请求的URL,在客户端表示要访问的URL。
    Proto   string
    ProtoMajor   int
    ProtoMinor   int
    Header   Header      //Header字段表示HTTP请求的头域。
    Body   io.ReadCloser   //Body是请求的主体。
    ContentLength   int64
    TransferEncoding   []string
    Close   bool
    Host   string
    Form   url.Values
    PostForm   url.Values
    MultipartForm   *multipart.Form
    Trailer   Header
    RemoteAddr   string
    RequestURL   string
    TLS   *tls.ConnectionState
}

具体的各个字段详细解释可以参考帮助文档或者访问下面一个网址:

帮助文档翻译版:http://git.oschina.net/liudiwu/pkgdoc(或者:http://mygodoc.oschina.mopaas.com

Go包方法使用:https://github.com/astaxie/gopkg 。

req.Header.Add("Content-Type", "application/json")
if headers != nil {
	for header, value := range headers {
		req.Header.Add(header, value)
	}
}
方法原型
type Header map[string][]string
func (h Header) Add(key, value string)

Add方法添加键值对到req的Header字段,header字段即HTTP请求的头域。

resp, err := client.HTTPClient.Do(req)
if err != nil {
	if !strings.Contains(err.Error(), "connection refused") && client.TLSConfig == nil {
		return nil, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
	}
	return nil, err
}
方法原型
func (c *Client) Do(req *Request) (resp *Response, err error)

Do方法发送请求,返回HTTP回复。

defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
	return nil, err
}
if resp.StatusCode == 404 {
	return nil, ErrNotFound
}
if resp.StatusCode >= 400 {
	return nil, Error{StatusCode: resp.StatusCode, Status: resp.Status, msg: string(data)}
}
return data, nil
方法原型
func ReaderAll(r io.Reader) ([]byte, error)

ReaderAll方法从请求返回的resp的Body中读取数据知道EOF活着遇到error,返回读取的数据和遇到的错误。并对返回的HTTP状态码进行判断,最后返回数据并关闭resp.Body。

Response结构类型:

type Response sctuct {
    Status  string
    StatusCode  int   
    Proto  string
    ProtoMajor  int
    ProtoMinor  int
    Header  Header
    Body  io.ReadCloser
    ContentLength  int64
    TransferEncoding  []string
    Close  bool
    Trailer  Header
    Request  *Request
    TLS  *tls.ConnectionState
}

总结:上面是DockerClient中主要的建立连接的方式,对于我这样的初学者来说这个项目起到基础的帮助作用,对于开发docker管理项目起到帮助。

参考资料:

1.https://docs.docker.com/reference/api/docker_remote_api/

2.https://github.com/samalba/dockerclient

3.http://git.oschina.net/liudiwu/pkgdoc

4.http://mygodoc.oschina.mopaas.com

5.https://github.com/astaxie/gopkg



© 著作权归作者所有

共有 人打赏支持
clearraining
粉丝 0
博文 1
码字总数 2196
作品 0
厦门
加载中

评论(1)

clearraining
clearraining
82
Kitematic和DockerCLI如何无缝对接

介绍 Kitematic是一个 Docker GUI 工具,它可以在 Mac 和Windows上更快速、更简单的运行Docker。Docker官方表示,Kitematic是其生态系统中成长起来的一个非常棒的项目。 Kitematic简化了安装...

Mrexamo
2015/08/12
893
0
Docker配置文件在Ubuntu中不起作用的解决办法

环境 1. OS 版本: Ubuntu 16.04 LTS 2. Docker版本: Docker version 1.11.2, build b9f10c9 问题描述 最近想使用Docker的Remote API,即使用REST API的形式访问、操作Docker,按照网上的几篇...

风摆残荷
2016/09/04
85
0
Docker学习笔记八 使用Docker API

8.1 Docker API 在Docker生态系统中一共有三种API: Registry API:提供了与Docker Registry集成的功能; Docker Hub API:提供了与Docker Hub集成的功能; Docker Remote API:提供了与Doc...

一万
2016/07/15
48
0
Docker on Mac上的Remote API 远程控制

Docker提供了Remote API,可以通过REST接口进行Docker服务的控制,包括pull/push等所有操作,结果与本机的操作完全一样。使用Docker Remote API可以通过脚本进行Docker集群的自动化控制。 但...

openthings
2016/10/29
491
0
一种新的进入容器的方式: WebSocket + Docker Remote API

众所周知,容器是基于操作系统内核的一种轻量级的虚拟化技术。其可以类比于虚拟机,但其本身并不是虚拟机。在传统的虚拟机使用场景中,每个用户都会通过堡垒机,根据自己被分配的权限,登录某...

xiaomin0322
01/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SSO单点登录PHP简单版

  前面做了一个新项目,需要用户资源可以需要共享。由于之前没有做过这样的东西,回家之后,立马网站百度“单点登录”。帖子很多,甄别之后,这里列几篇认为比较有营养。   http://blog...

slagga
26分钟前
1
0
Java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下。 本文参考java 泛型详解、Java中的泛型方法、 java泛型详解 1 概述 泛型在j...

hensemlee
30分钟前
1
0
Annotation注解详细介绍

目录介绍 1.Annotation库的简单介绍 2.@Nullable和@NonNull 3.资源类型注释 4.类型定义注释 5.线程注释 6.RGB颜色纸注释 7.值范围注释 8.权限注释 9.重写函数注释 10.返回值注释 11.@Keep注释...

潇湘剑雨
32分钟前
1
0
一步步编写自己的PHP爬取代理IP项目(二)

这一章节我们正式开展我们的爬虫项目,首先我们先要知道哪个网站能获取到免费代理IP,目前比较火的有西刺代理,快代理等,这里我们拿西刺代理作为例子。 这里就是一个个免费的IP地址以及各自...

NateHuang
51分钟前
2
0
11-利用思维导图梳理JavaSE-Java的反射机制

11-利用思维导图梳理JavaSE-Java的反射机制 主要内容 1.反射与Class类 1.1.反射概念 1.2.Class类 1.3.实例化Class类 1.4.反射的作用 1.5.Class对象的作用 2.反射的深入应用 2.1.调用无参的成...

飞鱼说编程
57分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部