Docker 开启 SSL 验证

最近看 OJ 项目的远程开发阶段,然后踩坑踩了 2 天😂

Docker 版本:在 CentOS 安装 sudo yum install docker-ce-20.10.9 docker-ce-cli-20.10.9 containerd.io

复制代码
Client: Docker Engine - Community
 Version:           20.10.9
 API version:       1.41
 Go version:        go1.16.8
 Git commit:        c2ea9bc
 Built:             Mon Oct  4 16:08:25 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.9
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.8
  Git commit:       79ea9d3
  Built:            Mon Oct  4 16:06:48 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.31
  GitCommit:        e377cd56a71523140ca6ae87e30244719194a521
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

SpringBoot 版本: 2.7.14

Java-Docker 依赖

xml 复制代码
<!-- https://mvnrepository.com/artifact/com.github.docker-java/docker-java -->
<dependency>
    <groupId>com.github.docker-java</groupId>
    <artifactId>docker-java</artifactId>
    <version>3.3.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.docker-java/docker-java-transport-httpclient5 -->
<dependency>
    <groupId>com.github.docker-java</groupId>
    <artifactId>docker-java-transport-httpclient5</artifactId>
    <version>3.3.4</version>
</dependency>

不设置 SSL 认证

bash 复制代码
vim /usr/lib/systemd/system/docker.service

主要添加 -H tcp://0.0.0.0:2376 进去,只需要修改这个位置就好了

1

然后重启 Docker 服务

bash 复制代码
systemctl daemon-reload
systemctl restart docker

然后查看是否守护线程启动成功

bash 复制代码
systemctl status docker.service

Java 调用代码

java 复制代码
	 // 获取默认的 Docker Client
    DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
            .withDockerHost("tcp://服务器IP:2376")
            .build();
    DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
            .dockerHost(config.getDockerHost())
            .maxConnections(100)
            .connectionTimeout(Duration.ofSeconds(30))
            .responseTimeout(Duration.ofSeconds(45))
            .build();
    DockerClient dockerClient = DockerClientImpl.getInstance(config, httpClient);
    PingCmd pingCmd = dockerClient.pingCmd();
    pingCmd.exec();

配置 SSL 验证

官方文档

需要注意一点 官方文档写的 TLS 应该在 2376 端口,这里之前踩了大坑(之前一直使用 2375 一直不行)

当然我们需要开启服务器的2376 端口的防火墙(和宝塔如果有的话)!!!

将以下示例中 $HOST 的所有实例替换为 Docker 守护程序主机(服务器 IP)

首先创建存储相关信息的文件夹

bash 复制代码
mkdir -p /usr/local/certs.d/dockerd/ca
cd /usr/local/certs.d/dockerd/ca

让后在这个文件夹下面执行对应的命令

bash 复制代码
$ openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
..............................................................................++
........++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem:
Verifying - Enter pass phrase for ca-key.pem:

$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code): CN
State or Province Name (full name)[]: Beijing 
Locality Name (eg, city) []: Beijing
Organization Name (eg, company) [Internet Widgits Pty Ltd]: China
Organizational Unit Name (eg, section) []: developer
Common Name (e.g. server FQDN or YOUR name) []:$HOST
Email Address []: 填写邮箱
bash 复制代码
$ openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
.....................................................................++
.................................................................................................++
e is 65537 (0x10001)

$ openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr

接下来,我们将使用我们的 CA 签署公钥:

这里官方文档使用了 DNS 我们可以不写

bash 复制代码
$ echo subjectAltName = IP:$HOST,IP:127.0.0.1 >> extfile.cnf

$ echo extendedKeyUsage = serverAuth >> extfile.cnf
bash 复制代码
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=your.host.com
Getting CA Private Key
Enter pass phrase for ca-key.pem:
bash 复制代码
$ openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
.........................................................++
................++
e is 65537 (0x10001)

$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr
bash 复制代码
$ echo extendedKeyUsage = clientAuth > extfile-client.cnf
bash 复制代码
$ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:

删除一些不重要的文件

bash 复制代码
rm -v client.csr server.csr extfile.cnf extfile-client.cnf

修改文件的权限

bash 复制代码
$ chmod -v 0400 ca-key.pem key.pem server-key.pem
$ chmod -v 0444 ca.pem server-cert.pem cert.pem

