最近看 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 依赖
com.github.docker-java docker-java 3.3.4 com.github.docker-java docker-java-transport-httpclient5 3.3.4
不设置 SSL 认证
vim /usr/lib/systemd/system/docker.service
主要添加 -H tcp://0.0.0.0:2376 进去,只需要修改这个位置就好了
1
然后重启 Docker 服务
systemctl daemon-reload systemctl restart docker
然后查看是否守护线程启动成功
systemctl status docker.service
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)
首先创建存储相关信息的文件夹
mkdir -p /usr/local/certs.d/dockerd/ca cd /usr/local/certs.d/dockerd/ca
让后在这个文件夹下面执行对应的命令
$ 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 []: 填写邮箱
$ 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 我们可以不写
$ echo subjectAltName = IP:$HOST,IP:127.0.0.1 >> extfile.cnf $ echo extendedKeyUsage = serverAuth >> extfile.cnf
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:
$ 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
$ echo extendedKeyUsage = clientAuth > extfile-client.cnf
$ 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:
删除一些不重要的文件
rm -v client.csr server.csr extfile.cnf extfile-client.cnf
修改文件的权限
$ chmod -v 0400 ca-key.pem key.pem server-key.pem $ chmod -v 0444 ca.pem server-cert.pem cert.pem
最后
vi /etc/docker/daemon.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 服务
systemctl daemon-reload systemctl restart docker
然后查看是否守护线程启动成功
systemctl status docker.service
测试连通性
我们需要在服务器上下载下面三个文件 ca.pem 、 key.pem、cert.pem 就在 /usr/local/certs.d/dockerd/ca目录下
PS 执行这个命令的时候我们需要在 ssl 目录里面放入这三个文件
curl https://服务器IP:2376/version --cert cert.pem --key key.pem --cacert ca.pem
Java 调用代码
─src │ ├─main │ │ ├─java │ │ └─resources │ │ ├─ca 文件放在这个目录下
而且文件的名称需要下面这三个名称即 ca.pem 、 key.pem、cert.pem
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()) 写了没有,其次在确认一下公钥私钥证书是否放到了对应的目录下面
还没有评论,来说两句吧...