使用 docker-client 對docker Engine 進行調用

使用 docker-client 對docker Engine 進行調用

前提:一段時間以來,使用程序操作docker都是通過shell腳本進行操作,這種方法有很大的弊端(個人理解分爲以下幾點:)

1、對併發處理不友好

1.1、如果生成shell腳本,腳本前面路徑加上UUID,只要腳本中的變量(例如路徑)都是唯一的,這種做法是行的通的。(Linux 多用戶,多任務)

舉例Java程序執行Java代碼調用腳本:

    public synchronized static String execCommand(String[] command){
        log.info("將要執行命令{}", JSONObject.toJSONString(command));
        StringBuilder result = new StringBuilder();
        try {
//            String image = "nginx-xi1:latest";
//            String[] command = new String[]{"docker","build","-t",image,"/root/xiqingsong/docker/642B426072C773F3BFCB6B408932594E"};
            Process ps = Runtime.getRuntime().exec(command);
            ps.waitFor();
            BufferedReader bufrIn = new BufferedReader(new InputStreamReader(ps.getInputStream(), "UTF-8"));
            BufferedReader bufrError = new BufferedReader(new InputStreamReader(ps.getErrorStream(), "UTF-8"));
            // 讀取輸出 result是shell中的輸出
//            StringBuilder result = new StringBuilder();
            String line = null;
            while ((line = bufrIn.readLine()) != null || (line = bufrError.readLine()) != null) {
                result.append(line).append('\n');
            }
            log.info(result.toString());
            return result.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

通過上面代碼示例發現一個方法 Process.waitFor() 先看看方法的說明:

Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.
導致當前線程在必要時等待,直到該進程對象所表示的進程終止。如果子進程已經終止,則該方法立即返回。如果子進程尚未終止,則調用線程將被阻塞,直到子進程退出。

沒錯,當程序執行Linux命令的時候,該線程必須要等待完成,而且通過執行結果也很難判斷出是否成功。當然shell腳本的話可能通過是不是 “exit 1” 進行判斷。
同時 還需要判斷執行時間,爲程序設置等待超時時間。(不到實在沒有解決方案的時候,慎用)

1.2 、對事務管理不友好

1.3、異常處理比較複雜

**沒有調查沒有發言權,1.2 1.3 這個我沒有驗證,公司大佬告訴我這個問題,我先寫上

2、選擇合適的SDK

官方地址:https://docs.docker.com/engine/api/sdk/examples/

2.1 、官方只給出了兩種語言操作docker Engine的示例(go 、 Python)

在這裏插入圖片描述

當然除了這兩種語言之外,官方下面推薦以下SDK

在這裏插入圖片描述

在這裏插入圖片描述

3、正文 目前Java用於操作docker 常用的工具有兩種:

在這裏插入圖片描述

3.1、操作docker 需要配置開放遠程調用的端口,和證書的配置

有興趣的同學可以去看官網上的介紹和操作步驟:https://docs.docker.com/engine/security/https/

下面是我借鑑其他博客實測過後生成證書的腳本:

#創建 Docker TLS 證書
#!/bin/bash

#相關配置信息
SERVER="192.168.80.136"
PASSWORD="123123"
COUNTRY="CN"
STATE="北京市"
CITY="北京市"
ORGANIZATION="本地測試"
ORGANIZATIONAL_UNIT="Dev"
EMAIL="[email protected]"

###開始生成文件###
echo "開始生成文件"

#切換到生產密鑰的目錄
cd /etc/docker   
#生成ca私鑰(使用aes256加密)
openssl genrsa -aes256 -passout pass:$PASSWORD  -out ca-key.pem 2048
#生成ca證書,填寫配置信息
openssl req -new -x509 -passin "pass:$PASSWORD" -days 3650 -key ca-key.pem -sha256 -out ca.pem -subj "/C=$COUNTRY/ST=$STATE/L=$CITY/O=$ORGANIZATION/OU=$ORGANIZATIONAL_UNIT/CN=$SERVER/emailAddress=$EMAIL"

#生成server證書私鑰文件
openssl genrsa -out server-key.pem 2048
#生成server證書請求文件
openssl req -subj "/CN=$SERVER" -new -key server-key.pem -out server.csr
#使用CA證書及CA密鑰以及上面的server證書請求文件進行簽發,生成server自簽證書
openssl x509 -req -days 3650 -in server.csr -CA ca.pem -CAkey ca-key.pem -passin "pass:$PASSWORD" -CAcreateserial  -out server-cert.pem

#生成client證書RSA私鑰文件
openssl genrsa -out key.pem 2048
#生成client證書請求文件
openssl req -subj '/CN=client' -new -key key.pem -out client.csr

sh -c 'echo "extendedKeyUsage=clientAuth" > extfile.cnf'
#生成client自簽證書(根據上面的client私鑰文件、client證書請求文件生成)
openssl x509 -req -days 3650 -in client.csr -CA ca.pem -CAkey ca-key.pem  -passin "pass:$PASSWORD" -CAcreateserial -out cert.pem  -extfile extfile.cnf

#更改密鑰權限
chmod 0400 ca-key.pem key.pem server-key.pem
#更改密鑰權限
chmod 0444 ca.pem server-cert.pem cert.pem
#刪除無用文件
rm client.csr server.csr

echo "生成文件完成"
###生成結束###

腳本來源:https://blog.csdn.net/qq_21187515/article/details/90268345

3.2 、 配置docker 添加證書

1> 獲取docker 啓動的時候加載的配置文件(由於環境安裝的都不一定一樣,所以這個路徑可能會變)

在這裏插入圖片描述

2> 編輯文件 添加證書

--tlsverify \
--tlscacert=/etc/docker/ca.pem \ 
--tlscert=/etc/docker/server-cert.pem \          
--tlskey=/etc/docker/server-key.pem \     
-H tcp://0.0.0.0:2376 \    
-H unix:///var/run/docker.sock 

3.3 、重啓docker

在這裏插入圖片描述

可以看到端口已經監聽了

3.4 、驗證配置是否成功

在這裏插入圖片描述

3.5 、問題解決

Get http://192.168.80.136:2376/v1.26/images/json: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
* Are you trying to connect to a TLS-enabled daemon without TLS? 

在這裏插入圖片描述

如果你出現這個問題,不要着急,下面是解決方案

在這裏插入圖片描述

原因分析:解決方法來源:http://tinylab.org/use-docker-without-sudo/

  • - 因爲 /var/run/docker.sock 所屬 docker 組具有 setuid 權限
    - 1. $ sudo ls -l /var/run/docker.sock
      2. srw-rw---- 1 root docker 0 May  1 21:35 /var/run/docker.sock
    

4、程序調用

maven添加:

<dependency>
    <groupId>com.spotify</groupId>
    <artifactId>docker-client</artifactId>
    <version>8.16.0</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>2.27</version>
</dependency>

代碼實現:

package com.qyos.docker.utils;

import com.spotify.docker.client.DefaultDockerClient;
import com.spotify.docker.client.DockerCertificates;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.exceptions.DockerCertificateException;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.Image;
import com.spotify.docker.client.messages.RegistryAuth;
import lombok.extern.slf4j.Slf4j;

import java.net.URI;
import java.nio.file.Paths;
import java.util.List;

/**
 * @Author xiqingsong
 * @CreateTime 2020/4/28 15:46
 * docker 客戶端統一處理docker操作
 **/
@Slf4j
public class DockerUtils {
    static DockerClient docker;

    static {
        try {
            docker = DefaultDockerClient.builder()
                    .uri(URI.create("https://192.168.80.136:2376"))
                    .dockerCertificates(new DockerCertificates(Paths.get("/etc/docker/")))  //jar 部署位置所需docker服務端的證書
                    .build();
        } catch (DockerCertificateException e) {
            e.printStackTrace();
        }
    }


    public static boolean getImageList(){
        try {
            List<Image> quxImages = docker.listImages();
            log.info(quxImages.toString());
            return true;
        } catch (DockerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

}

5 、docker-client 操作手冊

官方文檔: https://github.com/spotify/docker-client/blob/master/docs/user_manual.md

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章