最后

bash 复制代码
vi /etc/docker/daemon.json

填写相关内容

json 复制代码
{
    "registry-mirrors": ["https://mirror.ccs.tencentyun.com"],
    "tls": true,
    "tlscacert": "/usr/local/certs.d/dockerd/ca/ca.pem",
    "tlscert": "/usr/local/certs.d/dockerd/ca/server-cert.pem",
    "tlskey": "/usr/local/certs.d/dockerd/ca/server-key.pem"
}

然后重启 Docker 服务

bash 复制代码
systemctl daemon-reload
systemctl restart docker

然后查看是否守护线程启动成功

bash 复制代码
systemctl status docker.service

测试连通性

我们需要在服务器上下载下面三个文件 ca.pemkey.pemcert.pem 就在 /usr/local/certs.d/dockerd/ca目录下

PS 执行这个命令的时候我们需要在 ssl 目录里面放入这三个文件

bash 复制代码
curl https://服务器IP:2376/version --cert cert.pem --key key.pem  --cacert ca.pem

Java 调用代码

复制代码
─src
│  ├─main
│  │  ├─java
│  │  └─resources
│  │      ├─ca 文件放在这个目录下  

而且文件的名称需要下面这三个名称即 ca.pemkey.pemcert.pem

java 复制代码
   		URL url = ClassLoaderUtil.getClassLoader().getResource("ca");
        DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
                .withDockerHost("tcp://服务器 IP :2376")
                .withDockerTlsVerify(true)
            	// 下面三个参数不加也能运行成功
                // .withRegistryPassword("密码")
                // .withRegistryUsername("用户名")
                // .withRegistryEmail("邮箱")
                // 这里如果不截取的话会报错 url.getPath()结果是 /E:/yuoj-code-sandbox-master/target/classes/ca 
            	// 多一个 / 所以要截取,截取之后才不会报错
                .withDockerCertPath(url.getPath().substring(1)) 
                .build();
        DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
                .dockerHost(config.getDockerHost())
            	// 这里不要忘了啊,如果不加的话就会是 Status 400: Client sent an HTTP request to an HTTPS server 
                .sslConfig(config.getSSLConfig())
                .maxConnections(100)
                .connectionTimeout(Duration.ofSeconds(30))
                .responseTimeout(Duration.ofSeconds(45))
                .build();
        DockerClient dockerClient = DockerClientImpl.getInstance(config, httpClient);
        PingCmd pingCmd = dockerClient.pingCmd();
        pingCmd.exec();

报错小结

1、这里如果 Docker 版本过高会报一下错误 {"message":"client version 1.23 is too old. Minimum supported API version is 1.24, please upgrade your client to a newer version"}

解决办法:降低服务器 Docker 版本

2、还有一个报错 Cannot pull images when logged in to Docker Desktop (Status 500: unauthorized: incorrect username or password)

这个报错解决方法是,在 Docker 上登录一个账号就行了

3、报错信息 Status 400: Client sent an HTTP request to an HTTPS server

解决办法:首先确定 .sslConfig(config.getSSLConfig()) 写了没有,其次在确认一下公钥私钥证书是否放到了对应的目录下面

相关推荐
盖世英雄酱581362 分钟前
国企“高级”程序员写的那些问题代码(六期)
java·后端
南囝coding17 分钟前
这个Web新API让任何内容都能画中画!
前端·后端
林太白23 分钟前
VitePress项目工程化应该如何做
前端·后端
字节跳跃者1 小时前
Java 中的 Stream 可以替代 for 循环吗?
java·后端
北执南念1 小时前
如何在 Spring Boot 中设计和返回树形结构的组织和部门信息
java·spring boot·后端
修仙的人1 小时前
【开发环境】 VSCode 快速搭建 Python 项目开发环境
前端·后端·python
FinalLi1 小时前
SpringBoot3.5.0项目使用ALLATORI JAVA混淆器
后端
卸任2 小时前
Docker打包并部署Next.js
前端·docker·next.js
bobz9652 小时前
用于服务器测试的 MCP 开发工具
后端
SimonKing2 小时前
流式数据服务端怎么传给前端,前端怎么接收?
java·后端·程序员